diff options
author | Roland McGrath <roland@hack.frob.com> | 2015-05-13 12:34:11 -0700 |
---|---|---|
committer | Roland McGrath <roland@hack.frob.com> | 2015-05-13 12:34:11 -0700 |
commit | d2ee815ad677bba720c4f0275c1d6065f5809e7a (patch) | |
tree | bdf787aecee9e951a71ce1d852e26b4412743803 /dirent | |
parent | Break __scandir_cancel_handler out into its own file. (diff) | |
download | glibc-d2ee815ad677bba720c4f0275c1d6065f5809e7a.tar.gz glibc-d2ee815ad677bba720c4f0275c1d6065f5809e7a.tar.bz2 glibc-d2ee815ad677bba720c4f0275c1d6065f5809e7a.zip |
Refactor scandir/scandirat to use common tail.
Diffstat (limited to 'dirent')
-rw-r--r-- | dirent/Makefile | 3 | ||||
-rw-r--r-- | dirent/scandir-tail.c | 110 | ||||
-rw-r--r-- | dirent/scandir.c | 19 | ||||
-rw-r--r-- | dirent/scandir64-tail.c | 26 | ||||
-rw-r--r-- | dirent/scandir64.c | 8 | ||||
-rw-r--r-- | dirent/scandirat.c | 110 | ||||
-rw-r--r-- | dirent/scandirat64.c | 8 |
7 files changed, 162 insertions, 122 deletions
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 + <http://www.gnu.org/licenses/>. */ + +#include <dirent.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <bits/libc-lock.h> + +#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 <fcntl.h> - #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-tail.c b/dirent/scandir64-tail.c new file mode 100644 index 0000000000..b10dd0a5a8 --- /dev/null +++ b/dirent/scandir64-tail.c @@ -0,0 +1,26 @@ +/* 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 + 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 + <http://www.gnu.org/licenses/>. */ + +#include <dirent.h> + +#ifndef _DIRENT_MATCHES_DIRENT64 +# define SCANDIR_TAIL __scandir64_tail +# define READDIR __readdir64 +# define DIRENT_TYPE struct dirent64 +# include <scandir-tail.c> +#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 <dirent/scandir.c> +# include <dirent/scandir.c> #endif diff --git a/dirent/scandirat.c b/dirent/scandirat.c index d7ae5e52c8..41725af39a 100644 --- a/dirent/scandirat.c +++ b/dirent/scandirat.c @@ -24,114 +24,20 @@ #undef scandirat64 -#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 +# define SCANDIRAT __scandirat +# define SCANDIR_TAIL __scandir_tail +# define DIRENT_TYPE struct dirent # define SCANDIRAT_WEAK_ALIAS #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 **); +SCANDIRAT (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 (__glibc_unlikely (c.cnt == vsize)) - { - 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 SCANDIR_TAIL (__opendirat (dfd, dir), namelist, select, cmp); } libc_hidden_def (SCANDIRAT) #ifdef SCANDIRAT_WEAK_ALIAS 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 <scandirat.c> #endif |