yushuailong opened a new pull request, #19016:
URL: https://github.com/apache/nuttx/pull/19016
readdir() returned NULL at end-of-directory without ensuring errno was
clean. POSIX requires errno to be unchanged at EOF, but the underlying read()
path may leave a stale errno value. Callers that follow the POSIX idiom (set
errno to 0 before the call, test it after a NULL return), such as readdir_r()
and scandir(), then misread this as a readdir() failure.
Save errno on entry and restore it on the end-of-directory return so that
EOF no longer reports a spurious error, while genuine errors (read() returning
a negative value) still propagate.
## Summary
`readdir()` returns NULL both at end-of-directory and on error, and per
POSIX a caller distinguishes the two by setting `errno` to 0 before the call
and checking it after a NULL return. The current implementation does not
guarantee `errno` is left clean at end-of-directory: the underlying `read()`
path can leave a stale `errno` value behind, so a normal end-of-directory looks
like a failure to such callers (`readdir_r()`, `scandir()`, and the libc++
`std::filesystem::directory_iterator`).
This patch saves `errno` on entry and restores it on the end-of-directory
(`read() `== 0) return, mirroring glibc's `readdir()`. Genuine errors (`read()`
returning a negative value, with errno already set) are left untouched and
still propagate to the caller.
## Impact
Affected: `readdir() `only, and only its end-of-directory path
(`read()`==0), which now restores errno. The error path and normal path are
unchanged.
## Testing
Build Host: Ubuntu 22.04, arm-none-eabi-gcc 10.3.1 (2021.07)
Target: ARM Cortex-M55 (ARMv8-M) custom board
```c
static void test_readdir_eof_errno(FAR const char *path)
{
FAR DIR *dirp;
FAR struct dirent *ent;
int count = 0;
int eof_errno;
dirp = opendir(path);
if (dirp == NULL)
{
printf("readdir_test: opendir(%s) failed: errno=%d (%s)\n",
path, errno, strerror(errno));
return;
}
/* POSIX idiom: clear errno before the loop so that a non-zero errno
* after a NULL return unambiguously means an error (not end-of-dir).
*/
errno = 0;
while ((ent = readdir(dirp)) != NULL)
{
count++;
}
eof_errno = errno;
printf("readdir_test: path=%s entries=%d eof_errno=%d (%s) -> %s\n",
path, count, eof_errno, strerror(eof_errno),
eof_errno == 0 ? "PASS" : "FAIL");
closedir(dirp);
}
```
readdir_test: path=/font entries=17 eof_errno=0 (Unknown error 0) -> PASS
## PR verification Self-Check
* [x] This PR introduces only one functional change.
* [x] I have updated all required description fields above.
* [x] My PR adheres to Contributing
[Guidelines](https://github.com/apache/nuttx/blob/master/CONTRIBUTING.md) and
[Documentation](https://nuttx.apache.org/docs/latest/contributing/index.html)
(git commit title and message, coding standard, etc).
* [ ] My PR is still work in progress (not ready for review).
* [x] My PR is ready for review and can be safely merged into a codebase.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]