]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Implement scandirat function
authorUlrich Drepper <drepper@gmail.com>
Tue, 9 Aug 2011 13:57:55 +0000 (09:57 -0400)
committerUlrich Drepper <drepper@gmail.com>
Tue, 9 Aug 2011 13:57:55 +0000 (09:57 -0400)
16 files changed:
ChangeLog
NEWS
Versions.def
dirent/Makefile
dirent/Versions
dirent/dirent.h
dirent/opendir.c
dirent/scandir.c
dirent/scandir64.c
dirent/scandirat.c [new file with mode: 0644]
dirent/scandirat64.c [new file with mode: 0644]
include/dirent.h
sysdeps/unix/opendir.c
sysdeps/unix/sysv/linux/i386/scandir64.c
sysdeps/wordsize-64/scandirat.c [new file with mode: 0644]
sysdeps/wordsize-64/scandirat64.c [new file with mode: 0644]

index 4b6a62f07aa0f88af528f634e5b825c8a034f24d..3ca823237264e2bf9a0168cbe327a4b7384bda7c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2011-08-09  Ulrich Drepper  <drepper@gmail.com>
+
+       * Versions.def [libc]: Add GLIBC_2.15.
+       * dirent/Makefile (routines): Add scandirat and scandirat64.
+       * dirent/Versions [libc]: Export scandirat and scandirat64 for
+       GLIBC_2.15.
+       * dirent/dirent.h: Declare scandirat and scandirat64.
+       * dirent/scandirat.c: New file.
+       * dirent/scandirat64.c: New file.
+       * sysdeps/wordsize-64/scandirat.c: New file.
+       * sysdeps/wordsize-64/scandirat64.c: New file.
+       * dirent/opendir.c: Define opendirat.
+       * dirent/scandir.c: Move code to scandirat.c.  Implement scandir
+       using scandirat.
+       * dirent/scandir64.c: Adjust for scandir.c change.
+       * include/dirent.h: Define scandir_cancel_struct.  Declare __opendirat,
+       __scandirat64, and __scandir_cancel_handler.
+       * sysdeps/unix/opendir.c: Rename __opendir to __opendirat.  Take
+       additional parameter and use openat instead of open (outside of ld.so).
+       Add new __opendir as wrapper around __opendirat.
+       * sysdeps/unix/sysv/linux/i386/scandir64.c: Reimplement __old_scandir64
+       here without requiring old scandirat implementation.
+
 2011-08-08  Ulrich Drepper  <drepper@gmail.com>
 
        * dirent/scandir.c (cancel_handler): Renamed to
diff --git a/NEWS b/NEWS
index 1abcae1f9dd359b457ffdd9e647d6c5270531d1f..78810a9d5eb2f5435f3066f8b808b408d4bfdbac 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2011-7-23
+GNU C Library NEWS -- history of user-visible changes.  2011-8-8
 Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -26,6 +26,9 @@ Version 2.15
 
 * Optimized strcat and strncat on x86-64.
   Contributed by Liubov Dmitrieva.
+
+* New interfaces: scandirat, scandirat64
+  Implemented by Ulrich Drepper.
 \f
 Version 2.14
 
index 666ea7310860b1c4e3d4130766a323f9782371f5..98c28001acc3655ec3d9f6e1a8b13bffda036149 100644 (file)
@@ -31,6 +31,7 @@ libc {
   GLIBC_2.12
   GLIBC_2.13
   GLIBC_2.14
+  GLIBC_2.15
 %ifdef USE_IN_LIBIO
   HURD_CTHREADS_0.3
 %endif
index ef639f209594419969cc589e46ccfb12490e2fed..07f706e6781fe59a8be94acc378b5e0f4ae11f0c 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 1991-2000,2002,2003,2005,2006 Free Software Foundation, Inc.
+# Copyright (C) 1991-2000,2002,2003,2005,2006,2011 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
@@ -25,7 +25,8 @@ headers               := dirent.h bits/dirent.h
 routines       := opendir closedir readdir readdir_r rewinddir \
                   seekdir telldir scandir alphasort versionsort \
                   getdents getdents64 dirfd readdir64 readdir64_r scandir64 \
-                  alphasort64 versionsort64 fdopendir
+                  alphasort64 versionsort64 fdopendir \
+                  scandirat scandirat64
 distribute := dirstream.h
 
 tests     := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \
index 41c15844266ae4402dbbf99fe445880251684df6..d976d373f63139b9810829f9e9a363cd0b75a709 100644 (file)
@@ -44,4 +44,7 @@ libc {
   GLIBC_2.4 {
     fdopendir;
   }
+  GLIBC_2.15 {
+    scandirat; scandirat64;
+  }
 }
index bb4ede15802df85b4ad05c311dabf7875f64e53a..6a5a0ef81c5cc10223cf141eb8e93d1372c3a8bd 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-2000,2003-2005,2009,2010 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2000,2003-2005,2009,2010,2011
+   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
@@ -247,7 +248,10 @@ extern int dirfd (DIR *__dirp) __THROW __nonnull ((1));
 /* Scan the directory DIR, calling SELECTOR on each directory entry.
    Entries for which SELECT returns nonzero are individually malloc'd,
    sorted using qsort with CMP, and collected in a malloc'd array in
-   *NAMELIST.  Returns the number of entries selected, or -1 on error.  */
+   *NAMELIST.  Returns the number of entries selected, or -1 on error.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
 # ifndef __USE_FILE_OFFSET64
 extern int scandir (__const char *__restrict __dir,
                    struct dirent ***__restrict __namelist,
@@ -280,6 +284,43 @@ extern int scandir64 (__const char *__restrict __dir,
      __nonnull ((1, 2));
 # endif
 
+# ifdef __USE_GNU
+/* Similar to `scandir' but a relative DIR name is interpreted relative
+   to the directory for which DFD is a descriptor.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+#  ifndef __USE_FILE_OFFSET64
+extern int scandirat (int __dfd, __const char *__restrict __dir,
+                     struct dirent ***__restrict __namelist,
+                     int (*__selector) (__const struct dirent *),
+                     int (*__cmp) (__const struct dirent **,
+                                   __const struct dirent **))
+     __nonnull ((2, 3));
+#  else
+#   ifdef __REDIRECT
+extern int __REDIRECT (scandirat,
+                      (int __dfd, __const char *__restrict __dir,
+                       struct dirent ***__restrict __namelist,
+                       int (*__selector) (__const struct dirent *),
+                       int (*__cmp) (__const struct dirent **,
+                                     __const struct dirent **)),
+                      scandirat64) __nonnull ((2, 3));
+#   else
+#    define scandirat scandirat64
+#   endif
+#  endif
+
+/* This function is like `scandir' but it uses the 64bit dirent structure.
+   Please note that the CMP function must now work with struct dirent64 **.  */
+extern int scandirat64 (int __dfd, __const char *__restrict __dir,
+                       struct dirent64 ***__restrict __namelist,
+                       int (*__selector) (__const struct dirent64 *),
+                       int (*__cmp) (__const struct dirent64 **,
+                                     __const struct dirent64 **))
+     __nonnull ((2, 3));
+# endif
+
 /* Function to compare two `struct dirent's alphabetically.  */
 # ifndef __USE_FILE_OFFSET64
 extern int alphasort (__const struct dirent **__e1,
index 771013f6eb2c492d6d8d95ec9eac6e82da18783e..6375b6786a3c3fec2bcea82a0fe9ab1d43cff61a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1995, 1996, 1997, 2011 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
 #include <dirent.h>
 
 
-/* Open a directory stream on NAME.  */
 DIR *
-__opendir (const char *name)
+__opendirat (int dfd, const char *name)
 {
   __set_errno (ENOSYS);
   return NULL;
 }
+
+
+/* Open a directory stream on NAME.  */
+DIR *
+__opendir (const char *name)
+{
+  return __opendirat (AT_FDCWD, name);
+}
 weak_alias (__opendir, opendir)
 
 stub_warning (opendir)
index e90b942b1d69030ae61a32d5b1f8d15d63536952..3f69a8db7744ea5b98e04131c46906391b597d83 100644 (file)
    02111-1307 USA.  */
 
 #include <dirent.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <bits/libc-lock.h>
+#include <fcntl.h>
 
 #ifndef SCANDIR
 # define SCANDIR scandir
-# define READDIR __readdir
+# define SCANDIRAT scandirat
 # define DIRENT_TYPE struct dirent
 #endif
 
-#ifndef SCANDIR_CANCEL
-# define SCANDIR_CANCEL
-struct scandir_cancel_struct
-{
-  DIR *dp;
-  void *v;
-  size_t cnt;
-};
-
-# ifndef SKIP_SCANDIR_CANCEL
-void
-__scandir_cancel_handler (void *arg)
-{
-  struct scandir_cancel_struct *cp = arg;
-  size_t i;
-  void **v = cp->v;
-
-  for (i = 0; i < cp->cnt; ++i)
-    free (v[i]);
-  free (v);
-  (void) __closedir (cp->dp);
-}
-# else
-extern void __scandir_cancel_handler (void *arg);
-# endif
-#endif
-
 
 int
 SCANDIR (dir, namelist, select, cmp)
@@ -64,91 +34,5 @@ SCANDIR (dir, namelist, select, cmp)
      int (*select) (const DIRENT_TYPE *);
      int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **);
 {
-  DIR *dp = __opendir (dir);
-  DIRENT_TYPE **v = NULL;
-  size_t vsize = 0;
-  struct scandir_cancel_struct c;
-  DIRENT_TYPE *d;
-  int save;
-
-  if (dp == NULL)
-    return -1;
-
-  save = errno;
-  __set_errno (0);
-
-  c.dp = dp;
-  c.v = NULL;
-  c.cnt = 0;
-  __libc_cleanup_push (__scandir_cancel_handler, &c);
-
-  while ((d = READDIR (dp)) != NULL)
-    {
-      int use_it = select == NULL;
-
-      if (! use_it)
-       {
-         use_it = select (d);
-         /* The select function might have changed errno.  It was
-            zero before and it need to be again to make the latter
-            tests work.  */
-         __set_errno (0);
-       }
-
-      if (use_it)
-       {
-         DIRENT_TYPE *vnew;
-         size_t dsize;
-
-         /* Ignore errors from select or readdir */
-         __set_errno (0);
-
-         if (__builtin_expect (c.cnt == vsize, 0))
-           {
-             DIRENT_TYPE **new;
-             if (vsize == 0)
-               vsize = 10;
-             else
-               vsize *= 2;
-             new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v));
-             if (new == NULL)
-               break;
-             v = new;
-             c.v = (void *) v;
-           }
-
-         dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
-         vnew = (DIRENT_TYPE *) malloc (dsize);
-         if (vnew == NULL)
-           break;
-
-         v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize);
-       }
-    }
-
-  if (__builtin_expect (errno, 0) != 0)
-    {
-      save = errno;
-
-      while (c.cnt > 0)
-       free (v[--c.cnt]);
-      free (v);
-      c.cnt = -1;
-    }
-  else
-    {
-      /* Sort the list if we have a comparison function to sort with.  */
-      if (cmp != NULL)
-       qsort (v, c.cnt, sizeof (*v),
-              (int (*) (const void *, const void *)) cmp);
-
-      *namelist = v;
-    }
-
-  __libc_cleanup_pop (0);
-
-  (void) __closedir (dp);
-  __set_errno (save);
-
-  return c.cnt;
+  return SCANDIRAT (AT_FDCWD, dir, namelist, select, cmp);
 }
index 274822e125b7634a7b60190a1c45113ebc40b3ac..21a936e4bb4d88bc900ebcf9468713c7288c0823 100644 (file)
 #include <dirent.h>
 
 #define SCANDIR scandir64
-#define READDIR __readdir64
+#define SCANDIRAT scandirat64
 #define DIRENT_TYPE struct dirent64
-#define SKIP_SCANDIR_CANCEL 1
-
-int scandir64 (__const char *__restrict __dir,
-              struct dirent64 ***__restrict __namelist,
-              int (*__selector) (__const struct dirent64 *),
-              int (*__cmp) (__const struct dirent64 **,
-                            __const struct dirent64 **));
 
 #include <dirent/scandir.c>
diff --git a/dirent/scandirat.c b/dirent/scandirat.c
new file mode 100644 (file)
index 0000000..e6f5ece
--- /dev/null
@@ -0,0 +1,143 @@
+/* Copyright (C) 1992-1998,2000,2002,2003,2009,2011
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
+
+#ifndef SCANDIRAT
+# define SCANDIRAT scandirat
+# define READDIR __readdir
+# define DIRENT_TYPE struct dirent
+#endif
+
+#ifndef SKIP_SCANDIR_CANCEL
+void
+__scandir_cancel_handler (void *arg)
+{
+  struct scandir_cancel_struct *cp = arg;
+  size_t i;
+  void **v = cp->v;
+
+  for (i = 0; i < cp->cnt; ++i)
+    free (v[i]);
+  free (v);
+  (void) __closedir (cp->dp);
+}
+#endif
+
+
+int
+SCANDIRAT (dfd, dir, namelist, select, cmp)
+     int dfd;
+     const char *dir;
+     DIRENT_TYPE ***namelist;
+     int (*select) (const DIRENT_TYPE *);
+     int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **);
+{
+  DIR *dp = __opendirat (dfd, dir);
+  DIRENT_TYPE **v = NULL;
+  size_t vsize = 0;
+  struct scandir_cancel_struct c;
+  DIRENT_TYPE *d;
+  int save;
+
+  if (dp == NULL)
+    return -1;
+
+  save = errno;
+  __set_errno (0);
+
+  c.dp = dp;
+  c.v = NULL;
+  c.cnt = 0;
+  __libc_cleanup_push (__scandir_cancel_handler, &c);
+
+  while ((d = READDIR (dp)) != NULL)
+    {
+      int use_it = select == NULL;
+
+      if (! use_it)
+       {
+         use_it = select (d);
+         /* The select function might have changed errno.  It was
+            zero before and it need to be again to make the latter
+            tests work.  */
+         __set_errno (0);
+       }
+
+      if (use_it)
+       {
+         DIRENT_TYPE *vnew;
+         size_t dsize;
+
+         /* Ignore errors from select or readdir */
+         __set_errno (0);
+
+         if (__builtin_expect (c.cnt == vsize, 0))
+           {
+             DIRENT_TYPE **new;
+             if (vsize == 0)
+               vsize = 10;
+             else
+               vsize *= 2;
+             new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v));
+             if (new == NULL)
+               break;
+             v = new;
+             c.v = (void *) v;
+           }
+
+         dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
+         vnew = (DIRENT_TYPE *) malloc (dsize);
+         if (vnew == NULL)
+           break;
+
+         v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize);
+       }
+    }
+
+  if (__builtin_expect (errno, 0) != 0)
+    {
+      save = errno;
+
+      while (c.cnt > 0)
+       free (v[--c.cnt]);
+      free (v);
+      c.cnt = -1;
+    }
+  else
+    {
+      /* Sort the list if we have a comparison function to sort with.  */
+      if (cmp != NULL)
+       qsort (v, c.cnt, sizeof (*v),
+              (int (*) (const void *, const void *)) cmp);
+
+      *namelist = v;
+    }
+
+  __libc_cleanup_pop (0);
+
+  (void) __closedir (dp);
+  __set_errno (save);
+
+  return c.cnt;
+}
diff --git a/dirent/scandirat64.c b/dirent/scandirat64.c
new file mode 100644 (file)
index 0000000..c4afb90
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) 2000, 2009, 2011 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <dirent.h>
+
+#define SCANDIRAT __scandirat64
+#define READDIR __readdir64
+#define DIRENT_TYPE struct dirent64
+#define SKIP_SCANDIR_CANCEL 1
+
+#include "scandirat.c"
+
+weak_alias (__scandirat64, scandirat64)
index 0f8f1cbe882fa45ec3c3b0024193a5c45d997c40..9ed587689229246b32f105699c0bc9665bea71b8 100644 (file)
@@ -4,8 +4,16 @@
 # include <sys/stat.h>
 # include <stdbool.h>
 
+struct scandir_cancel_struct
+{
+  DIR *dp;
+  void *v;
+  size_t cnt;
+};
+
 /* Now define the internal interfaces.  */
 extern DIR *__opendir (__const char *__name);
+extern DIR *__opendirat (int dfd, __const char *__name) internal_function;
 extern DIR *__fdopendir (int __fd);
 extern int __closedir (DIR *__dirp);
 extern struct dirent *__readdir (DIR *__dirp);
@@ -19,6 +27,11 @@ extern int __scandir64 (__const char * __dir,
                        int (*__selector) (__const struct dirent64 *),
                        int (*__cmp) (__const struct dirent64 **,
                                      __const struct dirent64 **));
+extern int __scandirat64 (int __dfd, __const char * __dir,
+                         struct dirent64 *** __namelist,
+                         int (*__selector) (__const struct dirent64 *),
+                         int (*__cmp) (__const struct dirent64 **,
+                                       __const struct dirent64 **));
 extern __ssize_t __getdents (int __fd, char *__buf, size_t __nbytes)
      internal_function;
 extern __ssize_t __getdents64 (int __fd, char *__buf, size_t __nbytes)
@@ -31,6 +44,7 @@ extern int __versionsort64 (const struct dirent64 **a,
 extern DIR *__alloc_dir (int fd, bool close_fd, int flags,
                         const struct stat64 *statp)
      internal_function;
+extern void __scandir_cancel_handler (void *arg);
 
 libc_hidden_proto (rewinddir)
 
index c2d1ddaf885b5b7cd8a78d5d4cfca4c35d0787f9..58d31764da4476e971194bd7b405edfb4e8c1af5 100644 (file)
@@ -17,6 +17,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
@@ -76,9 +77,9 @@ tryopen_o_directory (void)
 #endif
 
 
-/* Open a directory stream on NAME.  */
 DIR *
-__opendir (const char *name)
+internal_function
+__opendirat (int dfd, const char *name)
 {
   struct stat64 statbuf;
   struct stat64 *statp = NULL;
@@ -116,7 +117,13 @@ __opendir (const char *name)
 #ifdef O_CLOEXEC
   flags |= O_CLOEXEC;
 #endif
-  int fd = open_not_cancel_2 (name, flags);
+  int fd;
+#ifdef IS_IN_rtld
+  assert (dfd == AT_FDCWD);
+  fd = open_not_cancel_2 (name, flags);
+#else
+  fd = openat_not_cancel_3 (dfd, name, flags);
+#endif
   if (__builtin_expect (fd, 0) < 0)
     return NULL;
 
@@ -140,6 +147,14 @@ __opendir (const char *name)
 
   return __alloc_dir (fd, true, 0, statp);
 }
+
+
+/* Open a directory stream on NAME.  */
+DIR *
+__opendir (const char *name)
+{
+  return __opendirat (AT_FDCWD, name);
+}
 weak_alias (__opendir, opendir)
 
 
index 837e1b9438d323546db893e6ed78f936a130da6b..dacac0a44c23c8274104855557faf60de7be1843 100644 (file)
@@ -19,6 +19,7 @@
 #include <dirent.h>
 
 #define SCANDIR __scandir64
+#define SCANDIRAT __scandirat64
 #define READDIR __readdir64
 #define DIRENT_TYPE struct dirent64
 #define SKIP_SCANDIR_CANCEL 1
 versioned_symbol (libc, __scandir64, scandir64, GLIBC_2_2);
 
 #if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
+# include <errno.h>
+# include "olddirent.h"
 
-#include <sysdeps/unix/sysv/linux/i386/olddirent.h>
+int
+__old_scandir64 (dir, namelist, select, cmp)
+     const char *dir;
+     struct __old_dirent64 ***namelist;
+     int (*select) (const struct __old_dirent64 *);
+     int (*cmp) (const struct __old_dirent64 **,
+                const struct __old_dirent64 **);
+{
+  DIR *dp = __opendir (dir);
+  struct __old_dirent64 **v = NULL;
+  size_t vsize = 0;
+  struct scandir_cancel_struct c;
+  struct __old_dirent64 *d;
+  int save;
 
-#define SCANDIR attribute_compat_text_section __old_scandir64
-#define READDIR __old_readdir64
-#define DIRENT_TYPE struct __old_dirent64
+  if (dp == NULL)
+    return -1;
 
-#include <dirent/scandir.c>
+  save = errno;
+  __set_errno (0);
+
+  c.dp = dp;
+  c.v = NULL;
+  c.cnt = 0;
+  __libc_cleanup_push (__scandir_cancel_handler, &c);
+
+  while ((d = __old_readdir64 (dp)) != NULL)
+    {
+      int use_it = select == NULL;
+
+      if (! use_it)
+       {
+         use_it = select (d);
+         /* The select function might have changed errno.  It was
+            zero before and it need to be again to make the latter
+            tests work.  */
+         __set_errno (0);
+       }
+
+      if (use_it)
+       {
+         struct __old_dirent64 *vnew;
+         size_t dsize;
+
+         /* Ignore errors from select or readdir */
+         __set_errno (0);
+
+         if (__builtin_expect (c.cnt == vsize, 0))
+           {
+             struct __old_dirent64 **new;
+             if (vsize == 0)
+               vsize = 10;
+             else
+               vsize *= 2;
+             new = (struct __old_dirent64 **) realloc (v,
+                                                       vsize * sizeof (*v));
+             if (new == NULL)
+               break;
+             v = new;
+             c.v = (void *) v;
+           }
+
+         dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
+         vnew = (struct __old_dirent64 *) malloc (dsize);
+         if (vnew == NULL)
+           break;
+
+         v[c.cnt++] = (struct __old_dirent64 *) memcpy (vnew, d, dsize);
+       }
+    }
+
+  if (__builtin_expect (errno, 0) != 0)
+    {
+      save = errno;
+
+      while (c.cnt > 0)
+       free (v[--c.cnt]);
+      free (v);
+      c.cnt = -1;
+    }
+  else
+    {
+      /* Sort the list if we have a comparison function to sort with.  */
+      if (cmp != NULL)
+       qsort (v, c.cnt, sizeof (*v),
+              (int (*) (const void *, const void *)) cmp);
+
+      *namelist = v;
+    }
+
+  __libc_cleanup_pop (0);
+
+  (void) __closedir (dp);
+  __set_errno (save);
 
+  return c.cnt;
+}
 compat_symbol (libc, __old_scandir64, scandir64, GLIBC_2_1);
 
 #endif
diff --git a/sysdeps/wordsize-64/scandirat.c b/sysdeps/wordsize-64/scandirat.c
new file mode 100644 (file)
index 0000000..02b8fde
--- /dev/null
@@ -0,0 +1,6 @@
+#define scandirat64 scandirat64_renamed
+
+#include "../../dirent/scandirat.c"
+
+#undef scandirat64
+weak_alias (scandirat, scandirat64)
diff --git a/sysdeps/wordsize-64/scandirat64.c b/sysdeps/wordsize-64/scandirat64.c
new file mode 100644 (file)
index 0000000..fb93865
--- /dev/null
@@ -0,0 +1 @@
+/* Defined in scandirat.c.  */