diff --git a/Linux-Do-not-skip-d_ino-0-entries-in-readdir-readdir.patch b/Linux-Do-not-skip-d_ino-0-entries-in-readdir-readdir.patch new file mode 100644 index 0000000..7b3455e --- /dev/null +++ b/Linux-Do-not-skip-d_ino-0-entries-in-readdir-readdir.patch @@ -0,0 +1,243 @@ +From 766b73768b290b303f5b56268c6c0d588d5a9267 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 + diff --git a/glibc.spec b/glibc.spec index 0cdc5f7..003b308 100644 --- a/glibc.spec +++ b/glibc.spec @@ -65,7 +65,7 @@ ############################################################################## Name: glibc Version: 2.36 -Release: 7 +Release: 8 Summary: The GNU libc libraries License: %{all_license} URL: http://www.gnu.org/software/glibc/ @@ -88,6 +88,7 @@ Patch1: linux-Mimic-kernel-defition-for-BLOCK_SIZE.patch Patch2: linux-Fix-sys-mount.h-usage-with-kernel-headers.patch Patch3: Linux-Fix-enum-fsconfig_command-detection-in-sys-mou.patch Patch4: syslog-Fix-large-messages-BZ-29536.patch +Patch5: Linux-Do-not-skip-d_ino-0-entries-in-readdir-readdir.patch Patch9000: turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch Patch9001: locale-delete-no-hard-link-to-avoid-all_language-pac.patch @@ -1263,6 +1264,9 @@ fi %endif %changelog +* Tue Sep 20 2022 SuperHugePan - 2.36-8 +- linux: Do not skip d_ino==0 entries in readdir, readdir64(bug 12165) + * Thu Sep 8 2022 Qingqing Li - 2.36-7 - add requires between glibc-info and glibc