fts.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. /*-
  2. * Copyright (c) 1990, 1993, 1994
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 4. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__)
  30. #if defined(LIBC_SCCS) && !defined(lint)
  31. static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
  32. #endif /* LIBC_SCCS and not lint */
  33. /* Hybrid of uClinux-dist/glibc/io/fts.c and MirBSD src/lib/libc/gen/fts.c */
  34. #include <sys/param.h>
  35. #include <sys/stat.h>
  36. #include <sys/statfs.h>
  37. #include <fcntl.h>
  38. #include <dirent.h>
  39. #include <errno.h>
  40. #ifdef __OpenBSD__
  41. #include <fts.h>
  42. #else
  43. #include "fts_gnu.h"
  44. #endif
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <unistd.h>
  48. #include "defs.h"
  49. #define internal_function
  50. /* Largest alignment size needed, minus one.
  51. Usually long double is the worst case. */
  52. #ifndef ALIGNBYTES
  53. #define ALIGNBYTES (__alignof__ (long double) - 1)
  54. #endif
  55. /* Align P to that size. */
  56. #ifndef ALIGN
  57. #define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
  58. #endif
  59. static FTSENT *fts_alloc (FTS *, const char *, int) internal_function;
  60. static FTSENT *fts_build (FTS *, int) internal_function;
  61. static void fts_lfree (FTSENT *) internal_function;
  62. static void fts_load (FTS *, FTSENT *) internal_function;
  63. static size_t fts_maxarglen (char * const *) internal_function;
  64. static void fts_padjust (FTS *, FTSENT *) internal_function;
  65. static int fts_palloc (FTS *, size_t) internal_function;
  66. static FTSENT *fts_sort (FTS *, FTSENT *, int) internal_function;
  67. static u_short fts_stat (FTS *, FTSENT *, int) internal_function;
  68. static int fts_safe_changedir(FTS *, FTSENT *, int, char *);
  69. #ifndef MAX
  70. #define MAX(a, b) ({ __typeof__ (a) _a = (a); \
  71. __typeof__ (b) _b = (b); \
  72. _a > _b ? _a : _b; })
  73. #endif
  74. #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
  75. #define CLR(opt) (sp->fts_options &= ~(opt))
  76. #define ISSET(opt) (sp->fts_options & (opt))
  77. #define SET(opt) (sp->fts_options |= (opt))
  78. #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
  79. /* fts_build flags */
  80. #define BCHILD 1 /* fts_children */
  81. #define BNAMES 2 /* fts_children, names only */
  82. #define BREAD 3 /* fts_read */
  83. FTS *
  84. fts_open(argv, options, compar)
  85. char * const *argv;
  86. register int options;
  87. int (*compar) (const FTSENT **, const FTSENT **);
  88. {
  89. register FTS *sp;
  90. register FTSENT *p, *root;
  91. register int nitems;
  92. FTSENT *parent, *tmp;
  93. int len;
  94. /* Options check. */
  95. if (options & ~FTS_OPTIONMASK) {
  96. errno = EINVAL;
  97. return (NULL);
  98. }
  99. /* Allocate/initialize the stream */
  100. if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
  101. return (NULL);
  102. memset(sp, 0, sizeof(FTS));
  103. sp->fts_compar = (int (*) (const void *, const void *)) compar;
  104. sp->fts_options = options;
  105. /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
  106. if (ISSET(FTS_LOGICAL))
  107. SET(FTS_NOCHDIR);
  108. /*
  109. * Start out with 1K of path space, and enough, in any case,
  110. * to hold the user's paths.
  111. */
  112. #ifndef MAXPATHLEN
  113. #define MAXPATHLEN 1024
  114. #endif
  115. if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
  116. goto mem1;
  117. /* Allocate/initialize root's parent. */
  118. if ((parent = fts_alloc(sp, "", 0)) == NULL)
  119. goto mem2;
  120. parent->fts_level = FTS_ROOTPARENTLEVEL;
  121. /* Allocate/initialize root(s). */
  122. for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
  123. /* Don't allow zero-length paths. */
  124. if ((len = strlen(*argv)) == 0) {
  125. errno = ENOENT;
  126. goto mem3;
  127. }
  128. p = fts_alloc(sp, *argv, len);
  129. p->fts_level = FTS_ROOTLEVEL;
  130. p->fts_parent = parent;
  131. p->fts_accpath = p->fts_name;
  132. p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
  133. /* Command-line "." and ".." are real directories. */
  134. if (p->fts_info == FTS_DOT)
  135. p->fts_info = FTS_D;
  136. /*
  137. * If comparison routine supplied, traverse in sorted
  138. * order; otherwise traverse in the order specified.
  139. */
  140. if (compar) {
  141. p->fts_link = root;
  142. root = p;
  143. } else {
  144. p->fts_link = NULL;
  145. if (root == NULL)
  146. tmp = root = p;
  147. else {
  148. tmp->fts_link = p;
  149. tmp = p;
  150. }
  151. }
  152. }
  153. if (compar && nitems > 1)
  154. root = fts_sort(sp, root, nitems);
  155. /*
  156. * Allocate a dummy pointer and make fts_read think that we've just
  157. * finished the node before the root(s); set p->fts_info to FTS_INIT
  158. * so that everything about the "current" node is ignored.
  159. */
  160. if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
  161. goto mem3;
  162. sp->fts_cur->fts_link = root;
  163. sp->fts_cur->fts_info = FTS_INIT;
  164. /*
  165. * If using chdir(2), grab a file descriptor pointing to dot to ensure
  166. * that we can get back here; this could be avoided for some paths,
  167. * but almost certainly not worth the effort. Slashes, symbolic links,
  168. * and ".." are all fairly nasty problems. Note, if we can't get the
  169. * descriptor we run anyway, just more slowly.
  170. */
  171. if (!ISSET(FTS_NOCHDIR)
  172. && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
  173. SET(FTS_NOCHDIR);
  174. return (sp);
  175. mem3: fts_lfree(root);
  176. free(parent);
  177. mem2: free(sp->fts_path);
  178. mem1: free(sp);
  179. return (NULL);
  180. }
  181. static void
  182. internal_function
  183. fts_load(sp, p)
  184. FTS *sp;
  185. register FTSENT *p;
  186. {
  187. register int len;
  188. register char *cp;
  189. /*
  190. * Load the stream structure for the next traversal. Since we don't
  191. * actually enter the directory until after the preorder visit, set
  192. * the fts_accpath field specially so the chdir gets done to the right
  193. * place and the user can access the first node. From fts_open it's
  194. * known that the path will fit.
  195. */
  196. len = p->fts_pathlen = p->fts_namelen;
  197. memmove(sp->fts_path, p->fts_name, len + 1);
  198. if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
  199. len = strlen(++cp);
  200. memmove(p->fts_name, cp, len + 1);
  201. p->fts_namelen = len;
  202. }
  203. p->fts_accpath = p->fts_path = sp->fts_path;
  204. sp->fts_dev = p->fts_dev;
  205. }
  206. int
  207. fts_close(sp)
  208. FTS *sp;
  209. {
  210. register FTSENT *freep, *p;
  211. int saved_errno;
  212. /*
  213. * This still works if we haven't read anything -- the dummy structure
  214. * points to the root list, so we step through to the end of the root
  215. * list which has a valid parent pointer.
  216. */
  217. if (sp->fts_cur) {
  218. for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
  219. freep = p;
  220. p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
  221. free(freep);
  222. }
  223. free(p);
  224. }
  225. /* Free up child linked list, sort array, path buffer. */
  226. if (sp->fts_child)
  227. fts_lfree(sp->fts_child);
  228. if (sp->fts_array)
  229. free(sp->fts_array);
  230. free(sp->fts_path);
  231. /* Return to original directory, save errno if necessary. */
  232. if (!ISSET(FTS_NOCHDIR)) {
  233. saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
  234. (void)close(sp->fts_rfd);
  235. /* Set errno and return. */
  236. if (saved_errno != 0) {
  237. /* Free up the stream pointer. */
  238. free(sp);
  239. errno = saved_errno;
  240. return (-1);
  241. }
  242. }
  243. /* Free up the stream pointer. */
  244. free(sp);
  245. return (0);
  246. }
  247. /*
  248. * Special case of "/" at the end of the path so that slashes aren't
  249. * appended which would cause paths to be written as "....//foo".
  250. */
  251. #define NAPPEND(p) \
  252. (p->fts_path[p->fts_pathlen - 1] == '/' \
  253. ? p->fts_pathlen - 1 : p->fts_pathlen)
  254. FTSENT *
  255. fts_read(sp)
  256. register FTS *sp;
  257. {
  258. register FTSENT *p, *tmp;
  259. register int instr;
  260. register char *t;
  261. int saved_errno;
  262. /* If finished or unrecoverable error, return NULL. */
  263. if (sp->fts_cur == NULL || ISSET(FTS_STOP))
  264. return (NULL);
  265. /* Set current node pointer. */
  266. p = sp->fts_cur;
  267. /* Save and zero out user instructions. */
  268. instr = p->fts_instr;
  269. p->fts_instr = FTS_NOINSTR;
  270. /* Any type of file may be re-visited; re-stat and re-turn. */
  271. if (instr == FTS_AGAIN) {
  272. p->fts_info = fts_stat(sp, p, 0);
  273. return (p);
  274. }
  275. /*
  276. * Following a symlink -- SLNONE test allows application to see
  277. * SLNONE and recover. If indirecting through a symlink, have
  278. * keep a pointer to current location. If unable to get that
  279. * pointer, follow fails.
  280. */
  281. if (instr == FTS_FOLLOW &&
  282. (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
  283. p->fts_info = fts_stat(sp, p, 1);
  284. if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
  285. if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
  286. p->fts_errno = errno;
  287. p->fts_info = FTS_ERR;
  288. } else
  289. p->fts_flags |= FTS_SYMFOLLOW;
  290. }
  291. return (p);
  292. }
  293. /* Directory in pre-order. */
  294. if (p->fts_info == FTS_D) {
  295. /* If skipped or crossed mount point, do post-order visit. */
  296. if (instr == FTS_SKIP ||
  297. (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
  298. if (p->fts_flags & FTS_SYMFOLLOW)
  299. (void)close(p->fts_symfd);
  300. if (sp->fts_child) {
  301. fts_lfree(sp->fts_child);
  302. sp->fts_child = NULL;
  303. }
  304. p->fts_info = FTS_DP;
  305. return (p);
  306. }
  307. /* Rebuild if only read the names and now traversing. */
  308. if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
  309. CLR(FTS_NAMEONLY);
  310. fts_lfree(sp->fts_child);
  311. sp->fts_child = NULL;
  312. }
  313. /*
  314. * Cd to the subdirectory.
  315. *
  316. * If have already read and now fail to chdir, whack the list
  317. * to make the names come out right, and set the parent errno
  318. * so the application will eventually get an error condition.
  319. * Set the FTS_DONTCHDIR flag so that when we logically change
  320. * directories back to the parent we don't do a chdir.
  321. *
  322. * If haven't read do so. If the read fails, fts_build sets
  323. * FTS_STOP or the fts_info field of the node.
  324. */
  325. if (sp->fts_child != NULL) {
  326. if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
  327. p->fts_errno = errno;
  328. p->fts_flags |= FTS_DONTCHDIR;
  329. for (p = sp->fts_child; p != NULL;
  330. p = p->fts_link)
  331. p->fts_accpath =
  332. p->fts_parent->fts_accpath;
  333. }
  334. } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
  335. if (ISSET(FTS_STOP))
  336. return (NULL);
  337. return (p);
  338. }
  339. p = sp->fts_child;
  340. sp->fts_child = NULL;
  341. goto name;
  342. }
  343. /* Move to the next node on this level. */
  344. next: tmp = p;
  345. if ((p = p->fts_link) != NULL) {
  346. free(tmp);
  347. /*
  348. * If reached the top, return to the original directory (or
  349. * the root of the tree), and load the paths for the next root.
  350. */
  351. if (p->fts_level == FTS_ROOTLEVEL) {
  352. if (FCHDIR(sp, sp->fts_rfd)) {
  353. SET(FTS_STOP);
  354. return (NULL);
  355. }
  356. fts_load(sp, p);
  357. return (sp->fts_cur = p);
  358. }
  359. /*
  360. * User may have called fts_set on the node. If skipped,
  361. * ignore. If followed, get a file descriptor so we can
  362. * get back if necessary.
  363. */
  364. if (p->fts_instr == FTS_SKIP)
  365. goto next;
  366. if (p->fts_instr == FTS_FOLLOW) {
  367. p->fts_info = fts_stat(sp, p, 1);
  368. if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
  369. if ((p->fts_symfd =
  370. open(".", O_RDONLY, 0)) < 0) {
  371. p->fts_errno = errno;
  372. p->fts_info = FTS_ERR;
  373. } else
  374. p->fts_flags |= FTS_SYMFOLLOW;
  375. }
  376. p->fts_instr = FTS_NOINSTR;
  377. }
  378. name: t = sp->fts_path + NAPPEND(p->fts_parent);
  379. *t++ = '/';
  380. memmove(t, p->fts_name, p->fts_namelen + 1);
  381. return (sp->fts_cur = p);
  382. }
  383. /* Move up to the parent node. */
  384. p = tmp->fts_parent;
  385. free(tmp);
  386. if (p->fts_level == FTS_ROOTPARENTLEVEL) {
  387. /*
  388. * Done; free everything up and set errno to 0 so the user
  389. * can distinguish between error and EOF.
  390. */
  391. free(p);
  392. errno = 0;
  393. return (sp->fts_cur = NULL);
  394. }
  395. /* NUL terminate the pathname. */
  396. sp->fts_path[p->fts_pathlen] = '\0';
  397. /*
  398. * Return to the parent directory. If at a root node or came through
  399. * a symlink, go back through the file descriptor. Otherwise, cd up
  400. * one directory.
  401. */
  402. if (p->fts_level == FTS_ROOTLEVEL) {
  403. if (FCHDIR(sp, sp->fts_rfd)) {
  404. SET(FTS_STOP);
  405. return (NULL);
  406. }
  407. } else if (p->fts_flags & FTS_SYMFOLLOW) {
  408. if (FCHDIR(sp, p->fts_symfd)) {
  409. saved_errno = errno;
  410. (void)close(p->fts_symfd);
  411. errno = saved_errno;
  412. SET(FTS_STOP);
  413. return (NULL);
  414. }
  415. (void)close(p->fts_symfd);
  416. } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
  417. fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
  418. SET(FTS_STOP);
  419. return (NULL);
  420. }
  421. p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
  422. return (sp->fts_cur = p);
  423. }
  424. /*
  425. * Fts_set takes the stream as an argument although it's not used in this
  426. * implementation; it would be necessary if anyone wanted to add global
  427. * semantics to fts using fts_set. An error return is allowed for similar
  428. * reasons.
  429. */
  430. /* ARGSUSED */
  431. int
  432. fts_set(sp, p, instr)
  433. FTS *sp;
  434. FTSENT *p;
  435. int instr;
  436. {
  437. if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
  438. instr != FTS_NOINSTR && instr != FTS_SKIP) {
  439. errno = EINVAL;
  440. return (1);
  441. }
  442. p->fts_instr = instr;
  443. return (0);
  444. }
  445. FTSENT *
  446. fts_children(sp, instr)
  447. register FTS *sp;
  448. int instr;
  449. {
  450. register FTSENT *p;
  451. int fd;
  452. if (instr != 0 && instr != FTS_NAMEONLY) {
  453. errno = EINVAL;
  454. return (NULL);
  455. }
  456. /* Set current node pointer. */
  457. p = sp->fts_cur;
  458. /*
  459. * Errno set to 0 so user can distinguish empty directory from
  460. * an error.
  461. */
  462. errno = 0;
  463. /* Fatal errors stop here. */
  464. if (ISSET(FTS_STOP))
  465. return (NULL);
  466. /* Return logical hierarchy of user's arguments. */
  467. if (p->fts_info == FTS_INIT)
  468. return (p->fts_link);
  469. /*
  470. * If not a directory being visited in pre-order, stop here. Could
  471. * allow FTS_DNR, assuming the user has fixed the problem, but the
  472. * same effect is available with FTS_AGAIN.
  473. */
  474. if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
  475. return (NULL);
  476. /* Free up any previous child list. */
  477. if (sp->fts_child != NULL)
  478. fts_lfree(sp->fts_child);
  479. if (instr == FTS_NAMEONLY) {
  480. SET(FTS_NAMEONLY);
  481. instr = BNAMES;
  482. } else
  483. instr = BCHILD;
  484. /*
  485. * If using chdir on a relative path and called BEFORE fts_read does
  486. * its chdir to the root of a traversal, we can lose -- we need to
  487. * chdir into the subdirectory, and we don't know where the current
  488. * directory is, so we can't get back so that the upcoming chdir by
  489. * fts_read will work.
  490. */
  491. if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
  492. ISSET(FTS_NOCHDIR))
  493. return (sp->fts_child = fts_build(sp, instr));
  494. if ((fd = open(".", O_RDONLY, 0)) < 0)
  495. return (NULL);
  496. sp->fts_child = fts_build(sp, instr);
  497. if (fchdir(fd))
  498. return (NULL);
  499. (void)close(fd);
  500. return (sp->fts_child);
  501. }
  502. /*
  503. * This is the tricky part -- do not casually change *anything* in here. The
  504. * idea is to build the linked list of entries that are used by fts_children
  505. * and fts_read. There are lots of special cases.
  506. *
  507. * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
  508. * set and it's a physical walk (so that symbolic links can't be directories),
  509. * we can do things quickly. First, if it's a 4.4BSD file system, the type
  510. * of the file is in the directory entry. Otherwise, we assume that the number
  511. * of subdirectories in a node is equal to the number of links to the parent.
  512. * The former skips all stat calls. The latter skips stat calls in any leaf
  513. * directories and for any files after the subdirectories in the directory have
  514. * been found, cutting the stat calls by about 2/3.
  515. */
  516. static FTSENT *
  517. internal_function
  518. fts_build(sp, type)
  519. register FTS *sp;
  520. int type;
  521. {
  522. register struct dirent *dp;
  523. register FTSENT *p, *head;
  524. register int nitems;
  525. FTSENT *cur, *tail;
  526. DIR *dirp;
  527. void *oldaddr;
  528. int cderrno, descend, len, level, maxlen, nlinks, saved_errno,
  529. nostat, doadjust;
  530. char *cp;
  531. /* Set current node pointer. */
  532. cur = sp->fts_cur;
  533. /*
  534. * Open the directory for reading. If this fails, we're done.
  535. * If being called from fts_read, set the fts_info field.
  536. */
  537. if ((dirp = opendir(cur->fts_accpath)) == NULL) {
  538. if (type == BREAD) {
  539. cur->fts_info = FTS_DNR;
  540. cur->fts_errno = errno;
  541. }
  542. return (NULL);
  543. }
  544. /*
  545. * Nlinks is the number of possible entries of type directory in the
  546. * directory if we're cheating on stat calls, 0 if we're not doing
  547. * any stat calls at all, -1 if we're doing stats on everything.
  548. */
  549. if (type == BNAMES) {
  550. nlinks = 0;
  551. /* Be quiet about nostat, GCC. */
  552. nostat = 0;
  553. } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
  554. nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
  555. nostat = 1;
  556. } else {
  557. nlinks = -1;
  558. nostat = 0;
  559. }
  560. #ifdef notdef
  561. (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
  562. (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
  563. ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
  564. #endif
  565. /*
  566. * If we're going to need to stat anything or we want to descend
  567. * and stay in the directory, chdir. If this fails we keep going,
  568. * but set a flag so we don't chdir after the post-order visit.
  569. * We won't be able to stat anything, but we can still return the
  570. * names themselves. Note, that since fts_read won't be able to
  571. * chdir into the directory, it will have to return different path
  572. * names than before, i.e. "a/b" instead of "b". Since the node
  573. * has already been visited in pre-order, have to wait until the
  574. * post-order visit to return the error. There is a special case
  575. * here, if there was nothing to stat then it's not an error to
  576. * not be able to stat. This is all fairly nasty. If a program
  577. * needed sorted entries or stat information, they had better be
  578. * checking FTS_NS on the returned nodes.
  579. */
  580. cderrno = 0;
  581. if (nlinks || type == BREAD) {
  582. if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
  583. if (nlinks && type == BREAD)
  584. cur->fts_errno = errno;
  585. cur->fts_flags |= FTS_DONTCHDIR;
  586. descend = 0;
  587. cderrno = errno;
  588. (void)closedir(dirp);
  589. dirp = NULL;
  590. } else
  591. descend = 1;
  592. } else
  593. descend = 0;
  594. /*
  595. * Figure out the max file name length that can be stored in the
  596. * current path -- the inner loop allocates more path as necessary.
  597. * We really wouldn't have to do the maxlen calculations here, we
  598. * could do them in fts_read before returning the path, but it's a
  599. * lot easier here since the length is part of the dirent structure.
  600. *
  601. * If not changing directories set a pointer so that can just append
  602. * each new name into the path.
  603. */
  604. len = NAPPEND(cur);
  605. if (ISSET(FTS_NOCHDIR)) {
  606. cp = sp->fts_path + len;
  607. *cp++ = '/';
  608. } else {
  609. /* GCC, you're too verbose. */
  610. cp = NULL;
  611. }
  612. len++;
  613. maxlen = sp->fts_pathlen - len;
  614. level = cur->fts_level + 1;
  615. /* Read the directory, attaching each entry to the `link' pointer. */
  616. doadjust = 0;
  617. for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
  618. if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
  619. continue;
  620. if ((p = fts_alloc(sp, dp->d_name, (int)strlen(dp->d_name))) == NULL)
  621. goto mem1;
  622. if (strlen(dp->d_name) >= maxlen) {/* include space for NUL */
  623. oldaddr = sp->fts_path;
  624. if (fts_palloc(sp, strlen(dp->d_name) + len + 1)) {
  625. /*
  626. * No more memory for path or structures. Save
  627. * errno, free up the current structure and the
  628. * structures already allocated.
  629. */
  630. mem1: saved_errno = errno;
  631. if (p)
  632. free(p);
  633. fts_lfree(head);
  634. (void)closedir(dirp);
  635. cur->fts_info = FTS_ERR;
  636. SET(FTS_STOP);
  637. errno = saved_errno;
  638. return (NULL);
  639. }
  640. /* Did realloc() change the pointer? */
  641. if (oldaddr != sp->fts_path) {
  642. doadjust = 1;
  643. if (ISSET(FTS_NOCHDIR))
  644. cp = sp->fts_path + len;
  645. }
  646. maxlen = sp->fts_pathlen - len;
  647. }
  648. if (len + strlen(dp->d_name) >= USHRT_MAX) {
  649. /*
  650. * In an FTSENT, fts_pathlen is a u_short so it is
  651. * possible to wraparound here. If we do, free up
  652. * the current structure and the structures already
  653. * allocated, then error out with ENAMETOOLONG.
  654. */
  655. free(p);
  656. fts_lfree(head);
  657. (void)closedir(dirp);
  658. cur->fts_info = FTS_ERR;
  659. SET(FTS_STOP);
  660. errno = ENAMETOOLONG;
  661. return (NULL);
  662. }
  663. p->fts_level = level;
  664. p->fts_parent = sp->fts_cur;
  665. p->fts_pathlen = len + strlen(dp->d_name);
  666. #if defined FTS_WHITEOUT && 0
  667. if (dp->d_type == DT_WHT)
  668. p->fts_flags |= FTS_ISW;
  669. #endif
  670. if (cderrno) {
  671. if (nlinks) {
  672. p->fts_info = FTS_NS;
  673. p->fts_errno = cderrno;
  674. } else
  675. p->fts_info = FTS_NSOK;
  676. p->fts_accpath = cur->fts_accpath;
  677. } else if (nlinks == 0
  678. #if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
  679. || (nostat &&
  680. dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
  681. #endif
  682. ) {
  683. p->fts_accpath =
  684. ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
  685. p->fts_info = FTS_NSOK;
  686. } else {
  687. /* Build a file name for fts_stat to stat. */
  688. if (ISSET(FTS_NOCHDIR)) {
  689. p->fts_accpath = p->fts_path;
  690. memmove(cp, p->fts_name, p->fts_namelen + 1);
  691. } else
  692. p->fts_accpath = p->fts_name;
  693. /* Stat it. */
  694. p->fts_info = fts_stat(sp, p, 0);
  695. /* Decrement link count if applicable. */
  696. if (nlinks > 0 && (p->fts_info == FTS_D ||
  697. p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
  698. --nlinks;
  699. }
  700. /* We walk in directory order so "ls -f" doesn't get upset. */
  701. p->fts_link = NULL;
  702. if (head == NULL)
  703. head = tail = p;
  704. else {
  705. tail->fts_link = p;
  706. tail = p;
  707. }
  708. ++nitems;
  709. }
  710. if (dirp)
  711. (void)closedir(dirp);
  712. /*
  713. * If realloc() changed the address of the path, adjust the
  714. * addresses for the rest of the tree and the dir list.
  715. */
  716. if (doadjust)
  717. fts_padjust(sp, head);
  718. /*
  719. * If not changing directories, reset the path back to original
  720. * state.
  721. */
  722. if (ISSET(FTS_NOCHDIR)) {
  723. if (len == sp->fts_pathlen || nitems == 0)
  724. --cp;
  725. *cp = '\0';
  726. }
  727. /*
  728. * If descended after called from fts_children or after called from
  729. * fts_read and nothing found, get back. At the root level we use
  730. * the saved fd; if one of fts_open()'s arguments is a relative path
  731. * to an empty directory, we wind up here with no other way back. If
  732. * can't get back, we're done.
  733. */
  734. if (descend && (type == BCHILD || !nitems) &&
  735. (cur->fts_level == FTS_ROOTLEVEL ?
  736. FCHDIR(sp, sp->fts_rfd) :
  737. fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
  738. cur->fts_info = FTS_ERR;
  739. SET(FTS_STOP);
  740. return (NULL);
  741. }
  742. /* If didn't find anything, return NULL. */
  743. if (!nitems) {
  744. if (type == BREAD)
  745. cur->fts_info = FTS_DP;
  746. return (NULL);
  747. }
  748. /* Sort the entries. */
  749. if (sp->fts_compar && nitems > 1)
  750. head = fts_sort(sp, head, nitems);
  751. return (head);
  752. }
  753. static u_short
  754. internal_function
  755. fts_stat(sp, p, follow)
  756. FTS *sp;
  757. register FTSENT *p;
  758. int follow;
  759. {
  760. register FTSENT *t;
  761. register dev_t dev;
  762. register ino_t ino;
  763. struct stat *sbp, sb;
  764. int saved_errno;
  765. /* If user needs stat info, stat buffer already allocated. */
  766. sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
  767. #if defined FTS_WHITEOUT && 0
  768. /* check for whiteout */
  769. if (p->fts_flags & FTS_ISW) {
  770. if (sbp != &sb) {
  771. memset(sbp, '\0', sizeof (*sbp));
  772. sbp->st_mode = S_IFWHT;
  773. }
  774. return (FTS_W);
  775. }
  776. #endif
  777. /*
  778. * If doing a logical walk, or application requested FTS_FOLLOW, do
  779. * a stat(2). If that fails, check for a non-existent symlink. If
  780. * fail, set the errno from the stat call.
  781. */
  782. if (ISSET(FTS_LOGICAL) || follow) {
  783. if (stat(p->fts_accpath, sbp)) {
  784. saved_errno = errno;
  785. if (!lstat(p->fts_accpath, sbp)) {
  786. errno = 0;
  787. return (FTS_SLNONE);
  788. }
  789. p->fts_errno = saved_errno;
  790. goto err;
  791. }
  792. } else if (lstat(p->fts_accpath, sbp)) {
  793. p->fts_errno = errno;
  794. err: memset(sbp, 0, sizeof(struct stat));
  795. return (FTS_NS);
  796. }
  797. if (S_ISDIR(sbp->st_mode)) {
  798. /*
  799. * Set the device/inode. Used to find cycles and check for
  800. * crossing mount points. Also remember the link count, used
  801. * in fts_build to limit the number of stat calls. It is
  802. * understood that these fields are only referenced if fts_info
  803. * is set to FTS_D.
  804. */
  805. dev = p->fts_dev = sbp->st_dev;
  806. ino = p->fts_ino = sbp->st_ino;
  807. p->fts_nlink = sbp->st_nlink;
  808. if (ISDOT(p->fts_name))
  809. return (FTS_DOT);
  810. /*
  811. * Cycle detection is done by brute force when the directory
  812. * is first encountered. If the tree gets deep enough or the
  813. * number of symbolic links to directories is high enough,
  814. * something faster might be worthwhile.
  815. */
  816. for (t = p->fts_parent;
  817. t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
  818. if (ino == t->fts_ino && dev == t->fts_dev) {
  819. p->fts_cycle = t;
  820. return (FTS_DC);
  821. }
  822. return (FTS_D);
  823. }
  824. if (S_ISLNK(sbp->st_mode))
  825. return (FTS_SL);
  826. if (S_ISREG(sbp->st_mode))
  827. return (FTS_F);
  828. return (FTS_DEFAULT);
  829. }
  830. static FTSENT *
  831. internal_function
  832. fts_sort(sp, head, nitems)
  833. FTS *sp;
  834. FTSENT *head;
  835. register int nitems;
  836. {
  837. register FTSENT **ap, *p;
  838. /*
  839. * Construct an array of pointers to the structures and call qsort(3).
  840. * Reassemble the array in the order returned by qsort. If unable to
  841. * sort for memory reasons, return the directory entries in their
  842. * current order. Allocate enough space for the current needs plus
  843. * 40 so don't realloc one entry at a time.
  844. */
  845. if (nitems > sp->fts_nitems) {
  846. sp->fts_nitems = nitems + 40;
  847. if ((sp->fts_array = realloc(sp->fts_array,
  848. (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
  849. sp->fts_nitems = 0;
  850. return (head);
  851. }
  852. }
  853. for (ap = sp->fts_array, p = head; p; p = p->fts_link)
  854. *ap++ = p;
  855. qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
  856. for (head = *(ap = sp->fts_array); --nitems; ++ap)
  857. ap[0]->fts_link = ap[1];
  858. ap[0]->fts_link = NULL;
  859. return (head);
  860. }
  861. static FTSENT *
  862. internal_function
  863. fts_alloc(sp, name, namelen)
  864. FTS *sp;
  865. const char *name;
  866. register int namelen;
  867. {
  868. register FTSENT *p;
  869. size_t len;
  870. /*
  871. * The file name is a variable length array and no stat structure is
  872. * necessary if the user has set the nostat bit. Allocate the FTSENT
  873. * structure, the file name and the stat structure in one chunk, but
  874. * be careful that the stat structure is reasonably aligned. Since the
  875. * fts_name field is declared to be of size 1, the fts_name pointer is
  876. * namelen + 2 before the first possible address of the stat structure.
  877. */
  878. len = sizeof(FTSENT) + namelen;
  879. if (!ISSET(FTS_NOSTAT))
  880. len += sizeof(struct stat) + ALIGNBYTES;
  881. if ((p = malloc(len)) == NULL)
  882. return (NULL);
  883. /* Copy the name and guarantee NUL termination. */
  884. memmove(p->fts_name, name, namelen);
  885. p->fts_name[namelen] = '\0';
  886. if (!ISSET(FTS_NOSTAT))
  887. p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
  888. p->fts_namelen = namelen;
  889. p->fts_path = sp->fts_path;
  890. p->fts_errno = 0;
  891. p->fts_flags = 0;
  892. p->fts_instr = FTS_NOINSTR;
  893. p->fts_number = 0;
  894. p->fts_pointer = NULL;
  895. return (p);
  896. }
  897. static void
  898. internal_function
  899. fts_lfree(head)
  900. register FTSENT *head;
  901. {
  902. register FTSENT *p;
  903. /* Free a linked list of structures. */
  904. while ((p = head)) {
  905. head = head->fts_link;
  906. free(p);
  907. }
  908. }
  909. /*
  910. * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
  911. * Most systems will allow creation of paths much longer than MAXPATHLEN, even
  912. * though the kernel won't resolve them. Add the size (not just what's needed)
  913. * plus 256 bytes so don't realloc the path 2 bytes at a time.
  914. */
  915. static int
  916. internal_function
  917. fts_palloc(sp, more)
  918. FTS *sp;
  919. size_t more;
  920. {
  921. sp->fts_pathlen += more + 256;
  922. /*
  923. * Check for possible wraparound. In an FTS, fts_pathlen is
  924. * a signed int but in an FTSENT it is an unsigned short.
  925. * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
  926. */
  927. if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
  928. if (sp->fts_path)
  929. free(sp->fts_path);
  930. sp->fts_path = NULL;
  931. errno = ENAMETOOLONG;
  932. return (1);
  933. }
  934. sp->fts_path = realloc(sp->fts_path, sp->fts_pathlen);
  935. return (sp->fts_path == NULL);
  936. }
  937. /*
  938. * When the path is realloc'd, have to fix all of the pointers in structures
  939. * already returned.
  940. */
  941. static void
  942. internal_function
  943. fts_padjust(sp, head)
  944. FTS *sp;
  945. FTSENT *head;
  946. {
  947. FTSENT *p;
  948. char *addr = sp->fts_path;
  949. #define ADJUST(p) do { \
  950. if ((p)->fts_accpath != (p)->fts_name) { \
  951. (p)->fts_accpath = \
  952. (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
  953. } \
  954. (p)->fts_path = addr; \
  955. } while (0)
  956. /* Adjust the current set of children. */
  957. for (p = sp->fts_child; p; p = p->fts_link)
  958. ADJUST(p);
  959. /* Adjust the rest of the tree, including the current level. */
  960. for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
  961. ADJUST(p);
  962. p = p->fts_link ? p->fts_link : p->fts_parent;
  963. }
  964. }
  965. static size_t
  966. internal_function
  967. fts_maxarglen(argv)
  968. char * const *argv;
  969. {
  970. size_t len, max;
  971. for (max = 0; *argv; ++argv)
  972. if ((len = strlen(*argv)) > max)
  973. max = len;
  974. return (max + 1);
  975. }
  976. /*
  977. * Change to dir specified by fd or p->fts_accpath without getting
  978. * tricked by someone changing the world out from underneath us.
  979. * Assumes p->fts_dev and p->fts_ino are filled in.
  980. */
  981. static int
  982. fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
  983. {
  984. int ret, oerrno, newfd;
  985. struct stat sb;
  986. newfd = fd;
  987. if (ISSET(FTS_NOCHDIR))
  988. return (0);
  989. if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
  990. return (-1);
  991. if (fstat(newfd, &sb)) {
  992. ret = -1;
  993. goto bail;
  994. }
  995. if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
  996. errno = ENOENT; /* disinformation */
  997. ret = -1;
  998. goto bail;
  999. }
  1000. ret = fchdir(newfd);
  1001. bail:
  1002. oerrno = errno;
  1003. if (fd < 0)
  1004. (void)close(newfd);
  1005. errno = oerrno;
  1006. return (ret);
  1007. }
  1008. #endif /* !OpenBSD/NetBSD/APPLE */