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 * 3. 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 * From: $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ 29 */ 30 31 #include "namespace.h" 32 #include <sys/param.h> 33 #define _WANT_FREEBSD11_STATFS 34 #include <sys/mount.h> 35 #define _WANT_FREEBSD11_STAT 36 #include <sys/stat.h> 37 38 #define _WANT_FREEBSD11_DIRENT 39 #include <dirent.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <fts.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include "gen-compat.h" 47 #include "fts-compat11.h" 48 #include "un-namespace.h" 49 50 #include "gen-private.h" 51 52 static FTSENT11 *fts_alloc(FTS11 *, char *, size_t); 53 static FTSENT11 *fts_build(FTS11 *, int); 54 static void fts_lfree(FTSENT11 *); 55 static void fts_load(FTS11 *, FTSENT11 *); 56 static size_t fts_maxarglen(char * const *); 57 static void fts_padjust(FTS11 *, FTSENT11 *); 58 static int fts_palloc(FTS11 *, size_t); 59 static FTSENT11 *fts_sort(FTS11 *, FTSENT11 *, size_t); 60 static int fts_stat(FTS11 *, FTSENT11 *, int, int); 61 static int fts_safe_changedir(FTS11 *, FTSENT11 *, int, char *); 62 static int fts_ufslinks(FTS11 *, const FTSENT11 *); 63 64 #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) 65 66 #define CLR(opt) (sp->fts_options &= ~(opt)) 67 #define ISSET(opt) (sp->fts_options & (opt)) 68 #define SET(opt) (sp->fts_options |= (opt)) 69 70 #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) 71 72 /* fts_build flags */ 73 #define BCHILD 1 /* fts_children */ 74 #define BNAMES 2 /* fts_children, names only */ 75 #define BREAD 3 /* fts_read */ 76 77 /* 78 * Internal representation of an FTS, including extra implementation 79 * details. The FTS returned from fts_open points to this structure's 80 * ftsp_fts member (and can be cast to an _fts_private as required) 81 */ 82 struct _fts_private11 { 83 FTS11 ftsp_fts; 84 struct freebsd11_statfs ftsp_statfs; 85 uint32_t ftsp_dev; 86 int ftsp_linksreliable; 87 }; 88 89 /* 90 * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it 91 * knows that a directory could not possibly have subdirectories. This 92 * is decided by looking at the link count: a subdirectory would 93 * increment its parent's link count by virtue of its own ".." entry. 94 * This assumption only holds for UFS-like filesystems that implement 95 * links and directories this way, so we must punt for others. 96 */ 97 98 static const char *ufslike_filesystems[] = { 99 "ufs", 100 "zfs", 101 "nfs", 102 "ext2fs", 103 0 104 }; 105 106 FTS11 * 107 freebsd11_fts_open(char * const *argv, int options, 108 int (*compar)(const FTSENT11 * const *, const FTSENT11 * const *)) 109 { 110 struct _fts_private11 *priv; 111 FTS11 *sp; 112 FTSENT11 *p, *root; 113 FTSENT11 *parent, *tmp; 114 size_t len, nitems; 115 116 /* Options check. */ 117 if (options & ~FTS_OPTIONMASK) { 118 errno = EINVAL; 119 return (NULL); 120 } 121 122 /* fts_open() requires at least one path */ 123 if (*argv == NULL) { 124 errno = EINVAL; 125 return (NULL); 126 } 127 128 /* Allocate/initialize the stream. */ 129 if ((priv = calloc(1, sizeof(*priv))) == NULL) 130 return (NULL); 131 sp = &priv->ftsp_fts; 132 sp->fts_compar = compar; 133 sp->fts_options = options; 134 135 /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ 136 if (ISSET(FTS_LOGICAL)) 137 SET(FTS_NOCHDIR); 138 139 /* 140 * Start out with 1K of path space, and enough, in any case, 141 * to hold the user's paths. 142 */ 143 if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) 144 goto mem1; 145 146 /* Allocate/initialize root's parent. */ 147 if ((parent = fts_alloc(sp, "", 0)) == NULL) 148 goto mem2; 149 parent->fts_level = FTS_ROOTPARENTLEVEL; 150 151 /* Shush, GCC. */ 152 tmp = NULL; 153 154 /* Allocate/initialize root(s). */ 155 for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { 156 len = strlen(*argv); 157 158 p = fts_alloc(sp, *argv, len); 159 p->fts_level = FTS_ROOTLEVEL; 160 p->fts_parent = parent; 161 p->fts_accpath = p->fts_name; 162 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1); 163 164 /* Command-line "." and ".." are real directories. */ 165 if (p->fts_info == FTS_DOT) 166 p->fts_info = FTS_D; 167 168 /* 169 * If comparison routine supplied, traverse in sorted 170 * order; otherwise traverse in the order specified. 171 */ 172 if (compar) { 173 p->fts_link = root; 174 root = p; 175 } else { 176 p->fts_link = NULL; 177 if (root == NULL) 178 tmp = root = p; 179 else { 180 tmp->fts_link = p; 181 tmp = p; 182 } 183 } 184 } 185 if (compar && nitems > 1) 186 root = fts_sort(sp, root, nitems); 187 188 /* 189 * Allocate a dummy pointer and make fts_read think that we've just 190 * finished the node before the root(s); set p->fts_info to FTS_INIT 191 * so that everything about the "current" node is ignored. 192 */ 193 if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) 194 goto mem3; 195 sp->fts_cur->fts_link = root; 196 sp->fts_cur->fts_info = FTS_INIT; 197 198 /* 199 * If using chdir(2), grab a file descriptor pointing to dot to ensure 200 * that we can get back here; this could be avoided for some paths, 201 * but almost certainly not worth the effort. Slashes, symbolic links, 202 * and ".." are all fairly nasty problems. Note, if we can't get the 203 * descriptor we run anyway, just more slowly. 204 */ 205 if (!ISSET(FTS_NOCHDIR) && 206 (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) 207 SET(FTS_NOCHDIR); 208 209 return (sp); 210 211 mem3: fts_lfree(root); 212 free(parent); 213 mem2: free(sp->fts_path); 214 mem1: free(sp); 215 return (NULL); 216 } 217 218 static void 219 fts_load(FTS11 *sp, FTSENT11 *p) 220 { 221 size_t len; 222 char *cp; 223 224 /* 225 * Load the stream structure for the next traversal. Since we don't 226 * actually enter the directory until after the preorder visit, set 227 * the fts_accpath field specially so the chdir gets done to the right 228 * place and the user can access the first node. From fts_open it's 229 * known that the path will fit. 230 */ 231 len = p->fts_pathlen = p->fts_namelen; 232 memmove(sp->fts_path, p->fts_name, len + 1); 233 if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { 234 len = strlen(++cp); 235 memmove(p->fts_name, cp, len + 1); 236 p->fts_namelen = len; 237 } 238 p->fts_accpath = p->fts_path = sp->fts_path; 239 sp->fts_dev = p->fts_dev; 240 } 241 242 int 243 freebsd11_fts_close(FTS11 *sp) 244 { 245 FTSENT11 *freep, *p; 246 int saved_errno; 247 248 /* 249 * This still works if we haven't read anything -- the dummy structure 250 * points to the root list, so we step through to the end of the root 251 * list which has a valid parent pointer. 252 */ 253 if (sp->fts_cur) { 254 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { 255 freep = p; 256 p = p->fts_link != NULL ? p->fts_link : p->fts_parent; 257 free(freep); 258 } 259 free(p); 260 } 261 262 /* Free up child linked list, sort array, path buffer. */ 263 if (sp->fts_child) 264 fts_lfree(sp->fts_child); 265 if (sp->fts_array) 266 free(sp->fts_array); 267 free(sp->fts_path); 268 269 /* Return to original directory, save errno if necessary. */ 270 if (!ISSET(FTS_NOCHDIR)) { 271 saved_errno = fchdir(sp->fts_rfd) ? errno : 0; 272 (void)_close(sp->fts_rfd); 273 274 /* Set errno and return. */ 275 if (saved_errno != 0) { 276 /* Free up the stream pointer. */ 277 free(sp); 278 errno = saved_errno; 279 return (-1); 280 } 281 } 282 283 /* Free up the stream pointer. */ 284 free(sp); 285 return (0); 286 } 287 288 /* 289 * Special case of "/" at the end of the path so that slashes aren't 290 * appended which would cause paths to be written as "....//foo". 291 */ 292 #define NAPPEND(p) \ 293 (p->fts_path[p->fts_pathlen - 1] == '/' \ 294 ? p->fts_pathlen - 1 : p->fts_pathlen) 295 296 FTSENT11 * 297 freebsd11_fts_read(FTS11 *sp) 298 { 299 FTSENT11 *p, *tmp; 300 int instr; 301 char *t; 302 int saved_errno; 303 304 /* If finished or unrecoverable error, return NULL. */ 305 if (sp->fts_cur == NULL || ISSET(FTS_STOP)) 306 return (NULL); 307 308 /* Set current node pointer. */ 309 p = sp->fts_cur; 310 311 /* Save and zero out user instructions. */ 312 instr = p->fts_instr; 313 p->fts_instr = FTS_NOINSTR; 314 315 /* Any type of file may be re-visited; re-stat and re-turn. */ 316 if (instr == FTS_AGAIN) { 317 p->fts_info = fts_stat(sp, p, 0, -1); 318 return (p); 319 } 320 321 /* 322 * Following a symlink -- SLNONE test allows application to see 323 * SLNONE and recover. If indirecting through a symlink, have 324 * keep a pointer to current location. If unable to get that 325 * pointer, follow fails. 326 */ 327 if (instr == FTS_FOLLOW && 328 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { 329 p->fts_info = fts_stat(sp, p, 1, -1); 330 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 331 if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC, 332 0)) < 0) { 333 p->fts_errno = errno; 334 p->fts_info = FTS_ERR; 335 } else 336 p->fts_flags |= FTS_SYMFOLLOW; 337 } 338 return (p); 339 } 340 341 /* Directory in pre-order. */ 342 if (p->fts_info == FTS_D) { 343 /* If skipped or crossed mount point, do post-order visit. */ 344 if (instr == FTS_SKIP || 345 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { 346 if (p->fts_flags & FTS_SYMFOLLOW) 347 (void)_close(p->fts_symfd); 348 if (sp->fts_child) { 349 fts_lfree(sp->fts_child); 350 sp->fts_child = NULL; 351 } 352 p->fts_info = FTS_DP; 353 return (p); 354 } 355 356 /* Rebuild if only read the names and now traversing. */ 357 if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { 358 CLR(FTS_NAMEONLY); 359 fts_lfree(sp->fts_child); 360 sp->fts_child = NULL; 361 } 362 363 /* 364 * Cd to the subdirectory. 365 * 366 * If have already read and now fail to chdir, whack the list 367 * to make the names come out right, and set the parent errno 368 * so the application will eventually get an error condition. 369 * Set the FTS_DONTCHDIR flag so that when we logically change 370 * directories back to the parent we don't do a chdir. 371 * 372 * If haven't read do so. If the read fails, fts_build sets 373 * FTS_STOP or the fts_info field of the node. 374 */ 375 if (sp->fts_child != NULL) { 376 if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { 377 p->fts_errno = errno; 378 p->fts_flags |= FTS_DONTCHDIR; 379 for (p = sp->fts_child; p != NULL; 380 p = p->fts_link) 381 p->fts_accpath = 382 p->fts_parent->fts_accpath; 383 } 384 } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { 385 if (ISSET(FTS_STOP)) 386 return (NULL); 387 return (p); 388 } 389 p = sp->fts_child; 390 sp->fts_child = NULL; 391 goto name; 392 } 393 394 /* Move to the next node on this level. */ 395 next: tmp = p; 396 if ((p = p->fts_link) != NULL) { 397 /* 398 * If reached the top, return to the original directory (or 399 * the root of the tree), and load the paths for the next root. 400 */ 401 if (p->fts_level == FTS_ROOTLEVEL) { 402 if (FCHDIR(sp, sp->fts_rfd)) { 403 SET(FTS_STOP); 404 return (NULL); 405 } 406 free(tmp); 407 fts_load(sp, p); 408 return (sp->fts_cur = p); 409 } 410 411 /* 412 * User may have called fts_set on the node. If skipped, 413 * ignore. If followed, get a file descriptor so we can 414 * get back if necessary. 415 */ 416 if (p->fts_instr == FTS_SKIP) { 417 free(tmp); 418 goto next; 419 } 420 if (p->fts_instr == FTS_FOLLOW) { 421 p->fts_info = fts_stat(sp, p, 1, -1); 422 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 423 if ((p->fts_symfd = 424 _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { 425 p->fts_errno = errno; 426 p->fts_info = FTS_ERR; 427 } else 428 p->fts_flags |= FTS_SYMFOLLOW; 429 } 430 p->fts_instr = FTS_NOINSTR; 431 } 432 433 free(tmp); 434 435 name: t = sp->fts_path + NAPPEND(p->fts_parent); 436 *t++ = '/'; 437 memmove(t, p->fts_name, p->fts_namelen + 1); 438 return (sp->fts_cur = p); 439 } 440 441 /* Move up to the parent node. */ 442 p = tmp->fts_parent; 443 444 if (p->fts_level == FTS_ROOTPARENTLEVEL) { 445 /* 446 * Done; free everything up and set errno to 0 so the user 447 * can distinguish between error and EOF. 448 */ 449 free(tmp); 450 free(p); 451 errno = 0; 452 return (sp->fts_cur = NULL); 453 } 454 455 /* NUL terminate the pathname. */ 456 sp->fts_path[p->fts_pathlen] = '\0'; 457 458 /* 459 * Return to the parent directory. If at a root node or came through 460 * a symlink, go back through the file descriptor. Otherwise, cd up 461 * one directory. 462 */ 463 if (p->fts_level == FTS_ROOTLEVEL) { 464 if (FCHDIR(sp, sp->fts_rfd)) { 465 SET(FTS_STOP); 466 return (NULL); 467 } 468 } else if (p->fts_flags & FTS_SYMFOLLOW) { 469 if (FCHDIR(sp, p->fts_symfd)) { 470 saved_errno = errno; 471 (void)_close(p->fts_symfd); 472 errno = saved_errno; 473 SET(FTS_STOP); 474 return (NULL); 475 } 476 (void)_close(p->fts_symfd); 477 } else if (!(p->fts_flags & FTS_DONTCHDIR) && 478 fts_safe_changedir(sp, p->fts_parent, -1, "..")) { 479 SET(FTS_STOP); 480 return (NULL); 481 } 482 free(tmp); 483 p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; 484 return (sp->fts_cur = p); 485 } 486 487 /* 488 * Fts_set takes the stream as an argument although it's not used in this 489 * implementation; it would be necessary if anyone wanted to add global 490 * semantics to fts using fts_set. An error return is allowed for similar 491 * reasons. 492 */ 493 /* ARGSUSED */ 494 int 495 freebsd11_fts_set(FTS11 *sp, FTSENT11 *p, int instr) 496 { 497 if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && 498 instr != FTS_NOINSTR && instr != FTS_SKIP) { 499 errno = EINVAL; 500 return (1); 501 } 502 p->fts_instr = instr; 503 return (0); 504 } 505 506 FTSENT11 * 507 freebsd11_fts_children(FTS11 *sp, int instr) 508 { 509 FTSENT11 *p; 510 int fd, rc, serrno; 511 512 if (instr != 0 && instr != FTS_NAMEONLY) { 513 errno = EINVAL; 514 return (NULL); 515 } 516 517 /* Set current node pointer. */ 518 p = sp->fts_cur; 519 520 /* 521 * Errno set to 0 so user can distinguish empty directory from 522 * an error. 523 */ 524 errno = 0; 525 526 /* Fatal errors stop here. */ 527 if (ISSET(FTS_STOP)) 528 return (NULL); 529 530 /* Return logical hierarchy of user's arguments. */ 531 if (p->fts_info == FTS_INIT) 532 return (p->fts_link); 533 534 /* 535 * If not a directory being visited in pre-order, stop here. Could 536 * allow FTS_DNR, assuming the user has fixed the problem, but the 537 * same effect is available with FTS_AGAIN. 538 */ 539 if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) 540 return (NULL); 541 542 /* Free up any previous child list. */ 543 if (sp->fts_child != NULL) 544 fts_lfree(sp->fts_child); 545 546 if (instr == FTS_NAMEONLY) { 547 SET(FTS_NAMEONLY); 548 instr = BNAMES; 549 } else 550 instr = BCHILD; 551 552 /* 553 * If using chdir on a relative path and called BEFORE fts_read does 554 * its chdir to the root of a traversal, we can lose -- we need to 555 * chdir into the subdirectory, and we don't know where the current 556 * directory is, so we can't get back so that the upcoming chdir by 557 * fts_read will work. 558 */ 559 if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || 560 ISSET(FTS_NOCHDIR)) 561 return (sp->fts_child = fts_build(sp, instr)); 562 563 if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) 564 return (NULL); 565 sp->fts_child = fts_build(sp, instr); 566 serrno = (sp->fts_child == NULL) ? errno : 0; 567 rc = fchdir(fd); 568 if (rc < 0 && serrno == 0) 569 serrno = errno; 570 (void)_close(fd); 571 errno = serrno; 572 if (rc < 0) 573 return (NULL); 574 return (sp->fts_child); 575 } 576 577 #ifndef freebsd11_fts_get_clientptr 578 #error "freebsd11_fts_get_clientptr not defined" 579 #endif 580 581 void * 582 (freebsd11_fts_get_clientptr)(FTS11 *sp) 583 { 584 585 return (freebsd11_fts_get_clientptr(sp)); 586 } 587 588 #ifndef freebsd11_fts_get_stream 589 #error "freebsd11_fts_get_stream not defined" 590 #endif 591 592 FTS11 * 593 (freebsd11_fts_get_stream)(FTSENT11 *p) 594 { 595 return (freebsd11_fts_get_stream(p)); 596 } 597 598 void 599 freebsd11_fts_set_clientptr(FTS11 *sp, void *clientptr) 600 { 601 602 sp->fts_clientptr = clientptr; 603 } 604 605 static struct freebsd11_dirent * 606 fts_safe_readdir(DIR *dirp, int *readdir_errno) 607 { 608 struct freebsd11_dirent *ret; 609 610 errno = 0; 611 if (!dirp) 612 return (NULL); 613 ret = freebsd11_readdir(dirp); 614 *readdir_errno = errno; 615 return (ret); 616 } 617 618 /* 619 * This is the tricky part -- do not casually change *anything* in here. The 620 * idea is to build the linked list of entries that are used by fts_children 621 * and fts_read. There are lots of special cases. 622 * 623 * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is 624 * set and it's a physical walk (so that symbolic links can't be directories), 625 * we can do things quickly. First, if it's a 4.4BSD file system, the type 626 * of the file is in the directory entry. Otherwise, we assume that the number 627 * of subdirectories in a node is equal to the number of links to the parent. 628 * The former skips all stat calls. The latter skips stat calls in any leaf 629 * directories and for any files after the subdirectories in the directory have 630 * been found, cutting the stat calls by about 2/3. 631 */ 632 static FTSENT11 * 633 fts_build(FTS11 *sp, int type) 634 { 635 struct freebsd11_dirent *dp; 636 FTSENT11 *p, *head; 637 FTSENT11 *cur, *tail; 638 DIR *dirp; 639 void *oldaddr; 640 char *cp; 641 int cderrno, descend, oflag, saved_errno, nostat, doadjust, 642 readdir_errno; 643 long level; 644 long nlinks; /* has to be signed because -1 is a magic value */ 645 size_t dnamlen, len, maxlen, nitems; 646 647 /* Set current node pointer. */ 648 cur = sp->fts_cur; 649 650 /* 651 * Open the directory for reading. If this fails, we're done. 652 * If being called from fts_read, set the fts_info field. 653 */ 654 #ifdef FTS_WHITEOUT 655 if (ISSET(FTS_WHITEOUT)) 656 oflag = DTF_NODUP; 657 else 658 oflag = DTF_HIDEW | DTF_NODUP; 659 #else 660 #define __opendir2(path, flag) opendir(path) 661 #endif 662 if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { 663 if (type == BREAD) { 664 cur->fts_info = FTS_DNR; 665 cur->fts_errno = errno; 666 } 667 return (NULL); 668 } 669 670 /* 671 * Nlinks is the number of possible entries of type directory in the 672 * directory if we're cheating on stat calls, 0 if we're not doing 673 * any stat calls at all, -1 if we're doing stats on everything. 674 */ 675 if (type == BNAMES) { 676 nlinks = 0; 677 /* Be quiet about nostat, GCC. */ 678 nostat = 0; 679 } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { 680 if (fts_ufslinks(sp, cur)) 681 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); 682 else 683 nlinks = -1; 684 nostat = 1; 685 } else { 686 nlinks = -1; 687 nostat = 0; 688 } 689 690 #ifdef notdef 691 (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); 692 (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", 693 ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); 694 #endif 695 /* 696 * If we're going to need to stat anything or we want to descend 697 * and stay in the directory, chdir. If this fails we keep going, 698 * but set a flag so we don't chdir after the post-order visit. 699 * We won't be able to stat anything, but we can still return the 700 * names themselves. Note, that since fts_read won't be able to 701 * chdir into the directory, it will have to return different path 702 * names than before, i.e. "a/b" instead of "b". Since the node 703 * has already been visited in pre-order, have to wait until the 704 * post-order visit to return the error. There is a special case 705 * here, if there was nothing to stat then it's not an error to 706 * not be able to stat. This is all fairly nasty. If a program 707 * needed sorted entries or stat information, they had better be 708 * checking FTS_NS on the returned nodes. 709 */ 710 cderrno = 0; 711 if (nlinks || type == BREAD) { 712 if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) { 713 if (nlinks && type == BREAD) 714 cur->fts_errno = errno; 715 cur->fts_flags |= FTS_DONTCHDIR; 716 descend = 0; 717 cderrno = errno; 718 } else 719 descend = 1; 720 } else 721 descend = 0; 722 723 /* 724 * Figure out the max file name length that can be stored in the 725 * current path -- the inner loop allocates more path as necessary. 726 * We really wouldn't have to do the maxlen calculations here, we 727 * could do them in fts_read before returning the path, but it's a 728 * lot easier here since the length is part of the dirent structure. 729 * 730 * If not changing directories set a pointer so that can just append 731 * each new name into the path. 732 */ 733 len = NAPPEND(cur); 734 if (ISSET(FTS_NOCHDIR)) { 735 cp = sp->fts_path + len; 736 *cp++ = '/'; 737 } else { 738 /* GCC, you're too verbose. */ 739 cp = NULL; 740 } 741 len++; 742 maxlen = sp->fts_pathlen - len; 743 744 level = cur->fts_level + 1; 745 746 /* Read the directory, attaching each entry to the `link' pointer. */ 747 doadjust = 0; 748 readdir_errno = 0; 749 for (head = tail = NULL, nitems = 0; 750 (dp = fts_safe_readdir(dirp, &readdir_errno));) { 751 dnamlen = dp->d_namlen; 752 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) 753 continue; 754 755 if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) 756 goto mem1; 757 if (dnamlen >= maxlen) { /* include space for NUL */ 758 oldaddr = sp->fts_path; 759 if (fts_palloc(sp, dnamlen + len + 1)) { 760 /* 761 * No more memory for path or structures. Save 762 * errno, free up the current structure and the 763 * structures already allocated. 764 */ 765 mem1: saved_errno = errno; 766 if (p) 767 free(p); 768 fts_lfree(head); 769 (void)closedir(dirp); 770 cur->fts_info = FTS_ERR; 771 SET(FTS_STOP); 772 errno = saved_errno; 773 return (NULL); 774 } 775 /* Did realloc() change the pointer? */ 776 if (oldaddr != sp->fts_path) { 777 doadjust = 1; 778 if (ISSET(FTS_NOCHDIR)) 779 cp = sp->fts_path + len; 780 } 781 maxlen = sp->fts_pathlen - len; 782 } 783 784 p->fts_level = level; 785 p->fts_parent = sp->fts_cur; 786 p->fts_pathlen = len + dnamlen; 787 788 #ifdef FTS_WHITEOUT 789 if (dp->d_type == DT_WHT) 790 p->fts_flags |= FTS_ISW; 791 #endif 792 793 if (cderrno) { 794 if (nlinks) { 795 p->fts_info = FTS_NS; 796 p->fts_errno = cderrno; 797 } else 798 p->fts_info = FTS_NSOK; 799 p->fts_accpath = cur->fts_accpath; 800 } else if (nlinks == 0 801 #ifdef DT_DIR 802 || (nostat && 803 dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) 804 #endif 805 ) { 806 p->fts_accpath = 807 ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; 808 p->fts_info = FTS_NSOK; 809 } else { 810 /* Build a file name for fts_stat to stat. */ 811 if (ISSET(FTS_NOCHDIR)) { 812 p->fts_accpath = p->fts_path; 813 memmove(cp, p->fts_name, p->fts_namelen + 1); 814 p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp)); 815 } else { 816 p->fts_accpath = p->fts_name; 817 p->fts_info = fts_stat(sp, p, 0, -1); 818 } 819 820 /* Decrement link count if applicable. */ 821 if (nlinks > 0 && (p->fts_info == FTS_D || 822 p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) 823 --nlinks; 824 } 825 826 /* We walk in directory order so "ls -f" doesn't get upset. */ 827 p->fts_link = NULL; 828 if (head == NULL) 829 head = tail = p; 830 else { 831 tail->fts_link = p; 832 tail = p; 833 } 834 ++nitems; 835 } 836 837 if (readdir_errno) { 838 cur->fts_errno = readdir_errno; 839 /* 840 * If we've not read any items yet, treat 841 * the error as if we can't access the dir. 842 */ 843 cur->fts_info = nitems ? FTS_ERR : FTS_DNR; 844 } 845 846 if (dirp) 847 (void)closedir(dirp); 848 849 /* 850 * If realloc() changed the address of the path, adjust the 851 * addresses for the rest of the tree and the dir list. 852 */ 853 if (doadjust) 854 fts_padjust(sp, head); 855 856 /* 857 * If not changing directories, reset the path back to original 858 * state. 859 */ 860 if (ISSET(FTS_NOCHDIR)) 861 sp->fts_path[cur->fts_pathlen] = '\0'; 862 863 /* 864 * If descended after called from fts_children or after called from 865 * fts_read and nothing found, get back. At the root level we use 866 * the saved fd; if one of fts_open()'s arguments is a relative path 867 * to an empty directory, we wind up here with no other way back. If 868 * can't get back, we're done. 869 */ 870 if (descend && (type == BCHILD || !nitems) && 871 (cur->fts_level == FTS_ROOTLEVEL ? 872 FCHDIR(sp, sp->fts_rfd) : 873 fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { 874 fts_lfree(head); 875 cur->fts_info = FTS_ERR; 876 SET(FTS_STOP); 877 return (NULL); 878 } 879 880 /* If didn't find anything, return NULL. */ 881 if (!nitems) { 882 if (type == BREAD && 883 cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR) 884 cur->fts_info = FTS_DP; 885 return (NULL); 886 } 887 888 /* Sort the entries. */ 889 if (sp->fts_compar && nitems > 1) 890 head = fts_sort(sp, head, nitems); 891 return (head); 892 } 893 894 static int 895 fts_stat(FTS11 *sp, FTSENT11 *p, int follow, int dfd) 896 { 897 FTSENT11 *t; 898 uint32_t dev; 899 uint32_t ino; 900 struct freebsd11_stat *sbp, sb; 901 int saved_errno; 902 const char *path; 903 904 if (dfd == -1) 905 path = p->fts_accpath, dfd = AT_FDCWD; 906 else 907 path = p->fts_name; 908 909 /* If user needs stat info, stat buffer already allocated. */ 910 sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; 911 912 #ifdef FTS_WHITEOUT 913 /* Check for whiteout. */ 914 if (p->fts_flags & FTS_ISW) { 915 if (sbp != &sb) { 916 memset(sbp, '\0', sizeof(*sbp)); 917 sbp->st_mode = S_IFWHT; 918 } 919 return (FTS_W); 920 } 921 #endif 922 923 /* 924 * If doing a logical walk, or application requested FTS_FOLLOW, do 925 * a stat(2). If that fails, check for a non-existent symlink. If 926 * fail, set the errno from the stat call. 927 */ 928 if (ISSET(FTS_LOGICAL) || follow) { 929 if (freebsd11_fstatat(dfd, path, sbp, 0)) { 930 saved_errno = errno; 931 if (freebsd11_fstatat(dfd, path, sbp, 932 AT_SYMLINK_NOFOLLOW)) { 933 p->fts_errno = saved_errno; 934 goto err; 935 } 936 errno = 0; 937 if (S_ISLNK(sbp->st_mode)) 938 return (FTS_SLNONE); 939 } 940 } else if (freebsd11_fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { 941 p->fts_errno = errno; 942 err: memset(sbp, 0, sizeof(*sbp)); 943 return (FTS_NS); 944 } 945 946 if (S_ISDIR(sbp->st_mode)) { 947 /* 948 * Set the device/inode. Used to find cycles and check for 949 * crossing mount points. Also remember the link count, used 950 * in fts_build to limit the number of stat calls. It is 951 * understood that these fields are only referenced if fts_info 952 * is set to FTS_D. 953 */ 954 dev = p->fts_dev = sbp->st_dev; 955 ino = p->fts_ino = sbp->st_ino; 956 p->fts_nlink = sbp->st_nlink; 957 958 if (ISDOT(p->fts_name)) 959 return (FTS_DOT); 960 961 /* 962 * Cycle detection is done by brute force when the directory 963 * is first encountered. If the tree gets deep enough or the 964 * number of symbolic links to directories is high enough, 965 * something faster might be worthwhile. 966 */ 967 for (t = p->fts_parent; 968 t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) 969 if (ino == t->fts_ino && dev == t->fts_dev) { 970 p->fts_cycle = t; 971 return (FTS_DC); 972 } 973 return (FTS_D); 974 } 975 if (S_ISLNK(sbp->st_mode)) 976 return (FTS_SL); 977 if (S_ISREG(sbp->st_mode)) 978 return (FTS_F); 979 return (FTS_DEFAULT); 980 } 981 982 /* 983 * The comparison function takes pointers to pointers to FTSENT structures. 984 * Qsort wants a comparison function that takes pointers to void. 985 * (Both with appropriate levels of const-poisoning, of course!) 986 * Use a trampoline function to deal with the difference. 987 */ 988 static int 989 fts_compar(const void *a, const void *b) 990 { 991 FTS11 *parent; 992 993 parent = (*(const FTSENT11 * const *)a)->fts_fts; 994 return (*parent->fts_compar)(a, b); 995 } 996 997 static FTSENT11 * 998 fts_sort(FTS11 *sp, FTSENT11 *head, size_t nitems) 999 { 1000 FTSENT11 **ap, *p; 1001 1002 /* 1003 * Construct an array of pointers to the structures and call qsort(3). 1004 * Reassemble the array in the order returned by qsort. If unable to 1005 * sort for memory reasons, return the directory entries in their 1006 * current order. Allocate enough space for the current needs plus 1007 * 40 so don't realloc one entry at a time. 1008 */ 1009 if (nitems > sp->fts_nitems) { 1010 sp->fts_nitems = nitems + 40; 1011 if ((sp->fts_array = reallocf(sp->fts_array, 1012 sp->fts_nitems * sizeof(FTSENT11 *))) == NULL) { 1013 sp->fts_nitems = 0; 1014 return (head); 1015 } 1016 } 1017 for (ap = sp->fts_array, p = head; p; p = p->fts_link) 1018 *ap++ = p; 1019 qsort(sp->fts_array, nitems, sizeof(FTSENT11 *), fts_compar); 1020 for (head = *(ap = sp->fts_array); --nitems; ++ap) 1021 ap[0]->fts_link = ap[1]; 1022 ap[0]->fts_link = NULL; 1023 return (head); 1024 } 1025 1026 static FTSENT11 * 1027 fts_alloc(FTS11 *sp, char *name, size_t namelen) 1028 { 1029 FTSENT11 *p; 1030 size_t len; 1031 1032 struct ftsent11_withstat { 1033 FTSENT11 ent; 1034 struct freebsd11_stat statbuf; 1035 }; 1036 1037 /* 1038 * The file name is a variable length array and no stat structure is 1039 * necessary if the user has set the nostat bit. Allocate the FTSENT 1040 * structure, the file name and the stat structure in one chunk, but 1041 * be careful that the stat structure is reasonably aligned. 1042 */ 1043 if (ISSET(FTS_NOSTAT)) 1044 len = sizeof(FTSENT11) + namelen + 1; 1045 else 1046 len = sizeof(struct ftsent11_withstat) + namelen + 1; 1047 1048 if ((p = malloc(len)) == NULL) 1049 return (NULL); 1050 1051 if (ISSET(FTS_NOSTAT)) { 1052 p->fts_name = (char *)(p + 1); 1053 p->fts_statp = NULL; 1054 } else { 1055 p->fts_name = (char *)((struct ftsent11_withstat *)p + 1); 1056 p->fts_statp = &((struct ftsent11_withstat *)p)->statbuf; 1057 } 1058 1059 /* Copy the name and guarantee NUL termination. */ 1060 memcpy(p->fts_name, name, namelen); 1061 p->fts_name[namelen] = '\0'; 1062 p->fts_namelen = namelen; 1063 p->fts_path = sp->fts_path; 1064 p->fts_errno = 0; 1065 p->fts_flags = 0; 1066 p->fts_instr = FTS_NOINSTR; 1067 p->fts_number = 0; 1068 p->fts_pointer = NULL; 1069 p->fts_fts = sp; 1070 return (p); 1071 } 1072 1073 static void 1074 fts_lfree(FTSENT11 *head) 1075 { 1076 FTSENT11 *p; 1077 1078 /* Free a linked list of structures. */ 1079 while ((p = head)) { 1080 head = head->fts_link; 1081 free(p); 1082 } 1083 } 1084 1085 /* 1086 * Allow essentially unlimited paths; find, rm, ls should all work on any tree. 1087 * Most systems will allow creation of paths much longer than MAXPATHLEN, even 1088 * though the kernel won't resolve them. Add the size (not just what's needed) 1089 * plus 256 bytes so don't realloc the path 2 bytes at a time. 1090 */ 1091 static int 1092 fts_palloc(FTS11 *sp, size_t more) 1093 { 1094 1095 sp->fts_pathlen += more + 256; 1096 sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen); 1097 return (sp->fts_path == NULL); 1098 } 1099 1100 /* 1101 * When the path is realloc'd, have to fix all of the pointers in structures 1102 * already returned. 1103 */ 1104 static void 1105 fts_padjust(FTS11 *sp, FTSENT11 *head) 1106 { 1107 FTSENT11 *p; 1108 char *addr = sp->fts_path; 1109 1110 #define ADJUST(p) do { \ 1111 if ((p)->fts_accpath != (p)->fts_name) { \ 1112 (p)->fts_accpath = \ 1113 (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ 1114 } \ 1115 (p)->fts_path = addr; \ 1116 } while (0) 1117 /* Adjust the current set of children. */ 1118 for (p = sp->fts_child; p; p = p->fts_link) 1119 ADJUST(p); 1120 1121 /* Adjust the rest of the tree, including the current level. */ 1122 for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { 1123 ADJUST(p); 1124 p = p->fts_link ? p->fts_link : p->fts_parent; 1125 } 1126 } 1127 1128 static size_t 1129 fts_maxarglen(char * const *argv) 1130 { 1131 size_t len, max; 1132 1133 for (max = 0; *argv; ++argv) 1134 if ((len = strlen(*argv)) > max) 1135 max = len; 1136 return (max + 1); 1137 } 1138 1139 /* 1140 * Change to dir specified by fd or p->fts_accpath without getting 1141 * tricked by someone changing the world out from underneath us. 1142 * Assumes p->fts_dev and p->fts_ino are filled in. 1143 */ 1144 static int 1145 fts_safe_changedir(FTS11 *sp, FTSENT11 *p, int fd, char *path) 1146 { 1147 int ret, oerrno, newfd; 1148 struct freebsd11_stat sb; 1149 1150 newfd = fd; 1151 if (ISSET(FTS_NOCHDIR)) 1152 return (0); 1153 if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY | 1154 O_CLOEXEC, 0)) < 0) 1155 return (-1); 1156 if (freebsd11_fstat(newfd, &sb)) { 1157 ret = -1; 1158 goto bail; 1159 } 1160 if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { 1161 errno = ENOENT; /* disinformation */ 1162 ret = -1; 1163 goto bail; 1164 } 1165 ret = fchdir(newfd); 1166 bail: 1167 oerrno = errno; 1168 if (fd < 0) 1169 (void)_close(newfd); 1170 errno = oerrno; 1171 return (ret); 1172 } 1173 1174 /* 1175 * Check if the filesystem for "ent" has UFS-style links. 1176 */ 1177 static int 1178 fts_ufslinks(FTS11 *sp, const FTSENT11 *ent) 1179 { 1180 struct _fts_private11 *priv; 1181 const char **cpp; 1182 1183 priv = (struct _fts_private11 *)sp; 1184 /* 1185 * If this node's device is different from the previous, grab 1186 * the filesystem information, and decide on the reliability 1187 * of the link information from this filesystem for stat(2) 1188 * avoidance. 1189 */ 1190 if (priv->ftsp_dev != ent->fts_dev) { 1191 if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { 1192 priv->ftsp_dev = ent->fts_dev; 1193 priv->ftsp_linksreliable = 0; 1194 for (cpp = ufslike_filesystems; *cpp; cpp++) { 1195 if (strcmp(priv->ftsp_statfs.f_fstypename, 1196 *cpp) == 0) { 1197 priv->ftsp_linksreliable = 1; 1198 break; 1199 } 1200 } 1201 } else { 1202 priv->ftsp_linksreliable = 0; 1203 } 1204 } 1205 return (priv->ftsp_linksreliable); 1206 } 1207 1208 __sym_compat(fts_open, freebsd11_fts_open, FBSD_1.1); 1209 __sym_compat(fts_close, freebsd11_fts_close, FBSD_1.1); 1210 __sym_compat(fts_read, freebsd11_fts_read, FBSD_1.1); 1211 __sym_compat(fts_set, freebsd11_fts_set, FBSD_1.1); 1212 __sym_compat(fts_children, freebsd11_fts_children, FBSD_1.1); 1213 __sym_compat(fts_get_clientptr, freebsd11_fts_get_clientptr, FBSD_1.1); 1214 __sym_compat(fts_get_stream, freebsd11_fts_get_stream, FBSD_1.1); 1215 __sym_compat(fts_set_clientptr, freebsd11_fts_set_clientptr, FBSD_1.1); 1216