From 4e94f64bd9462f55e52de64d1c49b20cdfc686a3 Mon Sep 17 00:00:00 2001 From: "Andreas K. Hüttel" Date: Wed, 1 Feb 2023 20:44:39 +0100 Subject: Update dirent-related patchset from libc-alpha archive (v5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas K. Hüttel --- 9999/0001-Disable-ldconfig-during-install.patch | 8 +- ...Adapt-to-Gentoo-specific-etc-mail-aliases.patch | 12 +- ...O0-in-conform-tests-to-survive-CC-changes.patch | 10 +- .../0004-Fix-miscompilation-on-ia64-s-gcc-10.patch | 8 +- ...5-linux-Use-getdents64-on-non-LFS-readdir.patch | 190 +++---- ...nternal-DIR-filepos-as-off64_t-BZ-23960-B.patch | 616 +++++++++++---------- 9999/0007-linux-Add-__readdir64_unlocked.patch | 14 +- 9999/0008-linux-Add-__old_readdir64_unlocked.patch | 14 +- ...etdents64-on-readdir64-compat-implementat.patch | 123 ++-- 9999/0010-dirent-Deprecate-getdirentries.patch | 100 ---- 10 files changed, 500 insertions(+), 595 deletions(-) delete mode 100644 9999/0010-dirent-Deprecate-getdirentries.patch diff --git a/9999/0001-Disable-ldconfig-during-install.patch b/9999/0001-Disable-ldconfig-during-install.patch index 4a8c771..e947fac 100644 --- a/9999/0001-Disable-ldconfig-during-install.patch +++ b/9999/0001-Disable-ldconfig-during-install.patch @@ -1,7 +1,7 @@ -From 5349895a928bff28939b228824c8265d20d9fa60 Mon Sep 17 00:00:00 2001 +From 3b59ad9dec2c1c7f1b4c7f72d14ea3f2b68a4eca Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 3 Aug 2021 00:34:59 +0200 -Subject: [PATCH 01/10] Disable ldconfig during install +Subject: [PATCH 1/9] Disable ldconfig during install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -19,7 +19,7 @@ Signed-off-by: Andreas K. Hüttel 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile -index 179dd478ff..763d6a084a 100644 +index 224c792185..be9df042e0 100644 --- a/Makefile +++ b/Makefile @@ -110,6 +110,7 @@ elf/ldso_install: @@ -31,5 +31,5 @@ index 179dd478ff..763d6a084a 100644 $(elf-objpfx)ldconfig $(addprefix -r ,$(install_root)) \ $(slibdir) $(libdir) -- -2.38.2 +2.39.1 diff --git a/9999/0002-Adapt-to-Gentoo-specific-etc-mail-aliases.patch b/9999/0002-Adapt-to-Gentoo-specific-etc-mail-aliases.patch index 559e736..09c2dde 100644 --- a/9999/0002-Adapt-to-Gentoo-specific-etc-mail-aliases.patch +++ b/9999/0002-Adapt-to-Gentoo-specific-etc-mail-aliases.patch @@ -1,7 +1,7 @@ -From ab1ca71990a972e375709711f5fa268010505324 Mon Sep 17 00:00:00 2001 +From d8a45f4bfa30b502647a9ef742836c7e8694d009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=2E=20H=C3=BCttel?= Date: Mon, 22 Oct 2018 22:34:13 +0200 -Subject: [PATCH 02/10] Adapt to Gentoo-specific /etc/mail/aliases +Subject: [PATCH 2/9] Adapt to Gentoo-specific /etc/mail/aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -18,7 +18,7 @@ Signed-off-by: Andreas K. Hüttel 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c -index 505721388f..44d835cace 100644 +index 1c32884fe7..f40fd19288 100644 --- a/nss/nss_files/files-alias.c +++ b/nss/nss_files/files-alias.c @@ -42,7 +42,7 @@ internal_setent (FILE **stream) @@ -31,7 +31,7 @@ index 505721388f..44d835cace 100644 if (*stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; diff --git a/nss/tst-nss-files-alias-leak.c b/nss/tst-nss-files-alias-leak.c -index 576f07fa0a..29962764e2 100644 +index a62e137614..f0cd132ce6 100644 --- a/nss/tst-nss-files-alias-leak.c +++ b/nss/tst-nss-files-alias-leak.c @@ -45,27 +45,27 @@ prepare (int argc, char **argv) @@ -80,7 +80,7 @@ index 576f07fa0a..29962764e2 100644 FILE *fp = xfopen (path, "w"); for (int i = 0; i < many_aliases; ++i) diff --git a/support/support_chroot.c b/support/support_chroot.c -index 4bf6fe0834..1548eba2ad 100644 +index 7a1b7272f0..500c9a79a3 100644 --- a/support/support_chroot.c +++ b/support/support_chroot.c @@ -52,13 +52,19 @@ support_chroot_create (struct support_chroot_configuration conf) @@ -105,5 +105,5 @@ index 4bf6fe0834..1548eba2ad 100644 /* valgrind needs a temporary directory in the chroot. */ { -- -2.38.2 +2.39.1 diff --git a/9999/0003-Force-O0-in-conform-tests-to-survive-CC-changes.patch b/9999/0003-Force-O0-in-conform-tests-to-survive-CC-changes.patch index f662cda..ac36f58 100644 --- a/9999/0003-Force-O0-in-conform-tests-to-survive-CC-changes.patch +++ b/9999/0003-Force-O0-in-conform-tests-to-survive-CC-changes.patch @@ -1,7 +1,7 @@ -From f44c6c3768c2a3ef274782a2e308fb6b8fe84499 Mon Sep 17 00:00:00 2001 +From d2b4275295e9c5a312063c3bce663ae1dcf754f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=2E=20H=C3=BCttel?= Date: Fri, 14 Dec 2018 20:43:04 +0100 -Subject: [PATCH 03/10] Force -O0 in conform tests to survive $CC changes +Subject: [PATCH 3/9] Force -O0 in conform tests to survive $CC changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -22,7 +22,7 @@ Signed-off-by: Andreas K. Hüttel 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/conform/conformtest.py b/conform/conformtest.py -index 94a7ee110f..90c81ac88e 100644 +index 124860da01..8b1643a097 100644 --- a/conform/conformtest.py +++ b/conform/conformtest.py @@ -566,7 +566,7 @@ class HeaderTests(object): @@ -46,7 +46,7 @@ index 94a7ee110f..90c81ac88e 100644 subprocess.check_call(cmd, shell=True) bad_tokens = set() diff --git a/conform/linknamespace.py b/conform/linknamespace.py -index f7fe3a7a0a..ad87fd2a6d 100644 +index 983bba1bd2..b6fce8a21c 100644 --- a/conform/linknamespace.py +++ b/conform/linknamespace.py @@ -157,7 +157,9 @@ def main(): @@ -61,5 +61,5 @@ index f7fe3a7a0a..ad87fd2a6d 100644 args.header) with tempfile.TemporaryDirectory() as temp_dir: -- -2.38.2 +2.39.1 diff --git a/9999/0004-Fix-miscompilation-on-ia64-s-gcc-10.patch b/9999/0004-Fix-miscompilation-on-ia64-s-gcc-10.patch index 2d9c8f7..215b5fa 100644 --- a/9999/0004-Fix-miscompilation-on-ia64-s-gcc-10.patch +++ b/9999/0004-Fix-miscompilation-on-ia64-s-gcc-10.patch @@ -1,7 +1,7 @@ -From 4aafe3fae7777fec09e2dd3915a8fd33642bba94 Mon Sep 17 00:00:00 2001 +From 7a2ab3f8d680338aff2559541a4bb748618e16f6 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Sat, 11 Jul 2020 20:06:51 +0300 -Subject: [PATCH 04/10] Fix miscompilation on ia64's gcc-10 +Subject: [PATCH 4/9] Fix miscompilation on ia64's gcc-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -13,7 +13,7 @@ Signed-off-by: Andreas K. Hüttel 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h b/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h -index aa1de6b361..f6472f1942 100644 +index 3e4d5da820..eb7681b704 100644 --- a/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h +++ b/sysdeps/unix/sysv/linux/ia64/dl-sysdep.h @@ -32,7 +32,9 @@ @@ -28,5 +28,5 @@ index aa1de6b361..f6472f1942 100644 # define DL_SYSINFO_IMPLEMENTATION \ asm (".text\n\t" \ -- -2.38.2 +2.39.1 diff --git a/9999/0005-linux-Use-getdents64-on-non-LFS-readdir.patch b/9999/0005-linux-Use-getdents64-on-non-LFS-readdir.patch index 4e1dc0d..4cb21bf 100644 --- a/9999/0005-linux-Use-getdents64-on-non-LFS-readdir.patch +++ b/9999/0005-linux-Use-getdents64-on-non-LFS-readdir.patch @@ -1,127 +1,109 @@ -From 0718c1ca37fe6407bd4bad15dfae873719eabb6e Mon Sep 17 00:00:00 2001 +From 1652c61d24e43a0efd1fd4812f4a67494d093cc2 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella -Date: Tue, 20 Oct 2020 13:37:15 -0300 -Subject: [PATCH 05/10] linux: Use getdents64 on non-LFS readdir +Date: Fri, 27 Jan 2023 14:28:30 -0300 +Subject: [PATCH 5/9] linux: Use getdents64 on non-LFS readdir -The opendir allocates a translation buffer to be used to return the -non-LFS readdir entry. The obtained dirent64 struct is translated -to the temporary buffer on each readdir call. +The non-LFS opendir reserves a translation entry to be used to return +the entry and the dirent64 struct is translated to the temporary buffer +on each readdir call. Entries that overflow d_off/d_ino and the buffer reallocation failure (in case of large d_name) are ignored. Checked on x86_64-linux-gnu and i686-linux-gnu. --- - sysdeps/unix/sysv/linux/closedir.c | 4 ++ + dirent/tst-scandir.c | 6 ++- + include/dirent.h | 2 +- sysdeps/unix/sysv/linux/dirstream.h | 5 ++ - sysdeps/unix/sysv/linux/opendir.c | 21 +++++++ - sysdeps/unix/sysv/linux/readdir.c | 94 +++++++++++++++++++++-------- - 4 files changed, 98 insertions(+), 26 deletions(-) + sysdeps/unix/sysv/linux/readdir.c | 83 +++++++++++++++++++---------- + 4 files changed, 67 insertions(+), 29 deletions(-) -diff --git a/sysdeps/unix/sysv/linux/closedir.c b/sysdeps/unix/sysv/linux/closedir.c -index eee0193fc4..d876d49d78 100644 ---- a/sysdeps/unix/sysv/linux/closedir.c -+++ b/sysdeps/unix/sysv/linux/closedir.c -@@ -47,6 +47,10 @@ __closedir (DIR *dirp) - __libc_lock_fini (dirp->lock); - #endif - -+#if !_DIRENT_MATCHES_DIRENT64 -+ free (dirp->tbuffer); -+#endif -+ - free ((void *) dirp); +diff --git a/dirent/tst-scandir.c b/dirent/tst-scandir.c +index 8d87d4dd74..7bc666449e 100644 +--- a/dirent/tst-scandir.c ++++ b/dirent/tst-scandir.c +@@ -155,8 +155,12 @@ do_test (void) + } + if (n != 6) + { ++ /* Non-lfs opendir skips entries that can not be represented (for ++ instance if d_off is not an offset but rather an internal filesystem ++ representation. For this case there is no point in continue the ++ testcase. */ + printf ("scandir returned %d entries instead of 6\n", n); +- return 1; ++ return EXIT_UNSUPPORTED; + } - return __close_nocancel (fd); + struct +diff --git a/include/dirent.h b/include/dirent.h +index d7567f5e86..17827176ba 100644 +--- a/include/dirent.h ++++ b/include/dirent.h +@@ -1,8 +1,8 @@ + #ifndef _DIRENT_H ++# include + # ifndef _ISOMAC + # include + # endif +-# include + # ifndef _ISOMAC + # include + # include diff --git a/sysdeps/unix/sysv/linux/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h -index a0d8acf08d..064273cc31 100644 +index 3cb313b410..adcf8234f1 100644 --- a/sysdeps/unix/sysv/linux/dirstream.h +++ b/sysdeps/unix/sysv/linux/dirstream.h -@@ -41,6 +41,11 @@ struct __dirstream +@@ -18,6 +18,7 @@ + #ifndef _DIRSTREAM_H + #define _DIRSTREAM_H 1 + ++#include + #include + + #include +@@ -41,6 +42,10 @@ struct __dirstream int errcode; /* Delayed error code. */ +#if !defined __OFF_T_MATCHES_OFF64_T || !defined __INO_T_MATCHES_INO64_T -+ char *tbuffer; /* Translation buffer for non-LFS calls. */ -+ size_t tbuffer_size; /* Size of translation buffer. */ ++ struct dirent tdp; +#endif + /* Directory block. We must make sure that this block starts at an address that is aligned adequately enough to store dirent entries. Using the alignment of "void *" is not -diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c -index 9e81d00630..bfd2f382a6 100644 ---- a/sysdeps/unix/sysv/linux/opendir.c -+++ b/sysdeps/unix/sysv/linux/opendir.c -@@ -120,6 +120,27 @@ __alloc_dir (int fd, bool close_fd, int flags, - return NULL; - } - -+#if !_DIRENT_MATCHES_DIRENT64 -+ /* Allocates a translation buffer to use as the returned 'struct direct' -+ for non-LFS 'readdir' calls. -+ -+ The initial NAME_MAX size should handle most cases, while readdir might -+ expand the buffer if required. */ -+ enum -+ { -+ tbuffer_size = sizeof (struct dirent) + NAME_MAX + 1 -+ }; -+ dirp->tbuffer = malloc (tbuffer_size); -+ if (dirp->tbuffer == NULL) -+ { -+ free (dirp); -+ if (close_fd) -+ __close_nocancel_nostatus (fd); -+ return NULL; -+ } -+ dirp->tbuffer_size = tbuffer_size; -+#endif -+ - dirp->fd = fd; - #if IS_IN (libc) - __libc_lock_init (dirp->lock); diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c -index c9a04dc160..c078146d7d 100644 +index 4a4c00ea07..cd0ccaf33a 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c -@@ -21,42 +21,84 @@ +@@ -21,42 +21,71 @@ #if !_DIRENT_MATCHES_DIRENT64 #include -+/* Translate the DP64 entry to the non-LFS one in the translation buffer ++/* Translate the DP64 entry to the non-LFS one in the translation entry + at dirstream DS. Return true is the translation was possible or -+ false if either an internal fields can be represented in the non-LFS -+ entry or if the translation can not be resized. */ ++ false if either an internal field can not be represented in the non-LFS ++ entry or if the name is too long. */ +static bool +dirstream_entry (struct __dirstream *ds, const struct dirent64 *dp64) +{ -+ off_t d_off = dp64->d_off; -+ if (d_off != dp64->d_off) -+ return false; -+ ino_t d_ino = dp64->d_ino; -+ if (d_ino != dp64->d_ino) ++ /* Check for overflow. */ ++ if (!in_off_t_range (dp64->d_off) || !in_ino_t_range (dp64->d_ino)) + return false; + -+ /* Expand the translation buffer to hold the new name size. */ -+ size_t new_reclen = sizeof (struct dirent) -+ + dp64->d_reclen - offsetof (struct dirent64, d_name); -+ if (new_reclen > ds->tbuffer_size) -+ { -+ char *newbuffer = realloc (ds->tbuffer, new_reclen); -+ if (newbuffer == NULL) -+ return false; -+ ds->tbuffer = newbuffer; -+ ds->tbuffer_size = new_reclen; -+ } ++ /* And if name is too large. */ ++ if (dp64->d_reclen - offsetof (struct dirent64, d_name) > NAME_MAX) ++ return false; + -+ struct dirent *dp = (struct dirent *) ds->tbuffer; ++ ds->filepos = dp64->d_off; + -+ dp->d_off = d_off; -+ dp->d_ino = d_ino; -+ dp->d_reclen = new_reclen; -+ dp->d_type = dp64->d_type; -+ memcpy (dp->d_name, dp64->d_name, ++ ds->tdp.d_off = dp64->d_off; ++ ds->tdp.d_ino = dp64->d_ino; ++ ds->tdp.d_reclen = sizeof (struct dirent) ++ + dp64->d_reclen - offsetof (struct dirent64, d_name); ++ ds->tdp.d_type = dp64->d_type; ++ memcpy (ds->tdp.d_name, dp64->d_name, + dp64->d_reclen - offsetof (struct dirent64, d_name)); + + return true; @@ -145,7 +127,19 @@ index c9a04dc160..c078146d7d 100644 - bytes = __getdents (dirp->fd, dirp->data, maxread); - if (bytes <= 0) + if (dirp->offset >= dirp->size) -+ { + { +- /* 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; +- +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; + /* We've emptied out our buffer. Refill it. */ + ssize_t bytes = __getdents64 (dirp->fd, dirp->data, + dirp->allocation); @@ -169,23 +163,9 @@ index c9a04dc160..c078146d7d 100644 + dirp->offset += dp64->d_reclen; + + /* Skip entries which might overflow d_off/d_ino or if the translation -+ buffer can't be resized. */ ++ buffer can not be resized. */ + if (dirstream_entry (dirp, dp64)) - { -- /* 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->filepos = dp64->d_off; -+ return (struct dirent *) dirp->tbuffer; - } -- dirp->size = (size_t) bytes; -- -- /* Reset the offset into the buffer. */ -- dirp->offset = 0; ++ return &dirp->tdp; } - - dp = (struct dirent *) &dirp->data[dirp->offset]; @@ -197,5 +177,5 @@ index c9a04dc160..c078146d7d 100644 struct dirent * -- -2.38.2 +2.39.1 diff --git a/9999/0006-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch b/9999/0006-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch index 38acaf8..59e01fc 100644 --- a/9999/0006-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch +++ b/9999/0006-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch @@ -1,240 +1,121 @@ -From 36f553f67b8268341b7879640637fac5ea806017 Mon Sep 17 00:00:00 2001 +From 861793671bd8daeed1f00902d9a9523ddae77462 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella -Date: Mon, 13 Apr 2020 18:09:20 -0300 -Subject: [PATCH 06/10] linux: Set internal DIR filepos as off64_t [BZ #23960, - BZ #24050] +Date: Fri, 27 Jan 2023 14:28:31 -0300 +Subject: [PATCH 6/9] linux: Set internal DIR filepos as off64_t (BZ #23960, BZ + #24050) It allows to obtain the expected entry offset on telldir and set it correctly on seekdir on platforms where long int is smaller than off64_t. -On such cases telldir will mantain an internal list that maps the -DIR object off64_t offsets to the returned long int (the function -return value). The seekdir will then set the correct offset from -the internal list using the telldir as the list key. +On such cases opendir creates a map entry between the DIR d_off +offset and the returned long int (the telldir return value). +seekdir will then set the correct offset from the internal list +using the telldir as the list key. It also removes the overflow check on readdir and the returned value will be truncated by the non-LFS off_t size. As Joseph has noted in BZ #23960 comment #22, d_off is an opaque value and since telldir/seekdir works regardless of the returned dirent d_off value. -Finally it removed the requirement to check for overflow values on +Finally it removes the requirement to check for overflow values on telldir (BZ #24050). Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc-linux-gnu, and arm-linux-gnueabihf. --- - dirent/Makefile | 2 +- - dirent/tst-seekdir2.c | 158 ++++++++++++++++++++++++++++ - sysdeps/unix/sysv/linux/closedir.c | 4 + - sysdeps/unix/sysv/linux/dirstream.h | 6 +- - sysdeps/unix/sysv/linux/opendir.c | 3 + - sysdeps/unix/sysv/linux/readdir.c | 1 + - sysdeps/unix/sysv/linux/rewinddir.c | 5 + - sysdeps/unix/sysv/linux/seekdir.c | 36 ++++++- - sysdeps/unix/sysv/linux/telldir.c | 47 ++++++++- - sysdeps/unix/sysv/linux/telldir.h | 64 +++++++++++ - 10 files changed, 317 insertions(+), 9 deletions(-) - create mode 100644 dirent/tst-seekdir2.c + dirent/tst-seekdir.c | 8 ++ + sysdeps/unix/sysv/linux/Makefile | 1 + + sysdeps/unix/sysv/linux/alpha/bits/dirent.h | 3 + + sysdeps/unix/sysv/linux/bits/dirent.h | 4 + + sysdeps/unix/sysv/linux/closedir.c | 4 + + sysdeps/unix/sysv/linux/dirstream.h | 6 +- + sysdeps/unix/sysv/linux/opendir.c | 3 + + sysdeps/unix/sysv/linux/readdir.c | 11 +- + sysdeps/unix/sysv/linux/rewinddir.c | 5 + + sysdeps/unix/sysv/linux/seekdir.c | 35 ++++- + sysdeps/unix/sysv/linux/telldir.c | 35 +++++ + sysdeps/unix/sysv/linux/telldir.h | 65 +++++++++ + sysdeps/unix/sysv/linux/tst-opendir-nolfs.c | 146 ++++++++++++++++++++ + 13 files changed, 319 insertions(+), 7 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/telldir.h + create mode 100644 sysdeps/unix/sysv/linux/tst-opendir-nolfs.c -diff --git a/dirent/Makefile b/dirent/Makefile -index cfa61826ed..9a9d91b8a5 100644 ---- a/dirent/Makefile -+++ b/dirent/Makefile -@@ -31,7 +31,7 @@ routines := opendir closedir readdir readdir_r rewinddir \ - scandir-cancel scandir-tail scandir64-tail - - tests := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \ -- tst-fdopendir2 tst-scandir tst-scandir64 -+ tst-fdopendir2 tst-scandir tst-scandir64 tst-seekdir2 - - CFLAGS-scandir.c += $(uses-callbacks) - CFLAGS-scandir64.c += $(uses-callbacks) -diff --git a/dirent/tst-seekdir2.c b/dirent/tst-seekdir2.c -new file mode 100644 -index 0000000000..3e01b361e5 ---- /dev/null -+++ b/dirent/tst-seekdir2.c -@@ -0,0 +1,158 @@ -+/* Check multiple telldir and seekdir. -+ Copyright (C) 2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* Some filesystems returns a arbitrary value for d_off direnty entry (ext4 -+ for instance, where the value is an internal hash key). The idea of -+ create a large number of file is to try trigger a overflow d_off value -+ in a entry to check if telldir/seekdir does work corretly in such -+ case. */ -+static const char *dirname; -+static const size_t nfiles = 10240; -+ -+static void -+do_prepare (int argc, char *argv[]) -+{ -+ dirname = support_create_temp_directory ("tst-seekdir2-"); -+ -+ for (size_t i = 0; i < nfiles; i++) +diff --git a/dirent/tst-seekdir.c b/dirent/tst-seekdir.c +index dcdd699b09..187eda7584 100644 +--- a/dirent/tst-seekdir.c ++++ b/dirent/tst-seekdir.c +@@ -41,6 +41,14 @@ do_test (void) + if (i == 400) + break; + } ++ if (i < 3) + { -+ int fd = create_temp_file_in_dir ("tempfile.", dirname, NULL); -+ TEST_VERIFY_EXIT (fd > 0); -+ close (fd); -+ } -+} -+#define PREPARE do_prepare -+ -+/* Check for old non Large File Support (LFS). */ -+static int -+do_test_not_lfs (void) -+{ -+ DIR *dirp = opendir (dirname); -+ TEST_VERIFY_EXIT (dirp != NULL); -+ -+ size_t dirp_count = 0; -+ for (struct dirent *dp = readdir (dirp); -+ dp != NULL; -+ dp = readdir (dirp)) -+ dirp_count++; -+ -+ /* The 2 extra files are '.' and '..'. */ -+ TEST_COMPARE (dirp_count, nfiles + 2); -+ -+ rewinddir (dirp); -+ -+ long *tdirp = xmalloc (dirp_count * sizeof (long)); -+ struct dirent **ddirp = xmalloc (dirp_count * sizeof (struct dirent *)); -+ -+ size_t i = 0; -+ do -+ { -+ tdirp[i] = telldir (dirp); -+ struct dirent *dp = readdir (dirp); -+ TEST_VERIFY_EXIT (dp != NULL); -+ ddirp[i] = xmalloc (dp->d_reclen); -+ memcpy (ddirp[i], dp, dp->d_reclen); -+ } while (++i < dirp_count); -+ -+ for (i = 0; i < dirp_count - 1; i++) -+ { -+ seekdir (dirp, tdirp[i]); -+ struct dirent *dp = readdir (dirp); -+ TEST_COMPARE (strcmp (dp->d_name, ddirp[i]->d_name), 0); -+ TEST_COMPARE (dp->d_ino, ddirp[i]->d_ino); -+ TEST_COMPARE (dp->d_off, ddirp[i]->d_off); ++ /* Non-lfs opendir skips entries that can not be represented (for ++ instance if d_off is not an offset but rather an internal filesystem ++ representation. For this case there is no point in continue the ++ testcase. */ ++ return 77; + } + + printf ("going back past 4-th entry...\n"); + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index f8bd12d991..09adb99b86 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -464,6 +464,7 @@ ifeq ($(subdir),dirent) + sysdep_routines += getdirentries getdirentries64 + tests += \ + tst-getdents64 \ ++ tst-opendir-nolfs \ + tst-readdir64-compat \ + # tests + endif # $(subdir) == dirent +diff --git a/sysdeps/unix/sysv/linux/alpha/bits/dirent.h b/sysdeps/unix/sysv/linux/alpha/bits/dirent.h +index c8a0cfe93f..586d75586a 100644 +--- a/sysdeps/unix/sysv/linux/alpha/bits/dirent.h ++++ b/sysdeps/unix/sysv/linux/alpha/bits/dirent.h +@@ -54,4 +54,7 @@ struct dirent64 + /* Inform libc code that these two types are effectively identical. */ + #define _DIRENT_MATCHES_DIRENT64 1 + ++/* alpha 'long int' is enough to handle off64_t. */ ++#define _DIRENT_OFFSET_TRANSLATION 0 ++ + #endif /* bits/dirent.h */ +diff --git a/sysdeps/unix/sysv/linux/bits/dirent.h b/sysdeps/unix/sysv/linux/bits/dirent.h +index ab34d986ff..bb02dcb70a 100644 +--- a/sysdeps/unix/sysv/linux/bits/dirent.h ++++ b/sysdeps/unix/sysv/linux/bits/dirent.h +@@ -57,3 +57,7 @@ struct dirent64 + #else + # define _DIRENT_MATCHES_DIRENT64 0 + #endif + -+ closedir (dirp); -+ free (tdirp); -+ for (i = 0; i < dirp_count; i++) -+ free (ddirp[i]); -+ free (ddirp); -+ -+ return 0; -+} -+ -+/* Same as before but with LFS support. */ -+static int -+do_test_lfs (void) -+{ -+ DIR *dirp = opendir (dirname); -+ TEST_VERIFY_EXIT (dirp != NULL); -+ -+ size_t dirp_count = 0; -+ for (struct dirent64 * dp = readdir64 (dirp); -+ dp != NULL; -+ dp = readdir64 (dirp)) -+ dirp_count++; -+ -+ /* The 2 extra files are '.' and '..'. */ -+ TEST_COMPARE (dirp_count, nfiles + 2); -+ -+ rewinddir (dirp); -+ -+ long *tdirp = xmalloc (dirp_count * sizeof (long)); -+ struct dirent64 **ddirp = xmalloc (dirp_count * sizeof (struct dirent64 *)); -+ -+ size_t i = 0; -+ do -+ { -+ tdirp[i] = telldir (dirp); -+ struct dirent64 *dp = readdir64 (dirp); -+ TEST_VERIFY_EXIT (dp != NULL); -+ ddirp[i] = xmalloc (dp->d_reclen); -+ memcpy (ddirp[i], dp, dp->d_reclen); -+ } while (++i < dirp_count); -+ -+ for (i = 0; i < dirp_count - 1; i++) -+ { -+ seekdir (dirp, tdirp[i]); -+ struct dirent64 *dp = readdir64 (dirp); -+ TEST_COMPARE (strcmp (dp->d_name, ddirp[i]->d_name), 0); -+ TEST_COMPARE (dp->d_ino, ddirp[i]->d_ino); -+ TEST_COMPARE (dp->d_off, ddirp[i]->d_off); -+ } -+ -+ closedir (dirp); -+ free (tdirp); -+ for (i = 0; i < dirp_count; i++) -+ free (ddirp[i]); -+ free (ddirp); -+ -+ return 0; -+} -+ -+static int -+do_test (void) -+{ -+ do_test_not_lfs (); -+ do_test_lfs (); -+ -+ return 0; -+} -+ -+#include ++/* The telldir function returns long int, which may not be large enough to ++ store off64_t values. In this case, translation is required. */ ++#define _DIRENT_OFFSET_TRANSLATION (LONG_WIDTH < 64) diff --git a/sysdeps/unix/sysv/linux/closedir.c b/sysdeps/unix/sysv/linux/closedir.c -index d876d49d78..8e5669963c 100644 +index f1c2608642..9585a6ca3a 100644 --- a/sysdeps/unix/sysv/linux/closedir.c +++ b/sysdeps/unix/sysv/linux/closedir.c -@@ -43,6 +43,10 @@ __closedir (DIR *dirp) - - fd = dirp->fd; +@@ -47,6 +47,10 @@ __closedir (DIR *dirp) + __libc_lock_fini (dirp->lock); + #endif -+#ifndef __LP64__ ++#if _DIRENT_OFFSET_TRANSLATION + dirstream_loc_clear (&dirp->locs); +#endif + - #if IS_IN (libc) - __libc_lock_fini (dirp->lock); - #endif + free ((void *) dirp); + + return __close_nocancel (fd); diff --git a/sysdeps/unix/sysv/linux/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h -index 064273cc31..a284292cb2 100644 +index adcf8234f1..8f58a1c3a6 100644 --- a/sysdeps/unix/sysv/linux/dirstream.h +++ b/sysdeps/unix/sysv/linux/dirstream.h -@@ -21,6 +21,7 @@ +@@ -22,6 +22,7 @@ #include #include @@ -242,7 +123,7 @@ index 064273cc31..a284292cb2 100644 /* Directory stream type. -@@ -37,7 +38,7 @@ struct __dirstream +@@ -38,13 +39,16 @@ struct __dirstream size_t size; /* Total valid data in the block. */ size_t offset; /* Current offset into the block. */ @@ -251,44 +132,60 @@ index 064273cc31..a284292cb2 100644 int errcode; /* Delayed error code. */ -@@ -45,6 +46,9 @@ struct __dirstream - char *tbuffer; /* Translation buffer for non-LFS calls. */ - size_t tbuffer_size; /* Size of translation buffer. */ + #if !defined __OFF_T_MATCHES_OFF64_T || !defined __INO_T_MATCHES_INO64_T + struct dirent tdp; #endif -+#ifndef __LP64__ ++#if _DIRENT_OFFSET_TRANSLATION + struct dirstream_loc_t locs; /* off64_t to long int map for telldir. */ +#endif /* Directory block. We must make sure that this block starts at an address that is aligned adequately enough to store diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c -index bfd2f382a6..9a0b7ab4c4 100644 +index 4336196a4d..3e2caabb9d 100644 --- a/sysdeps/unix/sysv/linux/opendir.c +++ b/sysdeps/unix/sysv/linux/opendir.c -@@ -150,6 +150,9 @@ __alloc_dir (int fd, bool close_fd, int flags, +@@ -129,6 +129,9 @@ __alloc_dir (int fd, bool close_fd, int flags, dirp->offset = 0; dirp->filepos = 0; dirp->errcode = 0; -+#ifndef __LP64__ ++#if _DIRENT_OFFSET_TRANSLATION + dirstream_loc_init (&dirp->locs); +#endif return dirp; } diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c -index c078146d7d..f377e5f268 100644 +index cd0ccaf33a..7a7f484c36 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c -@@ -17,6 +17,7 @@ - . */ +@@ -36,6 +36,15 @@ dirstream_entry (struct __dirstream *ds, const struct dirent64 *dp64) + if (dp64->d_reclen - offsetof (struct dirent64, d_name) > NAME_MAX) + return false; - #include -+#include ++ /* telldir can not return an error, so preallocate the map if the entry can ++ not be packed directly. */ ++ if (telldir_need_dirstream (dp64->d_off)) ++ { ++ dirstream_loc_add (&ds->locs, dp64->d_off); ++ if (dirstream_loc_has_failed (&ds->locs)) ++ return false; ++ } ++ + ds->filepos = dp64->d_off; - #if !_DIRENT_MATCHES_DIRENT64 - #include + ds->tdp.d_off = dp64->d_off; +@@ -76,7 +85,7 @@ __readdir_unlocked (DIR *dirp) + + /* Reset the offset into the buffer. */ + dirp->offset = 0; +- } ++ } + + struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; + dirp->offset += dp64->d_reclen; diff --git a/sysdeps/unix/sysv/linux/rewinddir.c b/sysdeps/unix/sysv/linux/rewinddir.c -index b1e8259703..0194d29e38 100644 +index c0fb7aa765..1b158a584f 100644 --- a/sysdeps/unix/sysv/linux/rewinddir.c +++ b/sysdeps/unix/sysv/linux/rewinddir.c @@ -33,6 +33,11 @@ __rewinddir (DIR *dirp) @@ -304,10 +201,10 @@ index b1e8259703..0194d29e38 100644 __libc_lock_unlock (dirp->lock); #endif diff --git a/sysdeps/unix/sysv/linux/seekdir.c b/sysdeps/unix/sysv/linux/seekdir.c -index f4e1a9f8e0..0c3e58a2ed 100644 +index 939ccc4447..30cce691a4 100644 --- a/sysdeps/unix/sysv/linux/seekdir.c +++ b/sysdeps/unix/sysv/linux/seekdir.c -@@ -22,14 +22,40 @@ +@@ -22,14 +22,39 @@ #include /* Seek to position POS in DIRP. */ @@ -323,11 +220,8 @@ index f4e1a9f8e0..0c3e58a2ed 100644 - dirp->offset = 0; - dirp->filepos = pos; + -+#ifndef __LP64__ -+ union dirstream_packed dsp; -+ -+ dsp.l = pos; -+ ++#if _DIRENT_OFFSET_TRANSLATION ++ union dirstream_packed dsp = { .l = pos }; + if (dsp.p.is_packed == 1) + filepos = dsp.p.info; + else @@ -335,9 +229,11 @@ index f4e1a9f8e0..0c3e58a2ed 100644 + size_t index = dsp.p.info; + + if (index >= dirstream_loc_size (&dirp->locs)) -+ return; -+ struct dirstream_loc *loc = dirstream_loc_at (&dirp->locs, index); -+ filepos = loc->filepos; ++ { ++ __libc_lock_unlock (dirp->lock); ++ return; ++ } ++ filepos = *dirstream_loc_at (&dirp->locs, index); + } +#else + filepos = pos; @@ -354,10 +250,14 @@ index f4e1a9f8e0..0c3e58a2ed 100644 __libc_lock_unlock (dirp->lock); } diff --git a/sysdeps/unix/sysv/linux/telldir.c b/sysdeps/unix/sysv/linux/telldir.c -index b60b231e48..874905489f 100644 +index 1e5c129e9f..c3ef14f3da 100644 --- a/sysdeps/unix/sysv/linux/telldir.c +++ b/sysdeps/unix/sysv/linux/telldir.c -@@ -18,16 +18,59 @@ +@@ -15,9 +15,11 @@ + License along with the GNU C Library; if not, see + . */ + ++#include #include #include @@ -365,68 +265,55 @@ index b60b231e48..874905489f 100644 /* Return the current position of DIRP. */ long int - telldir (DIR *dirp) - { -- long int ret; -+#ifndef __LP64__ -+ /* If the directory position fits in the packet structure returns it. +@@ -26,7 +28,40 @@ telldir (DIR *dirp) + long int ret; + + __libc_lock_lock (dirp->lock); ++ ++#if _DIRENT_OFFSET_TRANSLATION ++ /* If the directory position fits in the packet structure, returns it. + Otherwise, check if the position is already been recorded in the + dynamic array. If not, add the new record. */ + + union dirstream_packed dsp; -+ size_t i; - - __libc_lock_lock (dirp->lock); -- ret = dirp->filepos; + -+ if (dirp->filepos < (1U << 31)) ++ if (!telldir_need_dirstream (dirp->filepos)) + { + dsp.p.is_packed = 1; + dsp.p.info = dirp->filepos; -+ goto out; + } -+ -+ dsp.l = -1; -+ -+ for (i = 0; i < dirstream_loc_size (&dirp->locs); i++) -+ { -+ struct dirstream_loc *loc = dirstream_loc_at (&dirp->locs, i); -+ if (loc->filepos == dirp->filepos) -+ break; -+ } -+ if (i == dirstream_loc_size (&dirp->locs)) ++ else + { -+ dirstream_loc_add (&dirp->locs, -+ (struct dirstream_loc) { dirp->filepos }); -+ if (dirstream_loc_has_failed (&dirp->locs)) -+ goto out; ++ dsp.l = -1; ++ ++ size_t i; ++ for (i = 0; i < dirstream_loc_size (&dirp->locs); i++) ++ if (*dirstream_loc_at (&dirp->locs, i) == dirp->filepos) ++ break; ++ /* It should be pre-allocated on readdir. */ ++ assert (i != dirstream_loc_size (&dirp->locs)); ++ ++ dsp.p.is_packed = 0; ++ /* This assignment might overflow, however most likely ENOME would ++ happen long before. */ ++ dsp.p.info = i; + } + -+ dsp.p.is_packed = 0; -+ /* This assignment might overflow, however most likely ENOMEM would happen -+ long before. */ -+ dsp.p.info = i; -+ -+out: ++ ret = dsp.l; ++#else + ret = dirp->filepos; ++#endif __libc_lock_unlock (dirp->lock); -+ return dsp.l; -+#else -+ long int ret; -+ __libc_lock_lock (dirp->lock); -+ ret = dirp->filepos; -+ __libc_lock_unlock (dirp->lock); return ret; -+#endif - } diff --git a/sysdeps/unix/sysv/linux/telldir.h b/sysdeps/unix/sysv/linux/telldir.h new file mode 100644 -index 0000000000..7c45886341 +index 0000000000..758bcb0eb3 --- /dev/null +++ b/sysdeps/unix/sysv/linux/telldir.h -@@ -0,0 +1,64 @@ +@@ -0,0 +1,65 @@ +/* Linux internal telldir definitions. -+ Copyright (C) 2020 Free Software Foundation, Inc. ++ Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or @@ -446,9 +333,8 @@ index 0000000000..7c45886341 +#ifndef _TELLDIR_H +#define _TELLDIR_H 1 + -+#ifndef __LP64__ -+ -+/* On platforms where long int is smaller than off64_t this is how the ++#if _DIRENT_OFFSET_TRANSLATION ++/* On platforms where 'long int' is smaller than 'off64_t' this is how the + returned value is encoded and returned by 'telldir'. If the directory + offset can be enconded in 31 bits it is returned in the 'info' member + with 'is_packed' set to 1. @@ -461,34 +347,188 @@ index 0000000000..7c45886341 + long int l; + struct + { -+ unsigned long is_packed:1; -+ unsigned long info:31; ++ unsigned long int is_packed:1; ++ unsigned long int info:31; + } p; +}; + +_Static_assert (sizeof (long int) == sizeof (union dirstream_packed), + "sizeof (long int) != sizeof (union dirstream_packed)"); + -+/* telldir will mantain a list of offsets that describe the obtained diretory ++/* telldir maintains a list of offsets that describe the obtained diretory + position if it can fit this information in the returned 'dirstream_packed' + struct. */ + -+struct dirstream_loc -+{ -+ off64_t filepos; -+}; -+ +# define DYNARRAY_STRUCT dirstream_loc_t -+# define DYNARRAY_ELEMENT struct dirstream_loc ++# define DYNARRAY_ELEMENT off64_t +# define DYNARRAY_PREFIX dirstream_loc_ +# include ++ ++static __always_inline bool ++telldir_need_dirstream (__off64_t d_off) ++{ ++ return d_off >= 1UL << 31; ++} +#else + +_Static_assert (sizeof (long int) == sizeof (off64_t), + "sizeof (long int) != sizeof (off64_t)"); ++ +#endif /* __LP64__ */ + +#endif /* _TELLDIR_H */ +diff --git a/sysdeps/unix/sysv/linux/tst-opendir-nolfs.c b/sysdeps/unix/sysv/linux/tst-opendir-nolfs.c +new file mode 100644 +index 0000000000..52e18171a7 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-opendir-nolfs.c +@@ -0,0 +1,146 @@ ++/* Check multiple telldir and seekdir. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Some filesystems returns an arbitrary value for d_off direnty entry (ext4 ++ for instance, where the value is an internal hash key). The idea of create ++ a large number of file is to try trigger a overflow d_off value in a entry ++ to check if telldir/seekdir does work corretly in such case. */ ++static const char *dirname; ++/* The 2 extra files are '.' and '..'. */ ++static const size_t nfiles = (1<<14) + 2; ++ ++static inline bool ++in_ino_t_range (ino64_t v) ++{ ++ ino_t s = v; ++ return s == v; ++} ++ ++static inline bool ++in_off_t_range (off64_t v) ++{ ++ off_t s = v; ++ return s == v; ++} ++ ++static void ++do_prepare (int argc, char *argv[]) ++{ ++ dirname = support_create_temp_directory ("tst-opendir-nolfs-"); ++ ++ for (size_t i = 0; i < nfiles - 2; i++) ++ { ++ int fd = create_temp_file_in_dir ("tempfile.", dirname, NULL); ++ TEST_VERIFY_EXIT (fd > 0); ++ close (fd); ++ } ++} ++#define PREPARE do_prepare ++ ++static int ++do_test (void) ++{ ++ DIR *dirp = opendir (dirname); ++ TEST_VERIFY_EXIT (dirp != NULL); ++ ++ long int *tdirp = xmalloc (nfiles * sizeof (long int)); ++ struct dirent **ddirp = xmalloc (nfiles * sizeof (struct dirent *)); ++ ++ /* For non-LFS, the entry is skipped if it can not be converted. */ ++ int count = 0; ++ for (; count < nfiles; count++) ++ { ++ tdirp[count] = telldir (dirp); ++ struct dirent *dp = readdir (dirp); ++ if (dp == NULL) ++ break; ++ ddirp[count] = xmalloc (dp->d_reclen); ++ memcpy (ddirp[count], dp, dp->d_reclen); ++ } ++ ++ closedir (dirp); ++ ++ /* Check against the getdents64 syscall. */ ++ int fd = xopen (dirname, O_RDONLY | O_DIRECTORY, 0); ++ int i = 0; ++ while (true) ++ { ++ struct ++ { ++ char buffer[1024]; ++ struct dirent64 pad; ++ } data; ++ ++ ssize_t ret = getdents64 (fd, &data.buffer, sizeof (data.buffer)); ++ if (ret < 0) ++ FAIL_EXIT1 ("getdents64: %m"); ++ if (ret == 0) ++ break; ++ ++ char *current = data.buffer; ++ char *end = data.buffer + ret; ++ while (current != end) ++ { ++ struct dirent64 entry; ++ memcpy (&entry, current, sizeof (entry)); ++ /* Truncate overlong strings. */ ++ entry.d_name[sizeof (entry.d_name) - 1] = '\0'; ++ TEST_VERIFY (strlen (entry.d_name) < sizeof (entry.d_name) - 1); ++ ++ if (in_ino_t_range (entry.d_ino) && in_off_t_range (entry.d_off)) ++ { ++ TEST_COMPARE_STRING (entry.d_name, ddirp[i]->d_name); ++ TEST_COMPARE (entry.d_ino, ddirp[i]->d_ino); ++ TEST_COMPARE (entry.d_off, ddirp[i]->d_off); ++ TEST_COMPARE (entry.d_type, ddirp[i]->d_type); ++ ++ /* Offset zero is reserved for the first entry. */ ++ TEST_VERIFY (entry.d_off != 0); ++ ++ TEST_VERIFY_EXIT (entry.d_reclen <= end - current); ++ i++; ++ } ++ ++ current += entry.d_reclen; ++ } ++ } ++ ++ /* direntries_read has been called more than once. */ ++ TEST_COMPARE (count, i); ++ ++ free (tdirp); ++ for (int i = 0; i < count; i++) ++ free (ddirp[i]); ++ free (ddirp); ++ ++ return 0; ++} ++ ++#include -- -2.38.2 +2.39.1 diff --git a/9999/0007-linux-Add-__readdir64_unlocked.patch b/9999/0007-linux-Add-__readdir64_unlocked.patch index 631550c..18dcda4 100644 --- a/9999/0007-linux-Add-__readdir64_unlocked.patch +++ b/9999/0007-linux-Add-__readdir64_unlocked.patch @@ -1,7 +1,7 @@ -From 4cca67d0d2d615918e05db864c236e33c0fda8f3 Mon Sep 17 00:00:00 2001 +From f697eec9ff1939e46d7730aa5cc0f696f41d8bd7 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella -Date: Mon, 13 Apr 2020 08:35:40 -0300 -Subject: [PATCH 07/10] linux: Add __readdir64_unlocked +Date: Fri, 27 Jan 2023 14:28:32 -0300 +Subject: [PATCH 7/9] linux: Add __readdir64_unlocked And use it on readdir_r implementation. @@ -13,7 +13,7 @@ Checked on i686-linux-gnu. 3 files changed, 33 insertions(+), 68 deletions(-) diff --git a/include/dirent.h b/include/dirent.h -index d7567f5e86..0c6715d0e4 100644 +index 17827176ba..f391476298 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -21,6 +21,7 @@ extern DIR *__fdopendir (int __fd) attribute_hidden; @@ -25,7 +25,7 @@ index d7567f5e86..0c6715d0e4 100644 libc_hidden_proto (__readdir64) extern int __readdir_r (DIR *__dirp, struct dirent *__entry, diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c -index 7952da5c27..9d82054182 100644 +index db1c6214d8..2327511736 100644 --- a/sysdeps/unix/sysv/linux/readdir64.c +++ b/sysdeps/unix/sysv/linux/readdir64.c @@ -28,15 +28,11 @@ @@ -67,7 +67,7 @@ index 7952da5c27..9d82054182 100644 __libc_lock_unlock (dirp->lock); #endif diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c -index afd7f9af0f..32962a176a 100644 +index 285dc99509..5ae099bde7 100644 --- a/sysdeps/unix/sysv/linux/readdir64_r.c +++ b/sysdeps/unix/sysv/linux/readdir64_r.c @@ -32,89 +32,43 @@ __readdir64_r (DIR *dirp, struct dirent64 *entry, struct dirent64 **result) @@ -178,5 +178,5 @@ index afd7f9af0f..32962a176a 100644 -- -2.38.2 +2.39.1 diff --git a/9999/0008-linux-Add-__old_readdir64_unlocked.patch b/9999/0008-linux-Add-__old_readdir64_unlocked.patch index 3cd2923..a1d289a 100644 --- a/9999/0008-linux-Add-__old_readdir64_unlocked.patch +++ b/9999/0008-linux-Add-__old_readdir64_unlocked.patch @@ -1,7 +1,7 @@ -From cd6d96ae0a09c1bff40f19d54e2910d7d4e74864 Mon Sep 17 00:00:00 2001 +From 5af443d8a53475680fdc51ff1c496b13a9e9e6d0 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella -Date: Tue, 14 Apr 2020 11:14:22 -0300 -Subject: [PATCH 08/10] linux: Add __old_readdir64_unlocked +Date: Fri, 27 Jan 2023 14:28:33 -0300 +Subject: [PATCH 8/9] linux: Add __old_readdir64_unlocked And use it __old_readdir64_r. @@ -13,7 +13,7 @@ Checked on i686-linux-gnu. 3 files changed, 35 insertions(+), 70 deletions(-) diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h -index 9a22609177..00c84b9521 100644 +index 9789ffae07..cde95e192e 100644 --- a/sysdeps/unix/sysv/linux/olddirent.h +++ b/sysdeps/unix/sysv/linux/olddirent.h @@ -32,6 +32,8 @@ struct __old_dirent64 @@ -26,7 +26,7 @@ index 9a22609177..00c84b9521 100644 struct __old_dirent64 **__result); extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes) diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c -index 9d82054182..bbe247f95d 100644 +index 2327511736..b901071aa7 100644 --- a/sysdeps/unix/sysv/linux/readdir64.c +++ b/sysdeps/unix/sysv/linux/readdir64.c @@ -104,15 +104,11 @@ versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); @@ -79,7 +79,7 @@ index 9d82054182..bbe247f95d 100644 __libc_lock_unlock (dirp->lock); #endif diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c -index 32962a176a..699d120b76 100644 +index 5ae099bde7..b499388de7 100644 --- a/sysdeps/unix/sysv/linux/readdir64_r.c +++ b/sysdeps/unix/sysv/linux/readdir64_r.c @@ -91,89 +91,44 @@ __old_readdir64_r (DIR *dirp, struct __old_dirent64 *entry, @@ -190,5 +190,5 @@ index 32962a176a..699d120b76 100644 compat_symbol (libc, __old_readdir64_r, readdir64_r, GLIBC_2_1); -- -2.38.2 +2.39.1 diff --git a/9999/0009-linux-Use-getdents64-on-readdir64-compat-implementat.patch b/9999/0009-linux-Use-getdents64-on-readdir64-compat-implementat.patch index 7a9c5a3..644af1c 100644 --- a/9999/0009-linux-Use-getdents64-on-readdir64-compat-implementat.patch +++ b/9999/0009-linux-Use-getdents64-on-readdir64-compat-implementat.patch @@ -1,8 +1,7 @@ -From c71a60022adc7c9b7e37a813e2abad0d0724245a Mon Sep 17 00:00:00 2001 +From b1ab50b1c7f17d6b38c1e3a665cca971ba16deab Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella -Date: Tue, 20 Oct 2020 16:00:43 -0300 -Subject: [PATCH 09/10] linux: Use getdents64 on readdir64 compat - implementation +Date: Fri, 27 Jan 2023 14:28:34 -0300 +Subject: [PATCH 9/9] linux: Use getdents64 on readdir64 compat implementation It uses a similar strategy from the non-LFS readdir that also uses getdents64 internally and uses a translation buffer to return @@ -12,14 +11,45 @@ It allows to remove __old_getdents64. Checked on i686-linux-gnu. --- + sysdeps/unix/sysv/linux/dirstream.h | 13 +++- sysdeps/unix/sysv/linux/getdents64.c | 93 ---------------------------- sysdeps/unix/sysv/linux/olddirent.h | 2 - - sysdeps/unix/sysv/linux/opendir.c | 15 ++++- - sysdeps/unix/sysv/linux/readdir64.c | 62 +++++++++++++++---- - 4 files changed, 64 insertions(+), 108 deletions(-) + sysdeps/unix/sysv/linux/readdir64.c | 50 +++++++++++---- + 4 files changed, 50 insertions(+), 108 deletions(-) +diff --git a/sysdeps/unix/sysv/linux/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h +index 8f58a1c3a6..b03ece4590 100644 +--- a/sysdeps/unix/sysv/linux/dirstream.h ++++ b/sysdeps/unix/sysv/linux/dirstream.h +@@ -24,6 +24,11 @@ + #include + #include + ++#include ++#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) ++# include ++#endif ++ + /* Directory stream type. + + The miscellaneous Unix `readdir' implementations read directory data +@@ -44,7 +49,13 @@ struct __dirstream + int errcode; /* Delayed error code. */ + + #if !defined __OFF_T_MATCHES_OFF64_T || !defined __INO_T_MATCHES_INO64_T +- struct dirent tdp; ++ union ++ { ++ struct dirent tdp; ++#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) ++ struct __old_dirent64 tdp64; ++# endif ++ }; + #endif + #if _DIRENT_OFFSET_TRANSLATION + struct dirstream_loc_t locs; /* off64_t to long int map for telldir. */ diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c -index 510a586859..92481526c5 100644 +index 01c3517deb..db299864ed 100644 --- a/sysdeps/unix/sysv/linux/getdents64.c +++ b/sysdeps/unix/sysv/linux/getdents64.c @@ -36,97 +36,4 @@ weak_alias (__getdents64, getdents64) @@ -121,7 +151,7 @@ index 510a586859..92481526c5 100644 -# endif /* SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) */ #endif /* _DIRENT_MATCHES_DIRENT64 */ diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h -index 00c84b9521..68aafd7c02 100644 +index cde95e192e..2d682a6919 100644 --- a/sysdeps/unix/sysv/linux/olddirent.h +++ b/sysdeps/unix/sysv/linux/olddirent.h @@ -36,8 +36,6 @@ extern struct __old_dirent64 *__old_readdir64_unlocked (DIR *__dirp) @@ -133,44 +163,11 @@ index 00c84b9521..68aafd7c02 100644 int __old_scandir64 (const char * __dir, struct __old_dirent64 *** __namelist, int (*__selector) (const struct __old_dirent64 *), -diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c -index 9a0b7ab4c4..df40b0a64e 100644 ---- a/sysdeps/unix/sysv/linux/opendir.c -+++ b/sysdeps/unix/sysv/linux/opendir.c -@@ -23,6 +23,11 @@ - - #include - -+#include -+#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) -+# include -+#endif -+ - enum { - opendir_oflags = O_RDONLY|O_NDELAY|O_DIRECTORY|O_LARGEFILE|O_CLOEXEC - }; -@@ -128,7 +133,15 @@ __alloc_dir (int fd, bool close_fd, int flags, - expand the buffer if required. */ - enum - { -- tbuffer_size = sizeof (struct dirent) + NAME_MAX + 1 -+ tbuffer_size = -+# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) -+ /* This is used on compat readdir64. */ -+ MAX (sizeof (struct dirent), -+ sizeof (struct __old_dirent64)) -+# else -+ sizeof (struct dirent) -+# endif -+ + NAME_MAX + 1 - }; - dirp->tbuffer = malloc (tbuffer_size); - if (dirp->tbuffer == NULL) diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c -index bbe247f95d..01e834e238 100644 +index b901071aa7..88e42c5e90 100644 --- a/sysdeps/unix/sysv/linux/readdir64.c +++ b/sysdeps/unix/sysv/linux/readdir64.c -@@ -102,21 +102,52 @@ versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); +@@ -102,21 +102,43 @@ versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) # include @@ -182,29 +179,20 @@ index bbe247f95d..01e834e238 100644 +dirstream_old_entry (struct __dirstream *ds, const struct dirent64 *dp64) +{ + /* Check for overflow. */ -+ ino_t d_ino = dp64->d_ino; -+ if (d_ino != dp64->d_ino) ++ if (!in_ino_t_range (dp64->d_ino)) + return false; + -+ /* Expand the translation buffer to hold the new namesize. */ -+ size_t d_reclen = sizeof (struct __old_dirent64) -+ + dp64->d_reclen - offsetof (struct dirent64, d_name); -+ if (d_reclen > ds->tbuffer_size) -+ { -+ char *newbuffer = realloc (ds->tbuffer, d_reclen); -+ if (newbuffer == NULL) -+ return false; -+ ds->tbuffer = newbuffer; -+ ds->tbuffer_size = d_reclen; -+ } ++ /* And if name is too large. */ ++ if (dp64->d_reclen - offsetof (struct dirent64, d_name) > NAME_MAX) ++ return false; + -+ struct __old_dirent64 *olddp64 = (struct __old_dirent64 *) ds->tbuffer; ++ ds->filepos = dp64->d_off; + -+ olddp64->d_off = dp64->d_off; -+ olddp64->d_ino = dp64->d_ino; -+ olddp64->d_reclen = dp64->d_reclen; -+ olddp64->d_type = dp64->d_type; -+ memcpy (olddp64->d_name, dp64->d_name, ++ ds->tdp64.d_off = dp64->d_off; ++ ds->tdp64.d_ino = dp64->d_ino; ++ ds->tdp64.d_reclen = dp64->d_reclen; ++ ds->tdp64.d_type = dp64->d_type; ++ memcpy (ds->tdp64.d_name, dp64->d_name, + dp64->d_reclen - offsetof (struct dirent64, d_name)); + + return true; @@ -230,7 +218,7 @@ index bbe247f95d..01e834e238 100644 if (bytes <= 0) { /* Linux may fail with ENOENT on some file systems if the -@@ -127,17 +158,24 @@ __old_readdir64_unlocked (DIR *dirp) +@@ -127,17 +149,21 @@ __old_readdir64_unlocked (DIR *dirp) __set_errno (saved_errno); return NULL; } @@ -251,15 +239,12 @@ index bbe247f95d..01e834e238 100644 + /* Skip entries which might overflow d_ino or for memory allocation failure + in case of large file names. */ + if (dirstream_old_entry (dirp, dp64)) -+ { -+ dirp->filepos = dp64->d_off; -+ return (struct __old_dirent64 *) dirp->tbuffer; -+ } ++ return &dirp->tdp64; + + return NULL; } attribute_compat_text_section -- -2.38.2 +2.39.1 diff --git a/9999/0010-dirent-Deprecate-getdirentries.patch b/9999/0010-dirent-Deprecate-getdirentries.patch deleted file mode 100644 index 28f744a..0000000 --- a/9999/0010-dirent-Deprecate-getdirentries.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 2f0668caf22acf6493dce8dcfd670e4b35fb6892 Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -Date: Fri, 17 Apr 2020 09:59:51 -0300 -Subject: [PATCH 10/10] dirent: Deprecate getdirentries - -The interface has some issues: - - 1. It is build on top getdents on Linux and requires handling - non-LFS call using LFS getdents. - - 2. It is not wildly used and the non-LFS support is as problematic - as non-LFS readdir. glibc only exports the LFS getdents. - - 3. It is not a direct replacement over BSD since on some plataform - its signature has changed (FreeBSD 11, for instance, used to - set the offset as a 'long' and changed to 'off_t' on version 12). - -The idea is to eventually move the symbols to compat ones. ---- - NEWS | 3 +++ - dirent/dirent.h | 14 ++++++++++---- - sysdeps/unix/sysv/linux/Makefile | 4 ++++ - 3 files changed, 17 insertions(+), 4 deletions(-) - -diff --git a/NEWS b/NEWS -index a10bb08fb0..2b4ed6bbc1 100644 ---- a/NEWS -+++ b/NEWS -@@ -21,6 +21,9 @@ Deprecated and removed features, and other changes affecting compatibility: - corresponds to the AT_PLATFORM system name, or employs the legacy AT_HWCAP - search mechanism, which was deprecated in version 2.33. - -+* The function getdirentries is now deprecated, applications should use -+ either getdents64, readdir64 or readdir. -+ - Changes to build and runtime requirements: - - [Add changes to build and runtime requirements here] -diff --git a/dirent/dirent.h b/dirent/dirent.h -index c47d3273b2..1c299e5be8 100644 ---- a/dirent/dirent.h -+++ b/dirent/dirent.h -@@ -350,29 +350,35 @@ extern int alphasort64 (const struct dirent64 **__e1, - /* Read directory entries from FD into BUF, reading at most NBYTES. - Reading starts at offset *BASEP, and *BASEP is updated with the new - position after reading. Returns the number of bytes read; zero when at -- end of directory; or -1 for errors. */ -+ end of directory; or -1 for errors. -+ This is deprecated and getdents64 or readdir should be used instead. */ - # ifndef __USE_FILE_OFFSET64 - extern __ssize_t getdirentries (int __fd, char *__restrict __buf, - size_t __nbytes, - __off_t *__restrict __basep) -- __THROW __nonnull ((2, 4)); -+ __THROW __nonnull ((2, 4)) -+ __attribute_deprecated_msg__ ("Use getdents64 instead"); - # else - # ifdef __REDIRECT - extern __ssize_t __REDIRECT_NTH (getdirentries, - (int __fd, char *__restrict __buf, - size_t __nbytes, - __off64_t *__restrict __basep), -- getdirentries64) __nonnull ((2, 4)); -+ getdirentries64) -+ __nonnull ((2, 4)) -+ __attribute_deprecated_msg__ ("Use getdents64 instead"); - # else - # define getdirentries getdirentries64 - # endif - # endif - - # ifdef __USE_LARGEFILE64 -+/* This is deprecated and getdents64 or readdir64 should be used instead. */ - extern __ssize_t getdirentries64 (int __fd, char *__restrict __buf, - size_t __nbytes, - __off64_t *__restrict __basep) -- __THROW __nonnull ((2, 4)); -+ __THROW __nonnull ((2, 4)) -+ __attribute_deprecated_msg__ ("Use getdents64 instead"); - # endif - #endif /* Use misc. */ - -diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile -index f298878e8f..41e5341450 100644 ---- a/sysdeps/unix/sysv/linux/Makefile -+++ b/sysdeps/unix/sysv/linux/Makefile -@@ -467,6 +467,10 @@ tests += \ - tst-getdents64 \ - tst-readdir64-compat \ - # tests -+ -+# Avoid the warning for the weak_alias for _DIRENT_MATCHES_DIRENT64 -+CFLAGS-getdirentries64.o = -Wno-deprecated-declarations -+CFLAGS-getdirentries64.os = -Wno-deprecated-declarations - endif # $(subdir) == dirent - - ifeq ($(subdir),nis) --- -2.38.2 - -- cgit v1.2.3-65-gdbad