glob-susv3.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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. #include <features.h>
  7. #ifdef __UCLIBC_HAS_LFS__
  8. # define BUILD_GLOB64
  9. #endif
  10. #include <glob.h>
  11. #include <fnmatch.h>
  12. #include <sys/stat.h>
  13. #include <dirent.h>
  14. #include <limits.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <errno.h>
  18. #include <stddef.h>
  19. #include <unistd.h>
  20. #include <stdio.h>
  21. /* Experimentally off - libc_hidden_proto(memcpy) */
  22. /* Experimentally off - libc_hidden_proto(strcat) */
  23. /* Experimentally off - libc_hidden_proto(strchr) */
  24. /* Experimentally off - libc_hidden_proto(strcmp) */
  25. /* Experimentally off - libc_hidden_proto(strcpy) */
  26. /* Experimentally off - libc_hidden_proto(strlen) */
  27. /* libc_hidden_proto(opendir) */
  28. /* libc_hidden_proto(closedir) */
  29. /* libc_hidden_proto(qsort) */
  30. /* libc_hidden_proto(fnmatch) */
  31. struct match
  32. {
  33. struct match *next;
  34. char name[1];
  35. };
  36. #ifdef BUILD_GLOB64
  37. extern int __glob_is_literal(const char *p, int useesc) attribute_hidden;
  38. extern int __glob_append(struct match **tail, const char *name, size_t len, int mark) attribute_hidden;
  39. extern int __glob_ignore_err(const char *path, int err) attribute_hidden;
  40. extern void __glob_freelist(struct match *head) attribute_hidden;
  41. extern int __glob_sort(const void *a, const void *b) attribute_hidden;
  42. 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;
  43. #endif
  44. #ifdef __UCLIBC_HAS_LFS__
  45. # define stat stat64
  46. # define readdir_r readdir64_r
  47. # define dirent dirent64
  48. /* libc_hidden_proto(readdir64_r) */
  49. /* libc_hidden_proto(stat64) */
  50. # define struct_stat struct stat64
  51. #else
  52. /* libc_hidden_proto(readdir_r) */
  53. /* libc_hidden_proto(stat) */
  54. # define struct_stat struct stat
  55. #endif
  56. /* keep only one copy of these */
  57. #ifndef __GLOB64
  58. # ifndef BUILD_GLOB64
  59. static
  60. # endif
  61. int __glob_is_literal(const char *p, int useesc)
  62. {
  63. int bracket = 0;
  64. for (; *p; p++) {
  65. switch (*p) {
  66. case '\\':
  67. if (!useesc) break;
  68. case '?':
  69. case '*':
  70. return 0;
  71. case '[':
  72. bracket = 1;
  73. break;
  74. case ']':
  75. if (bracket) return 0;
  76. break;
  77. }
  78. }
  79. return 1;
  80. }
  81. # ifndef BUILD_GLOB64
  82. static
  83. # endif
  84. int __glob_append(struct match **tail, const char *name, size_t len, int mark)
  85. {
  86. struct match *new = malloc(sizeof(struct match) + len + 1);
  87. if (!new) return -1;
  88. (*tail)->next = new;
  89. new->next = NULL;
  90. strcpy(new->name, name);
  91. if (mark) strcat(new->name, "/");
  92. *tail = new;
  93. return 0;
  94. }
  95. # ifndef BUILD_GLOB64
  96. static
  97. # endif
  98. int __glob_match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail)
  99. {
  100. DIR *dir;
  101. long long de_buf[(sizeof(struct dirent) + NAME_MAX + sizeof(long long))/sizeof(long long)];
  102. struct dirent *de;
  103. char pat[strlen(p)+1];
  104. char *p2;
  105. size_t l = strlen(d);
  106. int literal;
  107. int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | FNM_PERIOD;
  108. int error;
  109. if ((p2 = strchr(p, '/'))) {
  110. strcpy(pat, p);
  111. pat[p2-p] = 0;
  112. for (; *p2 == '/'; p2++);
  113. p = pat;
  114. }
  115. literal = __glob_is_literal(p, !(flags & GLOB_NOESCAPE));
  116. if (*d == '/' && !*(d+1)) l = 0;
  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. # ifndef BUILD_GLOB64
  183. static
  184. # endif
  185. int __glob_ignore_err(const char *path, int err)
  186. {
  187. return 0;
  188. }
  189. # ifndef BUILD_GLOB64
  190. static
  191. # endif
  192. void __glob_freelist(struct match *head)
  193. {
  194. struct match *match, *next;
  195. for (match=head->next; match; match=next) {
  196. next = match->next;
  197. free(match);
  198. }
  199. }
  200. # ifndef BUILD_GLOB64
  201. static
  202. # endif
  203. int __glob_sort(const void *a, const void *b)
  204. {
  205. return strcmp(*(const char **)a, *(const char **)b);
  206. }
  207. #endif /* !__GLOB64 */
  208. #ifdef __GLOB64
  209. /* libc_hidden_proto(glob64) */
  210. #else
  211. /* libc_hidden_proto(glob) */
  212. #endif
  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. if (*p == '/') {
  221. for (; *p == '/'; p++);
  222. d = "/";
  223. } else {
  224. d = "";
  225. }
  226. if (!errfunc) errfunc = __glob_ignore_err;
  227. if (!(flags & GLOB_APPEND)) {
  228. g->gl_offs = offs;
  229. g->gl_pathc = 0;
  230. g->gl_pathv = NULL;
  231. }
  232. if (*p) error = __glob_match_in_dir(d, p, flags, errfunc, &tail);
  233. if (error == GLOB_NOSPACE) {
  234. __glob_freelist(&head);
  235. return error;
  236. }
  237. for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++);
  238. if (!cnt) {
  239. if (flags & GLOB_NOCHECK) {
  240. tail = &head;
  241. if (__glob_append(&tail, pat, strlen(pat), 0))
  242. return GLOB_NOSPACE;
  243. cnt++;
  244. } else
  245. return GLOB_NOMATCH;
  246. }
  247. if (flags & GLOB_APPEND) {
  248. char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *));
  249. if (!pathv) {
  250. __glob_freelist(&head);
  251. return GLOB_NOSPACE;
  252. }
  253. g->gl_pathv = pathv;
  254. offs += g->gl_pathc;
  255. } else {
  256. g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *));
  257. if (!g->gl_pathv) {
  258. __glob_freelist(&head);
  259. return GLOB_NOSPACE;
  260. }
  261. for (i=0; i<offs; i++)
  262. g->gl_pathv[i] = NULL;
  263. }
  264. for (i=0, tail=head.next; i<cnt; tail=tail->next, i++)
  265. g->gl_pathv[offs + i] = tail->name;
  266. g->gl_pathv[offs + i] = NULL;
  267. g->gl_pathc += cnt;
  268. if (!(flags & GLOB_NOSORT))
  269. qsort(g->gl_pathv+offs, cnt, sizeof(char *), __glob_sort);
  270. return error;
  271. }
  272. #ifdef __GLOB64
  273. libc_hidden_def(glob64)
  274. #else
  275. libc_hidden_def(glob)
  276. #endif
  277. #ifdef __GLOB64
  278. /* libc_hidden_proto(globfree64) */
  279. #else
  280. /* libc_hidden_proto(globfree) */
  281. #endif
  282. void globfree(glob_t *g)
  283. {
  284. size_t i;
  285. for (i=0; i<g->gl_pathc; i++)
  286. free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name));
  287. free(g->gl_pathv);
  288. g->gl_pathc = 0;
  289. g->gl_pathv = NULL;
  290. }
  291. #ifdef __GLOB64
  292. libc_hidden_def(globfree64)
  293. #else
  294. libc_hidden_def(globfree)
  295. #endif