| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static FTSENT * fts_alloc(FTS * sp, const char * name, int namelen); |
| static FTSENT * fts_build(FTS * sp, int type); |
| static void fts_lfree(FTSENT * head); |
| static void fts_load(FTS * sp, FTSENT * p); |
| static size_t fts_maxarglen(char * const * argv); |
| static void fts_padjust(FTS * sp, FTSENT * head); |
| static int fts_palloc(FTS * sp, size_t more); |
| static FTSENT * fts_sort(FTS * sp, FTSENT * head, int nitems); |
| static uint16_t fts_stat(FTS * sp, FTSENT * p, int follow); |
| static int fts_safe_changedir(FTS * sp, FTSENT * p, int fd, |
| const char * path); |
| |
| |
| |
| __typeof__ (b) _b = (b); \ |
| _a > _b ? _a : _b; }) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| FTS * |
| Fts_open(char * const * argv, int options, |
| int (*compar) (const FTSENT **, const FTSENT **)) |
| { |
| register FTS *sp; |
| register FTSENT *p, *root; |
| register int nitems; |
| FTSENT *parent, *tmp = NULL; |
| int len; |
| |
| |
| if (options & ~FTS_OPTIONMASK) { |
| __set_errno (EINVAL); |
| return (NULL); |
| } |
| |
| |
| if ((sp = malloc(sizeof(*sp))) == NULL) |
| return (NULL); |
| memset(sp, 0, sizeof(*sp)); |
| sp->fts_compar = (int (*) (const void *, const void *)) compar; |
| sp->fts_opendir = opendir; |
| sp->fts_readdir = readdir; |
| sp->fts_closedir = closedir; |
| sp->fts_stat = stat; |
| sp->fts_lstat = lstat; |
| sp->fts_options = options; |
| |
| |
| if (ISSET(FTS_LOGICAL)) |
| SET(FTS_NOCHDIR); |
| |
| |
| |
| |
| |
| |
| |
| |
| if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) |
| goto mem1; |
| |
| |
| if ((parent = fts_alloc(sp, "", 0)) == NULL) |
| goto mem2; |
| parent->fts_level = FTS_ROOTPARENTLEVEL; |
| |
| |
| for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { |
| |
| if ((len = strlen(*argv)) == 0) { |
| __set_errno (ENOENT); |
| goto mem3; |
| } |
| |
| p = fts_alloc(sp, *argv, len); |
| if (p == NULL) |
| goto mem3; |
| p->fts_level = FTS_ROOTLEVEL; |
| p->fts_parent = parent; |
| p->fts_accpath = p->fts_name; |
| p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); |
| |
| |
| if (p->fts_info == FTS_DOT) |
| p->fts_info = FTS_D; |
| |
| |
| |
| |
| |
| if (compar) { |
| p->fts_link = root; |
| root = p; |
| } else { |
| p->fts_link = NULL; |
| if (root == NULL) |
| tmp = root = p; |
| else { |
| if (tmp != NULL) |
| tmp->fts_link = p; |
| tmp = p; |
| } |
| } |
| } |
| if (compar && nitems > 1) |
| root = fts_sort(sp, root, nitems); |
| |
| |
| |
| |
| |
| |
| if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) |
| goto mem3; |
| sp->fts_cur->fts_link = root; |
| sp->fts_cur->fts_info = FTS_INIT; |
| |
| |
| |
| |
| |
| |
| |
| |
| if (!ISSET(FTS_NOCHDIR) |
| && (sp->fts_rfd = __open(".", O_RDONLY, 0)) < 0) |
| SET(FTS_NOCHDIR); |
| |
| return (sp); |
| |
| mem3: fts_lfree(root); |
| free(parent); |
| mem2: free(sp->fts_path); |
| mem1: free(sp); |
| return (NULL); |
| } |
| |
| static void |
| fts_load(FTS * sp, FTSENT * p) |
| { |
| register int len; |
| register char *cp; |
| |
| |
| |
| |
| |
| |
| |
| |
| len = p->fts_pathlen = p->fts_namelen; |
| memmove(sp->fts_path, p->fts_name, len + 1); |
| if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { |
| len = strlen(++cp); |
| memmove(p->fts_name, cp, len + 1); |
| p->fts_namelen = len; |
| } |
| p->fts_accpath = p->fts_path = sp->fts_path; |
| sp->fts_dev = p->fts_dev; |
| } |
| |
| int |
| Fts_close(FTS * sp) |
| { |
| register FTSENT *freep, *p; |
| int saved_errno; |
| |
| if (sp == NULL) |
| return 0; |
| |
| |
| |
| |
| |
| |
| if (sp->fts_cur) { |
| for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { |
| freep = p; |
| p = p->fts_link != NULL ? p->fts_link : p->fts_parent; |
| free(freep); |
| } |
| free(p); |
| } |
| |
| |
| if (sp->fts_child) |
| fts_lfree(sp->fts_child); |
| if (sp->fts_array) |
| free(sp->fts_array); |
| free(sp->fts_path); |
| |
| |
| if (!ISSET(FTS_NOCHDIR)) { |
| saved_errno = __fchdir(sp->fts_rfd) ? errno : 0; |
| (void)__close(sp->fts_rfd); |
| |
| |
| if (saved_errno != 0) { |
| |
| free(sp); |
| __set_errno (saved_errno); |
| return (-1); |
| } |
| } |
| |
| |
| free(sp); |
| return (0); |
| } |
| |
| |
| |
| |
| |
| |
| (p->fts_path[p->fts_pathlen - 1] == '/' \ |
| ? p->fts_pathlen - 1 : p->fts_pathlen) |
| |
| FTSENT * |
| Fts_read(FTS * sp) |
| { |
| register FTSENT *p; |
| register FTSENT *tmp; |
| register int instr; |
| register char *t; |
| int saved_errno; |
| |
| |
| if (sp == NULL || sp->fts_cur == NULL || ISSET(FTS_STOP)) |
| return (NULL); |
| |
| |
| p = sp->fts_cur; |
| |
| |
| instr = p->fts_instr; |
| p->fts_instr = FTS_NOINSTR; |
| |
| |
| if (instr == FTS_AGAIN) { |
| p->fts_info = fts_stat(sp, p, 0); |
| return (p); |
| } |
| |
| |
| |
| |
| |
| |
| |
| if (instr == FTS_FOLLOW && |
| (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { |
| p->fts_info = fts_stat(sp, p, 1); |
| if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { |
| if ((p->fts_symfd = __open(".", O_RDONLY, 0)) < 0) { |
| p->fts_errno = errno; |
| p->fts_info = FTS_ERR; |
| } else |
| p->fts_flags |= FTS_SYMFOLLOW; |
| } |
| return (p); |
| } |
| |
| |
| if (p->fts_info == FTS_D) { |
| |
| if (instr == FTS_SKIP || |
| (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { |
| if (p->fts_flags & FTS_SYMFOLLOW) |
| (void)__close(p->fts_symfd); |
| if (sp->fts_child) { |
| fts_lfree(sp->fts_child); |
| sp->fts_child = NULL; |
| } |
| p->fts_info = FTS_DP; |
| return (p); |
| } |
| |
| |
| if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { |
| CLR(FTS_NAMEONLY); |
| fts_lfree(sp->fts_child); |
| sp->fts_child = NULL; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if (sp->fts_child != NULL) { |
| if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { |
| p->fts_errno = errno; |
| p->fts_flags |= FTS_DONTCHDIR; |
| for (p = sp->fts_child; p != NULL; |
| p = p->fts_link) |
| p->fts_accpath = |
| p->fts_parent->fts_accpath; |
| } |
| } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { |
| if (ISSET(FTS_STOP)) |
| return (NULL); |
| return (p); |
| } |
| p = sp->fts_child; |
| sp->fts_child = NULL; |
| goto name; |
| } |
| |
| |
| next: tmp = p; |
| if ((p = p->fts_link) != NULL) { |
| free(tmp); |
| |
| |
| |
| |
| |
| if (p->fts_level == FTS_ROOTLEVEL) { |
| if (FCHDIR(sp, sp->fts_rfd)) { |
| SET(FTS_STOP); |
| return (NULL); |
| } |
| fts_load(sp, p); |
| return (sp->fts_cur = p); |
| } |
| |
| |
| |
| |
| |
| |
| if (p->fts_instr == FTS_SKIP) |
| goto next; |
| if (p->fts_instr == FTS_FOLLOW) { |
| p->fts_info = fts_stat(sp, p, 1); |
| if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { |
| if ((p->fts_symfd = |
| __open(".", O_RDONLY, 0)) < 0) { |
| p->fts_errno = errno; |
| p->fts_info = FTS_ERR; |
| } else |
| p->fts_flags |= FTS_SYMFOLLOW; |
| } |
| p->fts_instr = FTS_NOINSTR; |
| } |
| |
| name: t = sp->fts_path + NAPPEND(p->fts_parent); |
| *t++ = '/'; |
| memmove(t, p->fts_name, p->fts_namelen + 1); |
| return (sp->fts_cur = p); |
| } |
| |
| |
| p = tmp->fts_parent; |
| free(tmp); |
| |
| if (p->fts_level == FTS_ROOTPARENTLEVEL) { |
| |
| |
| |
| |
| free(p); |
| __set_errno (0); |
| return (sp->fts_cur = NULL); |
| } |
| |
| |
| sp->fts_path[p->fts_pathlen] = '\0'; |
| |
| |
| |
| |
| |
| |
| if (p->fts_level == FTS_ROOTLEVEL) { |
| if (FCHDIR(sp, sp->fts_rfd)) { |
| SET(FTS_STOP); |
| return (NULL); |
| } |
| } else if (p->fts_flags & FTS_SYMFOLLOW) { |
| if (FCHDIR(sp, p->fts_symfd)) { |
| saved_errno = errno; |
| (void)__close(p->fts_symfd); |
| __set_errno (saved_errno); |
| SET(FTS_STOP); |
| return (NULL); |
| } |
| (void)__close(p->fts_symfd); |
| } else if (!(p->fts_flags & FTS_DONTCHDIR) && |
| fts_safe_changedir(sp, p->fts_parent, -1, "..")) { |
| SET(FTS_STOP); |
| return (NULL); |
| } |
| p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; |
| return (sp->fts_cur = p); |
| } |
| |
| |
| |
| |
| |
| |
| |
| int |
| Fts_set(FTS * sp, FTSENT * p, int instr) |
| { |
| if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && |
| instr != FTS_NOINSTR && instr != FTS_SKIP) { |
| __set_errno (EINVAL); |
| return (1); |
| } |
| p->fts_instr = instr; |
| return (0); |
| } |
| |
| FTSENT * |
| Fts_children(FTS * sp, int instr) |
| { |
| register FTSENT *p; |
| int fd; |
| |
| if (instr != 0 && instr != FTS_NAMEONLY) { |
| __set_errno (EINVAL); |
| return (NULL); |
| } |
| |
| |
| p = sp->fts_cur; |
| |
| |
| |
| |
| |
| __set_errno (0); |
| |
| |
| if (ISSET(FTS_STOP)) |
| return (NULL); |
| |
| |
| if (p->fts_info == FTS_INIT) |
| return (p->fts_link); |
| |
| |
| |
| |
| |
| |
| if (p->fts_info != FTS_D ) |
| return (NULL); |
| |
| |
| if (sp->fts_child != NULL) |
| fts_lfree(sp->fts_child); |
| |
| if (instr == FTS_NAMEONLY) { |
| SET(FTS_NAMEONLY); |
| instr = BNAMES; |
| } else |
| instr = BCHILD; |
| |
| |
| |
| |
| |
| |
| |
| |
| if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || |
| ISSET(FTS_NOCHDIR)) |
| return (sp->fts_child = fts_build(sp, instr)); |
| |
| if ((fd = __open(".", O_RDONLY, 0)) < 0) |
| return (NULL); |
| sp->fts_child = fts_build(sp, instr); |
| if (__fchdir(fd)) |
| return (NULL); |
| (void)__close(fd); |
| return (sp->fts_child); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static FTSENT * |
| fts_build(FTS * sp, int type) |
| { |
| register struct dirent *dp; |
| register FTSENT *p, *head; |
| register int nitems; |
| FTSENT *cur, *tail; |
| DIR *dirp; |
| void *oldaddr; |
| int cderrno, descend, len, level, maxlen, nlinks, saved_errno, |
| nostat, doadjust; |
| char *cp; |
| |
| |
| cur = sp->fts_cur; |
| |
| |
| |
| |
| |
| |
| if (ISSET(FTS_WHITEOUT)) |
| oflag = DTF_NODUP|DTF_REWIND; |
| else |
| oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; |
| |
| |
| |
| if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { |
| if (type == BREAD) { |
| cur->fts_info = FTS_DNR; |
| cur->fts_errno = errno; |
| } |
| return (NULL); |
| } |
| |
| |
| |
| |
| |
| |
| if (type == BNAMES) { |
| nlinks = 0; |
| |
| nostat = 0; |
| } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { |
| nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); |
| nostat = 1; |
| } else { |
| nlinks = -1; |
| nostat = 0; |
| } |
| |
| |
| (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); |
| (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", |
| ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| cderrno = 0; |
| if (nlinks || type == BREAD) { |
| if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { |
| if (nlinks && type == BREAD) |
| cur->fts_errno = errno; |
| cur->fts_flags |= FTS_DONTCHDIR; |
| descend = 0; |
| cderrno = errno; |
| (void) (*sp->fts_closedir) (dirp); |
| dirp = NULL; |
| } else |
| descend = 1; |
| } else |
| descend = 0; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| len = NAPPEND(cur); |
| if (ISSET(FTS_NOCHDIR)) { |
| cp = sp->fts_path + len; |
| *cp++ = '/'; |
| } else { |
| |
| cp = NULL; |
| } |
| len++; |
| maxlen = sp->fts_pathlen - len; |
| |
| level = cur->fts_level + 1; |
| |
| |
| doadjust = 0; |
| for (head = tail = NULL, nitems = 0; |
| dirp && (dp = (*sp->fts_readdir) (dirp));) |
| { |
| if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) |
| continue; |
| |
| if ((p = fts_alloc(sp, dp->d_name, (int)_D_EXACT_NAMLEN (dp))) == NULL) |
| goto mem1; |
| if (_D_EXACT_NAMLEN (dp) >= maxlen) { |
| oldaddr = sp->fts_path; |
| if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) { |
| |
| |
| |
| |
| |
| mem1: saved_errno = errno; |
| if (p) |
| free(p); |
| fts_lfree(head); |
| (void) (*sp->fts_closedir) (dirp); |
| cur->fts_info = FTS_ERR; |
| SET(FTS_STOP); |
| __set_errno (saved_errno); |
| return (NULL); |
| } |
| |
| if (oldaddr != sp->fts_path) { |
| doadjust = 1; |
| if (ISSET(FTS_NOCHDIR)) |
| cp = sp->fts_path + len; |
| } |
| maxlen = sp->fts_pathlen - len; |
| } |
| |
| if (len + _D_EXACT_NAMLEN (dp) >= UINT16_MAX) { |
| |
| |
| |
| |
| |
| |
| free(p); |
| fts_lfree(head); |
| (void) (*sp->fts_closedir) (dirp); |
| cur->fts_info = FTS_ERR; |
| SET(FTS_STOP); |
| __set_errno (ENAMETOOLONG); |
| return (NULL); |
| } |
| p->fts_level = level; |
| p->fts_parent = sp->fts_cur; |
| p->fts_pathlen = len + _D_EXACT_NAMLEN (dp); |
| |
| |
| if (dp->d_type == DT_WHT) |
| p->fts_flags |= FTS_ISW; |
| |
| |
| if (cderrno) { |
| if (nlinks) { |
| p->fts_info = FTS_NS; |
| p->fts_errno = cderrno; |
| } else |
| p->fts_info = FTS_NSOK; |
| p->fts_accpath = cur->fts_accpath; |
| } else if (nlinks == 0 |
| |
| || (nostat && |
| dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) |
| |
| ) { |
| p->fts_accpath = |
| ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; |
| p->fts_info = FTS_NSOK; |
| } else { |
| |
| if (ISSET(FTS_NOCHDIR)) { |
| p->fts_accpath = p->fts_path; |
| memmove(cp, p->fts_name, p->fts_namelen + 1); |
| } else |
| p->fts_accpath = p->fts_name; |
| |
| p->fts_info = fts_stat(sp, p, 0); |
| |
| |
| if (nlinks > 0 && (p->fts_info == FTS_D || |
| p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) |
| --nlinks; |
| } |
| |
| |
| p->fts_link = NULL; |
| if (head == NULL) |
| head = tail = p; |
| else { |
| tail->fts_link = p; |
| tail = p; |
| } |
| ++nitems; |
| } |
| if (dirp) |
| (void) (*sp->fts_closedir) (dirp); |
| |
| |
| |
| |
| |
| if (doadjust) |
| fts_padjust(sp, head); |
| |
| |
| |
| |
| |
| if (ISSET(FTS_NOCHDIR)) { |
| if (len == sp->fts_pathlen || nitems == 0) |
| --cp; |
| if (cp != NULL) |
| *cp = '\0'; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| if (descend && (type == BCHILD || !nitems) && |
| (cur->fts_level == FTS_ROOTLEVEL ? |
| FCHDIR(sp, sp->fts_rfd) : |
| fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { |
| cur->fts_info = FTS_ERR; |
| SET(FTS_STOP); |
| return (NULL); |
| } |
| |
| |
| if (!nitems) { |
| if (type == BREAD) |
| cur->fts_info = FTS_DP; |
| return (NULL); |
| } |
| |
| |
| if (sp->fts_compar && nitems > 1) |
| head = fts_sort(sp, head, nitems); |
| return (head); |
| } |
| |
| static uint16_t |
| fts_stat(FTS * sp, FTSENT * p, int follow) |
| { |
| register FTSENT *t; |
| register dev_t dev; |
| register ino_t ino; |
| struct stat *sbp, sb; |
| int saved_errno; |
| |
| |
| sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; |
| |
| |
| |
| if (p->fts_flags & FTS_ISW) { |
| if (sbp != &sb) { |
| memset(sbp, '\0', sizeof (*sbp)); |
| sbp->st_mode = S_IFWHT; |
| } |
| return (FTS_W); |
| } |
| |
| |
| |
| |
| |
| |
| |
| if (ISSET(FTS_LOGICAL) || follow) { |
| if ((*sp->fts_stat) (p->fts_accpath, sbp)) { |
| saved_errno = errno; |
| if (!(*sp->fts_lstat) (p->fts_accpath, sbp)) { |
| __set_errno (0); |
| return (FTS_SLNONE); |
| } |
| p->fts_errno = saved_errno; |
| goto err; |
| } |
| } else if ((*sp->fts_lstat) (p->fts_accpath, sbp)) { |
| p->fts_errno = errno; |
| err: memset(sbp, 0, sizeof(*sbp)); |
| return (FTS_NS); |
| } |
| |
| if (S_ISDIR(sbp->st_mode)) { |
| |
| |
| |
| |
| |
| |
| |
| dev = p->fts_dev = sbp->st_dev; |
| ino = p->fts_ino = sbp->st_ino; |
| p->fts_nlink = sbp->st_nlink; |
| |
| if (ISDOT(p->fts_name)) |
| return (FTS_DOT); |
| |
| |
| |
| |
| |
| |
| |
| for (t = p->fts_parent; |
| t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) |
| if (ino == t->fts_ino && dev == t->fts_dev) { |
| p->fts_cycle = t; |
| return (FTS_DC); |
| } |
| return (FTS_D); |
| } |
| if (S_ISLNK(sbp->st_mode)) |
| return (FTS_SL); |
| if (S_ISREG(sbp->st_mode)) |
| return (FTS_F); |
| return (FTS_DEFAULT); |
| } |
| |
| static FTSENT * |
| fts_sort(FTS * sp, FTSENT * head, int nitems) |
| { |
| register FTSENT **ap, *p; |
| |
| |
| |
| |
| |
| |
| |
| |
| if (nitems > sp->fts_nitems) { |
| struct _ftsent **a; |
| |
| sp->fts_nitems = nitems + 40; |
| if ((a = realloc(sp->fts_array, |
| (size_t)(sp->fts_nitems * sizeof(*sp->fts_array)))) == NULL) |
| { |
| free(sp->fts_array); |
| sp->fts_array = NULL; |
| sp->fts_nitems = 0; |
| return (head); |
| } |
| sp->fts_array = a; |
| } |
| for (ap = sp->fts_array, p = head; p != NULL; p = p->fts_link) |
| *ap++ = p; |
| qsort((void *)sp->fts_array, nitems, sizeof(*sp->fts_array), |
| sp->fts_compar); |
| for (head = *(ap = sp->fts_array); --nitems; ++ap) |
| ap[0]->fts_link = ap[1]; |
| ap[0]->fts_link = NULL; |
| return (head); |
| } |
| |
| static FTSENT * |
| fts_alloc(FTS * sp, const char * name, int namelen) |
| { |
| register FTSENT *p; |
| size_t len; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| len = sizeof(*p) + namelen; |
| if (!ISSET(FTS_NOSTAT)) |
| len += sizeof(*p->fts_statp) + ALIGNBYTES; |
| if ((p = malloc(len)) == NULL) |
| return (NULL); |
| |
| |
| memmove(p->fts_name, name, namelen); |
| p->fts_name[namelen] = '\0'; |
| |
| if (!ISSET(FTS_NOSTAT)) |
| p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); |
| p->fts_namelen = namelen; |
| p->fts_path = sp->fts_path; |
| p->fts_errno = 0; |
| p->fts_flags = 0; |
| p->fts_instr = FTS_NOINSTR; |
| p->fts_number = 0; |
| p->fts_pointer = NULL; |
| return (p); |
| } |
| |
| static void |
| fts_lfree(FTSENT * head) |
| { |
| register FTSENT *p; |
| |
| |
| while ((p = head)) { |
| head = head->fts_link; |
| free(p); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| static int |
| fts_palloc(FTS * sp, size_t more) |
| { |
| char *p; |
| |
| sp->fts_pathlen += more + 256; |
| |
| |
| |
| |
| |
| if (sp->fts_pathlen < 0 || sp->fts_pathlen >= UINT16_MAX) { |
| if (sp->fts_path) { |
| free(sp->fts_path); |
| sp->fts_path = NULL; |
| } |
| sp->fts_path = NULL; |
| __set_errno (ENAMETOOLONG); |
| return (1); |
| } |
| p = realloc(sp->fts_path, sp->fts_pathlen); |
| if (p == NULL) { |
| free(sp->fts_path); |
| sp->fts_path = NULL; |
| return 1; |
| } |
| sp->fts_path = p; |
| return 0; |
| } |
| |
| |
| |
| |
| |
| static void |
| fts_padjust(FTS * sp, FTSENT * head) |
| { |
| FTSENT *p; |
| char *addr = sp->fts_path; |
| |
| |
| if ((p)->fts_accpath != (p)->fts_name) { \ |
| (p)->fts_accpath = \ |
| (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ |
| } \ |
| (p)->fts_path = addr; \ |
| } while (0) |
| |
| for (p = sp->fts_child; p != NULL; p = p->fts_link) |
| ADJUST(p); |
| |
| |
| for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { |
| ADJUST(p); |
| p = p->fts_link ? p->fts_link : p->fts_parent; |
| } |
| } |
| |
| static size_t |
| fts_maxarglen(char * const * argv) |
| { |
| size_t len, max; |
| |
| for (max = 0; *argv; ++argv) |
| if ((len = strlen(*argv)) > max) |
| max = len; |
| return (max + 1); |
| } |
| |
| |
| |
| |
| |
| |
| static int |
| fts_safe_changedir(FTS * sp, FTSENT * p, int fd, const char * path) |
| { |
| int ret, oerrno, newfd; |
| struct stat64 sb; |
| |
| newfd = fd; |
| if (ISSET(FTS_NOCHDIR)) |
| return (0); |
| if (fd < 0 && (newfd = __open(path, O_RDONLY, 0)) < 0) |
| return (-1); |
| if (FTS_FSTAT64(newfd, &sb)) { |
| ret = -1; |
| goto bail; |
| } |
| if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { |
| __set_errno (ENOENT); |
| ret = -1; |
| goto bail; |
| } |
| ret = __fchdir(newfd); |
| bail: |
| oerrno = errno; |
| if (fd < 0) |
| (void)__close(newfd); |
| __set_errno (oerrno); |
| return (ret); |
| } |