Changeset 619
- Timestamp:
- Nov 26, 2006, 7:53:00 AM (19 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gmake/kmkbuiltin/fts.c
r370 r619 1 /* $NetBSD: __fts13.c,v 1.44 2005/01/19 00:59:48 mycroft Exp $ */ 2 1 3 /*- 2 4 * Copyright (c) 1990, 1993, 1994 … … 11 13 * notice, this list of conditions and the following disclaimer in the 12 14 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 15 * 3. Neither the name of the University nor the names of its contributors 18 16 * may be used to endorse or promote products derived from this software 19 17 * without specific prior written permission. … … 30 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 29 * SUCH DAMAGE. 32 *33 * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $34 30 */ 35 31 32 #if HAVE_NBTOOL_CONFIG_H 33 #include "nbtool_config.h" 34 #endif 35 36 #include <sys/cdefs.h> 37 #if defined(LIBC_SCCS) && !defined(lint) 36 38 #if 0 37 #if defined(LIBC_SCCS) && !defined(lint)38 39 static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; 40 #else 41 __RCSID("$NetBSD: __fts13.c,v 1.44 2005/01/19 00:59:48 mycroft Exp $"); 42 #endif 39 43 #endif /* LIBC_SCCS and not lint */ 40 44 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD: src/lib/libc/gen/fts.c,v 1.27 2004/06/08 06:23:23 das Exp $"); 43 #endif 44 45 //#include "namespace.h" 46 #ifndef _MSC_VER 45 #include "namespace.h" 47 46 #include <sys/param.h> 48 #include <sys/mount.h>49 #endif50 47 #include <sys/stat.h> 51 48 49 #include <assert.h> 52 50 #include <dirent.h> 53 51 #include <errno.h> 54 52 #include <fcntl.h> 53 #include <fts.h> 55 54 #include <stdlib.h> 56 55 #include <string.h> 57 #ifndef _MSC_VER58 56 #include <unistd.h> 57 58 #if ! HAVE_NBTOOL_CONFIG_H 59 #define HAVE_STRUCT_DIRENT_D_NAMLEN 1 60 #endif 61 62 #ifdef __weak_alias 63 #ifdef __LIBC12_SOURCE__ 64 __weak_alias(fts_children,_fts_children) 65 __weak_alias(fts_close,_fts_close) 66 __weak_alias(fts_open,_fts_open) 67 __weak_alias(fts_read,_fts_read) 68 __weak_alias(fts_set,_fts_set) 69 #endif /* __LIBC12_SOURCE__ */ 70 #endif /* __weak_alias */ 71 72 #ifdef __LIBC12_SOURCE__ 73 #define STAT stat12 59 74 #else 60 #include "mscfakes.h" 61 #define dirfd(dir) -1 62 #endif 63 #include "ftsfake.h" 64 //#include "un-namespace.h" 65 66 static FTSENT *fts_alloc(FTS *, char *, int); 67 static FTSENT *fts_build(FTS *, int); 68 static void fts_lfree(FTSENT *); 69 static void fts_load(FTS *, FTSENT *); 70 static size_t fts_maxarglen(char * const *); 71 static void fts_padjust(FTS *, FTSENT *); 72 static int fts_palloc(FTS *, size_t); 73 static FTSENT *fts_sort(FTS *, FTSENT *, int); 74 static u_short fts_stat(FTS *, FTSENT *, int); 75 static int fts_safe_changedir(FTS *, FTSENT *, int, char *); 76 static int fts_ufslinks(FTS *, const FTSENT *); 77 78 #if defined(__EMX__) || defined(_MSC_VER) 79 # define NEED_STRRSLASH 80 # define IS_SLASH(ch) ( (ch) == '/' || (ch) == '\\' ) 81 #else 82 # define HAVE_FCHDIR 83 # define IS_SLASH(ch) ( (ch) == '/' ) 84 #endif 75 #define STAT stat 76 #endif 77 78 #ifdef __LIBC12_SOURCE__ 79 __warn_references(fts_children, 80 "warning: reference to compatibility fts_children();" 81 " include <fts.h> for correct reference") 82 __warn_references(fts_close, 83 "warning: reference to compatibility fts_close();" 84 " include <fts.h> for correct reference") 85 __warn_references(fts_open, 86 "warning: reference to compatibility fts_open();" 87 " include <fts.h> for correct reference") 88 __warn_references(fts_read, 89 "warning: reference to compatibility fts_read();" 90 " include <fts.h> for correct reference") 91 __warn_references(fts_set, 92 "warning: reference to compatibility fts_set();" 93 " include <fts.h> for correct reference") 94 #endif 95 96 static FTSENT *fts_alloc __P((FTS *, const char *, size_t)); 97 static FTSENT *fts_build __P((FTS *, int)); 98 static void fts_lfree __P((FTSENT *)); 99 static void fts_load __P((FTS *, FTSENT *)); 100 static size_t fts_maxarglen __P((char * const *)); 101 static size_t fts_pow2 __P((size_t)); 102 static int fts_palloc __P((FTS *, size_t)); 103 static void fts_padjust __P((FTS *, FTSENT *)); 104 static FTSENT *fts_sort __P((FTS *, FTSENT *, size_t)); 105 static u_short fts_stat __P((FTS *, FTSENT *, int)); 106 static int fts_safe_changedir __P((const FTS *, const FTSENT *, int, 107 const char *)); 85 108 86 109 #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) … … 90 113 #define SET(opt) (sp->fts_options |= (opt)) 91 114 92 # ifdef HAVE_FCHDIR115 #define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) 93 116 #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) 94 #else95 #define FCHDIR(sp, rdir) (!ISSET(FTS_NOCHDIR) && chdir(rdir))96 #endif97 117 98 118 /* fts_build flags */ … … 101 121 #define BREAD 3 /* fts_read */ 102 122 103 /* 104 * Internal representation of an FTS, including extra implementation 105 * details. The FTS returned from fts_open points to this structure's 106 * ftsp_fts member (and can be cast to an _fts_private as required) 107 */ 108 struct _fts_private { 109 FTS ftsp_fts; 110 #ifndef _MSC_VER 111 struct statfs ftsp_statfs; 112 #endif 113 dev_t ftsp_dev; 114 int ftsp_linksreliable; 115 }; 116 117 #if !defined(__EMX__) && !defined(_MSC_VER) 118 /* 119 * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it 120 * knows that a directory could not possibly have subdirectories. This 121 * is decided by looking at the link count: a subdirectory would 122 * increment its parent's link count by virtue of its own ".." entry. 123 * This assumption only holds for UFS-like filesystems that implement 124 * links and directories this way, so we must punt for others. 125 */ 126 127 static const char *ufslike_filesystems[] = { 128 "ufs", 129 "nfs", 130 "nfs4", 131 "ext2fs", 132 0 133 }; 134 #endif /* !__EMX__ && !_MSC_VER */ 123 #ifndef DTF_HIDEW 124 #undef FTS_WHITEOUT 125 #endif 135 126 136 127 FTS * … … 138 129 char * const *argv; 139 130 int options; 140 int (*compar)(const FTSENT * const *, const FTSENT * const *); 141 { 142 struct _fts_private *priv; 131 int (*compar) __P((const FTSENT **, const FTSENT **)); 132 { 143 133 FTS *sp; 144 134 FTSENT *p, *root; 145 int nitems; 146 FTSENT *parent, *tmp; 147 int len; 135 size_t nitems; 136 FTSENT *parent, *tmp = NULL; /* pacify gcc */ 137 size_t len; 138 139 _DIAGASSERT(argv != NULL); 148 140 149 141 /* Options check. */ … … 153 145 } 154 146 155 /* Allocate/initialize the stream .*/156 if (( priv = malloc(sizeof(*priv))) == NULL)147 /* Allocate/initialize the stream */ 148 if ((sp = malloc((u_int)sizeof(FTS))) == NULL) 157 149 return (NULL); 158 memset(priv, 0, sizeof(*priv)); 159 sp = &priv->ftsp_fts; 150 memset(sp, 0, sizeof(FTS)); 160 151 sp->fts_compar = compar; 161 152 sp->fts_options = options; 162 163 /* Shush, GCC. */164 tmp = NULL;165 153 166 154 /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ … … 181 169 182 170 /* Allocate/initialize root(s). */ 183 for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {171 for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { 184 172 /* Don't allow zero-length paths. */ 185 173 if ((len = strlen(*argv)) == 0) { … … 188 176 } 189 177 190 p = fts_alloc(sp, *argv, len); 178 if ((p = fts_alloc(sp, *argv, len)) == NULL) 179 goto mem3; 191 180 p->fts_level = FTS_ROOTLEVEL; 192 181 p->fts_parent = parent; … … 229 218 230 219 /* 231 * If using chdir(2), grab a file descriptor pointing to dot to ensure220 * If using chdir(2), grab a file descriptor pointing to dot to insure 232 221 * that we can get back here; this could be avoided for some paths, 233 222 * but almost certainly not worth the effort. Slashes, symbolic links, … … 235 224 * descriptor we run anyway, just more slowly. 236 225 */ 237 #ifdef HAVE_FCHDIR 238 if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = _open(".", O_RDONLY, 0)) < 0) 239 #else 240 if (!ISSET(FTS_NOCHDIR) && (sp->fts_rdir = getcwd(NULL, 0)) != NULL) 241 #endif 242 SET(FTS_NOCHDIR); 226 if (!ISSET(FTS_NOCHDIR)) { 227 if ((sp->fts_rfd = open(".", O_RDONLY, 0)) == -1) 228 SET(FTS_NOCHDIR); 229 else if (fcntl(sp->fts_rfd, F_SETFD, FD_CLOEXEC) == -1) { 230 close(sp->fts_rfd); 231 SET(FTS_NOCHDIR); 232 } 233 } 243 234 244 235 return (sp); … … 251 242 } 252 243 253 #ifdef NEED_STRRSLASH254 static char *strrslash(register char *psz)255 {256 register char ch;257 char *pszLast = NULL;258 for (; (ch = *psz); psz++)259 switch (ch)260 {261 case '/':262 case '\\':263 case ':':264 pszLast = psz;265 break;266 }267 return pszLast;268 }269 #endif270 271 244 static void 272 245 fts_load(sp, p) … … 274 247 FTSENT *p; 275 248 { 276 int len;249 size_t len; 277 250 char *cp; 251 252 _DIAGASSERT(sp != NULL); 253 _DIAGASSERT(p != NULL); 278 254 279 255 /* … … 286 262 len = p->fts_pathlen = p->fts_namelen; 287 263 memmove(sp->fts_path, p->fts_name, len + 1); 288 #ifdef NEED_STRRSLASH289 if ((cp = strrslash(p->fts_name)) && (cp != p->fts_name || cp[1])) {290 #else291 264 if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { 292 #endif293 265 len = strlen(++cp); 294 266 memmove(p->fts_name, cp, len + 1); … … 304 276 { 305 277 FTSENT *freep, *p; 306 int saved_errno; 278 int saved_errno = 0; 279 280 _DIAGASSERT(sp != NULL); 307 281 308 282 /* … … 312 286 */ 313 287 if (sp->fts_cur) { 288 if (ISSET(FTS_SYMFOLLOW)) 289 (void)close(sp->fts_cur->fts_symfd); 314 290 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { 315 291 freep = p; 316 p = p->fts_link != NULL? p->fts_link : p->fts_parent;292 p = p->fts_link ? p->fts_link : p->fts_parent; 317 293 free(freep); 318 294 } … … 329 305 /* Return to original directory, save errno if necessary. */ 330 306 if (!ISSET(FTS_NOCHDIR)) { 331 #ifdef HAVE_FCHDIR 332 saved_errno = fchdir(sp->fts_rfd) ? errno : 0; 333 (void)_close(sp->fts_rfd); 334 #else 335 saved_errno = chdir(sp->fts_rdir) ? errno : 0; 336 free(sp->fts_rdir); sp->fts_rdir = NULL; 337 #endif 338 339 /* Set errno and return. */ 340 if (saved_errno != 0) { 341 /* Free up the stream pointer. */ 342 free(sp); 343 errno = saved_errno; 344 return (-1); 345 } 307 if (fchdir(sp->fts_rfd)) 308 saved_errno = errno; 309 (void)close(sp->fts_rfd); 346 310 } 347 311 348 312 /* Free up the stream pointer. */ 349 313 free(sp); 314 /* ISSET() is illegal after this, since the macro touches sp */ 315 316 /* Set errno and return. */ 317 if (saved_errno) { 318 errno = saved_errno; 319 return (-1); 320 } 350 321 return (0); 351 322 } 352 323 353 354 324 /* 355 * Special case of "/" at the end of the path so that slashes aren't356 * appended which would cause paths to be written as "....//foo".325 * Special case a root of "/" so that slashes aren't appended which would 326 * cause paths to be written as "//foo". 357 327 */ 358 328 #define NAPPEND(p) \ 359 ( IS_SLASH(p->fts_path[p->fts_pathlen - 1])\360 ? p->fts_pathlen - 1: p->fts_pathlen)329 (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ 330 p->fts_path[0] == '/' ? 0 : p->fts_pathlen) 361 331 362 332 FTSENT * … … 369 339 int saved_errno; 370 340 341 _DIAGASSERT(sp != NULL); 342 371 343 /* If finished or unrecoverable error, return NULL. */ 372 344 if (sp->fts_cur == NULL || ISSET(FTS_STOP)) … … 396 368 p->fts_info = fts_stat(sp, p, 1); 397 369 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 398 #ifdef HAVE_FCHDIR 399 if ((p->fts_symfd = _open(".", O_RDONLY, 0)) < 0) { 370 if ((p->fts_symfd = open(".", O_RDONLY, 0)) == -1) { 400 371 p->fts_errno = errno; 401 372 p->fts_info = FTS_ERR; 373 } else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) { 374 p->fts_errno = errno; 375 p->fts_info = FTS_ERR; 376 close(p->fts_symfd); 402 377 } else 403 378 p->fts_flags |= FTS_SYMFOLLOW; 404 #endif405 379 } 406 380 return (p); … … 412 386 if (instr == FTS_SKIP || 413 387 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { 414 #ifdef HAVE_FCHDIR415 388 if (p->fts_flags & FTS_SYMFOLLOW) 416 (void)_close(p->fts_symfd); 417 #endif 389 (void)close(p->fts_symfd); 418 390 if (sp->fts_child) { 419 391 fts_lfree(sp->fts_child); … … 422 394 p->fts_info = FTS_DP; 423 395 return (p); 424 } 396 } 425 397 426 398 /* Rebuild if only read the names and now traversing. */ 427 if (sp->fts_child != NULL&& ISSET(FTS_NAMEONLY)) {399 if (sp->fts_child && ISSET(FTS_NAMEONLY)) { 428 400 CLR(FTS_NAMEONLY); 429 401 fts_lfree(sp->fts_child); … … 443 415 * FTS_STOP or the fts_info field of the node. 444 416 */ 445 if (sp->fts_child != NULL) {417 if (sp->fts_child) { 446 418 if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { 447 419 p->fts_errno = errno; 448 420 p->fts_flags |= FTS_DONTCHDIR; 449 for (p = sp->fts_child; p != NULL; 450 p = p->fts_link) 421 for (p = sp->fts_child; p; p = p->fts_link) 451 422 p->fts_accpath = 452 423 p->fts_parent->fts_accpath; … … 468 439 469 440 /* 470 * If reached the top, return to the original directory (or471 * the root of the tree), andload the paths for the next root.441 * If reached the top, return to the original directory, and 442 * load the paths for the next root. 472 443 */ 473 444 if (p->fts_level == FTS_ROOTLEVEL) { 474 #ifdef HAVE_FCHDIR475 445 if (FCHDIR(sp, sp->fts_rfd)) { 476 #else477 if (FCHDIR(sp, sp->fts_rdir)) {478 #endif479 446 SET(FTS_STOP); 480 447 return (NULL); … … 494 461 p->fts_info = fts_stat(sp, p, 1); 495 462 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 496 #ifdef HAVE_FCHDIR497 463 if ((p->fts_symfd = 498 _open(".", O_RDONLY, 0)) < 0) {464 open(".", O_RDONLY, 0)) == -1) { 499 465 p->fts_errno = errno; 500 466 p->fts_info = FTS_ERR; 467 } else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) { 468 p->fts_errno = errno; 469 p->fts_info = FTS_ERR; 470 close(p->fts_symfd); 501 471 } else 502 472 p->fts_flags |= FTS_SYMFOLLOW; 503 #endif504 473 } 505 474 p->fts_instr = FTS_NOINSTR; … … 508 477 name: t = sp->fts_path + NAPPEND(p->fts_parent); 509 478 *t++ = '/'; 510 memmove(t, p->fts_name, p->fts_namelen + 1);479 memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1)); 511 480 return (sp->fts_cur = p); 512 481 } … … 526 495 } 527 496 528 /* N ULterminate the pathname. */497 /* Nul terminate the pathname. */ 529 498 sp->fts_path[p->fts_pathlen] = '\0'; 530 499 … … 535 504 */ 536 505 if (p->fts_level == FTS_ROOTLEVEL) { 537 #ifdef HAVE_FCHDIR538 506 if (FCHDIR(sp, sp->fts_rfd)) { 539 #else540 if (FCHDIR(sp, sp->fts_rdir)) {541 #endif542 507 SET(FTS_STOP); 543 508 return (NULL); 544 509 } 545 #ifdef HAVE_FCHDIR546 510 } else if (p->fts_flags & FTS_SYMFOLLOW) { 547 511 if (FCHDIR(sp, p->fts_symfd)) { 548 512 saved_errno = errno; 549 (void) _close(p->fts_symfd);513 (void)close(p->fts_symfd); 550 514 errno = saved_errno; 551 515 SET(FTS_STOP); 552 516 return (NULL); 553 517 } 554 (void)_close(p->fts_symfd); 555 #else 556 (void)saved_errno; 557 #endif 518 (void)close(p->fts_symfd); 558 519 } else if (!(p->fts_flags & FTS_DONTCHDIR) && 559 520 fts_safe_changedir(sp, p->fts_parent, -1, "..")) { … … 578 539 int instr; 579 540 { 580 if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && 541 542 _DIAGASSERT(sp != NULL); 543 _DIAGASSERT(p != NULL); 544 545 if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW && 581 546 instr != FTS_NOINSTR && instr != FTS_SKIP) { 582 547 errno = EINVAL; … … 593 558 { 594 559 FTSENT *p; 595 #ifdef HAVE_FCHDIR596 560 int fd; 597 #else 598 char *pszRoot; 599 int rc; 600 #endif 601 if (instr != 0 && instr != FTS_NAMEONLY) { 561 562 _DIAGASSERT(sp != NULL); 563 564 if (instr && instr != FTS_NAMEONLY) { 602 565 errno = EINVAL; 603 566 return (NULL); … … 630 593 631 594 /* Free up any previous child list. */ 632 if (sp->fts_child != NULL)595 if (sp->fts_child) 633 596 fts_lfree(sp->fts_child); 634 597 … … 636 599 SET(FTS_NAMEONLY); 637 600 instr = BNAMES; 638 } else 601 } else 639 602 instr = BCHILD; 640 603 … … 646 609 * fts_read will work. 647 610 */ 648 if (p->fts_level != FTS_ROOTLEVEL || IS_SLASH(p->fts_accpath[0])||611 if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || 649 612 ISSET(FTS_NOCHDIR)) 650 613 return (sp->fts_child = fts_build(sp, instr)); 651 614 652 #ifdef HAVE_FCHDIR 653 if ((fd = _open(".", O_RDONLY, 0)) < 0)654 #else 655 if ((pszRoot = getcwd(NULL, 0)) == NULL) 656 #endif 615 if ((fd = open(".", O_RDONLY, 0)) == -1) 616 return (sp->fts_child = NULL); 617 sp->fts_child = fts_build(sp, instr); 618 if (fchdir(fd)) { 619 (void)close(fd); 657 620 return (NULL); 658 sp->fts_child = fts_build(sp, instr); 659 #ifdef HAVE_FCHDIR 660 if (fchdir(fd)) 661 return (NULL); 662 (void)_close(fd); 663 #else 664 rc = chdir(pszRoot); 665 free(pszRoot); 666 if (rc) 667 return NULL; 668 #endif 621 } 622 (void)close(fd); 669 623 return (sp->fts_child); 670 }671 672 #ifndef fts_get_clientptr673 #error "fts_get_clientptr not defined"674 #endif675 676 void *677 (fts_get_clientptr)(FTS *sp)678 {679 680 return (fts_get_clientptr(sp));681 }682 683 #ifndef fts_get_stream684 #error "fts_get_stream not defined"685 #endif686 687 FTS *688 (fts_get_stream)(FTSENT *p)689 {690 return (fts_get_stream(p));691 }692 693 void694 fts_set_clientptr(FTS *sp, void *clientptr)695 {696 697 sp->fts_clientptr = clientptr;698 624 } 699 625 … … 719 645 struct dirent *dp; 720 646 FTSENT *p, *head; 721 int nitems;647 size_t nitems; 722 648 FTSENT *cur, *tail; 723 649 DIR *dirp; 724 void *oldaddr; 725 int dnamlen; 726 int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno, 727 nostat, doadjust; 728 char *cp; 650 int adjust, cderrno, descend, len, level, nlinks, saved_errno, nostat; 651 size_t maxlen; 652 #ifdef FTS_WHITEOUT 653 int oflag; 654 #endif 655 char *cp = NULL; /* pacify gcc */ 656 657 _DIAGASSERT(sp != NULL); 729 658 730 659 /* Set current node pointer. */ … … 737 666 #ifdef FTS_WHITEOUT 738 667 if (ISSET(FTS_WHITEOUT)) 739 oflag = DTF_NODUP |DTF_REWIND;668 oflag = DTF_NODUP|DTF_REWIND; 740 669 else 741 oflag = DTF_HIDEW | DTF_NODUP |DTF_REWIND;670 oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; 742 671 #else 743 (void)(oflag);744 672 #define __opendir2(path, flag) opendir(path) 745 673 #endif … … 759 687 if (type == BNAMES) { 760 688 nlinks = 0; 761 /* Be quiet about nostat, GCC. */ 762 nostat = 0; 689 nostat = 1; 763 690 } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { 764 if (fts_ufslinks(sp, cur)) 765 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); 766 else 767 nlinks = -1; 691 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); 768 692 nostat = 1; 769 693 } else { … … 794 718 cderrno = 0; 795 719 if (nlinks || type == BREAD) { 796 #ifdef HAVE_FCHDIR797 720 if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { 798 #else799 if (fts_safe_changedir(sp, cur, dirfd(dirp), cur->fts_accpath)) {800 #endif801 721 if (nlinks && type == BREAD) 802 722 cur->fts_errno = errno; … … 823 743 cp = sp->fts_path + len; 824 744 *cp++ = '/'; 825 } else {826 /* GCC, you're too verbose. */827 cp = NULL;828 745 } 829 746 len++; … … 833 750 834 751 /* Read the directory, attaching each entry to the `link' pointer. */ 835 doadjust = 0; 836 for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { 837 #ifdef _MSC_VER 838 dnamlen = strlen(dp->d_name); 839 #else 840 dnamlen = dp->d_namlen; 841 #endif 752 adjust = 0; 753 for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)) != NULL;) { 754 size_t dlen; 755 842 756 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) 843 757 continue; 844 758 845 if ((p = fts_alloc(sp, dp->d_name, (int)dnamlen)) == NULL) 759 #if HAVE_STRUCT_DIRENT_D_NAMLEN 760 dlen = dp->d_namlen; 761 #else 762 dlen = strlen(dp->d_name); 763 #endif 764 if ((p = fts_alloc(sp, dp->d_name, dlen)) == NULL) 846 765 goto mem1; 847 if (dnamlen >= maxlen) { /* include space for NUL */ 848 oldaddr = sp->fts_path; 849 if (fts_palloc(sp, dnamlen + len + 1)) { 766 if (dlen >= maxlen) { /* include space for NUL */ 767 if (fts_palloc(sp, len + dlen + 1)) { 850 768 /* 851 769 * No more memory for path or structures. Save … … 858 776 fts_lfree(head); 859 777 (void)closedir(dirp); 778 errno = saved_errno; 860 779 cur->fts_info = FTS_ERR; 861 780 SET(FTS_STOP); 862 errno = saved_errno;863 781 return (NULL); 864 782 } 865 /* Did realloc() change the pointer? */ 866 if (oldaddr != sp->fts_path) { 867 doadjust = 1; 868 if (ISSET(FTS_NOCHDIR)) 869 cp = sp->fts_path + len; 870 } 783 adjust = 1; 784 if (ISSET(FTS_NOCHDIR)) 785 cp = sp->fts_path + len; 871 786 maxlen = sp->fts_pathlen - len; 872 787 } 873 788 874 if (len + dnamlen >= USHRT_MAX) { 875 /* 876 * In an FTSENT, fts_pathlen is a u_short so it is 877 * possible to wraparound here. If we do, free up 878 * the current structure and the structures already 879 * allocated, then error out with ENAMETOOLONG. 880 */ 881 free(p); 882 fts_lfree(head); 883 (void)closedir(dirp); 884 cur->fts_info = FTS_ERR; 885 SET(FTS_STOP); 886 errno = ENAMETOOLONG; 887 return (NULL); 888 } 789 p->fts_pathlen = len + dlen; 790 p->fts_parent = sp->fts_cur; 889 791 p->fts_level = level; 890 p->fts_parent = sp->fts_cur;891 p->fts_pathlen = len + dnamlen;892 792 893 793 #ifdef FTS_WHITEOUT … … 905 805 } else if (nlinks == 0 906 806 #ifdef DT_DIR 907 || (nostat && 807 || (nostat && 908 808 dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) 909 809 #endif … … 916 816 if (ISSET(FTS_NOCHDIR)) { 917 817 p->fts_accpath = p->fts_path; 918 memmove(cp, p->fts_name, p->fts_namelen + 1); 818 memmove(cp, p->fts_name, 819 (size_t)(p->fts_namelen + 1)); 919 820 } else 920 821 p->fts_accpath = p->fts_name; … … 938 839 ++nitems; 939 840 } 940 if (dirp) 941 (void)closedir(dirp); 942 943 /* 944 * If realloc() changed the address of the path, adjust the 945 * addresses for the rest of the tree and the dir list. 946 */ 947 if (doadjust) 841 (void)closedir(dirp); 842 843 /* 844 * If had to realloc the path, adjust the addresses for the rest 845 * of the tree. 846 */ 847 if (adjust) 948 848 fts_padjust(sp, head); 949 849 … … 953 853 */ 954 854 if (ISSET(FTS_NOCHDIR)) { 955 if ( len == sp->fts_pathlen || nitems == 0)855 if (cp - 1 > sp->fts_path) 956 856 --cp; 957 857 *cp = '\0'; … … 967 867 if (descend && (type == BCHILD || !nitems) && 968 868 (cur->fts_level == FTS_ROOTLEVEL ? 969 #ifdef HAVE_FCHDIR970 869 FCHDIR(sp, sp->fts_rfd) : 971 #else972 FCHDIR(sp, sp->fts_rdir) :973 #endif974 870 fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { 975 871 cur->fts_info = FTS_ERR; … … 1000 896 dev_t dev; 1001 897 ino_t ino; 1002 struct stat*sbp, sb;898 struct STAT *sbp, sb; 1003 899 int saved_errno; 900 901 _DIAGASSERT(sp != NULL); 902 _DIAGASSERT(p != NULL); 1004 903 1005 904 /* If user needs stat info, stat buffer already allocated. */ … … 1007 906 1008 907 #ifdef FTS_WHITEOUT 1009 /* Check for whiteout.*/908 /* check for whiteout */ 1010 909 if (p->fts_flags & FTS_ISW) { 1011 910 if (sbp != &sb) { 1012 memset(sbp, '\0', sizeof (*sbp));911 memset(sbp, '\0', sizeof (*sbp)); 1013 912 sbp->st_mode = S_IFWHT; 1014 913 } … … 1028 927 errno = 0; 1029 928 return (FTS_SLNONE); 1030 } 929 } 1031 930 p->fts_errno = saved_errno; 1032 931 goto err; … … 1034 933 } else if (lstat(p->fts_accpath, sbp)) { 1035 934 p->fts_errno = errno; 1036 err: memset(sbp, 0, sizeof(struct stat));935 err: memset(sbp, 0, sizeof(struct STAT)); 1037 936 return (FTS_NS); 1038 937 } … … 1074 973 } 1075 974 1076 /*1077 * The comparison function takes pointers to pointers to FTSENT structures.1078 * Qsort wants a comparison function that takes pointers to void.1079 * (Both with appropriate levels of const-poisoning, of course!)1080 * Use a trampoline function to deal with the difference.1081 */1082 static int1083 fts_compar(const void *a, const void *b)1084 {1085 FTS *parent;1086 1087 parent = (*(const FTSENT * const *)a)->fts_fts;1088 return (*parent->fts_compar)(a, b);1089 }1090 1091 975 static FTSENT * 1092 976 fts_sort(sp, head, nitems) 1093 977 FTS *sp; 1094 978 FTSENT *head; 1095 int nitems;979 size_t nitems; 1096 980 { 1097 981 FTSENT **ap, *p; 982 983 _DIAGASSERT(sp != NULL); 984 _DIAGASSERT(head != NULL); 1098 985 1099 986 /* … … 1105 992 */ 1106 993 if (nitems > sp->fts_nitems) { 994 FTSENT **new; 995 996 new = realloc(sp->fts_array, sizeof(FTSENT *) * (nitems + 40)); 997 if (new == 0) 998 return (head); 999 sp->fts_array = new; 1107 1000 sp->fts_nitems = nitems + 40; 1108 if ((sp->fts_array = reallocf(sp->fts_array,1109 sp->fts_nitems * sizeof(FTSENT *))) == NULL) {1110 sp->fts_nitems = 0;1111 return (head);1112 }1113 1001 } 1114 1002 for (ap = sp->fts_array, p = head; p; p = p->fts_link) 1115 1003 *ap++ = p; 1116 qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar); 1004 qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), 1005 (int (*) __P((const void *, const void *)))sp->fts_compar); 1117 1006 for (head = *(ap = sp->fts_array); --nitems; ++ap) 1118 1007 ap[0]->fts_link = ap[1]; … … 1124 1013 fts_alloc(sp, name, namelen) 1125 1014 FTS *sp; 1126 c har *name;1127 int namelen;1015 const char *name; 1016 size_t namelen; 1128 1017 { 1129 1018 FTSENT *p; 1130 1019 size_t len; 1131 1020 1132 struct ftsent_withstat { 1133 FTSENT ent; 1134 struct stat statbuf; 1135 }; 1136 1021 _DIAGASSERT(sp != NULL); 1022 _DIAGASSERT(name != NULL); 1023 1024 #if defined(ALIGNBYTES) && defined(ALIGN) 1137 1025 /* 1138 1026 * The file name is a variable length array and no stat structure is 1139 1027 * necessary if the user has set the nostat bit. Allocate the FTSENT 1140 1028 * structure, the file name and the stat structure in one chunk, but 1141 * be careful that the stat structure is reasonably aligned. 1142 * /1143 if (ISSET(FTS_NOSTAT))1144 len = sizeof(FTSENT) + namelen + 1;1145 else1146 len = sizeof(struct ftsent_withstat) + namelen + 1;1147 1029 * be careful that the stat structure is reasonably aligned. Since the 1030 * fts_name field is declared to be of size 1, the fts_name pointer is 1031 * namelen + 2 before the first possible address of the stat structure. 1032 */ 1033 len = sizeof(FTSENT) + namelen; 1034 if (!ISSET(FTS_NOSTAT)) 1035 len += sizeof(struct STAT) + ALIGNBYTES; 1148 1036 if ((p = malloc(len)) == NULL) 1149 1037 return (NULL); 1150 1038 1151 if (ISSET(FTS_NOSTAT)) { 1152 p->fts_name = (char *)(p + 1); 1153 p->fts_statp = NULL; 1154 } else { 1155 p->fts_name = (char *)((struct ftsent_withstat *)p + 1); 1156 p->fts_statp = &((struct ftsent_withstat *)p)->statbuf; 1157 } 1158 1159 /* Copy the name and guarantee NUL termination. */ 1160 memcpy(p->fts_name, name, namelen); 1161 p->fts_name[namelen] = '\0'; 1039 if (!ISSET(FTS_NOSTAT)) 1040 p->fts_statp = 1041 (struct STAT *)ALIGN((u_long)(p->fts_name + namelen + 2)); 1042 #else 1043 if ((p = malloc(sizeof(FTSENT) + namelen)) == NULL) 1044 return (NULL); 1045 1046 if (!ISSET(FTS_NOSTAT)) 1047 if ((p->fts_statp = malloc(sizeof(struct STAT))) == NULL) { 1048 free(p); 1049 return (NULL); 1050 } 1051 #endif 1052 1053 /* Copy the name plus the trailing NULL. */ 1054 memmove(p->fts_name, name, namelen + 1); 1055 1162 1056 p->fts_namelen = namelen; 1163 1057 p->fts_path = sp->fts_path; … … 1167 1061 p->fts_number = 0; 1168 1062 p->fts_pointer = NULL; 1169 p->fts_fts = sp;1170 1063 return (p); 1171 1064 } … … 1177 1070 FTSENT *p; 1178 1071 1072 /* XXX: head may be NULL ? */ 1073 1179 1074 /* Free a linked list of structures. */ 1180 while ((p = head) ) {1075 while ((p = head) != NULL) { 1181 1076 head = head->fts_link; 1077 1078 #if !defined(ALIGNBYTES) || !defined(ALIGN) 1079 if (p->fts_statp) 1080 free(p->fts_statp); 1081 #endif 1182 1082 free(p); 1183 1083 } 1084 } 1085 1086 static size_t 1087 fts_pow2(x) 1088 size_t x; 1089 { 1090 1091 x--; 1092 x |= x>>1; 1093 x |= x>>2; 1094 x |= x>>4; 1095 x |= x>>8; 1096 x |= x>>16; 1097 #if LONG_BIT > 32 1098 x |= x>>32; 1099 #endif 1100 #if LONG_BIT > 64 1101 x |= x>>64; 1102 #endif 1103 x++; 1104 return (x); 1184 1105 } 1185 1106 … … 1187 1108 * Allow essentially unlimited paths; find, rm, ls should all work on any tree. 1188 1109 * Most systems will allow creation of paths much longer than MAXPATHLEN, even 1189 * though the kernel won't resolve them. Add the size (not just what's needed)1190 * plus 256 bytes so don't realloc the path 2 bytes at a time.1110 * though the kernel won't resolve them. Round up the new size to a power of 2, 1111 * so we don't realloc the path 2 bytes at a time. 1191 1112 */ 1192 1113 static int 1193 fts_palloc(sp, more)1114 fts_palloc(sp, size) 1194 1115 FTS *sp; 1195 size_t more; 1196 { 1197 1198 sp->fts_pathlen += more + 256; 1199 /* 1200 * Check for possible wraparound. In an FTS, fts_pathlen is 1201 * a signed int but in an FTSENT it is an unsigned short. 1202 * We limit fts_pathlen to USHRT_MAX to be safe in both cases. 1203 */ 1204 if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) { 1205 if (sp->fts_path) 1206 free(sp->fts_path); 1207 sp->fts_path = NULL; 1208 errno = ENAMETOOLONG; 1116 size_t size; 1117 { 1118 char *new; 1119 1120 _DIAGASSERT(sp != NULL); 1121 1122 #if 1 1123 /* Protect against fts_pathlen overflow. */ 1124 if (size > USHRT_MAX + 1) { 1125 errno = ENOMEM; 1209 1126 return (1); 1210 1127 } 1211 sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen); 1212 return (sp->fts_path == NULL); 1128 #endif 1129 size = fts_pow2(size); 1130 new = realloc(sp->fts_path, size); 1131 if (new == 0) 1132 return (1); 1133 sp->fts_path = new; 1134 sp->fts_pathlen = size; 1135 return (0); 1213 1136 } 1214 1137 … … 1223 1146 { 1224 1147 FTSENT *p; 1225 char *addr = sp->fts_path; 1148 char *addr; 1149 1150 _DIAGASSERT(sp != NULL); 1226 1151 1227 1152 #define ADJUST(p) do { \ 1228 if ((p)->fts_accpath != (p)->fts_name) {\1153 if ((p)->fts_accpath != (p)->fts_name) \ 1229 1154 (p)->fts_accpath = \ 1230 (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ 1231 } \ 1155 addr + ((p)->fts_accpath - (p)->fts_path); \ 1232 1156 (p)->fts_path = addr; \ 1233 } while (0) 1157 } while (/*CONSTCOND*/0) 1158 1159 addr = sp->fts_path; 1160 1234 1161 /* Adjust the current set of children. */ 1235 1162 for (p = sp->fts_child; p; p = p->fts_link) … … 1248 1175 { 1249 1176 size_t len, max; 1177 1178 _DIAGASSERT(argv != NULL); 1250 1179 1251 1180 for (max = 0; *argv; ++argv) … … 1262 1191 static int 1263 1192 fts_safe_changedir(sp, p, fd, path) 1264 FTS *sp;1265 FTSENT *p;1193 const FTS *sp; 1194 const FTSENT *p; 1266 1195 int fd; 1267 char *path; 1268 { 1269 int ret, oerrno, newfd; 1270 struct stat sb; 1271 1272 newfd = fd; 1196 const char *path; 1197 { 1198 int oldfd = fd, ret = -1; 1199 struct STAT sb; 1200 1273 1201 if (ISSET(FTS_NOCHDIR)) 1274 return (0); 1275 #ifdef HAVE_FCHDIR 1276 if (fd < 0 && (newfd = _open(path, O_RDONLY, 0)) < 0) 1277 return (-1); 1278 if (_fstat(newfd, &sb)) { 1279 #else 1280 (void)newfd; 1281 if (stat(path, &sb)) { 1282 #endif 1283 ret = -1; 1202 return 0; 1203 1204 if (oldfd < 0 && (fd = open(path, O_RDONLY)) == -1) 1205 return -1; 1206 1207 if (fstat(fd, &sb) == -1) 1284 1208 goto bail; 1285 } 1286 if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { 1287 errno = ENOENT; /* disinformation */ 1288 ret = -1; 1209 1210 if (sb.st_ino != p->fts_ino || sb.st_dev != p->fts_dev) { 1211 errno = ENOENT; 1289 1212 goto bail; 1290 1213 } 1291 #ifdef HAVE_FCHDIR 1292 ret = fchdir(newfd); 1293 #else 1294 ret = chdir(path); 1295 #endif 1214 1215 ret = fchdir(fd); 1216 1296 1217 bail: 1297 #ifdef HAVE_FCHDIR 1298 oerrno = errno; 1299 if (fd < 0) 1300 (void)_close(newfd); 1301 errno = oerrno; 1302 #else 1303 (void)oerrno; 1304 #endif 1305 return (ret); 1306 } 1307 1308 /* 1309 * Check if the filesystem for "ent" has UFS-style links. 1310 */ 1311 static int 1312 fts_ufslinks(FTS *sp, const FTSENT *ent) 1313 { 1314 struct _fts_private *priv; 1315 const char **cpp; 1316 1317 priv = (struct _fts_private *)sp; 1318 #if defined(__EMX__) || defined(_MSC_VER) 1319 /* we don't have reliable links */ 1320 priv->ftsp_linksreliable = 0; 1321 (void)cpp; 1322 #else 1323 /* 1324 * If this node's device is different from the previous, grab 1325 * the filesystem information, and decide on the reliability 1326 * of the link information from this filesystem for stat(2) 1327 * avoidance. 1328 */ 1329 if (priv->ftsp_dev != ent->fts_dev) { 1330 if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { 1331 priv->ftsp_dev = ent->fts_dev; 1332 priv->ftsp_linksreliable = 0; 1333 for (cpp = ufslike_filesystems; *cpp; cpp++) { 1334 if (strcmp(priv->ftsp_statfs.f_fstypename, 1335 *cpp) == 0) { 1336 priv->ftsp_linksreliable = 1; 1337 break; 1338 } 1339 } 1340 } else { 1341 priv->ftsp_linksreliable = 0; 1342 } 1343 } 1344 #endif 1345 return (priv->ftsp_linksreliable); 1346 } 1347 1218 if (oldfd < 0) { 1219 int save_errno = errno; 1220 (void)close(fd); 1221 errno = save_errno; 1222 } 1223 return ret; 1224 }
Note:
See TracChangeset
for help on using the changeset viewer.