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]

Reply via email to