]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libc/misc/dirent/scandir.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libc / misc / dirent / scandir.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Copyright (C) 2000-2011 Erik Andersen <andersen@uclibc.org>
4  *
5  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6  */
7
8 #include <dirent.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include "dirstream.h"
13
14 #ifndef __SCANDIR
15 # define __SCANDIR scandir
16 # define __DIRENT_TYPE struct dirent
17 # define __READDIR readdir
18 #endif
19
20 int __SCANDIR(const char *dir, __DIRENT_TYPE ***namelist,
21         int (*selector) (const __DIRENT_TYPE *),
22         int (*compar) (const __DIRENT_TYPE **, const __DIRENT_TYPE **))
23 {
24     DIR *dp = opendir (dir);
25     __DIRENT_TYPE *current;
26     __DIRENT_TYPE **names = NULL;
27     size_t names_size = 0, pos;
28     int save;
29
30     if (dp == NULL)
31         return -1;
32
33     save = errno;
34     __set_errno (0);
35
36     pos = 0;
37     while ((current = __READDIR (dp)) != NULL) {
38         int use_it = selector == NULL;
39
40         if (! use_it)
41         {
42             use_it = (*selector) (current);
43             /* The selector function might have changed errno.
44              * It was zero before and it need to be again to make
45              * the latter tests work.  */
46             if (! use_it)
47                 __set_errno (0);
48         }
49         if (use_it)
50         {
51             __DIRENT_TYPE *vnew;
52             size_t dsize;
53
54             /* Ignore errors from selector or readdir */
55             __set_errno (0);
56
57             if (unlikely(pos == names_size))
58             {
59                 __DIRENT_TYPE **new;
60                 if (names_size == 0)
61                     names_size = 10;
62                 else
63                     names_size *= 2;
64                 new = (__DIRENT_TYPE **) realloc (names,
65                                         names_size * sizeof (__DIRENT_TYPE *));
66                 if (new == NULL)
67                     break;
68                 names = new;
69             }
70
71             dsize = &current->d_name[_D_ALLOC_NAMLEN(current)] - (char*)current;
72             vnew = (__DIRENT_TYPE *) malloc (dsize);
73             if (vnew == NULL)
74                 break;
75
76             names[pos++] = (__DIRENT_TYPE *) memcpy (vnew, current, dsize);
77         }
78     }
79
80     if (unlikely(errno != 0))
81     {
82         save = errno;
83         closedir (dp);
84         while (pos > 0)
85             free (names[--pos]);
86         free (names);
87         __set_errno (save);
88         return -1;
89     }
90
91     closedir (dp);
92     __set_errno (save);
93
94     /* Sort the list if we have a comparison function to sort with.  */
95     if (compar != NULL)
96         qsort (names, pos, sizeof (__DIRENT_TYPE *), (comparison_fn_t) compar);
97     *namelist = names;
98     return pos;
99 }
100 #if defined __UCLIBC_HAS_LFS__ && __WORDSIZE == 64
101 strong_alias_untyped(scandir,scandir64)
102 #endif