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* 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 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)) 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 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 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* 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 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 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* 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* 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 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 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 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