Annotation of 43BSDReno/lib/libc/gen/fts.c, revision 1.1.1.1

1.1       root        1: /*-
                      2:  * Copyright (c) 1990 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted provided
                      6:  * that: (1) source distributions retain this entire copyright notice and
                      7:  * comment, and (2) distributions including binaries display the following
                      8:  * acknowledgement:  ``This product includes software developed by the
                      9:  * University of California, Berkeley and its contributors'' in the
                     10:  * documentation or other materials provided with the distribution and in
                     11:  * all advertising materials mentioning features or use of this software.
                     12:  * Neither the name of the University nor the names of its contributors may
                     13:  * be used to endorse or promote products derived from this software without
                     14:  * specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #if defined(LIBC_SCCS) && !defined(lint)
                     21: static char sccsid[] = "@(#)fts.c      5.10 (Berkeley) 6/9/90";
                     22: #endif /* LIBC_SCCS and not lint */
                     23: 
                     24: #include <sys/param.h>
                     25: #include <sys/stat.h>
                     26: #include <fcntl.h>
                     27: #include <dirent.h>
                     28: #include <errno.h>
                     29: #include <fts.h>
                     30: #include <string.h>
                     31: #include <stdlib.h>
                     32: 
                     33: FTSENT *fts_alloc(), *fts_build(), *fts_cycle(), *fts_sort(), *fts_root();
                     34: short fts_stat();
                     35: 
                     36: /*
                     37:  * Special case a root of "/" so that slashes aren't appended causing
                     38:  * paths to be written as "//foo".
                     39:  */
                     40: #define        NAPPEND(p) \
                     41:        (p->fts_level == ROOTLEVEL && p->fts_pathlen == 1 && \
                     42:            p->fts_path[0] == '/' ? 0 : p->fts_pathlen)
                     43: 
                     44: #define        CHDIR(sp, path) (!(sp->fts_options & FTS_NOCHDIR) && chdir(path))
                     45: #define        FCHDIR(sp, fd)  (!(sp->fts_options & FTS_NOCHDIR) && fchdir(fd))
                     46: 
                     47: #define        ROOTLEVEL       0
                     48: #define        ROOTPARENTLEVEL -1
                     49: 
                     50: /* fts_build flags */
                     51: #define        BCHILD          1               /* from ftschildren */
                     52: #define        BREAD           2               /* from ftsread */
                     53: 
                     54: static FTS *stream;                    /* current stream pointer */
                     55: 
                     56: FTS *
                     57: ftsopen(argv, options, compar)
                     58:        char *argv[];
                     59:        register int options;
                     60:        int (*compar)();
                     61: {
                     62:        register FTS *sp;
                     63:        register FTSENT *p, *root;
                     64:        register int nitems, maxlen;
                     65:        FTSENT *parent, *tmp;
                     66:        char *fts_path();
                     67: 
                     68:        /* allocate/initialize the stream */
                     69:        if (!(stream = sp = (FTS *)malloc((u_int)sizeof(FTS))))
                     70:                return(NULL);
                     71:        bzero(sp, sizeof(FTS));
                     72:        sp->fts_compar = compar;
                     73: 
                     74:        /*
                     75:         * logical walks turn on NOCHDIR; symbolic links are just too
                     76:         * hard to deal with.
                     77:         */
                     78:        sp->fts_options = options;
                     79:        if (options & FTS_LOGICAL)
                     80:                sp->fts_options |= FTS_NOCHDIR;
                     81: 
                     82:        /* allocate/initialize root's parent */
                     83:        if (!(parent = fts_alloc("", 0)))
                     84:                goto mem1;
                     85:        parent->fts_level = ROOTPARENTLEVEL;
                     86: 
                     87:        /* allocate/initialize root(s) */
                     88:        maxlen = -1;
                     89:        for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
                     90:                if (!(p = fts_root(*argv)))
                     91:                        goto mem2;
                     92:                if (maxlen < p->fts_namelen)
                     93:                        maxlen = p->fts_namelen;
                     94:                /*
                     95:                 * if comparison routine supplied, traverse in sorted
                     96:                 * order; otherwise traverse in the order specified.
                     97:                 */
                     98:                if (compar) {
                     99:                        p->fts_link = root;
                    100:                        root = p;
                    101:                        p->fts_accpath = p->fts_name;
                    102:                        if (!(options & FTS_NOSTAT))
                    103:                                p->fts_info = fts_stat(p, 0);
                    104:                } else {
                    105:                        p->fts_link = NULL;
                    106:                        if (!root)
                    107:                                tmp = root = p;
                    108:                        else {
                    109:                                tmp->fts_link = p;
                    110:                                tmp = p;
                    111:                        }
                    112:                }
                    113:                p->fts_level = ROOTLEVEL;
                    114:                p->fts_parent = parent;
                    115:        }
                    116:        if (compar && nitems > 1)
                    117:                root = fts_sort(root, nitems);
                    118: 
                    119:        /*
                    120:         * allocate a dummy pointer and make ftsread think that we've just
                    121:         * finished the node before the root(s); set p->fts_info to FTS_NS
                    122:         * so that everything about the "current" node is ignored.
                    123:         */
                    124:        if (!(sp->fts_cur = fts_alloc("", 0)))
                    125:                goto mem2;
                    126:        sp->fts_cur->fts_link = root;
                    127:        sp->fts_cur->fts_info = FTS_NS;
                    128: 
                    129:        /* start out with at least 1K+ of path space */
                    130:        if (!fts_path(MAX(maxlen, MAXPATHLEN)))
                    131:                goto mem3;
                    132: 
                    133:        /*
                    134:         * if using chdir(2), grab a file descriptor pointing to dot to insure
                    135:         * that we can get back here; this could be avoided for some paths,
                    136:         * but almost certainly not worth the effort.  Slashes, symbolic links,
                    137:         * and ".." are all fairly nasty problems.  Note, if we can't get the
                    138:         * descriptor we run anyway, just more slowly.
                    139:         */
                    140:        if (!(options & FTS_NOCHDIR) &&
                    141:            (sp->fts_sd = open(".", O_RDONLY, 0)) < 0)
                    142:                sp->fts_options |= FTS_NOCHDIR;
                    143: 
                    144:        return(sp);
                    145: 
                    146: mem3:  (void)free((void *)sp->fts_cur);
                    147: mem2:  fts_lfree(root);
                    148:        (void)free((void *)parent);
                    149: mem1:  (void)free((void *)sp);
                    150:        return(NULL);
                    151: }
                    152: 
                    153: static
                    154: fts_load(p)
                    155:        register FTSENT *p;
                    156: {
                    157:        register int len;
                    158:        register char *cp;
                    159: 
                    160:        /*
                    161:         * load the stream structure for the next traversal; set the
                    162:         * accpath field specially so the chdir gets done to the right
                    163:         * place and the user can access the first node.
                    164:         */
                    165:        len = p->fts_pathlen = p->fts_namelen;
                    166:        bcopy(p->fts_name, stream->fts_path, len + 1);
                    167:        if ((cp = rindex(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
                    168:                len = strlen(++cp);
                    169:                bcopy(cp, p->fts_name, len + 1);
                    170:                p->fts_namelen = len;
                    171:        }
                    172:        p->fts_accpath = p->fts_path = stream->fts_path;
                    173: }
                    174: 
                    175: ftsclose(sp)
                    176:        FTS *sp;
                    177: {
                    178:        register FTSENT *freep, *p;
                    179:        int saved_errno;
                    180: 
                    181:        if (sp->fts_cur) {
                    182:                /*
                    183:                 * this still works if we haven't read anything -- the dummy
                    184:                 * structure points to the root list, so we step through to
                    185:                 * the end of the root list which has a valid parent pointer.
                    186:                 */
                    187:                for (p = sp->fts_cur; p->fts_level > ROOTPARENTLEVEL;) {
                    188:                        freep = p;
                    189:                        p = p->fts_link ? p->fts_link : p->fts_parent;
                    190:                        (void)free((void *)freep);
                    191:                }
                    192:                (void)free((void *)p);
                    193:        }
                    194: 
                    195:        /* free up child linked list, sort array, path buffer */
                    196:        if (sp->fts_child)
                    197:                fts_lfree(sp->fts_child);
                    198:        if (sp->fts_array)
                    199:                (void)free((void *)sp->fts_array);
                    200:        (void)free((char *)sp->fts_path);
                    201: 
                    202:        /*
                    203:         * return to original directory, save errno if necessary;
                    204:         * free up the directory buffer
                    205:         */
                    206:        if (!(sp->fts_options & FTS_NOCHDIR)) {
                    207:                saved_errno = fchdir(sp->fts_sd) ? errno : 0;
                    208:                (void)close(sp->fts_sd);
                    209:        }
                    210: 
                    211:        /* free up the stream pointer */
                    212:        (void)free((void *)sp);
                    213: 
                    214:        /* set errno and return */
                    215:        if (!(sp->fts_options & FTS_NOCHDIR) && saved_errno) {
                    216:                errno = saved_errno;
                    217:                return(-1);
                    218:        }
                    219:        return(0);
                    220: }
                    221: 
                    222: FTSENT *
                    223: ftsread(sp)
                    224:        register FTS *sp;
                    225: {
                    226:        register FTSENT *p, *tmp;
                    227:        register int instr;
                    228:        register char *cp;
                    229:        static int cd;
                    230: 
                    231:        /* if finished or unrecoverable error, return NULL */
                    232:        if (!sp->fts_cur || sp->fts_options & FTS__STOP)
                    233:                return(NULL);
                    234: 
                    235:        /* set global stream pointer, and current node pointer */
                    236:        stream = sp;
                    237:        p = sp->fts_cur;
                    238: 
                    239:        /* save and zero out user instructions */
                    240:        instr = p->fts_instr;
                    241:        p->fts_instr = 0;
                    242: 
                    243:        /* if used link pointer for cycle detection, restore it */
                    244:        if (sp->fts_savelink) {
                    245:                p->fts_link = sp->fts_savelink;
                    246:                sp->fts_savelink = NULL;
                    247:        }
                    248: 
                    249:        /* any type of file may be re-visited; re-stat and return */
                    250:        if (instr == FTS_AGAIN) {
                    251:                p->fts_info = fts_stat(p, 0);
                    252:                return(p);
                    253:        }
                    254: 
                    255:        /* following a symbolic link */
                    256:        if (p->fts_info == FTS_SL && instr == FTS_FOLLOW) {
                    257:                p->fts_info = fts_stat(p, 1);
                    258:                return(p);
                    259:        }
                    260: 
                    261:        /* directory in pre-order */
                    262:        if (p->fts_info == FTS_D) {
                    263:                /* if skipped or crossed mount point, do post-order visit */
                    264:                if (instr == FTS_SKIP || sp->fts_options & FTS_XDEV &&
                    265:                    p->fts_statb.st_dev != sp->sdev) {
                    266:                        if (sp->fts_child) {
                    267:                                fts_lfree(sp->fts_child);
                    268:                                sp->fts_child = NULL;
                    269:                        }
                    270:                        p->fts_info = FTS_DP;
                    271:                        return(p);
                    272:                } 
                    273: 
                    274:                /* read the directory if necessary, and return first entry */
                    275:                if (sp->fts_child) 
                    276:                        if (CHDIR(sp, p->fts_accpath)) {
                    277:                                fts_lfree(sp->fts_child);
                    278:                                p->fts_info = FTS_DNX;
                    279:                        } else {
                    280:                                p = sp->fts_child;
                    281:                                cp = sp->fts_path + NAPPEND(p->fts_parent);
                    282:                                *cp++ = '/';
                    283:                                bcopy(p->fts_name, cp, p->fts_namelen + 1);
                    284:                        }
                    285:                else {
                    286:                        if (!(sp->fts_child = fts_build(sp, BREAD)))
                    287:                                return(p);
                    288:                        p = sp->fts_child;
                    289:                }
                    290:                sp->fts_child = NULL;
                    291:                return(sp->fts_cur = p);
                    292:        }
                    293: 
                    294:        /* move to next node on this level */
                    295: next:  tmp = p;
                    296:        if (p = p->fts_link) {
                    297:                /*
                    298:                 * if root level node, set up paths and return.  If not the
                    299:                 * first time, and it's not an absolute pathname, get back
                    300:                 * to starting directory.
                    301:                 */
                    302:                if (p->fts_level == ROOTLEVEL) {
                    303:                        fts_load(p);
                    304:                        (void)free((void *)tmp);
                    305:                        if (cd &&
                    306:                            p->fts_path[0] != '/' && FCHDIR(sp, sp->fts_sd)) {
                    307:                                /* should never happen... */
                    308:                                p->fts_path = "starting directory";
                    309:                                p->fts_info = FTS_ERR;
                    310:                                sp->fts_options |= FTS__STOP;
                    311:                                return(sp->fts_cur = p);
                    312:                        } 
                    313:                        cd = 1;
                    314:                        p->fts_info = fts_stat(p, 0);
                    315:                        sp->sdev = p->fts_statb.st_dev;
                    316:                } else {
                    317:                        (void)free((void *)tmp);
                    318: 
                    319:                        /* user may have called ftsset on node */
                    320:                        if (p->fts_instr == FTS_SKIP)
                    321:                                goto next;
                    322:                        if (p->fts_instr == FTS_FOLLOW) {
                    323:                                p->fts_info = fts_stat(p, 1);
                    324:                                p->fts_instr = 0;
                    325:                        }
                    326: 
                    327:                        /* fill in the paths */
                    328:                        cp = sp->fts_path + NAPPEND(p->fts_parent);
                    329:                        *cp++ = '/';
                    330:                        bcopy(p->fts_name, cp, p->fts_namelen + 1);
                    331: 
                    332:                        /* check for directory cycles */
                    333:                        if (p->fts_info == FTS_D && (tmp = fts_cycle(p))) {
                    334:                                sp->fts_savelink = p->fts_link;
                    335:                                p->fts_link = tmp;
                    336:                                p->fts_info = FTS_DC;
                    337:                        }
                    338:                }
                    339:                return(sp->fts_cur = p);
                    340:        }
                    341: 
                    342:        /* move to parent */
                    343:        p = tmp->fts_parent;
                    344:        (void)free((void *)tmp);
                    345: 
                    346:        if (p->fts_level == ROOTPARENTLEVEL) {
                    347:                /*
                    348:                 * done; free everything up and set errno to 0 so the user
                    349:                 * can distinguish between error and EOF.
                    350:                 */
                    351:                (void)free((void *)p);
                    352:                errno = 0;
                    353:                return(sp->fts_cur = NULL);
                    354:        }
                    355: 
                    356:        sp->fts_path[p->fts_pathlen] = '\0';
                    357:        if (CHDIR(sp, "..")) {
                    358:                sp->fts_options |= FTS__STOP;
                    359:                p->fts_info = FTS_ERR;
                    360:        } else
                    361:                p->fts_info = FTS_DP;
                    362:        return(sp->fts_cur = p);
                    363: }
                    364: 
                    365: /*
                    366:  * ftsset takes the stream as an argument although it's not used in this
                    367:  * implementation; it would be necessary if anyone wanted to add global
                    368:  * semantics to fts using ftsset.  A possible error return is allowed for
                    369:  * similar reasons.
                    370:  */
                    371: /* ARGSUSED */
                    372: ftsset(sp, p, instr)
                    373:        FTS *sp;
                    374:        FTSENT *p;
                    375:        int instr;
                    376: {
                    377:        p->fts_instr = instr;
                    378:        return(0);
                    379: }
                    380: 
                    381: FTSENT *
                    382: ftschildren(sp)
                    383:        register FTS *sp;
                    384: {
                    385:        register FTSENT *p;
                    386:        int fd;
                    387: 
                    388:        /*
                    389:         * set errno to 0 so that user can tell the difference between an
                    390:         * error and a directory without entries.
                    391:         */
                    392:        errno = 0;
                    393:        p = sp->fts_cur;
                    394:        if (p->fts_info != FTS_D || sp->fts_options & FTS__STOP)
                    395:                return(NULL);
                    396:        if (sp->fts_child)
                    397:                fts_lfree(sp->fts_child);
                    398: 
                    399:        /*
                    400:         * if using chdir on a relative path and called BEFORE ftsread on the
                    401:         * root of a traversal, we can lose because we need to chdir into the
                    402:         * subdirectory, and we don't know where the current directory is to
                    403:         * get back so that the upcoming chdir by ftsread will work.
                    404:         */
                    405:        if (p->fts_level != ROOTLEVEL || p->fts_accpath[0] == '/' ||
                    406:            sp->fts_options & FTS_NOCHDIR)
                    407:                return(sp->fts_child = fts_build(sp, BCHILD));
                    408: 
                    409:        if ((fd = open(".", O_RDONLY, 0)) < 0)
                    410:                return(NULL);
                    411:        sp->fts_child = fts_build(sp, BCHILD);
                    412:        if (fchdir(fd))
                    413:                return(NULL);
                    414:        (void)close(fd);
                    415:        return(sp->fts_child);
                    416: }
                    417: 
                    418: #define        ISDOT(a)        (a[0] == '.' && (!a[1] || a[1] == '.' && !a[2]))
                    419: 
                    420: FTSENT *
                    421: fts_build(sp, type)
                    422:        register FTS *sp;
                    423:        int type;
                    424: {
                    425:        register struct dirent *dp;
                    426:        register FTSENT *p, *head;
                    427:        register int nitems;
                    428:        DIR *dirp;
                    429:        int descend, len, level, maxlen, nlinks, saved_errno;
                    430:        char *cp;
                    431: 
                    432:        p = sp->fts_cur;
                    433:        if (!(dirp = opendir(p->fts_accpath))) {
                    434:                if (type == BREAD) {
                    435:                        errno = 0;
                    436:                        p->fts_info = FTS_DNR;
                    437:                }
                    438:                return(NULL);
                    439:        }
                    440: 
                    441:        /*
                    442:         * the real slowdown in walking the tree is the stat calls.  If
                    443:         * FTS_NOSTAT is set and it's a physical walk (so that symbolic
                    444:         * links can't be directories), fts assumes that the number of
                    445:         * subdirectories in a node is equal to the number of links to
                    446:         * the parent.  This allows stat calls to be skipped in any leaf
                    447:         * directories and for any nodes after the directories in the
                    448:         * parent node have been found.  This empirically cuts the stat
                    449:         * calls by about 2/3.
                    450:         */
                    451:        nlinks =
                    452:            sp->fts_options & FTS_NOSTAT && sp->fts_options & FTS_PHYSICAL ?
                    453:            p->fts_statb.st_nlink - (sp->fts_options & FTS_SEEDOT ? 0 : 2) : -1;
                    454: 
                    455:        /* if told to descend or found links and not told not to descend. */
                    456:        if (nlinks || type == BREAD) {
                    457:                if (FCHDIR(sp, dirfd(dirp))) {
                    458:                        if (type == BREAD) {
                    459:                                errno = 0;
                    460:                                p->fts_info = FTS_DNX;
                    461:                        }
                    462:                        (void)closedir(dirp);
                    463:                        return(NULL);
                    464:                }
                    465:                descend = 1;
                    466:        } else
                    467:                descend = 0;
                    468: 
                    469:        /* get max file name length that can be stored in current path */
                    470:        maxlen = sp->fts_pathlen - p->fts_pathlen - 1;
                    471: 
                    472:        cp = sp->fts_path + (len = NAPPEND(p));
                    473:        *cp++ = '/';
                    474: 
                    475:        level = p->fts_level + 1;
                    476: 
                    477:        /* read the directory, attching each new entry to the `link' pointer */
                    478:        for (head = NULL, nitems = 0; dp = readdir(dirp);) {
                    479:                if (ISDOT(dp->d_name) && !(sp->fts_options & FTS_SEEDOT))
                    480:                        continue;
                    481: 
                    482:                if (!(p = fts_alloc(dp->d_name, dp->d_namlen))) {
                    483:                        saved_errno = errno;
                    484:                        goto mem1;
                    485:                }
                    486:                if (dp->d_namlen > maxlen) {
                    487:                        if (!fts_path((int)dp->d_namlen)) {
                    488:                                /* quit: this stream no longer has a path */
                    489:                                sp->fts_options |= FTS__STOP;
                    490:                                saved_errno = errno;
                    491:                                (void)free((void *)p);
                    492: mem1:                          fts_lfree(head);
                    493:                                if (type == BREAD)
                    494:                                        p->fts_info = FTS_ERR;
                    495:                                if (descend && CHDIR(sp, "..")) {
                    496:                                        saved_errno = errno;
                    497:                                        sp->fts_options |= FTS__STOP;
                    498:                                }
                    499:                                errno = saved_errno;
                    500:                                (void)closedir(dirp);
                    501:                                return(NULL);
                    502:                        }
                    503:                        maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1;
                    504:                }
                    505: 
                    506:                p->fts_pathlen = len + dp->d_namlen + 1;
                    507:                p->fts_accpath =
                    508:                    sp->fts_options & FTS_NOCHDIR ? p->fts_path : p->fts_name;
                    509: 
                    510:                p->fts_parent = sp->fts_cur;
                    511:                p->fts_level = level;
                    512: 
                    513:                if (nlinks) {
                    514:                        /* make sure fts_stat has a filename to stat */
                    515:                        if (sp->fts_options & FTS_NOCHDIR)
                    516:                                bcopy(p->fts_name, cp, p->fts_namelen + 1);
                    517:                        p->fts_info = fts_stat(p, 0);
                    518:                        if (nlinks > 0 && (p->fts_info == FTS_D ||
                    519:                            p->fts_info == FTS_DNR || p->fts_info == FTS_DNX))
                    520:                                --nlinks;
                    521:                } else
                    522:                        p->fts_info = FTS_NS;
                    523: 
                    524:                p->fts_link = head;
                    525:                head = p;
                    526:                ++nitems;
                    527:        }
                    528:        (void)closedir(dirp);
                    529: 
                    530:        /* reset the path */
                    531:        if (cp - 1 > sp->fts_path)
                    532:                --cp;
                    533:        *cp = '\0';
                    534: 
                    535:        /*
                    536:         * if descended: if were called from ftsread and didn't find anything,
                    537:         * or were called from ftschildren, get back.
                    538:         */
                    539:        if (descend && (!nitems || type == BCHILD) && CHDIR(sp, "..")) {
                    540:                sp->fts_options |= FTS__STOP;
                    541:                p->fts_info = FTS_ERR;
                    542:                return(NULL);
                    543:        }
                    544: 
                    545:        if (!nitems) {
                    546:                if (type == BREAD)
                    547:                        p->fts_info = FTS_DP;
                    548:                return(NULL);
                    549:        }
                    550: 
                    551:        if (sp->fts_compar && nitems > 1)
                    552:                head = fts_sort(head, nitems);
                    553: 
                    554:        if (type == BREAD) {
                    555:                *cp = '/';
                    556:                bcopy(head->fts_name, cp + 1, head->fts_namelen + 1);
                    557:        }
                    558:        return(head);
                    559: }
                    560: 
                    561: static short
                    562: fts_stat(p, symflag)
                    563:        register FTSENT *p;
                    564:        int symflag;
                    565: {
                    566:        /*
                    567:         * detection of symbolic links w/o targets.  If FTS_FOLLOW is set,
                    568:         * the symlink structure is overwritten with the stat structure of
                    569:         * the target.
                    570:         */
                    571:        if (stream->fts_options & FTS_LOGICAL || symflag) {
                    572:                if (stat(p->fts_accpath, &p->fts_statb))
                    573:                        return(symflag || !lstat(p->fts_accpath,
                    574:                            &p->fts_statb) ? FTS_SLNONE : FTS_ERR);
                    575:        } else if (lstat(p->fts_accpath, &p->fts_statb))
                    576:                return(FTS_ERR);
                    577: 
                    578:        switch(p->fts_statb.st_mode&S_IFMT) {
                    579:        case S_IFDIR:
                    580:                return(FTS_D);
                    581:        case S_IFLNK:
                    582:                return(FTS_SL);
                    583:        case S_IFREG:
                    584:                return(FTS_F);
                    585:        }
                    586:        return(FTS_DEFAULT);
                    587: }
                    588: 
                    589: static FTSENT *
                    590: fts_cycle(p)
                    591:        register FTSENT *p;
                    592: {
                    593:        register dev_t dev;
                    594:        register ino_t ino;
                    595: 
                    596:        /*
                    597:         * cycle detection is brute force; if the tree gets deep enough or
                    598:         * the number of symbolic links to directories is really high
                    599:         * something faster might be worthwhile.
                    600:         */
                    601:        dev = p->fts_statb.st_dev;
                    602:        ino = p->fts_statb.st_ino;
                    603:        for (p = p->fts_parent; p->fts_level > ROOTLEVEL; p = p->fts_parent)
                    604:                if (ino == p->fts_statb.st_ino && dev == p->fts_statb.st_dev)
                    605:                        return(p);
                    606:        return(NULL);
                    607: }
                    608: 
                    609: #define        R(type, nelem, ptr) \
                    610:        (type *)realloc((void *)ptr, (u_int)((nelem) * sizeof(type)))
                    611: 
                    612: static FTSENT *
                    613: fts_sort(head, nitems)
                    614:        FTSENT *head;
                    615:        register int nitems;
                    616: {
                    617:        register FTSENT **ap, *p;
                    618: 
                    619:        /*
                    620:         * construct an array of pointers to the structures and call qsort(3).
                    621:         * Reassemble the array in the order returned by qsort.  If unable to
                    622:         * sort for memory reasons, return the directory entries in their
                    623:         * current order.  Allocate enough space for the current needs plus
                    624:         * 40 so we don't realloc one entry at a time.
                    625:         */
                    626:        if (nitems > stream->fts_nitems) {
                    627:                stream->fts_nitems = nitems + 40;
                    628:                if (!(stream->fts_array =
                    629:                    R(FTSENT *, stream->fts_nitems, stream->fts_array))) {
                    630:                        stream->fts_nitems = 0;
                    631:                        return(head);
                    632:                }
                    633:        }
                    634:        for (ap = stream->fts_array, p = head; p; p = p->fts_link)
                    635:                *ap++ = p;
                    636:        qsort((void *)stream->fts_array, nitems, sizeof(FTSENT *),
                    637:            stream->fts_compar);
                    638:        for (head = *(ap = stream->fts_array); --nitems; ++ap)
                    639:                ap[0]->fts_link = ap[1];
                    640:        ap[0]->fts_link = NULL;
                    641:        return(head);
                    642: }
                    643: 
                    644: static FTSENT *
                    645: fts_alloc(name, len)
                    646:        char *name;
                    647:        register int len;
                    648: {
                    649:        register FTSENT *p;
                    650: 
                    651:        /*
                    652:         * variable sized structures; the name is the last element so
                    653:         * allocate enough extra space after the structure to hold it.
                    654:         */
                    655:        if (!(p = (FTSENT *)malloc((size_t)(sizeof(FTSENT) + len))))
                    656:                return(NULL);
                    657:        bcopy(name, p->fts_name, len + 1);
                    658:        p->fts_namelen = len;
                    659:        p->fts_path = stream->fts_path;
                    660:        p->fts_instr = 0;
                    661:        p->fts_local.number = 0;
                    662:        p->fts_local.pointer = NULL;
                    663:        return(p);
                    664: }
                    665: 
                    666: static
                    667: fts_lfree(head)
                    668:        register FTSENT *head;
                    669: {
                    670:        register FTSENT *p;
                    671: 
                    672:        while (p = head) {
                    673:                head = head->fts_link;
                    674:                (void)free((void *)p);
                    675:        }
                    676: }
                    677: 
                    678: /*
                    679:  * allow essentially unlimited paths; certain programs (find, remove, ls)
                    680:  * need to work on any tree.  Most systems will allow creation of paths
                    681:  * much longer than MAXPATHLEN, even though the kernel won't resolve them.
                    682:  * Add an extra 128 bytes to the requested size so that we don't realloc
                    683:  * the path 2 bytes at a time.
                    684:  */
                    685: static char *
                    686: fts_path(size)
                    687:        int size;
                    688: {
                    689:        stream->fts_pathlen += size + 128;
                    690:        return(stream->fts_path =
                    691:            R(char, stream->fts_pathlen, stream->fts_path));
                    692: }
                    693: 
                    694: static FTSENT *
                    695: fts_root(name)
                    696:        register char *name;
                    697: {
                    698:        register char *cp;
                    699: 
                    700:        /*
                    701:         * rip trailing slashes; it's somewhat unclear in POSIX 1003.1 what
                    702:         * /a/b/ really is, they don't talk about what a null path component
                    703:         * resolves to.  This hopefully does what the user intended.  Don't
                    704:         * allow null pathnames.
                    705:         */
                    706:        for (cp = name; *cp; ++cp);
                    707:        if (cp == name) {
                    708:                errno = ENOENT;
                    709:                return(NULL);
                    710:        }
                    711:        while (--cp > name && *cp == '/');
                    712:        *++cp = '\0';
                    713:        return(fts_alloc(name, cp - name));
                    714: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.