[COMMITTED] Linux: readdir_r needs to report getdents failures (bug 32124)

Message ID 87mskmflxy.fsf@oldenburg.str.redhat.com
State Committed
Commit 61f2c2e1d1287a791c22d86c943b44bcf66bb8ad
Headers
Series [COMMITTED] Linux: readdir_r needs to report getdents failures (bug 32124) |

Commit Message

Florian Weimer Sept. 5, 2024, 10:12 a.m. UTC
  I botched patch split, so this is what I committed.  The combination of
the two patches is identical to what DJ reviewed.
---8<---
Upon error, return the errno value set by the __getdents call
in __readdir_unlocked.  Previously, kernel-reported errors
were ignored.

Reviewed-by: DJ Delorie <dj@redhat.com>

---
 sysdeps/unix/sysv/linux/readdir_r.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)


base-commit: 3b1d32177635023e37bec7fbfd77c3cfb2659eb1
  

Patch

diff --git a/sysdeps/unix/sysv/linux/readdir_r.c b/sysdeps/unix/sysv/linux/readdir_r.c
index ffd5262cf5..1d595688f7 100644
--- a/sysdeps/unix/sysv/linux/readdir_r.c
+++ b/sysdeps/unix/sysv/linux/readdir_r.c
@@ -25,14 +25,22 @@  __readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result)
 {
   struct dirent *dp;
   size_t reclen;
+  int saved_errno = errno;
 
   __libc_lock_lock (dirp->lock);
 
   while (1)
     {
+      /* If errno is changed from 0, the NULL return value indicates
+	 an actual error.  It overrides a pending ENAMETOOLONG error.  */
+      __set_errno (0);
       dp = __readdir_unlocked (dirp);
       if (dp == NULL)
-	break;
+	{
+	  if (errno != 0)
+	    dirp->errcode = errno;
+	  break;
+	}
 
       reclen = dp->d_reclen;
       if (reclen <= offsetof (struct dirent, d_name) + NAME_MAX + 1)
@@ -61,6 +69,7 @@  __readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result)
 
   __libc_lock_unlock (dirp->lock);
 
+  __set_errno (saved_errno);
   return dp != NULL ? 0 : dirp->errcode;
 }