1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)fts.c 5.21 (Berkeley) 12/30/91"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 #include <sys/param.h> 13 #include <sys/stat.h> 14 #include <fcntl.h> 15 #include <dirent.h> 16 #include <errno.h> 17 #include "fts.h" 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 22 static FTSENT *fts_alloc __P((FTS *, char *, int)); 23 static FTSENT *fts_build __P((FTS *, int)); 24 static void fts_lfree __P((FTSENT *)); 25 static void fts_load __P((FTS *, FTSENT *)); 26 static char *fts_path __P((FTS *, int)); 27 static FTSENT *fts_sort __P((FTS *, FTSENT *, int)); 28 static u_short fts_stat __P((FTS *, FTSENT *, int)); 29 30 #define ISSET(opt) (sp->fts_options & opt) 31 #define SET(opt) (sp->fts_options |= opt) 32 33 #define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) 34 #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) 35 36 /* fts_build flags */ 37 #define BCHILD 1 /* from fts_children */ 38 #define BREAD 2 /* from fts_read */ 39 40 FTS * 41 fts_open(argv, options, compar) 42 char * const *argv; 43 register int options; 44 int (*compar)(); 45 { 46 register FTS *sp; 47 register FTSENT *p, *root; 48 register int nitems, maxlen; 49 FTSENT *parent, *tmp; 50 int len; 51 52 /* Allocate/initialize the stream */ 53 if (!(sp = (FTS *)malloc((u_int)sizeof(FTS)))) 54 return(NULL); 55 bzero(sp, sizeof(FTS)); 56 sp->fts_compar = compar; 57 sp->fts_options = options; 58 59 /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ 60 if (ISSET(FTS_LOGICAL)) 61 SET(FTS_NOCHDIR); 62 63 /* Allocate/initialize root's parent. */ 64 if (!(parent = fts_alloc(sp, "", 0))) 65 goto mem1; 66 parent->fts_level = FTS_ROOTPARENTLEVEL; 67 68 /* Allocate/initialize root(s). */ 69 maxlen = -1; 70 for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { 71 if (!(len = strlen(*argv))) { 72 errno = ENOENT; 73 goto mem2; 74 } 75 if (maxlen < len) 76 maxlen = len; 77 p = fts_alloc(sp, *argv, len); 78 p->fts_level = FTS_ROOTLEVEL; 79 p->fts_parent = parent; 80 /* 81 * If comparison routine supplied, traverse in sorted 82 * order; otherwise traverse in the order specified. 83 */ 84 if (compar) { 85 p->fts_link = root; 86 root = p; 87 p->fts_accpath = p->fts_name; 88 if (!(options & FTS_NOSTAT)) 89 p->fts_info = fts_stat(sp, p, 0); 90 } else { 91 p->fts_link = NULL; 92 if (!root) 93 tmp = root = p; 94 else { 95 tmp->fts_link = p; 96 tmp = p; 97 } 98 } 99 } 100 if (compar && nitems > 1) 101 root = fts_sort(sp, root, nitems); 102 103 /* 104 * Allocate a dummy pointer and make fts_read think that we've just 105 * finished the node before the root(s); set p->fts_info to FTS_NS 106 * so that everything about the "current" node is ignored. 107 */ 108 if (!(sp->fts_cur = fts_alloc(sp, "", 0))) 109 goto mem2; 110 sp->fts_cur->fts_link = root; 111 sp->fts_cur->fts_info = FTS_NS; 112 113 /* Start out with at least 1K+ of path space. */ 114 if (!fts_path(sp, MAX(maxlen, MAXPATHLEN))) 115 goto mem3; 116 117 /* 118 * If using chdir(2), grab a file descriptor pointing to dot to insure 119 * that we can get back here; this could be avoided for some paths, 120 * but almost certainly not worth the effort. Slashes, symbolic links, 121 * and ".." are all fairly nasty problems. Note, if we can't get the 122 * descriptor we run anyway, just more slowly. 123 */ 124 if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0) 125 SET(FTS_NOCHDIR); 126 127 return(sp); 128 129 mem3: free(sp->fts_cur); 130 mem2: fts_lfree(root); 131 free(parent); 132 mem1: free(sp); 133 return(NULL); 134 } 135 136 static void 137 fts_load(sp, p) 138 FTS *sp; 139 register FTSENT *p; 140 { 141 register int len; 142 register char *cp; 143 144 /* 145 * Load the stream structure for the next traversal. Since we don't 146 * actually enter the directory until after the preorder visit, set 147 * the fts_accpath field specially so the chdir gets done to the right 148 * place and the user can access the first node. 149 */ 150 len = p->fts_pathlen = p->fts_namelen; 151 bcopy(p->fts_name, sp->fts_path, len + 1); 152 if ((cp = rindex(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { 153 len = strlen(++cp); 154 bcopy(cp, p->fts_name, len + 1); 155 p->fts_namelen = len; 156 } 157 p->fts_accpath = p->fts_path = sp->fts_path; 158 159 p->fts_info = fts_stat(sp, p, 0); 160 sp->rdev = p->fts_statb.st_dev; 161 } 162 163 fts_close(sp) 164 FTS *sp; 165 { 166 register FTSENT *freep, *p; 167 int saved_errno; 168 169 if (sp->fts_cur) { 170 /* 171 * This still works if we haven't read anything -- the dummy 172 * structure points to the root list, so we step through to 173 * the end of the root list which has a valid parent pointer. 174 */ 175 for (p = sp->fts_cur; p->fts_level > FTS_ROOTPARENTLEVEL;) { 176 freep = p; 177 p = p->fts_link ? p->fts_link : p->fts_parent; 178 free(freep); 179 } 180 free(p); 181 } 182 183 /* Free up child linked list, sort array, path buffer. */ 184 if (sp->fts_child) 185 fts_lfree(sp->fts_child); 186 if (sp->fts_array) 187 free(sp->fts_array); 188 free(sp->fts_path); 189 190 /* Return to original directory, save errno if necessary. */ 191 if (!ISSET(FTS_NOCHDIR)) { 192 saved_errno = fchdir(sp->fts_rfd) ? errno : 0; 193 (void)close(sp->fts_rfd); 194 } 195 196 /* Free up the stream pointer. */ 197 free(sp); 198 199 /* Set errno and return. */ 200 if (!ISSET(FTS_NOCHDIR) && saved_errno) { 201 errno = saved_errno; 202 return(-1); 203 } 204 return(0); 205 } 206 207 /* 208 * Special case a root of "/" so that slashes aren't appended causing 209 * paths to be written as "//foo". 210 */ 211 #define NAPPEND(p) \ 212 (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ 213 p->fts_path[0] == '/' ? 0 : p->fts_pathlen) 214 215 FTSENT * 216 fts_read(sp) 217 register FTS *sp; 218 { 219 register FTSENT *p, *tmp; 220 register int instr; 221 register char *t; 222 223 /* If finished or unrecoverable error, return NULL. */ 224 if (!sp->fts_cur || ISSET(FTS_STOP)) 225 return(NULL); 226 227 /* Set current node pointer. */ 228 p = sp->fts_cur; 229 230 /* Save and zero out user instructions. */ 231 instr = p->fts_instr; 232 p->fts_instr = FTS_NOINSTR; 233 234 /* Any type of file may be re-visited; re-stat and re-turn. */ 235 if (instr == FTS_AGAIN) { 236 p->fts_info = fts_stat(sp, p, 0); 237 return(p); 238 } 239 240 /* 241 * Following a symlink -- SLNONE test allows application to see 242 * SLNONE and recover. 243 */ 244 if (instr == FTS_FOLLOW && 245 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { 246 p->fts_info = fts_stat(sp, p, 1); 247 return(p); 248 } 249 250 /* Directory in pre-order. */ 251 if (p->fts_info == FTS_D) { 252 /* If skipped or crossed mount point, do post-order visit. */ 253 if (instr == FTS_SKIP || 254 ISSET(FTS_XDEV) && p->fts_statb.st_dev != sp->rdev) { 255 if (sp->fts_child) { 256 fts_lfree(sp->fts_child); 257 sp->fts_child = NULL; 258 } 259 p->fts_info = FTS_DP; 260 return(p); 261 } 262 263 /* 264 * Cd to the subdirectory, reading it if haven't already. If 265 * the read fails for any reason, or the directory is empty, 266 * the fts_info field of the current node is set by fts_build. 267 * If have already read and now fail to chdir, whack the list 268 * to make the names come out right, and set the parent state 269 * so the application will eventually get an error condition. 270 * If haven't read and fail to chdir, check to see if we're 271 * at the root node -- if so, we have to get back or the root 272 * node may be inaccessible. 273 */ 274 if (sp->fts_child) { 275 if (CHDIR(sp, p->fts_accpath)) { 276 p->fts_parent->fts_cderr = errno; 277 for (p = sp->fts_child; p; p = p->fts_link) 278 p->fts_accpath = 279 p->fts_parent->fts_accpath; 280 } 281 } else if (!(sp->fts_child = fts_build(sp, BREAD))) { 282 if ISSET(FTS_STOP) 283 return(NULL); 284 if (p->fts_level == FTS_ROOTLEVEL && 285 FCHDIR(sp, sp->fts_rfd)) { 286 SET(FTS_STOP); 287 return(NULL); 288 } 289 return(p); 290 } 291 p = sp->fts_child; 292 sp->fts_child = NULL; 293 goto name; 294 } 295 296 /* Move to next node on this level. */ 297 next: tmp = p; 298 if (p = p->fts_link) { 299 free(tmp); 300 301 /* If reached the top, load the paths for the next root. */ 302 if (p->fts_level == FTS_ROOTLEVEL) { 303 fts_load(sp, p); 304 return(sp->fts_cur = p); 305 } 306 307 /* User may have called fts_set on the node. */ 308 if (p->fts_instr == FTS_SKIP) 309 goto next; 310 if (p->fts_instr == FTS_FOLLOW) { 311 p->fts_info = fts_stat(sp, p, 1); 312 p->fts_instr = FTS_NOINSTR; 313 } 314 315 name: t = sp->fts_path + NAPPEND(p->fts_parent); 316 *t++ = '/'; 317 bcopy(p->fts_name, t, p->fts_namelen + 1); 318 return(sp->fts_cur = p); 319 } 320 321 /* Move up to the parent node. */ 322 p = tmp->fts_parent; 323 free(tmp); 324 325 if (p->fts_level == FTS_ROOTPARENTLEVEL) { 326 /* 327 * Done; free everything up and set errno to 0 so the user 328 * can distinguish between error and EOF. 329 */ 330 free(p); 331 errno = 0; 332 return(sp->fts_cur = NULL); 333 } 334 335 sp->fts_path[p->fts_pathlen] = '\0'; 336 337 /* 338 * Cd back up to the parent directory. If at a root node, have to cd 339 * back to the original place, otherwise may not be able to access the 340 * original node on post-order. 341 */ 342 if (p->fts_level == FTS_ROOTLEVEL) { 343 if (FCHDIR(sp, sp->fts_rfd)) { 344 SET(FTS_STOP); 345 return(NULL); 346 } 347 } 348 else if (CHDIR(sp, "..")) { 349 SET(FTS_STOP); 350 return(NULL); 351 } 352 353 /* 354 * If had a chdir error when trying to get into the directory, set the 355 * info field to reflect this, and restore errno. The error indicator 356 * has to be reset to 0 so that if the user does an FTS_AGAIN, it all 357 * works. 358 */ 359 if (p->fts_cderr) { 360 errno = p->fts_cderr; 361 p->fts_cderr = 0; 362 p->fts_info = FTS_ERR; 363 } else 364 p->fts_info = FTS_DP; 365 return(sp->fts_cur = p); 366 } 367 368 /* 369 * Fts_set takes the stream as an argument although it's not used in this 370 * implementation; it would be necessary if anyone wanted to add global 371 * semantics to fts using fts_set. An error return is allowed for similar 372 * reasons. 373 */ 374 /* ARGSUSED */ 375 fts_set(sp, p, instr) 376 FTS *sp; 377 FTSENT *p; 378 int instr; 379 { 380 p->fts_instr = instr; 381 return(0); 382 } 383 384 FTSENT * 385 fts_children(sp) 386 register FTS *sp; 387 { 388 register FTSENT *p; 389 int fd; 390 391 /* Set current node pointer. */ 392 p = sp->fts_cur; 393 394 /* 395 * Set errno to 0 so that user can tell the difference between an 396 * error and a directory without entries. If not a directory being 397 * visited in *pre-order*, or we've already had fatal errors, return 398 * immediately. 399 */ 400 errno = 0; 401 if (ISSET(FTS_STOP) || p->fts_info != FTS_D && p->fts_info != FTS_DNR) 402 return(NULL); 403 404 /* Free up any previous child list. */ 405 if (sp->fts_child) 406 fts_lfree(sp->fts_child); 407 408 /* 409 * If using chdir on a relative path and called BEFORE fts_read does 410 * its chdir to the root of a traversal, we can lose -- we need to 411 * chdir into the subdirectory, and we don't know where the current 412 * directory is, so we can't get back so that the upcoming chdir by 413 * fts_read will work. 414 */ 415 if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || 416 ISSET(FTS_NOCHDIR)) 417 return(sp->fts_child = fts_build(sp, BCHILD)); 418 419 if ((fd = open(".", O_RDONLY, 0)) < 0) 420 return(NULL); 421 sp->fts_child = fts_build(sp, BCHILD); 422 if (fchdir(fd)) 423 return(NULL); 424 (void)close(fd); 425 return(sp->fts_child); 426 } 427 428 /* 429 * This is the tricky part -- do not casually change *anything* in here. The 430 * idea is to build the linked list of entries that are used by fts_children 431 * and fts_read. There are lots of special cases. 432 * 433 * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is 434 * set and it's a physical walk (so that symbolic links can't be directories), 435 * we assume that the number of subdirectories in a node is equal to the number 436 * of links to the parent. This allows stat calls to be skipped in any leaf 437 * directories and for any nodes after the directories in the parent node have 438 * been found. This empirically cuts the stat calls by about 2/3. 439 */ 440 #define ISDOT(a) (a[0] == '.' && (!a[1] || a[1] == '.' && !a[2])) 441 442 static FTSENT * 443 fts_build(sp, type) 444 register FTS *sp; 445 int type; 446 { 447 register struct dirent *dp; 448 register FTSENT *p, *head; 449 register int nitems; 450 FTSENT *cur; 451 DIR *dirp; 452 int cderr, descend, len, level, maxlen, nlinks, saved_errno; 453 char *cp; 454 455 /* Set current node pointer. */ 456 cur = sp->fts_cur; 457 458 /* 459 * Open the directory for reading. If this fails, we're done. 460 * If being called from fts_read, set the fts_info field. 461 */ 462 if (!(dirp = opendir(cur->fts_accpath))) { 463 if (type == BREAD) 464 cur->fts_info = FTS_DNR; 465 return(NULL); 466 } 467 468 /* 469 * Nlinks is the number of possible entries of type directory in the 470 * directory if we're cheating on stat calls, 0 if we're not doing 471 * any stat calls at all, -1 if we're doing stats on everything. 472 */ 473 nlinks = 474 ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL) ? 475 cur->fts_statb.st_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2) : -1; 476 477 /* 478 * If we're going to need to stat anything or we want to descend 479 * and stay in the directory, chdir. If this fails we keep going. 480 * We won't be able to stat anything, but we can still return the 481 * names themselves. Note, that since fts_read won't be able to 482 * chdir into the directory, it will have to return different path 483 * names than before, i.e. "a/b" instead of "b". Since the node 484 * has already been visited in pre-order, have to wait until the 485 * post-order visit to return the error. This is all fairly nasty. 486 * If a program needed sorted entries or stat information, they had 487 * better be checking FTS_NS on the returned nodes. 488 */ 489 if (nlinks || type == BREAD) 490 if (FCHDIR(sp, dirfd(dirp))) { 491 if (type == BREAD) 492 cur->fts_cderr = errno; 493 descend = nlinks = 0; 494 cderr = 1; 495 } else { 496 descend = 1; 497 cderr = 0; 498 } 499 else 500 descend = 0; 501 502 /* 503 * Figure out the max file name length that can be stored in the 504 * current path -- the inner loop allocates more path as necessary. 505 * We really wouldn't have to do the maxlen calculations here, we 506 * could do them in fts_read before returning the path, but it's a 507 * lot easier here since the length is part of the dirent structure. 508 * 509 * If not changing directories set a pointer so that we can just 510 * append each new name into the path. 511 */ 512 maxlen = sp->fts_pathlen - cur->fts_pathlen - 1; 513 len = NAPPEND(cur); 514 if (ISSET(FTS_NOCHDIR)) { 515 cp = sp->fts_path + len; 516 *cp++ = '/'; 517 } 518 519 level = cur->fts_level + 1; 520 521 /* Read the directory, attaching each entry to the `link' pointer. */ 522 for (head = NULL, nitems = 0; dp = readdir(dirp);) { 523 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) 524 continue; 525 526 if (!(p = fts_alloc(sp, dp->d_name, (int)dp->d_namlen))) 527 goto mem1; 528 if (dp->d_namlen > maxlen) { 529 if (!fts_path(sp, (int)dp->d_namlen)) { 530 /* 531 * No more memory for path or structures. Save 532 * errno, free up the current structure and the 533 * structures already allocated. 534 */ 535 mem1: saved_errno = errno; 536 if (p) 537 free(p); 538 fts_lfree(head); 539 (void)closedir(dirp); 540 errno = saved_errno; 541 cur->fts_info = FTS_ERR; 542 SET(FTS_STOP); 543 return(NULL); 544 } 545 maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1; 546 } 547 548 p->fts_pathlen = len + dp->d_namlen + 1; 549 p->fts_parent = sp->fts_cur; 550 p->fts_level = level; 551 552 if (nlinks) { 553 /* Build a file name for fts_stat to stat. */ 554 if (ISSET(FTS_NOCHDIR)) { 555 p->fts_accpath = p->fts_path; 556 bcopy(p->fts_name, cp, p->fts_namelen + 1); 557 } else 558 p->fts_accpath = p->fts_name; 559 p->fts_info = fts_stat(sp, p, 0); 560 if (nlinks > 0 && p->fts_info == FTS_D) 561 --nlinks; 562 } else if (cderr) { 563 p->fts_info = ISSET(FTS_NOSTAT) ? FTS_NSOK : FTS_NS; 564 p->fts_accpath = cur->fts_accpath; 565 } else { 566 p->fts_accpath = 567 ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; 568 p->fts_info = FTS_NSOK; 569 } 570 571 p->fts_link = head; 572 head = p; 573 ++nitems; 574 } 575 (void)closedir(dirp); 576 577 /* 578 * If not changing directories, reset the path back to original 579 * state. 580 */ 581 if (ISSET(FTS_NOCHDIR)) { 582 if (cp - 1 > sp->fts_path) 583 --cp; 584 *cp = '\0'; 585 } 586 587 /* 588 * If descended after called from fts_children or called from 589 * fts_read and didn't find anything, get back. If can't get 590 * back, we're done. 591 */ 592 if (descend && (!nitems || type == BCHILD) && CHDIR(sp, "..")) { 593 cur->fts_info = FTS_ERR; 594 SET(FTS_STOP); 595 return(NULL); 596 } 597 598 /* If we didn't find anything, just do the post-order visit */ 599 if (!nitems) { 600 if (type == BREAD) 601 cur->fts_info = FTS_DP; 602 return(NULL); 603 } 604 605 /* Sort the entries. */ 606 if (sp->fts_compar && nitems > 1) 607 head = fts_sort(sp, head, nitems); 608 return(head); 609 } 610 611 static u_short 612 fts_stat(sp, p, follow) 613 FTS *sp; 614 register FTSENT *p; 615 int follow; 616 { 617 int saved_errno; 618 619 /* 620 * If doing a logical walk, or application requested FTS_FOLLOW, do 621 * a stat(2). If that fails, check for a non-existent symlink. If 622 * fail, return the errno from the stat call. 623 */ 624 if (ISSET(FTS_LOGICAL) || follow) { 625 if (stat(p->fts_accpath, &p->fts_statb)) { 626 saved_errno = errno; 627 if (!lstat(p->fts_accpath, &p->fts_statb)) { 628 errno = 0; 629 return(FTS_SLNONE); 630 } 631 errno = saved_errno; 632 bzero(&p->fts_statb, sizeof(struct stat)); 633 return(FTS_NS); 634 } 635 } else if (lstat(p->fts_accpath, &p->fts_statb)) { 636 bzero(&p->fts_statb, sizeof(struct stat)); 637 return(FTS_NS); 638 } 639 640 /* 641 * Cycle detection is done as soon as we find a directory. Detection 642 * is by brute force; if the tree gets deep enough or the number of 643 * symbolic links to directories high enough something faster might 644 * be worthwhile. 645 */ 646 if (S_ISDIR(p->fts_statb.st_mode)) { 647 register FTSENT *t; 648 register dev_t dev; 649 register ino_t ino; 650 651 dev = p->fts_statb.st_dev; 652 ino = p->fts_statb.st_ino; 653 for (t = p->fts_parent; t->fts_level >= FTS_ROOTLEVEL; 654 t = t->fts_parent) 655 if (ino == t->fts_statb.st_ino && 656 dev == t->fts_statb.st_dev) { 657 p->fts_cycle = t; 658 return(FTS_DC); 659 } 660 return(FTS_D); 661 } 662 if (S_ISLNK(p->fts_statb.st_mode)) 663 return(FTS_SL); 664 if (S_ISREG(p->fts_statb.st_mode)) 665 return(FTS_F); 666 return(FTS_DEFAULT); 667 } 668 669 #define R(type, nelem, ptr) \ 670 (type *)realloc((void *)ptr, (u_int)((nelem) * sizeof(type))) 671 672 static FTSENT * 673 fts_sort(sp, head, nitems) 674 FTS *sp; 675 FTSENT *head; 676 register int nitems; 677 { 678 register FTSENT **ap, *p; 679 680 /* 681 * Construct an array of pointers to the structures and call qsort(3). 682 * Reassemble the array in the order returned by qsort. If unable to 683 * sort for memory reasons, return the directory entries in their 684 * current order. Allocate enough space for the current needs plus 685 * 40 so we don't realloc one entry at a time. 686 */ 687 if (nitems > sp->fts_nitems) { 688 sp->fts_nitems = nitems + 40; 689 if (!(sp->fts_array = 690 R(FTSENT *, sp->fts_nitems, sp->fts_array))) { 691 sp->fts_nitems = 0; 692 return(head); 693 } 694 } 695 for (ap = sp->fts_array, p = head; p; p = p->fts_link) 696 *ap++ = p; 697 qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); 698 for (head = *(ap = sp->fts_array); --nitems; ++ap) 699 ap[0]->fts_link = ap[1]; 700 ap[0]->fts_link = NULL; 701 return(head); 702 } 703 704 static FTSENT * 705 fts_alloc(sp, name, len) 706 FTS *sp; 707 char *name; 708 register int len; 709 { 710 register FTSENT *p; 711 712 /* 713 * Variable sized structures; the name is the last element so 714 * we allocate enough extra space after the structure to store 715 * it. 716 */ 717 if (!(p = (FTSENT *)malloc((size_t)(sizeof(FTSENT) + len)))) 718 return(NULL); 719 bcopy(name, p->fts_name, len + 1); 720 p->fts_namelen = len; 721 p->fts_path = sp->fts_path; 722 p->fts_instr = FTS_NOINSTR; 723 p->fts_cderr = 0; 724 p->fts_number = 0; 725 p->fts_pointer = NULL; 726 return(p); 727 } 728 729 static void 730 fts_lfree(head) 731 register FTSENT *head; 732 { 733 register FTSENT *p; 734 735 /* Free a linked list of structures. */ 736 while (p = head) { 737 head = head->fts_link; 738 free(p); 739 } 740 } 741 742 /* 743 * Allow essentially unlimited paths; certain programs (find, rm, ls) need to 744 * work on any tree. Most systems will allow creation of paths much longer 745 * than MAXPATHLEN, even though the kernel won't resolve them. Add an extra 746 * 128 bytes to the requested size so that we don't realloc the path 2 bytes 747 * at a time. 748 */ 749 static char * 750 fts_path(sp, size) 751 FTS *sp; 752 int size; 753 { 754 sp->fts_pathlen += size + 128; 755 return(sp->fts_path = R(char, sp->fts_pathlen, sp->fts_path)); 756 } 757