summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-08-09 09:57:55 -0400
committerUlrich Drepper <drepper@gmail.com>2011-08-09 09:57:55 -0400
commitc55fbd1ea768f9fdef34a01377702c0d72cbc213 (patch)
tree0e67d339ad240756843292384535c40cad03df95
parent879165f25a1a6b13995e43c11e88b1a21b6f101e (diff)
downloadglibc-c55fbd1ea768f9fdef34a01377702c0d72cbc213.tar.gz
Implement scandirat function
-rw-r--r--ChangeLog23
-rw-r--r--NEWS5
-rw-r--r--Versions.def1
-rw-r--r--dirent/Makefile5
-rw-r--r--dirent/Versions3
-rw-r--r--dirent/dirent.h45
-rw-r--r--dirent/opendir.c13
-rw-r--r--dirent/scandir.c122
-rw-r--r--dirent/scandir64.c9
-rw-r--r--dirent/scandirat.c143
-rw-r--r--dirent/scandirat64.c28
-rw-r--r--include/dirent.h14
-rw-r--r--sysdeps/unix/opendir.c21
-rw-r--r--sysdeps/unix/sysv/linux/i386/scandir64.c102
-rw-r--r--sysdeps/wordsize-64/scandirat.c6
-rw-r--r--sysdeps/wordsize-64/scandirat64.c1
16 files changed, 398 insertions, 143 deletions
diff --git a/ChangeLog b/ChangeLog
index 4b6a62f07a..3ca8232372 100644
--- 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 1abcae1f9d..78810a9d5e 100644
--- 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.
Version 2.14
diff --git a/Versions.def b/Versions.def
index 666ea73108..98c28001ac 100644
--- a/Versions.def
+++ b/Versions.def
@@ -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
diff --git a/dirent/Makefile b/dirent/Makefile
index ef639f2095..07f706e678 100644
--- a/dirent/Makefile
+++ b/dirent/Makefile
@@ -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 \
diff --git a/dirent/Versions b/dirent/Versions
index 41c1584426..d976d373f6 100644
--- a/dirent/Versions
+++ b/dirent/Versions
@@ -44,4 +44,7 @@ libc {
GLIBC_2.4 {
fdopendir;
}
+ GLIBC_2.15 {
+ scandirat; scandirat64;
+ }
}
diff --git a/dirent/dirent.h b/dirent/dirent.h
index bb4ede1580..6a5a0ef81c 100644
--- a/dirent/dirent.h
+++ b/dirent/dirent.h
@@ -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,
diff --git a/dirent/opendir.c b/dirent/opendir.c
index 771013f6eb..6375b6786a 100644
--- a/dirent/opendir.c
+++ b/dirent/opendir.c
@@ -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
@@ -21,13 +21,20 @@
#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)
diff --git a/dirent/scandir.c b/dirent/scandir.c
index e90b942b1d..3f69a8db77 100644
--- a/dirent/scandir.c
+++ b/dirent/scandir.c
@@ -18,44 +18,14 @@
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);
}
diff --git a/dirent/scandir64.c b/dirent/scandir64.c
index 274822e125..21a936e4bb 100644
--- a/dirent/scandir64.c
+++ b/dirent/scandir64.c
@@ -19,14 +19,7 @@
#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
index 0000000000..e6f5ece76f
--- /dev/null
+++ b/dirent/scandirat.c
@@ -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
index 0000000000..c4afb90d3d
--- /dev/null
+++ b/dirent/scandirat64.c
@@ -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)
diff --git a/include/dirent.h b/include/dirent.h
index 0f8f1cbe88..9ed5876892 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -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)
diff --git a/sysdeps/unix/opendir.c b/sysdeps/unix/opendir.c
index c2d1ddaf88..58d31764da 100644
--- a/sysdeps/unix/opendir.c
+++ b/sysdeps/unix/opendir.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/i386/scandir64.c b/sysdeps/unix/sysv/linux/i386/scandir64.c
index 837e1b9438..dacac0a44c 100644
--- a/sysdeps/unix/sysv/linux/i386/scandir64.c
+++ b/sysdeps/unix/sysv/linux/i386/scandir64.c
@@ -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
@@ -34,15 +35,106 @@
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
index 0000000000..02b8fdee0f
--- /dev/null
+++ b/sysdeps/wordsize-64/scandirat.c
@@ -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
index 0000000000..fb938654a4
--- /dev/null
+++ b/sysdeps/wordsize-64/scandirat64.c
@@ -0,0 +1 @@
+/* Defined in scandirat.c. */