From 522f2db7d83d4c5b9cc4c29ba776362e0c95d84e Mon Sep 17 00:00:00 2001 From: "Andreas K. Hüttel" Date: Mon, 25 Dec 2023 21:15:00 +0100 Subject: Rebase onto master 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 | 6 +- ...Adapt-to-Gentoo-specific-etc-mail-aliases.patch | 4 +- ...O0-in-conform-tests-to-survive-CC-changes.patch | 4 +- ...4-linux-Use-getdents64-on-non-LFS-readdir.patch | 181 +++++++ ...nternal-DIR-filepos-as-off64_t-BZ-23960-B.patch | 534 +++++++++++++++++++++ ...5-linux-Use-getdents64-on-non-LFS-readdir.patch | 181 ------- 9999/0006-linux-Add-__readdir64_unlocked.patch | 182 +++++++ ...nternal-DIR-filepos-as-off64_t-BZ-23960-B.patch | 534 --------------------- 9999/0007-linux-Add-__old_readdir64_unlocked.patch | 194 ++++++++ 9999/0007-linux-Add-__readdir64_unlocked.patch | 182 ------- 9999/0008-linux-Add-__old_readdir64_unlocked.patch | 194 -------- ...etdents64-on-readdir64-compat-implementat.patch | 250 ++++++++++ ...sable-valgrind-based-tests-too-unreliable.patch | 38 ++ ...etdents64-on-readdir64-compat-implementat.patch | 250 ---------- ...sable-valgrind-based-tests-too-unreliable.patch | 38 -- 15 files changed, 1386 insertions(+), 1386 deletions(-) create mode 100644 9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch create mode 100644 9999/0005-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch delete mode 100644 9999/0005-linux-Use-getdents64-on-non-LFS-readdir.patch create mode 100644 9999/0006-linux-Add-__readdir64_unlocked.patch delete mode 100644 9999/0006-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch create mode 100644 9999/0007-linux-Add-__old_readdir64_unlocked.patch delete mode 100644 9999/0007-linux-Add-__readdir64_unlocked.patch delete mode 100644 9999/0008-linux-Add-__old_readdir64_unlocked.patch create mode 100644 9999/0008-linux-Use-getdents64-on-readdir64-compat-implementat.patch create mode 100644 9999/0009-Gentoo-Disable-valgrind-based-tests-too-unreliable.patch delete mode 100644 9999/0009-linux-Use-getdents64-on-readdir64-compat-implementat.patch delete mode 100644 9999/0011-Gentoo-Disable-valgrind-based-tests-too-unreliable.patch diff --git a/9999/0001-Disable-ldconfig-during-install.patch b/9999/0001-Disable-ldconfig-during-install.patch index 117d65d..5dc96e2 100644 --- a/9999/0001-Disable-ldconfig-during-install.patch +++ b/9999/0001-Disable-ldconfig-during-install.patch @@ -1,4 +1,4 @@ -From 3924368571ae2b77a8465de8bb7ec7e6288dae67 Mon Sep 17 00:00:00 2001 +From 2c5f0265999e3469b81a8cf27d713f212746a352 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 3 Aug 2021 00:34:59 +0200 Subject: [PATCH 1/9] Disable ldconfig during install @@ -19,7 +19,7 @@ Signed-off-by: Andreas K. Hüttel 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile -index f324df7a1f..0221906533 100644 +index a4f3378e21..dca38dd666 100644 --- a/Makefile +++ b/Makefile @@ -110,6 +110,7 @@ elf/ldso_install: @@ -31,5 +31,5 @@ index f324df7a1f..0221906533 100644 $(elf-objpfx)ldconfig $(addprefix -r ,$(install_root)) \ $(slibdir) $(libdir) -- -2.39.3 +2.41.0 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 52d6412..44af542 100644 --- a/9999/0002-Adapt-to-Gentoo-specific-etc-mail-aliases.patch +++ b/9999/0002-Adapt-to-Gentoo-specific-etc-mail-aliases.patch @@ -1,4 +1,4 @@ -From bc18d3d2140f40e43f9767bf8964eca3b2d0da17 Mon Sep 17 00:00:00 2001 +From e6abcb198ba9bbc848fe00af7da56daff3da7048 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 2/9] Adapt to Gentoo-specific /etc/mail/aliases @@ -105,5 +105,5 @@ index 7a1b7272f0..500c9a79a3 100644 /* valgrind needs a temporary directory in the chroot. */ { -- -2.39.3 +2.41.0 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 d890165..9b03cfd 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,4 +1,4 @@ -From 85d0916ff499c8d9d135cd5200ec1d4797a74565 Mon Sep 17 00:00:00 2001 +From 6f5c946863eb63605ccf7388eebebc63cc3523d2 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 3/9] Force -O0 in conform tests to survive $CC changes @@ -61,5 +61,5 @@ index 983bba1bd2..b6fce8a21c 100644 args.header) with tempfile.TemporaryDirectory() as temp_dir: -- -2.39.3 +2.41.0 diff --git a/9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch b/9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch new file mode 100644 index 0000000..a451fd6 --- /dev/null +++ b/9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch @@ -0,0 +1,181 @@ +From 782410070379ffbf54cb8abe71cc13fd24cfaea5 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Fri, 27 Jan 2023 14:28:30 -0300 +Subject: [PATCH 4/9] linux: Use getdents64 on non-LFS readdir + +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. +--- + dirent/tst-scandir.c | 6 ++- + include/dirent.h | 2 +- + sysdeps/unix/sysv/linux/dirstream.h | 5 ++ + sysdeps/unix/sysv/linux/readdir.c | 83 +++++++++++++++++++---------- + 4 files changed, 67 insertions(+), 29 deletions(-) + +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; + } + + 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 3cb313b410..adcf8234f1 100644 +--- a/sysdeps/unix/sysv/linux/dirstream.h ++++ b/sysdeps/unix/sysv/linux/dirstream.h +@@ -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 ++ 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/readdir.c b/sysdeps/unix/sysv/linux/readdir.c +index 4a4c00ea07..cd0ccaf33a 100644 +--- a/sysdeps/unix/sysv/linux/readdir.c ++++ b/sysdeps/unix/sysv/linux/readdir.c +@@ -21,42 +21,71 @@ + #if !_DIRENT_MATCHES_DIRENT64 + #include + ++/* 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 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) ++{ ++ /* Check for overflow. */ ++ if (!in_off_t_range (dp64->d_off) || !in_ino_t_range (dp64->d_ino)) ++ return false; ++ ++ /* And if name is too large. */ ++ if (dp64->d_reclen - offsetof (struct dirent64, d_name) > NAME_MAX) ++ return false; ++ ++ ds->filepos = dp64->d_off; ++ ++ 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; ++} ++ + /* Read a directory entry from DIRP. */ + struct dirent * + __readdir_unlocked (DIR *dirp) + { +- struct dirent *dp; + int saved_errno = errno; + +- if (dirp->offset >= dirp->size) ++ while (1) + { +- /* 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) ++ 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); ++ if (bytes <= 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 = bytes; ++ ++ /* Reset the offset into the buffer. */ ++ dirp->offset = 0; ++ } ++ ++ struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; ++ dirp->offset += dp64->d_reclen; ++ ++ /* Skip entries which might overflow d_off/d_ino or if the translation ++ buffer can not be resized. */ ++ if (dirstream_entry (dirp, dp64)) ++ return &dirp->tdp; + } +- +- dp = (struct dirent *) &dirp->data[dirp->offset]; +- dirp->offset += dp->d_reclen; +- dirp->filepos = dp->d_off; +- +- return dp; + } + + struct dirent * +-- +2.41.0 + diff --git a/9999/0005-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch b/9999/0005-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch new file mode 100644 index 0000000..9b566a2 --- /dev/null +++ b/9999/0005-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch @@ -0,0 +1,534 @@ +From 8b628a35f0ce66d74be6557e74e28a49a58d749a Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Fri, 27 Jan 2023 14:28:31 -0300 +Subject: [PATCH 5/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 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 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/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/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) ++ { ++ /* 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 415aa1f14d..dc204883db 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -574,6 +574,7 @@ sysdep_routines += \ + + 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 ++ ++/* 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 f1c2608642..9585a6ca3a 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_OFFSET_TRANSLATION ++ dirstream_loc_clear (&dirp->locs); ++#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 adcf8234f1..8f58a1c3a6 100644 +--- a/sysdeps/unix/sysv/linux/dirstream.h ++++ b/sysdeps/unix/sysv/linux/dirstream.h +@@ -22,6 +22,7 @@ + #include + + #include ++#include + + /* Directory stream type. + +@@ -38,13 +39,16 @@ struct __dirstream + size_t size; /* Total valid data in the block. */ + size_t offset; /* Current offset into the block. */ + +- off_t filepos; /* Position of next entry to read. */ ++ off64_t filepos; /* Position of next entry to read. */ + + int errcode; /* Delayed error code. */ + + #if !defined __OFF_T_MATCHES_OFF64_T || !defined __INO_T_MATCHES_INO64_T + struct dirent tdp; + #endif ++#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 4336196a4d..3e2caabb9d 100644 +--- a/sysdeps/unix/sysv/linux/opendir.c ++++ b/sysdeps/unix/sysv/linux/opendir.c +@@ -129,6 +129,9 @@ __alloc_dir (int fd, bool close_fd, int flags, + dirp->offset = 0; + dirp->filepos = 0; + dirp->errcode = 0; ++#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 cd0ccaf33a..7a7f484c36 100644 +--- a/sysdeps/unix/sysv/linux/readdir.c ++++ b/sysdeps/unix/sysv/linux/readdir.c +@@ -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; + ++ /* 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; + + 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 c0fb7aa765..1b158a584f 100644 +--- a/sysdeps/unix/sysv/linux/rewinddir.c ++++ b/sysdeps/unix/sysv/linux/rewinddir.c +@@ -33,6 +33,11 @@ __rewinddir (DIR *dirp) + dirp->offset = 0; + dirp->size = 0; + dirp->errcode = 0; ++ ++#ifndef __LP64__ ++ dirstream_loc_clear (&dirp->locs); ++#endif ++ + #if IS_IN (libc) + __libc_lock_unlock (dirp->lock); + #endif +diff --git a/sysdeps/unix/sysv/linux/seekdir.c b/sysdeps/unix/sysv/linux/seekdir.c +index 939ccc4447..30cce691a4 100644 +--- a/sysdeps/unix/sysv/linux/seekdir.c ++++ b/sysdeps/unix/sysv/linux/seekdir.c +@@ -22,14 +22,39 @@ + #include + + /* Seek to position POS in DIRP. */ +-/* XXX should be __seekdir ? */ + void + seekdir (DIR *dirp, long int pos) + { ++ off64_t filepos; ++ + __libc_lock_lock (dirp->lock); +- (void) __lseek (dirp->fd, pos, SEEK_SET); +- dirp->size = 0; +- dirp->offset = 0; +- dirp->filepos = pos; ++ ++#if _DIRENT_OFFSET_TRANSLATION ++ union dirstream_packed dsp = { .l = pos }; ++ if (dsp.p.is_packed == 1) ++ filepos = dsp.p.info; ++ else ++ { ++ size_t index = dsp.p.info; ++ ++ if (index >= dirstream_loc_size (&dirp->locs)) ++ { ++ __libc_lock_unlock (dirp->lock); ++ return; ++ } ++ filepos = *dirstream_loc_at (&dirp->locs, index); ++ } ++#else ++ filepos = pos; ++#endif ++ ++ if (dirp->filepos != filepos) ++ { ++ __lseek64 (dirp->fd, filepos, SEEK_SET); ++ dirp->filepos = filepos; ++ dirp->offset = 0; ++ dirp->size = 0; ++ } ++ + __libc_lock_unlock (dirp->lock); + } +diff --git a/sysdeps/unix/sysv/linux/telldir.c b/sysdeps/unix/sysv/linux/telldir.c +index 1e5c129e9f..c3ef14f3da 100644 +--- a/sysdeps/unix/sysv/linux/telldir.c ++++ b/sysdeps/unix/sysv/linux/telldir.c +@@ -15,9 +15,11 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + + #include ++#include + + /* Return the current position of DIRP. */ + long int +@@ -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; ++ ++ if (!telldir_need_dirstream (dirp->filepos)) ++ { ++ dsp.p.is_packed = 1; ++ dsp.p.info = dirp->filepos; ++ } ++ else ++ { ++ 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; ++ } ++ ++ ret = dsp.l; ++#else + ret = dirp->filepos; ++#endif + __libc_lock_unlock (dirp->lock); + + return ret; +diff --git a/sysdeps/unix/sysv/linux/telldir.h b/sysdeps/unix/sysv/linux/telldir.h +new file mode 100644 +index 0000000000..758bcb0eb3 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/telldir.h +@@ -0,0 +1,65 @@ ++/* Linux internal telldir definitions. ++ 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 ++ . */ ++ ++#ifndef _TELLDIR_H ++#define _TELLDIR_H 1 ++ ++#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. ++ ++ Otherwise, the 'info' member describes an index in a dynamic array at ++ 'DIR' structure. */ ++ ++union dirstream_packed ++{ ++ long int l; ++ struct ++ { ++ 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 maintains a list of offsets that describe the obtained diretory ++ position if it can fit this information in the returned 'dirstream_packed' ++ struct. */ ++ ++# define DYNARRAY_STRUCT dirstream_loc_t ++# 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.41.0 + diff --git a/9999/0005-linux-Use-getdents64-on-non-LFS-readdir.patch b/9999/0005-linux-Use-getdents64-on-non-LFS-readdir.patch deleted file mode 100644 index 3bae810..0000000 --- a/9999/0005-linux-Use-getdents64-on-non-LFS-readdir.patch +++ /dev/null @@ -1,181 +0,0 @@ -From bc521cf2674e2a27cc4a0dfd638c151462d51d1b Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -Date: Fri, 27 Jan 2023 14:28:30 -0300 -Subject: [PATCH 5/9] linux: Use getdents64 on non-LFS readdir - -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. ---- - dirent/tst-scandir.c | 6 ++- - include/dirent.h | 2 +- - sysdeps/unix/sysv/linux/dirstream.h | 5 ++ - sysdeps/unix/sysv/linux/readdir.c | 83 +++++++++++++++++++---------- - 4 files changed, 67 insertions(+), 29 deletions(-) - -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; - } - - 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 3cb313b410..adcf8234f1 100644 ---- a/sysdeps/unix/sysv/linux/dirstream.h -+++ b/sysdeps/unix/sysv/linux/dirstream.h -@@ -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 -+ 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/readdir.c b/sysdeps/unix/sysv/linux/readdir.c -index 4a4c00ea07..cd0ccaf33a 100644 ---- a/sysdeps/unix/sysv/linux/readdir.c -+++ b/sysdeps/unix/sysv/linux/readdir.c -@@ -21,42 +21,71 @@ - #if !_DIRENT_MATCHES_DIRENT64 - #include - -+/* 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 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) -+{ -+ /* Check for overflow. */ -+ if (!in_off_t_range (dp64->d_off) || !in_ino_t_range (dp64->d_ino)) -+ return false; -+ -+ /* And if name is too large. */ -+ if (dp64->d_reclen - offsetof (struct dirent64, d_name) > NAME_MAX) -+ return false; -+ -+ ds->filepos = dp64->d_off; -+ -+ 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; -+} -+ - /* Read a directory entry from DIRP. */ - struct dirent * - __readdir_unlocked (DIR *dirp) - { -- struct dirent *dp; - int saved_errno = errno; - -- if (dirp->offset >= dirp->size) -+ while (1) - { -- /* 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) -+ 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); -+ if (bytes <= 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 = bytes; -+ -+ /* Reset the offset into the buffer. */ -+ dirp->offset = 0; -+ } -+ -+ struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; -+ dirp->offset += dp64->d_reclen; -+ -+ /* Skip entries which might overflow d_off/d_ino or if the translation -+ buffer can not be resized. */ -+ if (dirstream_entry (dirp, dp64)) -+ return &dirp->tdp; - } -- -- dp = (struct dirent *) &dirp->data[dirp->offset]; -- dirp->offset += dp->d_reclen; -- dirp->filepos = dp->d_off; -- -- return dp; - } - - struct dirent * --- -2.39.3 - diff --git a/9999/0006-linux-Add-__readdir64_unlocked.patch b/9999/0006-linux-Add-__readdir64_unlocked.patch new file mode 100644 index 0000000..3510868 --- /dev/null +++ b/9999/0006-linux-Add-__readdir64_unlocked.patch @@ -0,0 +1,182 @@ +From a2a34383be6e082561a09f37c5747215a70e2439 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Fri, 27 Jan 2023 14:28:32 -0300 +Subject: [PATCH 6/9] linux: Add __readdir64_unlocked + +And use it on readdir_r implementation. + +Checked on i686-linux-gnu. +--- + include/dirent.h | 1 + + sysdeps/unix/sysv/linux/readdir64.c | 20 +++++-- + sysdeps/unix/sysv/linux/readdir64_r.c | 80 ++++++--------------------- + 3 files changed, 33 insertions(+), 68 deletions(-) + +diff --git a/include/dirent.h b/include/dirent.h +index 17827176ba..f391476298 100644 +--- a/include/dirent.h ++++ b/include/dirent.h +@@ -21,6 +21,7 @@ extern DIR *__fdopendir (int __fd) attribute_hidden; + extern int __closedir (DIR *__dirp) attribute_hidden; + extern struct dirent *__readdir (DIR *__dirp) attribute_hidden; + extern struct dirent *__readdir_unlocked (DIR *__dirp) attribute_hidden; ++extern struct dirent64 *__readdir64_unlocked (DIR *__dirp) attribute_hidden; + extern struct dirent64 *__readdir64 (DIR *__dirp); + 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 db1c6214d8..2327511736 100644 +--- a/sysdeps/unix/sysv/linux/readdir64.c ++++ b/sysdeps/unix/sysv/linux/readdir64.c +@@ -28,15 +28,11 @@ + + /* Read a directory entry from DIRP. */ + struct dirent64 * +-__readdir64 (DIR *dirp) ++__readdir64_unlocked (DIR *dirp) + { + struct dirent64 *dp; + int saved_errno = errno; + +-#if IS_IN (libc) +- __libc_lock_lock (dirp->lock); +-#endif +- + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ +@@ -68,6 +64,20 @@ __readdir64 (DIR *dirp) + dirp->offset += dp->d_reclen; + dirp->filepos = dp->d_off; + ++ return dp; ++} ++ ++struct dirent64 * ++__readdir64 (DIR *dirp) ++{ ++ struct dirent64 *dp; ++ ++#if IS_IN (libc) ++ __libc_lock_lock (dirp->lock); ++#endif ++ ++ dp = __readdir64_unlocked (dirp); ++ + #if IS_IN (libc) + __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 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) + { + struct dirent64 *dp; + size_t reclen; +- const int saved_errno = errno; +- int ret; + + __libc_lock_lock (dirp->lock); +- +- do ++ while (1) + { +- if (dirp->offset >= dirp->size) +- { +- /* We've emptied out our buffer. Refill it. */ +- +- size_t maxread = dirp->allocation; +- ssize_t bytes; +- +- maxread = dirp->allocation; +- +- 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; +- __set_errno (saved_errno); +- } +- if (bytes < 0) +- dirp->errcode = errno; +- +- dp = NULL; +- break; +- } +- dirp->size = (size_t) bytes; +- +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; +- } +- +- dp = (struct dirent64 *) &dirp->data[dirp->offset]; ++ dp = __readdir64_unlocked (dirp); ++ if (dp == NULL) ++ break; + + reclen = dp->d_reclen; ++ if (reclen <= offsetof (struct dirent64, d_name) + NAME_MAX + 1) ++ break; + +- dirp->offset += reclen; +- +- dirp->filepos = dp->d_off; +- +- if (reclen > offsetof (struct dirent64, d_name) + NAME_MAX + 1) ++ /* The record is very long. It could still fit into the caller-supplied ++ buffer if we can skip padding at the end. */ ++ size_t namelen = _D_EXACT_NAMLEN (dp); ++ if (namelen <= NAME_MAX) + { +- /* The record is very long. It could still fit into the +- caller-supplied buffer if we can skip padding at the +- end. */ +- size_t namelen = _D_EXACT_NAMLEN (dp); +- if (namelen <= NAME_MAX) +- reclen = offsetof (struct dirent64, d_name) + namelen + 1; +- else +- { +- /* The name is too long. Ignore this file. */ +- dirp->errcode = ENAMETOOLONG; +- dp->d_ino = 0; +- continue; +- } ++ reclen = offsetof (struct dirent64, d_name) + namelen + 1; ++ break; + } + +- /* Skip deleted and ignored files. */ ++ /* The name is too long. Ignore this file. */ ++ dirp->errcode = ENAMETOOLONG; ++ dp->d_ino = 0; + } +- while (dp->d_ino == 0); + + if (dp != NULL) + { + *result = memcpy (entry, dp, reclen); + entry->d_reclen = reclen; +- ret = 0; + } + else +- { +- *result = NULL; +- ret = dirp->errcode; +- } ++ *result = NULL; + + __libc_lock_unlock (dirp->lock); + +- return ret; ++ return dp != NULL ? 0 : dirp->errcode; + } + + +-- +2.41.0 + 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 deleted file mode 100644 index 69f6ca0..0000000 --- a/9999/0006-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch +++ /dev/null @@ -1,534 +0,0 @@ -From 61beae8ace3127d476570b8989ec4d60f421b94e Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -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 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 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/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/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) -+ { -+ /* 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 be801e3be4..29c747b387 100644 ---- a/sysdeps/unix/sysv/linux/Makefile -+++ b/sysdeps/unix/sysv/linux/Makefile -@@ -546,6 +546,7 @@ sysdep_routines += \ - - 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 -+ -+/* 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 f1c2608642..9585a6ca3a 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_OFFSET_TRANSLATION -+ dirstream_loc_clear (&dirp->locs); -+#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 adcf8234f1..8f58a1c3a6 100644 ---- a/sysdeps/unix/sysv/linux/dirstream.h -+++ b/sysdeps/unix/sysv/linux/dirstream.h -@@ -22,6 +22,7 @@ - #include - - #include -+#include - - /* Directory stream type. - -@@ -38,13 +39,16 @@ struct __dirstream - size_t size; /* Total valid data in the block. */ - size_t offset; /* Current offset into the block. */ - -- off_t filepos; /* Position of next entry to read. */ -+ off64_t filepos; /* Position of next entry to read. */ - - int errcode; /* Delayed error code. */ - - #if !defined __OFF_T_MATCHES_OFF64_T || !defined __INO_T_MATCHES_INO64_T - struct dirent tdp; - #endif -+#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 4336196a4d..3e2caabb9d 100644 ---- a/sysdeps/unix/sysv/linux/opendir.c -+++ b/sysdeps/unix/sysv/linux/opendir.c -@@ -129,6 +129,9 @@ __alloc_dir (int fd, bool close_fd, int flags, - dirp->offset = 0; - dirp->filepos = 0; - dirp->errcode = 0; -+#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 cd0ccaf33a..7a7f484c36 100644 ---- a/sysdeps/unix/sysv/linux/readdir.c -+++ b/sysdeps/unix/sysv/linux/readdir.c -@@ -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; - -+ /* 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; - - 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 c0fb7aa765..1b158a584f 100644 ---- a/sysdeps/unix/sysv/linux/rewinddir.c -+++ b/sysdeps/unix/sysv/linux/rewinddir.c -@@ -33,6 +33,11 @@ __rewinddir (DIR *dirp) - dirp->offset = 0; - dirp->size = 0; - dirp->errcode = 0; -+ -+#ifndef __LP64__ -+ dirstream_loc_clear (&dirp->locs); -+#endif -+ - #if IS_IN (libc) - __libc_lock_unlock (dirp->lock); - #endif -diff --git a/sysdeps/unix/sysv/linux/seekdir.c b/sysdeps/unix/sysv/linux/seekdir.c -index 939ccc4447..30cce691a4 100644 ---- a/sysdeps/unix/sysv/linux/seekdir.c -+++ b/sysdeps/unix/sysv/linux/seekdir.c -@@ -22,14 +22,39 @@ - #include - - /* Seek to position POS in DIRP. */ --/* XXX should be __seekdir ? */ - void - seekdir (DIR *dirp, long int pos) - { -+ off64_t filepos; -+ - __libc_lock_lock (dirp->lock); -- (void) __lseek (dirp->fd, pos, SEEK_SET); -- dirp->size = 0; -- dirp->offset = 0; -- dirp->filepos = pos; -+ -+#if _DIRENT_OFFSET_TRANSLATION -+ union dirstream_packed dsp = { .l = pos }; -+ if (dsp.p.is_packed == 1) -+ filepos = dsp.p.info; -+ else -+ { -+ size_t index = dsp.p.info; -+ -+ if (index >= dirstream_loc_size (&dirp->locs)) -+ { -+ __libc_lock_unlock (dirp->lock); -+ return; -+ } -+ filepos = *dirstream_loc_at (&dirp->locs, index); -+ } -+#else -+ filepos = pos; -+#endif -+ -+ if (dirp->filepos != filepos) -+ { -+ __lseek64 (dirp->fd, filepos, SEEK_SET); -+ dirp->filepos = filepos; -+ dirp->offset = 0; -+ dirp->size = 0; -+ } -+ - __libc_lock_unlock (dirp->lock); - } -diff --git a/sysdeps/unix/sysv/linux/telldir.c b/sysdeps/unix/sysv/linux/telldir.c -index 1e5c129e9f..c3ef14f3da 100644 ---- a/sysdeps/unix/sysv/linux/telldir.c -+++ b/sysdeps/unix/sysv/linux/telldir.c -@@ -15,9 +15,11 @@ - License along with the GNU C Library; if not, see - . */ - -+#include - #include - - #include -+#include - - /* Return the current position of DIRP. */ - long int -@@ -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; -+ -+ if (!telldir_need_dirstream (dirp->filepos)) -+ { -+ dsp.p.is_packed = 1; -+ dsp.p.info = dirp->filepos; -+ } -+ else -+ { -+ 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; -+ } -+ -+ ret = dsp.l; -+#else - ret = dirp->filepos; -+#endif - __libc_lock_unlock (dirp->lock); - - return ret; -diff --git a/sysdeps/unix/sysv/linux/telldir.h b/sysdeps/unix/sysv/linux/telldir.h -new file mode 100644 -index 0000000000..758bcb0eb3 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/telldir.h -@@ -0,0 +1,65 @@ -+/* Linux internal telldir definitions. -+ 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 -+ . */ -+ -+#ifndef _TELLDIR_H -+#define _TELLDIR_H 1 -+ -+#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. -+ -+ Otherwise, the 'info' member describes an index in a dynamic array at -+ 'DIR' structure. */ -+ -+union dirstream_packed -+{ -+ long int l; -+ struct -+ { -+ 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 maintains a list of offsets that describe the obtained diretory -+ position if it can fit this information in the returned 'dirstream_packed' -+ struct. */ -+ -+# define DYNARRAY_STRUCT dirstream_loc_t -+# 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.39.3 - diff --git a/9999/0007-linux-Add-__old_readdir64_unlocked.patch b/9999/0007-linux-Add-__old_readdir64_unlocked.patch new file mode 100644 index 0000000..2b99897 --- /dev/null +++ b/9999/0007-linux-Add-__old_readdir64_unlocked.patch @@ -0,0 +1,194 @@ +From f1d798104d5adfdec9aff9390dd7b62014d888eb Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Fri, 27 Jan 2023 14:28:33 -0300 +Subject: [PATCH 7/9] linux: Add __old_readdir64_unlocked + +And use it __old_readdir64_r. + +Checked on i686-linux-gnu. +--- + sysdeps/unix/sysv/linux/olddirent.h | 2 + + sysdeps/unix/sysv/linux/readdir64.c | 24 +++++--- + sysdeps/unix/sysv/linux/readdir64_r.c | 79 ++++++--------------------- + 3 files changed, 35 insertions(+), 70 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h +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 + /* Now define the internal interfaces. */ + extern struct __old_dirent64 *__old_readdir64 (DIR *__dirp); + libc_hidden_proto (__old_readdir64); ++extern struct __old_dirent64 *__old_readdir64_unlocked (DIR *__dirp) ++ attribute_hidden; + extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, + 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 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); + + attribute_compat_text_section + struct __old_dirent64 * +-__old_readdir64 (DIR *dirp) ++__old_readdir64_unlocked (DIR *dirp) + { + struct __old_dirent64 *dp; + int saved_errno = errno; + +-#if IS_IN (libc) +- __libc_lock_lock (dirp->lock); +-#endif +- + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ +@@ -129,9 +125,6 @@ __old_readdir64 (DIR *dirp) + 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; +@@ -144,6 +137,21 @@ __old_readdir64 (DIR *dirp) + dirp->offset += dp->d_reclen; + dirp->filepos = dp->d_off; + ++ return dp; ++} ++ ++attribute_compat_text_section ++struct __old_dirent64 * ++__old_readdir64 (DIR *dirp) ++{ ++ struct __old_dirent64 *dp; ++ ++#if IS_IN (libc) ++ __libc_lock_lock (dirp->lock); ++#endif ++ ++ dp = __old_readdir64_unlocked (dirp); ++ + #if IS_IN (libc) + __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 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, + { + struct __old_dirent64 *dp; + size_t reclen; +- const int saved_errno = errno; +- int ret; + + __libc_lock_lock (dirp->lock); + +- do ++ while (1) + { +- if (dirp->offset >= dirp->size) +- { +- /* We've emptied out our buffer. Refill it. */ +- +- size_t maxread = dirp->allocation; +- ssize_t bytes; +- +- maxread = dirp->allocation; +- +- 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; +- __set_errno (saved_errno); +- } +- if (bytes < 0) +- dirp->errcode = errno; +- +- dp = NULL; +- break; +- } +- dirp->size = (size_t) bytes; +- +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; +- } +- +- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; ++ dp = __old_readdir64_unlocked (dirp); ++ if (dp == NULL) ++ break; + + reclen = dp->d_reclen; ++ if (reclen <= offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) ++ break; + +- dirp->offset += reclen; +- +- dirp->filepos = dp->d_off; +- +- if (reclen > offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) ++ /* The record is very long. It could still fit into the caller-supplied ++ buffer if we can skip padding at the end. */ ++ size_t namelen = _D_EXACT_NAMLEN (dp); ++ if (namelen <= NAME_MAX) + { +- /* The record is very long. It could still fit into the +- caller-supplied buffer if we can skip padding at the +- end. */ +- size_t namelen = _D_EXACT_NAMLEN (dp); +- if (namelen <= NAME_MAX) +- reclen = offsetof (struct __old_dirent64, d_name) + namelen + 1; +- else +- { +- /* The name is too long. Ignore this file. */ +- dirp->errcode = ENAMETOOLONG; +- dp->d_ino = 0; +- continue; +- } ++ reclen = offsetof (struct dirent64, d_name) + namelen + 1; ++ break; + } + +- /* Skip deleted and ignored files. */ ++ /* The name is too long. Ignore this file. */ ++ dirp->errcode = ENAMETOOLONG; ++ dp->d_ino = 0; + } +- while (dp->d_ino == 0); + + if (dp != NULL) + { + *result = memcpy (entry, dp, reclen); + entry->d_reclen = reclen; +- ret = 0; + } + else +- { +- *result = NULL; +- ret = dirp->errcode; +- } ++ *result = NULL; + + __libc_lock_unlock (dirp->lock); + +- return ret; ++ return dp != NULL ? 0 : dirp->errcode; + } + + compat_symbol (libc, __old_readdir64_r, readdir64_r, GLIBC_2_1); +-- +2.41.0 + diff --git a/9999/0007-linux-Add-__readdir64_unlocked.patch b/9999/0007-linux-Add-__readdir64_unlocked.patch deleted file mode 100644 index 73bf546..0000000 --- a/9999/0007-linux-Add-__readdir64_unlocked.patch +++ /dev/null @@ -1,182 +0,0 @@ -From aa6bdde21d0305ce4e95fd49f7b36524ba92e745 Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -Date: Fri, 27 Jan 2023 14:28:32 -0300 -Subject: [PATCH 7/9] linux: Add __readdir64_unlocked - -And use it on readdir_r implementation. - -Checked on i686-linux-gnu. ---- - include/dirent.h | 1 + - sysdeps/unix/sysv/linux/readdir64.c | 20 +++++-- - sysdeps/unix/sysv/linux/readdir64_r.c | 80 ++++++--------------------- - 3 files changed, 33 insertions(+), 68 deletions(-) - -diff --git a/include/dirent.h b/include/dirent.h -index 17827176ba..f391476298 100644 ---- a/include/dirent.h -+++ b/include/dirent.h -@@ -21,6 +21,7 @@ extern DIR *__fdopendir (int __fd) attribute_hidden; - extern int __closedir (DIR *__dirp) attribute_hidden; - extern struct dirent *__readdir (DIR *__dirp) attribute_hidden; - extern struct dirent *__readdir_unlocked (DIR *__dirp) attribute_hidden; -+extern struct dirent64 *__readdir64_unlocked (DIR *__dirp) attribute_hidden; - extern struct dirent64 *__readdir64 (DIR *__dirp); - 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 db1c6214d8..2327511736 100644 ---- a/sysdeps/unix/sysv/linux/readdir64.c -+++ b/sysdeps/unix/sysv/linux/readdir64.c -@@ -28,15 +28,11 @@ - - /* Read a directory entry from DIRP. */ - struct dirent64 * --__readdir64 (DIR *dirp) -+__readdir64_unlocked (DIR *dirp) - { - struct dirent64 *dp; - int saved_errno = errno; - --#if IS_IN (libc) -- __libc_lock_lock (dirp->lock); --#endif -- - if (dirp->offset >= dirp->size) - { - /* We've emptied out our buffer. Refill it. */ -@@ -68,6 +64,20 @@ __readdir64 (DIR *dirp) - dirp->offset += dp->d_reclen; - dirp->filepos = dp->d_off; - -+ return dp; -+} -+ -+struct dirent64 * -+__readdir64 (DIR *dirp) -+{ -+ struct dirent64 *dp; -+ -+#if IS_IN (libc) -+ __libc_lock_lock (dirp->lock); -+#endif -+ -+ dp = __readdir64_unlocked (dirp); -+ - #if IS_IN (libc) - __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 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) - { - struct dirent64 *dp; - size_t reclen; -- const int saved_errno = errno; -- int ret; - - __libc_lock_lock (dirp->lock); -- -- do -+ while (1) - { -- if (dirp->offset >= dirp->size) -- { -- /* We've emptied out our buffer. Refill it. */ -- -- size_t maxread = dirp->allocation; -- ssize_t bytes; -- -- maxread = dirp->allocation; -- -- 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; -- __set_errno (saved_errno); -- } -- if (bytes < 0) -- dirp->errcode = errno; -- -- dp = NULL; -- break; -- } -- dirp->size = (size_t) bytes; -- -- /* Reset the offset into the buffer. */ -- dirp->offset = 0; -- } -- -- dp = (struct dirent64 *) &dirp->data[dirp->offset]; -+ dp = __readdir64_unlocked (dirp); -+ if (dp == NULL) -+ break; - - reclen = dp->d_reclen; -+ if (reclen <= offsetof (struct dirent64, d_name) + NAME_MAX + 1) -+ break; - -- dirp->offset += reclen; -- -- dirp->filepos = dp->d_off; -- -- if (reclen > offsetof (struct dirent64, d_name) + NAME_MAX + 1) -+ /* The record is very long. It could still fit into the caller-supplied -+ buffer if we can skip padding at the end. */ -+ size_t namelen = _D_EXACT_NAMLEN (dp); -+ if (namelen <= NAME_MAX) - { -- /* The record is very long. It could still fit into the -- caller-supplied buffer if we can skip padding at the -- end. */ -- size_t namelen = _D_EXACT_NAMLEN (dp); -- if (namelen <= NAME_MAX) -- reclen = offsetof (struct dirent64, d_name) + namelen + 1; -- else -- { -- /* The name is too long. Ignore this file. */ -- dirp->errcode = ENAMETOOLONG; -- dp->d_ino = 0; -- continue; -- } -+ reclen = offsetof (struct dirent64, d_name) + namelen + 1; -+ break; - } - -- /* Skip deleted and ignored files. */ -+ /* The name is too long. Ignore this file. */ -+ dirp->errcode = ENAMETOOLONG; -+ dp->d_ino = 0; - } -- while (dp->d_ino == 0); - - if (dp != NULL) - { - *result = memcpy (entry, dp, reclen); - entry->d_reclen = reclen; -- ret = 0; - } - else -- { -- *result = NULL; -- ret = dirp->errcode; -- } -+ *result = NULL; - - __libc_lock_unlock (dirp->lock); - -- return ret; -+ return dp != NULL ? 0 : dirp->errcode; - } - - --- -2.39.3 - diff --git a/9999/0008-linux-Add-__old_readdir64_unlocked.patch b/9999/0008-linux-Add-__old_readdir64_unlocked.patch deleted file mode 100644 index 200d275..0000000 --- a/9999/0008-linux-Add-__old_readdir64_unlocked.patch +++ /dev/null @@ -1,194 +0,0 @@ -From 906b7cf87806610267ffff0b850b138bd1fd2098 Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -Date: Fri, 27 Jan 2023 14:28:33 -0300 -Subject: [PATCH 8/9] linux: Add __old_readdir64_unlocked - -And use it __old_readdir64_r. - -Checked on i686-linux-gnu. ---- - sysdeps/unix/sysv/linux/olddirent.h | 2 + - sysdeps/unix/sysv/linux/readdir64.c | 24 +++++--- - sysdeps/unix/sysv/linux/readdir64_r.c | 79 ++++++--------------------- - 3 files changed, 35 insertions(+), 70 deletions(-) - -diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h -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 - /* Now define the internal interfaces. */ - extern struct __old_dirent64 *__old_readdir64 (DIR *__dirp); - libc_hidden_proto (__old_readdir64); -+extern struct __old_dirent64 *__old_readdir64_unlocked (DIR *__dirp) -+ attribute_hidden; - extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, - 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 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); - - attribute_compat_text_section - struct __old_dirent64 * --__old_readdir64 (DIR *dirp) -+__old_readdir64_unlocked (DIR *dirp) - { - struct __old_dirent64 *dp; - int saved_errno = errno; - --#if IS_IN (libc) -- __libc_lock_lock (dirp->lock); --#endif -- - if (dirp->offset >= dirp->size) - { - /* We've emptied out our buffer. Refill it. */ -@@ -129,9 +125,6 @@ __old_readdir64 (DIR *dirp) - 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; -@@ -144,6 +137,21 @@ __old_readdir64 (DIR *dirp) - dirp->offset += dp->d_reclen; - dirp->filepos = dp->d_off; - -+ return dp; -+} -+ -+attribute_compat_text_section -+struct __old_dirent64 * -+__old_readdir64 (DIR *dirp) -+{ -+ struct __old_dirent64 *dp; -+ -+#if IS_IN (libc) -+ __libc_lock_lock (dirp->lock); -+#endif -+ -+ dp = __old_readdir64_unlocked (dirp); -+ - #if IS_IN (libc) - __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 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, - { - struct __old_dirent64 *dp; - size_t reclen; -- const int saved_errno = errno; -- int ret; - - __libc_lock_lock (dirp->lock); - -- do -+ while (1) - { -- if (dirp->offset >= dirp->size) -- { -- /* We've emptied out our buffer. Refill it. */ -- -- size_t maxread = dirp->allocation; -- ssize_t bytes; -- -- maxread = dirp->allocation; -- -- 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; -- __set_errno (saved_errno); -- } -- if (bytes < 0) -- dirp->errcode = errno; -- -- dp = NULL; -- break; -- } -- dirp->size = (size_t) bytes; -- -- /* Reset the offset into the buffer. */ -- dirp->offset = 0; -- } -- -- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; -+ dp = __old_readdir64_unlocked (dirp); -+ if (dp == NULL) -+ break; - - reclen = dp->d_reclen; -+ if (reclen <= offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) -+ break; - -- dirp->offset += reclen; -- -- dirp->filepos = dp->d_off; -- -- if (reclen > offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) -+ /* The record is very long. It could still fit into the caller-supplied -+ buffer if we can skip padding at the end. */ -+ size_t namelen = _D_EXACT_NAMLEN (dp); -+ if (namelen <= NAME_MAX) - { -- /* The record is very long. It could still fit into the -- caller-supplied buffer if we can skip padding at the -- end. */ -- size_t namelen = _D_EXACT_NAMLEN (dp); -- if (namelen <= NAME_MAX) -- reclen = offsetof (struct __old_dirent64, d_name) + namelen + 1; -- else -- { -- /* The name is too long. Ignore this file. */ -- dirp->errcode = ENAMETOOLONG; -- dp->d_ino = 0; -- continue; -- } -+ reclen = offsetof (struct dirent64, d_name) + namelen + 1; -+ break; - } - -- /* Skip deleted and ignored files. */ -+ /* The name is too long. Ignore this file. */ -+ dirp->errcode = ENAMETOOLONG; -+ dp->d_ino = 0; - } -- while (dp->d_ino == 0); - - if (dp != NULL) - { - *result = memcpy (entry, dp, reclen); - entry->d_reclen = reclen; -- ret = 0; - } - else -- { -- *result = NULL; -- ret = dirp->errcode; -- } -+ *result = NULL; - - __libc_lock_unlock (dirp->lock); - -- return ret; -+ return dp != NULL ? 0 : dirp->errcode; - } - - compat_symbol (libc, __old_readdir64_r, readdir64_r, GLIBC_2_1); --- -2.39.3 - diff --git a/9999/0008-linux-Use-getdents64-on-readdir64-compat-implementat.patch b/9999/0008-linux-Use-getdents64-on-readdir64-compat-implementat.patch new file mode 100644 index 0000000..bf2981e --- /dev/null +++ b/9999/0008-linux-Use-getdents64-on-readdir64-compat-implementat.patch @@ -0,0 +1,250 @@ +From 43e064d5764246f49561def52f9fd592d58b7ac2 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Fri, 27 Jan 2023 14:28:34 -0300 +Subject: [PATCH 8/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 +the compat readdir64 entry. + +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/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 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) + + #if _DIRENT_MATCHES_DIRENT64 + strong_alias (__getdents64, __getdents) +-#else +-# include +- +-# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) +-# include +-# include +- +-static ssize_t +-handle_overflow (int fd, __off64_t offset, ssize_t count) +-{ +- /* If this is the first entry in the buffer, we can report the +- error. */ +- if (offset == 0) +- { +- __set_errno (EOVERFLOW); +- return -1; +- } +- +- /* Otherwise, seek to the overflowing entry, so that the next call +- will report the error, and return the data read so far. */ +- if (__lseek64 (fd, offset, SEEK_SET) != 0) +- return -1; +- return count; +-} +- +-ssize_t +-__old_getdents64 (int fd, char *buf, size_t nbytes) +-{ +- /* We do not move the individual directory entries. This is only +- possible if the target type (struct __old_dirent64) is smaller +- than the source type. */ +- _Static_assert (offsetof (struct __old_dirent64, d_name) +- <= offsetof (struct dirent64, d_name), +- "__old_dirent64 is larger than dirent64"); +- _Static_assert (__alignof__ (struct __old_dirent64) +- <= __alignof__ (struct dirent64), +- "alignment of __old_dirent64 is larger than dirent64"); +- +- ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); +- if (retval > 0) +- { +- /* This is the marker for the first entry. Offset 0 is reserved +- for the first entry (see rewinddir). Here, we use it as a +- marker for the first entry in the buffer. We never actually +- seek to offset 0 because handle_overflow reports the error +- directly, so it does not matter that the offset is incorrect +- if entries have been read from the descriptor before (so that +- the descriptor is not actually at offset 0). */ +- __off64_t previous_offset = 0; +- +- char *p = buf; +- char *end = buf + retval; +- while (p < end) +- { +- struct dirent64 *source = (struct dirent64 *) p; +- +- /* Copy out the fixed-size data. */ +- __ino_t ino = source->d_ino; +- __off64_t offset = source->d_off; +- unsigned int reclen = source->d_reclen; +- unsigned char type = source->d_type; +- +- /* Check for ino_t overflow. */ +- if (__glibc_unlikely (ino != source->d_ino)) +- return handle_overflow (fd, previous_offset, p - buf); +- +- /* Convert to the target layout. Use a separate struct and +- memcpy to side-step aliasing issues. */ +- struct __old_dirent64 result; +- result.d_ino = ino; +- result.d_off = offset; +- result.d_reclen = reclen; +- result.d_type = type; +- +- /* Write the fixed-sized part of the result to the +- buffer. */ +- size_t result_name_offset = offsetof (struct __old_dirent64, d_name); +- memcpy (p, &result, result_name_offset); +- +- /* Adjust the position of the name if necessary. Copy +- everything until the end of the record, including the +- terminating NUL byte. */ +- if (result_name_offset != offsetof (struct dirent64, d_name)) +- memmove (p + result_name_offset, source->d_name, +- reclen - offsetof (struct dirent64, d_name)); +- +- p += reclen; +- previous_offset = offset; +- } +- } +- return retval; +-} +-# 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 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) + attribute_hidden; + extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, + struct __old_dirent64 **__result); +-extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes) +- attribute_hidden; + int __old_scandir64 (const char * __dir, + struct __old_dirent64 *** __namelist, + int (*__selector) (const struct __old_dirent64 *), +diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c +index b901071aa7..88e42c5e90 100644 +--- a/sysdeps/unix/sysv/linux/readdir64.c ++++ b/sysdeps/unix/sysv/linux/readdir64.c +@@ -102,21 +102,43 @@ versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); + # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) + # include + ++/* Translate the DP64 entry to the old LFS one in the translation buffer ++ 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. */ ++static bool ++dirstream_old_entry (struct __dirstream *ds, const struct dirent64 *dp64) ++{ ++ /* Check for overflow. */ ++ if (!in_ino_t_range (dp64->d_ino)) ++ return false; ++ ++ /* And if name is too large. */ ++ if (dp64->d_reclen - offsetof (struct dirent64, d_name) > NAME_MAX) ++ return false; ++ ++ ds->filepos = dp64->d_off; ++ ++ 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; ++} ++ + attribute_compat_text_section + struct __old_dirent64 * + __old_readdir64_unlocked (DIR *dirp) + { +- struct __old_dirent64 *dp; +- int saved_errno = errno; ++ const int saved_errno = errno; + + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ +- +- size_t maxread = dirp->allocation; +- ssize_t bytes; +- +- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); ++ ssize_t bytes = __getdents64 (dirp->fd, dirp->data, dirp->allocation); + if (bytes <= 0) + { + /* Linux may fail with ENOENT on some file systems if the +@@ -127,17 +149,21 @@ __old_readdir64_unlocked (DIR *dirp) + __set_errno (saved_errno); + return NULL; + } +- dirp->size = (size_t) bytes; ++ dirp->size = bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + +- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; +- dirp->offset += dp->d_reclen; +- dirp->filepos = dp->d_off; ++ struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; ++ dirp->offset += dp64->d_reclen; + +- return dp; ++ /* Skip entries which might overflow d_ino or for memory allocation failure ++ in case of large file names. */ ++ if (dirstream_old_entry (dirp, dp64)) ++ return &dirp->tdp64; ++ ++ return NULL; + } + + attribute_compat_text_section +-- +2.41.0 + diff --git a/9999/0009-Gentoo-Disable-valgrind-based-tests-too-unreliable.patch b/9999/0009-Gentoo-Disable-valgrind-based-tests-too-unreliable.patch new file mode 100644 index 0000000..9f13cb0 --- /dev/null +++ b/9999/0009-Gentoo-Disable-valgrind-based-tests-too-unreliable.patch @@ -0,0 +1,38 @@ +From 47f6f53cd39997f8e7fea5235b27a30fbdc9dd4d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andreas=20K=2E=20H=C3=BCttel?= +Date: Sat, 23 Dec 2023 22:56:11 +0100 +Subject: [PATCH 9/9] Gentoo: Disable valgrind-based tests, too unreliable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Andreas K. Hüttel +--- + elf/Makefile | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/elf/Makefile b/elf/Makefile +index ba7b71035c..4337603c6b 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -480,7 +480,6 @@ tests += \ + unload6 \ + unload7 \ + unload8 \ +- valgrind-test \ + # tests + tests-cxx = \ + tst-dlopen-nodelete-reloc \ +@@ -611,9 +610,6 @@ $(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \ + --required=__io_vtables \ + > $@ 2>&1; $(evaluate-test) + +-ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-valgrind-smoke.out +-endif + $(objpfx)tst-valgrind-smoke.out: tst-valgrind-smoke.sh $(objpfx)ld.so $(objpfx)valgrind-test + $(SHELL) $< $(objpfx)ld.so $(rtlddir)/$(rtld-installed-name) '$(test-wrapper-env)' \ + '$(run-program-env)' '$(rpath-link)' $(objpfx)valgrind-test > $@; $(evaluate-test) +-- +2.41.0 + diff --git a/9999/0009-linux-Use-getdents64-on-readdir64-compat-implementat.patch b/9999/0009-linux-Use-getdents64-on-readdir64-compat-implementat.patch deleted file mode 100644 index 99429ea..0000000 --- a/9999/0009-linux-Use-getdents64-on-readdir64-compat-implementat.patch +++ /dev/null @@ -1,250 +0,0 @@ -From 8eb2ff5f6f4040f238bd40083d6bfbb711fc675c Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -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 -the compat readdir64 entry. - -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/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 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) - - #if _DIRENT_MATCHES_DIRENT64 - strong_alias (__getdents64, __getdents) --#else --# include -- --# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) --# include --# include -- --static ssize_t --handle_overflow (int fd, __off64_t offset, ssize_t count) --{ -- /* If this is the first entry in the buffer, we can report the -- error. */ -- if (offset == 0) -- { -- __set_errno (EOVERFLOW); -- return -1; -- } -- -- /* Otherwise, seek to the overflowing entry, so that the next call -- will report the error, and return the data read so far. */ -- if (__lseek64 (fd, offset, SEEK_SET) != 0) -- return -1; -- return count; --} -- --ssize_t --__old_getdents64 (int fd, char *buf, size_t nbytes) --{ -- /* We do not move the individual directory entries. This is only -- possible if the target type (struct __old_dirent64) is smaller -- than the source type. */ -- _Static_assert (offsetof (struct __old_dirent64, d_name) -- <= offsetof (struct dirent64, d_name), -- "__old_dirent64 is larger than dirent64"); -- _Static_assert (__alignof__ (struct __old_dirent64) -- <= __alignof__ (struct dirent64), -- "alignment of __old_dirent64 is larger than dirent64"); -- -- ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); -- if (retval > 0) -- { -- /* This is the marker for the first entry. Offset 0 is reserved -- for the first entry (see rewinddir). Here, we use it as a -- marker for the first entry in the buffer. We never actually -- seek to offset 0 because handle_overflow reports the error -- directly, so it does not matter that the offset is incorrect -- if entries have been read from the descriptor before (so that -- the descriptor is not actually at offset 0). */ -- __off64_t previous_offset = 0; -- -- char *p = buf; -- char *end = buf + retval; -- while (p < end) -- { -- struct dirent64 *source = (struct dirent64 *) p; -- -- /* Copy out the fixed-size data. */ -- __ino_t ino = source->d_ino; -- __off64_t offset = source->d_off; -- unsigned int reclen = source->d_reclen; -- unsigned char type = source->d_type; -- -- /* Check for ino_t overflow. */ -- if (__glibc_unlikely (ino != source->d_ino)) -- return handle_overflow (fd, previous_offset, p - buf); -- -- /* Convert to the target layout. Use a separate struct and -- memcpy to side-step aliasing issues. */ -- struct __old_dirent64 result; -- result.d_ino = ino; -- result.d_off = offset; -- result.d_reclen = reclen; -- result.d_type = type; -- -- /* Write the fixed-sized part of the result to the -- buffer. */ -- size_t result_name_offset = offsetof (struct __old_dirent64, d_name); -- memcpy (p, &result, result_name_offset); -- -- /* Adjust the position of the name if necessary. Copy -- everything until the end of the record, including the -- terminating NUL byte. */ -- if (result_name_offset != offsetof (struct dirent64, d_name)) -- memmove (p + result_name_offset, source->d_name, -- reclen - offsetof (struct dirent64, d_name)); -- -- p += reclen; -- previous_offset = offset; -- } -- } -- return retval; --} --# 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 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) - attribute_hidden; - extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, - struct __old_dirent64 **__result); --extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes) -- attribute_hidden; - int __old_scandir64 (const char * __dir, - struct __old_dirent64 *** __namelist, - int (*__selector) (const struct __old_dirent64 *), -diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c -index b901071aa7..88e42c5e90 100644 ---- a/sysdeps/unix/sysv/linux/readdir64.c -+++ b/sysdeps/unix/sysv/linux/readdir64.c -@@ -102,21 +102,43 @@ versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); - # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) - # include - -+/* Translate the DP64 entry to the old LFS one in the translation buffer -+ 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. */ -+static bool -+dirstream_old_entry (struct __dirstream *ds, const struct dirent64 *dp64) -+{ -+ /* Check for overflow. */ -+ if (!in_ino_t_range (dp64->d_ino)) -+ return false; -+ -+ /* And if name is too large. */ -+ if (dp64->d_reclen - offsetof (struct dirent64, d_name) > NAME_MAX) -+ return false; -+ -+ ds->filepos = dp64->d_off; -+ -+ 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; -+} -+ - attribute_compat_text_section - struct __old_dirent64 * - __old_readdir64_unlocked (DIR *dirp) - { -- struct __old_dirent64 *dp; -- int saved_errno = errno; -+ const int saved_errno = errno; - - if (dirp->offset >= dirp->size) - { - /* We've emptied out our buffer. Refill it. */ -- -- size_t maxread = dirp->allocation; -- ssize_t bytes; -- -- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); -+ ssize_t bytes = __getdents64 (dirp->fd, dirp->data, dirp->allocation); - if (bytes <= 0) - { - /* Linux may fail with ENOENT on some file systems if the -@@ -127,17 +149,21 @@ __old_readdir64_unlocked (DIR *dirp) - __set_errno (saved_errno); - return NULL; - } -- dirp->size = (size_t) bytes; -+ dirp->size = bytes; - - /* Reset the offset into the buffer. */ - dirp->offset = 0; - } - -- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; -- dirp->offset += dp->d_reclen; -- dirp->filepos = dp->d_off; -+ struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; -+ dirp->offset += dp64->d_reclen; - -- return dp; -+ /* Skip entries which might overflow d_ino or for memory allocation failure -+ in case of large file names. */ -+ if (dirstream_old_entry (dirp, dp64)) -+ return &dirp->tdp64; -+ -+ return NULL; - } - - attribute_compat_text_section --- -2.39.3 - diff --git a/9999/0011-Gentoo-Disable-valgrind-based-tests-too-unreliable.patch b/9999/0011-Gentoo-Disable-valgrind-based-tests-too-unreliable.patch deleted file mode 100644 index 4d2931f..0000000 --- a/9999/0011-Gentoo-Disable-valgrind-based-tests-too-unreliable.patch +++ /dev/null @@ -1,38 +0,0 @@ -From d63e3913e62114f4fc71862f2d57b454a5746a24 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andreas=20K=2E=20H=C3=BCttel?= -Date: Sat, 23 Dec 2023 22:56:11 +0100 -Subject: [PATCH] Gentoo: Disable valgrind-based tests, too unreliable -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Andreas K. Hüttel ---- - elf/Makefile | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/elf/Makefile b/elf/Makefile -index 1a05a6aaca..5910453e1c 100644 ---- a/elf/Makefile -+++ b/elf/Makefile -@@ -470,7 +470,6 @@ tests += \ - unload6 \ - unload7 \ - unload8 \ -- valgrind-test \ - # tests - tests-cxx = \ - tst-dlopen-nodelete-reloc \ -@@ -601,9 +600,6 @@ $(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \ - --required=__io_vtables \ - > $@ 2>&1; $(evaluate-test) - --ifeq ($(run-built-tests),yes) --tests-special += $(objpfx)tst-valgrind-smoke.out --endif - $(objpfx)tst-valgrind-smoke.out: tst-valgrind-smoke.sh $(objpfx)ld.so $(objpfx)valgrind-test - $(SHELL) $< $(objpfx)ld.so $(rtlddir)/$(rtld-installed-name) '$(test-wrapper-env)' \ - '$(run-program-env)' '$(rpath-link)' $(objpfx)valgrind-test > $@; $(evaluate-test) --- -2.41.0 - -- cgit v1.2.3-65-gdbad