diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/i386/scandir64.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/scandir64.c | 102 |
1 files changed, 97 insertions, 5 deletions
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 |