d2c49567f7
Resolves: RHEL-56542
237 lines
6.7 KiB
Diff
237 lines
6.7 KiB
Diff
commit 766b73768b290b303f5b56268c6c0d588d5a9267
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Mon Sep 19 08:10:41 2022 +0200
|
|
|
|
Linux: Do not skip d_ino == 0 entries in readdir, readdir64 (bug 12165)
|
|
|
|
POSIX does not say this value is special. For example, old XFS file
|
|
systems may still use inode number zero.
|
|
|
|
Also update the comment regarding ENOENT. Linux may return ENOENT
|
|
for some file systems.
|
|
|
|
diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c
|
|
index b4801351645d1236..ef95611f09e761a4 100644
|
|
--- a/sysdeps/unix/sysv/linux/readdir.c
|
|
+++ b/sysdeps/unix/sysv/linux/readdir.c
|
|
@@ -28,48 +28,33 @@ __readdir_unlocked (DIR *dirp)
|
|
struct dirent *dp;
|
|
int saved_errno = errno;
|
|
|
|
- do
|
|
+ if (dirp->offset >= dirp->size)
|
|
{
|
|
- size_t reclen;
|
|
+ /* We've emptied out our buffer. Refill it. */
|
|
|
|
- if (dirp->offset >= dirp->size)
|
|
+ size_t maxread = dirp->allocation;
|
|
+ ssize_t bytes;
|
|
+
|
|
+ bytes = __getdents (dirp->fd, dirp->data, maxread);
|
|
+ if (bytes <= 0)
|
|
{
|
|
- /* We've emptied out our buffer. Refill it. */
|
|
-
|
|
- size_t maxread = dirp->allocation;
|
|
- ssize_t bytes;
|
|
-
|
|
- bytes = __getdents (dirp->fd, dirp->data, maxread);
|
|
- if (bytes <= 0)
|
|
- {
|
|
- /* On some systems getdents fails with ENOENT when the
|
|
- open directory has been rmdir'd already. POSIX.1
|
|
- requires that we treat this condition like normal EOF. */
|
|
- if (bytes < 0 && errno == ENOENT)
|
|
- bytes = 0;
|
|
-
|
|
- /* Don't modifiy errno when reaching EOF. */
|
|
- if (bytes == 0)
|
|
- __set_errno (saved_errno);
|
|
- dp = NULL;
|
|
- break;
|
|
- }
|
|
- dirp->size = (size_t) bytes;
|
|
-
|
|
- /* Reset the offset into the buffer. */
|
|
- dirp->offset = 0;
|
|
+ /* Linux may fail with ENOENT on some file systems if the
|
|
+ directory inode is marked as dead (deleted). POSIX
|
|
+ treats this as a regular end-of-directory condition, so
|
|
+ do not set errno in that case, to indicate success. */
|
|
+ if (bytes == 0 || errno == ENOENT)
|
|
+ __set_errno (saved_errno);
|
|
+ return NULL;
|
|
}
|
|
+ dirp->size = (size_t) bytes;
|
|
|
|
- dp = (struct dirent *) &dirp->data[dirp->offset];
|
|
-
|
|
- reclen = dp->d_reclen;
|
|
-
|
|
- dirp->offset += reclen;
|
|
-
|
|
- dirp->filepos = dp->d_off;
|
|
+ /* Reset the offset into the buffer. */
|
|
+ dirp->offset = 0;
|
|
+ }
|
|
|
|
- /* Skip deleted files. */
|
|
- } while (dp->d_ino == 0);
|
|
+ dp = (struct dirent *) &dirp->data[dirp->offset];
|
|
+ dirp->offset += dp->d_reclen;
|
|
+ dirp->filepos = dp->d_off;
|
|
|
|
return dp;
|
|
}
|
|
diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c
|
|
index 52b11eb9d91bb5fd..8a60504649aa54a2 100644
|
|
--- a/sysdeps/unix/sysv/linux/readdir64.c
|
|
+++ b/sysdeps/unix/sysv/linux/readdir64.c
|
|
@@ -37,48 +37,36 @@ __readdir64 (DIR *dirp)
|
|
__libc_lock_lock (dirp->lock);
|
|
#endif
|
|
|
|
- do
|
|
+ if (dirp->offset >= dirp->size)
|
|
{
|
|
- size_t reclen;
|
|
+ /* We've emptied out our buffer. Refill it. */
|
|
|
|
- if (dirp->offset >= dirp->size)
|
|
+ size_t maxread = dirp->allocation;
|
|
+ ssize_t bytes;
|
|
+
|
|
+ bytes = __getdents64 (dirp->fd, dirp->data, maxread);
|
|
+ if (bytes <= 0)
|
|
{
|
|
- /* We've emptied out our buffer. Refill it. */
|
|
-
|
|
- size_t maxread = dirp->allocation;
|
|
- ssize_t bytes;
|
|
-
|
|
- bytes = __getdents64 (dirp->fd, dirp->data, maxread);
|
|
- if (bytes <= 0)
|
|
- {
|
|
- /* On some systems getdents fails with ENOENT when the
|
|
- open directory has been rmdir'd already. POSIX.1
|
|
- requires that we treat this condition like normal EOF. */
|
|
- if (bytes < 0 && errno == ENOENT)
|
|
- bytes = 0;
|
|
-
|
|
- /* Don't modifiy errno when reaching EOF. */
|
|
- if (bytes == 0)
|
|
- __set_errno (saved_errno);
|
|
- dp = NULL;
|
|
- break;
|
|
- }
|
|
- dirp->size = (size_t) bytes;
|
|
-
|
|
- /* Reset the offset into the buffer. */
|
|
- dirp->offset = 0;
|
|
+ /* Linux may fail with ENOENT on some file systems if the
|
|
+ directory inode is marked as dead (deleted). POSIX
|
|
+ treats this as a regular end-of-directory condition, so
|
|
+ do not set errno in that case, to indicate success. */
|
|
+ if (bytes == 0 || errno == ENOENT)
|
|
+ __set_errno (saved_errno);
|
|
+#if IS_IN (libc)
|
|
+ __libc_lock_unlock (dirp->lock);
|
|
+#endif
|
|
+ return NULL;
|
|
}
|
|
+ dirp->size = (size_t) bytes;
|
|
|
|
- dp = (struct dirent64 *) &dirp->data[dirp->offset];
|
|
-
|
|
- reclen = dp->d_reclen;
|
|
-
|
|
- dirp->offset += reclen;
|
|
-
|
|
- dirp->filepos = dp->d_off;
|
|
+ /* Reset the offset into the buffer. */
|
|
+ dirp->offset = 0;
|
|
+ }
|
|
|
|
- /* Skip deleted files. */
|
|
- } while (dp->d_ino == 0);
|
|
+ dp = (struct dirent64 *) &dirp->data[dirp->offset];
|
|
+ dirp->offset += dp->d_reclen;
|
|
+ dirp->filepos = dp->d_off;
|
|
|
|
#if IS_IN (libc)
|
|
__libc_lock_unlock (dirp->lock);
|
|
@@ -115,48 +103,36 @@ __old_readdir64 (DIR *dirp)
|
|
__libc_lock_lock (dirp->lock);
|
|
#endif
|
|
|
|
- do
|
|
+ if (dirp->offset >= dirp->size)
|
|
{
|
|
- size_t reclen;
|
|
+ /* We've emptied out our buffer. Refill it. */
|
|
|
|
- if (dirp->offset >= dirp->size)
|
|
+ size_t maxread = dirp->allocation;
|
|
+ ssize_t bytes;
|
|
+
|
|
+ bytes = __old_getdents64 (dirp->fd, dirp->data, maxread);
|
|
+ if (bytes <= 0)
|
|
{
|
|
- /* We've emptied out our buffer. Refill it. */
|
|
-
|
|
- size_t maxread = dirp->allocation;
|
|
- ssize_t bytes;
|
|
-
|
|
- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread);
|
|
- if (bytes <= 0)
|
|
- {
|
|
- /* On some systems getdents fails with ENOENT when the
|
|
- open directory has been rmdir'd already. POSIX.1
|
|
- requires that we treat this condition like normal EOF. */
|
|
- if (bytes < 0 && errno == ENOENT)
|
|
- bytes = 0;
|
|
-
|
|
- /* Don't modifiy errno when reaching EOF. */
|
|
- if (bytes == 0)
|
|
- __set_errno (saved_errno);
|
|
- dp = NULL;
|
|
- break;
|
|
- }
|
|
- dirp->size = (size_t) bytes;
|
|
-
|
|
- /* Reset the offset into the buffer. */
|
|
- dirp->offset = 0;
|
|
+ /* Linux may fail with ENOENT on some file systems if the
|
|
+ directory inode is marked as dead (deleted). POSIX
|
|
+ treats this as a regular end-of-directory condition, so
|
|
+ do not set errno in that case, to indicate success. */
|
|
+ if (bytes == 0 || errno == ENOENT)
|
|
+ __set_errno (saved_errno);
|
|
+#if IS_IN (libc)
|
|
+ __libc_lock_unlock (dirp->lock);
|
|
+#endif
|
|
+ return NULL;
|
|
}
|
|
+ dirp->size = (size_t) bytes;
|
|
|
|
- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset];
|
|
-
|
|
- reclen = dp->d_reclen;
|
|
-
|
|
- dirp->offset += reclen;
|
|
-
|
|
- dirp->filepos = dp->d_off;
|
|
+ /* Reset the offset into the buffer. */
|
|
+ dirp->offset = 0;
|
|
+ }
|
|
|
|
- /* Skip deleted files. */
|
|
- } while (dp->d_ino == 0);
|
|
+ dp = (struct __old_dirent64 *) &dirp->data[dirp->offset];
|
|
+ dirp->offset += dp->d_reclen;
|
|
+ dirp->filepos = dp->d_off;
|
|
|
|
#if IS_IN (libc)
|
|
__libc_lock_unlock (dirp->lock);
|