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