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