Skip to content

posix: implement missing directory functions#433

Open
R4ken wants to merge 3 commits intomasterfrom
jrak/dir
Open

posix: implement missing directory functions#433
R4ken wants to merge 3 commits intomasterfrom
jrak/dir

Conversation

@R4ken
Copy link
Contributor

@R4ken R4ken commented Sep 1, 2025

Implement missing POSIX functions (fdopendir,seekdir, telldir) working on DIR structs

JIRA: RTOS-1088

Description

Implemented fdopendir,seekdir and telldir functions.

Motivation and Context

Missing POSIX functions useful in porting applications

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Chore (refactoring, style fixes, git/CI config, submodule management, no code logic changes)

How Has This Been Tested?

  • Already covered by automatic testing.
  • New test added: (add PR link here).
  • Tested by hand on: (ia32-generic-qemu, armv7a9-zynq7000-qemu)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing linter checks and tests passed.
  • My changes generate no new compilation warnings for any of the targets.

Special treatment

  • This PR needs additional PRs to work (list the PRs, preferably in merge-order).
  • I will merge this PR by myself when appropriate.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @R4ken, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces three essential POSIX directory functions: fdopendir, seekdir, and telldir. These additions are crucial for improving the system's compatibility with POSIX standards, thereby simplifying the porting of various applications that rely on these common directory operations. The changes enhance the system's file system interaction capabilities without altering existing functionality.

Highlights

  • New POSIX Directory Functions: Implemented fdopendir, seekdir, and telldir functions to provide more comprehensive POSIX-compliant directory manipulation capabilities.
  • Header Updates: Added declarations for the new directory functions in include/dirent.h.
  • Core Logic Implementation: Provided the full implementation for fdopendir, seekdir, and telldir within unistd/dir.c, including necessary error handling and file descriptor management.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request implements the missing POSIX directory functions fdopendir, seekdir, and telldir. The implementations are a good start, but I've identified a few high-severity issues related to null pointer dereferences and error handling that could lead to crashes or undefined behavior. I've provided detailed comments and code suggestions to address these points, which also include a small efficiency improvement in fdopendir.


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

Copy link
Member

Choose a reason for hiding this comment

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

Please look carefully at the condition.

Also, I agree that POSIX does not specify how to report the error, but: should we deviate from the "common" errno setting, as is the case with other directory functions in this file? We don't even have this function documented in p-r-doc, so using an approach other than errno seems counter-intuitive. Please either use errno or make a PR to p-r-doc (which will eventually be needed, though).

Copy link
Member

Choose a reason for hiding this comment

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

Addressed

@R4ken R4ken marked this pull request as draft September 1, 2025 14:46
@github-actions
Copy link

github-actions bot commented Sep 1, 2025

Unit Test Results

8 533 tests   - 1 020   8 006 ✅  - 955   46m 59s ⏱️ - 5m 33s
  525 suites  -    66     527 💤  -  65 
    1 files   ±    0       0 ❌ ±  0 

Results for commit 7647476. ± Comparison against base commit 74852cb.

This pull request removes 1020 tests.
flash ‑ armv7a7-imx6ull-evk:flash
phoenix-rtos-tests/cpp/hello-cpp ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/cpp/hello-cpp
phoenix-rtos-tests/initfini/main ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/initfini/main
phoenix-rtos-tests/ioctl/test-ioctl ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/ioctl/test-ioctl.ioctl.data_in
phoenix-rtos-tests/ioctl/test-ioctl ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/ioctl/test-ioctl.ioctl.data_in_big
phoenix-rtos-tests/ioctl/test-ioctl ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/ioctl/test-ioctl.ioctl.data_inout
phoenix-rtos-tests/ioctl/test-ioctl ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/ioctl/test-ioctl.ioctl.data_inout_big
phoenix-rtos-tests/ioctl/test-ioctl ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/ioctl/test-ioctl.ioctl.data_out
phoenix-rtos-tests/ioctl/test-ioctl ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/ioctl/test-ioctl.ioctl.data_out_big
phoenix-rtos-tests/ioctl/test-ioctl ‑ armv7a7-imx6ull-evk:phoenix-rtos-tests/ioctl/test-ioctl.ioctl.in_val
…

♻️ This comment has been updated with latest results.

@R4ken R4ken requested a review from jlatusek September 2, 2025 06:48
@R4ken R4ken requested a review from Darchiv September 8, 2025 15:08
@R4ken R4ken marked this pull request as ready for review September 25, 2025 07:39
unistd/dir.c Outdated
free(s);
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.

Copy link
Member

Choose a reason for hiding this comment

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

Is fd_flags & O_RDONLY) == 0 idiomatic? WHat about use of O_ACCMODE? Should we assume that O_RDONLY, O_WRONLY, and O_RDWR are bitmasks (0x1, 0x2, 0x4)? Or they are an enumeration (0x0, 0x1, 0x2) to be checked with O_ACCMODE == 0x3? (I'm not asking about how we or Linux implement it, but what is the most portable way.)

Copy link
Member

Choose a reason for hiding this comment

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

Addressed. Will create a new, linked PR in p-r-k.

Copy link
Member

Choose a reason for hiding this comment

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

Also, this check would be a no-op in enum-like access modes. It seems that it is here in this version to check if any mode is set (as rdonly is the default), on most systems O_RDONLY is defined as 0, so it is implicitly a default and there is no need to check it here.

@Darchiv Darchiv removed the request for review from jlatusek November 26, 2025 13:51
Copy link
Member

@oI0ck oI0ck left a comment

Choose a reason for hiding this comment

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

I'd be good to introduce NULL checks while we are at it.


long telldir(DIR *dirp)
{
return dirp->pos;
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

unistd/dir.c Outdated
free(s);
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.

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.

@oI0ck oI0ck requested a review from Darchiv November 26, 2025 14:12
unistd/dir.c Outdated
int ret = 0;

if (dirp != NULL) {
return -EBADF;
Copy link
Member

Choose a reason for hiding this comment

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

So, only dirp == NULL is allowed to proceed?

The same case in telldir()


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

extern long telldir(DIR *dirp);
Copy link
Member

Choose a reason for hiding this comment

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

Keep two empty lines between function prototypes.

Copy link
Member

Choose a reason for hiding this comment

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

Addressed.

include/dirent.h Outdated
Copy link
Member

Choose a reason for hiding this comment

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

For some reason, s is used as a parameter name instead of dirp. Maybe make it consistent now, if you make changes to these functions already?

if (msg.o.err < 0) {
free(s->dirent);
s->dirent = NULL;
return NULL;
Copy link
Member

Choose a reason for hiding this comment

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

As per POSIX:

Upon successful completion, readdir() shall return a pointer to an object of type struct dirent. When an error is encountered, a null pointer shall be returned and errno shall be set to indicate the error. When the end of the directory is encountered, a null pointer shall be returned and errno is not changed.

Discriminating between the end of the directory and errors seems to rely on checking the value of errno while readdir() returns NULL. If so, it makes sense to set errno in all cases when an error occurs - i.e. when:

  • calloc() above fails,
  • msgSend() above fails - there is a comment about EIO, but it is not assigned to errno!); msgSend() only returns error codes, it does not set errno,
  • msg.o.err < 0, so errno = -msg.o.err here? Or errno = EIO, but I think returning an actual error code from the same abstraction layer (a filesystem server) is nice, especially for debugging.

If you already make changes to error reporting in this already-existing function, then please do so fully.

Copy link
Member

Choose a reason for hiding this comment

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

I think we should differentiate between cases when we reach end of directory stream (with err set to -ENOENT) and cases when we return any other errors; errno should be only modified in latter case.

This imposes a requirement on our filesystem implementations to adhere to this behaviour (to return -ENOENT on end of dirstream), which is true for ext2 at least, not sure about other filesystems.

Copy link
Member

Choose a reason for hiding this comment

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

Addressed.

As far as I checked, most of our filesystems return -ENOENT on reaching the end of dirstream, with the exception of JFFS2. I'll create and link a new pr in p-r-fs


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

Choose a reason for hiding this comment

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

Please look carefully at the condition.

Also, I agree that POSIX does not specify how to report the error, but: should we deviate from the "common" errno setting, as is the case with other directory functions in this file? We don't even have this function documented in p-r-doc, so using an approach other than errno seems counter-intuitive. Please either use errno or make a PR to p-r-doc (which will eventually be needed, though).

unistd/dir.c Outdated
free(s);
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.

Is fd_flags & O_RDONLY) == 0 idiomatic? WHat about use of O_ACCMODE? Should we assume that O_RDONLY, O_WRONLY, and O_RDWR are bitmasks (0x1, 0x2, 0x4)? Or they are an enumeration (0x0, 0x1, 0x2) to be checked with O_ACCMODE == 0x3? (I'm not asking about how we or Linux implement it, but what is the most portable way.)

@oI0ck
Copy link
Member

oI0ck commented Mar 26, 2026

@Darchiv

Is fd_flags & O_RDONLY) == 0 idiomatic? WHat about use of O_ACCMODE? Should we assume that O_RDONLY, O_WRONLY, and O_RDWR are bitmasks (0x1, 0x2, 0x4)? Or they are an enumeration (0x0, 0x1, 0x2) to be checked with O_ACCMODE == 0x3? (I'm not asking about how we or Linux implement it, but what is the most portable way.)

Most POSIX conformant/compilant operating systems seem to treat those values as enums, not bitfields.
I'll change it to enum-like values for the sake or portability.

R4ken and others added 2 commits March 26, 2026 15:18
Implement missing POSIX functions (fdopendir,seekdir, telldir) working
on DIR structs

JIRA: RTOS-1088
@oI0ck oI0ck requested a review from Darchiv March 26, 2026 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants