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