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