diff options
author | 2024-01-12 00:27:10 +0100 | |
---|---|---|
committer | 2024-01-12 00:27:10 +0100 | |
commit | d53894fd2ecb4fe3ae4242b36d314d95f8222a3e (patch) | |
tree | 7ef58fe300197243997a1d9cdb7ebf9cfa1d5067 | |
parent | Rebase onto master (diff) | |
download | glibc-patches-d53894fd2ecb4fe3ae4242b36d314d95f8222a3e.tar.gz glibc-patches-d53894fd2ecb4fe3ae4242b36d314d95f8222a3e.tar.bz2 glibc-patches-d53894fd2ecb4fe3ae4242b36d314d95f8222a3e.zip |
Update qemu patch series from azanella/bz23960-dirent
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
-rw-r--r-- | 9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch | 179 | ||||
-rw-r--r-- | 9999/0005-support-Add-xreallocarray.patch | 76 | ||||
-rw-r--r-- | 9999/0006-linux-Add-__readdir64_unlocked.patch | 182 | ||||
-rw-r--r-- | 9999/0006-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch (renamed from 9999/0005-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch) | 254 | ||||
-rw-r--r-- | 9999/0007-linux-Add-__old_readdir64_unlocked.patch | 194 | ||||
-rw-r--r-- | 9999/0008-linux-Use-getdents64-on-readdir64-compat-implementat.patch | 250 |
6 files changed, 290 insertions, 845 deletions
diff --git a/9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch b/9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch index a451fd6..ddb3660 100644 --- a/9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch +++ b/9999/0004-linux-Use-getdents64-on-non-LFS-readdir.patch @@ -1,114 +1,29 @@ -From 782410070379ffbf54cb8abe71cc13fd24cfaea5 Mon Sep 17 00:00:00 2001 +From 3fac92713621f894d33a9f499bacb5b20f0d8ec3 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella <adhemerval.zanella@linaro.org> -Date: Fri, 27 Jan 2023 14:28:30 -0300 -Subject: [PATCH 4/9] linux: Use getdents64 on non-LFS readdir +Date: Tue, 20 Oct 2020 13:37:15 -0300 +Subject: [PATCH 1/3] 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. +It is similar to what non-LFS getdents do (including overflow check). 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(-) + sysdeps/unix/sysv/linux/readdir.c | 97 +++++++++++++++++++++++-------- + 1 file changed, 73 insertions(+), 24 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 <dirent/dirent.h> - # ifndef _ISOMAC - # include <dirstream.h> - # endif --# include <dirent/dirent.h> - # ifndef _ISOMAC - # include <sys/stat.h> - # include <stdbool.h> -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 <dirent.h> - #include <sys/types.h> - - #include <libc-lock.h> -@@ -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 +index 33bae4b57d..4e2214f21e 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c -@@ -21,42 +21,71 @@ +@@ -20,43 +20,92 @@ + #if !_DIRENT_MATCHES_DIRENT64 #include <dirstream.h> - -+/* 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; -+} ++#include <unistd.h> + ++# ifndef DIRENT_SET_DP_INO ++# define DIRENT_SET_DP_INO(dp, value) (dp)->d_ino = (value) ++# endif + /* Read a directory entry from DIRP. */ struct dirent * __readdir_unlocked (DIR *dirp) @@ -134,13 +49,6 @@ index 4a4c00ea07..cd0ccaf33a 100644 - 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) @@ -159,13 +67,60 @@ index 4a4c00ea07..cd0ccaf33a 100644 + dirp->offset = 0; + } + -+ struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; -+ dirp->offset += dp64->d_reclen; ++ /* These two pointers might alias the same memory buffer. Standard C ++ requires that we always use the same type for them, so we must use the ++ union type. */ ++ union ++ { ++ struct dirent64 dp64; ++ struct dirent dp; ++ char *b; ++ } *inp, *outp; ++ inp = (void*) &dirp->data[dirp->offset]; ++ outp = (void*) &dirp->data[dirp->offset]; ++ ++ const size_t size_diff = offsetof (struct dirent64, d_name) ++ - offsetof (struct dirent, d_name); ++ ++ /* Since inp->dp64.d_reclen is already aligned for the kernel structure ++ this may compute a value that is bigger than necessary. */ ++ size_t old_reclen = inp->dp64.d_reclen; ++ size_t new_reclen = ALIGN_UP (old_reclen - size_diff, ++ _Alignof (struct dirent)); ++ ++ if (!in_ino_t_range (inp->dp64.d_ino) ++ || !in_off_t_range (inp->dp64.d_off)) ++ { ++ /* Overflow. If there was at least one entry before this one, ++ return them without error, otherwise signal overflow. */ ++ if (dirp->offset != 0) ++ { ++ __lseek64 (dirp->fd, dirp->offset, SEEK_SET); ++ outp = (void*)(outp->b - dirp->data); ++ return &outp->dp; ++ } ++ __set_errno (EOVERFLOW); + return NULL; + } +- dirp->size = (size_t) bytes; + +- /* Reset the offset into the buffer. */ +- dirp->offset = 0; ++ /* Copy the data from INP and access only OUTP. */ ++ const uint64_t d_ino = inp->dp64.d_ino; ++ const int64_t d_off = inp->dp64.d_off; ++ const uint8_t d_type = inp->dp64.d_type; ++ outp->dp.d_ino = d_ino; ++ outp->dp.d_off = d_off; ++ outp->dp.d_reclen = new_reclen; ++ outp->dp.d_type = d_type; ++ memmove (outp->dp.d_name, inp->dp64.d_name, ++ old_reclen - offsetof (struct dirent64, d_name)); ++ ++ dirp->filepos = d_off; ++ dirp->offset += old_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; ++ return &outp->dp; } - - dp = (struct dirent *) &dirp->data[dirp->offset]; diff --git a/9999/0005-support-Add-xreallocarray.patch b/9999/0005-support-Add-xreallocarray.patch new file mode 100644 index 0000000..dbfae4d --- /dev/null +++ b/9999/0005-support-Add-xreallocarray.patch @@ -0,0 +1,76 @@ +From 7d0638e792ebe528af3f6d8e353eff68157d7105 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella <adhemerval.zanella@linaro.org> +Date: Wed, 1 Mar 2023 14:41:23 -0300 +Subject: [PATCH 2/3] support: Add xreallocarray + +As a wrapper over reallocarray. +--- + support/Makefile | 1 + + support/support.h | 2 ++ + support/xreallocarray.c | 29 +++++++++++++++++++++++++++++ + 3 files changed, 32 insertions(+) + create mode 100644 support/xreallocarray.c + +diff --git a/support/Makefile b/support/Makefile +index 362a51f882..d056563c15 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -201,6 +201,7 @@ libsupport-routines = \ + xread \ + xreadlink \ + xrealloc \ ++ xreallocarray \ + xrecvfrom \ + xsendto \ + xsetlocale \ +diff --git a/support/support.h b/support/support.h +index ba21ec9b5a..b4e31e4483 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -107,6 +107,8 @@ extern void *xcalloc (size_t n, size_t s) + __returns_nonnull; + extern void *xrealloc (void *o, size_t n) + __attribute_malloc__ __attribute_alloc_size__ ((2)) __attr_dealloc_free; ++extern void *xreallocarray (void *p, size_t n, size_t s) ++ __attribute_alloc_size__ ((2, 3)) __attr_dealloc_free; + extern char *xstrdup (const char *) __attribute_malloc__ __attr_dealloc_free + __returns_nonnull; + void *xposix_memalign (size_t alignment, size_t n) +diff --git a/support/xreallocarray.c b/support/xreallocarray.c +new file mode 100644 +index 0000000000..74fdaa421b +--- /dev/null ++++ b/support/xreallocarray.c +@@ -0,0 +1,29 @@ ++/* Error-checking wrapper for reallocarray ++ Copyright (C) 2016-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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <stdlib.h> ++#include <support/support.h> ++ ++void * ++xreallocarray (void *p, size_t n, size_t s) ++{ ++ void *r = reallocarray (p, n, s); ++ if (r == NULL && (p == NULL || (n != 0 && s != 0))) ++ oom_error ("reallocarray", n); ++ return r; ++} +-- +2.41.0 + diff --git a/9999/0006-linux-Add-__readdir64_unlocked.patch b/9999/0006-linux-Add-__readdir64_unlocked.patch deleted file mode 100644 index 3510868..0000000 --- a/9999/0006-linux-Add-__readdir64_unlocked.patch +++ /dev/null @@ -1,182 +0,0 @@ -From a2a34383be6e082561a09f37c5747215a70e2439 Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella <adhemerval.zanella@linaro.org> -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/0005-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 9b566a2..6450910 100644 --- a/9999/0005-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,7 +1,7 @@ -From 8b628a35f0ce66d74be6557e74e28a49a58d749a Mon Sep 17 00:00:00 2001 +From 6d5975652503acffae0566500cc15f8efc89e30a Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella <adhemerval.zanella@linaro.org> -Date: Fri, 27 Jan 2023 14:28:31 -0300 -Subject: [PATCH 5/9] linux: Set internal DIR filepos as off64_t (BZ #23960, BZ +Date: Mon, 13 Apr 2020 18:09:20 -0300 +Subject: [PATCH 3/3] linux: Set internal DIR filepos as off64_t (BZ #23960, BZ #24050) It allows to obtain the expected entry offset on telldir and set @@ -24,56 +24,55 @@ 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 + + include/dirent.h | 2 +- + sysdeps/unix/sysv/linux/Makefile | 2 + 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/dirstream.h | 9 +- sysdeps/unix/sysv/linux/opendir.c | 3 + - sysdeps/unix/sysv/linux/readdir.c | 11 +- + sysdeps/unix/sysv/linux/readdir.c | 21 ++- + sysdeps/unix/sysv/linux/readdir64.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(-) + sysdeps/unix/sysv/linux/seekdir.c | 30 +++- + sysdeps/unix/sysv/linux/telldir.c | 36 +++++ + sysdeps/unix/sysv/linux/telldir.h | 70 ++++++++++ + sysdeps/unix/sysv/linux/tst-opendir-lfs.c | 2 + + sysdeps/unix/sysv/linux/tst-opendir.c | 145 ++++++++++++++++++++ + 15 files changed, 329 insertions(+), 18 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/telldir.h - create mode 100644 sysdeps/unix/sysv/linux/tst-opendir-nolfs.c + create mode 100644 sysdeps/unix/sysv/linux/tst-opendir-lfs.c + create mode 100644 sysdeps/unix/sysv/linux/tst-opendir.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/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 <dirent/dirent.h> + # ifndef _ISOMAC + # include <dirstream.h> + # endif +-# include <dirent/dirent.h> + # ifndef _ISOMAC + # include <sys/stat.h> + # include <stdbool.h> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile -index 415aa1f14d..dc204883db 100644 +index 415aa1f14d..d5b6e26e76 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile -@@ -574,6 +574,7 @@ sysdep_routines += \ +@@ -574,6 +574,8 @@ sysdep_routines += \ tests += \ tst-getdents64 \ -+ tst-opendir-nolfs \ ++ tst-opendir \ ++ tst-opendir-lfs \ 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 +index b604576188..4e511e7654 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 @@ -85,7 +84,7 @@ index c8a0cfe93f..586d75586a 100644 + #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 +index 8bf38f8188..7c5f3419cd 100644 --- a/sysdeps/unix/sysv/linux/bits/dirent.h +++ b/sysdeps/unix/sysv/linux/bits/dirent.h @@ -57,3 +57,7 @@ struct dirent64 @@ -97,7 +96,7 @@ index ab34d986ff..bb02dcb70a 100644 + 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 +index b86f79f133..3a4eba03f1 100644 --- a/sysdeps/unix/sysv/linux/closedir.c +++ b/sysdeps/unix/sysv/linux/closedir.c @@ -47,6 +47,10 @@ __closedir (DIR *dirp) @@ -112,10 +111,10 @@ index f1c2608642..9585a6ca3a 100644 return __close_nocancel (fd); diff --git a/sysdeps/unix/sysv/linux/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h -index adcf8234f1..8f58a1c3a6 100644 +index 3d3643733a..fc2586566a 100644 --- a/sysdeps/unix/sysv/linux/dirstream.h +++ b/sysdeps/unix/sysv/linux/dirstream.h -@@ -22,6 +22,7 @@ +@@ -21,6 +21,7 @@ #include <sys/types.h> #include <libc-lock.h> @@ -123,7 +122,7 @@ index adcf8234f1..8f58a1c3a6 100644 /* Directory stream type. -@@ -38,13 +39,16 @@ struct __dirstream +@@ -37,10 +38,16 @@ struct __dirstream size_t size; /* Total valid data in the block. */ size_t offset; /* Current offset into the block. */ @@ -132,17 +131,17 @@ index adcf8234f1..8f58a1c3a6 100644 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. */ ++ /* The array is used to map long to off_64 for telldir/seekdir for ABIs ++ where long can not fully represend a LFS off_t value. */ ++ struct dirstream_loc_t locs; +#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 4336196a4d..3e2caabb9d 100644 +index b5218138ec..fda2c5f9fe 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, @@ -156,36 +155,68 @@ index 4336196a4d..3e2caabb9d 100644 return dirp; } diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c -index cd0ccaf33a..7a7f484c36 100644 +index 4e2214f21e..d474f70a8d 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; +@@ -75,25 +75,22 @@ __readdir_unlocked (DIR *dirp) + size_t new_reclen = ALIGN_UP (old_reclen - size_diff, + _Alignof (struct dirent)); + +- if (!in_ino_t_range (inp->dp64.d_ino) +- || !in_off_t_range (inp->dp64.d_off)) ++ /* telldir can not return an error, so preallocate a map entry if ++ d_off can not be used directly. */ ++ if (telldir_need_dirstream (inp->dp64.d_off)) + { +- /* Overflow. If there was at least one entry before this one, +- return them without error, otherwise signal overflow. */ +- if (dirp->offset != 0) +- { +- __lseek64 (dirp->fd, dirp->offset, SEEK_SET); +- outp = (void*)(outp->b - dirp->data); +- return &outp->dp; +- } +- __set_errno (EOVERFLOW); +- return NULL; ++ dirstream_loc_add (&dirp->locs, inp->dp64.d_off); ++ if (dirstream_loc_has_failed (&dirp->locs)) ++ return NULL; + } + + /* Copy the data from INP and access only OUTP. */ + const uint64_t d_ino = inp->dp64.d_ino; + const int64_t d_off = inp->dp64.d_off; + const uint8_t d_type = inp->dp64.d_type; ++ /* This will clamp both d_off and d_ino values, which is required to ++ avoid return EOVERFLOW. The lelldir/seekdir uses the 'locs' value ++ if the value overflows. */ + outp->dp.d_ino = d_ino; + outp->dp.d_off = d_off; + outp->dp.d_reclen = new_reclen; +diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c +index e6f5108c0a..d61c5e6e26 100644 +--- a/sysdeps/unix/sysv/linux/readdir64.c ++++ b/sysdeps/unix/sysv/linux/readdir64.c +@@ -68,6 +68,17 @@ __readdir64 (DIR *dirp) + dirp->offset += dp->d_reclen; + dirp->filepos = dp->d_off; -+ /* 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)) ++#if _DIRENT_OFFSET_TRANSLATION ++ /* telldir can not return an error, so preallocate a map entry if ++ d_off can not be used directly. */ ++ if (telldir_need_dirstream (dp->d_off)) + { -+ dirstream_loc_add (&ds->locs, dp64->d_off); -+ if (dirstream_loc_has_failed (&ds->locs)) -+ return false; ++ dirstream_loc_add (&dirp->locs, dp->d_off); ++ if (dirstream_loc_has_failed (&dirp->locs)) ++ dp = NULL; + } ++#endif + - 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; + #if IS_IN (libc) + __libc_lock_unlock (dirp->lock); + #endif diff --git a/sysdeps/unix/sysv/linux/rewinddir.c b/sysdeps/unix/sysv/linux/rewinddir.c -index c0fb7aa765..1b158a584f 100644 +index af85000a28..4936be5c6a 100644 --- a/sysdeps/unix/sysv/linux/rewinddir.c +++ b/sysdeps/unix/sysv/linux/rewinddir.c @@ -33,6 +33,11 @@ __rewinddir (DIR *dirp) @@ -201,10 +232,10 @@ index c0fb7aa765..1b158a584f 100644 __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 +index 52005878fc..cd49676750 100644 --- a/sysdeps/unix/sysv/linux/seekdir.c +++ b/sysdeps/unix/sysv/linux/seekdir.c -@@ -22,14 +22,39 @@ +@@ -22,14 +22,36 @@ #include <dirstream.h> /* Seek to position POS in DIRP. */ @@ -217,8 +248,6 @@ index 939ccc4447..30cce691a4 100644 __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 }; @@ -239,24 +268,23 @@ index 939ccc4447..30cce691a4 100644 + filepos = pos; +#endif + -+ if (dirp->filepos != filepos) -+ { -+ __lseek64 (dirp->fd, filepos, SEEK_SET); -+ dirp->filepos = filepos; -+ dirp->offset = 0; -+ dirp->size = 0; -+ } ++ __lseek64 (dirp->fd, filepos, SEEK_SET); ++ dirp->filepos = filepos; + dirp->offset = 0; +- dirp->filepos = pos; ++ 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 +index c8dff30719..8d9e2c9db2 100644 --- a/sysdeps/unix/sysv/linux/telldir.c +++ b/sysdeps/unix/sysv/linux/telldir.c -@@ -15,9 +15,11 @@ +@@ -15,9 +15,12 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ ++#include <stdio.h> +#include <assert.h> #include <dirent.h> @@ -265,7 +293,7 @@ index 1e5c129e9f..c3ef14f3da 100644 /* Return the current position of DIRP. */ long int -@@ -26,7 +28,40 @@ telldir (DIR *dirp) +@@ -26,7 +29,40 @@ telldir (DIR *dirp) long int ret; __libc_lock_lock (dirp->lock); @@ -287,15 +315,15 @@ index 1e5c129e9f..c3ef14f3da 100644 + 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)); ++ for (i = 0; ;i++) ++ { ++ /* It should be pre-allocated on readdir. */ ++ assert (i < dirstream_loc_size (&dirp->locs)); ++ if (*dirstream_loc_at (&dirp->locs, i) == dirp->filepos) ++ break; ++ } + + dsp.p.is_packed = 0; -+ /* This assignment might overflow, however most likely ENOME would -+ happen long before. */ + dsp.p.info = i; + } + @@ -308,10 +336,10 @@ index 1e5c129e9f..c3ef14f3da 100644 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 +index 0000000000..7772129db0 --- /dev/null +++ b/sysdeps/unix/sysv/linux/telldir.h -@@ -0,0 +1,65 @@ +@@ -0,0 +1,70 @@ +/* Linux internal telldir definitions. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -333,7 +361,15 @@ index 0000000000..758bcb0eb3 +#ifndef _TELLDIR_H +#define _TELLDIR_H 1 + ++#include <dirent.h> ++ +#if _DIRENT_OFFSET_TRANSLATION ++ ++_Static_assert (sizeof (long int) < sizeof (__off64_t), ++ "sizeof (long int) >= sizeof (__off64_t)"); ++ ++# include <intprops.h> ++ +/* 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 @@ -352,9 +388,6 @@ index 0000000000..758bcb0eb3 + } 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. */ @@ -367,7 +400,7 @@ index 0000000000..758bcb0eb3 +static __always_inline bool +telldir_need_dirstream (__off64_t d_off) +{ -+ return d_off >= 1UL << 31; ++ return ! (TYPE_MINIMUM (off_t) <= d_off && d_off <= TYPE_MAXIMUM (off_t)); +} +#else + @@ -377,12 +410,20 @@ index 0000000000..758bcb0eb3 +#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 +diff --git a/sysdeps/unix/sysv/linux/tst-opendir-lfs.c b/sysdeps/unix/sysv/linux/tst-opendir-lfs.c new file mode 100644 -index 0000000000..52e18171a7 +index 0000000000..1de1891fb4 --- /dev/null -+++ b/sysdeps/unix/sysv/linux/tst-opendir-nolfs.c -@@ -0,0 +1,146 @@ ++++ b/sysdeps/unix/sysv/linux/tst-opendir-lfs.c +@@ -0,0 +1,2 @@ ++#define _FILE_OFFSET_BITS 64 ++#include "tst-opendir.c" +diff --git a/sysdeps/unix/sysv/linux/tst-opendir.c b/sysdeps/unix/sysv/linux/tst-opendir.c +new file mode 100644 +index 0000000000..216ecf123f +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-opendir.c +@@ -0,0 +1,145 @@ +/* Check multiple telldir and seekdir. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -455,17 +496,18 @@ index 0000000000..52e18171a7 + 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 *)); ++ long int *tdirp = xreallocarray (NULL, nfiles, sizeof (long int)); ++ struct dirent **ddirp = xreallocarray (NULL, 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; ++ tdirp[count] = telldir (dirp); + ddirp[count] = xmalloc (dp->d_reclen); + memcpy (ddirp[count], dp, dp->d_reclen); + } @@ -499,11 +541,10 @@ index 0000000000..52e18171a7 + 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)) ++ if (in_ino_t_range (entry.d_ino)) + { + 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. */ @@ -517,7 +558,6 @@ index 0000000000..52e18171a7 + } + } + -+ /* direntries_read has been called more than once. */ + TEST_COMPARE (count, i); + + free (tdirp); diff --git a/9999/0007-linux-Add-__old_readdir64_unlocked.patch b/9999/0007-linux-Add-__old_readdir64_unlocked.patch deleted file mode 100644 index 2b99897..0000000 --- a/9999/0007-linux-Add-__old_readdir64_unlocked.patch +++ /dev/null @@ -1,194 +0,0 @@ -From f1d798104d5adfdec9aff9390dd7b62014d888eb Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella <adhemerval.zanella@linaro.org> -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/0008-linux-Use-getdents64-on-readdir64-compat-implementat.patch b/9999/0008-linux-Use-getdents64-on-readdir64-compat-implementat.patch deleted file mode 100644 index bf2981e..0000000 --- a/9999/0008-linux-Use-getdents64-on-readdir64-compat-implementat.patch +++ /dev/null @@ -1,250 +0,0 @@ -From 43e064d5764246f49561def52f9fd592d58b7ac2 Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella <adhemerval.zanella@linaro.org> -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 <libc-lock.h> - #include <telldir.h> - -+#include <shlib-compat.h> -+#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) -+# include <olddirent.h> -+#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 <shlib-compat.h> -- --# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) --# include <olddirent.h> --# include <unistd.h> -- --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 <olddirent.h> - -+/* 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 - |