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