14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin * Phong Vo
254887Schin * Glenn Fowler
264887Schin * AT&T Research
274887Schin *
284887Schin * fts implementation unwound from the kpv ftwalk() of 1988-10-30
294887Schin */
304887Schin
314887Schin #include <ast.h>
324887Schin #include <ast_dir.h>
334887Schin #include <error.h>
344887Schin #include <fs3d.h>
358462SApril.Chin@Sun.COM #include <ls.h>
364887Schin
374887Schin struct Ftsent;
384887Schin
394887Schin typedef int (*Compar_f)(struct Ftsent* const*, struct Ftsent* const*);
404887Schin typedef int (*Stat_f)(const char*, struct stat*);
414887Schin
4210898Sroland.mainz@nrubsig.org #define _fts_status status
4310898Sroland.mainz@nrubsig.org #define _fts_statb statb
4410898Sroland.mainz@nrubsig.org
454887Schin #define _FTS_PRIVATE_ \
464887Schin FTSENT* parent; /* top parent */ \
474887Schin FTSENT* todo; /* todo list */ \
484887Schin FTSENT* top; /* top element */ \
494887Schin FTSENT* root; \
504887Schin FTSENT* bot; /* bottom element */ \
514887Schin FTSENT* free; /* free element */ \
524887Schin FTSENT* diroot; \
534887Schin FTSENT* curdir; \
544887Schin FTSENT* current; /* current element */ \
554887Schin FTSENT* previous; /* previous current */ \
564887Schin FTSENT* dotdot; \
574887Schin FTSENT* link; /* real current fts_link*/ \
584887Schin FTSENT* pwd; /* pwd parent */ \
594887Schin DIR* dir; /* current dir stream */ \
604887Schin Compar_f comparf; /* node comparison func */ \
6110898Sroland.mainz@nrubsig.org size_t baselen; /* current strlen(base) */ \
6210898Sroland.mainz@nrubsig.org size_t homesize; /* sizeof(home) */ \
634887Schin int cd; /* chdir status */ \
644887Schin int cpname; \
654887Schin int flags; /* fts_open() flags */ \
664887Schin int nd; \
674887Schin unsigned char children; \
684887Schin unsigned char fs3d; \
694887Schin unsigned char nostat; \
704887Schin unsigned char state; /* fts_read() state */ \
714887Schin char* base; /* basename in path */ \
724887Schin char* name; \
734887Schin char* path; /* path workspace */ \
744887Schin char* home; /* home/path buffer */ \
754887Schin char* endbase; /* space to build paths */ \
764887Schin char* endbuf; /* space to build paths */ \
778462SApril.Chin@Sun.COM char* pad[2]; /* $0.02 to splain this */
784887Schin
794887Schin /*
804887Schin * NOTE: <ftwalk.h> relies on status and statb being the first two elements
814887Schin */
824887Schin
834887Schin #define _FTSENT_PRIVATE_ \
844887Schin int nd; /* popdir() count */ \
854887Schin FTSENT* left; /* left child */ \
864887Schin FTSENT* right; /* right child */ \
874887Schin FTSENT* pwd; /* pwd parent */ \
884887Schin FTSENT* stack; /* getlist() stack */ \
894887Schin long nlink; /* FTS_D link count */ \
904887Schin unsigned char must; /* must stat */ \
914887Schin unsigned char type; /* DT_* type */ \
924887Schin unsigned char symlink; /* originally a symlink */ \
934887Schin char name[sizeof(int)]; /* fts_name data */
944887Schin
954887Schin #include <fts.h>
964887Schin
974887Schin #ifndef ENOSYS
984887Schin #define ENOSYS EINVAL
994887Schin #endif
1004887Schin
1014887Schin
1024887Schin #if MAXNAMLEN > 16
1034887Schin #define MINNAME 32
1044887Schin #else
1054887Schin #define MINNAME 16
1064887Schin #endif
1074887Schin
1084887Schin #define drop(p,f) (((f)->fts_namelen < MINNAME) ? ((f)->fts_link = (p)->free, (p)->free = (f)) : (free(f), (p)->free))
1094887Schin
1104887Schin #define ACCESS(p,f) ((p)->cd==0?(f)->fts_name:(f)->fts_path)
1114887Schin #define PATH(f,p,l) ((!((f)->flags&FTS_SEEDOTDIR)&&(l)>0&&(p)[0]=='.'&&(p)[1]=='/')?((p)+2):(p))
1124887Schin #define SAME(one,two) ((one)->st_ino==(two)->st_ino&&(one)->st_dev==(two)->st_dev)
1134887Schin #define SKIPLINK(p,f) ((f)->fts_parent->nlink == 0)
1144887Schin
1154887Schin #ifdef D_TYPE
1164887Schin #define ISTYPE(f,t) ((f)->type == (t))
1174887Schin #define TYPE(f,t) ((f)->type = (t))
1184887Schin #define SKIP(p,f) ((f)->fts_parent->must == 0 && (((f)->type == DT_UNKNOWN) ? SKIPLINK(p,f) : ((f)->type != DT_DIR && ((f)->type != DT_LNK || ((p)->flags & FTS_PHYSICAL)))))
1194887Schin #else
1204887Schin #undef DT_UNKNOWN
1214887Schin #define DT_UNKNOWN 0
1224887Schin #undef DT_LNK
1234887Schin #define DT_LNK 1
1244887Schin #define ISTYPE(f,t) ((t)==DT_UNKNOWN)
1254887Schin #define TYPE(f,d)
1264887Schin #define SKIP(p,f) ((f)->fts_parent->must == 0 && SKIPLINK(p,f))
1274887Schin #endif
1284887Schin
1294887Schin #ifndef D_FILENO
1304887Schin #define D_FILENO(d) (1)
1314887Schin #endif
1324887Schin
1334887Schin /*
1344887Schin * NOTE: a malicious dir rename() could change .. underfoot so we
1354887Schin * must always verify; undef verify to enable the unsafe code
1364887Schin */
1374887Schin
1384887Schin #define verify 1
1394887Schin
1404887Schin /*
1414887Schin * FTS_NOSTAT requires a dir with
1424887Schin * D_TYPE(&dirent_t)!=DT_UNKNOWN
1434887Schin * OR
1444887Schin * st_nlink>=2
1454887Schin */
1464887Schin
1474887Schin #define FTS_children_resume 1
1484887Schin #define FTS_children_return 2
1494887Schin #define FTS_error 3
1504887Schin #define FTS_popstack 4
1514887Schin #define FTS_popstack_resume 5
1524887Schin #define FTS_popstack_return 6
1534887Schin #define FTS_preorder 7
1544887Schin #define FTS_preorder_resume 8
1554887Schin #define FTS_preorder_return 9
1564887Schin #define FTS_readdir 10
1574887Schin #define FTS_terminal 11
1584887Schin #define FTS_todo 12
1594887Schin #define FTS_top_return 13
1604887Schin
1614887Schin typedef int (*Notify_f)(FTS*, FTSENT*, void*);
1624887Schin
1634887Schin typedef struct Notify_s
1644887Schin {
1654887Schin struct Notify_s* next;
1664887Schin Notify_f notifyf;
1674887Schin void* context;
1684887Schin } Notify_t;
1694887Schin
1704887Schin static Notify_t* notify;
1714887Schin
1724887Schin /*
1734887Schin * allocate an FTSENT node
1744887Schin */
1754887Schin
1764887Schin static FTSENT*
node(FTS * fts,FTSENT * parent,register char * name,register size_t namelen)17710898Sroland.mainz@nrubsig.org node(FTS* fts, FTSENT* parent, register char* name, register size_t namelen)
1784887Schin {
1794887Schin register FTSENT* f;
18010898Sroland.mainz@nrubsig.org register size_t n;
1814887Schin
1824887Schin if (fts->free && namelen < MINNAME)
1834887Schin {
1844887Schin f = fts->free;
1854887Schin fts->free = f->fts_link;
1864887Schin }
1874887Schin else
1884887Schin {
1894887Schin n = (namelen < MINNAME ? MINNAME : namelen + 1) - sizeof(int);
1904887Schin if (!(f = newof(0, FTSENT, 1, n)))
1914887Schin {
1924887Schin fts->fts_errno = errno;
1934887Schin fts->state = FTS_error;
1944887Schin return 0;
1954887Schin }
1964887Schin f->fts = fts;
1974887Schin }
1984887Schin TYPE(f, DT_UNKNOWN);
1994887Schin f->status = 0;
2004887Schin f->symlink = 0;
2014887Schin f->fts_level = (f->fts_parent = parent)->fts_level + 1;
20210898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
20310898Sroland.mainz@nrubsig.org f->_fts_level = (short)f->fts_level;
20410898Sroland.mainz@nrubsig.org #endif
2054887Schin f->fts_link = 0;
2064887Schin f->fts_pointer = 0;
2074887Schin f->fts_number = 0;
2084887Schin f->fts_errno = 0;
2094887Schin f->fts_namelen = namelen;
21010898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
21110898Sroland.mainz@nrubsig.org f->_fts_namelen = (unsigned short)f->fts_namelen;
21210898Sroland.mainz@nrubsig.org #endif
2134887Schin f->fts_name = f->name;
2144887Schin f->fts_statp = &f->statb;
2154887Schin memcpy(f->fts_name, name, namelen + 1);
2164887Schin return f;
2174887Schin }
2184887Schin
2194887Schin /*
2204887Schin * compare directories by device/inode
2214887Schin */
2224887Schin
2234887Schin static int
statcmp(FTSENT * const * pf1,FTSENT * const * pf2)2244887Schin statcmp(FTSENT* const* pf1, FTSENT* const* pf2)
2254887Schin {
2264887Schin register const FTSENT* f1 = *pf1;
2274887Schin register const FTSENT* f2 = *pf2;
2284887Schin
2294887Schin if (f1->statb.st_ino < f2->statb.st_ino)
2304887Schin return -1;
2314887Schin if (f1->statb.st_ino > f2->statb.st_ino)
2324887Schin return 1;
2334887Schin if (f1->statb.st_dev < f2->statb.st_dev)
2344887Schin return -1;
2354887Schin if (f1->statb.st_dev > f2->statb.st_dev)
2364887Schin return 1;
2374887Schin
2384887Schin /*
2394887Schin * hack for NFS where <dev,ino> may not uniquely identify objects
2404887Schin */
2414887Schin
2424887Schin if (f1->statb.st_mtime < f2->statb.st_mtime)
2434887Schin return -1;
2444887Schin if (f1->statb.st_mtime > f2->statb.st_mtime)
2454887Schin return 1;
2464887Schin return 0;
2474887Schin }
2484887Schin
2494887Schin /*
2504887Schin * search trees with top-down splaying (a la Tarjan and Sleator)
2514887Schin * when used for insertion sort, this implements a stable sort
2524887Schin */
2534887Schin
2544887Schin #define RROTATE(r) (t = r->left, r->left = t->right, t->right = r, r = t)
2554887Schin #define LROTATE(r) (t = r->right, r->right = t->left, t->left = r, r = t)
2564887Schin
2574887Schin static FTSENT*
search(FTSENT * e,FTSENT * root,int (* comparf)(FTSENT * const *,FTSENT * const *),int insert)2584887Schin search(FTSENT* e, FTSENT* root, int(*comparf)(FTSENT* const*, FTSENT* const*), int insert)
2594887Schin {
2604887Schin register int cmp;
2614887Schin register FTSENT* t;
2624887Schin register FTSENT* left;
2634887Schin register FTSENT* right;
2644887Schin register FTSENT* lroot;
2654887Schin register FTSENT* rroot;
2664887Schin
2674887Schin left = right = lroot = rroot = 0;
2684887Schin while (root)
2694887Schin {
2704887Schin if (!(cmp = (*comparf)(&e, &root)) && !insert)
2714887Schin break;
2724887Schin if (cmp < 0)
2734887Schin {
2744887Schin /*
2754887Schin * this is the left zig-zig case
2764887Schin */
2774887Schin
2784887Schin if (root->left && (cmp = (*comparf)(&e, &root->left)) <= 0)
2794887Schin {
2804887Schin RROTATE(root);
2814887Schin if (!cmp && !insert)
2824887Schin break;
2834887Schin }
2844887Schin
2854887Schin /*
2864887Schin * stick all things > e to the right tree
2874887Schin */
2884887Schin
2894887Schin if (right)
2904887Schin right->left = root;
2914887Schin else
2924887Schin rroot = root;
2934887Schin right = root;
2944887Schin root = root->left;
2954887Schin right->left = 0;
2964887Schin }
2974887Schin else
2984887Schin {
2994887Schin /*
3004887Schin * this is the right zig-zig case
3014887Schin */
3024887Schin
3034887Schin if (root->right && (cmp = (*comparf)(&e, &root->right)) >= 0)
3044887Schin {
3054887Schin LROTATE(root);
3064887Schin if (!cmp && !insert)
3074887Schin break;
3084887Schin }
3094887Schin
3104887Schin /*
3114887Schin * stick all things <= e to the left tree
3124887Schin */
3134887Schin
3144887Schin if (left)
3154887Schin left->right = root;
3164887Schin else
3174887Schin lroot = root;
3184887Schin left = root;
3194887Schin root = root->right;
3204887Schin left->right = 0;
3214887Schin }
3224887Schin }
3234887Schin if (!root)
3244887Schin root = e;
3254887Schin else
3264887Schin {
3274887Schin if (right)
3284887Schin right->left = root->right;
3294887Schin else
3304887Schin rroot = root->right;
3314887Schin if (left)
3324887Schin left->right = root->left;
3334887Schin else
3344887Schin lroot = root->left;
3354887Schin }
3364887Schin root->left = lroot;
3374887Schin root->right = rroot;
3384887Schin return root;
3394887Schin }
3404887Schin
3414887Schin /*
3424887Schin * delete the root element from the tree
3434887Schin */
3444887Schin
3454887Schin static FTSENT*
deleteroot(register FTSENT * root)3464887Schin deleteroot(register FTSENT* root)
3474887Schin {
3484887Schin register FTSENT* t;
3494887Schin register FTSENT* left;
3504887Schin register FTSENT* right;
3514887Schin
3524887Schin right = root->right;
3534887Schin if (!(left = root->left))
3544887Schin root = right;
3554887Schin else
3564887Schin {
3574887Schin while (left->right)
3584887Schin LROTATE(left);
3594887Schin left->right = right;
3604887Schin root = left;
3614887Schin }
3624887Schin return root;
3634887Schin }
3644887Schin
3654887Schin /*
3664887Schin * generate ordered fts_link list from binary tree at root
3674887Schin * FTSENT.stack instead of recursion to avoid blowing the real
3684887Schin * stack on big directories
3694887Schin */
3704887Schin
3714887Schin static void
getlist(register FTSENT ** top,register FTSENT ** bot,register FTSENT * root)3724887Schin getlist(register FTSENT** top, register FTSENT** bot, register FTSENT* root)
3734887Schin {
3744887Schin register FTSENT* stack = 0;
3754887Schin
3764887Schin for (;;)
3774887Schin {
3784887Schin if (root->left)
3794887Schin {
3804887Schin root->stack = stack;
3814887Schin stack = root;
3824887Schin root = root->left;
3834887Schin }
3844887Schin else
3854887Schin {
3864887Schin for (;;)
3874887Schin {
3884887Schin if (*top)
3894887Schin *bot = (*bot)->fts_link = root;
3904887Schin else
3914887Schin *bot = *top = root;
3924887Schin if (root->right)
3934887Schin {
3944887Schin root = root->right;
3954887Schin break;
3964887Schin }
3974887Schin if (!(root = stack))
39810898Sroland.mainz@nrubsig.org {
39910898Sroland.mainz@nrubsig.org (*bot)->fts_link = 0;
4004887Schin return;
40110898Sroland.mainz@nrubsig.org }
4024887Schin stack = stack->stack;
4034887Schin }
4044887Schin }
4054887Schin }
4064887Schin }
4074887Schin
4084887Schin /*
4094887Schin * set directory when curdir is lost in space
4104887Schin */
4114887Schin
4124887Schin static int
setdir(register char * home,register char * path)4134887Schin setdir(register char* home, register char* path)
4144887Schin {
4154887Schin register int cdrv;
4164887Schin
4174887Schin if (path[0] == '/')
4184887Schin cdrv = pathcd(path, NiL);
4194887Schin else
4204887Schin {
4214887Schin /*
4224887Schin * note that path and home are in the same buffer
4234887Schin */
4244887Schin
4254887Schin path[-1] = '/';
4264887Schin cdrv = pathcd(home, NiL);
4274887Schin path[-1] = 0;
4284887Schin }
4294887Schin if (cdrv < 0)
4304887Schin pathcd(home, NiL);
4314887Schin return cdrv;
4324887Schin }
4334887Schin
4344887Schin /*
4354887Schin * set to parent dir
4364887Schin */
4374887Schin
4384887Schin static int
setpdir(register char * home,register char * path,register char * base)4394887Schin setpdir(register char* home, register char* path, register char* base)
4404887Schin {
4414887Schin register int c;
4424887Schin register int cdrv;
4434887Schin
4444887Schin if (base > path)
4454887Schin {
4464887Schin c = base[0];
4474887Schin base[0] = 0;
4484887Schin cdrv = setdir(home, path);
4494887Schin base[0] = c;
4504887Schin }
4514887Schin else
4524887Schin cdrv = pathcd(home, NiL);
4534887Schin return cdrv;
4544887Schin }
4554887Schin
4564887Schin /*
4574887Schin * pop a set of directories
4584887Schin */
4594887Schin static int
popdirs(FTS * fts)4604887Schin popdirs(FTS* fts)
4614887Schin {
4624887Schin register FTSENT*f;
4634887Schin register char* s;
4644887Schin register char* e;
4654887Schin #ifndef verify
4664887Schin register int verify;
4674887Schin #endif
4684887Schin struct stat sb;
4694887Schin char buf[PATH_MAX];
4704887Schin
4714887Schin if (!(f = fts->curdir) || f->fts_level < 0)
4724887Schin return -1;
4734887Schin e = buf + sizeof(buf) - 4;
4744887Schin #ifndef verify
4754887Schin verify = 0;
4764887Schin #endif
4774887Schin while (fts->nd > 0)
4784887Schin {
4794887Schin for (s = buf; s < e && fts->nd > 0; fts->nd--)
4804887Schin {
4814887Schin if (fts->pwd)
4824887Schin {
4834887Schin #ifndef verify
4844887Schin verify |= fts->pwd->symlink;
4854887Schin #endif
4864887Schin fts->pwd = fts->pwd->pwd;
4874887Schin }
4884887Schin *s++ = '.';
4894887Schin *s++ = '.';
4904887Schin *s++ = '/';
4914887Schin }
4924887Schin *s = 0;
4934887Schin if (chdir(buf))
4944887Schin return -1;
4954887Schin }
4964887Schin return (verify && (stat(".", &sb) < 0 || !SAME(&sb, f->fts_statp))) ? -1 : 0;
4974887Schin }
4984887Schin
4994887Schin /*
5004887Schin * initialize st from path and fts_info from st
5014887Schin */
5024887Schin
5034887Schin static int
info(FTS * fts,register FTSENT * f,const char * path,struct stat * sp,int flags)5044887Schin info(FTS* fts, register FTSENT* f, const char* path, struct stat* sp, int flags)
5054887Schin {
5064887Schin if (path)
5074887Schin {
5084887Schin #ifdef S_ISLNK
5094887Schin if (!f->symlink && (ISTYPE(f, DT_UNKNOWN) || ISTYPE(f, DT_LNK)))
5104887Schin {
5114887Schin if (lstat(path, sp) < 0)
5124887Schin goto bad;
5134887Schin }
5144887Schin else
5154887Schin #endif
5164887Schin if (stat(path, sp) < 0)
5174887Schin goto bad;
5184887Schin }
5194887Schin #ifdef S_ISLNK
5204887Schin again:
5214887Schin #endif
5224887Schin if (S_ISDIR(sp->st_mode))
5234887Schin {
5244887Schin if ((flags & FTS_NOSTAT) && !fts->fs3d)
5254887Schin {
5264887Schin f->fts_parent->nlink--;
5274887Schin #ifdef D_TYPE
5284887Schin if ((f->nlink = sp->st_nlink) < 2)
5298462SApril.Chin@Sun.COM {
5308462SApril.Chin@Sun.COM f->must = 2;
5314887Schin f->nlink = 2;
5328462SApril.Chin@Sun.COM }
5338462SApril.Chin@Sun.COM else
5348462SApril.Chin@Sun.COM f->must = 0;
5354887Schin #else
5364887Schin if ((f->nlink = sp->st_nlink) >= 2)
5374887Schin f->must = 1;
5384887Schin else
5394887Schin f->must = 2;
5404887Schin #endif
5414887Schin }
5424887Schin else
5434887Schin f->must = 2;
5444887Schin TYPE(f, DT_DIR);
5454887Schin f->fts_info = FTS_D;
5464887Schin }
5474887Schin #ifdef S_ISLNK
5484887Schin else if (S_ISLNK((sp)->st_mode))
5494887Schin {
5504887Schin struct stat sb;
5514887Schin
5524887Schin f->symlink = 1;
5534887Schin if (!(flags & FTS_PHYSICAL) && stat(path, &sb) >= 0)
5544887Schin {
5554887Schin *sp = sb;
5564887Schin flags = FTS_PHYSICAL;
5574887Schin goto again;
5584887Schin }
5594887Schin TYPE(f, DT_LNK);
5604887Schin f->fts_info = FTS_SL;
5614887Schin }
5624887Schin #endif
5634887Schin else
5644887Schin {
5654887Schin TYPE(f, DT_REG);
5664887Schin f->fts_info = FTS_F;
5674887Schin }
5684887Schin return 0;
5694887Schin bad:
5704887Schin TYPE(f, DT_UNKNOWN);
5714887Schin f->fts_info = FTS_NS;
5724887Schin return -1;
5734887Schin }
5744887Schin
5754887Schin /*
5764887Schin * get top list of elements to process
57710898Sroland.mainz@nrubsig.org * ordering delayed until first fts_read()
57810898Sroland.mainz@nrubsig.org * to give caller a chance to set fts->handle
5794887Schin */
5804887Schin
5814887Schin static FTSENT*
toplist(FTS * fts,register char * const * pathnames)5824887Schin toplist(FTS* fts, register char* const* pathnames)
5834887Schin {
5844887Schin register char* path;
5854887Schin register FTSENT* f;
58610898Sroland.mainz@nrubsig.org register FTSENT* top;
58710898Sroland.mainz@nrubsig.org register FTSENT* bot;
5884887Schin int physical;
5894887Schin int metaphysical;
5904887Schin char* s;
5914887Schin struct stat st;
5924887Schin
5934887Schin if (fts->flags & FTS_NOSEEDOTDIR)
5944887Schin fts->flags &= ~FTS_SEEDOTDIR;
5954887Schin physical = (fts->flags & FTS_PHYSICAL);
5964887Schin metaphysical = (fts->flags & (FTS_META|FTS_PHYSICAL)) == (FTS_META|FTS_PHYSICAL);
59710898Sroland.mainz@nrubsig.org top = bot = 0;
5984887Schin while (path = *pathnames++)
5994887Schin {
6004887Schin /*
6014887Schin * make elements
6024887Schin */
6034887Schin
6044887Schin if (!(f = node(fts, fts->parent, path, strlen(path))))
6054887Schin break;
6064887Schin path = f->fts_name;
6074887Schin if (!physical)
6084887Schin f->fts_namelen = (fts->flags & FTS_SEEDOTDIR) ? strlen(path) : (pathcanon(path, 0) - path);
6094887Schin else if (*path != '.')
6104887Schin {
6114887Schin f->fts_namelen = strlen(path);
6124887Schin fts->flags |= FTS_SEEDOTDIR;
6134887Schin }
6144887Schin else
6154887Schin {
6164887Schin if (fts->flags & FTS_NOSEEDOTDIR)
6174887Schin {
6184887Schin fts->flags &= ~FTS_SEEDOTDIR;
6194887Schin s = path;
6204887Schin while (*s++ == '.' && *s++ == '/')
6214887Schin {
6224887Schin while (*s == '/')
6234887Schin s++;
6244887Schin if (!*s)
6254887Schin break;
6264887Schin path = f->fts_name;
6274887Schin while (*path++ = *s++);
6284887Schin path = f->fts_name;
6294887Schin }
6304887Schin }
6314887Schin else
6324887Schin fts->flags |= FTS_SEEDOTDIR;
6334887Schin for (s = path + strlen(path); s > path && *(s - 1) == '/'; s--);
6344887Schin *s = 0;
6354887Schin f->fts_namelen = s - path;
6364887Schin }
63710898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
63810898Sroland.mainz@nrubsig.org f->_fts_namelen = (unsigned short)f->fts_namelen;
63910898Sroland.mainz@nrubsig.org #endif
6404887Schin if (!*path)
6414887Schin {
6424887Schin errno = ENOENT;
6434887Schin f->fts_info = FTS_NS;
6444887Schin }
6454887Schin else
64610898Sroland.mainz@nrubsig.org info(fts, f, path, f->fts_statp, fts->flags);
6474887Schin #ifdef S_ISLNK
6484887Schin
6494887Schin /*
6504887Schin * don't let any standards committee get
6514887Schin * away with calling your idea a hack
6524887Schin */
6534887Schin
6544887Schin if (metaphysical && f->fts_info == FTS_SL && stat(path, &st) >= 0)
6554887Schin {
65610898Sroland.mainz@nrubsig.org *f->fts_statp = st;
65710898Sroland.mainz@nrubsig.org info(fts, f, NiL, f->fts_statp, 0);
6584887Schin }
6594887Schin #endif
66010898Sroland.mainz@nrubsig.org if (bot)
6614887Schin {
6624887Schin bot->fts_link = f;
6634887Schin bot = f;
6644887Schin }
6654887Schin else
6664887Schin top = bot = f;
6674887Schin }
6684887Schin return top;
6694887Schin }
6704887Schin
6714887Schin /*
67210898Sroland.mainz@nrubsig.org * order fts->todo if fts->comparf != 0
67310898Sroland.mainz@nrubsig.org */
67410898Sroland.mainz@nrubsig.org
67510898Sroland.mainz@nrubsig.org static void
order(FTS * fts)67610898Sroland.mainz@nrubsig.org order(FTS* fts)
67710898Sroland.mainz@nrubsig.org {
67810898Sroland.mainz@nrubsig.org register FTSENT* f;
67910898Sroland.mainz@nrubsig.org register FTSENT* root;
68010898Sroland.mainz@nrubsig.org FTSENT* top;
68110898Sroland.mainz@nrubsig.org FTSENT* bot;
68210898Sroland.mainz@nrubsig.org
68310898Sroland.mainz@nrubsig.org top = bot = root = 0;
68410898Sroland.mainz@nrubsig.org for (f = fts->todo; f; f = f->fts_link)
68510898Sroland.mainz@nrubsig.org root = search(f, root, fts->comparf, 1);
68610898Sroland.mainz@nrubsig.org getlist(&top, &bot, root);
68710898Sroland.mainz@nrubsig.org fts->todo = top;
68810898Sroland.mainz@nrubsig.org }
68910898Sroland.mainz@nrubsig.org
69010898Sroland.mainz@nrubsig.org /*
6914887Schin * resize the path buffer
6924887Schin * note that free() is not used because we may need to chdir(fts->home)
6934887Schin * if there isn't enough space to continue
6944887Schin */
6954887Schin
6964887Schin static int
resize(register FTS * fts,size_t inc)69710898Sroland.mainz@nrubsig.org resize(register FTS* fts, size_t inc)
6984887Schin {
6994887Schin register char* old;
7004887Schin register char* newp;
70110898Sroland.mainz@nrubsig.org register size_t n_old;
7024887Schin
7034887Schin /*
7044887Schin * add space for "/." used in testing FTS_DNX
7054887Schin */
7064887Schin
7074887Schin n_old = fts->homesize;
7084887Schin fts->homesize = ((fts->homesize + inc + 4) / PATH_MAX + 1) * PATH_MAX;
7094887Schin if (!(newp = newof(0, char, fts->homesize, 0)))
7104887Schin {
7114887Schin fts->fts_errno = errno;
7124887Schin fts->state = FTS_error;
7134887Schin return -1;
7144887Schin }
7154887Schin old = fts->home;
7164887Schin fts->home = newp;
7174887Schin memcpy(newp, old, n_old);
7184887Schin if (fts->endbuf)
7194887Schin fts->endbuf = newp + fts->homesize - 4;
7204887Schin if (fts->path)
7214887Schin fts->path = newp + (fts->path - old);
7224887Schin if (fts->base)
7234887Schin fts->base = newp + (fts->base - old);
7244887Schin free(old);
7254887Schin return 0;
7264887Schin }
7274887Schin
7284887Schin /*
7294887Schin * open a new fts stream on pathnames
7304887Schin */
7314887Schin
7324887Schin FTS*
fts_open(char * const * pathnames,int flags,int (* comparf)(FTSENT * const *,FTSENT * const *))7334887Schin fts_open(char* const* pathnames, int flags, int (*comparf)(FTSENT* const*, FTSENT* const*))
7344887Schin {
7354887Schin register FTS* fts;
7364887Schin
7374887Schin if (!(fts = newof(0, FTS, 1, sizeof(FTSENT))))
7384887Schin return 0;
7394887Schin fts->flags = flags;
7404887Schin fts->cd = (flags & FTS_NOCHDIR) ? 1 : -1;
7414887Schin fts->comparf = comparf;
7424887Schin fts->fs3d = fs3d(FS3D_TEST);
7434887Schin
7444887Schin /*
7454887Schin * set up the path work buffer
7464887Schin */
7474887Schin
7484887Schin fts->homesize = 2 * PATH_MAX;
7494887Schin for (;;)
7504887Schin {
7514887Schin if (!(fts->home = newof(fts->home, char, fts->homesize, 0)))
7524887Schin {
7534887Schin free(fts);
7544887Schin return 0;
7554887Schin }
7564887Schin if (fts->cd > 0 || getcwd(fts->home, fts->homesize))
7574887Schin break;
7584887Schin if (errno == ERANGE)
7594887Schin fts->homesize += PATH_MAX;
7604887Schin else
7614887Schin fts->cd = 1;
7624887Schin }
7634887Schin fts->endbuf = fts->home + fts->homesize - 4;
7644887Schin
7654887Schin /*
7664887Schin * initialize the tippity-top
7674887Schin */
7684887Schin
7694887Schin fts->parent = (FTSENT*)(fts + 1);
7704887Schin fts->parent->fts_info = FTS_D;
7714887Schin memcpy(fts->parent->fts_accpath = fts->parent->fts_path = fts->parent->fts_name = fts->parent->name, ".", 2);
7724887Schin fts->parent->fts_level = -1;
77310898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
77410898Sroland.mainz@nrubsig.org fts->parent->_fts_level = (short)fts->parent->fts_level;
77510898Sroland.mainz@nrubsig.org #endif
7764887Schin fts->parent->fts_statp = &fts->parent->statb;
7774887Schin fts->parent->must = 2;
7784887Schin fts->parent->type = DT_UNKNOWN;
7794887Schin fts->path = fts->home + strlen(fts->home) + 1;
7804887Schin
7814887Schin /*
7824887Schin * make the list of top elements
7834887Schin */
7844887Schin
7854887Schin if (!pathnames || (flags & FTS_ONEPATH) || !*pathnames)
7864887Schin {
7874887Schin char* v[2];
7884887Schin
7894887Schin v[0] = pathnames && (flags & FTS_ONEPATH) ? (char*)pathnames : ".";
7904887Schin v[1] = 0;
7914887Schin fts->todo = toplist(fts, v);
7924887Schin }
7934887Schin else
7944887Schin fts->todo = toplist(fts, pathnames);
7954887Schin if (!fts->todo || fts->todo->fts_info == FTS_NS && !fts->todo->fts_link)
7964887Schin {
7974887Schin fts_close(fts);
7984887Schin return 0;
7994887Schin }
8004887Schin return fts;
8014887Schin }
8024887Schin
8034887Schin /*
8044887Schin * return the next FTS entry
8054887Schin */
8064887Schin
8074887Schin FTSENT*
fts_read(register FTS * fts)8084887Schin fts_read(register FTS* fts)
8094887Schin {
8104887Schin register char* s;
8114887Schin register int n;
8124887Schin register FTSENT* f;
8134887Schin struct dirent* d;
81410898Sroland.mainz@nrubsig.org size_t i;
8154887Schin FTSENT* t;
8164887Schin Notify_t* p;
8174887Schin #ifdef verify
8184887Schin struct stat sb;
8194887Schin #endif
8204887Schin
82110898Sroland.mainz@nrubsig.org for (;;)
82210898Sroland.mainz@nrubsig.org switch (fts->state)
82310898Sroland.mainz@nrubsig.org {
8244887Schin
82510898Sroland.mainz@nrubsig.org case FTS_top_return:
8264887Schin
82710898Sroland.mainz@nrubsig.org f = fts->todo;
82810898Sroland.mainz@nrubsig.org t = 0;
82910898Sroland.mainz@nrubsig.org while (f)
83010898Sroland.mainz@nrubsig.org if (f->status == FTS_SKIP)
8314887Schin {
83210898Sroland.mainz@nrubsig.org if (t)
83310898Sroland.mainz@nrubsig.org {
83410898Sroland.mainz@nrubsig.org t->fts_link = f->fts_link;
83510898Sroland.mainz@nrubsig.org drop(fts, f);
83610898Sroland.mainz@nrubsig.org f = t->fts_link;
83710898Sroland.mainz@nrubsig.org }
83810898Sroland.mainz@nrubsig.org else
83910898Sroland.mainz@nrubsig.org {
84010898Sroland.mainz@nrubsig.org fts->todo = f->fts_link;
84110898Sroland.mainz@nrubsig.org drop(fts, f);
84210898Sroland.mainz@nrubsig.org f = fts->todo;
84310898Sroland.mainz@nrubsig.org }
8444887Schin }
8454887Schin else
8464887Schin {
84710898Sroland.mainz@nrubsig.org t = f;
84810898Sroland.mainz@nrubsig.org f = f->fts_link;
84910898Sroland.mainz@nrubsig.org }
85010898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
85110898Sroland.mainz@nrubsig.org
85210898Sroland.mainz@nrubsig.org case 0:
85310898Sroland.mainz@nrubsig.org
85410898Sroland.mainz@nrubsig.org if (!fts->state && fts->comparf)
85510898Sroland.mainz@nrubsig.org order(fts);
85610898Sroland.mainz@nrubsig.org if (!(f = fts->todo))
85710898Sroland.mainz@nrubsig.org return 0;
85810898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
85910898Sroland.mainz@nrubsig.org
86010898Sroland.mainz@nrubsig.org case FTS_todo:
86110898Sroland.mainz@nrubsig.org
86210898Sroland.mainz@nrubsig.org /*
86310898Sroland.mainz@nrubsig.org * process the top object on the stack
86410898Sroland.mainz@nrubsig.org */
86510898Sroland.mainz@nrubsig.org
86610898Sroland.mainz@nrubsig.org fts->root = fts->top = fts->bot = 0;
86710898Sroland.mainz@nrubsig.org
86810898Sroland.mainz@nrubsig.org /*
86910898Sroland.mainz@nrubsig.org * initialize the top level
87010898Sroland.mainz@nrubsig.org */
87110898Sroland.mainz@nrubsig.org
87210898Sroland.mainz@nrubsig.org if (f->fts_level == 0)
87310898Sroland.mainz@nrubsig.org {
87410898Sroland.mainz@nrubsig.org fts->parent->fts_number = f->fts_number;
87510898Sroland.mainz@nrubsig.org fts->parent->fts_pointer = f->fts_pointer;
87610898Sroland.mainz@nrubsig.org fts->parent->fts_statp = f->fts_statp;
87710898Sroland.mainz@nrubsig.org fts->parent->statb = *f->fts_statp;
87810898Sroland.mainz@nrubsig.org f->fts_parent = fts->parent;
87910898Sroland.mainz@nrubsig.org fts->diroot = 0;
88010898Sroland.mainz@nrubsig.org if (fts->cd == 0)
88110898Sroland.mainz@nrubsig.org pathcd(fts->home, NiL);
88210898Sroland.mainz@nrubsig.org else if (fts->cd < 0)
88310898Sroland.mainz@nrubsig.org fts->cd = 0;
88410898Sroland.mainz@nrubsig.org fts->pwd = f->fts_parent;
88510898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : f->fts_parent;
88610898Sroland.mainz@nrubsig.org *(fts->base = fts->path) = 0;
88710898Sroland.mainz@nrubsig.org }
88810898Sroland.mainz@nrubsig.org
88910898Sroland.mainz@nrubsig.org /*
89010898Sroland.mainz@nrubsig.org * chdir to parent if asked for
89110898Sroland.mainz@nrubsig.org */
89210898Sroland.mainz@nrubsig.org
89310898Sroland.mainz@nrubsig.org if (fts->cd < 0)
89410898Sroland.mainz@nrubsig.org {
89510898Sroland.mainz@nrubsig.org fts->cd = setdir(fts->home, fts->path);
89610898Sroland.mainz@nrubsig.org fts->pwd = f->fts_parent;
89710898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : f->fts_parent;
89810898Sroland.mainz@nrubsig.org }
89910898Sroland.mainz@nrubsig.org
90010898Sroland.mainz@nrubsig.org /*
90110898Sroland.mainz@nrubsig.org * add object's name to the path
90210898Sroland.mainz@nrubsig.org */
90310898Sroland.mainz@nrubsig.org
90410898Sroland.mainz@nrubsig.org if ((fts->baselen = f->fts_namelen) >= (fts->endbuf - fts->base) && resize(fts, fts->baselen))
90510898Sroland.mainz@nrubsig.org return 0;
90610898Sroland.mainz@nrubsig.org memcpy(fts->base, f->name, fts->baselen + 1);
90710898Sroland.mainz@nrubsig.org fts->name = fts->cd ? fts->path : fts->base;
90810898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
90910898Sroland.mainz@nrubsig.org
91010898Sroland.mainz@nrubsig.org case FTS_preorder:
91110898Sroland.mainz@nrubsig.org
91210898Sroland.mainz@nrubsig.org /*
91310898Sroland.mainz@nrubsig.org * check for cycle and open dir
91410898Sroland.mainz@nrubsig.org */
91510898Sroland.mainz@nrubsig.org
91610898Sroland.mainz@nrubsig.org if (f->fts_info == FTS_D)
91710898Sroland.mainz@nrubsig.org {
91810898Sroland.mainz@nrubsig.org if ((fts->diroot = search(f, fts->diroot, statcmp, 0)) != f || f->fts_level > 0 && (t = f) && statcmp(&t, &f->fts_parent) == 0)
91910898Sroland.mainz@nrubsig.org {
92010898Sroland.mainz@nrubsig.org f->fts_info = FTS_DC;
92110898Sroland.mainz@nrubsig.org f->fts_cycle = fts->diroot;
92210898Sroland.mainz@nrubsig.org }
92310898Sroland.mainz@nrubsig.org else if (!(fts->flags & FTS_TOP) && (!(fts->flags & FTS_XDEV) || f->statb.st_dev == f->fts_parent->statb.st_dev))
92410898Sroland.mainz@nrubsig.org {
92510898Sroland.mainz@nrubsig.org /*
92610898Sroland.mainz@nrubsig.org * buffer is known to be large enough here!
92710898Sroland.mainz@nrubsig.org */
92810898Sroland.mainz@nrubsig.org
92910898Sroland.mainz@nrubsig.org if (fts->base[fts->baselen - 1] != '/')
93010898Sroland.mainz@nrubsig.org memcpy(fts->base + fts->baselen, "/.", 3);
93110898Sroland.mainz@nrubsig.org if (!(fts->dir = opendir(fts->name)))
93210898Sroland.mainz@nrubsig.org f->fts_info = FTS_DNX;
93310898Sroland.mainz@nrubsig.org fts->base[fts->baselen] = 0;
93410898Sroland.mainz@nrubsig.org if (!fts->dir && !(fts->dir = opendir(fts->name)))
93510898Sroland.mainz@nrubsig.org f->fts_info = FTS_DNR;
9364887Schin }
9374887Schin }
93810898Sroland.mainz@nrubsig.org f->nd = f->fts_info & ~FTS_DNX;
93910898Sroland.mainz@nrubsig.org if (f->nd || !(fts->flags & FTS_NOPREORDER))
9404887Schin {
94110898Sroland.mainz@nrubsig.org fts->current = f;
94210898Sroland.mainz@nrubsig.org fts->link = f->fts_link;
94310898Sroland.mainz@nrubsig.org f->fts_link = 0;
94410898Sroland.mainz@nrubsig.org f->fts_path = PATH(fts, fts->path, f->fts_level);
94510898Sroland.mainz@nrubsig.org f->fts_pathlen = (fts->base - f->fts_path) + fts->baselen;
94610898Sroland.mainz@nrubsig.org f->fts_accpath = ACCESS(fts, f);
94710898Sroland.mainz@nrubsig.org fts->state = FTS_preorder_return;
94810898Sroland.mainz@nrubsig.org goto note;
9494887Schin }
95010898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
9514887Schin
95210898Sroland.mainz@nrubsig.org case FTS_preorder_resume:
9534887Schin
95410898Sroland.mainz@nrubsig.org /*
95510898Sroland.mainz@nrubsig.org * prune
95610898Sroland.mainz@nrubsig.org */
9574887Schin
95810898Sroland.mainz@nrubsig.org if (!fts->dir || f->nd || f->status == FTS_SKIP)
95910898Sroland.mainz@nrubsig.org {
96010898Sroland.mainz@nrubsig.org if (fts->dir)
96110898Sroland.mainz@nrubsig.org {
96210898Sroland.mainz@nrubsig.org closedir(fts->dir);
96310898Sroland.mainz@nrubsig.org fts->dir = 0;
96410898Sroland.mainz@nrubsig.org }
96510898Sroland.mainz@nrubsig.org fts->state = FTS_popstack;
96610898Sroland.mainz@nrubsig.org continue;
96710898Sroland.mainz@nrubsig.org }
9684887Schin
96910898Sroland.mainz@nrubsig.org /*
97010898Sroland.mainz@nrubsig.org * FTS_D or FTS_DNX, about to read children
97110898Sroland.mainz@nrubsig.org */
9724887Schin
97310898Sroland.mainz@nrubsig.org if (fts->cd == 0)
97410898Sroland.mainz@nrubsig.org {
97510898Sroland.mainz@nrubsig.org if ((fts->cd = chdir(fts->name)) < 0)
97610898Sroland.mainz@nrubsig.org pathcd(fts->home, NiL);
97710898Sroland.mainz@nrubsig.org else if (fts->pwd != f)
97810898Sroland.mainz@nrubsig.org {
97910898Sroland.mainz@nrubsig.org f->pwd = fts->pwd;
98010898Sroland.mainz@nrubsig.org fts->pwd = f;
98110898Sroland.mainz@nrubsig.org }
98210898Sroland.mainz@nrubsig.org fts->curdir = fts->cd < 0 ? 0 : f;
9834887Schin }
98410898Sroland.mainz@nrubsig.org fts->nostat = fts->children > 1 || f->fts_info == FTS_DNX;
98510898Sroland.mainz@nrubsig.org fts->cpname = fts->cd && !fts->nostat || !fts->children && !fts->comparf;
98610898Sroland.mainz@nrubsig.org fts->dotdot = 0;
98710898Sroland.mainz@nrubsig.org fts->endbase = fts->base + fts->baselen;
98810898Sroland.mainz@nrubsig.org if (fts->endbase[-1] != '/')
98910898Sroland.mainz@nrubsig.org *fts->endbase++ = '/';
9904887Schin fts->current = f;
99110898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
9924887Schin
99310898Sroland.mainz@nrubsig.org case FTS_readdir:
9944887Schin
99510898Sroland.mainz@nrubsig.org while (d = readdir(fts->dir))
9964887Schin {
99710898Sroland.mainz@nrubsig.org s = d->d_name;
99810898Sroland.mainz@nrubsig.org if (s[0] == '.')
9994887Schin {
100010898Sroland.mainz@nrubsig.org if (s[1] == 0)
100110898Sroland.mainz@nrubsig.org {
100210898Sroland.mainz@nrubsig.org fts->current->nlink--;
100310898Sroland.mainz@nrubsig.org if (!(fts->flags & FTS_SEEDOT))
100410898Sroland.mainz@nrubsig.org continue;
100510898Sroland.mainz@nrubsig.org n = 1;
100610898Sroland.mainz@nrubsig.org }
100710898Sroland.mainz@nrubsig.org else if (s[1] == '.' && s[2] == 0)
100810898Sroland.mainz@nrubsig.org {
100910898Sroland.mainz@nrubsig.org fts->current->nlink--;
101010898Sroland.mainz@nrubsig.org if (fts->current->must == 1)
101110898Sroland.mainz@nrubsig.org fts->current->must = 0;
101210898Sroland.mainz@nrubsig.org if (!(fts->flags & FTS_SEEDOT))
101310898Sroland.mainz@nrubsig.org continue;
101410898Sroland.mainz@nrubsig.org n = 2;
101510898Sroland.mainz@nrubsig.org }
101610898Sroland.mainz@nrubsig.org else
101710898Sroland.mainz@nrubsig.org n = 0;
10184887Schin }
10194887Schin else
10204887Schin n = 0;
10214887Schin
10224887Schin /*
102310898Sroland.mainz@nrubsig.org * make a new entry
10244887Schin */
10254887Schin
102610898Sroland.mainz@nrubsig.org i = D_NAMLEN(d);
102710898Sroland.mainz@nrubsig.org if (!(f = node(fts, fts->current, s, i)))
102810898Sroland.mainz@nrubsig.org return 0;
102910898Sroland.mainz@nrubsig.org TYPE(f, D_TYPE(d));
103010898Sroland.mainz@nrubsig.org
10314887Schin /*
103210898Sroland.mainz@nrubsig.org * check for space
10334887Schin */
10344887Schin
103510898Sroland.mainz@nrubsig.org if (i >= fts->endbuf - fts->endbase)
10364887Schin {
103710898Sroland.mainz@nrubsig.org if (resize(fts, i))
103810898Sroland.mainz@nrubsig.org return 0;
103910898Sroland.mainz@nrubsig.org fts->endbase = fts->base + fts->baselen;
104010898Sroland.mainz@nrubsig.org if (fts->endbase[-1] != '/')
104110898Sroland.mainz@nrubsig.org fts->endbase++;
10424887Schin }
104310898Sroland.mainz@nrubsig.org if (fts->cpname)
104410898Sroland.mainz@nrubsig.org {
104510898Sroland.mainz@nrubsig.org memcpy(fts->endbase, s, i + 1);
104610898Sroland.mainz@nrubsig.org if (fts->cd)
104710898Sroland.mainz@nrubsig.org s = fts->path;
104810898Sroland.mainz@nrubsig.org }
104910898Sroland.mainz@nrubsig.org if (n)
10504887Schin {
10514887Schin /*
105210898Sroland.mainz@nrubsig.org * don't recurse on . and ..
10534887Schin */
10544887Schin
105510898Sroland.mainz@nrubsig.org if (n == 1)
105610898Sroland.mainz@nrubsig.org f->fts_statp = fts->current->fts_statp;
105710898Sroland.mainz@nrubsig.org else
105810898Sroland.mainz@nrubsig.org {
105910898Sroland.mainz@nrubsig.org if (f->fts_info != FTS_NS)
106010898Sroland.mainz@nrubsig.org fts->dotdot = f;
106110898Sroland.mainz@nrubsig.org if (fts->current->fts_parent->fts_level < 0)
106210898Sroland.mainz@nrubsig.org {
106310898Sroland.mainz@nrubsig.org f->fts_statp = &fts->current->fts_parent->statb;
106410898Sroland.mainz@nrubsig.org info(fts, f, s, f->fts_statp, 0);
106510898Sroland.mainz@nrubsig.org }
106610898Sroland.mainz@nrubsig.org else
106710898Sroland.mainz@nrubsig.org f->fts_statp = fts->current->fts_parent->fts_statp;
106810898Sroland.mainz@nrubsig.org }
106910898Sroland.mainz@nrubsig.org f->fts_info = FTS_DOT;
107010898Sroland.mainz@nrubsig.org }
107110898Sroland.mainz@nrubsig.org else if ((fts->nostat || SKIP(fts, f)) && (f->fts_info = FTS_NSOK) || info(fts, f, s, &f->statb, fts->flags))
107210898Sroland.mainz@nrubsig.org f->statb.st_ino = D_FILENO(d);
107310898Sroland.mainz@nrubsig.org if (fts->comparf)
107410898Sroland.mainz@nrubsig.org fts->root = search(f, fts->root, fts->comparf, 1);
107510898Sroland.mainz@nrubsig.org else if (fts->children || f->fts_info == FTS_D || f->fts_info == FTS_SL)
107610898Sroland.mainz@nrubsig.org {
107710898Sroland.mainz@nrubsig.org if (fts->top)
107810898Sroland.mainz@nrubsig.org fts->bot = fts->bot->fts_link = f;
107910898Sroland.mainz@nrubsig.org else
108010898Sroland.mainz@nrubsig.org fts->top = fts->bot = f;
108110898Sroland.mainz@nrubsig.org }
108210898Sroland.mainz@nrubsig.org else
108310898Sroland.mainz@nrubsig.org {
10844887Schin /*
108510898Sroland.mainz@nrubsig.org * terminal node
10864887Schin */
10874887Schin
108810898Sroland.mainz@nrubsig.org f->fts_path = PATH(fts, fts->path, 1);
108910898Sroland.mainz@nrubsig.org f->fts_pathlen = fts->endbase - f->fts_path + f->fts_namelen;
109010898Sroland.mainz@nrubsig.org f->fts_accpath = ACCESS(fts, f);
109110898Sroland.mainz@nrubsig.org fts->previous = fts->current;
109210898Sroland.mainz@nrubsig.org fts->current = f;
109310898Sroland.mainz@nrubsig.org fts->state = FTS_terminal;
10944887Schin goto note;
10954887Schin }
10964887Schin }
10974887Schin
10984887Schin /*
109910898Sroland.mainz@nrubsig.org * done with the directory
110010898Sroland.mainz@nrubsig.org */
110110898Sroland.mainz@nrubsig.org
110210898Sroland.mainz@nrubsig.org closedir(fts->dir);
110310898Sroland.mainz@nrubsig.org fts->dir = 0;
110410898Sroland.mainz@nrubsig.org if (fts->root)
110510898Sroland.mainz@nrubsig.org getlist(&fts->top, &fts->bot, fts->root);
110610898Sroland.mainz@nrubsig.org if (fts->children)
110710898Sroland.mainz@nrubsig.org {
110810898Sroland.mainz@nrubsig.org /*
110910898Sroland.mainz@nrubsig.org * try moving back to parent dir
111010898Sroland.mainz@nrubsig.org */
111110898Sroland.mainz@nrubsig.org
111210898Sroland.mainz@nrubsig.org fts->base[fts->baselen] = 0;
111310898Sroland.mainz@nrubsig.org if (fts->cd <= 0)
111410898Sroland.mainz@nrubsig.org {
111510898Sroland.mainz@nrubsig.org f = fts->current->fts_parent;
111610898Sroland.mainz@nrubsig.org if (fts->cd < 0
111710898Sroland.mainz@nrubsig.org || f != fts->curdir
111810898Sroland.mainz@nrubsig.org || !fts->dotdot
111910898Sroland.mainz@nrubsig.org || !SAME(f->fts_statp, fts->dotdot->fts_statp)
112010898Sroland.mainz@nrubsig.org || fts->pwd && fts->pwd->symlink
112110898Sroland.mainz@nrubsig.org || (fts->cd = chdir("..")) < 0
112210898Sroland.mainz@nrubsig.org #ifdef verify
112310898Sroland.mainz@nrubsig.org || stat(".", &sb) < 0
112410898Sroland.mainz@nrubsig.org || !SAME(&sb, fts->dotdot->fts_statp)
112510898Sroland.mainz@nrubsig.org #endif
112610898Sroland.mainz@nrubsig.org )
112710898Sroland.mainz@nrubsig.org fts->cd = setpdir(fts->home, fts->path, fts->base);
112810898Sroland.mainz@nrubsig.org if (fts->pwd)
112910898Sroland.mainz@nrubsig.org fts->pwd = fts->pwd->pwd;
113010898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : f;
113110898Sroland.mainz@nrubsig.org }
113210898Sroland.mainz@nrubsig.org f = fts->current;
113310898Sroland.mainz@nrubsig.org fts->link = f->fts_link;
113410898Sroland.mainz@nrubsig.org f->fts_link = fts->top;
113510898Sroland.mainz@nrubsig.org f->fts_path = PATH(fts, fts->path, f->fts_level);
113610898Sroland.mainz@nrubsig.org f->fts_pathlen = (fts->base - f->fts_path) + f->fts_namelen;
113710898Sroland.mainz@nrubsig.org f->fts_accpath = ACCESS(fts, f);
113810898Sroland.mainz@nrubsig.org fts->state = FTS_children_return;
113910898Sroland.mainz@nrubsig.org goto note;
114010898Sroland.mainz@nrubsig.org }
114110898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
114210898Sroland.mainz@nrubsig.org
114310898Sroland.mainz@nrubsig.org case FTS_children_resume:
114410898Sroland.mainz@nrubsig.org
114510898Sroland.mainz@nrubsig.org fts->base[fts->baselen] = 0;
114610898Sroland.mainz@nrubsig.org if (fts->top)
114710898Sroland.mainz@nrubsig.org {
114810898Sroland.mainz@nrubsig.org fts->bot->fts_link = fts->todo;
114910898Sroland.mainz@nrubsig.org fts->todo = fts->top;
115010898Sroland.mainz@nrubsig.org fts->top = 0;
115110898Sroland.mainz@nrubsig.org }
115210898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
115310898Sroland.mainz@nrubsig.org
115410898Sroland.mainz@nrubsig.org case FTS_popstack:
115510898Sroland.mainz@nrubsig.org
115610898Sroland.mainz@nrubsig.org /*
115710898Sroland.mainz@nrubsig.org * pop objects completely processed
11584887Schin */
11594887Schin
116010898Sroland.mainz@nrubsig.org fts->nd = 0;
116110898Sroland.mainz@nrubsig.org f = fts->current;
116210898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
116310898Sroland.mainz@nrubsig.org
116410898Sroland.mainz@nrubsig.org case FTS_popstack_resume:
116510898Sroland.mainz@nrubsig.org
116610898Sroland.mainz@nrubsig.org while (fts->todo && f == fts->todo)
116710898Sroland.mainz@nrubsig.org {
116810898Sroland.mainz@nrubsig.org t = f->fts_parent;
116910898Sroland.mainz@nrubsig.org if ((f->fts_info & FTS_DP) == FTS_D)
117010898Sroland.mainz@nrubsig.org {
117110898Sroland.mainz@nrubsig.org /*
117210898Sroland.mainz@nrubsig.org * delete from <dev,ino> tree
117310898Sroland.mainz@nrubsig.org */
117410898Sroland.mainz@nrubsig.org
117510898Sroland.mainz@nrubsig.org if (f != fts->diroot)
117610898Sroland.mainz@nrubsig.org fts->diroot = search(f, fts->diroot, statcmp, 0);
117710898Sroland.mainz@nrubsig.org fts->diroot = deleteroot(fts->diroot);
117810898Sroland.mainz@nrubsig.org if (f == fts->curdir)
117910898Sroland.mainz@nrubsig.org {
118010898Sroland.mainz@nrubsig.org fts->nd++;
118110898Sroland.mainz@nrubsig.org fts->curdir = t;
118210898Sroland.mainz@nrubsig.org }
118310898Sroland.mainz@nrubsig.org
118410898Sroland.mainz@nrubsig.org /*
118510898Sroland.mainz@nrubsig.org * perform post-order processing
118610898Sroland.mainz@nrubsig.org */
118710898Sroland.mainz@nrubsig.org
118810898Sroland.mainz@nrubsig.org if (!(fts->flags & FTS_NOPOSTORDER) &&
118910898Sroland.mainz@nrubsig.org f->status != FTS_SKIP &&
119010898Sroland.mainz@nrubsig.org f->status != FTS_NOPOSTORDER)
119110898Sroland.mainz@nrubsig.org {
119210898Sroland.mainz@nrubsig.org /*
119310898Sroland.mainz@nrubsig.org * move to parent dir
119410898Sroland.mainz@nrubsig.org */
119510898Sroland.mainz@nrubsig.org
119610898Sroland.mainz@nrubsig.org if (fts->nd > 0)
119710898Sroland.mainz@nrubsig.org fts->cd = popdirs(fts);
119810898Sroland.mainz@nrubsig.org if (fts->cd < 0)
119910898Sroland.mainz@nrubsig.org fts->cd = setpdir(fts->home, fts->path, fts->base);
120010898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : t;
120110898Sroland.mainz@nrubsig.org f->fts_info = FTS_DP;
120210898Sroland.mainz@nrubsig.org f->fts_path = PATH(fts, fts->path, f->fts_level);
120310898Sroland.mainz@nrubsig.org f->fts_pathlen = (fts->base - f->fts_path) + f->fts_namelen;
120410898Sroland.mainz@nrubsig.org f->fts_accpath = ACCESS(fts, f);
120510898Sroland.mainz@nrubsig.org
120610898Sroland.mainz@nrubsig.org /*
120710898Sroland.mainz@nrubsig.org * re-stat to update nlink/times
120810898Sroland.mainz@nrubsig.org */
120910898Sroland.mainz@nrubsig.org
121010898Sroland.mainz@nrubsig.org stat(f->fts_accpath, f->fts_statp);
121110898Sroland.mainz@nrubsig.org fts->link = f->fts_link;
121210898Sroland.mainz@nrubsig.org f->fts_link = 0;
121310898Sroland.mainz@nrubsig.org fts->state = FTS_popstack_return;
121410898Sroland.mainz@nrubsig.org goto note;
121510898Sroland.mainz@nrubsig.org }
121610898Sroland.mainz@nrubsig.org }
121710898Sroland.mainz@nrubsig.org
121810898Sroland.mainz@nrubsig.org /*
121910898Sroland.mainz@nrubsig.org * reset base
122010898Sroland.mainz@nrubsig.org */
122110898Sroland.mainz@nrubsig.org
122210898Sroland.mainz@nrubsig.org if (fts->base > fts->path + t->fts_namelen)
122310898Sroland.mainz@nrubsig.org fts->base--;
122410898Sroland.mainz@nrubsig.org *fts->base = 0;
122510898Sroland.mainz@nrubsig.org fts->base -= t->fts_namelen;
122610898Sroland.mainz@nrubsig.org
122710898Sroland.mainz@nrubsig.org /*
122810898Sroland.mainz@nrubsig.org * try again or delete from top of stack
122910898Sroland.mainz@nrubsig.org */
123010898Sroland.mainz@nrubsig.org
123110898Sroland.mainz@nrubsig.org if (f->status == FTS_AGAIN)
123210898Sroland.mainz@nrubsig.org {
123310898Sroland.mainz@nrubsig.org f->fts_info = FTS_D;
123410898Sroland.mainz@nrubsig.org f->status = 0;
123510898Sroland.mainz@nrubsig.org }
123610898Sroland.mainz@nrubsig.org else
123710898Sroland.mainz@nrubsig.org {
123810898Sroland.mainz@nrubsig.org fts->todo = fts->todo->fts_link;
123910898Sroland.mainz@nrubsig.org drop(fts, f);
124010898Sroland.mainz@nrubsig.org }
124110898Sroland.mainz@nrubsig.org f = t;
124210898Sroland.mainz@nrubsig.org }
12434887Schin
12444887Schin /*
124510898Sroland.mainz@nrubsig.org * reset current directory
12464887Schin */
12474887Schin
124810898Sroland.mainz@nrubsig.org if (fts->nd > 0 && popdirs(fts) < 0)
12494887Schin {
125010898Sroland.mainz@nrubsig.org pathcd(fts->home, NiL);
125110898Sroland.mainz@nrubsig.org fts->curdir = 0;
125210898Sroland.mainz@nrubsig.org fts->cd = -1;
12534887Schin }
125410898Sroland.mainz@nrubsig.org if (fts->todo)
12554887Schin {
125610898Sroland.mainz@nrubsig.org if (*fts->base)
125710898Sroland.mainz@nrubsig.org fts->base += f->fts_namelen;
125810898Sroland.mainz@nrubsig.org if (*(fts->base - 1) != '/')
125910898Sroland.mainz@nrubsig.org *fts->base++ = '/';
126010898Sroland.mainz@nrubsig.org *fts->base = 0;
126110898Sroland.mainz@nrubsig.org f = fts->todo;
126210898Sroland.mainz@nrubsig.org fts->state = FTS_todo;
126310898Sroland.mainz@nrubsig.org continue;
12644887Schin }
126510898Sroland.mainz@nrubsig.org return 0;
12664887Schin
126710898Sroland.mainz@nrubsig.org case FTS_children_return:
12684887Schin
126910898Sroland.mainz@nrubsig.org f = fts->current;
127010898Sroland.mainz@nrubsig.org f->fts_link = fts->link;
127110898Sroland.mainz@nrubsig.org
127210898Sroland.mainz@nrubsig.org /*
127310898Sroland.mainz@nrubsig.org * chdir down again
127410898Sroland.mainz@nrubsig.org */
12754887Schin
127610898Sroland.mainz@nrubsig.org i = f->fts_info != FTS_DNX;
127710898Sroland.mainz@nrubsig.org n = f->status == FTS_SKIP;
127810898Sroland.mainz@nrubsig.org if (!n && fts->cd == 0)
127910898Sroland.mainz@nrubsig.org {
128010898Sroland.mainz@nrubsig.org if ((fts->cd = chdir(fts->base)) < 0)
128110898Sroland.mainz@nrubsig.org pathcd(fts->home, NiL);
128210898Sroland.mainz@nrubsig.org else if (fts->pwd != f)
128310898Sroland.mainz@nrubsig.org {
128410898Sroland.mainz@nrubsig.org f->pwd = fts->pwd;
128510898Sroland.mainz@nrubsig.org fts->pwd = f;
128610898Sroland.mainz@nrubsig.org }
128710898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : f;
128810898Sroland.mainz@nrubsig.org }
12894887Schin
129010898Sroland.mainz@nrubsig.org /*
129110898Sroland.mainz@nrubsig.org * prune
129210898Sroland.mainz@nrubsig.org */
12934887Schin
129410898Sroland.mainz@nrubsig.org if (fts->base[fts->baselen - 1] != '/')
129510898Sroland.mainz@nrubsig.org fts->base[fts->baselen] = '/';
129610898Sroland.mainz@nrubsig.org for (fts->bot = 0, f = fts->top; f; )
129710898Sroland.mainz@nrubsig.org if (n || f->status == FTS_SKIP)
129810898Sroland.mainz@nrubsig.org {
129910898Sroland.mainz@nrubsig.org if (fts->bot)
130010898Sroland.mainz@nrubsig.org fts->bot->fts_link = f->fts_link;
130110898Sroland.mainz@nrubsig.org else
130210898Sroland.mainz@nrubsig.org fts->top = f->fts_link;
130310898Sroland.mainz@nrubsig.org drop(fts, f);
130410898Sroland.mainz@nrubsig.org f = fts->bot ? fts->bot->fts_link : fts->top;
130510898Sroland.mainz@nrubsig.org }
130610898Sroland.mainz@nrubsig.org else
130710898Sroland.mainz@nrubsig.org {
130810898Sroland.mainz@nrubsig.org if (fts->children > 1 && i)
130910898Sroland.mainz@nrubsig.org {
131010898Sroland.mainz@nrubsig.org if (f->status == FTS_STAT)
131110898Sroland.mainz@nrubsig.org info(fts, f, NiL, f->fts_statp, 0);
131210898Sroland.mainz@nrubsig.org else if (f->fts_info == FTS_NSOK && !SKIP(fts, f))
131310898Sroland.mainz@nrubsig.org {
131410898Sroland.mainz@nrubsig.org s = f->fts_name;
131510898Sroland.mainz@nrubsig.org if (fts->cd)
131610898Sroland.mainz@nrubsig.org {
131710898Sroland.mainz@nrubsig.org memcpy(fts->endbase, s, f->fts_namelen + 1);
131810898Sroland.mainz@nrubsig.org s = fts->path;
131910898Sroland.mainz@nrubsig.org }
132010898Sroland.mainz@nrubsig.org info(fts, f, s, f->fts_statp, fts->flags);
132110898Sroland.mainz@nrubsig.org }
132210898Sroland.mainz@nrubsig.org }
132310898Sroland.mainz@nrubsig.org fts->bot = f;
132410898Sroland.mainz@nrubsig.org f = f->fts_link;
132510898Sroland.mainz@nrubsig.org }
132610898Sroland.mainz@nrubsig.org fts->children = 0;
132710898Sroland.mainz@nrubsig.org fts->state = FTS_children_resume;
132810898Sroland.mainz@nrubsig.org continue;
13294887Schin
133010898Sroland.mainz@nrubsig.org case FTS_popstack_return:
133110898Sroland.mainz@nrubsig.org
133210898Sroland.mainz@nrubsig.org f = fts->todo;
133310898Sroland.mainz@nrubsig.org f->fts_link = fts->link;
133410898Sroland.mainz@nrubsig.org f->fts_info = f->status == FTS_AGAIN ? FTS_DP : 0;
133510898Sroland.mainz@nrubsig.org fts->state = FTS_popstack_resume;
133610898Sroland.mainz@nrubsig.org continue;
13374887Schin
133810898Sroland.mainz@nrubsig.org case FTS_preorder_return:
133910898Sroland.mainz@nrubsig.org
134010898Sroland.mainz@nrubsig.org f = fts->current;
134110898Sroland.mainz@nrubsig.org f->fts_link = fts->link;
134210898Sroland.mainz@nrubsig.org
134310898Sroland.mainz@nrubsig.org /*
134410898Sroland.mainz@nrubsig.org * follow symlink if asked to
134510898Sroland.mainz@nrubsig.org */
134610898Sroland.mainz@nrubsig.org
134710898Sroland.mainz@nrubsig.org if (f->status == FTS_FOLLOW)
13484887Schin {
134910898Sroland.mainz@nrubsig.org f->status = 0;
135010898Sroland.mainz@nrubsig.org if (f->fts_info == FTS_SL || ISTYPE(f, DT_LNK) || f->fts_info == FTS_NSOK)
13514887Schin {
135210898Sroland.mainz@nrubsig.org info(fts, f, f->fts_accpath, f->fts_statp, 0);
135310898Sroland.mainz@nrubsig.org if (f->fts_info != FTS_SL)
13544887Schin {
135510898Sroland.mainz@nrubsig.org fts->state = FTS_preorder;
135610898Sroland.mainz@nrubsig.org continue;
13574887Schin }
13584887Schin }
13594887Schin }
136010898Sroland.mainz@nrubsig.org
136110898Sroland.mainz@nrubsig.org /*
136210898Sroland.mainz@nrubsig.org * about to prune this f and already at home
136310898Sroland.mainz@nrubsig.org */
13644887Schin
136510898Sroland.mainz@nrubsig.org if (fts->cd == 0 && f->fts_level == 0 && f->nd)
136610898Sroland.mainz@nrubsig.org fts->cd = -1;
136710898Sroland.mainz@nrubsig.org fts->state = FTS_preorder_resume;
136810898Sroland.mainz@nrubsig.org continue;
13694887Schin
137010898Sroland.mainz@nrubsig.org case FTS_terminal:
13714887Schin
137210898Sroland.mainz@nrubsig.org f = fts->current;
137310898Sroland.mainz@nrubsig.org if (f->status == FTS_FOLLOW)
13744887Schin {
137510898Sroland.mainz@nrubsig.org f->status = 0;
137610898Sroland.mainz@nrubsig.org if (f->fts_info == FTS_SL || ISTYPE(f, DT_LNK) || f->fts_info == FTS_NSOK)
13774887Schin {
137810898Sroland.mainz@nrubsig.org info(fts, f, f->fts_accpath, f->fts_statp, 0);
137910898Sroland.mainz@nrubsig.org if (f->symlink && f->fts_info != FTS_SL)
138010898Sroland.mainz@nrubsig.org {
138110898Sroland.mainz@nrubsig.org if (!(f->fts_link = fts->top))
138210898Sroland.mainz@nrubsig.org fts->bot = f;
138310898Sroland.mainz@nrubsig.org fts->top = f;
138410898Sroland.mainz@nrubsig.org fts->current = fts->previous;
138510898Sroland.mainz@nrubsig.org fts->state = FTS_readdir;
138610898Sroland.mainz@nrubsig.org continue;
138710898Sroland.mainz@nrubsig.org }
13884887Schin }
13894887Schin }
139010898Sroland.mainz@nrubsig.org f = f->fts_parent;
139110898Sroland.mainz@nrubsig.org drop(fts, fts->current);
139210898Sroland.mainz@nrubsig.org fts->current = f;
139310898Sroland.mainz@nrubsig.org fts->state = FTS_readdir;
139410898Sroland.mainz@nrubsig.org continue;
13954887Schin
139610898Sroland.mainz@nrubsig.org case FTS_error:
13974887Schin
139810898Sroland.mainz@nrubsig.org return 0;
13994887Schin
140010898Sroland.mainz@nrubsig.org default:
140110898Sroland.mainz@nrubsig.org
140210898Sroland.mainz@nrubsig.org fts->fts_errno = EINVAL;
140310898Sroland.mainz@nrubsig.org fts->state = FTS_error;
140410898Sroland.mainz@nrubsig.org return 0;
140510898Sroland.mainz@nrubsig.org
14064887Schin }
14074887Schin note:
140810898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
140910898Sroland.mainz@nrubsig.org f->_fts_pathlen = (unsigned short)f->fts_pathlen;
141010898Sroland.mainz@nrubsig.org #endif
14114887Schin for (p = notify; p; p = p->next)
14124887Schin if ((n = (*p->notifyf)(fts, f, p->context)) > 0)
14134887Schin break;
14144887Schin else if (n < 0)
14154887Schin {
14164887Schin fts->fts_errno = EINVAL;
14174887Schin fts->state = FTS_error;
14184887Schin return 0;
14194887Schin }
14204887Schin return f;
14214887Schin }
14224887Schin
14234887Schin /*
14244887Schin * set stream or entry flags
14254887Schin */
14264887Schin
14274887Schin int
fts_set(register FTS * fts,register FTSENT * f,int status)14284887Schin fts_set(register FTS* fts, register FTSENT* f, int status)
14294887Schin {
14304887Schin if (fts || !f || f->fts->current != f)
14314887Schin return -1;
14324887Schin switch (status)
14334887Schin {
14344887Schin case FTS_AGAIN:
14354887Schin break;
14364887Schin case FTS_FOLLOW:
14374887Schin if (!(f->fts_info & FTS_SL))
14384887Schin return -1;
14394887Schin break;
14404887Schin case FTS_NOPOSTORDER:
14414887Schin break;
14424887Schin case FTS_SKIP:
14434887Schin if ((f->fts_info & (FTS_D|FTS_P)) != FTS_D)
14444887Schin return -1;
14454887Schin break;
14464887Schin default:
14474887Schin return -1;
14484887Schin }
14494887Schin f->status = status;
14504887Schin return 0;
14514887Schin }
14524887Schin
14534887Schin /*
14544887Schin * return the list of child entries
14554887Schin */
14564887Schin
14574887Schin FTSENT*
fts_children(register FTS * fts,int flags)14584887Schin fts_children(register FTS* fts, int flags)
14594887Schin {
14604887Schin register FTSENT* f;
14614887Schin
14624887Schin switch (fts->state)
14634887Schin {
14644887Schin
14654887Schin case 0:
14664887Schin
146710898Sroland.mainz@nrubsig.org if (fts->comparf)
146810898Sroland.mainz@nrubsig.org order(fts);
14694887Schin fts->state = FTS_top_return;
14704887Schin return fts->todo;
14714887Schin
14724887Schin case FTS_preorder_return:
14734887Schin
14744887Schin fts->children = ((flags | fts->flags) & FTS_NOSTAT) ? 2 : 1;
14754887Schin if (f = fts_read(fts))
14764887Schin f = f->fts_link;
14774887Schin return f;
14784887Schin
14794887Schin }
14804887Schin return 0;
14814887Schin }
14824887Schin
14834887Schin /*
14844887Schin * return default (FTS_LOGICAL|FTS_META|FTS_PHYSICAL|FTS_SEEDOTDIR) flags
14854887Schin * conditioned by astconf()
14864887Schin */
14874887Schin
14884887Schin int
fts_flags(void)14894887Schin fts_flags(void)
14904887Schin {
14914887Schin register char* s;
14924887Schin
14934887Schin s = astconf("PATH_RESOLVE", NiL, NiL);
14944887Schin if (streq(s, "logical"))
14954887Schin return FTS_LOGICAL;
14964887Schin if (streq(s, "physical"))
14974887Schin return FTS_PHYSICAL|FTS_SEEDOTDIR;
14984887Schin return FTS_META|FTS_PHYSICAL|FTS_SEEDOTDIR;
14994887Schin }
15004887Schin
15014887Schin /*
15028462SApril.Chin@Sun.COM * return 1 if ent is mounted on a local filesystem
15038462SApril.Chin@Sun.COM */
15048462SApril.Chin@Sun.COM
15058462SApril.Chin@Sun.COM int
fts_local(FTSENT * ent)15068462SApril.Chin@Sun.COM fts_local(FTSENT* ent)
15078462SApril.Chin@Sun.COM {
15088462SApril.Chin@Sun.COM #ifdef ST_LOCAL
15098462SApril.Chin@Sun.COM struct statvfs fs;
15108462SApril.Chin@Sun.COM
15118462SApril.Chin@Sun.COM return statvfs(ent->fts_path, &fs) || (fs.f_flag & ST_LOCAL);
15128462SApril.Chin@Sun.COM #else
15138462SApril.Chin@Sun.COM return !strgrpmatch(fmtfs(ent->fts_statp), "([an]fs|samb)", NiL, 0, STR_LEFT|STR_ICASE);
15148462SApril.Chin@Sun.COM #endif
15158462SApril.Chin@Sun.COM }
15168462SApril.Chin@Sun.COM
15178462SApril.Chin@Sun.COM /*
15184887Schin * close an open fts stream
15194887Schin */
15204887Schin
15214887Schin int
fts_close(register FTS * fts)15224887Schin fts_close(register FTS* fts)
15234887Schin {
15244887Schin register FTSENT* f;
15254887Schin register FTSENT* x;
15264887Schin
15274887Schin if (fts->dir)
15284887Schin closedir(fts->dir);
15294887Schin if (fts->cd == 0)
15304887Schin pathcd(fts->home, NiL);
15314887Schin free(fts->home);
15324887Schin if (fts->state == FTS_children_return)
15334887Schin fts->current->fts_link = fts->link;
15344887Schin if (fts->top)
15354887Schin {
15364887Schin fts->bot->fts_link = fts->todo;
15374887Schin fts->todo = fts->top;
15384887Schin }
15394887Schin for (f = fts->todo; f; f = x)
15404887Schin {
15414887Schin x = f->fts_link;
15424887Schin free(f);
15434887Schin }
15444887Schin for (f = fts->free; f; f = x)
15454887Schin {
15464887Schin x = f->fts_link;
15474887Schin free(f);
15484887Schin }
15498462SApril.Chin@Sun.COM free(fts);
15504887Schin return 0;
15514887Schin }
15524887Schin
15534887Schin /*
15544887Schin * register function to be called for each fts_read() entry
15558462SApril.Chin@Sun.COM * context==0 => unregister notifyf
15564887Schin */
15574887Schin
15584887Schin int
fts_notify(Notify_f notifyf,void * context)15594887Schin fts_notify(Notify_f notifyf, void* context)
15604887Schin {
15614887Schin register Notify_t* np;
15628462SApril.Chin@Sun.COM register Notify_t* pp;
15634887Schin
15648462SApril.Chin@Sun.COM if (context)
15658462SApril.Chin@Sun.COM {
15668462SApril.Chin@Sun.COM if (!(np = newof(0, Notify_t, 1, 0)))
15678462SApril.Chin@Sun.COM return -1;
15688462SApril.Chin@Sun.COM np->notifyf = notifyf;
15698462SApril.Chin@Sun.COM np->context = context;
15708462SApril.Chin@Sun.COM np->next = notify;
15718462SApril.Chin@Sun.COM notify = np;
15728462SApril.Chin@Sun.COM }
15738462SApril.Chin@Sun.COM else
15748462SApril.Chin@Sun.COM {
15758462SApril.Chin@Sun.COM for (np = notify, pp = 0; np; pp = np, np = np->next)
15768462SApril.Chin@Sun.COM if (np->notifyf == notifyf)
15778462SApril.Chin@Sun.COM {
15788462SApril.Chin@Sun.COM if (pp)
15798462SApril.Chin@Sun.COM pp->next = np->next;
15808462SApril.Chin@Sun.COM else
15818462SApril.Chin@Sun.COM notify = np->next;
15828462SApril.Chin@Sun.COM free(np);
15838462SApril.Chin@Sun.COM return 0;
15848462SApril.Chin@Sun.COM }
15854887Schin return -1;
15868462SApril.Chin@Sun.COM }
15874887Schin return 0;
15884887Schin }
1589