Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions include/dirent.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ extern struct dirent *readdir(DIR *s);

extern DIR *opendir(const char *dirname);

extern DIR *fdopendir(int fd);

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

extern long telldir(DIR *dirp);

extern void rewinddir(DIR *dirp);

Expand Down
64 changes: 64 additions & 0 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 @@ -440,6 +441,69 @@ DIR *opendir(const char *dirname)
}


DIR *fdopendir(int fd)
{
DIR *s;
struct stat statbuf;
int fd_flags;

fd_flags = fcntl(fd, F_GETFL);
if (fd_flags < 0) {
return NULL;
}
if ((fd_flags & O_RDONLY) == 0) {
Copy link
Member

Choose a reason for hiding this comment

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

What if O_RDWR is set, so O_RDONLY is not? I think a file descriptor open for reading can be as well open for writing, as long as it is still readable

Copy link
Contributor Author

@R4ken R4ken Sep 30, 2025

Choose a reason for hiding this comment

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

open from libphoenix sets EISDIR on errno while opening directory with either O_WRONLY or O_RDWR flag.
Thus opening directory with O_RDWR is not possible

Fragment of open function from libphoenix

if (oflag & (O_WRONLY | O_RDWR)) {
  if ((err = stat(filename, &st)) < 0) {
	  if (errno != ENOENT)
		  return err;
  }
  else if (S_ISDIR(st.st_mode)) {
	  return SET_ERRNO(-EISDIR);
  }
}

Copy link
Member

Choose a reason for hiding this comment

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

This behaviour seems common, I can replicate it on both Linux and one of the BSD's, I think we can keep it like that for the sake of compatibility.

errno = EBADF;
return NULL; /* EBADF */
}

if (fstat(fd, &statbuf) < 0) {
return NULL;
}

msg_t msg = {
.type = mtGetAttr,
.oid = { .port = statbuf.st_dev, .id = statbuf.st_ino },
.i.attr.type = atType,
};

if ((msgSend(statbuf.st_dev, &msg) < 0) || (msg.o.err < 0)) {
errno = EIO;
return NULL; /* EIO */
}

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

if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
return NULL;
}

s = calloc(1, sizeof(DIR));
if (s == NULL) {
errno = ENOMEM;
return NULL;
}
s->oid = msg.oid;
s->dirent = NULL;

return s;
}


void seekdir(DIR *dirp, long loc)
{
dirp->pos = loc;

Choose a reason for hiding this comment

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

high

The function should handle the case where dirp is NULL to prevent a segmentation fault. Dereferencing a NULL pointer is undefined behavior.

	if (dirp != NULL)
		dirp->pos = loc;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Other libphoenix functions don't validate whether dirp is non NULL pointer

Copy link
Member

Choose a reason for hiding this comment

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

Yes, you are right, although I think that this might be a good opportunity to introduce those checks here.
Linux's behaviour in these calls is not unreasonable and helping the programmer by making this deterministic is IMO good

}


long telldir(DIR *dirp)
{
return dirp->pos;

Choose a reason for hiding this comment

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

high

The function should handle the case where dirp is NULL. According to the POSIX standard, if dirp does not refer to a valid directory stream, telldir() should return -1 and set errno to EBADF.

	if (dirp == NULL) {
		errno = EBADF;
		return -1;
	}
	return dirp->pos;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, this behavior exists in Linux, POSIX does not specify it

Copy link
Member

Choose a reason for hiding this comment

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

As above

}


void rewinddir(DIR *dirp)
{
dirp->pos = 0;
Expand Down
Loading