|
rpm
5.4.4
|
00001 /*@-dependenttrans -nullpass -retalias -usereleased @*/ 00002 /*- 00003 * Copyright (c) 1990, 1993, 1994 00004 * The Regents of the University of California. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 4. Neither the name of the University nor the names of its contributors 00015 * may be used to endorse or promote products derived from this software 00016 * without specific prior written permission. 00017 * 00018 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 00019 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00021 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 00022 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00023 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00024 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00025 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00026 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00027 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00028 * SUCH DAMAGE. 00029 */ 00030 00031 #include "system.h" 00032 00033 #if defined(LIBC_SCCS) && !defined(lint) 00034 static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; 00035 #endif /* LIBC_SCCS and not lint */ 00036 00037 #if defined(_LIBC) 00038 #include <sys/param.h> 00039 #include <include/sys/stat.h> 00040 #include <fcntl.h> 00041 #include <dirent.h> 00042 #include <errno.h> 00043 #include <fts.h> 00044 #include <stdlib.h> 00045 #include <string.h> 00046 #include <unistd.h> 00047 #else 00048 #if defined(__UCLIBC__) 00049 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00050 #endif 00051 #if defined(hpux) || defined(__hpux) 00052 # define _INCLUDE_POSIX_SOURCE 00053 # define __errno_location() (&errno) 00054 # define dirfd(dirp) -1 00055 # define stat64 stat 00056 # define _STAT_VER 0 00057 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00058 # define _D_EXACT_NAMLEN(d) ((d)->d_namlen) 00059 #endif 00060 #if defined(sun) || defined(RPM_OS_UNIXWARE) 00061 # define __errno_location() (&errno) 00062 # define dirfd(dirp) -1 00063 # define _STAT_VER 0 00064 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00065 #endif 00066 #if defined(__APPLE__) 00067 # include <sys/stat.h> 00068 # define __errno_location() (__error()) 00069 #ifndef __DARWIN_STRUCT_STAT64 00070 # define stat64 stat 00071 #endif 00072 # define _STAT_VER 0 00073 #ifndef __DARWIN_STRUCT_STAT64 00074 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00075 #else 00076 # define __fxstat64(_stat_ver, _fd, _sbp) fstat64((_fd), (_sbp)) 00077 #endif 00078 #endif 00079 #if defined(__CYGWIN__) || defined(__MINGW32__) 00080 # include <sys/stat.h> 00081 #if defined(__CYGWIN__) 00082 # define __errno_location() (__errno()) 00083 #elif !defined(_UWIN) 00084 # define __errno_location() (_errno()) 00085 #else 00086 # define __errno_location() (&errno) 00087 #endif 00088 # define stat64 stat 00089 # define _STAT_VER 0 00090 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00091 #endif 00092 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 00093 # define __errno_location() (&errno) 00094 # define stat64 stat 00095 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00096 # define _D_EXACT_NAMLEN(d) ((d)->d_namlen) 00097 #endif 00098 #if defined(__osf__) 00099 # define __errno_location() (&errno) 00100 # define dirfd(dirp) -1 00101 # define stat64 stat 00102 # define _STAT_VER 0 00103 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00104 # define _D_EXACT_NAMLEN(d) ((d)->d_namlen) 00105 #endif 00106 #if defined(RPM_OS_IRIX) 00107 # define __errno_location() (&errno) 00108 # define dirfd(dirp) -1 00109 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00110 # define _D_EXACT_NAMLEN(d) ((d)->d_reclen) 00111 #endif 00112 #if defined(RPM_OS_AIX) 00113 # define __errno_location() (&errno) 00114 # define dirfd(dirp) ((dirp)->dd_fd) 00115 # define _STAT_VER 0 00116 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00117 # define _D_EXACT_NAMLEN(d) ((d)->d_namlen) 00118 #endif 00119 #if defined(RPM_OS_NTOQNX) 00120 # define __errno_location() (&errno) 00121 # define stat64 stat 00122 # define _STAT_VER 0 00123 # define dirfd(dirp) -1 00124 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp)) 00125 #endif 00126 00127 #if !defined(_D_EXACT_NAMLEN) 00128 # define _D_EXACT_NAMLEN(d) (strlen((d)->d_name)) 00129 #endif 00130 00131 #include "fts.h" 00132 #include <rpmio.h> 00133 #include <rpmurl.h> 00134 #include <rpmdir.h> 00135 00136 #include "debug.h" 00137 00138 # define __set_errno(val) (*__errno_location ()) = (val) 00139 # define __open open 00140 # define __close close 00141 # define __fchdir fchdir 00142 #endif /* defined(_LIBC) */ 00143 00144 #if !defined(USHRT_MAX) 00145 #define USHRT_MAX 65535 00146 #endif 00147 00148 /* Largest alignment size needed, minus one. 00149 Usually long double is the worst case. */ 00150 #ifndef ALIGNBYTES 00151 #if defined __GNUC__ && __GNUC__ >= 2 00152 # define alignof(TYPE) __alignof__ (TYPE) 00153 #else 00154 # define alignof(TYPE) \ 00155 ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2) 00156 #endif 00157 #define ALIGNBYTES (alignof(long double) - 1) 00158 #endif 00159 /* Align P to that size. */ 00160 #ifndef ALIGN 00161 #define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES) 00162 #endif 00163 00164 /*@unchecked@*/ 00165 int _fts_debug = 0; 00166 00167 /*@only@*/ /*@null@*/ 00168 static FTSENT * fts_alloc(FTS * sp, const char * name, int namelen) 00169 /*@*/; 00170 /*@null@*/ 00171 static FTSENT * fts_build(FTS * sp, int type) 00172 /*@globals fileSystem, internalState @*/ 00173 /*@modifies *sp, fileSystem, internalState @*/; 00174 static void fts_lfree(/*@only@*/ FTSENT * head) 00175 /*@modifies head @*/; 00176 static void fts_load(FTS * sp, FTSENT * p) 00177 /*@modifies *sp, *p @*/; 00178 static size_t fts_maxarglen(char * const * argv) 00179 /*@*/; 00180 static void fts_padjust(FTS * sp, FTSENT * head) 00181 /*@modifies *sp, *head @*/; 00182 static int fts_palloc(FTS * sp, size_t more) 00183 /*@modifies *sp @*/; 00184 static FTSENT * fts_sort(FTS * sp, /*@returned@*/ FTSENT * head, int nitems) 00185 /*@modifies *sp @*/; 00186 static u_short fts_stat(FTS * sp, FTSENT * p, int follow) 00187 /*@modifies *p @*/; 00188 static int fts_safe_changedir(FTS * sp, FTSENT * p, int fd, 00189 const char * path) 00190 /*@globals fileSystem, internalState @*/ 00191 /*@modifies fileSystem, internalState @*/; 00192 00193 #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '/' && !a[2]) || (a[1] == '.' && (!a[2] || (a[2] == '/' && !a[3]))))) 00194 00195 #define CLR(opt) (sp->fts_options &= ~(opt)) 00196 #define ISSET(opt) (sp->fts_options & (opt)) 00197 #define SET(opt) (sp->fts_options |= (opt)) 00198 00199 #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && __fchdir(fd)) 00200 00201 /* fts_build flags */ 00202 #define BCHILD 1 /* fts_children */ 00203 #define BNAMES 2 /* fts_children, names only */ 00204 #define BREAD 3 /* fts_read */ 00205 00206 FTS * 00207 Fts_open(char * const * argv, int options, 00208 int (*compar) (const FTSENT **, const FTSENT **)) 00209 { 00210 register FTS *sp; 00211 register FTSENT *p, *root; 00212 register int nitems; 00213 FTSENT *parent = NULL; 00214 FTSENT *tmp = NULL; 00215 size_t len; 00216 00217 /*@-formattype -modfilesys@*/ 00218 if (_fts_debug) 00219 fprintf(stderr, "--> Fts_open(%p, 0x%x, %p) av[0] %s\n", argv, options, compar, argv[0]); 00220 /*@=formattype =modfilesys@*/ 00221 00222 /* Options check. */ 00223 if (options & ~FTS_OPTIONMASK) { 00224 /*@-sysunrecog@*/ 00225 __set_errno (EINVAL); 00226 /*@=sysunrecog@*/ 00227 return (NULL); 00228 } 00229 00230 /* Allocate/initialize the stream */ 00231 if ((sp = malloc((u_int)sizeof(*sp))) == NULL) 00232 return (NULL); 00233 memset(sp, 0, sizeof(*sp)); 00234 sp->fts_compar = (int (*) (const void *, const void *)) compar; 00235 sp->fts_opendir = Opendir; 00236 sp->fts_readdir = Readdir; 00237 sp->fts_closedir = Closedir; 00238 sp->fts_stat = Stat; 00239 sp->fts_lstat = Lstat; 00240 sp->fts_options = options; 00241 00242 /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ 00243 if (ISSET(FTS_LOGICAL)) 00244 SET(FTS_NOCHDIR); 00245 00246 /* 00247 * Start out with 1K of path space, and enough, in any case, 00248 * to hold the user's paths. 00249 */ 00250 #ifndef MAXPATHLEN 00251 #define MAXPATHLEN 1024 00252 #endif 00253 len = fts_maxarglen(argv); 00254 if (len < MAXPATHLEN) 00255 len = MAXPATHLEN; 00256 if (fts_palloc(sp, len)) 00257 goto mem1; 00258 00259 /* Allocate/initialize root's parent. */ 00260 if (*argv != NULL) { 00261 if ((parent = fts_alloc(sp, "", 0)) == NULL) 00262 goto mem2; 00263 parent->fts_level = FTS_ROOTPARENTLEVEL; 00264 } 00265 00266 /* Allocate/initialize root(s). */ 00267 for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { 00268 /* Don't allow zero-length paths. */ 00269 if ((len = strlen(*argv)) == 0) { 00270 __set_errno (ENOENT); 00271 goto mem3; 00272 } 00273 00274 /* Use fchdir(2) speedup only if local DASDI. */ 00275 switch (urlIsURL(*argv)) { 00276 case URL_IS_DASH: 00277 case URL_IS_HKP: 00278 case URL_IS_MONGO: /* XXX FIXME */ 00279 __set_errno (ENOENT); 00280 goto mem3; 00281 /*@notreached@*/ /*@switchbreak@*/ break; 00282 case URL_IS_HTTPS: 00283 case URL_IS_HTTP: 00284 case URL_IS_FTP: 00285 SET(FTS_NOCHDIR); 00286 /*@switchbreak@*/ break; 00287 case URL_IS_UNKNOWN: 00288 case URL_IS_PATH: 00289 /*@switchbreak@*/ break; 00290 } 00291 00292 p = fts_alloc(sp, *argv, (int)len); 00293 if (p == NULL) 00294 goto mem3; 00295 p->fts_level = FTS_ROOTLEVEL; 00296 p->fts_parent = parent; 00297 p->fts_accpath = p->fts_name; 00298 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); 00299 00300 /* Command-line "." and ".." are real directories. */ 00301 if (p->fts_info == FTS_DOT) 00302 p->fts_info = FTS_D; 00303 00304 /* 00305 * If comparison routine supplied, traverse in sorted 00306 * order; otherwise traverse in the order specified. 00307 */ 00308 if (compar) { 00309 p->fts_link = root; 00310 root = p; 00311 } else { 00312 p->fts_link = NULL; 00313 if (root == NULL) 00314 tmp = root = p; 00315 else { 00316 if (tmp != NULL) /* XXX can't happen */ 00317 tmp->fts_link = p; 00318 tmp = p; 00319 } 00320 } 00321 } 00322 if (compar && nitems > 1) 00323 root = fts_sort(sp, root, nitems); 00324 00325 /* 00326 * Allocate a dummy pointer and make fts_read think that we've just 00327 * finished the node before the root(s); set p->fts_info to FTS_INIT 00328 * so that everything about the "current" node is ignored. 00329 */ 00330 if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) 00331 goto mem3; 00332 sp->fts_cur->fts_link = root; 00333 sp->fts_cur->fts_info = FTS_INIT; 00334 00335 /* 00336 * If using chdir(2), grab a file descriptor pointing to dot to ensure 00337 * that we can get back here; this could be avoided for some paths, 00338 * but almost certainly not worth the effort. Slashes, symbolic links, 00339 * and ".." are all fairly nasty problems. Note, if we can't get the 00340 * descriptor we run anyway, just more slowly. 00341 */ 00342 if (!ISSET(FTS_NOCHDIR) 00343 && (sp->fts_rfd = __open(".", O_RDONLY, 0)) < 0) 00344 SET(FTS_NOCHDIR); 00345 00346 return (sp); 00347 00348 mem3: fts_lfree(root); 00349 free(parent); 00350 mem2: free(sp->fts_path); 00351 mem1: free(sp); 00352 return (NULL); 00353 } 00354 00355 static void 00356 fts_load(FTS * sp, FTSENT * p) 00357 { 00358 register size_t len; 00359 register char *cp; 00360 00361 /* 00362 * Load the stream structure for the next traversal. Since we don't 00363 * actually enter the directory until after the preorder visit, set 00364 * the fts_accpath field specially so the chdir gets done to the right 00365 * place and the user can access the first node. From fts_open it's 00366 * known that the path will fit. 00367 */ 00368 len = p->fts_pathlen = p->fts_namelen; 00369 memmove(sp->fts_path, p->fts_name, len + 1); 00370 if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { 00371 len = strlen(++cp); 00372 memmove(p->fts_name, cp, len + 1); 00373 p->fts_namelen = (u_short)len; 00374 } 00375 p->fts_accpath = p->fts_path = sp->fts_path; 00376 sp->fts_dev = p->fts_dev; 00377 } 00378 00379 int 00380 Fts_close(FTS * sp) 00381 { 00382 register FTSENT *freep, *p; 00383 int saved_errno; 00384 00385 if (_fts_debug) 00386 fprintf(stderr, "--> Fts_close(%p)\n", sp); 00387 00388 if (sp == NULL) 00389 return 0; 00390 00391 /* 00392 * This still works if we haven't read anything -- the dummy structure 00393 * points to the root list, so we step through to the end of the root 00394 * list which has a valid parent pointer. 00395 */ 00396 if (sp->fts_cur) { 00397 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { 00398 freep = p; 00399 p = p->fts_link != NULL ? p->fts_link : p->fts_parent; 00400 free(freep); 00401 } 00402 free(p); 00403 } 00404 00405 /* Free up child linked list, sort array, path buffer. */ 00406 if (sp->fts_child) 00407 fts_lfree(sp->fts_child); 00408 if (sp->fts_array) 00409 free(sp->fts_array); 00410 free(sp->fts_path); 00411 00412 /* Return to original directory, save errno if necessary. */ 00413 if (!ISSET(FTS_NOCHDIR)) { 00414 saved_errno = __fchdir(sp->fts_rfd) ? errno : 0; 00415 (void)__close(sp->fts_rfd); 00416 00417 /* Set errno and return. */ 00418 if (saved_errno != 0) { 00419 /* Free up the stream pointer. */ 00420 free(sp); 00421 __set_errno (saved_errno); 00422 return (-1); 00423 } 00424 } 00425 00426 /* Free up the stream pointer. */ 00427 free(sp); 00428 return (0); 00429 } 00430 00431 static int indent = 2; 00432 00433 static const char * ftsInfoStrings[] = { 00434 "UNKNOWN", 00435 "D", 00436 "DC", 00437 "DEFAULT", 00438 "DNR", 00439 "DOT", 00440 "DP", 00441 "ERR", 00442 "F", 00443 "INIT", 00444 "NS", 00445 "NSOK", 00446 "SL", 00447 "SLNONE", 00448 "W", 00449 }; 00450 00451 static const char * ftsInfoStr(int fts_info) 00452 { 00453 if (!(fts_info >= 1 && fts_info <= 14)) 00454 fts_info = 0; 00455 return ftsInfoStrings[ fts_info ]; 00456 } 00457 00458 /* 00459 * Special case of "/" at the end of the path so that slashes aren't 00460 * appended which would cause paths to be written as "....//foo". 00461 */ 00462 #define NAPPEND(p) \ 00463 (p->fts_path[p->fts_pathlen - 1] == '/' \ 00464 ? p->fts_pathlen - 1 : p->fts_pathlen) 00465 00466 FTSENT * 00467 Fts_read(FTS * sp) 00468 { 00469 register FTSENT *p; 00470 register FTSENT *tmp; 00471 register int instr; 00472 register char *t; 00473 int saved_errno; 00474 00475 if (_fts_debug) 00476 fprintf(stderr, "--> Fts_read(%p)\n", sp); 00477 /* If finished or unrecoverable error, return NULL. */ 00478 if (sp == NULL || sp->fts_cur == NULL || ISSET(FTS_STOP)) { 00479 p = NULL; 00480 goto exit; 00481 } 00482 00483 /* Set current node pointer. */ 00484 p = sp->fts_cur; 00485 00486 /* Save and zero out user instructions. */ 00487 instr = p->fts_instr; 00488 p->fts_instr = FTS_NOINSTR; 00489 00490 /* Any type of file may be re-visited; re-stat and re-turn. */ 00491 if (instr == FTS_AGAIN) { 00492 p->fts_info = fts_stat(sp, p, 0); 00493 goto exit; 00494 } 00495 00496 /* 00497 * Following a symlink -- SLNONE test allows application to see 00498 * SLNONE and recover. If indirecting through a symlink, have 00499 * keep a pointer to current location. If unable to get that 00500 * pointer, follow fails. 00501 */ 00502 if (instr == FTS_FOLLOW && 00503 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { 00504 p->fts_info = fts_stat(sp, p, 1); 00505 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 00506 if ((p->fts_symfd = __open(".", O_RDONLY, 0)) < 0) { 00507 p->fts_errno = errno; 00508 p->fts_info = FTS_ERR; 00509 } else 00510 p->fts_flags |= FTS_SYMFOLLOW; 00511 } 00512 goto exit; 00513 } 00514 00515 /* Directory in pre-order. */ 00516 if (p->fts_info == FTS_D) { 00517 /* If skipped or crossed mount point, do post-order visit. */ 00518 if (instr == FTS_SKIP || 00519 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { 00520 if (p->fts_flags & FTS_SYMFOLLOW) { 00521 (void)__close(p->fts_symfd); 00522 p->fts_symfd = -1; 00523 } 00524 if (sp->fts_child) { 00525 fts_lfree(sp->fts_child); 00526 sp->fts_child = NULL; 00527 } 00528 p->fts_info = FTS_DP; 00529 goto exit; 00530 } 00531 00532 /* Rebuild if only read the names and now traversing. */ 00533 if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { 00534 CLR(FTS_NAMEONLY); 00535 fts_lfree(sp->fts_child); 00536 sp->fts_child = NULL; 00537 } 00538 00539 /* 00540 * Cd to the subdirectory. 00541 * 00542 * If have already read and now fail to chdir, whack the list 00543 * to make the names come out right, and set the parent errno 00544 * so the application will eventually get an error condition. 00545 * Set the FTS_DONTCHDIR flag so that when we logically change 00546 * directories back to the parent we don't do a chdir. 00547 * 00548 * If haven't read do so. If the read fails, fts_build sets 00549 * FTS_STOP or the fts_info field of the node. 00550 */ 00551 if (sp->fts_child != NULL) { 00552 if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { 00553 p->fts_errno = errno; 00554 p->fts_flags |= FTS_DONTCHDIR; 00555 for (p = sp->fts_child; p != NULL; 00556 p = p->fts_link) 00557 p->fts_accpath = 00558 p->fts_parent->fts_accpath; 00559 } 00560 } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { 00561 if (ISSET(FTS_STOP)) { 00562 p = NULL; 00563 goto exit; 00564 } 00565 goto exit; 00566 } 00567 p = sp->fts_child; 00568 sp->fts_child = NULL; 00569 sp->fts_cur = p; 00570 goto name; 00571 } 00572 00573 /* Move to the next node on this level. */ 00574 next: tmp = p; 00575 if ((p = p->fts_link) != NULL) { 00576 sp->fts_cur = p; 00577 free(tmp); 00578 00579 /* 00580 * If reached the top, return to the original directory (or 00581 * the root of the tree), and load the paths for the next root. 00582 */ 00583 if (p->fts_level == FTS_ROOTLEVEL) { 00584 if (FCHDIR(sp, sp->fts_rfd)) { 00585 SET(FTS_STOP); 00586 p = NULL; 00587 goto exit; 00588 } 00589 fts_load(sp, p); 00590 goto exit; 00591 } 00592 00593 /* 00594 * User may have called fts_set on the node. If skipped, 00595 * ignore. If followed, get a file descriptor so we can 00596 * get back if necessary. 00597 */ 00598 if (p->fts_instr == FTS_SKIP) 00599 goto next; 00600 if (p->fts_instr == FTS_FOLLOW) { 00601 p->fts_info = fts_stat(sp, p, 1); 00602 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 00603 if ((p->fts_symfd = 00604 __open(".", O_RDONLY, 0)) < 0) { 00605 p->fts_errno = errno; 00606 p->fts_info = FTS_ERR; 00607 } else 00608 p->fts_flags |= FTS_SYMFOLLOW; 00609 } 00610 p->fts_instr = FTS_NOINSTR; 00611 } 00612 00613 name: t = sp->fts_path + NAPPEND(p->fts_parent); 00614 *t++ = '/'; 00615 memmove(t, p->fts_name, p->fts_namelen + 1); 00616 goto exit; 00617 } 00618 00619 /* Move up to the parent node. */ 00620 p = tmp->fts_parent; 00621 sp->fts_cur = p; 00622 free(tmp); 00623 00624 if (p->fts_level == FTS_ROOTPARENTLEVEL) { 00625 /* 00626 * Done; free everything up and set errno to 0 so the user 00627 * can distinguish between error and EOF. 00628 */ 00629 free(p); 00630 __set_errno (0); 00631 sp->fts_cur = p = NULL; 00632 goto exit; 00633 } 00634 00635 /* NUL terminate the pathname. */ 00636 sp->fts_path[p->fts_pathlen] = '\0'; 00637 00638 /* 00639 * Return to the parent directory. If at a root node or came through 00640 * a symlink, go back through the file descriptor. Otherwise, cd up 00641 * one directory. 00642 */ 00643 if (p->fts_level == FTS_ROOTLEVEL) { 00644 if (FCHDIR(sp, sp->fts_rfd)) { 00645 SET(FTS_STOP); 00646 p = NULL; 00647 goto exit; 00648 } 00649 } else if (p->fts_flags & FTS_SYMFOLLOW) { 00650 if (FCHDIR(sp, p->fts_symfd)) { 00651 saved_errno = errno; 00652 (void)__close(p->fts_symfd); 00653 p->fts_symfd = -1; 00654 __set_errno (saved_errno); 00655 SET(FTS_STOP); 00656 p = NULL; 00657 goto exit; 00658 } 00659 (void)__close(p->fts_symfd); 00660 p->fts_symfd = -1; 00661 } else if (!(p->fts_flags & FTS_DONTCHDIR) && 00662 fts_safe_changedir(sp, p->fts_parent, -1, "..")) { 00663 SET(FTS_STOP); 00664 p = NULL; 00665 goto exit; 00666 } 00667 p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; 00668 00669 exit: 00670 if (_fts_debug) { 00671 fprintf(stderr, "<-- Fts_read(%p) ret %p", sp, p); 00672 if (p) 00673 fprintf(stderr, " FTS_%s\t%*s %s", ftsInfoStr(p->fts_info), 00674 indent * (p->fts_level < 0 ? 0 : p->fts_level), "", 00675 (p->fts_name[0] != '\0' ? p->fts_name : p->fts_path)); 00676 fprintf(stderr, "\n"); 00677 } 00678 return (p); 00679 } 00680 00681 /* 00682 * Fts_set takes the stream as an argument although it's not used in this 00683 * implementation; it would be necessary if anyone wanted to add global 00684 * semantics to fts using fts_set. An error return is allowed for similar 00685 * reasons. 00686 */ 00687 int 00688 Fts_set(/*@unused@*/ FTS * sp, FTSENT * p, int instr) 00689 { 00690 /*@-modfilesys@*/ 00691 if (_fts_debug) 00692 fprintf(stderr, "--> Fts_set(%p, %p, 0x%x)\n", sp, p, instr); 00693 /*@=modfilesys@*/ 00694 00695 if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && 00696 instr != FTS_NOINSTR && instr != FTS_SKIP) { 00697 __set_errno (EINVAL); 00698 return (1); 00699 } 00700 p->fts_instr = instr; 00701 return (0); 00702 } 00703 00704 FTSENT * 00705 Fts_children(FTS * sp, int instr) 00706 { 00707 register FTSENT *p; 00708 int fd; 00709 00710 /*@-modfilesys@*/ 00711 if (_fts_debug) 00712 fprintf(stderr, "--> Fts_children(%p, 0x%x)\n", sp, instr); 00713 /*@=modfilesys@*/ 00714 00715 if (instr != 0 && instr != FTS_NAMEONLY) { 00716 __set_errno (EINVAL); 00717 return (NULL); 00718 } 00719 00720 /* Set current node pointer. */ 00721 p = sp->fts_cur; 00722 00723 /* 00724 * Errno set to 0 so user can distinguish empty directory from 00725 * an error. 00726 */ 00727 __set_errno (0); 00728 00729 /* Fatal errors stop here. */ 00730 if (ISSET(FTS_STOP)) 00731 return (NULL); 00732 00733 /* Return logical hierarchy of user's arguments. */ 00734 if (p->fts_info == FTS_INIT) 00735 return (p->fts_link); 00736 00737 /* 00738 * If not a directory being visited in pre-order, stop here. Could 00739 * allow FTS_DNR, assuming the user has fixed the problem, but the 00740 * same effect is available with FTS_AGAIN. 00741 */ 00742 if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) 00743 return (NULL); 00744 00745 /* Free up any previous child list. */ 00746 if (sp->fts_child != NULL) 00747 fts_lfree(sp->fts_child); 00748 00749 if (instr == FTS_NAMEONLY) { 00750 SET(FTS_NAMEONLY); 00751 instr = BNAMES; 00752 } else 00753 instr = BCHILD; 00754 00755 /* 00756 * If using chdir on a relative path and called BEFORE fts_read does 00757 * its chdir to the root of a traversal, we can lose -- we need to 00758 * chdir into the subdirectory, and we don't know where the current 00759 * directory is, so we can't get back so that the upcoming chdir by 00760 * fts_read will work. 00761 */ 00762 if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || 00763 ISSET(FTS_NOCHDIR)) 00764 return (sp->fts_child = fts_build(sp, instr)); 00765 00766 if ((fd = __open(".", O_RDONLY, 0)) < 0) 00767 return (NULL); 00768 sp->fts_child = fts_build(sp, instr); 00769 if (__fchdir(fd)) 00770 return (NULL); 00771 (void)__close(fd); 00772 return (sp->fts_child); 00773 } 00774 00775 /* 00776 * This is the tricky part -- do not casually change *anything* in here. The 00777 * idea is to build the linked list of entries that are used by fts_children 00778 * and fts_read. There are lots of special cases. 00779 * 00780 * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is 00781 * set and it's a physical walk (so that symbolic links can't be directories), 00782 * we can do things quickly. First, if it's a 4.4BSD file system, the type 00783 * of the file is in the directory entry. Otherwise, we assume that the number 00784 * of subdirectories in a node is equal to the number of links to the parent. 00785 * The former skips all stat calls. The latter skips stat calls in any leaf 00786 * directories and for any files after the subdirectories in the directory have 00787 * been found, cutting the stat calls by about 2/3. 00788 */ 00789 static FTSENT * 00790 fts_build(FTS * sp, int type) 00791 { 00792 register struct dirent *dp; 00793 register FTSENT *p, *head; 00794 register int nitems; 00795 FTSENT *cur, *tail; 00796 DIR *dirp; 00797 void *oldaddr; 00798 int cderrno, descend, len, level, nlinks, saved_errno, 00799 nostat, doadjust; 00800 size_t maxlen; 00801 char *cp; 00802 00803 /* Set current node pointer. */ 00804 cur = sp->fts_cur; 00805 00806 /* 00807 * Open the directory for reading. If this fails, we're done. 00808 * If being called from fts_read, set the fts_info field. 00809 */ 00810 #if defined FTS_WHITEOUT && 0 00811 if (ISSET(FTS_WHITEOUT)) 00812 oflag = DTF_NODUP|DTF_REWIND; 00813 else 00814 oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; 00815 #else 00816 # define __opendir2(path, flag) (*sp->fts_opendir) (path) 00817 #endif 00818 if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { 00819 if (type == BREAD) { 00820 cur->fts_info = FTS_DNR; 00821 cur->fts_errno = errno; 00822 } 00823 return (NULL); 00824 } 00825 00826 /* 00827 * Nlinks is the number of possible entries of type directory in the 00828 * directory if we're cheating on stat calls, 0 if we're not doing 00829 * any stat calls at all, -1 if we're doing stats on everything. 00830 */ 00831 if (type == BNAMES) { 00832 nlinks = 0; 00833 /* Be quiet about nostat, GCC. */ 00834 nostat = 0; 00835 } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { 00836 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); 00837 nostat = 1; 00838 } else { 00839 nlinks = -1; 00840 nostat = 0; 00841 } 00842 00843 #ifdef notdef 00844 (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); 00845 (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", 00846 ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); 00847 #endif 00848 /* 00849 * If we're going to need to stat anything or we want to descend 00850 * and stay in the directory, chdir. If this fails we keep going, 00851 * but set a flag so we don't chdir after the post-order visit. 00852 * We won't be able to stat anything, but we can still return the 00853 * names themselves. Note, that since fts_read won't be able to 00854 * chdir into the directory, it will have to return different path 00855 * names than before, i.e. "a/b" instead of "b". Since the node 00856 * has already been visited in pre-order, have to wait until the 00857 * post-order visit to return the error. There is a special case 00858 * here, if there was nothing to stat then it's not an error to 00859 * not be able to stat. This is all fairly nasty. If a program 00860 * needed sorted entries or stat information, they had better be 00861 * checking FTS_NS on the returned nodes. 00862 */ 00863 cderrno = 0; 00864 if (nlinks || type == BREAD) { 00865 /*@-unrecog@*/ 00866 if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { 00867 /*@=unrecog@*/ 00868 if (nlinks && type == BREAD) 00869 cur->fts_errno = errno; 00870 cur->fts_flags |= FTS_DONTCHDIR; 00871 descend = 0; 00872 cderrno = errno; 00873 (void) (*sp->fts_closedir) (dirp); 00874 dirp = NULL; 00875 } else 00876 descend = 1; 00877 } else 00878 descend = 0; 00879 00880 /* 00881 * Figure out the max file name length that can be stored in the 00882 * current path -- the inner loop allocates more path as necessary. 00883 * We really wouldn't have to do the maxlen calculations here, we 00884 * could do them in fts_read before returning the path, but it's a 00885 * lot easier here since the length is part of the dirent structure. 00886 * 00887 * If not changing directories set a pointer so that can just append 00888 * each new name into the path. 00889 */ 00890 len = NAPPEND(cur); 00891 if (ISSET(FTS_NOCHDIR)) { 00892 cp = sp->fts_path + len; 00893 *cp++ = '/'; 00894 } else { 00895 /* GCC, you're too verbose. */ 00896 cp = NULL; 00897 } 00898 len++; 00899 maxlen = sp->fts_pathlen - len; 00900 00901 level = cur->fts_level + 1; 00902 00903 /* Read the directory, attaching each entry to the `link' pointer. */ 00904 doadjust = 0; 00905 for (head = tail = NULL, nitems = 0; 00906 dirp && (dp = (*sp->fts_readdir) (dirp));) 00907 { 00908 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) 00909 continue; 00910 00911 if ((p = fts_alloc(sp, dp->d_name, (int)_D_EXACT_NAMLEN (dp))) == NULL) 00912 goto mem1; 00913 if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */ 00914 oldaddr = sp->fts_path; 00915 if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) { 00916 /* 00917 * No more memory for path or structures. Save 00918 * errno, free up the current structure and the 00919 * structures already allocated. 00920 */ 00921 mem1: saved_errno = errno; 00922 if (p) 00923 free(p); 00924 fts_lfree(head); 00925 (void) (*sp->fts_closedir) (dirp); 00926 cur->fts_info = FTS_ERR; 00927 SET(FTS_STOP); 00928 __set_errno (saved_errno); 00929 return (NULL); 00930 } 00931 /* Did realloc() change the pointer? */ 00932 if (oldaddr != sp->fts_path) { 00933 doadjust = 1; 00934 if (ISSET(FTS_NOCHDIR)) 00935 cp = sp->fts_path + len; 00936 } 00937 maxlen = sp->fts_pathlen - len; 00938 } 00939 00940 if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) { 00941 /* 00942 * In an FTSENT, fts_pathlen is a u_short so it is 00943 * possible to wraparound here. If we do, free up 00944 * the current structure and the structures already 00945 * allocated, then error out with ENAMETOOLONG. 00946 */ 00947 free(p); 00948 fts_lfree(head); 00949 (void) (*sp->fts_closedir) (dirp); 00950 cur->fts_info = FTS_ERR; 00951 SET(FTS_STOP); 00952 __set_errno (ENAMETOOLONG); 00953 return (NULL); 00954 } 00955 p->fts_level = level; 00956 p->fts_parent = sp->fts_cur; 00957 p->fts_pathlen = (u_short)(len + _D_EXACT_NAMLEN (dp)); 00958 00959 #if defined FTS_WHITEOUT && 0 00960 if (dp->d_type == DT_WHT) 00961 p->fts_flags |= FTS_ISW; 00962 #endif 00963 00964 #if 0 00965 /* 00966 * Unreachable code. cderrno is only ever set to a nonnull 00967 * value if dirp is closed at the same time. But then we 00968 * cannot enter this loop. 00969 */ 00970 if (cderrno) { 00971 if (nlinks) { 00972 p->fts_info = FTS_NS; 00973 p->fts_errno = cderrno; 00974 } else 00975 p->fts_info = FTS_NSOK; 00976 p->fts_accpath = cur->fts_accpath; 00977 } else 00978 #endif 00979 if (nlinks == 0 00980 #if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE 00981 || (nostat && 00982 dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) 00983 #endif 00984 ) { 00985 p->fts_accpath = 00986 ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; 00987 p->fts_info = FTS_NSOK; 00988 } else { 00989 /* Build a file name for fts_stat to stat. */ 00990 if (ISSET(FTS_NOCHDIR)) { 00991 p->fts_accpath = p->fts_path; 00992 memmove(cp, p->fts_name, p->fts_namelen + 1); 00993 } else 00994 p->fts_accpath = p->fts_name; 00995 /* Stat it. */ 00996 p->fts_info = fts_stat(sp, p, 0); 00997 00998 /* Decrement link count if applicable. */ 00999 if (nlinks > 0 && (p->fts_info == FTS_D || 01000 p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) 01001 --nlinks; 01002 } 01003 01004 /* We walk in directory order so "ls -f" doesn't get upset. */ 01005 p->fts_link = NULL; 01006 if (head == NULL) 01007 head = tail = p; 01008 else { 01009 tail->fts_link = p; 01010 tail = p; 01011 } 01012 ++nitems; 01013 } 01014 if (dirp) 01015 (void) (*sp->fts_closedir) (dirp); 01016 01017 /* 01018 * If realloc() changed the address of the path, adjust the 01019 * addresses for the rest of the tree and the dir list. 01020 */ 01021 if (doadjust) 01022 fts_padjust(sp, head); 01023 01024 /* 01025 * If not changing directories, reset the path back to original 01026 * state. 01027 */ 01028 if (ISSET(FTS_NOCHDIR)) { 01029 if (len == sp->fts_pathlen || nitems == 0) 01030 --cp; 01031 if (cp != NULL) /* XXX can't happen */ 01032 *cp = '\0'; 01033 } 01034 01035 /* 01036 * If descended after called from fts_children or after called from 01037 * fts_read and nothing found, get back. At the root level we use 01038 * the saved fd; if one of fts_open()'s arguments is a relative path 01039 * to an empty directory, we wind up here with no other way back. If 01040 * can't get back, we're done. 01041 */ 01042 if (descend && (type == BCHILD || !nitems) && 01043 (cur->fts_level == FTS_ROOTLEVEL ? 01044 FCHDIR(sp, sp->fts_rfd) : 01045 fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { 01046 cur->fts_info = FTS_ERR; 01047 SET(FTS_STOP); 01048 fts_lfree(head); 01049 return (NULL); 01050 } 01051 01052 /* If didn't find anything, return NULL. */ 01053 if (!nitems) { 01054 if (type == BREAD) 01055 cur->fts_info = FTS_DP; 01056 fts_lfree(head); 01057 return (NULL); 01058 } 01059 01060 /* Sort the entries. */ 01061 if (sp->fts_compar && nitems > 1) 01062 head = fts_sort(sp, head, nitems); 01063 return (head); 01064 } 01065 01066 static u_short 01067 fts_stat(FTS * sp, FTSENT * p, int follow) 01068 { 01069 register FTSENT *t; 01070 register dev_t dev; 01071 register ino_t ino; 01072 struct stat *sbp, sb; 01073 int saved_errno; 01074 01075 /* If user needs stat info, stat buffer already allocated. */ 01076 sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; 01077 01078 #if defined FTS_WHITEOUT && 0 01079 /* check for whiteout */ 01080 if (p->fts_flags & FTS_ISW) { 01081 if (sbp != &sb) { 01082 memset(sbp, '\0', sizeof (*sbp)); 01083 sbp->st_mode = S_IFWHT; 01084 } 01085 return (FTS_W); 01086 } 01087 #endif 01088 01089 /* 01090 * If doing a logical walk, or application requested FTS_FOLLOW, do 01091 * a stat(2). If that fails, check for a non-existent symlink. If 01092 * fail, set the errno from the stat call. 01093 */ 01094 if (ISSET(FTS_LOGICAL) || follow) { 01095 if ((*sp->fts_stat) (p->fts_accpath, sbp)) { 01096 saved_errno = errno; 01097 if (!(*sp->fts_lstat) (p->fts_accpath, sbp)) { 01098 __set_errno (0); 01099 return (FTS_SLNONE); 01100 } 01101 p->fts_errno = saved_errno; 01102 goto err; 01103 } 01104 } else if ((*sp->fts_lstat) (p->fts_accpath, sbp)) { 01105 p->fts_errno = errno; 01106 err: memset(sbp, 0, sizeof(*sbp)); 01107 return (FTS_NS); 01108 } 01109 01110 if (S_ISDIR(sbp->st_mode)) { 01111 /* 01112 * Set the device/inode. Used to find cycles and check for 01113 * crossing mount points. Also remember the link count, used 01114 * in fts_build to limit the number of stat calls. It is 01115 * understood that these fields are only referenced if fts_info 01116 * is set to FTS_D. 01117 */ 01118 dev = p->fts_dev = sbp->st_dev; 01119 ino = p->fts_ino = sbp->st_ino; 01120 p->fts_nlink = sbp->st_nlink; 01121 01122 if (ISDOT(p->fts_name)) 01123 return (FTS_DOT); 01124 01125 /* 01126 * Cycle detection is done by brute force when the directory 01127 * is first encountered. If the tree gets deep enough or the 01128 * number of symbolic links to directories is high enough, 01129 * something faster might be worthwhile. 01130 */ 01131 for (t = p->fts_parent; 01132 t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) 01133 if (ino == t->fts_ino && dev == t->fts_dev) { 01134 p->fts_cycle = t; 01135 return (FTS_DC); 01136 } 01137 return (FTS_D); 01138 } 01139 if (S_ISLNK(sbp->st_mode)) 01140 return (FTS_SL); 01141 if (S_ISREG(sbp->st_mode)) 01142 return (FTS_F); 01143 return (FTS_DEFAULT); 01144 } 01145 01146 static FTSENT * 01147 fts_sort(FTS * sp, FTSENT * head, int nitems) 01148 { 01149 register FTSENT **ap, *p; 01150 01151 /* 01152 * Construct an array of pointers to the structures and call qsort(3). 01153 * Reassemble the array in the order returned by qsort. If unable to 01154 * sort for memory reasons, return the directory entries in their 01155 * current order. Allocate enough space for the current needs plus 01156 * 40 so don't realloc one entry at a time. 01157 */ 01158 if (nitems > sp->fts_nitems) { 01159 struct _ftsent **a; 01160 01161 sp->fts_nitems = nitems + 40; 01162 if ((a = realloc(sp->fts_array, 01163 (size_t)(sp->fts_nitems * sizeof(*sp->fts_array)))) == NULL) 01164 { 01165 free(sp->fts_array); 01166 sp->fts_array = NULL; 01167 sp->fts_nitems = 0; 01168 return (head); 01169 } 01170 sp->fts_array = a; 01171 } 01172 for (ap = sp->fts_array, p = head; p != NULL; p = p->fts_link) 01173 *ap++ = p; 01174 qsort((void *)sp->fts_array, nitems, sizeof(*sp->fts_array), 01175 sp->fts_compar); 01176 for (head = *(ap = sp->fts_array); --nitems; ++ap) 01177 ap[0]->fts_link = ap[1]; 01178 ap[0]->fts_link = NULL; 01179 return (head); 01180 } 01181 01182 static FTSENT * 01183 fts_alloc(FTS * sp, const char * name, int namelen) 01184 { 01185 register FTSENT *p; 01186 size_t len; 01187 01188 /* 01189 * The file name is a variable length array and no stat structure is 01190 * necessary if the user has set the nostat bit. Allocate the FTSENT 01191 * structure, the file name and the stat structure in one chunk, but 01192 * be careful that the stat structure is reasonably aligned. Since the 01193 * fts_name field is declared to be of size 1, the fts_name pointer is 01194 * namelen + 2 before the first possible address of the stat structure. 01195 */ 01196 len = sizeof(*p) + namelen; 01197 if (!ISSET(FTS_NOSTAT)) 01198 len += sizeof(*p->fts_statp) + ALIGNBYTES; 01199 if ((p = malloc(len)) == NULL) 01200 return (NULL); 01201 memset(p, 0, sizeof(*p)); 01202 p->fts_symfd = -1; 01203 01204 /* Copy the name and guarantee NUL termination. */ 01205 memmove(p->fts_name, name, namelen); 01206 p->fts_name[namelen] = '\0'; 01207 01208 if (!ISSET(FTS_NOSTAT)) 01209 p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); 01210 p->fts_namelen = namelen; 01211 p->fts_path = sp->fts_path; 01212 p->fts_errno = 0; 01213 p->fts_flags = 0; 01214 p->fts_instr = FTS_NOINSTR; 01215 p->fts_number = 0; 01216 p->fts_pointer = NULL; 01217 return (p); 01218 } 01219 01220 static void 01221 fts_lfree(FTSENT * head) 01222 { 01223 register FTSENT *p; 01224 01225 /* Free a linked list of structures. */ 01226 while ((p = head)) { 01227 head = head->fts_link; 01228 free(p); 01229 } 01230 } 01231 01232 /* 01233 * Allow essentially unlimited paths; find, rm, ls should all work on any tree. 01234 * Most systems will allow creation of paths much longer than MAXPATHLEN, even 01235 * though the kernel won't resolve them. Add the size (not just what's needed) 01236 * plus 256 bytes so don't realloc the path 2 bytes at a time. 01237 */ 01238 static int 01239 fts_palloc(FTS * sp, size_t more) 01240 { 01241 char *p; 01242 01243 sp->fts_pathlen += more + 256; 01244 /* 01245 * Check for possible wraparound. In an FTS, fts_pathlen is 01246 * a signed int but in an FTSENT it is an unsigned short. 01247 * We limit fts_pathlen to USHRT_MAX to be safe in both cases. 01248 */ 01249 if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) { 01250 if (sp->fts_path) 01251 free(sp->fts_path); 01252 sp->fts_path = NULL; 01253 __set_errno (ENAMETOOLONG); 01254 return (1); 01255 } 01256 p = realloc(sp->fts_path, sp->fts_pathlen); 01257 if (p == NULL) { 01258 free(sp->fts_path); 01259 sp->fts_path = NULL; 01260 return 1; 01261 } 01262 sp->fts_path = p; 01263 return 0; 01264 } 01265 01266 /* 01267 * When the path is realloc'd, have to fix all of the pointers in structures 01268 * already returned. 01269 */ 01270 static void 01271 fts_padjust(FTS * sp, FTSENT * head) 01272 { 01273 FTSENT *p; 01274 char *addr = sp->fts_path; 01275 01276 #define ADJUST(p) do { \ 01277 if ((p)->fts_accpath != (p)->fts_name) { \ 01278 (p)->fts_accpath = \ 01279 (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ 01280 } \ 01281 (p)->fts_path = addr; \ 01282 } while (0) 01283 /* Adjust the current set of children. */ 01284 for (p = sp->fts_child; p != NULL; p = p->fts_link) 01285 ADJUST(p); 01286 01287 /* Adjust the rest of the tree, including the current level. */ 01288 for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { 01289 ADJUST(p); 01290 p = p->fts_link ? p->fts_link : p->fts_parent; 01291 } 01292 } 01293 01294 static size_t 01295 fts_maxarglen(char * const * argv) 01296 { 01297 size_t len, max; 01298 01299 for (max = 0; *argv; ++argv) 01300 if ((len = strlen(*argv)) > max) 01301 max = len; 01302 return (max + 1); 01303 } 01304 01305 /* 01306 * Change to dir specified by fd or p->fts_accpath without getting 01307 * tricked by someone changing the world out from underneath us. 01308 * Assumes p->fts_dev and p->fts_ino are filled in. 01309 */ 01310 static int 01311 fts_safe_changedir(FTS * sp, FTSENT * p, int fd, const char * path) 01312 { 01313 int ret, oerrno, newfd; 01314 struct stat64 sb; 01315 01316 newfd = fd; 01317 if (ISSET(FTS_NOCHDIR)) 01318 return (0); 01319 01320 /* Permit open(2) on file:// prefixed URI paths. */ 01321 /* XXX todo: use Open(2), which is Chroot(2) path invariant. */ 01322 /* XXX todo: add Fts(3) options to disable the hackery? */ 01323 { const char * lpath = NULL; 01324 int ut = urlPath(path, &lpath); 01325 if (ut == URL_IS_PATH) path = lpath; 01326 } 01327 01328 if (fd < 0 && (newfd = __open(path, O_RDONLY, 0)) < 0) 01329 return (-1); 01330 /*@-sysunrecog -unrecog @*/ 01331 if (__fxstat64(_STAT_VER, newfd, &sb)) { 01332 ret = -1; 01333 goto bail; 01334 } 01335 /*@=sysunrecog =unrecog @*/ 01336 if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { 01337 __set_errno (ENOENT); /* disinformation */ 01338 ret = -1; 01339 goto bail; 01340 } 01341 ret = __fchdir(newfd); 01342 bail: 01343 oerrno = errno; 01344 if (fd < 0) 01345 (void)__close(newfd); 01346 __set_errno (oerrno); 01347 return (ret); 01348 } 01349 /*@=dependenttrans =nullpass =retalias =usereleased @*/
1.7.5.1