File indexing completed on 2025-05-11 08:24:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #ifdef HAVE_CONFIG_H
0033 #include "config.h"
0034 #endif
0035
0036 #if HAVE_NBTOOL_CONFIG_H
0037 #include "nbtool_config.h"
0038 #endif
0039
0040 #include <sys/cdefs.h>
0041 #if defined(LIBC_SCCS) && !defined(lint)
0042 #if 0
0043 static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
0044 #else
0045 __RCSID("$NetBSD: fts.c,v 1.40 2009/11/02 17:17:34 stacktic Exp $");
0046 #endif
0047 #endif
0048
0049 #ifndef __rtems__
0050 #include "namespace.h"
0051 #endif
0052 #include <limits.h>
0053 #include <sys/param.h>
0054 #include <sys/stat.h>
0055
0056 #include <assert.h>
0057 #include <dirent.h>
0058 #include <errno.h>
0059 #include <fcntl.h>
0060 #include "fts.h"
0061 #include <stdlib.h>
0062 #include <stdint.h>
0063 #include <string.h>
0064 #include <unistd.h>
0065
0066 #define _DIAGASSERT(a)
0067 #undef FTS_WHITEOUT
0068 #define dirfd(dp) __dirfd(dp)
0069
0070 #if ! HAVE_NBTOOL_CONFIG_H
0071 #define HAVE_STRUCT_DIRENT_D_NAMLEN
0072 #endif
0073
0074 static FTSENT *fts_alloc(FTS *, const char *, size_t);
0075 static FTSENT *fts_build(FTS *, int);
0076 static void fts_free(FTSENT *);
0077 static void fts_lfree(FTSENT *);
0078 static void fts_load(FTS *, FTSENT *);
0079 static size_t fts_maxarglen(char * const *);
0080 static size_t fts_pow2(size_t);
0081 static int fts_palloc(FTS *, size_t);
0082 static void fts_padjust(FTS *, FTSENT *);
0083 static FTSENT *fts_sort(FTS *, FTSENT *, size_t);
0084 static unsigned short fts_stat(FTS *, FTSENT *, int);
0085 static int fts_safe_changedir(const FTS *, const FTSENT *, int,
0086 const char *);
0087
0088 #if defined(ALIGNBYTES) && defined(ALIGN)
0089 #define FTS_ALLOC_ALIGNED 1
0090
0091
0092 #undef ALIGN
0093 #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) & ~ALIGNBYTES)
0094 #else
0095 #undef FTS_ALLOC_ALIGNED
0096 #endif
0097
0098 #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
0099
0100 #define CLR(opt) (sp->fts_options &= ~(opt))
0101 #define ISSET(opt) (sp->fts_options & (opt))
0102 #define SET(opt) (sp->fts_options |= (opt))
0103
0104 #define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path))
0105 #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
0106
0107
0108 #define BCHILD 1
0109 #define BNAMES 2
0110 #define BREAD 3
0111
0112 #ifndef DTF_HIDEW
0113 #undef FTS_WHITEOUT
0114 #endif
0115
0116 FTS *
0117 fts_open(char * const *argv, int options,
0118 int (*compar)(const FTSENT **, const FTSENT **))
0119 {
0120 FTS *sp;
0121 FTSENT *p, *root;
0122 size_t nitems;
0123 FTSENT *parent, *tmp = NULL;
0124 size_t len;
0125
0126 _DIAGASSERT(argv != NULL);
0127
0128
0129 if (options & ~FTS_OPTIONMASK) {
0130 errno = EINVAL;
0131 return (NULL);
0132 }
0133
0134
0135 if ((sp = malloc((unsigned int)sizeof(FTS))) == NULL)
0136 return (NULL);
0137 memset(sp, 0, sizeof(FTS));
0138 sp->fts_compar = compar;
0139 sp->fts_options = options;
0140
0141
0142 if (ISSET(FTS_LOGICAL))
0143 SET(FTS_NOCHDIR);
0144
0145
0146
0147
0148
0149 if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
0150 goto mem1;
0151
0152
0153 if ((parent = fts_alloc(sp, "", 0)) == NULL)
0154 goto mem2;
0155 parent->fts_level = FTS_ROOTPARENTLEVEL;
0156
0157
0158 for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
0159
0160 if ((len = strlen(*argv)) == 0) {
0161 errno = ENOENT;
0162 goto mem3;
0163 }
0164
0165 if ((p = fts_alloc(sp, *argv, len)) == NULL)
0166 goto mem3;
0167 p->fts_level = FTS_ROOTLEVEL;
0168 p->fts_parent = parent;
0169 p->fts_accpath = p->fts_name;
0170 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
0171
0172
0173 if (p->fts_info == FTS_DOT)
0174 p->fts_info = FTS_D;
0175
0176
0177
0178
0179
0180 if (compar) {
0181 p->fts_link = root;
0182 root = p;
0183 } else {
0184 p->fts_link = NULL;
0185 if (root == NULL)
0186 tmp = root = p;
0187 else {
0188 tmp->fts_link = p;
0189 tmp = p;
0190 }
0191 }
0192 }
0193 if (compar && nitems > 1)
0194 root = fts_sort(sp, root, nitems);
0195
0196
0197
0198
0199
0200
0201 if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
0202 goto mem3;
0203 sp->fts_cur->fts_link = root;
0204 sp->fts_cur->fts_info = FTS_INIT;
0205
0206
0207
0208
0209
0210
0211
0212
0213 if (!ISSET(FTS_NOCHDIR)) {
0214 if ((sp->fts_rfd = open(".", O_RDONLY, 0)) == -1)
0215 SET(FTS_NOCHDIR);
0216 else if (fcntl(sp->fts_rfd, F_SETFD, FD_CLOEXEC) == -1) {
0217 close(sp->fts_rfd);
0218 SET(FTS_NOCHDIR);
0219 }
0220 }
0221
0222 if (nitems == 0)
0223 fts_free(parent);
0224
0225 return (sp);
0226
0227 mem3: fts_lfree(root);
0228 fts_free(parent);
0229 mem2: free(sp->fts_path);
0230 mem1: free(sp);
0231 return (NULL);
0232 }
0233
0234 static void
0235 fts_load(FTS *sp, FTSENT *p)
0236 {
0237 size_t len;
0238 char *cp;
0239
0240 _DIAGASSERT(sp != NULL);
0241 _DIAGASSERT(p != NULL);
0242
0243
0244
0245
0246
0247
0248
0249
0250 len = p->fts_pathlen = p->fts_namelen;
0251 memmove(sp->fts_path, p->fts_name, len + 1);
0252 if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
0253 len = strlen(++cp);
0254 memmove(p->fts_name, cp, len + 1);
0255 p->fts_namelen = len;
0256 }
0257 p->fts_accpath = p->fts_path = sp->fts_path;
0258 sp->fts_dev = p->fts_dev;
0259 }
0260
0261 int
0262 fts_close(FTS *sp)
0263 {
0264 FTSENT *freep, *p;
0265 int saved_errno = 0;
0266
0267 _DIAGASSERT(sp != NULL);
0268
0269
0270
0271
0272
0273
0274 if (sp->fts_cur) {
0275 if (sp->fts_cur->fts_flags & FTS_SYMFOLLOW)
0276 (void)close(sp->fts_cur->fts_symfd);
0277 for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
0278 freep = p;
0279 p = p->fts_link ? p->fts_link : p->fts_parent;
0280 fts_free(freep);
0281 }
0282 fts_free(p);
0283 }
0284
0285
0286 if (sp->fts_child)
0287 fts_lfree(sp->fts_child);
0288 if (sp->fts_array)
0289 free(sp->fts_array);
0290 free(sp->fts_path);
0291
0292
0293 if (!ISSET(FTS_NOCHDIR)) {
0294 if (fchdir(sp->fts_rfd) == -1)
0295 saved_errno = errno;
0296 (void)close(sp->fts_rfd);
0297 }
0298
0299
0300 free(sp);
0301 if (saved_errno) {
0302 errno = saved_errno;
0303 return -1;
0304 }
0305
0306 return 0;
0307 }
0308
0309 #if !defined(__FTS_COMPAT_TAILINGSLASH)
0310
0311
0312
0313
0314
0315 #define NAPPEND(p) \
0316 (p->fts_path[p->fts_pathlen - 1] == '/' \
0317 ? p->fts_pathlen - 1 : p->fts_pathlen)
0318
0319 #else
0320
0321
0322
0323
0324
0325
0326
0327
0328 #define NAPPEND(p) \
0329 (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \
0330 p->fts_path[0] == '/' ? 0 : p->fts_pathlen)
0331
0332 #endif
0333
0334 FTSENT *
0335 fts_read(FTS *sp)
0336 {
0337 FTSENT *p, *tmp;
0338 int instr;
0339 char *t;
0340 int saved_errno;
0341
0342 _DIAGASSERT(sp != NULL);
0343
0344
0345 if (sp->fts_cur == NULL || ISSET(FTS_STOP))
0346 return (NULL);
0347
0348
0349 p = sp->fts_cur;
0350
0351
0352 instr = p->fts_instr;
0353 p->fts_instr = FTS_NOINSTR;
0354
0355
0356 if (instr == FTS_AGAIN) {
0357 p->fts_info = fts_stat(sp, p, 0);
0358 return (p);
0359 }
0360
0361
0362
0363
0364
0365
0366
0367 if (instr == FTS_FOLLOW &&
0368 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
0369 p->fts_info = fts_stat(sp, p, 1);
0370 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
0371 if ((p->fts_symfd = open(".", O_RDONLY, 0)) == -1) {
0372 p->fts_errno = errno;
0373 p->fts_info = FTS_ERR;
0374 } else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) {
0375 p->fts_errno = errno;
0376 p->fts_info = FTS_ERR;
0377 close(p->fts_symfd);
0378 } else
0379 p->fts_flags |= FTS_SYMFOLLOW;
0380 }
0381 return (p);
0382 }
0383
0384
0385 if (p->fts_info == FTS_D) {
0386
0387 if (instr == FTS_SKIP ||
0388 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
0389 if (p->fts_flags & FTS_SYMFOLLOW)
0390 (void)close(p->fts_symfd);
0391 if (sp->fts_child) {
0392 fts_lfree(sp->fts_child);
0393 sp->fts_child = NULL;
0394 }
0395 p->fts_info = FTS_DP;
0396 return (p);
0397 }
0398
0399
0400 if (sp->fts_child && ISSET(FTS_NAMEONLY)) {
0401 CLR(FTS_NAMEONLY);
0402 fts_lfree(sp->fts_child);
0403 sp->fts_child = NULL;
0404 }
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418 if (sp->fts_child) {
0419 if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
0420 p->fts_errno = errno;
0421 p->fts_flags |= FTS_DONTCHDIR;
0422 for (p = sp->fts_child; p; p = p->fts_link)
0423 p->fts_accpath =
0424 p->fts_parent->fts_accpath;
0425 }
0426 } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
0427 if (ISSET(FTS_STOP))
0428 return (NULL);
0429 return (p);
0430 }
0431 p = sp->fts_child;
0432 sp->fts_child = NULL;
0433 goto name;
0434 }
0435
0436
0437 next: tmp = p;
0438 if ((p = p->fts_link) != NULL) {
0439 fts_free(tmp);
0440
0441
0442
0443
0444
0445 if (p->fts_level == FTS_ROOTLEVEL) {
0446 if (FCHDIR(sp, sp->fts_rfd)) {
0447 SET(FTS_STOP);
0448 return (NULL);
0449 }
0450 fts_load(sp, p);
0451 return (sp->fts_cur = p);
0452 }
0453
0454
0455
0456
0457
0458
0459 if (p->fts_instr == FTS_SKIP)
0460 goto next;
0461 if (p->fts_instr == FTS_FOLLOW) {
0462 p->fts_info = fts_stat(sp, p, 1);
0463 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
0464 if ((p->fts_symfd =
0465 open(".", O_RDONLY, 0)) == -1) {
0466 p->fts_errno = errno;
0467 p->fts_info = FTS_ERR;
0468 } else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) {
0469 p->fts_errno = errno;
0470 p->fts_info = FTS_ERR;
0471 close(p->fts_symfd);
0472 } else
0473 p->fts_flags |= FTS_SYMFOLLOW;
0474 }
0475 p->fts_instr = FTS_NOINSTR;
0476 }
0477
0478 name: t = sp->fts_path + NAPPEND(p->fts_parent);
0479 *t++ = '/';
0480 memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1));
0481 return (sp->fts_cur = p);
0482 }
0483
0484
0485 p = tmp->fts_parent;
0486 fts_free(tmp);
0487
0488 if (p->fts_level == FTS_ROOTPARENTLEVEL) {
0489
0490
0491
0492
0493 fts_free(p);
0494 errno = 0;
0495 return (sp->fts_cur = NULL);
0496 }
0497
0498
0499 sp->fts_path[p->fts_pathlen] = '\0';
0500
0501
0502
0503
0504
0505
0506 if (p->fts_level == FTS_ROOTLEVEL) {
0507 if (FCHDIR(sp, sp->fts_rfd)) {
0508 SET(FTS_STOP);
0509 return (NULL);
0510 }
0511 } else if (p->fts_flags & FTS_SYMFOLLOW) {
0512 if (FCHDIR(sp, p->fts_symfd)) {
0513 saved_errno = errno;
0514 (void)close(p->fts_symfd);
0515 errno = saved_errno;
0516 SET(FTS_STOP);
0517 return (NULL);
0518 }
0519 (void)close(p->fts_symfd);
0520 } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
0521 fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
0522 SET(FTS_STOP);
0523 return (NULL);
0524 }
0525 p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
0526 return (sp->fts_cur = p);
0527 }
0528
0529
0530
0531
0532
0533
0534
0535
0536 int
0537 fts_set(FTS *sp, FTSENT *p, int instr)
0538 {
0539
0540 _DIAGASSERT(sp != NULL);
0541 _DIAGASSERT(p != NULL);
0542
0543 if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
0544 instr != FTS_NOINSTR && instr != FTS_SKIP) {
0545 errno = EINVAL;
0546 return (1);
0547 }
0548 p->fts_instr = instr;
0549 return (0);
0550 }
0551
0552 FTSENT *
0553 fts_children(FTS *sp, int instr)
0554 {
0555 FTSENT *p;
0556 int fd;
0557
0558 _DIAGASSERT(sp != NULL);
0559
0560 if (instr && instr != FTS_NAMEONLY) {
0561 errno = EINVAL;
0562 return (NULL);
0563 }
0564
0565
0566 p = sp->fts_cur;
0567
0568
0569
0570
0571
0572 errno = 0;
0573
0574
0575 if (ISSET(FTS_STOP))
0576 return (NULL);
0577
0578
0579 if (p->fts_info == FTS_INIT)
0580 return (p->fts_link);
0581
0582
0583
0584
0585
0586
0587 if (p->fts_info != FTS_D )
0588 return (NULL);
0589
0590
0591 if (sp->fts_child)
0592 fts_lfree(sp->fts_child);
0593
0594 if (instr == FTS_NAMEONLY) {
0595 SET(FTS_NAMEONLY);
0596 instr = BNAMES;
0597 } else
0598 instr = BCHILD;
0599
0600
0601
0602
0603
0604
0605
0606
0607 if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
0608 ISSET(FTS_NOCHDIR))
0609 return (sp->fts_child = fts_build(sp, instr));
0610
0611 if ((fd = open(".", O_RDONLY, 0)) == -1)
0612 return (sp->fts_child = NULL);
0613 sp->fts_child = fts_build(sp, instr);
0614 if (fchdir(fd)) {
0615 (void)close(fd);
0616 return (NULL);
0617 }
0618 (void)close(fd);
0619 return (sp->fts_child);
0620 }
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636 static FTSENT *
0637 fts_build(FTS *sp, int type)
0638 {
0639 struct dirent *dp;
0640 FTSENT *p, *head;
0641 size_t nitems;
0642 FTSENT *cur, *tail;
0643 DIR *dirp;
0644 void *oldaddr;
0645 size_t dnamlen;
0646 int cderrno, descend, level, nlinks, saved_errno;
0647 #ifdef DT_DIR
0648 int nostat;
0649 #endif
0650 int doadjust;
0651 size_t len, maxlen;
0652 #ifdef FTS_WHITEOUT
0653 int oflag;
0654 #endif
0655 char *cp = NULL;
0656
0657 _DIAGASSERT(sp != NULL);
0658
0659
0660 cur = sp->fts_cur;
0661
0662
0663
0664
0665
0666 #ifdef FTS_WHITEOUT
0667 if (ISSET(FTS_WHITEOUT))
0668 oflag = DTF_NODUP|DTF_REWIND;
0669 else
0670 oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
0671 #else
0672 #define __opendir2(path, flag) opendir(path)
0673 #endif
0674 if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
0675 if (type == BREAD) {
0676 cur->fts_info = FTS_DNR;
0677 cur->fts_errno = errno;
0678 }
0679 return (NULL);
0680 }
0681
0682
0683
0684
0685
0686
0687 if (type == BNAMES) {
0688 nlinks = 0;
0689 #ifdef DT_DIR
0690 nostat = 1;
0691 #endif
0692 } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
0693 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
0694 #ifdef DT_DIR
0695 nostat = 1;
0696 #endif
0697 } else {
0698 nlinks = -1;
0699 #ifdef DT_DIR
0700 nostat = 0;
0701 #endif
0702 }
0703
0704 #ifdef notdef
0705 (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
0706 (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
0707 ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
0708 #endif
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724 cderrno = 0;
0725 if (nlinks || type == BREAD) {
0726 if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
0727 if (nlinks && type == BREAD)
0728 cur->fts_errno = errno;
0729 cur->fts_flags |= FTS_DONTCHDIR;
0730 descend = 0;
0731 cderrno = errno;
0732 } else
0733 descend = 1;
0734 } else
0735 descend = 0;
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747 len = NAPPEND(cur);
0748 if (ISSET(FTS_NOCHDIR)) {
0749 cp = sp->fts_path + len;
0750 *cp++ = '/';
0751 }
0752 len++;
0753 maxlen = sp->fts_pathlen - len;
0754
0755 #if defined(__FTS_COMPAT_LEVEL)
0756 if (cur->fts_level == SHRT_MAX) {
0757 (void)closedir(dirp);
0758 cur->fts_info = FTS_ERR;
0759 SET(FTS_STOP);
0760 errno = ENAMETOOLONG;
0761 return (NULL);
0762 }
0763 #endif
0764
0765 level = cur->fts_level + 1;
0766
0767
0768 doadjust = 0;
0769 for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)) != NULL;) {
0770
0771 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
0772 continue;
0773
0774 #if defined(HAVE_STRUCT_DIRENT_D_NAMLEN)
0775 dnamlen = dp->d_namlen;
0776 #else
0777 dnamlen = strlen(dp->d_name);
0778 #endif
0779 if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL)
0780 goto mem1;
0781 if (dnamlen >= maxlen) {
0782 oldaddr = sp->fts_path;
0783 if (fts_palloc(sp, dnamlen + len + 1)) {
0784
0785
0786
0787
0788
0789 mem1: saved_errno = errno;
0790 if (p)
0791 fts_free(p);
0792 fts_lfree(head);
0793 (void)closedir(dirp);
0794 errno = saved_errno;
0795 cur->fts_info = FTS_ERR;
0796 SET(FTS_STOP);
0797 return (NULL);
0798 }
0799
0800 if (oldaddr != sp->fts_path) {
0801 doadjust = 1;
0802 if (ISSET(FTS_NOCHDIR))
0803 cp = sp->fts_path + len;
0804 }
0805 maxlen = sp->fts_pathlen - len;
0806 }
0807
0808 #if defined(__FTS_COMPAT_LENGTH)
0809 if (len + dnamlen >= USHRT_MAX) {
0810
0811
0812
0813
0814
0815
0816
0817 fts_free(p);
0818 fts_lfree(head);
0819 (void)closedir(dirp);
0820 cur->fts_info = FTS_ERR;
0821 SET(FTS_STOP);
0822 errno = ENAMETOOLONG;
0823 return (NULL);
0824 }
0825 #endif
0826 p->fts_level = level;
0827 p->fts_pathlen = len + dnamlen;
0828 p->fts_parent = sp->fts_cur;
0829
0830 #ifdef FTS_WHITEOUT
0831 if (dp->d_type == DT_WHT)
0832 p->fts_flags |= FTS_ISW;
0833 #endif
0834
0835 if (cderrno) {
0836 if (nlinks) {
0837 p->fts_info = FTS_NS;
0838 p->fts_errno = cderrno;
0839 }
0840
0841
0842
0843 p->fts_accpath = cur->fts_accpath;
0844 } else if (nlinks == 0
0845 #ifdef DT_DIR
0846 || (nostat &&
0847 dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
0848 #endif
0849 ) {
0850 p->fts_accpath =
0851 ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
0852 p->fts_info = FTS_NSOK;
0853 } else {
0854
0855 if (ISSET(FTS_NOCHDIR)) {
0856 p->fts_accpath = p->fts_path;
0857 memmove(cp, p->fts_name,
0858 (size_t)(p->fts_namelen + 1));
0859 } else
0860 p->fts_accpath = p->fts_name;
0861
0862 p->fts_info = fts_stat(sp, p, 0);
0863
0864
0865 if (nlinks > 0 && (p->fts_info == FTS_D ||
0866 p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
0867 --nlinks;
0868 }
0869
0870
0871 p->fts_link = NULL;
0872 if (head == NULL)
0873 head = tail = p;
0874 else {
0875 tail->fts_link = p;
0876 tail = p;
0877 }
0878 ++nitems;
0879 }
0880 (void)closedir(dirp);
0881
0882
0883
0884
0885
0886 if (doadjust)
0887 fts_padjust(sp, head);
0888
0889
0890
0891
0892
0893 if (ISSET(FTS_NOCHDIR)) {
0894 if (len == sp->fts_pathlen || nitems == 0)
0895 --cp;
0896 *cp = '\0';
0897 }
0898
0899
0900
0901
0902
0903
0904
0905
0906 if (descend && (type == BCHILD || !nitems) &&
0907 (cur->fts_level == FTS_ROOTLEVEL ?
0908 FCHDIR(sp, sp->fts_rfd) :
0909 fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
0910 cur->fts_info = FTS_ERR;
0911 SET(FTS_STOP);
0912 return (NULL);
0913 }
0914
0915
0916 if (!nitems) {
0917 if (type == BREAD)
0918 cur->fts_info = FTS_DP;
0919 return (NULL);
0920 }
0921
0922
0923 if (sp->fts_compar && nitems > 1)
0924 head = fts_sort(sp, head, nitems);
0925 return (head);
0926 }
0927
0928 static unsigned short
0929 fts_stat(FTS *sp, FTSENT *p, int follow)
0930 {
0931 FTSENT *t;
0932 dev_t dev;
0933 __fts_ino_t ino;
0934 __fts_stat_t *sbp, sb;
0935 int saved_errno;
0936
0937 _DIAGASSERT(sp != NULL);
0938 _DIAGASSERT(p != NULL);
0939
0940
0941 sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
0942
0943 #ifdef FTS_WHITEOUT
0944
0945 if (p->fts_flags & FTS_ISW) {
0946 if (sbp != &sb) {
0947 memset(sbp, '\0', sizeof (*sbp));
0948 sbp->st_mode = S_IFWHT;
0949 }
0950 return (FTS_W);
0951 }
0952 #endif
0953
0954
0955
0956
0957
0958
0959 if (ISSET(FTS_LOGICAL) || follow) {
0960 if (stat(p->fts_accpath, sbp)) {
0961 saved_errno = errno;
0962 if (!lstat(p->fts_accpath, sbp)) {
0963 errno = 0;
0964 return (FTS_SLNONE);
0965 }
0966 p->fts_errno = saved_errno;
0967 goto err;
0968 }
0969 } else if (lstat(p->fts_accpath, sbp)) {
0970 p->fts_errno = errno;
0971 err: memset(sbp, 0, sizeof(*sbp));
0972 return (FTS_NS);
0973 }
0974
0975 if (S_ISDIR(sbp->st_mode)) {
0976
0977
0978
0979
0980
0981
0982
0983 dev = p->fts_dev = sbp->st_dev;
0984 ino = p->fts_ino = sbp->st_ino;
0985 p->fts_nlink = sbp->st_nlink;
0986
0987 if (ISDOT(p->fts_name))
0988 return (FTS_DOT);
0989
0990
0991
0992
0993
0994
0995
0996 for (t = p->fts_parent;
0997 t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
0998 if (ino == t->fts_ino && dev == t->fts_dev) {
0999 p->fts_cycle = t;
1000 return (FTS_DC);
1001 }
1002 return (FTS_D);
1003 }
1004 if (S_ISLNK(sbp->st_mode))
1005 return (FTS_SL);
1006 if (S_ISREG(sbp->st_mode))
1007 return (FTS_F);
1008 return (FTS_DEFAULT);
1009 }
1010
1011 static FTSENT *
1012 fts_sort(FTS *sp, FTSENT *head, size_t nitems)
1013 {
1014 FTSENT **ap, *p;
1015
1016 _DIAGASSERT(sp != NULL);
1017 _DIAGASSERT(head != NULL);
1018
1019
1020
1021
1022
1023
1024
1025
1026 if (nitems > sp->fts_nitems) {
1027 FTSENT **new;
1028
1029 new = realloc(sp->fts_array, sizeof(FTSENT *) * (nitems + 40));
1030 if (new == 0)
1031 return (head);
1032 sp->fts_array = new;
1033 sp->fts_nitems = nitems + 40;
1034 }
1035 for (ap = sp->fts_array, p = head; p; p = p->fts_link)
1036 *ap++ = p;
1037 qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *),
1038 (int (*)(const void *, const void *))sp->fts_compar);
1039 for (head = *(ap = sp->fts_array); --nitems; ++ap)
1040 ap[0]->fts_link = ap[1];
1041 ap[0]->fts_link = NULL;
1042 return (head);
1043 }
1044
1045 static FTSENT *
1046 fts_alloc(FTS *sp, const char *name, size_t namelen)
1047 {
1048 FTSENT *p;
1049 #if defined(FTS_ALLOC_ALIGNED)
1050 size_t len;
1051 #endif
1052
1053 _DIAGASSERT(sp != NULL);
1054 _DIAGASSERT(name != NULL);
1055
1056 #if defined(FTS_ALLOC_ALIGNED)
1057
1058
1059
1060
1061
1062
1063
1064
1065 len = sizeof(FTSENT) + namelen;
1066 if (!ISSET(FTS_NOSTAT))
1067 len += sizeof(*(p->fts_statp)) + ALIGNBYTES;
1068 if ((p = malloc(len)) == NULL)
1069 return (NULL);
1070
1071 if (!ISSET(FTS_NOSTAT))
1072 p->fts_statp = (__fts_stat_t *)ALIGN(p->fts_name + namelen + 2);
1073 #else
1074 if ((p = malloc(sizeof(FTSENT) + namelen)) == NULL)
1075 return (NULL);
1076
1077 if (!ISSET(FTS_NOSTAT))
1078 if ((p->fts_statp = malloc(sizeof(*(p->fts_statp)))) == NULL) {
1079 free(p);
1080 return (NULL);
1081 }
1082 #endif
1083
1084 if (ISSET(FTS_NOSTAT))
1085 p->fts_statp = NULL;
1086
1087
1088 memmove(p->fts_name, name, namelen + 1);
1089
1090 p->fts_namelen = namelen;
1091 p->fts_path = sp->fts_path;
1092 p->fts_errno = 0;
1093 p->fts_flags = 0;
1094 p->fts_instr = FTS_NOINSTR;
1095 p->fts_number = 0;
1096 p->fts_pointer = NULL;
1097 return (p);
1098 }
1099
1100 static void
1101 fts_free(FTSENT *p)
1102 {
1103 #if !defined(FTS_ALLOC_ALIGNED)
1104 if (p->fts_statp)
1105 free(p->fts_statp);
1106 #endif
1107 free(p);
1108 }
1109
1110 static void
1111 fts_lfree(FTSENT *head)
1112 {
1113 FTSENT *p;
1114
1115
1116
1117
1118 while ((p = head) != NULL) {
1119 head = head->fts_link;
1120 fts_free(p);
1121 }
1122 }
1123
1124 static size_t
1125 fts_pow2(size_t x)
1126 {
1127
1128 x--;
1129 x |= x>>1;
1130 x |= x>>2;
1131 x |= x>>4;
1132 x |= x>>8;
1133 #if (SIZEOF_SIZE_T * CHAR_BIT) > 16
1134 x |= x>>16;
1135 #endif
1136 #if (SIZEOF_SIZE_T * CHAR_BIT) > 32
1137 x |= x>>32;
1138 #endif
1139 #if (SIZEOF_SIZE_T * CHAR_BIT) > 64
1140 x |= x>>64;
1141 #endif
1142 x++;
1143 return (x);
1144 }
1145
1146
1147
1148
1149
1150
1151
1152 static int
1153 fts_palloc(FTS *sp, size_t size)
1154 {
1155 char *new;
1156
1157 _DIAGASSERT(sp != NULL);
1158
1159 #ifdef __FTS_COMPAT_LENGTH
1160
1161 if (size > USHRT_MAX + 1) {
1162 errno = ENAMETOOLONG;
1163 return (1);
1164 }
1165 #endif
1166 size = fts_pow2(size);
1167 new = realloc(sp->fts_path, size);
1168 if (new == 0)
1169 return (1);
1170 sp->fts_path = new;
1171 sp->fts_pathlen = size;
1172 return (0);
1173 }
1174
1175
1176
1177
1178
1179 static void
1180 fts_padjust(FTS *sp, FTSENT *head)
1181 {
1182 FTSENT *p;
1183 char *addr;
1184
1185 _DIAGASSERT(sp != NULL);
1186
1187 #define ADJUST(p) do { \
1188 if ((p)->fts_accpath != (p)->fts_name) \
1189 (p)->fts_accpath = \
1190 addr + ((p)->fts_accpath - (p)->fts_path); \
1191 (p)->fts_path = addr; \
1192 } while (0)
1193
1194 addr = sp->fts_path;
1195
1196
1197 for (p = sp->fts_child; p; p = p->fts_link)
1198 ADJUST(p);
1199
1200
1201 for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
1202 ADJUST(p);
1203 p = p->fts_link ? p->fts_link : p->fts_parent;
1204 }
1205 }
1206
1207 static size_t
1208 fts_maxarglen(char * const *argv)
1209 {
1210 size_t len, max;
1211
1212 _DIAGASSERT(argv != NULL);
1213
1214 for (max = 0; *argv; ++argv)
1215 if ((len = strlen(*argv)) > max)
1216 max = len;
1217 return (max + 1);
1218 }
1219
1220
1221
1222
1223
1224
1225 static int
1226 fts_safe_changedir(const FTS *sp, const FTSENT *p, int fd, const char *path)
1227 {
1228 int oldfd = fd, ret = -1;
1229 __fts_stat_t sb;
1230
1231 if (ISSET(FTS_NOCHDIR))
1232 return 0;
1233
1234 if (oldfd < 0 && (fd = open(path, O_RDONLY)) == -1)
1235 return -1;
1236
1237 if (fstat(fd, &sb) == -1)
1238 goto bail;
1239
1240 if (sb.st_ino != p->fts_ino || sb.st_dev != p->fts_dev) {
1241 errno = ENOENT;
1242 goto bail;
1243 }
1244
1245 ret = fchdir(fd);
1246
1247 bail:
1248 if (oldfd < 0) {
1249 int save_errno = errno;
1250 (void)close(fd);
1251 errno = save_errno;
1252 }
1253 return ret;
1254 }