Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion include/dirent.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,22 @@ struct dirent {
};


extern struct dirent *readdir(DIR *s);
/* These functions are not thread-safe */
extern struct dirent *readdir(DIR *dirp);
Comment thread
ziemleszcz marked this conversation as resolved.


extern DIR *opendir(const char *dirname);


extern DIR *fdopendir(int fd);


extern void seekdir(DIR *dirp, long loc);


extern long telldir(DIR *dirp);
Comment thread
oI0ck marked this conversation as resolved.


extern void rewinddir(DIR *dirp);


Expand Down
3 changes: 2 additions & 1 deletion include/stdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ typedef struct _FILE {

typedef struct _DIR {
oid_t oid;
size_t pos;
int fd;
off_t pos;
struct dirent *dirent;
} DIR;

Expand Down
185 changes: 143 additions & 42 deletions unistd/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <sys/stat.h>
#include <sys/file.h>
#include <posix/utils.h>
#include <fcntl.h>


static struct {
Expand Down Expand Up @@ -347,101 +348,191 @@ char *realpath(const char *path, char *resolved_path)
}


struct dirent *readdir(DIR *s)
struct dirent *readdir(DIR *dirp)
{
if (s->dirent == NULL) {
if ((s->dirent = calloc(1, sizeof(struct dirent) + NAME_MAX + 1)) == NULL)
return NULL;
if (dirp == NULL) {
errno = EBADF;
return NULL;
}

if (dirp->dirent == NULL) {
dirp->dirent = calloc(1, sizeof(struct dirent) + NAME_MAX + 1);
if (dirp->dirent == NULL) {
return NULL; /* errno set by calloc() */
}
}

msg_t msg = {
.type = mtReaddir,
.oid = s->oid,
.i.readdir.offs = s->pos,
.o.data = s->dirent,
.oid = dirp->oid,
.i.readdir.offs = dirp->pos,
.o.data = dirp->dirent,
.o.size = sizeof(struct dirent) + NAME_MAX + 1
};

if (msgSend(s->oid.port, &msg) < 0) {
free(s->dirent);
s->dirent = NULL;
return NULL; /* EIO */
if (msgSend(dirp->oid.port, &msg) < 0) {
free(dirp->dirent);
dirp->dirent = NULL;
errno = EIO;
return NULL;
}

if (msg.o.err < 0) {
free(s->dirent);
s->dirent = NULL;
free(dirp->dirent);
dirp->dirent = NULL;
/* Any other errors should be set, ENOENT signals
* end of a directory stream
*/
if (msg.o.err != -ENOENT) {
errno = -msg.o.err;
}
Comment thread
ziemleszcz marked this conversation as resolved.
return NULL;
}

s->pos += s->dirent->d_reclen;
dirp->pos += dirp->dirent->d_reclen;

return s->dirent;
return dirp->dirent;
}


DIR *opendir(const char *dirname)
{
char *canonical_name = resolve_path(dirname, NULL, 1, 0);
DIR *s = calloc(1, sizeof(DIR));
DIR *dirp = calloc(1, sizeof(DIR));

if ((canonical_name == NULL) || (s == NULL)) {
if ((canonical_name == NULL) || (dirp == NULL)) {
free(canonical_name);
free(s);
free(dirp);
return NULL; /* errno set by resolve_path */
}

if (!dirname[0] || (safe_lookup(canonical_name, NULL, &s->oid) < 0)) {
if (!dirname[0] || (safe_lookup(canonical_name, NULL, &dirp->oid) < 0)) {
free(canonical_name);
free(s);
free(dirp);
errno = ENOENT;
return NULL; /* ENOENT */
return NULL;
}

free(canonical_name);
s->dirent = NULL;
dirp->dirent = NULL;
/* Following field is only valid in fdopendir */
dirp->fd = -1;

msg_t msg = {
.type = mtGetAttr,
.oid = s->oid,
.oid = dirp->oid,
.i.attr.type = atType,
};

if ((msgSend(s->oid.port, &msg) < 0) || (msg.o.err < 0)) {
free(s);
if ((msgSend(dirp->oid.port, &msg) < 0) || (msg.o.err < 0)) {
free(dirp);
errno = EIO;
return NULL; /* EIO */
return NULL;
}

if (msg.o.attr.val != otDir) {
free(s);
free(dirp);
errno = ENOTDIR;
return NULL; /* ENOTDIR */
return NULL;
}

memset(&msg, 0, sizeof(msg));
msg.type = mtOpen;
msg.oid = s->oid;
msg.oid = dirp->oid;
msg.i.openclose.flags = 0;

if (msgSend(s->oid.port, &msg) < 0) {
free(s);
if (msgSend(dirp->oid.port, &msg) < 0 || (msg.o.err < 0)) {
free(dirp);
errno = EIO;
return NULL; /* EIO */
return NULL;
}

if (msg.o.err < 0) {
free(s);
errno = EIO;
return dirp;
}


/*
* FIXME: fstat() does not return proper OIDs for directories mounted under
* a different filesystem.
*/
DIR *fdopendir(int fd)
Comment thread
oI0ck marked this conversation as resolved.
{
DIR *dirp;
struct stat statbuf;
int flags;
off_t pos;

flags = fcntl(fd, F_GETFL);
if (flags < 0) {
return NULL; /* errno set by fcntl() */
}
if ((flags & O_RDONLY) == 0) {
errno = EBADF;
return NULL;
}

return s;
pos = lseek(fd, 0, SEEK_CUR);
if (pos == (off_t)-1) {
return NULL; /* errno set by lseek() */
}

if (fstat(fd, &statbuf) < 0) {
return NULL; /* errno set by fstat() */
}

if (!S_ISDIR(statbuf.st_mode)) {
errno = ENOTDIR;
return NULL;
}

dirp = calloc(1, sizeof(DIR));
if (dirp == NULL) {
return NULL; /* errno set by calloc() */
}
dirp->oid.port = statbuf.st_dev;
dirp->oid.id = statbuf.st_ino;
dirp->fd = fd;
dirp->dirent = NULL;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant.

dirp->pos = pos;

if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
free(dirp);
return NULL; /* errno set by fcntl() */
}

return dirp;
}


void seekdir(DIR *dirp, long loc)
{
if (dirp == NULL) {
errno = EBADF;
return;
}

dirp->pos = (off_t)loc;
}

Comment thread
R4ken marked this conversation as resolved.

long telldir(DIR *dirp)
{
if (dirp == NULL) {
errno = EBADF;
return -1;
}

return (long)dirp->pos;
}


void rewinddir(DIR *dirp)
{
if (dirp == NULL) {
errno = EBADF;
return;
}

dirp->pos = 0;
}

Expand All @@ -450,13 +541,23 @@ int closedir(DIR *dirp)
{
int ret = 0;

msg_t msg = {
.type = mtClose,
.oid = dirp->oid
};
if (dirp == NULL) {
return SET_ERRNO(-EBADF);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not errno = EBADF?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be the way to set errno in functions that return integer values. I don't understand what is wrong with this snippet.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SET_ERRNO(err) should be used when err could be 0 (success). In this case you know it's an error so you can set errno directly.

}

if ((msgSend(dirp->oid.port, &msg) < 0) || (msg.o.err < 0)) {
ret = -1;
if (dirp->fd >= 0) {
ret = close(dirp->fd);
}
else {
msg_t msg = {
.type = mtClose,
.oid = dirp->oid
};

if ((msgSend(dirp->oid.port, &msg) < 0) || (msg.o.err < 0)) {
errno = EIO;
ret = -1;
}
}

free(dirp->dirent);
Expand Down
Loading