From d2ee815ad677bba720c4f0275c1d6065f5809e7a Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 13 May 2015 12:34:11 -0700 Subject: [PATCH] Refactor scandir/scandirat to use common tail. --- ChangeLog | 18 +++++ dirent/Makefile | 3 +- dirent/scandir-tail.c | 110 +++++++++++++++++++++++++++++++ dirent/scandir.c | 19 +++--- dirent/{scandir64.c => scandir64-tail.c} | 15 ++--- dirent/scandir64.c | 8 +-- dirent/{scandir.c => scandirat.c} | 33 +++++----- dirent/scandirat64.c | 8 +-- include/dirent.h | 20 ++++++ sysdeps/unix/sysv/linux/i386/scandir64.c | 15 ++--- 10 files changed, 196 insertions(+), 53 deletions(-) create mode 100644 dirent/scandir-tail.c copy dirent/{scandir64.c => scandir64-tail.c} (75%) copy dirent/{scandir.c => scandirat.c} (64%) diff --git a/ChangeLog b/ChangeLog index 00079ec3b3..6ecfde29c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,23 @@ 2015-05-13 Roland McGrath + * dirent/scandir64-tail.c: New file. + * dirent/Makefile (routines): Add them. + * include/dirent.h (__scandir_tail, __scandir64_tail): Declare them. + * dirent/scandir.c [!SCANDIR] (SCANDIRAT): Macro removed. + [!SCANDIR] (SCANDIR_TAIL): New macro. + (SCANDIR): Call __opendir and __scandir_tail, not __scandirat. + * dirent/scandir64.c [!_DIRENT_MATCHES_DIRENT64] + (SCANDIRAT): Macro removed. + (SCANDIR_TAIL): New macro. + * dirent/scandirat.c [!SCANDIRAT] (READDIR): Macro removed. + [!SCANDIRAT] (SCANDIR_TAIL): New macro. + (SCANDIRAT): Just call __opendirat and __scandir_tail. + * dirent/scandirat64.c [!_DIRENT_MATCHES_DIRENT64] + (READDIR): Macro removed. + (SCANDIR_TAIL): New macro. + * sysdeps/unix/sysv/linux/i386/scandir64.c (READDIR): Macro removed. + (SCANDIR_TAIL): New macro. + * dirent/scandirat.c (__scandir_cancel_handler): Function moved ... * dirent/scandir-cancel.c: ... to this new file. * dirent/Makefile (routines): Add it. diff --git a/dirent/Makefile b/dirent/Makefile index 2a97649c04..551372ebba 100644 --- a/dirent/Makefile +++ b/dirent/Makefile @@ -27,7 +27,8 @@ routines := opendir closedir readdir readdir_r rewinddir \ seekdir telldir scandir alphasort versionsort \ getdents getdents64 dirfd readdir64 readdir64_r scandir64 \ alphasort64 versionsort64 fdopendir \ - scandirat scandirat64 scandir-cancel + scandirat scandirat64 \ + scandir-cancel scandir-tail scandir64-tail tests := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \ tst-fdopendir2 tst-scandir tst-scandir64 diff --git a/dirent/scandir-tail.c b/dirent/scandir-tail.c new file mode 100644 index 0000000000..4560834af5 --- /dev/null +++ b/dirent/scandir-tail.c @@ -0,0 +1,110 @@ +/* Logic guts of scandir*. + Copyright (C) 1992-2015 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 + . */ + +#include +#include +#include +#include +#include + +#ifndef SCANDIR_TAIL +# define SCANDIR_TAIL __scandir_tail +# define READDIR __readdir +# define DIRENT_TYPE struct dirent +#endif + +internal_function +int +SCANDIR_TAIL (DIR *dp, + DIRENT_TYPE ***namelist, + int (*select) (const DIRENT_TYPE *), + int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **)) +{ + if (dp == NULL) + return -1; + + int save = errno; + __set_errno (0); + + int result; + struct scandir_cancel_struct c = { .dp = dp }; + __libc_cleanup_push (&__scandir_cancel_handler, &c); + + DIRENT_TYPE **v = NULL; + size_t vsize = 0; + DIRENT_TYPE *d; + while ((d = READDIR (dp)) != NULL) + { + if (select != NULL) + { + int selected = (*select) (d); + + /* The SELECT function might have changed errno. It was + zero before and it need to be again to make the later + tests work. */ + __set_errno (0); + + if (!selected) + continue; + } + else + __set_errno (0); + + if (__glibc_unlikely (c.cnt == vsize)) + { + if (vsize == 0) + vsize = 10; + else + vsize *= 2; + DIRENT_TYPE **new = realloc (v, vsize * sizeof *v); + if (new == NULL) + break; + c.v = v = new; + } + + size_t dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d; + DIRENT_TYPE *vnew = malloc (dsize); + if (vnew == NULL) + break; + v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize); + } + + if (__glibc_likely (errno == 0)) + { + __closedir (dp); + + /* Sort the list if we have a comparison function to sort with. */ + if (cmp != NULL) + qsort (v, c.cnt, sizeof *v, (__compar_fn_t) cmp); + + *namelist = v; + result = c.cnt; + } + else + { + /* This frees everything and calls closedir. */ + __scandir_cancel_handler (&c); + result = -1; + } + + __libc_cleanup_pop (0); + + if (result >= 0) + __set_errno (save); + return result; +} diff --git a/dirent/scandir.c b/dirent/scandir.c index 99c968181c..c0c3f7a3cf 100644 --- a/dirent/scandir.c +++ b/dirent/scandir.c @@ -24,23 +24,20 @@ #undef scandir64 -#include - #ifndef SCANDIR -# define SCANDIR scandir -# define SCANDIRAT __scandirat -# define DIRENT_TYPE struct dirent +# define SCANDIR scandir +# define SCANDIR_TAIL __scandir_tail +# define DIRENT_TYPE struct dirent #endif int -SCANDIR (dir, namelist, select, cmp) - const char *dir; - DIRENT_TYPE ***namelist; - int (*select) (const DIRENT_TYPE *); - int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **); +SCANDIR (const char *dir, + DIRENT_TYPE ***namelist, + int (*select) (const DIRENT_TYPE *), + int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **)) { - return SCANDIRAT (AT_FDCWD, dir, namelist, select, cmp); + return SCANDIR_TAIL (__opendir (dir), namelist, select, cmp); } #ifdef _DIRENT_MATCHES_DIRENT64 diff --git a/dirent/scandir64.c b/dirent/scandir64-tail.c similarity index 75% copy from dirent/scandir64.c copy to dirent/scandir64-tail.c index d9f780fa33..b10dd0a5a8 100644 --- a/dirent/scandir64.c +++ b/dirent/scandir64-tail.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2000-2015 Free Software Foundation, Inc. +/* Logic guts of scandir*64. + Copyright (C) 2015 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 @@ -17,13 +18,9 @@ #include -/* scandir.c defines scandir64 as an alias if _DIRENT_MATCHES_DIRENT64. */ #ifndef _DIRENT_MATCHES_DIRENT64 - -#define SCANDIR scandir64 -#define SCANDIRAT scandirat64 -#define DIRENT_TYPE struct dirent64 - -#include - +# define SCANDIR_TAIL __scandir64_tail +# define READDIR __readdir64 +# define DIRENT_TYPE struct dirent64 +# include #endif diff --git a/dirent/scandir64.c b/dirent/scandir64.c index d9f780fa33..fbb1866348 100644 --- a/dirent/scandir64.c +++ b/dirent/scandir64.c @@ -20,10 +20,10 @@ /* scandir.c defines scandir64 as an alias if _DIRENT_MATCHES_DIRENT64. */ #ifndef _DIRENT_MATCHES_DIRENT64 -#define SCANDIR scandir64 -#define SCANDIRAT scandirat64 -#define DIRENT_TYPE struct dirent64 +# define SCANDIR scandir64 +# define SCANDIR_TAIL __scandir64_tail +# define DIRENT_TYPE struct dirent64 -#include +# include #endif diff --git a/dirent/scandir.c b/dirent/scandirat.c similarity index 64% copy from dirent/scandir.c copy to dirent/scandirat.c index 99c968181c..41725af39a 100644 --- a/dirent/scandir.c +++ b/dirent/scandirat.c @@ -18,31 +18,32 @@ /* We need to avoid the header declaration of scandir64, because the types don't match scandir and then the compiler will complain about the mismatch when we do the alias below. */ -#define scandir64 __renamed_scandir64 +#define scandirat64 __renamed_scandirat64 #include -#undef scandir64 +#undef scandirat64 -#include - -#ifndef SCANDIR -# define SCANDIR scandir -# define SCANDIRAT __scandirat -# define DIRENT_TYPE struct dirent +#ifndef SCANDIRAT +# define SCANDIRAT __scandirat +# define SCANDIR_TAIL __scandir_tail +# define DIRENT_TYPE struct dirent +# define SCANDIRAT_WEAK_ALIAS #endif - int -SCANDIR (dir, namelist, select, cmp) - const char *dir; - DIRENT_TYPE ***namelist; - int (*select) (const DIRENT_TYPE *); - int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **); +SCANDIRAT (int dfd, const char *dir, + DIRENT_TYPE ***namelist, + int (*select) (const DIRENT_TYPE *), + int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **)) { - return SCANDIRAT (AT_FDCWD, dir, namelist, select, cmp); + return SCANDIR_TAIL (__opendirat (dfd, dir), namelist, select, cmp); } +libc_hidden_def (SCANDIRAT) +#ifdef SCANDIRAT_WEAK_ALIAS +weak_alias (__scandirat, scandirat) +#endif #ifdef _DIRENT_MATCHES_DIRENT64 -weak_alias (scandir, scandir64) +weak_alias (scandirat, scandirat64) #endif diff --git a/dirent/scandirat64.c b/dirent/scandirat64.c index fcdd1a9a73..e330a7bba6 100644 --- a/dirent/scandirat64.c +++ b/dirent/scandirat64.c @@ -20,10 +20,10 @@ /* scandirat.c defines scandirat64 as an alias if _DIRENT_MATCHES_DIRENT64. */ #ifndef _DIRENT_MATCHES_DIRENT64 -#define SCANDIRAT scandirat64 -#define READDIR __readdir64 -#define DIRENT_TYPE struct dirent64 +# define SCANDIRAT scandirat64 +# define SCANDIR_TAIL __scandir64_tail +# define DIRENT_TYPE struct dirent64 -#include "scandirat.c" +# include #endif diff --git a/include/dirent.h b/include/dirent.h index c50bd23783..258f2d0791 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -49,6 +49,26 @@ extern DIR *__alloc_dir (int fd, bool close_fd, int flags, extern __typeof (rewinddir) __rewinddir; extern void __scandir_cancel_handler (void *arg) attribute_hidden; +extern int __scandir_tail (DIR *dp, + struct dirent ***namelist, + int (*select) (const struct dirent *), + int (*cmp) (const struct dirent **, + const struct dirent **)) + internal_function attribute_hidden; +# ifdef _DIRENT_MATCHES_DIRENT64 +# define __scandir64_tail (dp, namelist, select, cmp) \ + __scandir_tail (dp, (struct dirent ***) (namelist), \ + (int (*) (const struct dirent *)) (select), \ + (int (*) (const struct dirent **, \ + const struct dirent **)) (cmp)) +# else +extern int __scandir64_tail (DIR *dp, + struct dirent64 ***namelist, + int (*select) (const struct dirent64 *), + int (*cmp) (const struct dirent64 **, + const struct dirent64 **)) + internal_function attribute_hidden; +# endif libc_hidden_proto (__rewinddir) extern __typeof (scandirat) __scandirat; diff --git a/sysdeps/unix/sysv/linux/i386/scandir64.c b/sysdeps/unix/sysv/linux/i386/scandir64.c index 824bf84bd2..86290780c4 100644 --- a/sysdeps/unix/sysv/linux/i386/scandir64.c +++ b/sysdeps/unix/sysv/linux/i386/scandir64.c @@ -17,22 +17,21 @@ #include -#define SCANDIR __scandir64 -#define SCANDIRAT scandirat64 -#define READDIR __readdir64 -#define DIRENT_TYPE struct dirent64 +#define SCANDIR __scandir64 +#define SCANDIR_TAIL __scandir64_tail +#define DIRENT_TYPE struct dirent64 #include -#undef SCANDIR -#undef READDIR -#undef DIRENT_TYPE +#undef SCANDIR +#undef SCANDIR_TAIL +#undef DIRENT_TYPE #include versioned_symbol (libc, __scandir64, scandir64, GLIBC_2_2); -#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) +#if SHLIB_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) # include # include # include "olddirent.h" -- 2.11.4.GIT