From c55fbd1ea768f9fdef34a01377702c0d72cbc213 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Tue, 9 Aug 2011 09:57:55 -0400 Subject: Implement scandirat function --- dirent/Makefile | 5 +- dirent/Versions | 3 ++ dirent/dirent.h | 45 +++++++++++++++- dirent/opendir.c | 13 +++-- dirent/scandir.c | 122 ++----------------------------------------- dirent/scandir64.c | 9 +--- dirent/scandirat.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++ dirent/scandirat64.c | 28 ++++++++++ 8 files changed, 234 insertions(+), 134 deletions(-) create mode 100644 dirent/scandirat.c create mode 100644 dirent/scandirat64.c (limited to 'dirent') 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 -/* 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 -#include -#include -#include -#include +#include #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 #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 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 +#include +#include +#include +#include + +#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 + +#define SCANDIRAT __scandirat64 +#define READDIR __readdir64 +#define DIRENT_TYPE struct dirent64 +#define SKIP_SCANDIR_CANCEL 1 + +#include "scandirat.c" + +weak_alias (__scandirat64, scandirat64) -- cgit 1.4.1