dir.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to
  8. * deal in the Software without restriction, including without limitation the
  9. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. * sell copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22. * IN THE SOFTWARE.
  23. */
  24. #if !defined(NO_GNU_SOURCE_THIS_TIME)
  25. #define NO_GNU_SOURCE_THIS_TIME
  26. #endif
  27. #if !defined(_DARWIN_C_SOURCE)
  28. #define _DARWIN_C_SOURCE
  29. #endif
  30. #include <libwebsockets.h>
  31. #include "private-lib-core.h"
  32. #include <string.h>
  33. #include <stdio.h>
  34. #include <sys/stat.h>
  35. #if defined(WIN32)
  36. #include <direct.h>
  37. #define read _read
  38. #define open _open
  39. #define close _close
  40. #define write _write
  41. #define mkdir(x,y) _mkdir(x)
  42. #define rmdir _rmdir
  43. #define unlink _unlink
  44. #define HAVE_STRUCT_TIMESPEC
  45. #if defined(pid_t)
  46. #undef pid_t
  47. #endif
  48. #endif /* win32 */
  49. #define COMBO_SIZEOF 512
  50. #if !defined(LWS_PLAT_FREERTOS)
  51. #if defined(WIN32)
  52. #include "../../win32port/dirent/dirent-win32.h"
  53. #else
  54. #include <dirent.h>
  55. #endif
  56. static int filter(const struct dirent *ent)
  57. {
  58. if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
  59. return 0;
  60. return 1;
  61. }
  62. #if !defined(WIN32)
  63. static char csep = '/';
  64. #else
  65. static char csep = '\\';
  66. #endif
  67. static void
  68. lws_dir_via_stat(char *combo, size_t l, const char *path, struct lws_dir_entry *lde)
  69. {
  70. struct stat s;
  71. lws_strncpy(combo + l, path, COMBO_SIZEOF - l);
  72. lde->type = LDOT_UNKNOWN;
  73. if (!stat(combo, &s)) {
  74. switch (s.st_mode & S_IFMT) {
  75. case S_IFBLK:
  76. lde->type = LDOT_BLOCK;
  77. break;
  78. case S_IFCHR:
  79. lde->type = LDOT_CHAR;
  80. break;
  81. case S_IFDIR:
  82. lde->type = LDOT_DIR;
  83. break;
  84. case S_IFIFO:
  85. lde->type = LDOT_FIFO;
  86. break;
  87. #if !defined(WIN32)
  88. case S_IFLNK:
  89. lde->type = LDOT_LINK;
  90. break;
  91. #endif
  92. case S_IFREG:
  93. lde->type = LDOT_FILE;
  94. break;
  95. default:
  96. break;
  97. }
  98. }
  99. }
  100. int
  101. lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb)
  102. {
  103. struct lws_dir_entry lde;
  104. struct dirent **namelist;
  105. int n, i, ret = 1;
  106. char combo[COMBO_SIZEOF];
  107. size_t l;
  108. l = lws_snprintf(combo, COMBO_SIZEOF - 2, "%s", dirpath);
  109. combo[l++] = csep;
  110. combo[l] = '\0';
  111. n = scandir((char *)dirpath, &namelist, filter, alphasort);
  112. if (n < 0) {
  113. lwsl_err("Scandir on '%s' failed, errno %d\n", dirpath, LWS_ERRNO);
  114. return 1;
  115. }
  116. for (i = 0; i < n; i++) {
  117. unsigned int type = namelist[i]->d_type;
  118. if (strchr(namelist[i]->d_name, '~'))
  119. goto skip;
  120. lde.name = namelist[i]->d_name;
  121. /*
  122. * some filesystems don't report this (ZFS) and tell that
  123. * files are LDOT_UNKNOWN
  124. */
  125. #if defined(__sun)
  126. lws_dir_via_stat(combo, l, namelist[i]->d_name, &lde);
  127. #else
  128. /*
  129. * XFS on Linux doesn't fill in d_type at all, always zero.
  130. */
  131. if (DT_BLK != DT_UNKNOWN && type == DT_BLK)
  132. lde.type = LDOT_BLOCK;
  133. else if (DT_CHR != DT_UNKNOWN && type == DT_CHR)
  134. lde.type = LDOT_CHAR;
  135. else if (DT_DIR != DT_UNKNOWN && type == DT_DIR)
  136. lde.type = LDOT_DIR;
  137. else if (DT_FIFO != DT_UNKNOWN && type == DT_FIFO)
  138. lde.type = LDOT_FIFO;
  139. else if (DT_LNK != DT_UNKNOWN && type == DT_LNK)
  140. lde.type = LDOT_LINK;
  141. else if (DT_REG != DT_UNKNOWN && type == DT_REG)
  142. lde.type = LDOT_FILE;
  143. else if (DT_SOCK != DT_UNKNOWN && type == DT_SOCK)
  144. lde.type = LDOTT_SOCKET;
  145. else {
  146. lde.type = LDOT_UNKNOWN;
  147. lws_dir_via_stat(combo, l, namelist[i]->d_name, &lde);
  148. }
  149. #endif
  150. if (cb(dirpath, user, &lde)) {
  151. while (++i < n)
  152. free(namelist[i]);
  153. goto bail;
  154. }
  155. skip:
  156. free(namelist[i]);
  157. }
  158. ret = 0;
  159. bail:
  160. free(namelist);
  161. return ret;
  162. }
  163. /*
  164. * Check filename against one globby filter
  165. *
  166. * We can support things like "*.rpm"
  167. */
  168. static int
  169. lws_dir_glob_check(const char *nm, const char *filt)
  170. {
  171. while (*nm) {
  172. if (*filt == '*') {
  173. if (!strcmp(nm, filt + 1))
  174. return 1;
  175. } else {
  176. if (*nm != *filt)
  177. return 0;
  178. filt++;
  179. }
  180. nm++;
  181. }
  182. return 0;
  183. }
  184. /*
  185. * We get passed a single filter string, like "*.txt" or "mydir/\*.rpm" or so.
  186. */
  187. int
  188. lws_dir_glob_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
  189. {
  190. lws_dir_glob_t *filter = (lws_dir_glob_t*)user;
  191. char path[384];
  192. if (!strcmp(lde->name, ".") || !strcmp(lde->name, ".."))
  193. return 0;
  194. if (lde->type == LDOT_DIR)
  195. return 0;
  196. if (lws_dir_glob_check(lde->name, filter->filter)) {
  197. lws_snprintf(path, sizeof(path), "%s%c%s", dirpath, csep,
  198. lde->name);
  199. filter->cb(filter->user, path);
  200. }
  201. return 0;
  202. }
  203. int
  204. lws_dir_rm_rf_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
  205. {
  206. char path[384];
  207. if (!strcmp(lde->name, ".") || !strcmp(lde->name, ".."))
  208. return 0;
  209. lws_snprintf(path, sizeof(path), "%s%c%s", dirpath, csep, lde->name);
  210. if (lde->type == LDOT_DIR) {
  211. #if !defined(WIN32) && !defined(_WIN32) && !defined(__COVERITY__)
  212. char dummy[8];
  213. /*
  214. * hm... eg, recursive dir symlinks can show up a LDOT_DIR
  215. * here. If it's a symlink, don't recurse into it.
  216. *
  217. * Notice we immediately discard dummy without looking in it.
  218. * There is no way to get into trouble from its lack of NUL
  219. * termination in dummy[]. We just wanted to know if it was
  220. * a symlink at all.
  221. *
  222. * Hide this from Coverity since it flags any use of readlink()
  223. * even if safe.
  224. */
  225. if (readlink(path, dummy, sizeof(dummy)) < 0)
  226. #endif
  227. lws_dir(path, NULL, lws_dir_rm_rf_cb);
  228. if (rmdir(path))
  229. lwsl_warn("%s: rmdir %s failed %d\n", __func__, path, errno);
  230. } else {
  231. if (unlink(path)) {
  232. #if defined(WIN32)
  233. SetFileAttributesA(path, FILE_ATTRIBUTE_NORMAL);
  234. if (unlink(path))
  235. #else
  236. if (rmdir(path))
  237. #endif
  238. lwsl_warn("%s: unlink %s failed %d (type %d)\n",
  239. __func__, path, errno, lde->type);
  240. }
  241. }
  242. return 0;
  243. }
  244. #endif
  245. #if defined(LWS_WITH_PLUGINS_API)
  246. struct lws_plugins_args {
  247. struct lws_plugin **pplugin;
  248. const char *_class;
  249. const char *filter;
  250. each_plugin_cb_t each;
  251. void *each_user;
  252. };
  253. static int
  254. lws_plugins_dir_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
  255. {
  256. struct lws_plugins_args *pa = (struct lws_plugins_args *)user;
  257. char path[256], base[64], *q = base;
  258. const char *p;
  259. if (strlen(lde->name) < 7)
  260. return 0;
  261. /*
  262. * The actual plugin names for protocol plugins look like
  263. * "libprotocol_lws_ssh_base.so" and for event libs
  264. * "libwebsockets-evlib_ev.so"... to recover the base name of
  265. * "lws_ssh_base" and "evlib_ev" we strip from the left to after the
  266. * first _ or -, and then truncate at the first .
  267. */
  268. p = lde->name;
  269. while (*p && *p != '_' && *p != '-')
  270. p++;
  271. if (!*p)
  272. return 0;
  273. p++;
  274. while (*p && *p != '.' && lws_ptr_diff(q, base) < (int)sizeof(base) - 1)
  275. *q++ = *p++;
  276. *q = '\0';
  277. /* if he's given a filter, only match if base matches it */
  278. if (pa->filter && strcmp(base, pa->filter))
  279. return 0;
  280. lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name);
  281. lwsl_notice(" %s\n", path);
  282. return !lws_plat_dlopen(pa->pplugin, path, base, pa->_class,
  283. pa->each, pa->each_user);
  284. }
  285. int
  286. lws_plugins_init(struct lws_plugin **pplugin, const char * const *d,
  287. const char *_class, const char *filter,
  288. each_plugin_cb_t each, void *each_user)
  289. {
  290. struct lws_plugins_args pa;
  291. pa.pplugin = pplugin;
  292. pa._class = _class;
  293. pa.each = each;
  294. pa.each_user = each_user;
  295. pa.filter = filter;
  296. while (d && *d) {
  297. lws_dir(*d, &pa, lws_plugins_dir_cb);
  298. d++;
  299. }
  300. return 0;
  301. }
  302. int
  303. lws_plugins_destroy(struct lws_plugin **pplugin, each_plugin_cb_t each,
  304. void *each_user)
  305. {
  306. struct lws_plugin *p = *pplugin, *p1;
  307. while (p) {
  308. if (each)
  309. each(p, each_user);
  310. lws_plat_destroy_dl(p);
  311. p1 = p->list;
  312. p->list = NULL;
  313. lws_free(p);
  314. p = p1;
  315. }
  316. *pplugin = NULL;
  317. return 0;
  318. }
  319. #endif