]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/uclibc/lib/contrib/uclibc/libc/misc/glob/glob-susv3.c
Update
[l4.git] / l4 / pkg / l4re-core / uclibc / lib / contrib / uclibc / libc / misc / glob / glob-susv3.c
1 /*
2  * Copyright (C) 2006 Rich Felker <dalias@aerifal.cx>
3  *
4  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
5  */
6
7 #include <features.h>
8
9 #ifdef __UCLIBC_HAS_LFS__
10 # define BUILD_GLOB64
11 #endif
12
13 #include <glob.h>
14 #include <fnmatch.h>
15 #include <sys/stat.h>
16 #include <dirent.h>
17 #include <limits.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <stddef.h>
22
23 #include <unistd.h>
24 #include <stdio.h>
25
26
27 struct match
28 {
29         struct match *next;
30         char name[1];
31 };
32
33 #ifdef BUILD_GLOB64
34 extern int __glob_is_literal(const char *p, int useesc) attribute_hidden;
35 extern int __glob_append(struct match **tail, const char *name, size_t len, int mark) attribute_hidden;
36 extern int __glob_ignore_err(const char *path, int err) attribute_hidden;
37 extern void __glob_freelist(struct match *head) attribute_hidden;
38 extern int __glob_sort(const void *a, const void *b) attribute_hidden;
39 extern int __glob_match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail) attribute_hidden;
40 #endif
41
42 #ifdef __UCLIBC_HAS_LFS__
43 # define stat stat64
44 # define readdir_r readdir64_r
45 # define dirent dirent64
46 # define struct_stat struct stat64
47 #else
48 # define struct_stat struct stat
49 #endif
50
51 /* keep only one copy of these */
52 #ifndef __GLOB64
53
54 # ifndef BUILD_GLOB64
55 static
56 # endif
57 int __glob_is_literal(const char *p, int useesc)
58 {
59         int bracket = 0;
60         for (; *p; p++) {
61                 switch (*p) {
62                 case '\\':
63                         if (!useesc) break;
64                 case '?':
65                 case '*':
66                         return 0;
67                 case '[':
68                         bracket = 1;
69                         break;
70                 case ']':
71                         if (bracket) return 0;
72                         break;
73                 }
74         }
75         return 1;
76 }
77
78 # ifndef BUILD_GLOB64
79 static
80 # endif
81 int __glob_append(struct match **tail, const char *name, size_t len, int mark)
82 {
83         struct match *new = malloc(sizeof(struct match) + len + 1);
84         if (!new) return -1;
85         (*tail)->next = new;
86         new->next = NULL;
87         strcpy(new->name, name);
88         if (mark) strcat(new->name, "/");
89         *tail = new;
90         return 0;
91 }
92
93 # ifndef BUILD_GLOB64
94 static
95 # endif
96 int __glob_match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail)
97 {
98         DIR *dir;
99         long long de_buf[(sizeof(struct dirent) + NAME_MAX + sizeof(long long))/sizeof(long long)];
100         struct dirent *de;
101         char pat[strlen(p)+1];
102         char *p2;
103         size_t l = strlen(d);
104         int literal;
105         int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | FNM_PERIOD;
106         int error;
107
108         if ((p2 = strchr(p, '/'))) {
109                 strcpy(pat, p);
110                 pat[p2-p] = 0;
111                 for (; *p2 == '/'; p2++);
112                 p = pat;
113         }
114         literal = __glob_is_literal(p, !(flags & GLOB_NOESCAPE));
115         if (*d == '/' && !*(d+1)) l = 0;
116
117         /* rely on opendir failing for nondirectory objects */
118         dir = opendir(*d ? d : ".");
119         error = errno;
120         if (!dir) {
121                 /* this is not an error -- we let opendir call stat for us */
122                 if (error == ENOTDIR) return 0;
123                 if (error == EACCES && !*p) {
124                         struct_stat st;
125                         if (!stat(d, &st) && S_ISDIR(st.st_mode)) {
126                                 if (__glob_append(tail, d, l, l))
127                                         return GLOB_NOSPACE;
128                                 return 0;
129                         }
130                 }
131                 if (errfunc(d, error) || (flags & GLOB_ERR))
132                         return GLOB_ABORTED;
133                 return 0;
134         }
135         if (!*p) {
136                 error = __glob_append(tail, d, l, l) ? GLOB_NOSPACE : 0;
137                 closedir(dir);
138                 return error;
139         }
140         while (!(error = readdir_r(dir, (void *)de_buf, &de)) && de) {
141                 char namebuf[l+de->d_reclen+2], *name = namebuf;
142                 if (!literal && fnmatch(p, de->d_name, fnm_flags))
143                         continue;
144                 if (literal && strcmp(p, de->d_name))
145                         continue;
146                 if (p2 && de->d_type && !S_ISDIR(de->d_type<<12) && !S_ISLNK(de->d_type<<12))
147                         continue;
148                 if (*d) {
149                         memcpy(name, d, l);
150                         name[l] = '/';
151                         strcpy(name+l+1, de->d_name);
152                 } else {
153                         name = de->d_name;
154                 }
155                 if (p2) {
156                         if ((error = __glob_match_in_dir(name, p2, flags, errfunc, tail))) {
157                                 closedir(dir);
158                                 return error;
159                         }
160                 } else {
161                         int mark = 0;
162                         if (flags & GLOB_MARK) {
163                                 if (de->d_type)
164                                         mark = S_ISDIR(de->d_type<<12);
165                                 else {
166                                         struct_stat st;
167                                         stat(name, &st);
168                                         mark = S_ISDIR(st.st_mode);
169                                 }
170                         }
171                         if (__glob_append(tail, name, l+de->d_reclen+1, mark)) {
172                                 closedir(dir);
173                                 return GLOB_NOSPACE;
174                         }
175                 }
176         }
177         closedir(dir);
178         if (error && (errfunc(d, error) || (flags & GLOB_ERR)))
179                 return GLOB_ABORTED;
180         return 0;
181 }
182
183 # ifndef BUILD_GLOB64
184 static
185 # endif
186 int __glob_ignore_err(const char * path attribute_unused,
187                         int err attribute_unused)
188 {
189         return 0;
190 }
191
192 # ifndef BUILD_GLOB64
193 static
194 # endif
195 void __glob_freelist(struct match *head)
196 {
197         struct match *match, *next;
198         for (match=head->next; match; match=next) {
199                 next = match->next;
200                 free(match);
201         }
202 }
203
204 # ifndef BUILD_GLOB64
205 static
206 # endif
207 int __glob_sort(const void *a, const void *b)
208 {
209         return strcmp(*(const char **)a, *(const char **)b);
210 }
211 #endif /* !__GLOB64 */
212
213 int glob(const char *pat, int flags, int (*errfunc)(const char *path, int err), glob_t *g)
214 {
215         const char *p=pat, *d;
216         struct match head = { .next = NULL }, *tail = &head;
217         size_t cnt, i;
218         size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0;
219         int error = 0;
220
221         if (*p == '/') {
222                 for (; *p == '/'; p++);
223                 d = "/";
224         } else {
225                 d = "";
226         }
227
228         if (!errfunc) errfunc = __glob_ignore_err;
229
230         if (!(flags & GLOB_APPEND)) {
231                 g->gl_offs = offs;
232                 g->gl_pathc = 0;
233                 g->gl_pathv = NULL;
234         }
235
236         if (*p) error = __glob_match_in_dir(d, p, flags, errfunc, &tail);
237         if (error == GLOB_NOSPACE) {
238                 __glob_freelist(&head);
239                 return error;
240         }
241
242         for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++);
243         if (!cnt) {
244                 if (flags & GLOB_NOCHECK) {
245                         tail = &head;
246                         if (__glob_append(&tail, pat, strlen(pat), 0))
247                                 return GLOB_NOSPACE;
248                         cnt++;
249                 } else
250                         return GLOB_NOMATCH;
251         }
252
253         if (flags & GLOB_APPEND) {
254                 char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *));
255                 if (!pathv) {
256                         __glob_freelist(&head);
257                         return GLOB_NOSPACE;
258                 }
259                 g->gl_pathv = pathv;
260                 offs += g->gl_pathc;
261         } else {
262                 g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *));
263                 if (!g->gl_pathv) {
264                         __glob_freelist(&head);
265                         return GLOB_NOSPACE;
266                 }
267                 for (i=0; i<offs; i++)
268                         g->gl_pathv[i] = NULL;
269         }
270         for (i=0, tail=head.next; i<cnt; tail=tail->next, i++)
271                 g->gl_pathv[offs + i] = tail->name;
272         g->gl_pathv[offs + i] = NULL;
273         g->gl_pathc += cnt;
274
275         if (!(flags & GLOB_NOSORT))
276                 qsort(g->gl_pathv+offs, cnt, sizeof(char *), __glob_sort);
277
278         return error;
279 }
280 #ifdef __GLOB64
281 libc_hidden_def(glob64)
282 #else
283 libc_hidden_def(glob)
284 #endif
285
286 void globfree(glob_t *g)
287 {
288         size_t i;
289         for (i=0; i<g->gl_pathc; i++)
290                 free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name));
291         free(g->gl_pathv);
292         g->gl_pathc = 0;
293         g->gl_pathv = NULL;
294 }
295 #ifdef __GLOB64
296 libc_hidden_def(globfree64)
297 #else
298 libc_hidden_def(globfree)
299 #endif