00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #if defined(LIBC_SCCS) && !defined(lint)
00034 static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
00035 #endif
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(hpux) || defined(__hpux)
00049 # define _INCLUDE_POSIX_SOURCE
00050 # define __errno_location() (&errno)
00051 # define dirfd(dirp) -1
00052 # define stat64 stat
00053 # define _STAT_VER 0
00054 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp))
00055 #endif
00056 #if defined(sun)
00057 # define __errno_location() (&errno)
00058 # define dirfd(dirp) -1
00059 # define _STAT_VER 0
00060 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp))
00061 #endif
00062 #if defined(__APPLE__)
00063 # define __errno_location() (__error())
00064 # define stat64 stat
00065 # define _STAT_VER 0
00066 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp))
00067 #endif
00068 #if defined(__FreeBSD__)
00069 # define __errno_location() (&errno)
00070 # define stat64 stat
00071 # define __fxstat64(_stat_ver, _fd, _sbp) fstat((_fd), (_sbp))
00072 #endif
00073 #include "system.h"
00074 #include "fts.h"
00075 #include "rpmio.h"
00076 #include "rpmurl.h"
00077 # define __set_errno(val) (*__errno_location ()) = (val)
00078 # define __open open
00079 # define __close close
00080 # define __fchdir fchdir
00081 #endif
00082
00083 #if !defined(USHRT_MAX)
00084 #define USHRT_MAX 65535
00085 #endif
00086
00087
00088
00089 #ifndef ALIGNBYTES
00090 #if defined __GNUC__ && __GNUC__ >= 2
00091 # define alignof(TYPE) __alignof__ (TYPE)
00092 #else
00093 # define alignof(TYPE) \
00094 ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
00095 #endif
00096 #define ALIGNBYTES (alignof(long double) - 1)
00097 #endif
00098
00099 #ifndef ALIGN
00100 #define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
00101 #endif
00102
00103
00104 static int _fts_debug = 0;
00105
00106
00107 static FTSENT * fts_alloc(FTS * sp, const char * name, int namelen)
00108 ;
00109
00110 static FTSENT * fts_build(FTS * sp, int type)
00111
00112 ;
00113 static void fts_lfree( FTSENT * head)
00114 ;
00115 static void fts_load(FTS * sp, FTSENT * p)
00116 ;
00117 static size_t fts_maxarglen(char * const * argv)
00118 ;
00119 static void fts_padjust(FTS * sp, FTSENT * head)
00120 ;
00121 static int fts_palloc(FTS * sp, size_t more)
00122 ;
00123 static FTSENT * fts_sort(FTS * sp, FTSENT * head, int nitems)
00124 ;
00125 static u_short fts_stat(FTS * sp, FTSENT * p, int follow)
00126 ;
00127 static int fts_safe_changedir(FTS * sp, FTSENT * p, int fd,
00128 const char * path)
00129
00130 ;
00131
00132 #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
00133
00134 #define CLR(opt) (sp->fts_options &= ~(opt))
00135 #define ISSET(opt) (sp->fts_options & (opt))
00136 #define SET(opt) (sp->fts_options |= (opt))
00137
00138 #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && __fchdir(fd))
00139
00140
00141 #define BCHILD 1
00142 #define BNAMES 2
00143 #define BREAD 3
00144
00145 FTS *
00146 Fts_open(char * const * argv, int options,
00147 int (*compar) (const FTSENT **, const FTSENT **))
00148 {
00149 register FTS *sp;
00150 register FTSENT *p, *root;
00151 register int nitems;
00152 FTSENT *parent = NULL;
00153 FTSENT *tmp = NULL;
00154 size_t len;
00155
00156
00157 if (_fts_debug)
00158 fprintf(stderr, "*** Fts_open(%p, 0x%x, %p)\n", argv, options, compar);
00159
00160
00161
00162 if (options & ~FTS_OPTIONMASK) {
00163
00164 __set_errno (EINVAL);
00165
00166 return (NULL);
00167 }
00168
00169
00170 if ((sp = malloc((u_int)sizeof(*sp))) == NULL)
00171 return (NULL);
00172 memset(sp, 0, sizeof(*sp));
00173 sp->fts_compar = (int (*) (const void *, const void *)) compar;
00174 sp->fts_opendir = Opendir;
00175 sp->fts_readdir = Readdir;
00176 sp->fts_closedir = Closedir;
00177 sp->fts_stat = Stat;
00178 sp->fts_lstat = Lstat;
00179 sp->fts_options = options;
00180
00181
00182 if (ISSET(FTS_LOGICAL))
00183 SET(FTS_NOCHDIR);
00184
00185
00186
00187
00188
00189 #ifndef MAXPATHLEN
00190 #define MAXPATHLEN 1024
00191 #endif
00192 len = fts_maxarglen(argv);
00193 if (len < MAXPATHLEN)
00194 len = MAXPATHLEN;
00195 if (fts_palloc(sp, len))
00196 goto mem1;
00197
00198
00199
00200 if (*argv != NULL) {
00201 if ((parent = fts_alloc(sp, "", 0)) == NULL)
00202 goto mem2;
00203 parent->fts_level = FTS_ROOTPARENTLEVEL;
00204 }
00205
00206
00207
00208 for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
00209
00210 if ((len = strlen(*argv)) == 0) {
00211
00212 __set_errno (ENOENT);
00213
00214 goto mem3;
00215 }
00216
00217
00218 switch (urlIsURL(*argv)) {
00219 case URL_IS_DASH:
00220 case URL_IS_HKP:
00221
00222 __set_errno (ENOENT);
00223
00224 goto mem3;
00225 break;
00226 case URL_IS_HTTPS:
00227 case URL_IS_HTTP:
00228 case URL_IS_FTP:
00229 SET(FTS_NOCHDIR);
00230 break;
00231 case URL_IS_UNKNOWN:
00232 case URL_IS_PATH:
00233 break;
00234 }
00235
00236 p = fts_alloc(sp, *argv, len);
00237 if (p == NULL)
00238 goto mem3;
00239 p->fts_level = FTS_ROOTLEVEL;
00240 p->fts_parent = parent;
00241 p->fts_accpath = p->fts_name;
00242 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
00243
00244
00245 if (p->fts_info == FTS_DOT)
00246 p->fts_info = FTS_D;
00247
00248
00249
00250
00251
00252 if (compar) {
00253 p->fts_link = root;
00254 root = p;
00255 } else {
00256 p->fts_link = NULL;
00257 if (root == NULL)
00258 tmp = root = p;
00259 else {
00260 if (tmp != NULL)
00261 tmp->fts_link = p;
00262 tmp = p;
00263 }
00264 }
00265 }
00266
00267 if (compar && nitems > 1)
00268 root = fts_sort(sp, root, nitems);
00269
00270
00271
00272
00273
00274
00275
00276 if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
00277 goto mem3;
00278 sp->fts_cur->fts_link = root;
00279 sp->fts_cur->fts_info = FTS_INIT;
00280
00281
00282
00283
00284
00285
00286
00287
00288 if (!ISSET(FTS_NOCHDIR)
00289 && (sp->fts_rfd = __open(".", O_RDONLY, 0)) < 0)
00290 SET(FTS_NOCHDIR);
00291
00292 return (sp);
00293
00294 mem3: fts_lfree(root);
00295 free(parent);
00296 mem2: free(sp->fts_path);
00297 mem1: free(sp);
00298 return (NULL);
00299 }
00300
00301 static void
00302 fts_load(FTS * sp, FTSENT * p)
00303 {
00304 register int len;
00305 register char *cp;
00306
00307
00308
00309
00310
00311
00312
00313
00314 len = p->fts_pathlen = p->fts_namelen;
00315
00316 memmove(sp->fts_path, p->fts_name, len + 1);
00317 if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
00318 len = strlen(++cp);
00319 memmove(p->fts_name, cp, len + 1);
00320 p->fts_namelen = len;
00321 }
00322 p->fts_accpath = p->fts_path = sp->fts_path;
00323 sp->fts_dev = p->fts_dev;
00324
00325 }
00326
00327 int
00328 Fts_close(FTS * sp)
00329 {
00330 register FTSENT *freep, *p;
00331 int saved_errno;
00332
00333 if (sp == NULL)
00334 return 0;
00335
00336
00337
00338
00339
00340
00341
00342 if (sp->fts_cur) {
00343 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
00344 freep = p;
00345 p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
00346 free(freep);
00347 }
00348 free(p);
00349 }
00350
00351
00352
00353 if (sp->fts_child)
00354 fts_lfree(sp->fts_child);
00355 if (sp->fts_array)
00356 free(sp->fts_array);
00357 free(sp->fts_path);
00358
00359
00360 if (!ISSET(FTS_NOCHDIR)) {
00361 saved_errno = __fchdir(sp->fts_rfd) ? errno : 0;
00362 (void)__close(sp->fts_rfd);
00363
00364
00365 if (saved_errno != 0) {
00366
00367 free(sp);
00368
00369 __set_errno (saved_errno);
00370
00371 return (-1);
00372 }
00373 }
00374
00375
00376 free(sp);
00377 return (0);
00378 }
00379
00380
00381
00382
00383
00384 #define NAPPEND(p) \
00385 (p->fts_path[p->fts_pathlen - 1] == '/' \
00386 ? p->fts_pathlen - 1 : p->fts_pathlen)
00387
00388 FTSENT *
00389 Fts_read(FTS * sp)
00390 {
00391 register FTSENT *p;
00392 register FTSENT *tmp;
00393 register int instr;
00394 register char *t;
00395 int saved_errno;
00396
00397
00398 if (sp == NULL || sp->fts_cur == NULL || ISSET(FTS_STOP))
00399 return (NULL);
00400
00401
00402 p = sp->fts_cur;
00403
00404
00405 instr = p->fts_instr;
00406 p->fts_instr = FTS_NOINSTR;
00407
00408
00409 if (instr == FTS_AGAIN) {
00410 p->fts_info = fts_stat(sp, p, 0);
00411 return (p);
00412 }
00413
00414
00415
00416
00417
00418
00419
00420 if (instr == FTS_FOLLOW &&
00421 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
00422 p->fts_info = fts_stat(sp, p, 1);
00423 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
00424 if ((p->fts_symfd = __open(".", O_RDONLY, 0)) < 0) {
00425 p->fts_errno = errno;
00426 p->fts_info = FTS_ERR;
00427 } else
00428 p->fts_flags |= FTS_SYMFOLLOW;
00429 }
00430 return (p);
00431 }
00432
00433
00434 if (p->fts_info == FTS_D) {
00435
00436 if (instr == FTS_SKIP ||
00437 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
00438 if (p->fts_flags & FTS_SYMFOLLOW)
00439 (void)__close(p->fts_symfd);
00440 if (sp->fts_child) {
00441 fts_lfree(sp->fts_child);
00442 sp->fts_child = NULL;
00443 }
00444 p->fts_info = FTS_DP;
00445 return (p);
00446 }
00447
00448
00449 if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
00450 CLR(FTS_NAMEONLY);
00451 fts_lfree(sp->fts_child);
00452 sp->fts_child = NULL;
00453 }
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 if (sp->fts_child != NULL) {
00468 if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
00469 p->fts_errno = errno;
00470 p->fts_flags |= FTS_DONTCHDIR;
00471 for (p = sp->fts_child; p != NULL;
00472 p = p->fts_link)
00473 p->fts_accpath =
00474 p->fts_parent->fts_accpath;
00475 }
00476 } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
00477 if (ISSET(FTS_STOP))
00478 return (NULL);
00479 return (p);
00480 }
00481 p = sp->fts_child;
00482 sp->fts_child = NULL;
00483 sp->fts_cur = p;
00484 goto name;
00485 }
00486
00487
00488
00489 next: tmp = p;
00490 if ((p = p->fts_link) != NULL) {
00491 sp->fts_cur = p;
00492 free(tmp);
00493
00494
00495
00496
00497
00498 if (p->fts_level == FTS_ROOTLEVEL) {
00499 if (FCHDIR(sp, sp->fts_rfd)) {
00500 SET(FTS_STOP);
00501 return (NULL);
00502 }
00503 fts_load(sp, p);
00504 return (p);
00505 }
00506
00507
00508
00509
00510
00511
00512 if (p->fts_instr == FTS_SKIP)
00513 goto next;
00514
00515 if (p->fts_instr == FTS_FOLLOW) {
00516 p->fts_info = fts_stat(sp, p, 1);
00517 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
00518 if ((p->fts_symfd =
00519 __open(".", O_RDONLY, 0)) < 0) {
00520 p->fts_errno = errno;
00521 p->fts_info = FTS_ERR;
00522 } else
00523 p->fts_flags |= FTS_SYMFOLLOW;
00524 }
00525 p->fts_instr = FTS_NOINSTR;
00526 }
00527
00528
00529 name: t = sp->fts_path + NAPPEND(p->fts_parent);
00530 *t++ = '/';
00531 memmove(t, p->fts_name, p->fts_namelen + 1);
00532 return (p);
00533 }
00534
00535
00536 p = tmp->fts_parent;
00537 sp->fts_cur = p;
00538 free(tmp);
00539
00540 if (p->fts_level == FTS_ROOTPARENTLEVEL) {
00541
00542
00543
00544
00545 free(p);
00546 __set_errno (0);
00547 return (sp->fts_cur = NULL);
00548 }
00549
00550
00551 sp->fts_path[p->fts_pathlen] = '\0';
00552
00553
00554
00555
00556
00557
00558
00559 if (p->fts_level == FTS_ROOTLEVEL) {
00560 if (FCHDIR(sp, sp->fts_rfd)) {
00561 SET(FTS_STOP);
00562 return (NULL);
00563 }
00564 } else if (p->fts_flags & FTS_SYMFOLLOW) {
00565 if (FCHDIR(sp, p->fts_symfd)) {
00566 saved_errno = errno;
00567 (void)__close(p->fts_symfd);
00568
00569 __set_errno (saved_errno);
00570
00571 SET(FTS_STOP);
00572 return (NULL);
00573 }
00574 (void)__close(p->fts_symfd);
00575 } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
00576 fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
00577 SET(FTS_STOP);
00578 return (NULL);
00579 }
00580 p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
00581 return (p);
00582 }
00583
00584
00585
00586
00587
00588
00589
00590 int
00591 Fts_set( FTS * sp, FTSENT * p, int instr)
00592 {
00593
00594 if (_fts_debug)
00595 fprintf(stderr, "*** Fts_set(%p, %p, 0x%x)\n", sp, p, instr);
00596
00597
00598 if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
00599 instr != FTS_NOINSTR && instr != FTS_SKIP) {
00600
00601 __set_errno (EINVAL);
00602
00603 return (1);
00604 }
00605 p->fts_instr = instr;
00606 return (0);
00607 }
00608
00609 FTSENT *
00610 Fts_children(FTS * sp, int instr)
00611 {
00612 register FTSENT *p;
00613 int fd;
00614
00615
00616 if (_fts_debug)
00617 fprintf(stderr, "*** Fts_children(%p, 0x%x)\n", sp, instr);
00618
00619
00620 if (instr != 0 && instr != FTS_NAMEONLY) {
00621
00622 __set_errno (EINVAL);
00623
00624 return (NULL);
00625 }
00626
00627
00628 p = sp->fts_cur;
00629
00630
00631
00632
00633
00634
00635 __set_errno (0);
00636
00637
00638
00639 if (ISSET(FTS_STOP))
00640 return (NULL);
00641
00642
00643 if (p->fts_info == FTS_INIT)
00644 return (p->fts_link);
00645
00646
00647
00648
00649
00650
00651 if (p->fts_info != FTS_D )
00652 return (NULL);
00653
00654
00655 if (sp->fts_child != NULL)
00656 fts_lfree(sp->fts_child);
00657
00658 if (instr == FTS_NAMEONLY) {
00659 SET(FTS_NAMEONLY);
00660 instr = BNAMES;
00661 } else
00662 instr = BCHILD;
00663
00664
00665
00666
00667
00668
00669
00670
00671 if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
00672 ISSET(FTS_NOCHDIR))
00673 return (sp->fts_child = fts_build(sp, instr));
00674
00675 if ((fd = __open(".", O_RDONLY, 0)) < 0)
00676 return (NULL);
00677 sp->fts_child = fts_build(sp, instr);
00678 if (__fchdir(fd))
00679 return (NULL);
00680 (void)__close(fd);
00681 return (sp->fts_child);
00682 }
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698 static FTSENT *
00699 fts_build(FTS * sp, int type)
00700 {
00701 register struct dirent *dp;
00702 register FTSENT *p, *head;
00703 register int nitems;
00704 FTSENT *cur, *tail;
00705 DIR *dirp;
00706 void *oldaddr;
00707 int cderrno, descend, len, level, nlinks, saved_errno,
00708 nostat, doadjust;
00709 size_t maxlen;
00710 char *cp;
00711
00712
00713 cur = sp->fts_cur;
00714
00715
00716
00717
00718
00719 #if defined FTS_WHITEOUT && 0
00720 if (ISSET(FTS_WHITEOUT))
00721 oflag = DTF_NODUP|DTF_REWIND;
00722 else
00723 oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
00724 #else
00725 # define __opendir2(path, flag) (*sp->fts_opendir) (path)
00726 #endif
00727 if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
00728 if (type == BREAD) {
00729 cur->fts_info = FTS_DNR;
00730 cur->fts_errno = errno;
00731 }
00732 return (NULL);
00733 }
00734
00735
00736
00737
00738
00739
00740 if (type == BNAMES) {
00741 nlinks = 0;
00742
00743 nostat = 0;
00744 } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
00745 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
00746 nostat = 1;
00747 } else {
00748 nlinks = -1;
00749 nostat = 0;
00750 }
00751
00752 #ifdef notdef
00753 (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
00754 (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
00755 ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
00756 #endif
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772 cderrno = 0;
00773 if (nlinks || type == BREAD) {
00774 if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
00775 if (nlinks && type == BREAD)
00776 cur->fts_errno = errno;
00777 cur->fts_flags |= FTS_DONTCHDIR;
00778 descend = 0;
00779 cderrno = errno;
00780 (void) (*sp->fts_closedir) (dirp);
00781 dirp = NULL;
00782 } else
00783 descend = 1;
00784 } else
00785 descend = 0;
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797 len = NAPPEND(cur);
00798 if (ISSET(FTS_NOCHDIR)) {
00799 cp = sp->fts_path + len;
00800
00801 *cp++ = '/';
00802
00803 } else {
00804
00805 cp = NULL;
00806 }
00807 len++;
00808 maxlen = sp->fts_pathlen - len;
00809
00810 level = cur->fts_level + 1;
00811
00812
00813 doadjust = 0;
00814 for (head = tail = NULL, nitems = 0;
00815 dirp && (dp = (*sp->fts_readdir) (dirp));)
00816 {
00817 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
00818 continue;
00819
00820 if ((p = fts_alloc(sp, dp->d_name, (int)_D_EXACT_NAMLEN (dp))) == NULL)
00821 goto mem1;
00822 if (_D_EXACT_NAMLEN (dp) >= maxlen) {
00823 oldaddr = sp->fts_path;
00824 if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
00825
00826
00827
00828
00829
00830 mem1: saved_errno = errno;
00831 if (p)
00832 free(p);
00833 fts_lfree(head);
00834 (void) (*sp->fts_closedir) (dirp);
00835 cur->fts_info = FTS_ERR;
00836 SET(FTS_STOP);
00837 __set_errno (saved_errno);
00838 return (NULL);
00839 }
00840
00841 if (oldaddr != sp->fts_path) {
00842 doadjust = 1;
00843 if (ISSET(FTS_NOCHDIR))
00844 cp = sp->fts_path + len;
00845 }
00846 maxlen = sp->fts_pathlen - len;
00847 }
00848
00849 if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
00850
00851
00852
00853
00854
00855
00856 free(p);
00857 fts_lfree(head);
00858 (void) (*sp->fts_closedir) (dirp);
00859 cur->fts_info = FTS_ERR;
00860 SET(FTS_STOP);
00861 __set_errno (ENAMETOOLONG);
00862 return (NULL);
00863 }
00864 p->fts_level = level;
00865 p->fts_parent = sp->fts_cur;
00866 p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
00867
00868 #if defined FTS_WHITEOUT && 0
00869 if (dp->d_type == DT_WHT)
00870 p->fts_flags |= FTS_ISW;
00871 #endif
00872
00873 #if 0
00874
00875
00876
00877
00878
00879 if (cderrno) {
00880 if (nlinks) {
00881 p->fts_info = FTS_NS;
00882 p->fts_errno = cderrno;
00883 } else
00884 p->fts_info = FTS_NSOK;
00885 p->fts_accpath = cur->fts_accpath;
00886 } else
00887 #endif
00888 if (nlinks == 0
00889 #if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
00890 || (nostat &&
00891 dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
00892 #endif
00893 ) {
00894 p->fts_accpath =
00895 ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
00896 p->fts_info = FTS_NSOK;
00897 } else {
00898
00899 if (ISSET(FTS_NOCHDIR)) {
00900 p->fts_accpath = p->fts_path;
00901 memmove(cp, p->fts_name, p->fts_namelen + 1);
00902 } else
00903 p->fts_accpath = p->fts_name;
00904
00905 p->fts_info = fts_stat(sp, p, 0);
00906
00907
00908 if (nlinks > 0 && (p->fts_info == FTS_D ||
00909 p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
00910 --nlinks;
00911 }
00912
00913
00914 p->fts_link = NULL;
00915 if (head == NULL)
00916 head = tail = p;
00917 else {
00918 tail->fts_link = p;
00919 tail = p;
00920 }
00921 ++nitems;
00922 }
00923 if (dirp)
00924 (void) (*sp->fts_closedir) (dirp);
00925
00926
00927
00928
00929
00930 if (doadjust)
00931 fts_padjust(sp, head);
00932
00933
00934
00935
00936
00937 if (ISSET(FTS_NOCHDIR)) {
00938 if (len == sp->fts_pathlen || nitems == 0)
00939 --cp;
00940
00941 if (cp != NULL)
00942 *cp = '\0';
00943
00944 }
00945
00946
00947
00948
00949
00950
00951
00952
00953 if (descend && (type == BCHILD || !nitems) &&
00954 (cur->fts_level == FTS_ROOTLEVEL ?
00955 FCHDIR(sp, sp->fts_rfd) :
00956 fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
00957 cur->fts_info = FTS_ERR;
00958 SET(FTS_STOP);
00959 fts_lfree(head);
00960 return (NULL);
00961 }
00962
00963
00964 if (!nitems) {
00965 if (type == BREAD)
00966 cur->fts_info = FTS_DP;
00967 fts_lfree(head);
00968 return (NULL);
00969 }
00970
00971
00972 if (sp->fts_compar && nitems > 1)
00973 head = fts_sort(sp, head, nitems);
00974 return (head);
00975 }
00976
00977 static u_short
00978 fts_stat(FTS * sp, FTSENT * p, int follow)
00979 {
00980 register FTSENT *t;
00981 register dev_t dev;
00982 register ino_t ino;
00983 struct stat *sbp, sb;
00984 int saved_errno;
00985
00986
00987 sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
00988
00989 #if defined FTS_WHITEOUT && 0
00990
00991 if (p->fts_flags & FTS_ISW) {
00992 if (sbp != &sb) {
00993 memset(sbp, '\0', sizeof (*sbp));
00994 sbp->st_mode = S_IFWHT;
00995 }
00996 return (FTS_W);
00997 }
00998 #endif
00999
01000
01001
01002
01003
01004
01005 if (ISSET(FTS_LOGICAL) || follow) {
01006 if ((*sp->fts_stat) (p->fts_accpath, sbp)) {
01007 saved_errno = errno;
01008 if (!(*sp->fts_lstat) (p->fts_accpath, sbp)) {
01009
01010 __set_errno (0);
01011
01012 return (FTS_SLNONE);
01013 }
01014 p->fts_errno = saved_errno;
01015 goto err;
01016 }
01017 } else if ((*sp->fts_lstat) (p->fts_accpath, sbp)) {
01018 p->fts_errno = errno;
01019
01020 err: memset(sbp, 0, sizeof(*sbp));
01021
01022 return (FTS_NS);
01023 }
01024
01025 if (S_ISDIR(sbp->st_mode)) {
01026
01027
01028
01029
01030
01031
01032
01033 dev = p->fts_dev = sbp->st_dev;
01034 ino = p->fts_ino = sbp->st_ino;
01035 p->fts_nlink = sbp->st_nlink;
01036
01037 if (ISDOT(p->fts_name))
01038 return (FTS_DOT);
01039
01040
01041
01042
01043
01044
01045
01046 for (t = p->fts_parent;
01047 t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
01048 if (ino == t->fts_ino && dev == t->fts_dev) {
01049 p->fts_cycle = t;
01050 return (FTS_DC);
01051 }
01052 return (FTS_D);
01053 }
01054 if (S_ISLNK(sbp->st_mode))
01055 return (FTS_SL);
01056 if (S_ISREG(sbp->st_mode))
01057 return (FTS_F);
01058 return (FTS_DEFAULT);
01059 }
01060
01061 static FTSENT *
01062 fts_sort(FTS * sp, FTSENT * head, int nitems)
01063 {
01064 register FTSENT **ap, *p;
01065
01066
01067
01068
01069
01070
01071
01072
01073 if (nitems > sp->fts_nitems) {
01074 struct _ftsent **a;
01075
01076 sp->fts_nitems = nitems + 40;
01077 if ((a = realloc(sp->fts_array,
01078 (size_t)(sp->fts_nitems * sizeof(*sp->fts_array)))) == NULL)
01079 {
01080 free(sp->fts_array);
01081 sp->fts_array = NULL;
01082 sp->fts_nitems = 0;
01083 return (head);
01084 }
01085 sp->fts_array = a;
01086 }
01087
01088 for (ap = sp->fts_array, p = head; p != NULL; p = p->fts_link)
01089 *ap++ = p;
01090 qsort((void *)sp->fts_array, nitems, sizeof(*sp->fts_array),
01091 sp->fts_compar);
01092 for (head = *(ap = sp->fts_array); --nitems; ++ap)
01093 ap[0]->fts_link = ap[1];
01094 ap[0]->fts_link = NULL;
01095
01096 return (head);
01097 }
01098
01099 static FTSENT *
01100 fts_alloc(FTS * sp, const char * name, int namelen)
01101 {
01102 register FTSENT *p;
01103 size_t len;
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113 len = sizeof(*p) + namelen;
01114 if (!ISSET(FTS_NOSTAT))
01115 len += sizeof(*p->fts_statp) + ALIGNBYTES;
01116 if ((p = malloc(len)) == NULL)
01117 return (NULL);
01118
01119
01120
01121 memmove(p->fts_name, name, namelen);
01122 p->fts_name[namelen] = '\0';
01123
01124
01125 if (!ISSET(FTS_NOSTAT))
01126 p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
01127 p->fts_namelen = namelen;
01128 p->fts_path = sp->fts_path;
01129 p->fts_errno = 0;
01130 p->fts_flags = 0;
01131 p->fts_instr = FTS_NOINSTR;
01132 p->fts_number = 0;
01133 p->fts_pointer = NULL;
01134 return (p);
01135 }
01136
01137 static void
01138 fts_lfree(FTSENT * head)
01139 {
01140 register FTSENT *p;
01141
01142
01143
01144 while ((p = head)) {
01145 head = head->fts_link;
01146 free(p);
01147 }
01148
01149 }
01150
01151
01152
01153
01154
01155
01156
01157 static int
01158 fts_palloc(FTS * sp, size_t more)
01159 {
01160 char *p;
01161
01162 sp->fts_pathlen += more + 256;
01163
01164
01165
01166
01167
01168 if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
01169 if (sp->fts_path)
01170 free(sp->fts_path);
01171 sp->fts_path = NULL;
01172
01173 __set_errno (ENAMETOOLONG);
01174
01175 return (1);
01176 }
01177 p = realloc(sp->fts_path, sp->fts_pathlen);
01178 if (p == NULL) {
01179 free(sp->fts_path);
01180 sp->fts_path = NULL;
01181 return 1;
01182 }
01183 sp->fts_path = p;
01184 return 0;
01185 }
01186
01187
01188
01189
01190
01191 static void
01192 fts_padjust(FTS * sp, FTSENT * head)
01193 {
01194 FTSENT *p;
01195 char *addr = sp->fts_path;
01196
01197 #define ADJUST(p) do { \
01198 if ((p)->fts_accpath != (p)->fts_name) { \
01199 (p)->fts_accpath = \
01200 (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
01201 } \
01202 (p)->fts_path = addr; \
01203 } while (0)
01204
01205 for (p = sp->fts_child; p != NULL; p = p->fts_link)
01206 ADJUST(p);
01207
01208
01209 for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
01210 ADJUST(p);
01211 p = p->fts_link ? p->fts_link : p->fts_parent;
01212 }
01213 }
01214
01215 static size_t
01216 fts_maxarglen(char * const * argv)
01217 {
01218 size_t len, max;
01219
01220 for (max = 0; *argv; ++argv)
01221 if ((len = strlen(*argv)) > max)
01222 max = len;
01223 return (max + 1);
01224 }
01225
01226
01227
01228
01229
01230
01231 static int
01232 fts_safe_changedir(FTS * sp, FTSENT * p, int fd, const char * path)
01233 {
01234 int ret, oerrno, newfd;
01235 struct stat64 sb;
01236
01237 newfd = fd;
01238 if (ISSET(FTS_NOCHDIR))
01239 return (0);
01240 if (fd < 0 && (newfd = __open(path, O_RDONLY, 0)) < 0)
01241 return (-1);
01242 if (__fxstat64(_STAT_VER, newfd, &sb)) {
01243 ret = -1;
01244 goto bail;
01245 }
01246 if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
01247
01248 __set_errno (ENOENT);
01249
01250 ret = -1;
01251 goto bail;
01252 }
01253 ret = __fchdir(newfd);
01254 bail:
01255 oerrno = errno;
01256 if (fd < 0)
01257 (void)__close(newfd);
01258
01259 __set_errno (oerrno);
01260
01261 return (ret);
01262 }
01263
01264
01265