blob: 34de9923cb53e83d05b3c5c323114c70e662e994 [file] [log] [blame]
Elliott Hughes03ac1582021-01-08 14:19:27 -08001/* $OpenBSD: fts.c,v 1.60 2021/01/08 16:06:30 tb Exp $ */
Colin Cross64ceac32010-01-13 21:19:52 -08002
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
Elliott Hughes03ac1582021-01-08 14:19:27 -080032#include <sys/param.h> /* ALIGN */
Colin Cross64ceac32010-01-13 21:19:52 -080033#include <sys/stat.h>
34
35#include <dirent.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <fts.h>
Elliott Hughesec67cde2014-07-01 17:20:06 -070039#include <limits.h>
Colin Cross64ceac32010-01-13 21:19:52 -080040#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
Elliott Hughes03ac1582021-01-08 14:19:27 -080044#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
45
46static FTSENT *fts_alloc(FTS *, const char *, size_t);
Colin Cross64ceac32010-01-13 21:19:52 -080047static FTSENT *fts_build(FTS *, int);
48static void fts_lfree(FTSENT *);
49static void fts_load(FTS *, FTSENT *);
50static size_t fts_maxarglen(char * const *);
51static void fts_padjust(FTS *, FTSENT *);
52static int fts_palloc(FTS *, size_t);
53static FTSENT *fts_sort(FTS *, FTSENT *, int);
Elliott Hughes28182792014-11-21 19:25:27 -080054static u_short fts_stat(FTS *, FTSENT *, int, int);
Elliott Hughes03ac1582021-01-08 14:19:27 -080055static int fts_safe_changedir(FTS *, FTSENT *, int, const char *);
Colin Cross64ceac32010-01-13 21:19:52 -080056
Elliott Hughes03ac1582021-01-08 14:19:27 -080057#define DEF_WEAK(s) /* nothing */
Calin Juravlec20de902014-03-20 15:21:32 +000058#define ALIGNBYTES (sizeof(uintptr_t) - 1)
59#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
Elliott Hughes28182792014-11-21 19:25:27 -080060void* reallocarray(void*, size_t, size_t);
Elliott Hughes03ac1582021-01-08 14:19:27 -080061void* recallocarray(void*, size_t, size_t, size_t);
Calin Juravlec20de902014-03-20 15:21:32 +000062
Colin Cross64ceac32010-01-13 21:19:52 -080063#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
64
65#define CLR(opt) (sp->fts_options &= ~(opt))
66#define ISSET(opt) (sp->fts_options & (opt))
67#define SET(opt) (sp->fts_options |= (opt))
68
69#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
70
71/* fts_build flags */
72#define BCHILD 1 /* fts_children */
73#define BNAMES 2 /* fts_children, names only */
74#define BREAD 3 /* fts_read */
75
Elliott Hughes03ac1582021-01-08 14:19:27 -080076FTS *
77__fts_open(char * const *argv, int options,
78 int (*compar)(const FTSENT **, const FTSENT **))
79{
Colin Cross64ceac32010-01-13 21:19:52 -080080 FTS *sp;
81 FTSENT *p, *root;
82 int nitems;
Elliott Hughes03ac1582021-01-08 14:19:27 -080083 FTSENT *parent, *prev;
84
85 /* Android: options check moved to __fts_open() for ftw(). */
86
87 /* At least one path must be specified. */
88 if (*argv == NULL) {
89 errno = EINVAL;
90 return (NULL);
91 }
Colin Cross64ceac32010-01-13 21:19:52 -080092
Colin Cross64ceac32010-01-13 21:19:52 -080093 /* Allocate/initialize the stream */
94 if ((sp = calloc(1, sizeof(FTS))) == NULL)
95 return (NULL);
96 sp->fts_compar = compar;
97 sp->fts_options = options;
98
99 /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
100 if (ISSET(FTS_LOGICAL))
101 SET(FTS_NOCHDIR);
102
103 /*
104 * Start out with 1K of path space, and enough, in any case,
105 * to hold the user's paths.
106 */
Elliott Hughes03ac1582021-01-08 14:19:27 -0800107 if (fts_palloc(sp, MAXIMUM(fts_maxarglen(argv), PATH_MAX)))
Colin Cross64ceac32010-01-13 21:19:52 -0800108 goto mem1;
109
110 /* Allocate/initialize root's parent. */
111 if ((parent = fts_alloc(sp, "", 0)) == NULL)
112 goto mem2;
113 parent->fts_level = FTS_ROOTPARENTLEVEL;
114
115 /* Allocate/initialize root(s). */
Elliott Hughes03ac1582021-01-08 14:19:27 -0800116 for (root = prev = NULL, nitems = 0; *argv; ++argv, ++nitems) {
117 if ((p = fts_alloc(sp, *argv, strlen(*argv))) == NULL)
Colin Cross64ceac32010-01-13 21:19:52 -0800118 goto mem3;
119 p->fts_level = FTS_ROOTLEVEL;
120 p->fts_parent = parent;
121 p->fts_accpath = p->fts_name;
Elliott Hughes28182792014-11-21 19:25:27 -0800122 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
Colin Cross64ceac32010-01-13 21:19:52 -0800123
Elliott Hughes03ac1582021-01-08 14:19:27 -0800124 // Android: for ftw/nftw we need to fail early: http://b/31152735
Elliott Hughes70a8f222018-05-07 16:44:13 -0700125 if ((options & FTS_FOR_FTW) != 0 && p->fts_info == FTS_NS) goto mem3;
126
Colin Cross64ceac32010-01-13 21:19:52 -0800127 /* Command-line "." and ".." are real directories. */
128 if (p->fts_info == FTS_DOT)
129 p->fts_info = FTS_D;
130
131 /*
132 * If comparison routine supplied, traverse in sorted
133 * order; otherwise traverse in the order specified.
134 */
135 if (compar) {
136 p->fts_link = root;
137 root = p;
138 } else {
139 p->fts_link = NULL;
140 if (root == NULL)
Elliott Hughes03ac1582021-01-08 14:19:27 -0800141 root = p;
142 else
143 prev->fts_link = p;
144 prev = p;
Colin Cross64ceac32010-01-13 21:19:52 -0800145 }
146 }
147 if (compar && nitems > 1)
148 root = fts_sort(sp, root, nitems);
149
150 /*
151 * Allocate a dummy pointer and make fts_read think that we've just
152 * finished the node before the root(s); set p->fts_info to FTS_INIT
153 * so that everything about the "current" node is ignored.
154 */
155 if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
156 goto mem3;
157 sp->fts_cur->fts_link = root;
158 sp->fts_cur->fts_info = FTS_INIT;
159
160 /*
161 * If using chdir(2), grab a file descriptor pointing to dot to ensure
162 * that we can get back here; this could be avoided for some paths,
163 * but almost certainly not worth the effort. Slashes, symbolic links,
164 * and ".." are all fairly nasty problems. Note, if we can't get the
165 * descriptor we run anyway, just more slowly.
166 */
Elliott Hughes03ac1582021-01-08 14:19:27 -0800167 if (!ISSET(FTS_NOCHDIR) &&
168 (sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC)) == -1)
Colin Cross64ceac32010-01-13 21:19:52 -0800169 SET(FTS_NOCHDIR);
170
171 if (nitems == 0)
172 free(parent);
173
174 return (sp);
175
176mem3: fts_lfree(root);
177 free(parent);
178mem2: free(sp->fts_path);
179mem1: free(sp);
180 return (NULL);
181}
Elliott Hughes03ac1582021-01-08 14:19:27 -0800182DEF_WEAK(fts_open);
Colin Cross64ceac32010-01-13 21:19:52 -0800183
184static void
185fts_load(FTS *sp, FTSENT *p)
186{
187 size_t len;
188 char *cp;
189
190 /*
191 * Load the stream structure for the next traversal. Since we don't
192 * actually enter the directory until after the preorder visit, set
193 * the fts_accpath field specially so the chdir gets done to the right
194 * place and the user can access the first node. From fts_open it's
195 * known that the path will fit.
196 */
197 len = p->fts_pathlen = p->fts_namelen;
198 memmove(sp->fts_path, p->fts_name, len + 1);
199 if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
200 len = strlen(++cp);
201 memmove(p->fts_name, cp, len + 1);
202 p->fts_namelen = len;
203 }
204 p->fts_accpath = p->fts_path = sp->fts_path;
205 sp->fts_dev = p->fts_dev;
206}
207
208int
209fts_close(FTS *sp)
210{
211 FTSENT *freep, *p;
212 int rfd, error = 0;
213
214 /*
215 * This still works if we haven't read anything -- the dummy structure
216 * points to the root list, so we step through to the end of the root
217 * list which has a valid parent pointer.
218 */
219 if (sp->fts_cur) {
220 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
221 freep = p;
222 p = p->fts_link ? p->fts_link : p->fts_parent;
223 free(freep);
224 }
225 free(p);
226 }
227
228 /* Stash the original directory fd if needed. */
229 rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd;
230
231 /* Free up child linked list, sort array, path buffer, stream ptr.*/
Elliott Hughes03ac1582021-01-08 14:19:27 -0800232 if (sp->fts_child)
233 fts_lfree(sp->fts_child);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700234 free(sp->fts_array);
Colin Cross64ceac32010-01-13 21:19:52 -0800235 free(sp->fts_path);
236 free(sp);
237
238 /* Return to original directory, checking for error. */
239 if (rfd != -1) {
240 int saved_errno;
241 error = fchdir(rfd);
242 saved_errno = errno;
243 (void)close(rfd);
244 errno = saved_errno;
245 }
246
247 return (error);
248}
Elliott Hughes03ac1582021-01-08 14:19:27 -0800249DEF_WEAK(fts_close);
Colin Cross64ceac32010-01-13 21:19:52 -0800250
251/*
252 * Special case of "/" at the end of the path so that slashes aren't
253 * appended which would cause paths to be written as "....//foo".
254 */
255#define NAPPEND(p) \
256 (p->fts_path[p->fts_pathlen - 1] == '/' \
257 ? p->fts_pathlen - 1 : p->fts_pathlen)
258
259FTSENT *
260fts_read(FTS *sp)
261{
262 FTSENT *p, *tmp;
263 int instr;
264 char *t;
265 int saved_errno;
266
267 /* If finished or unrecoverable error, return NULL. */
268 if (sp->fts_cur == NULL || ISSET(FTS_STOP))
269 return (NULL);
270
271 /* Set current node pointer. */
272 p = sp->fts_cur;
273
274 /* Save and zero out user instructions. */
275 instr = p->fts_instr;
276 p->fts_instr = FTS_NOINSTR;
277
278 /* Any type of file may be re-visited; re-stat and re-turn. */
279 if (instr == FTS_AGAIN) {
Elliott Hughes28182792014-11-21 19:25:27 -0800280 p->fts_info = fts_stat(sp, p, 0, -1);
Colin Cross64ceac32010-01-13 21:19:52 -0800281 return (p);
282 }
283
284 /*
285 * Following a symlink -- SLNONE test allows application to see
286 * SLNONE and recover. If indirecting through a symlink, have
287 * keep a pointer to current location. If unable to get that
288 * pointer, follow fails.
289 */
290 if (instr == FTS_FOLLOW &&
291 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
Elliott Hughes28182792014-11-21 19:25:27 -0800292 p->fts_info = fts_stat(sp, p, 1, -1);
Colin Cross64ceac32010-01-13 21:19:52 -0800293 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
Elliott Hughes03ac1582021-01-08 14:19:27 -0800294 if ((p->fts_symfd =
295 open(".", O_RDONLY | O_CLOEXEC)) == -1) {
Colin Cross64ceac32010-01-13 21:19:52 -0800296 p->fts_errno = errno;
297 p->fts_info = FTS_ERR;
298 } else
299 p->fts_flags |= FTS_SYMFOLLOW;
300 }
301 return (p);
302 }
303
304 /* Directory in pre-order. */
305 if (p->fts_info == FTS_D) {
306 /* If skipped or crossed mount point, do post-order visit. */
307 if (instr == FTS_SKIP ||
308 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
309 if (p->fts_flags & FTS_SYMFOLLOW)
310 (void)close(p->fts_symfd);
311 if (sp->fts_child) {
312 fts_lfree(sp->fts_child);
313 sp->fts_child = NULL;
314 }
315 p->fts_info = FTS_DP;
316 return (p);
317 }
318
319 /* Rebuild if only read the names and now traversing. */
320 if (sp->fts_child && ISSET(FTS_NAMEONLY)) {
321 CLR(FTS_NAMEONLY);
322 fts_lfree(sp->fts_child);
323 sp->fts_child = NULL;
324 }
325
326 /*
327 * Cd to the subdirectory.
328 *
329 * If have already read and now fail to chdir, whack the list
330 * to make the names come out right, and set the parent errno
331 * so the application will eventually get an error condition.
332 * Set the FTS_DONTCHDIR flag so that when we logically change
333 * directories back to the parent we don't do a chdir.
334 *
335 * If haven't read do so. If the read fails, fts_build sets
336 * FTS_STOP or the fts_info field of the node.
337 */
338 if (sp->fts_child) {
339 if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
340 p->fts_errno = errno;
341 p->fts_flags |= FTS_DONTCHDIR;
342 for (p = sp->fts_child; p; p = p->fts_link)
343 p->fts_accpath =
344 p->fts_parent->fts_accpath;
345 }
346 } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
347 if (ISSET(FTS_STOP))
348 return (NULL);
349 return (p);
350 }
351 p = sp->fts_child;
352 sp->fts_child = NULL;
353 goto name;
354 }
355
356 /* Move to the next node on this level. */
357next: tmp = p;
358 if ((p = p->fts_link)) {
359 free(tmp);
360
361 /*
362 * If reached the top, return to the original directory (or
363 * the root of the tree), and load the paths for the next root.
364 */
365 if (p->fts_level == FTS_ROOTLEVEL) {
366 if (FCHDIR(sp, sp->fts_rfd)) {
367 SET(FTS_STOP);
368 return (NULL);
369 }
370 fts_load(sp, p);
371 return (sp->fts_cur = p);
372 }
373
374 /*
375 * User may have called fts_set on the node. If skipped,
376 * ignore. If followed, get a file descriptor so we can
377 * get back if necessary.
378 */
379 if (p->fts_instr == FTS_SKIP)
380 goto next;
381 if (p->fts_instr == FTS_FOLLOW) {
Elliott Hughes28182792014-11-21 19:25:27 -0800382 p->fts_info = fts_stat(sp, p, 1, -1);
Colin Cross64ceac32010-01-13 21:19:52 -0800383 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
Elliott Hughes03ac1582021-01-08 14:19:27 -0800384 if ((p->fts_symfd =
385 open(".", O_RDONLY | O_CLOEXEC)) == -1) {
Colin Cross64ceac32010-01-13 21:19:52 -0800386 p->fts_errno = errno;
387 p->fts_info = FTS_ERR;
388 } else
389 p->fts_flags |= FTS_SYMFOLLOW;
390 }
391 p->fts_instr = FTS_NOINSTR;
392 }
393
394name: t = sp->fts_path + NAPPEND(p->fts_parent);
395 *t++ = '/';
396 memmove(t, p->fts_name, p->fts_namelen + 1);
397 return (sp->fts_cur = p);
398 }
399
400 /* Move up to the parent node. */
401 p = tmp->fts_parent;
402 free(tmp);
403
404 if (p->fts_level == FTS_ROOTPARENTLEVEL) {
405 /*
406 * Done; free everything up and set errno to 0 so the user
407 * can distinguish between error and EOF.
408 */
409 free(p);
410 errno = 0;
411 return (sp->fts_cur = NULL);
412 }
413
414 /* NUL terminate the pathname. */
415 sp->fts_path[p->fts_pathlen] = '\0';
416
417 /*
418 * Return to the parent directory. If at a root node or came through
419 * a symlink, go back through the file descriptor. Otherwise, cd up
420 * one directory.
421 */
422 if (p->fts_level == FTS_ROOTLEVEL) {
423 if (FCHDIR(sp, sp->fts_rfd)) {
424 SET(FTS_STOP);
425 sp->fts_cur = p;
426 return (NULL);
427 }
428 } else if (p->fts_flags & FTS_SYMFOLLOW) {
429 if (FCHDIR(sp, p->fts_symfd)) {
430 saved_errno = errno;
431 (void)close(p->fts_symfd);
432 errno = saved_errno;
433 SET(FTS_STOP);
434 sp->fts_cur = p;
435 return (NULL);
436 }
437 (void)close(p->fts_symfd);
438 } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
439 fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
440 SET(FTS_STOP);
441 sp->fts_cur = p;
442 return (NULL);
443 }
444 p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
445 return (sp->fts_cur = p);
446}
Elliott Hughes03ac1582021-01-08 14:19:27 -0800447DEF_WEAK(fts_read);
Colin Cross64ceac32010-01-13 21:19:52 -0800448
449/*
450 * Fts_set takes the stream as an argument although it's not used in this
451 * implementation; it would be necessary if anyone wanted to add global
452 * semantics to fts using fts_set. An error return is allowed for similar
453 * reasons.
454 */
Colin Cross64ceac32010-01-13 21:19:52 -0800455int
Elliott Hughesec67cde2014-07-01 17:20:06 -0700456fts_set(FTS *sp __unused, FTSENT *p, int instr)
Colin Cross64ceac32010-01-13 21:19:52 -0800457{
458 if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
459 instr != FTS_NOINSTR && instr != FTS_SKIP) {
460 errno = EINVAL;
461 return (1);
462 }
463 p->fts_instr = instr;
464 return (0);
465}
Elliott Hughes03ac1582021-01-08 14:19:27 -0800466DEF_WEAK(fts_set);
Colin Cross64ceac32010-01-13 21:19:52 -0800467
468FTSENT *
469fts_children(FTS *sp, int instr)
470{
471 FTSENT *p;
472 int fd;
473
474 if (instr && instr != FTS_NAMEONLY) {
475 errno = EINVAL;
476 return (NULL);
477 }
478
479 /* Set current node pointer. */
480 p = sp->fts_cur;
481
482 /*
483 * Errno set to 0 so user can distinguish empty directory from
484 * an error.
485 */
486 errno = 0;
487
488 /* Fatal errors stop here. */
489 if (ISSET(FTS_STOP))
490 return (NULL);
491
492 /* Return logical hierarchy of user's arguments. */
493 if (p->fts_info == FTS_INIT)
494 return (p->fts_link);
495
496 /*
497 * If not a directory being visited in pre-order, stop here. Could
498 * allow FTS_DNR, assuming the user has fixed the problem, but the
499 * same effect is available with FTS_AGAIN.
500 */
501 if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
502 return (NULL);
503
504 /* Free up any previous child list. */
Elliott Hughes03ac1582021-01-08 14:19:27 -0800505 if (sp->fts_child)
506 fts_lfree(sp->fts_child);
Colin Cross64ceac32010-01-13 21:19:52 -0800507
508 if (instr == FTS_NAMEONLY) {
509 SET(FTS_NAMEONLY);
510 instr = BNAMES;
511 } else
512 instr = BCHILD;
513
514 /*
515 * If using chdir on a relative path and called BEFORE fts_read does
516 * its chdir to the root of a traversal, we can lose -- we need to
517 * chdir into the subdirectory, and we don't know where the current
518 * directory is, so we can't get back so that the upcoming chdir by
519 * fts_read will work.
520 */
521 if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
522 ISSET(FTS_NOCHDIR))
523 return (sp->fts_child = fts_build(sp, instr));
524
Elliott Hughes03ac1582021-01-08 14:19:27 -0800525 if ((fd = open(".", O_RDONLY | O_CLOEXEC)) == -1)
Colin Cross64ceac32010-01-13 21:19:52 -0800526 return (NULL);
527 sp->fts_child = fts_build(sp, instr);
528 if (fchdir(fd)) {
529 (void)close(fd);
530 return (NULL);
531 }
532 (void)close(fd);
533 return (sp->fts_child);
534}
Elliott Hughes03ac1582021-01-08 14:19:27 -0800535DEF_WEAK(fts_children);
Colin Cross64ceac32010-01-13 21:19:52 -0800536
537/*
538 * This is the tricky part -- do not casually change *anything* in here. The
539 * idea is to build the linked list of entries that are used by fts_children
540 * and fts_read. There are lots of special cases.
541 *
542 * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
543 * set and it's a physical walk (so that symbolic links can't be directories),
544 * we can do things quickly. First, if it's a 4.4BSD file system, the type
545 * of the file is in the directory entry. Otherwise, we assume that the number
546 * of subdirectories in a node is equal to the number of links to the parent.
547 * The former skips all stat calls. The latter skips stat calls in any leaf
548 * directories and for any files after the subdirectories in the directory have
549 * been found, cutting the stat calls by about 2/3.
550 */
551static FTSENT *
552fts_build(FTS *sp, int type)
553{
554 struct dirent *dp;
555 FTSENT *p, *head;
556 FTSENT *cur, *tail;
557 DIR *dirp;
558 void *oldaddr;
559 size_t len, maxlen;
Elliott Hughes03ac1582021-01-08 14:19:27 -0800560 int nitems, cderrno, descend, level, nlinks, nostat, doadjust;
Colin Cross64ceac32010-01-13 21:19:52 -0800561 int saved_errno;
Elliott Hughes03ac1582021-01-08 14:19:27 -0800562 char *cp;
Colin Cross64ceac32010-01-13 21:19:52 -0800563
564 /* Set current node pointer. */
565 cur = sp->fts_cur;
566
567 /*
568 * Open the directory for reading. If this fails, we're done.
569 * If being called from fts_read, set the fts_info field.
570 */
571 if ((dirp = opendir(cur->fts_accpath)) == NULL) {
572 if (type == BREAD) {
573 cur->fts_info = FTS_DNR;
574 cur->fts_errno = errno;
575 }
576 return (NULL);
577 }
578
579 /*
580 * Nlinks is the number of possible entries of type directory in the
581 * directory if we're cheating on stat calls, 0 if we're not doing
582 * any stat calls at all, -1 if we're doing stats on everything.
583 */
584 if (type == BNAMES)
585 nlinks = 0;
586 else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
587 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
588 nostat = 1;
589 } else {
590 nlinks = -1;
591 nostat = 0;
592 }
593
594#ifdef notdef
595 (void)printf("nlinks == %d (cur: %u)\n", nlinks, cur->fts_nlink);
596 (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
597 ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
598#endif
599 /*
600 * If we're going to need to stat anything or we want to descend
601 * and stay in the directory, chdir. If this fails we keep going,
602 * but set a flag so we don't chdir after the post-order visit.
603 * We won't be able to stat anything, but we can still return the
604 * names themselves. Note, that since fts_read won't be able to
605 * chdir into the directory, it will have to return different path
606 * names than before, i.e. "a/b" instead of "b". Since the node
607 * has already been visited in pre-order, have to wait until the
608 * post-order visit to return the error. There is a special case
609 * here, if there was nothing to stat then it's not an error to
610 * not be able to stat. This is all fairly nasty. If a program
611 * needed sorted entries or stat information, they had better be
612 * checking FTS_NS on the returned nodes.
613 */
614 cderrno = 0;
615 if (nlinks || type == BREAD) {
616 if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
617 if (nlinks && type == BREAD)
618 cur->fts_errno = errno;
619 cur->fts_flags |= FTS_DONTCHDIR;
620 descend = 0;
621 cderrno = errno;
622 (void)closedir(dirp);
623 dirp = NULL;
624 } else
625 descend = 1;
626 } else
627 descend = 0;
628
629 /*
630 * Figure out the max file name length that can be stored in the
631 * current path -- the inner loop allocates more path as necessary.
632 * We really wouldn't have to do the maxlen calculations here, we
633 * could do them in fts_read before returning the path, but it's a
634 * lot easier here since the length is part of the dirent structure.
635 *
636 * If not changing directories set a pointer so that can just append
637 * each new name into the path.
638 */
639 len = NAPPEND(cur);
640 if (ISSET(FTS_NOCHDIR)) {
641 cp = sp->fts_path + len;
642 *cp++ = '/';
643 }
644 len++;
645 maxlen = sp->fts_pathlen - len;
646
647 /*
Elliott Hughesec67cde2014-07-01 17:20:06 -0700648 * fts_level is signed so we must prevent it from wrapping
Colin Cross64ceac32010-01-13 21:19:52 -0800649 * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL.
650 */
651 level = cur->fts_level;
652 if (level < FTS_MAXLEVEL)
653 level++;
654
655 /* Read the directory, attaching each entry to the `link' pointer. */
656 doadjust = 0;
657 for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
658 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
659 continue;
660
661 if (!(p = fts_alloc(sp, dp->d_name, strlen(dp->d_name))))
662 goto mem1;
663 if (strlen(dp->d_name) >= maxlen) { /* include space for NUL */
664 oldaddr = sp->fts_path;
665 if (fts_palloc(sp, strlen(dp->d_name) +len + 1)) {
666 /*
667 * No more memory for path or structures. Save
668 * errno, free up the current structure and the
669 * structures already allocated.
670 */
671mem1: saved_errno = errno;
Elliott Hughes70a8f222018-05-07 16:44:13 -0700672 free(p);
Colin Cross64ceac32010-01-13 21:19:52 -0800673 fts_lfree(head);
674 (void)closedir(dirp);
675 cur->fts_info = FTS_ERR;
676 SET(FTS_STOP);
677 errno = saved_errno;
678 return (NULL);
679 }
680 /* Did realloc() change the pointer? */
681 if (oldaddr != sp->fts_path) {
682 doadjust = 1;
683 if (ISSET(FTS_NOCHDIR))
684 cp = sp->fts_path + len;
685 }
686 maxlen = sp->fts_pathlen - len;
687 }
688
689 p->fts_level = level;
690 p->fts_parent = sp->fts_cur;
691 p->fts_pathlen = len + strlen(dp->d_name);
692 if (p->fts_pathlen < len) {
693 /*
694 * If we wrap, free up the current structure and
695 * the structures already allocated, then error
696 * out with ENAMETOOLONG.
697 */
698 free(p);
699 fts_lfree(head);
700 (void)closedir(dirp);
701 cur->fts_info = FTS_ERR;
702 SET(FTS_STOP);
703 errno = ENAMETOOLONG;
704 return (NULL);
705 }
706
707 if (cderrno) {
708 if (nlinks) {
709 p->fts_info = FTS_NS;
710 p->fts_errno = cderrno;
711 } else
712 p->fts_info = FTS_NSOK;
713 p->fts_accpath = cur->fts_accpath;
714 } else if (nlinks == 0
715#ifdef DT_DIR
716 || (nostat &&
717 dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
718#endif
719 ) {
720 p->fts_accpath =
721 ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
722 p->fts_info = FTS_NSOK;
723 } else {
724 /* Build a file name for fts_stat to stat. */
725 if (ISSET(FTS_NOCHDIR)) {
726 p->fts_accpath = p->fts_path;
Elliott Hughes03ac1582021-01-08 14:19:27 -0800727 memmove(cp, p->fts_name, p->fts_namelen + 1);
Elliott Hughes28182792014-11-21 19:25:27 -0800728 p->fts_info = fts_stat(sp, p, 0, dirfd(dirp));
729 } else {
Colin Cross64ceac32010-01-13 21:19:52 -0800730 p->fts_accpath = p->fts_name;
Elliott Hughes28182792014-11-21 19:25:27 -0800731 p->fts_info = fts_stat(sp, p, 0, -1);
732 }
Colin Cross64ceac32010-01-13 21:19:52 -0800733
734 /* Decrement link count if applicable. */
735 if (nlinks > 0 && (p->fts_info == FTS_D ||
736 p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
737 --nlinks;
738 }
739
740 /* We walk in directory order so "ls -f" doesn't get upset. */
741 p->fts_link = NULL;
742 if (head == NULL)
743 head = tail = p;
744 else {
745 tail->fts_link = p;
746 tail = p;
747 }
748 ++nitems;
749 }
750 if (dirp)
751 (void)closedir(dirp);
752
753 /*
754 * If realloc() changed the address of the path, adjust the
755 * addresses for the rest of the tree and the dir list.
756 */
757 if (doadjust)
758 fts_padjust(sp, head);
759
760 /*
761 * If not changing directories, reset the path back to original
762 * state.
763 */
764 if (ISSET(FTS_NOCHDIR)) {
765 if (len == sp->fts_pathlen || nitems == 0)
766 --cp;
767 *cp = '\0';
768 }
769
770 /*
771 * If descended after called from fts_children or after called from
772 * fts_read and nothing found, get back. At the root level we use
773 * the saved fd; if one of fts_open()'s arguments is a relative path
774 * to an empty directory, we wind up here with no other way back. If
775 * can't get back, we're done.
776 */
777 if (descend && (type == BCHILD || !nitems) &&
778 (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) :
779 fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
780 cur->fts_info = FTS_ERR;
781 SET(FTS_STOP);
782 return (NULL);
783 }
784
785 /* If didn't find anything, return NULL. */
786 if (!nitems) {
787 if (type == BREAD)
788 cur->fts_info = FTS_DP;
789 return (NULL);
790 }
791
792 /* Sort the entries. */
793 if (sp->fts_compar && nitems > 1)
794 head = fts_sort(sp, head, nitems);
795 return (head);
796}
797
798static u_short
Elliott Hughes28182792014-11-21 19:25:27 -0800799fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
Colin Cross64ceac32010-01-13 21:19:52 -0800800{
801 FTSENT *t;
802 dev_t dev;
803 ino_t ino;
804 struct stat *sbp, sb;
805 int saved_errno;
Elliott Hughes28182792014-11-21 19:25:27 -0800806 const char *path;
807
808 if (dfd == -1) {
809 path = p->fts_accpath;
810 dfd = AT_FDCWD;
811 } else
812 path = p->fts_name;
Colin Cross64ceac32010-01-13 21:19:52 -0800813
814 /* If user needs stat info, stat buffer already allocated. */
815 sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
816
817 /*
818 * If doing a logical walk, or application requested FTS_FOLLOW, do
819 * a stat(2). If that fails, check for a non-existent symlink. If
820 * fail, set the errno from the stat call.
821 */
822 if (ISSET(FTS_LOGICAL) || follow) {
Elliott Hughes03ac1582021-01-08 14:19:27 -0800823 if (fstatat(dfd, path, sbp, 0)) {
Colin Cross64ceac32010-01-13 21:19:52 -0800824 saved_errno = errno;
Elliott Hughes03ac1582021-01-08 14:19:27 -0800825 if (!fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
Colin Cross64ceac32010-01-13 21:19:52 -0800826 errno = 0;
827 return (FTS_SLNONE);
828 }
829 p->fts_errno = saved_errno;
830 goto err;
831 }
Elliott Hughes28182792014-11-21 19:25:27 -0800832 } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
Colin Cross64ceac32010-01-13 21:19:52 -0800833 p->fts_errno = errno;
834err: memset(sbp, 0, sizeof(struct stat));
835 return (FTS_NS);
836 }
837
838 if (S_ISDIR(sbp->st_mode)) {
839 /*
840 * Set the device/inode. Used to find cycles and check for
841 * crossing mount points. Also remember the link count, used
842 * in fts_build to limit the number of stat calls. It is
843 * understood that these fields are only referenced if fts_info
844 * is set to FTS_D.
845 */
846 dev = p->fts_dev = sbp->st_dev;
847 ino = p->fts_ino = sbp->st_ino;
848 p->fts_nlink = sbp->st_nlink;
849
850 if (ISDOT(p->fts_name))
851 return (FTS_DOT);
852
853 /*
854 * Cycle detection is done by brute force when the directory
855 * is first encountered. If the tree gets deep enough or the
856 * number of symbolic links to directories is high enough,
857 * something faster might be worthwhile.
858 */
859 for (t = p->fts_parent;
860 t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
861 if (ino == t->fts_ino && dev == t->fts_dev) {
862 p->fts_cycle = t;
863 return (FTS_DC);
864 }
865 return (FTS_D);
866 }
867 if (S_ISLNK(sbp->st_mode))
868 return (FTS_SL);
869 if (S_ISREG(sbp->st_mode))
870 return (FTS_F);
871 return (FTS_DEFAULT);
872}
873
874static FTSENT *
875fts_sort(FTS *sp, FTSENT *head, int nitems)
876{
877 FTSENT **ap, *p;
878
879 /*
880 * Construct an array of pointers to the structures and call qsort(3).
881 * Reassemble the array in the order returned by qsort. If unable to
882 * sort for memory reasons, return the directory entries in their
883 * current order. Allocate enough space for the current needs plus
884 * 40 so don't realloc one entry at a time.
885 */
886 if (nitems > sp->fts_nitems) {
887 struct _ftsent **a;
888
Elliott Hughes28182792014-11-21 19:25:27 -0800889 if ((a = reallocarray(sp->fts_array,
Elliott Hughes03ac1582021-01-08 14:19:27 -0800890 nitems + 40, sizeof(FTSENT *))) == NULL) {
Elliott Hughes70a8f222018-05-07 16:44:13 -0700891 free(sp->fts_array);
Colin Cross64ceac32010-01-13 21:19:52 -0800892 sp->fts_array = NULL;
893 sp->fts_nitems = 0;
894 return (head);
895 }
Elliott Hughes03ac1582021-01-08 14:19:27 -0800896 sp->fts_nitems = nitems + 40;
Colin Cross64ceac32010-01-13 21:19:52 -0800897 sp->fts_array = a;
898 }
899 for (ap = sp->fts_array, p = head; p; p = p->fts_link)
900 *ap++ = p;
Elliott Hughes03ac1582021-01-08 14:19:27 -0800901 qsort(sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
Colin Cross64ceac32010-01-13 21:19:52 -0800902 for (head = *(ap = sp->fts_array); --nitems; ++ap)
903 ap[0]->fts_link = ap[1];
904 ap[0]->fts_link = NULL;
905 return (head);
906}
907
908static FTSENT *
Elliott Hughes03ac1582021-01-08 14:19:27 -0800909fts_alloc(FTS *sp, const char *name, size_t namelen)
Colin Cross64ceac32010-01-13 21:19:52 -0800910{
911 FTSENT *p;
912 size_t len;
913
914 /*
915 * The file name is a variable length array and no stat structure is
916 * necessary if the user has set the nostat bit. Allocate the FTSENT
917 * structure, the file name and the stat structure in one chunk, but
918 * be careful that the stat structure is reasonably aligned. Since the
919 * fts_name field is declared to be of size 1, the fts_name pointer is
920 * namelen + 2 before the first possible address of the stat structure.
921 */
922 len = sizeof(FTSENT) + namelen;
923 if (!ISSET(FTS_NOSTAT))
924 len += sizeof(struct stat) + ALIGNBYTES;
Elliott Hughesec67cde2014-07-01 17:20:06 -0700925 if ((p = calloc(1, len)) == NULL)
Colin Cross64ceac32010-01-13 21:19:52 -0800926 return (NULL);
927
Colin Cross64ceac32010-01-13 21:19:52 -0800928 p->fts_path = sp->fts_path;
929 p->fts_namelen = namelen;
930 p->fts_instr = FTS_NOINSTR;
931 if (!ISSET(FTS_NOSTAT))
932 p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
933 memcpy(p->fts_name, name, namelen);
934
935 return (p);
936}
937
938static void
939fts_lfree(FTSENT *head)
940{
941 FTSENT *p;
942
943 /* Free a linked list of structures. */
944 while ((p = head)) {
945 head = head->fts_link;
946 free(p);
947 }
948}
949
950/*
951 * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
Elliott Hughesec67cde2014-07-01 17:20:06 -0700952 * Most systems will allow creation of paths much longer than PATH_MAX, even
Colin Cross64ceac32010-01-13 21:19:52 -0800953 * though the kernel won't resolve them. Add the size (not just what's needed)
954 * plus 256 bytes so don't realloc the path 2 bytes at a time.
955 */
956static int
957fts_palloc(FTS *sp, size_t more)
958{
959 char *p;
960
961 /*
962 * Check for possible wraparound.
963 */
964 more += 256;
965 if (sp->fts_pathlen + more < sp->fts_pathlen) {
Elliott Hughes70a8f222018-05-07 16:44:13 -0700966 free(sp->fts_path);
Colin Cross64ceac32010-01-13 21:19:52 -0800967 sp->fts_path = NULL;
968 errno = ENAMETOOLONG;
969 return (1);
970 }
Elliott Hughes03ac1582021-01-08 14:19:27 -0800971 p = recallocarray(sp->fts_path, sp->fts_pathlen,
972 sp->fts_pathlen + more, 1);
Colin Cross64ceac32010-01-13 21:19:52 -0800973 if (p == NULL) {
Elliott Hughes70a8f222018-05-07 16:44:13 -0700974 free(sp->fts_path);
Colin Cross64ceac32010-01-13 21:19:52 -0800975 sp->fts_path = NULL;
976 return (1);
977 }
Elliott Hughes03ac1582021-01-08 14:19:27 -0800978 sp->fts_pathlen += more;
Colin Cross64ceac32010-01-13 21:19:52 -0800979 sp->fts_path = p;
980 return (0);
981}
982
983/*
984 * When the path is realloc'd, have to fix all of the pointers in structures
985 * already returned.
986 */
987static void
988fts_padjust(FTS *sp, FTSENT *head)
989{
990 FTSENT *p;
991 char *addr = sp->fts_path;
992
993#define ADJUST(p) { \
994 if ((p)->fts_accpath != (p)->fts_name) { \
995 (p)->fts_accpath = \
996 (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
997 } \
998 (p)->fts_path = addr; \
999}
1000 /* Adjust the current set of children. */
1001 for (p = sp->fts_child; p; p = p->fts_link)
1002 ADJUST(p);
1003
1004 /* Adjust the rest of the tree, including the current level. */
1005 for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
1006 ADJUST(p);
1007 p = p->fts_link ? p->fts_link : p->fts_parent;
1008 }
1009}
1010
1011static size_t
1012fts_maxarglen(char * const *argv)
1013{
1014 size_t len, max;
1015
1016 for (max = 0; *argv; ++argv)
1017 if ((len = strlen(*argv)) > max)
1018 max = len;
1019 return (max + 1);
1020}
1021
1022/*
1023 * Change to dir specified by fd or p->fts_accpath without getting
1024 * tricked by someone changing the world out from underneath us.
1025 * Assumes p->fts_dev and p->fts_ino are filled in.
1026 */
1027static int
Elliott Hughes03ac1582021-01-08 14:19:27 -08001028fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
Colin Cross64ceac32010-01-13 21:19:52 -08001029{
1030 int ret, oerrno, newfd;
1031 struct stat sb;
1032
1033 newfd = fd;
1034 if (ISSET(FTS_NOCHDIR))
1035 return (0);
Elliott Hughes03ac1582021-01-08 14:19:27 -08001036 if (fd == -1 && (newfd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC)) == -1)
Colin Cross64ceac32010-01-13 21:19:52 -08001037 return (-1);
Elliott Hughes03ac1582021-01-08 14:19:27 -08001038 if (fstat(newfd, &sb) == -1) {
Colin Cross64ceac32010-01-13 21:19:52 -08001039 ret = -1;
1040 goto bail;
1041 }
1042 if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
1043 errno = ENOENT; /* disinformation */
1044 ret = -1;
1045 goto bail;
1046 }
1047 ret = fchdir(newfd);
1048bail:
1049 oerrno = errno;
Elliott Hughes03ac1582021-01-08 14:19:27 -08001050 if (fd == -1)
Colin Cross64ceac32010-01-13 21:19:52 -08001051 (void)close(newfd);
1052 errno = oerrno;
1053 return (ret);
1054}
Elliott Hughes70a8f222018-05-07 16:44:13 -07001055
Elliott Hughes03ac1582021-01-08 14:19:27 -08001056FTS *
1057fts_open(char * const *argv, int options,
1058 int (*compar)(const FTSENT **, const FTSENT **))
1059{
1060 // Android needs to an __fts_open() that doesn't make this check
1061 // so that FTS_FOR_FTW works.
1062 if (options & ~FTS_OPTIONMASK) {
1063 errno = EINVAL;
1064 return (NULL);
1065 }
1066 return __fts_open(argv, options, compar);
Elliott Hughes70a8f222018-05-07 16:44:13 -07001067}