14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1985-2009 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 42*10898Sroland.mainz@nrubsig.org #define _fts_status status 43*10898Sroland.mainz@nrubsig.org #define _fts_statb statb 44*10898Sroland.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 */ \ 61*10898Sroland.mainz@nrubsig.org size_t baselen; /* current strlen(base) */ \ 62*10898Sroland.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* 177*10898Sroland.mainz@nrubsig.org node(FTS* fts, FTSENT* parent, register char* name, register size_t namelen) 1784887Schin { 1794887Schin register FTSENT* f; 180*10898Sroland.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; 202*10898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101 203*10898Sroland.mainz@nrubsig.org f->_fts_level = (short)f->fts_level; 204*10898Sroland.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; 210*10898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101 211*10898Sroland.mainz@nrubsig.org f->_fts_namelen = (unsigned short)f->fts_namelen; 212*10898Sroland.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 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* 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* 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 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)) 398*10898Sroland.mainz@nrubsig.org { 399*10898Sroland.mainz@nrubsig.org (*bot)->fts_link = 0; 4004887Schin return; 401*10898Sroland.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 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 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 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 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 577*10898Sroland.mainz@nrubsig.org * ordering delayed until first fts_read() 578*10898Sroland.mainz@nrubsig.org * to give caller a chance to set fts->handle 5794887Schin */ 5804887Schin 5814887Schin static FTSENT* 5824887Schin toplist(FTS* fts, register char* const* pathnames) 5834887Schin { 5844887Schin register char* path; 5854887Schin register FTSENT* f; 586*10898Sroland.mainz@nrubsig.org register FTSENT* top; 587*10898Sroland.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); 597*10898Sroland.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 } 637*10898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101 638*10898Sroland.mainz@nrubsig.org f->_fts_namelen = (unsigned short)f->fts_namelen; 639*10898Sroland.mainz@nrubsig.org #endif 6404887Schin if (!*path) 6414887Schin { 6424887Schin errno = ENOENT; 6434887Schin f->fts_info = FTS_NS; 6444887Schin } 6454887Schin else 646*10898Sroland.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 { 656*10898Sroland.mainz@nrubsig.org *f->fts_statp = st; 657*10898Sroland.mainz@nrubsig.org info(fts, f, NiL, f->fts_statp, 0); 6584887Schin } 6594887Schin #endif 660*10898Sroland.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 /* 672*10898Sroland.mainz@nrubsig.org * order fts->todo if fts->comparf != 0 673*10898Sroland.mainz@nrubsig.org */ 674*10898Sroland.mainz@nrubsig.org 675*10898Sroland.mainz@nrubsig.org static void 676*10898Sroland.mainz@nrubsig.org order(FTS* fts) 677*10898Sroland.mainz@nrubsig.org { 678*10898Sroland.mainz@nrubsig.org register FTSENT* f; 679*10898Sroland.mainz@nrubsig.org register FTSENT* root; 680*10898Sroland.mainz@nrubsig.org FTSENT* top; 681*10898Sroland.mainz@nrubsig.org FTSENT* bot; 682*10898Sroland.mainz@nrubsig.org 683*10898Sroland.mainz@nrubsig.org top = bot = root = 0; 684*10898Sroland.mainz@nrubsig.org for (f = fts->todo; f; f = f->fts_link) 685*10898Sroland.mainz@nrubsig.org root = search(f, root, fts->comparf, 1); 686*10898Sroland.mainz@nrubsig.org getlist(&top, &bot, root); 687*10898Sroland.mainz@nrubsig.org fts->todo = top; 688*10898Sroland.mainz@nrubsig.org } 689*10898Sroland.mainz@nrubsig.org 690*10898Sroland.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 697*10898Sroland.mainz@nrubsig.org resize(register FTS* fts, size_t inc) 6984887Schin { 6994887Schin register char* old; 7004887Schin register char* newp; 701*10898Sroland.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* 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; 773*10898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101 774*10898Sroland.mainz@nrubsig.org fts->parent->_fts_level = (short)fts->parent->fts_level; 775*10898Sroland.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* 8084887Schin fts_read(register FTS* fts) 8094887Schin { 8104887Schin register char* s; 8114887Schin register int n; 8124887Schin register FTSENT* f; 8134887Schin struct dirent* d; 814*10898Sroland.mainz@nrubsig.org size_t i; 8154887Schin FTSENT* t; 8164887Schin Notify_t* p; 8174887Schin #ifdef verify 8184887Schin struct stat sb; 8194887Schin #endif 8204887Schin 821*10898Sroland.mainz@nrubsig.org for (;;) 822*10898Sroland.mainz@nrubsig.org switch (fts->state) 823*10898Sroland.mainz@nrubsig.org { 8244887Schin 825*10898Sroland.mainz@nrubsig.org case FTS_top_return: 8264887Schin 827*10898Sroland.mainz@nrubsig.org f = fts->todo; 828*10898Sroland.mainz@nrubsig.org t = 0; 829*10898Sroland.mainz@nrubsig.org while (f) 830*10898Sroland.mainz@nrubsig.org if (f->status == FTS_SKIP) 8314887Schin { 832*10898Sroland.mainz@nrubsig.org if (t) 833*10898Sroland.mainz@nrubsig.org { 834*10898Sroland.mainz@nrubsig.org t->fts_link = f->fts_link; 835*10898Sroland.mainz@nrubsig.org drop(fts, f); 836*10898Sroland.mainz@nrubsig.org f = t->fts_link; 837*10898Sroland.mainz@nrubsig.org } 838*10898Sroland.mainz@nrubsig.org else 839*10898Sroland.mainz@nrubsig.org { 840*10898Sroland.mainz@nrubsig.org fts->todo = f->fts_link; 841*10898Sroland.mainz@nrubsig.org drop(fts, f); 842*10898Sroland.mainz@nrubsig.org f = fts->todo; 843*10898Sroland.mainz@nrubsig.org } 8444887Schin } 8454887Schin else 8464887Schin { 847*10898Sroland.mainz@nrubsig.org t = f; 848*10898Sroland.mainz@nrubsig.org f = f->fts_link; 849*10898Sroland.mainz@nrubsig.org } 850*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 851*10898Sroland.mainz@nrubsig.org 852*10898Sroland.mainz@nrubsig.org case 0: 853*10898Sroland.mainz@nrubsig.org 854*10898Sroland.mainz@nrubsig.org if (!fts->state && fts->comparf) 855*10898Sroland.mainz@nrubsig.org order(fts); 856*10898Sroland.mainz@nrubsig.org if (!(f = fts->todo)) 857*10898Sroland.mainz@nrubsig.org return 0; 858*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 859*10898Sroland.mainz@nrubsig.org 860*10898Sroland.mainz@nrubsig.org case FTS_todo: 861*10898Sroland.mainz@nrubsig.org 862*10898Sroland.mainz@nrubsig.org /* 863*10898Sroland.mainz@nrubsig.org * process the top object on the stack 864*10898Sroland.mainz@nrubsig.org */ 865*10898Sroland.mainz@nrubsig.org 866*10898Sroland.mainz@nrubsig.org fts->root = fts->top = fts->bot = 0; 867*10898Sroland.mainz@nrubsig.org 868*10898Sroland.mainz@nrubsig.org /* 869*10898Sroland.mainz@nrubsig.org * initialize the top level 870*10898Sroland.mainz@nrubsig.org */ 871*10898Sroland.mainz@nrubsig.org 872*10898Sroland.mainz@nrubsig.org if (f->fts_level == 0) 873*10898Sroland.mainz@nrubsig.org { 874*10898Sroland.mainz@nrubsig.org fts->parent->fts_number = f->fts_number; 875*10898Sroland.mainz@nrubsig.org fts->parent->fts_pointer = f->fts_pointer; 876*10898Sroland.mainz@nrubsig.org fts->parent->fts_statp = f->fts_statp; 877*10898Sroland.mainz@nrubsig.org fts->parent->statb = *f->fts_statp; 878*10898Sroland.mainz@nrubsig.org f->fts_parent = fts->parent; 879*10898Sroland.mainz@nrubsig.org fts->diroot = 0; 880*10898Sroland.mainz@nrubsig.org if (fts->cd == 0) 881*10898Sroland.mainz@nrubsig.org pathcd(fts->home, NiL); 882*10898Sroland.mainz@nrubsig.org else if (fts->cd < 0) 883*10898Sroland.mainz@nrubsig.org fts->cd = 0; 884*10898Sroland.mainz@nrubsig.org fts->pwd = f->fts_parent; 885*10898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : f->fts_parent; 886*10898Sroland.mainz@nrubsig.org *(fts->base = fts->path) = 0; 887*10898Sroland.mainz@nrubsig.org } 888*10898Sroland.mainz@nrubsig.org 889*10898Sroland.mainz@nrubsig.org /* 890*10898Sroland.mainz@nrubsig.org * chdir to parent if asked for 891*10898Sroland.mainz@nrubsig.org */ 892*10898Sroland.mainz@nrubsig.org 893*10898Sroland.mainz@nrubsig.org if (fts->cd < 0) 894*10898Sroland.mainz@nrubsig.org { 895*10898Sroland.mainz@nrubsig.org fts->cd = setdir(fts->home, fts->path); 896*10898Sroland.mainz@nrubsig.org fts->pwd = f->fts_parent; 897*10898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : f->fts_parent; 898*10898Sroland.mainz@nrubsig.org } 899*10898Sroland.mainz@nrubsig.org 900*10898Sroland.mainz@nrubsig.org /* 901*10898Sroland.mainz@nrubsig.org * add object's name to the path 902*10898Sroland.mainz@nrubsig.org */ 903*10898Sroland.mainz@nrubsig.org 904*10898Sroland.mainz@nrubsig.org if ((fts->baselen = f->fts_namelen) >= (fts->endbuf - fts->base) && resize(fts, fts->baselen)) 905*10898Sroland.mainz@nrubsig.org return 0; 906*10898Sroland.mainz@nrubsig.org memcpy(fts->base, f->name, fts->baselen + 1); 907*10898Sroland.mainz@nrubsig.org fts->name = fts->cd ? fts->path : fts->base; 908*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 909*10898Sroland.mainz@nrubsig.org 910*10898Sroland.mainz@nrubsig.org case FTS_preorder: 911*10898Sroland.mainz@nrubsig.org 912*10898Sroland.mainz@nrubsig.org /* 913*10898Sroland.mainz@nrubsig.org * check for cycle and open dir 914*10898Sroland.mainz@nrubsig.org */ 915*10898Sroland.mainz@nrubsig.org 916*10898Sroland.mainz@nrubsig.org if (f->fts_info == FTS_D) 917*10898Sroland.mainz@nrubsig.org { 918*10898Sroland.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) 919*10898Sroland.mainz@nrubsig.org { 920*10898Sroland.mainz@nrubsig.org f->fts_info = FTS_DC; 921*10898Sroland.mainz@nrubsig.org f->fts_cycle = fts->diroot; 922*10898Sroland.mainz@nrubsig.org } 923*10898Sroland.mainz@nrubsig.org else if (!(fts->flags & FTS_TOP) && (!(fts->flags & FTS_XDEV) || f->statb.st_dev == f->fts_parent->statb.st_dev)) 924*10898Sroland.mainz@nrubsig.org { 925*10898Sroland.mainz@nrubsig.org /* 926*10898Sroland.mainz@nrubsig.org * buffer is known to be large enough here! 927*10898Sroland.mainz@nrubsig.org */ 928*10898Sroland.mainz@nrubsig.org 929*10898Sroland.mainz@nrubsig.org if (fts->base[fts->baselen - 1] != '/') 930*10898Sroland.mainz@nrubsig.org memcpy(fts->base + fts->baselen, "/.", 3); 931*10898Sroland.mainz@nrubsig.org if (!(fts->dir = opendir(fts->name))) 932*10898Sroland.mainz@nrubsig.org f->fts_info = FTS_DNX; 933*10898Sroland.mainz@nrubsig.org fts->base[fts->baselen] = 0; 934*10898Sroland.mainz@nrubsig.org if (!fts->dir && !(fts->dir = opendir(fts->name))) 935*10898Sroland.mainz@nrubsig.org f->fts_info = FTS_DNR; 9364887Schin } 9374887Schin } 938*10898Sroland.mainz@nrubsig.org f->nd = f->fts_info & ~FTS_DNX; 939*10898Sroland.mainz@nrubsig.org if (f->nd || !(fts->flags & FTS_NOPREORDER)) 9404887Schin { 941*10898Sroland.mainz@nrubsig.org fts->current = f; 942*10898Sroland.mainz@nrubsig.org fts->link = f->fts_link; 943*10898Sroland.mainz@nrubsig.org f->fts_link = 0; 944*10898Sroland.mainz@nrubsig.org f->fts_path = PATH(fts, fts->path, f->fts_level); 945*10898Sroland.mainz@nrubsig.org f->fts_pathlen = (fts->base - f->fts_path) + fts->baselen; 946*10898Sroland.mainz@nrubsig.org f->fts_accpath = ACCESS(fts, f); 947*10898Sroland.mainz@nrubsig.org fts->state = FTS_preorder_return; 948*10898Sroland.mainz@nrubsig.org goto note; 9494887Schin } 950*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 9514887Schin 952*10898Sroland.mainz@nrubsig.org case FTS_preorder_resume: 9534887Schin 954*10898Sroland.mainz@nrubsig.org /* 955*10898Sroland.mainz@nrubsig.org * prune 956*10898Sroland.mainz@nrubsig.org */ 9574887Schin 958*10898Sroland.mainz@nrubsig.org if (!fts->dir || f->nd || f->status == FTS_SKIP) 959*10898Sroland.mainz@nrubsig.org { 960*10898Sroland.mainz@nrubsig.org if (fts->dir) 961*10898Sroland.mainz@nrubsig.org { 962*10898Sroland.mainz@nrubsig.org closedir(fts->dir); 963*10898Sroland.mainz@nrubsig.org fts->dir = 0; 964*10898Sroland.mainz@nrubsig.org } 965*10898Sroland.mainz@nrubsig.org fts->state = FTS_popstack; 966*10898Sroland.mainz@nrubsig.org continue; 967*10898Sroland.mainz@nrubsig.org } 9684887Schin 969*10898Sroland.mainz@nrubsig.org /* 970*10898Sroland.mainz@nrubsig.org * FTS_D or FTS_DNX, about to read children 971*10898Sroland.mainz@nrubsig.org */ 9724887Schin 973*10898Sroland.mainz@nrubsig.org if (fts->cd == 0) 974*10898Sroland.mainz@nrubsig.org { 975*10898Sroland.mainz@nrubsig.org if ((fts->cd = chdir(fts->name)) < 0) 976*10898Sroland.mainz@nrubsig.org pathcd(fts->home, NiL); 977*10898Sroland.mainz@nrubsig.org else if (fts->pwd != f) 978*10898Sroland.mainz@nrubsig.org { 979*10898Sroland.mainz@nrubsig.org f->pwd = fts->pwd; 980*10898Sroland.mainz@nrubsig.org fts->pwd = f; 981*10898Sroland.mainz@nrubsig.org } 982*10898Sroland.mainz@nrubsig.org fts->curdir = fts->cd < 0 ? 0 : f; 9834887Schin } 984*10898Sroland.mainz@nrubsig.org fts->nostat = fts->children > 1 || f->fts_info == FTS_DNX; 985*10898Sroland.mainz@nrubsig.org fts->cpname = fts->cd && !fts->nostat || !fts->children && !fts->comparf; 986*10898Sroland.mainz@nrubsig.org fts->dotdot = 0; 987*10898Sroland.mainz@nrubsig.org fts->endbase = fts->base + fts->baselen; 988*10898Sroland.mainz@nrubsig.org if (fts->endbase[-1] != '/') 989*10898Sroland.mainz@nrubsig.org *fts->endbase++ = '/'; 9904887Schin fts->current = f; 991*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 9924887Schin 993*10898Sroland.mainz@nrubsig.org case FTS_readdir: 9944887Schin 995*10898Sroland.mainz@nrubsig.org while (d = readdir(fts->dir)) 9964887Schin { 997*10898Sroland.mainz@nrubsig.org s = d->d_name; 998*10898Sroland.mainz@nrubsig.org if (s[0] == '.') 9994887Schin { 1000*10898Sroland.mainz@nrubsig.org if (s[1] == 0) 1001*10898Sroland.mainz@nrubsig.org { 1002*10898Sroland.mainz@nrubsig.org fts->current->nlink--; 1003*10898Sroland.mainz@nrubsig.org if (!(fts->flags & FTS_SEEDOT)) 1004*10898Sroland.mainz@nrubsig.org continue; 1005*10898Sroland.mainz@nrubsig.org n = 1; 1006*10898Sroland.mainz@nrubsig.org } 1007*10898Sroland.mainz@nrubsig.org else if (s[1] == '.' && s[2] == 0) 1008*10898Sroland.mainz@nrubsig.org { 1009*10898Sroland.mainz@nrubsig.org fts->current->nlink--; 1010*10898Sroland.mainz@nrubsig.org if (fts->current->must == 1) 1011*10898Sroland.mainz@nrubsig.org fts->current->must = 0; 1012*10898Sroland.mainz@nrubsig.org if (!(fts->flags & FTS_SEEDOT)) 1013*10898Sroland.mainz@nrubsig.org continue; 1014*10898Sroland.mainz@nrubsig.org n = 2; 1015*10898Sroland.mainz@nrubsig.org } 1016*10898Sroland.mainz@nrubsig.org else 1017*10898Sroland.mainz@nrubsig.org n = 0; 10184887Schin } 10194887Schin else 10204887Schin n = 0; 10214887Schin 10224887Schin /* 1023*10898Sroland.mainz@nrubsig.org * make a new entry 10244887Schin */ 10254887Schin 1026*10898Sroland.mainz@nrubsig.org i = D_NAMLEN(d); 1027*10898Sroland.mainz@nrubsig.org if (!(f = node(fts, fts->current, s, i))) 1028*10898Sroland.mainz@nrubsig.org return 0; 1029*10898Sroland.mainz@nrubsig.org TYPE(f, D_TYPE(d)); 1030*10898Sroland.mainz@nrubsig.org 10314887Schin /* 1032*10898Sroland.mainz@nrubsig.org * check for space 10334887Schin */ 10344887Schin 1035*10898Sroland.mainz@nrubsig.org if (i >= fts->endbuf - fts->endbase) 10364887Schin { 1037*10898Sroland.mainz@nrubsig.org if (resize(fts, i)) 1038*10898Sroland.mainz@nrubsig.org return 0; 1039*10898Sroland.mainz@nrubsig.org fts->endbase = fts->base + fts->baselen; 1040*10898Sroland.mainz@nrubsig.org if (fts->endbase[-1] != '/') 1041*10898Sroland.mainz@nrubsig.org fts->endbase++; 10424887Schin } 1043*10898Sroland.mainz@nrubsig.org if (fts->cpname) 1044*10898Sroland.mainz@nrubsig.org { 1045*10898Sroland.mainz@nrubsig.org memcpy(fts->endbase, s, i + 1); 1046*10898Sroland.mainz@nrubsig.org if (fts->cd) 1047*10898Sroland.mainz@nrubsig.org s = fts->path; 1048*10898Sroland.mainz@nrubsig.org } 1049*10898Sroland.mainz@nrubsig.org if (n) 10504887Schin { 10514887Schin /* 1052*10898Sroland.mainz@nrubsig.org * don't recurse on . and .. 10534887Schin */ 10544887Schin 1055*10898Sroland.mainz@nrubsig.org if (n == 1) 1056*10898Sroland.mainz@nrubsig.org f->fts_statp = fts->current->fts_statp; 1057*10898Sroland.mainz@nrubsig.org else 1058*10898Sroland.mainz@nrubsig.org { 1059*10898Sroland.mainz@nrubsig.org if (f->fts_info != FTS_NS) 1060*10898Sroland.mainz@nrubsig.org fts->dotdot = f; 1061*10898Sroland.mainz@nrubsig.org if (fts->current->fts_parent->fts_level < 0) 1062*10898Sroland.mainz@nrubsig.org { 1063*10898Sroland.mainz@nrubsig.org f->fts_statp = &fts->current->fts_parent->statb; 1064*10898Sroland.mainz@nrubsig.org info(fts, f, s, f->fts_statp, 0); 1065*10898Sroland.mainz@nrubsig.org } 1066*10898Sroland.mainz@nrubsig.org else 1067*10898Sroland.mainz@nrubsig.org f->fts_statp = fts->current->fts_parent->fts_statp; 1068*10898Sroland.mainz@nrubsig.org } 1069*10898Sroland.mainz@nrubsig.org f->fts_info = FTS_DOT; 1070*10898Sroland.mainz@nrubsig.org } 1071*10898Sroland.mainz@nrubsig.org else if ((fts->nostat || SKIP(fts, f)) && (f->fts_info = FTS_NSOK) || info(fts, f, s, &f->statb, fts->flags)) 1072*10898Sroland.mainz@nrubsig.org f->statb.st_ino = D_FILENO(d); 1073*10898Sroland.mainz@nrubsig.org if (fts->comparf) 1074*10898Sroland.mainz@nrubsig.org fts->root = search(f, fts->root, fts->comparf, 1); 1075*10898Sroland.mainz@nrubsig.org else if (fts->children || f->fts_info == FTS_D || f->fts_info == FTS_SL) 1076*10898Sroland.mainz@nrubsig.org { 1077*10898Sroland.mainz@nrubsig.org if (fts->top) 1078*10898Sroland.mainz@nrubsig.org fts->bot = fts->bot->fts_link = f; 1079*10898Sroland.mainz@nrubsig.org else 1080*10898Sroland.mainz@nrubsig.org fts->top = fts->bot = f; 1081*10898Sroland.mainz@nrubsig.org } 1082*10898Sroland.mainz@nrubsig.org else 1083*10898Sroland.mainz@nrubsig.org { 10844887Schin /* 1085*10898Sroland.mainz@nrubsig.org * terminal node 10864887Schin */ 10874887Schin 1088*10898Sroland.mainz@nrubsig.org f->fts_path = PATH(fts, fts->path, 1); 1089*10898Sroland.mainz@nrubsig.org f->fts_pathlen = fts->endbase - f->fts_path + f->fts_namelen; 1090*10898Sroland.mainz@nrubsig.org f->fts_accpath = ACCESS(fts, f); 1091*10898Sroland.mainz@nrubsig.org fts->previous = fts->current; 1092*10898Sroland.mainz@nrubsig.org fts->current = f; 1093*10898Sroland.mainz@nrubsig.org fts->state = FTS_terminal; 10944887Schin goto note; 10954887Schin } 10964887Schin } 10974887Schin 10984887Schin /* 1099*10898Sroland.mainz@nrubsig.org * done with the directory 1100*10898Sroland.mainz@nrubsig.org */ 1101*10898Sroland.mainz@nrubsig.org 1102*10898Sroland.mainz@nrubsig.org closedir(fts->dir); 1103*10898Sroland.mainz@nrubsig.org fts->dir = 0; 1104*10898Sroland.mainz@nrubsig.org if (fts->root) 1105*10898Sroland.mainz@nrubsig.org getlist(&fts->top, &fts->bot, fts->root); 1106*10898Sroland.mainz@nrubsig.org if (fts->children) 1107*10898Sroland.mainz@nrubsig.org { 1108*10898Sroland.mainz@nrubsig.org /* 1109*10898Sroland.mainz@nrubsig.org * try moving back to parent dir 1110*10898Sroland.mainz@nrubsig.org */ 1111*10898Sroland.mainz@nrubsig.org 1112*10898Sroland.mainz@nrubsig.org fts->base[fts->baselen] = 0; 1113*10898Sroland.mainz@nrubsig.org if (fts->cd <= 0) 1114*10898Sroland.mainz@nrubsig.org { 1115*10898Sroland.mainz@nrubsig.org f = fts->current->fts_parent; 1116*10898Sroland.mainz@nrubsig.org if (fts->cd < 0 1117*10898Sroland.mainz@nrubsig.org || f != fts->curdir 1118*10898Sroland.mainz@nrubsig.org || !fts->dotdot 1119*10898Sroland.mainz@nrubsig.org || !SAME(f->fts_statp, fts->dotdot->fts_statp) 1120*10898Sroland.mainz@nrubsig.org || fts->pwd && fts->pwd->symlink 1121*10898Sroland.mainz@nrubsig.org || (fts->cd = chdir("..")) < 0 1122*10898Sroland.mainz@nrubsig.org #ifdef verify 1123*10898Sroland.mainz@nrubsig.org || stat(".", &sb) < 0 1124*10898Sroland.mainz@nrubsig.org || !SAME(&sb, fts->dotdot->fts_statp) 1125*10898Sroland.mainz@nrubsig.org #endif 1126*10898Sroland.mainz@nrubsig.org ) 1127*10898Sroland.mainz@nrubsig.org fts->cd = setpdir(fts->home, fts->path, fts->base); 1128*10898Sroland.mainz@nrubsig.org if (fts->pwd) 1129*10898Sroland.mainz@nrubsig.org fts->pwd = fts->pwd->pwd; 1130*10898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : f; 1131*10898Sroland.mainz@nrubsig.org } 1132*10898Sroland.mainz@nrubsig.org f = fts->current; 1133*10898Sroland.mainz@nrubsig.org fts->link = f->fts_link; 1134*10898Sroland.mainz@nrubsig.org f->fts_link = fts->top; 1135*10898Sroland.mainz@nrubsig.org f->fts_path = PATH(fts, fts->path, f->fts_level); 1136*10898Sroland.mainz@nrubsig.org f->fts_pathlen = (fts->base - f->fts_path) + f->fts_namelen; 1137*10898Sroland.mainz@nrubsig.org f->fts_accpath = ACCESS(fts, f); 1138*10898Sroland.mainz@nrubsig.org fts->state = FTS_children_return; 1139*10898Sroland.mainz@nrubsig.org goto note; 1140*10898Sroland.mainz@nrubsig.org } 1141*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 1142*10898Sroland.mainz@nrubsig.org 1143*10898Sroland.mainz@nrubsig.org case FTS_children_resume: 1144*10898Sroland.mainz@nrubsig.org 1145*10898Sroland.mainz@nrubsig.org fts->base[fts->baselen] = 0; 1146*10898Sroland.mainz@nrubsig.org if (fts->top) 1147*10898Sroland.mainz@nrubsig.org { 1148*10898Sroland.mainz@nrubsig.org fts->bot->fts_link = fts->todo; 1149*10898Sroland.mainz@nrubsig.org fts->todo = fts->top; 1150*10898Sroland.mainz@nrubsig.org fts->top = 0; 1151*10898Sroland.mainz@nrubsig.org } 1152*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 1153*10898Sroland.mainz@nrubsig.org 1154*10898Sroland.mainz@nrubsig.org case FTS_popstack: 1155*10898Sroland.mainz@nrubsig.org 1156*10898Sroland.mainz@nrubsig.org /* 1157*10898Sroland.mainz@nrubsig.org * pop objects completely processed 11584887Schin */ 11594887Schin 1160*10898Sroland.mainz@nrubsig.org fts->nd = 0; 1161*10898Sroland.mainz@nrubsig.org f = fts->current; 1162*10898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/ 1163*10898Sroland.mainz@nrubsig.org 1164*10898Sroland.mainz@nrubsig.org case FTS_popstack_resume: 1165*10898Sroland.mainz@nrubsig.org 1166*10898Sroland.mainz@nrubsig.org while (fts->todo && f == fts->todo) 1167*10898Sroland.mainz@nrubsig.org { 1168*10898Sroland.mainz@nrubsig.org t = f->fts_parent; 1169*10898Sroland.mainz@nrubsig.org if ((f->fts_info & FTS_DP) == FTS_D) 1170*10898Sroland.mainz@nrubsig.org { 1171*10898Sroland.mainz@nrubsig.org /* 1172*10898Sroland.mainz@nrubsig.org * delete from <dev,ino> tree 1173*10898Sroland.mainz@nrubsig.org */ 1174*10898Sroland.mainz@nrubsig.org 1175*10898Sroland.mainz@nrubsig.org if (f != fts->diroot) 1176*10898Sroland.mainz@nrubsig.org fts->diroot = search(f, fts->diroot, statcmp, 0); 1177*10898Sroland.mainz@nrubsig.org fts->diroot = deleteroot(fts->diroot); 1178*10898Sroland.mainz@nrubsig.org if (f == fts->curdir) 1179*10898Sroland.mainz@nrubsig.org { 1180*10898Sroland.mainz@nrubsig.org fts->nd++; 1181*10898Sroland.mainz@nrubsig.org fts->curdir = t; 1182*10898Sroland.mainz@nrubsig.org } 1183*10898Sroland.mainz@nrubsig.org 1184*10898Sroland.mainz@nrubsig.org /* 1185*10898Sroland.mainz@nrubsig.org * perform post-order processing 1186*10898Sroland.mainz@nrubsig.org */ 1187*10898Sroland.mainz@nrubsig.org 1188*10898Sroland.mainz@nrubsig.org if (!(fts->flags & FTS_NOPOSTORDER) && 1189*10898Sroland.mainz@nrubsig.org f->status != FTS_SKIP && 1190*10898Sroland.mainz@nrubsig.org f->status != FTS_NOPOSTORDER) 1191*10898Sroland.mainz@nrubsig.org { 1192*10898Sroland.mainz@nrubsig.org /* 1193*10898Sroland.mainz@nrubsig.org * move to parent dir 1194*10898Sroland.mainz@nrubsig.org */ 1195*10898Sroland.mainz@nrubsig.org 1196*10898Sroland.mainz@nrubsig.org if (fts->nd > 0) 1197*10898Sroland.mainz@nrubsig.org fts->cd = popdirs(fts); 1198*10898Sroland.mainz@nrubsig.org if (fts->cd < 0) 1199*10898Sroland.mainz@nrubsig.org fts->cd = setpdir(fts->home, fts->path, fts->base); 1200*10898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : t; 1201*10898Sroland.mainz@nrubsig.org f->fts_info = FTS_DP; 1202*10898Sroland.mainz@nrubsig.org f->fts_path = PATH(fts, fts->path, f->fts_level); 1203*10898Sroland.mainz@nrubsig.org f->fts_pathlen = (fts->base - f->fts_path) + f->fts_namelen; 1204*10898Sroland.mainz@nrubsig.org f->fts_accpath = ACCESS(fts, f); 1205*10898Sroland.mainz@nrubsig.org 1206*10898Sroland.mainz@nrubsig.org /* 1207*10898Sroland.mainz@nrubsig.org * re-stat to update nlink/times 1208*10898Sroland.mainz@nrubsig.org */ 1209*10898Sroland.mainz@nrubsig.org 1210*10898Sroland.mainz@nrubsig.org stat(f->fts_accpath, f->fts_statp); 1211*10898Sroland.mainz@nrubsig.org fts->link = f->fts_link; 1212*10898Sroland.mainz@nrubsig.org f->fts_link = 0; 1213*10898Sroland.mainz@nrubsig.org fts->state = FTS_popstack_return; 1214*10898Sroland.mainz@nrubsig.org goto note; 1215*10898Sroland.mainz@nrubsig.org } 1216*10898Sroland.mainz@nrubsig.org } 1217*10898Sroland.mainz@nrubsig.org 1218*10898Sroland.mainz@nrubsig.org /* 1219*10898Sroland.mainz@nrubsig.org * reset base 1220*10898Sroland.mainz@nrubsig.org */ 1221*10898Sroland.mainz@nrubsig.org 1222*10898Sroland.mainz@nrubsig.org if (fts->base > fts->path + t->fts_namelen) 1223*10898Sroland.mainz@nrubsig.org fts->base--; 1224*10898Sroland.mainz@nrubsig.org *fts->base = 0; 1225*10898Sroland.mainz@nrubsig.org fts->base -= t->fts_namelen; 1226*10898Sroland.mainz@nrubsig.org 1227*10898Sroland.mainz@nrubsig.org /* 1228*10898Sroland.mainz@nrubsig.org * try again or delete from top of stack 1229*10898Sroland.mainz@nrubsig.org */ 1230*10898Sroland.mainz@nrubsig.org 1231*10898Sroland.mainz@nrubsig.org if (f->status == FTS_AGAIN) 1232*10898Sroland.mainz@nrubsig.org { 1233*10898Sroland.mainz@nrubsig.org f->fts_info = FTS_D; 1234*10898Sroland.mainz@nrubsig.org f->status = 0; 1235*10898Sroland.mainz@nrubsig.org } 1236*10898Sroland.mainz@nrubsig.org else 1237*10898Sroland.mainz@nrubsig.org { 1238*10898Sroland.mainz@nrubsig.org fts->todo = fts->todo->fts_link; 1239*10898Sroland.mainz@nrubsig.org drop(fts, f); 1240*10898Sroland.mainz@nrubsig.org } 1241*10898Sroland.mainz@nrubsig.org f = t; 1242*10898Sroland.mainz@nrubsig.org } 12434887Schin 12444887Schin /* 1245*10898Sroland.mainz@nrubsig.org * reset current directory 12464887Schin */ 12474887Schin 1248*10898Sroland.mainz@nrubsig.org if (fts->nd > 0 && popdirs(fts) < 0) 12494887Schin { 1250*10898Sroland.mainz@nrubsig.org pathcd(fts->home, NiL); 1251*10898Sroland.mainz@nrubsig.org fts->curdir = 0; 1252*10898Sroland.mainz@nrubsig.org fts->cd = -1; 12534887Schin } 1254*10898Sroland.mainz@nrubsig.org if (fts->todo) 12554887Schin { 1256*10898Sroland.mainz@nrubsig.org if (*fts->base) 1257*10898Sroland.mainz@nrubsig.org fts->base += f->fts_namelen; 1258*10898Sroland.mainz@nrubsig.org if (*(fts->base - 1) != '/') 1259*10898Sroland.mainz@nrubsig.org *fts->base++ = '/'; 1260*10898Sroland.mainz@nrubsig.org *fts->base = 0; 1261*10898Sroland.mainz@nrubsig.org f = fts->todo; 1262*10898Sroland.mainz@nrubsig.org fts->state = FTS_todo; 1263*10898Sroland.mainz@nrubsig.org continue; 12644887Schin } 1265*10898Sroland.mainz@nrubsig.org return 0; 12664887Schin 1267*10898Sroland.mainz@nrubsig.org case FTS_children_return: 12684887Schin 1269*10898Sroland.mainz@nrubsig.org f = fts->current; 1270*10898Sroland.mainz@nrubsig.org f->fts_link = fts->link; 1271*10898Sroland.mainz@nrubsig.org 1272*10898Sroland.mainz@nrubsig.org /* 1273*10898Sroland.mainz@nrubsig.org * chdir down again 1274*10898Sroland.mainz@nrubsig.org */ 12754887Schin 1276*10898Sroland.mainz@nrubsig.org i = f->fts_info != FTS_DNX; 1277*10898Sroland.mainz@nrubsig.org n = f->status == FTS_SKIP; 1278*10898Sroland.mainz@nrubsig.org if (!n && fts->cd == 0) 1279*10898Sroland.mainz@nrubsig.org { 1280*10898Sroland.mainz@nrubsig.org if ((fts->cd = chdir(fts->base)) < 0) 1281*10898Sroland.mainz@nrubsig.org pathcd(fts->home, NiL); 1282*10898Sroland.mainz@nrubsig.org else if (fts->pwd != f) 1283*10898Sroland.mainz@nrubsig.org { 1284*10898Sroland.mainz@nrubsig.org f->pwd = fts->pwd; 1285*10898Sroland.mainz@nrubsig.org fts->pwd = f; 1286*10898Sroland.mainz@nrubsig.org } 1287*10898Sroland.mainz@nrubsig.org fts->curdir = fts->cd ? 0 : f; 1288*10898Sroland.mainz@nrubsig.org } 12894887Schin 1290*10898Sroland.mainz@nrubsig.org /* 1291*10898Sroland.mainz@nrubsig.org * prune 1292*10898Sroland.mainz@nrubsig.org */ 12934887Schin 1294*10898Sroland.mainz@nrubsig.org if (fts->base[fts->baselen - 1] != '/') 1295*10898Sroland.mainz@nrubsig.org fts->base[fts->baselen] = '/'; 1296*10898Sroland.mainz@nrubsig.org for (fts->bot = 0, f = fts->top; f; ) 1297*10898Sroland.mainz@nrubsig.org if (n || f->status == FTS_SKIP) 1298*10898Sroland.mainz@nrubsig.org { 1299*10898Sroland.mainz@nrubsig.org if (fts->bot) 1300*10898Sroland.mainz@nrubsig.org fts->bot->fts_link = f->fts_link; 1301*10898Sroland.mainz@nrubsig.org else 1302*10898Sroland.mainz@nrubsig.org fts->top = f->fts_link; 1303*10898Sroland.mainz@nrubsig.org drop(fts, f); 1304*10898Sroland.mainz@nrubsig.org f = fts->bot ? fts->bot->fts_link : fts->top; 1305*10898Sroland.mainz@nrubsig.org } 1306*10898Sroland.mainz@nrubsig.org else 1307*10898Sroland.mainz@nrubsig.org { 1308*10898Sroland.mainz@nrubsig.org if (fts->children > 1 && i) 1309*10898Sroland.mainz@nrubsig.org { 1310*10898Sroland.mainz@nrubsig.org if (f->status == FTS_STAT) 1311*10898Sroland.mainz@nrubsig.org info(fts, f, NiL, f->fts_statp, 0); 1312*10898Sroland.mainz@nrubsig.org else if (f->fts_info == FTS_NSOK && !SKIP(fts, f)) 1313*10898Sroland.mainz@nrubsig.org { 1314*10898Sroland.mainz@nrubsig.org s = f->fts_name; 1315*10898Sroland.mainz@nrubsig.org if (fts->cd) 1316*10898Sroland.mainz@nrubsig.org { 1317*10898Sroland.mainz@nrubsig.org memcpy(fts->endbase, s, f->fts_namelen + 1); 1318*10898Sroland.mainz@nrubsig.org s = fts->path; 1319*10898Sroland.mainz@nrubsig.org } 1320*10898Sroland.mainz@nrubsig.org info(fts, f, s, f->fts_statp, fts->flags); 1321*10898Sroland.mainz@nrubsig.org } 1322*10898Sroland.mainz@nrubsig.org } 1323*10898Sroland.mainz@nrubsig.org fts->bot = f; 1324*10898Sroland.mainz@nrubsig.org f = f->fts_link; 1325*10898Sroland.mainz@nrubsig.org } 1326*10898Sroland.mainz@nrubsig.org fts->children = 0; 1327*10898Sroland.mainz@nrubsig.org fts->state = FTS_children_resume; 1328*10898Sroland.mainz@nrubsig.org continue; 13294887Schin 1330*10898Sroland.mainz@nrubsig.org case FTS_popstack_return: 1331*10898Sroland.mainz@nrubsig.org 1332*10898Sroland.mainz@nrubsig.org f = fts->todo; 1333*10898Sroland.mainz@nrubsig.org f->fts_link = fts->link; 1334*10898Sroland.mainz@nrubsig.org f->fts_info = f->status == FTS_AGAIN ? FTS_DP : 0; 1335*10898Sroland.mainz@nrubsig.org fts->state = FTS_popstack_resume; 1336*10898Sroland.mainz@nrubsig.org continue; 13374887Schin 1338*10898Sroland.mainz@nrubsig.org case FTS_preorder_return: 1339*10898Sroland.mainz@nrubsig.org 1340*10898Sroland.mainz@nrubsig.org f = fts->current; 1341*10898Sroland.mainz@nrubsig.org f->fts_link = fts->link; 1342*10898Sroland.mainz@nrubsig.org 1343*10898Sroland.mainz@nrubsig.org /* 1344*10898Sroland.mainz@nrubsig.org * follow symlink if asked to 1345*10898Sroland.mainz@nrubsig.org */ 1346*10898Sroland.mainz@nrubsig.org 1347*10898Sroland.mainz@nrubsig.org if (f->status == FTS_FOLLOW) 13484887Schin { 1349*10898Sroland.mainz@nrubsig.org f->status = 0; 1350*10898Sroland.mainz@nrubsig.org if (f->fts_info == FTS_SL || ISTYPE(f, DT_LNK) || f->fts_info == FTS_NSOK) 13514887Schin { 1352*10898Sroland.mainz@nrubsig.org info(fts, f, f->fts_accpath, f->fts_statp, 0); 1353*10898Sroland.mainz@nrubsig.org if (f->fts_info != FTS_SL) 13544887Schin { 1355*10898Sroland.mainz@nrubsig.org fts->state = FTS_preorder; 1356*10898Sroland.mainz@nrubsig.org continue; 13574887Schin } 13584887Schin } 13594887Schin } 1360*10898Sroland.mainz@nrubsig.org 1361*10898Sroland.mainz@nrubsig.org /* 1362*10898Sroland.mainz@nrubsig.org * about to prune this f and already at home 1363*10898Sroland.mainz@nrubsig.org */ 13644887Schin 1365*10898Sroland.mainz@nrubsig.org if (fts->cd == 0 && f->fts_level == 0 && f->nd) 1366*10898Sroland.mainz@nrubsig.org fts->cd = -1; 1367*10898Sroland.mainz@nrubsig.org fts->state = FTS_preorder_resume; 1368*10898Sroland.mainz@nrubsig.org continue; 13694887Schin 1370*10898Sroland.mainz@nrubsig.org case FTS_terminal: 13714887Schin 1372*10898Sroland.mainz@nrubsig.org f = fts->current; 1373*10898Sroland.mainz@nrubsig.org if (f->status == FTS_FOLLOW) 13744887Schin { 1375*10898Sroland.mainz@nrubsig.org f->status = 0; 1376*10898Sroland.mainz@nrubsig.org if (f->fts_info == FTS_SL || ISTYPE(f, DT_LNK) || f->fts_info == FTS_NSOK) 13774887Schin { 1378*10898Sroland.mainz@nrubsig.org info(fts, f, f->fts_accpath, f->fts_statp, 0); 1379*10898Sroland.mainz@nrubsig.org if (f->symlink && f->fts_info != FTS_SL) 1380*10898Sroland.mainz@nrubsig.org { 1381*10898Sroland.mainz@nrubsig.org if (!(f->fts_link = fts->top)) 1382*10898Sroland.mainz@nrubsig.org fts->bot = f; 1383*10898Sroland.mainz@nrubsig.org fts->top = f; 1384*10898Sroland.mainz@nrubsig.org fts->current = fts->previous; 1385*10898Sroland.mainz@nrubsig.org fts->state = FTS_readdir; 1386*10898Sroland.mainz@nrubsig.org continue; 1387*10898Sroland.mainz@nrubsig.org } 13884887Schin } 13894887Schin } 1390*10898Sroland.mainz@nrubsig.org f = f->fts_parent; 1391*10898Sroland.mainz@nrubsig.org drop(fts, fts->current); 1392*10898Sroland.mainz@nrubsig.org fts->current = f; 1393*10898Sroland.mainz@nrubsig.org fts->state = FTS_readdir; 1394*10898Sroland.mainz@nrubsig.org continue; 13954887Schin 1396*10898Sroland.mainz@nrubsig.org case FTS_error: 13974887Schin 1398*10898Sroland.mainz@nrubsig.org return 0; 13994887Schin 1400*10898Sroland.mainz@nrubsig.org default: 1401*10898Sroland.mainz@nrubsig.org 1402*10898Sroland.mainz@nrubsig.org fts->fts_errno = EINVAL; 1403*10898Sroland.mainz@nrubsig.org fts->state = FTS_error; 1404*10898Sroland.mainz@nrubsig.org return 0; 1405*10898Sroland.mainz@nrubsig.org 14064887Schin } 14074887Schin note: 1408*10898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101 1409*10898Sroland.mainz@nrubsig.org f->_fts_pathlen = (unsigned short)f->fts_pathlen; 1410*10898Sroland.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 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* 14584887Schin fts_children(register FTS* fts, int flags) 14594887Schin { 14604887Schin register FTSENT* f; 14614887Schin 14624887Schin switch (fts->state) 14634887Schin { 14644887Schin 14654887Schin case 0: 14664887Schin 1467*10898Sroland.mainz@nrubsig.org if (fts->comparf) 1468*10898Sroland.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 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 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 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 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