PageRenderTime 23ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/util/portability/glob.cpp

https://gitlab.com/iranjith4/hhvm
C++ | 271 lines | 220 code | 23 blank | 28 comment | 71 complexity | 4e5f60d8e0caa4e120175ca47a379250 MD5 | raw file
  1. // Borrowed from Musl Libc, under the following license:
  2. /*
  3. * Copyright ? 2005-2014 Rich Felker, et al.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  19. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  20. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  21. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  22. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. */
  24. // Note that this file has had moderate changes to make it compile as C++, and
  25. // under MSVC.
  26. #include "hphp/util/portability/glob.h"
  27. #include <sys/stat.h>
  28. #include <limits.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include <errno.h>
  32. #include <stddef.h>
  33. #include <folly/CPortability.h>
  34. #include <folly/FilePortability.h>
  35. #include <folly/ScopeGuard.h>
  36. #include "hphp/util/portability/fnmatch.h"
  37. #include "hphp/util/portability.h"
  38. struct match {
  39. struct match *next;
  40. char name[1];
  41. };
  42. static int is_literal(const char *p, int useesc) {
  43. int bracket = 0;
  44. for (; *p; p++) {
  45. switch (*p) {
  46. case '\\':
  47. if (!useesc) break;
  48. case '?':
  49. case '*':
  50. return 0;
  51. case '[':
  52. bracket = 1;
  53. break;
  54. case ']':
  55. if (bracket) return 0;
  56. break;
  57. }
  58. }
  59. return 1;
  60. }
  61. static int append(struct match **tail, const char *name, size_t len, int mark) {
  62. struct match *ne = (match*)malloc(sizeof(struct match) + len + 1);
  63. if (!ne) return -1;
  64. (*tail)->next = ne;
  65. ne->next = nullptr;
  66. strcpy(ne->name, name);
  67. if (mark) strcat(ne->name, "/");
  68. *tail = ne;
  69. return 0;
  70. }
  71. // Never inline, to ensure that the alloca of the pattern buffer is always safe.
  72. NEVER_INLINE
  73. static int match_in_dir(const char *d,
  74. const char *p,
  75. int flags,
  76. int(*errfunc)(const char *path, int err),
  77. struct match **tail) {
  78. DIR *dir;
  79. struct dirent de_buf, *de;
  80. char* pat = (char*)alloca(sizeof(char) * (strlen(p) + 1));
  81. const char *p2;
  82. size_t l = strlen(d);
  83. int literal;
  84. int fnm_flags = ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
  85. | ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0);
  86. int error;
  87. if ((p2 = strchr(p, '/'))) {
  88. strcpy(pat, p);
  89. pat[p2 - p] = 0;
  90. for (; *p2 == '/'; p2++);
  91. p = pat;
  92. }
  93. literal = is_literal(p, !(flags & GLOB_NOESCAPE));
  94. if (*d == '/' && !*(d + 1)) l = 0;
  95. /* rely on opendir failing for nondirectory objects */
  96. dir = opendir(*d ? d : ".");
  97. error = errno;
  98. if (!dir) {
  99. /* this is not an error -- we let opendir call stat for us */
  100. if (error == ENOTDIR) return 0;
  101. if (error == EACCES && !*p) {
  102. struct stat st;
  103. if (!stat(d, &st) && S_ISDIR(st.st_mode)) {
  104. if (append(tail, d, l, l))
  105. return GLOB_NOSPACE;
  106. return 0;
  107. }
  108. }
  109. if (errfunc(d, error) || (flags & GLOB_ERR))
  110. return GLOB_ABORTED;
  111. return 0;
  112. }
  113. if (!*p) {
  114. error = append(tail, d, l, l) ? GLOB_NOSPACE : 0;
  115. closedir(dir);
  116. return error;
  117. }
  118. while (!(error = readdir_r(dir, &de_buf, &de)) && de) {
  119. char* namebuf = (char*)malloc(sizeof(char) * (l + strlen(de->d_name) + 2));
  120. SCOPE_EXIT {
  121. free(namebuf);
  122. };
  123. char* name = namebuf;
  124. if (!literal && fnmatch(p, de->d_name, fnm_flags))
  125. continue;
  126. if (literal && strcmp(p, de->d_name))
  127. continue;
  128. if (p2 && de->d_type && !S_ISDIR(de->d_type << 12)
  129. && !S_ISLNK(de->d_type << 12))
  130. continue;
  131. if (*d) {
  132. memcpy(name, d, l);
  133. name[l] = '/';
  134. strcpy(name + l + 1, de->d_name);
  135. } else {
  136. name = de->d_name;
  137. }
  138. if (p2) {
  139. if ((error = match_in_dir(name, p2, flags, errfunc, tail))) {
  140. closedir(dir);
  141. return error;
  142. }
  143. } else {
  144. int mark = 0;
  145. if (flags & GLOB_MARK) {
  146. if (de->d_type && !S_ISLNK(de->d_type << 12))
  147. mark = S_ISDIR(de->d_type << 12);
  148. else {
  149. struct stat st;
  150. stat(name, &st);
  151. mark = S_ISDIR(st.st_mode);
  152. }
  153. }
  154. if (append(tail, name, l + strlen(de->d_name) + 1, mark)) {
  155. closedir(dir);
  156. return GLOB_NOSPACE;
  157. }
  158. }
  159. }
  160. closedir(dir);
  161. if (error && (errfunc(d, error) || (flags & GLOB_ERR)))
  162. return GLOB_ABORTED;
  163. return 0;
  164. }
  165. static int ignore_err(const char *path, int err) {
  166. return 0;
  167. }
  168. static void freelist(struct match *head) {
  169. struct match *match, *next;
  170. for (match = head->next; match; match = next) {
  171. next = match->next;
  172. free(match);
  173. }
  174. }
  175. static int sort(const void *a, const void *b) {
  176. return strcmp(*(const char **)a, *(const char **)b);
  177. }
  178. extern "C" int glob(const char *__restrict pat,
  179. int flags,
  180. int(*errfunc)(const char *path, int err),
  181. glob_t *__restrict g) {
  182. const char *p = pat, *d;
  183. struct match head = { nullptr }, *tail = &head;
  184. size_t cnt, i;
  185. size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0;
  186. int error = 0;
  187. if (*p == '/') {
  188. for (; *p == '/'; p++);
  189. d = "/";
  190. } else {
  191. d = "";
  192. }
  193. if (strlen(p) > PATH_MAX) return GLOB_NOSPACE;
  194. if (!errfunc) errfunc = ignore_err;
  195. if (!(flags & GLOB_APPEND)) {
  196. g->gl_offs = offs;
  197. g->gl_pathc = 0;
  198. g->gl_pathv = nullptr;
  199. }
  200. if (*p) error = match_in_dir(d, p, flags, errfunc, &tail);
  201. if (error == GLOB_NOSPACE) {
  202. freelist(&head);
  203. return error;
  204. }
  205. for (cnt = 0, tail = head.next; tail; tail = tail->next, cnt++);
  206. if (!cnt) {
  207. if (flags & GLOB_NOCHECK) {
  208. tail = &head;
  209. if (append(&tail, pat, strlen(pat), 0))
  210. return GLOB_NOSPACE;
  211. cnt++;
  212. } else
  213. return GLOB_NOMATCH;
  214. }
  215. if (flags & GLOB_APPEND) {
  216. char **pathv = (char**)realloc(g->gl_pathv,
  217. (offs + g->gl_pathc + cnt + 1) * sizeof(char*));
  218. if (!pathv) {
  219. freelist(&head);
  220. return GLOB_NOSPACE;
  221. }
  222. g->gl_pathv = pathv;
  223. offs += g->gl_pathc;
  224. } else {
  225. g->gl_pathv = (char**)malloc((offs + cnt + 1) * sizeof(char *));
  226. if (!g->gl_pathv) {
  227. freelist(&head);
  228. return GLOB_NOSPACE;
  229. }
  230. for (i = 0; i<offs; i++)
  231. g->gl_pathv[i] = nullptr;
  232. }
  233. for (i = 0, tail = head.next; i<cnt; tail = tail->next, i++)
  234. g->gl_pathv[offs + i] = tail->name;
  235. g->gl_pathv[offs + i] = nullptr;
  236. g->gl_pathc += cnt;
  237. if (!(flags & GLOB_NOSORT))
  238. qsort(g->gl_pathv + offs, cnt, sizeof(char *), sort);
  239. return error;
  240. }
  241. extern "C" void globfree(glob_t *g) {
  242. size_t i;
  243. for (i = 0; i<g->gl_pathc; i++)
  244. free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name));
  245. free(g->gl_pathv);
  246. g->gl_pathc = 0;
  247. g->gl_pathv = nullptr;
  248. }