244 lines
6.9 KiB
Diff
244 lines
6.9 KiB
Diff
|
|
From 766b73768b290b303f5b56268c6c0d588d5a9267 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Florian Weimer <fweimer@redhat.com>
|
||
|
|
Date: Mon, 19 Sep 2022 08:10:41 +0200
|
||
|
|
Subject: [PATCH] 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.
|
||
|
|
---
|
||
|
|
sysdeps/unix/sysv/linux/readdir.c | 57 +++++--------
|
||
|
|
sysdeps/unix/sysv/linux/readdir64.c | 120 +++++++++++-----------------
|
||
|
|
2 files changed, 69 insertions(+), 108 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c
|
||
|
|
index c31f349639..c9a04dc160 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 e876d84b02..7952da5c27 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);
|
||
|
|
--
|
||
|
|
2.23.0
|
||
|
|
|