glob.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include <glob.h>
  2. #include <fnmatch.h>
  3. #include <sys/stat.h>
  4. #include <dirent.h>
  5. #include <limits.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. #include <errno.h>
  9. #include <stddef.h>
  10. #include "libc.h"
  11. struct match
  12. {
  13. struct match *next;
  14. char name[1];
  15. };
  16. static int is_literal(const char *p, int useesc)
  17. {
  18. int bracket = 0;
  19. for (; *p; p++) {
  20. switch (*p) {
  21. case '\\':
  22. if (!useesc) break;
  23. case '?':
  24. case '*':
  25. return 0;
  26. case '[':
  27. bracket = 1;
  28. break;
  29. case ']':
  30. if (bracket) return 0;
  31. break;
  32. }
  33. }
  34. return 1;
  35. }
  36. static int append(struct match **tail, const char *name, size_t len, int mark)
  37. {
  38. struct match *new = malloc(sizeof(struct match) + len + 1);
  39. if (!new) return -1;
  40. (*tail)->next = new;
  41. new->next = NULL;
  42. strcpy(new->name, name);
  43. if (mark) strcat(new->name, "/");
  44. *tail = new;
  45. return 0;
  46. }
  47. static int match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail)
  48. {
  49. DIR *dir;
  50. struct dirent de_buf, *de;
  51. char pat[strlen(p)+1];
  52. char *p2;
  53. size_t l = strlen(d);
  54. int literal;
  55. int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
  56. | ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0);
  57. int error;
  58. if ((p2 = strchr(p, '/'))) {
  59. strcpy(pat, p);
  60. pat[p2-p] = 0;
  61. for (; *p2 == '/'; p2++);
  62. p = pat;
  63. }
  64. literal = is_literal(p, !(flags & GLOB_NOESCAPE));
  65. if (*d == '/' && !*(d+1)) l = 0;
  66. /* rely on opendir failing for nondirectory objects */
  67. dir = opendir(*d ? d : ".");
  68. error = errno;
  69. if (!dir) {
  70. /* this is not an error -- we let opendir call stat for us */
  71. if (error == ENOTDIR) return 0;
  72. if (error == EACCES && !*p) {
  73. struct stat st;
  74. if (!stat(d, &st) && S_ISDIR(st.st_mode)) {
  75. if (append(tail, d, l, l))
  76. return GLOB_NOSPACE;
  77. return 0;
  78. }
  79. }
  80. if (errfunc(d, error) || (flags & GLOB_ERR))
  81. return GLOB_ABORTED;
  82. return 0;
  83. }
  84. if (!*p) {
  85. error = append(tail, d, l, l) ? GLOB_NOSPACE : 0;
  86. closedir(dir);
  87. return error;
  88. }
  89. while (!(error = readdir_r(dir, &de_buf, &de)) && de) {
  90. char namebuf[l+de->d_reclen+2], *name = namebuf;
  91. if (!literal && fnmatch(p, de->d_name, fnm_flags))
  92. continue;
  93. if (literal && strcmp(p, de->d_name))
  94. continue;
  95. if (p2 && de->d_type && !S_ISDIR(de->d_type<<12) && !S_ISLNK(de->d_type<<12))
  96. continue;
  97. if (*d) {
  98. memcpy(name, d, l);
  99. name[l] = '/';
  100. strcpy(name+l+1, de->d_name);
  101. } else {
  102. name = de->d_name;
  103. }
  104. if (p2) {
  105. if ((error = match_in_dir(name, p2, flags, errfunc, tail))) {
  106. closedir(dir);
  107. return error;
  108. }
  109. } else {
  110. int mark = 0;
  111. if (flags & GLOB_MARK) {
  112. if (de->d_type && !S_ISLNK(de->d_type<<12))
  113. mark = S_ISDIR(de->d_type<<12);
  114. else {
  115. struct stat st;
  116. stat(name, &st);
  117. mark = S_ISDIR(st.st_mode);
  118. }
  119. }
  120. if (append(tail, name, l+de->d_reclen+1, mark)) {
  121. closedir(dir);
  122. return GLOB_NOSPACE;
  123. }
  124. }
  125. }
  126. closedir(dir);
  127. if (error && (errfunc(d, error) || (flags & GLOB_ERR)))
  128. return GLOB_ABORTED;
  129. return 0;
  130. }
  131. static int ignore_err(const char *path, int err)
  132. {
  133. return 0;
  134. }
  135. static void freelist(struct match *head)
  136. {
  137. struct match *match, *next;
  138. for (match=head->next; match; match=next) {
  139. next = match->next;
  140. free(match);
  141. }
  142. }
  143. static int sort(const void *a, const void *b)
  144. {
  145. return strcmp(*(const char **)a, *(const char **)b);
  146. }
  147. int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g)
  148. {
  149. const char *p=pat, *d;
  150. struct match head = { .next = NULL }, *tail = &head;
  151. size_t cnt, i;
  152. size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0;
  153. int error = 0;
  154. if (*p == '/') {
  155. for (; *p == '/'; p++);
  156. d = "/";
  157. } else {
  158. d = "";
  159. }
  160. if (!errfunc) errfunc = ignore_err;
  161. if (!(flags & GLOB_APPEND)) {
  162. g->gl_offs = offs;
  163. g->gl_pathc = 0;
  164. g->gl_pathv = NULL;
  165. }
  166. if (strnlen(p, PATH_MAX+1) > PATH_MAX) return GLOB_NOSPACE;
  167. if (*p) error = match_in_dir(d, p, flags, errfunc, &tail);
  168. if (error == GLOB_NOSPACE) {
  169. freelist(&head);
  170. return error;
  171. }
  172. for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++);
  173. if (!cnt) {
  174. if (flags & GLOB_NOCHECK) {
  175. tail = &head;
  176. if (append(&tail, pat, strlen(pat), 0))
  177. return GLOB_NOSPACE;
  178. cnt++;
  179. } else
  180. return GLOB_NOMATCH;
  181. }
  182. if (flags & GLOB_APPEND) {
  183. char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *));
  184. if (!pathv) {
  185. freelist(&head);
  186. return GLOB_NOSPACE;
  187. }
  188. g->gl_pathv = pathv;
  189. offs += g->gl_pathc;
  190. } else {
  191. g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *));
  192. if (!g->gl_pathv) {
  193. freelist(&head);
  194. return GLOB_NOSPACE;
  195. }
  196. for (i=0; i<offs; i++)
  197. g->gl_pathv[i] = NULL;
  198. }
  199. for (i=0, tail=head.next; i<cnt; tail=tail->next, i++)
  200. g->gl_pathv[offs + i] = tail->name;
  201. g->gl_pathv[offs + i] = NULL;
  202. g->gl_pathc += cnt;
  203. if (!(flags & GLOB_NOSORT))
  204. qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort);
  205. return error;
  206. }
  207. void globfree(glob_t *g)
  208. {
  209. size_t i;
  210. for (i=0; i<g->gl_pathc; i++)
  211. free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name));
  212. free(g->gl_pathv);
  213. g->gl_pathc = 0;
  214. g->gl_pathv = NULL;
  215. }
  216. LFS64(glob);
  217. LFS64(globfree);