diff options
author | Ulrich Drepper <drepper@gmail.com> | 2011-08-09 09:57:55 -0400 |
---|---|---|
committer | Ulrich Drepper <drepper@gmail.com> | 2011-08-09 09:57:55 -0400 |
commit | c55fbd1ea768f9fdef34a01377702c0d72cbc213 (patch) | |
tree | 0e67d339ad240756843292384535c40cad03df95 /sysdeps | |
parent | 879165f25a1a6b13995e43c11e88b1a21b6f101e (diff) | |
download | glibc-c55fbd1ea768f9fdef34a01377702c0d72cbc213.tar glibc-c55fbd1ea768f9fdef34a01377702c0d72cbc213.tar.gz glibc-c55fbd1ea768f9fdef34a01377702c0d72cbc213.tar.bz2 glibc-c55fbd1ea768f9fdef34a01377702c0d72cbc213.zip |
Implement scandirat function
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/unix/opendir.c | 21 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/scandir64.c | 102 | ||||
-rw-r--r-- | sysdeps/wordsize-64/scandirat.c | 6 | ||||
-rw-r--r-- | sysdeps/wordsize-64/scandirat64.c | 1 |
4 files changed, 122 insertions, 8 deletions
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. */ |