1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin * Phong Vo
25da2e3ebdSchin * Glenn Fowler
26da2e3ebdSchin * AT&T Research
27da2e3ebdSchin *
28da2e3ebdSchin * fts implementation unwound from the kpv ftwalk() of 1988-10-30
29da2e3ebdSchin */
30da2e3ebdSchin
31da2e3ebdSchin #include <ast.h>
32da2e3ebdSchin #include <ast_dir.h>
33da2e3ebdSchin #include <error.h>
34da2e3ebdSchin #include <fs3d.h>
357c2fbfb3SApril Chin #include <ls.h>
36da2e3ebdSchin
37da2e3ebdSchin struct Ftsent;
38da2e3ebdSchin
39da2e3ebdSchin typedef int (*Compar_f)(struct Ftsent* const*, struct Ftsent* const*);
40da2e3ebdSchin typedef int (*Stat_f)(const char*, struct stat*);
41da2e3ebdSchin
4234f9b3eeSRoland Mainz #define _fts_status status
4334f9b3eeSRoland Mainz #define _fts_statb statb
4434f9b3eeSRoland Mainz
45da2e3ebdSchin #define _FTS_PRIVATE_ \
46da2e3ebdSchin FTSENT* parent; /* top parent */ \
47da2e3ebdSchin FTSENT* todo; /* todo list */ \
48da2e3ebdSchin FTSENT* top; /* top element */ \
49da2e3ebdSchin FTSENT* root; \
50da2e3ebdSchin FTSENT* bot; /* bottom element */ \
51da2e3ebdSchin FTSENT* free; /* free element */ \
52da2e3ebdSchin FTSENT* diroot; \
53da2e3ebdSchin FTSENT* curdir; \
54da2e3ebdSchin FTSENT* current; /* current element */ \
55da2e3ebdSchin FTSENT* previous; /* previous current */ \
56da2e3ebdSchin FTSENT* dotdot; \
57da2e3ebdSchin FTSENT* link; /* real current fts_link*/ \
58da2e3ebdSchin FTSENT* pwd; /* pwd parent */ \
59da2e3ebdSchin DIR* dir; /* current dir stream */ \
60da2e3ebdSchin Compar_f comparf; /* node comparison func */ \
6134f9b3eeSRoland Mainz size_t baselen; /* current strlen(base) */ \
6234f9b3eeSRoland Mainz size_t homesize; /* sizeof(home) */ \
63da2e3ebdSchin int cd; /* chdir status */ \
64da2e3ebdSchin int cpname; \
65da2e3ebdSchin int flags; /* fts_open() flags */ \
66da2e3ebdSchin int nd; \
67da2e3ebdSchin unsigned char children; \
68da2e3ebdSchin unsigned char fs3d; \
69da2e3ebdSchin unsigned char nostat; \
70da2e3ebdSchin unsigned char state; /* fts_read() state */ \
71da2e3ebdSchin char* base; /* basename in path */ \
72da2e3ebdSchin char* name; \
73da2e3ebdSchin char* path; /* path workspace */ \
74da2e3ebdSchin char* home; /* home/path buffer */ \
75da2e3ebdSchin char* endbase; /* space to build paths */ \
76da2e3ebdSchin char* endbuf; /* space to build paths */ \
777c2fbfb3SApril Chin char* pad[2]; /* $0.02 to splain this */
78da2e3ebdSchin
79da2e3ebdSchin /*
80da2e3ebdSchin * NOTE: <ftwalk.h> relies on status and statb being the first two elements
81da2e3ebdSchin */
82da2e3ebdSchin
83da2e3ebdSchin #define _FTSENT_PRIVATE_ \
84da2e3ebdSchin int nd; /* popdir() count */ \
85da2e3ebdSchin FTSENT* left; /* left child */ \
86da2e3ebdSchin FTSENT* right; /* right child */ \
87da2e3ebdSchin FTSENT* pwd; /* pwd parent */ \
88da2e3ebdSchin FTSENT* stack; /* getlist() stack */ \
89da2e3ebdSchin long nlink; /* FTS_D link count */ \
90da2e3ebdSchin unsigned char must; /* must stat */ \
91da2e3ebdSchin unsigned char type; /* DT_* type */ \
92da2e3ebdSchin unsigned char symlink; /* originally a symlink */ \
93da2e3ebdSchin char name[sizeof(int)]; /* fts_name data */
94da2e3ebdSchin
95da2e3ebdSchin #include <fts.h>
96da2e3ebdSchin
97da2e3ebdSchin #ifndef ENOSYS
98da2e3ebdSchin #define ENOSYS EINVAL
99da2e3ebdSchin #endif
100da2e3ebdSchin
101da2e3ebdSchin
102da2e3ebdSchin #if MAXNAMLEN > 16
103da2e3ebdSchin #define MINNAME 32
104da2e3ebdSchin #else
105da2e3ebdSchin #define MINNAME 16
106da2e3ebdSchin #endif
107da2e3ebdSchin
108da2e3ebdSchin #define drop(p,f) (((f)->fts_namelen < MINNAME) ? ((f)->fts_link = (p)->free, (p)->free = (f)) : (free(f), (p)->free))
109da2e3ebdSchin
110da2e3ebdSchin #define ACCESS(p,f) ((p)->cd==0?(f)->fts_name:(f)->fts_path)
111da2e3ebdSchin #define PATH(f,p,l) ((!((f)->flags&FTS_SEEDOTDIR)&&(l)>0&&(p)[0]=='.'&&(p)[1]=='/')?((p)+2):(p))
112da2e3ebdSchin #define SAME(one,two) ((one)->st_ino==(two)->st_ino&&(one)->st_dev==(two)->st_dev)
113da2e3ebdSchin #define SKIPLINK(p,f) ((f)->fts_parent->nlink == 0)
114da2e3ebdSchin
115da2e3ebdSchin #ifdef D_TYPE
116da2e3ebdSchin #define ISTYPE(f,t) ((f)->type == (t))
117da2e3ebdSchin #define TYPE(f,t) ((f)->type = (t))
118da2e3ebdSchin #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)))))
119da2e3ebdSchin #else
120da2e3ebdSchin #undef DT_UNKNOWN
121da2e3ebdSchin #define DT_UNKNOWN 0
122da2e3ebdSchin #undef DT_LNK
123da2e3ebdSchin #define DT_LNK 1
124da2e3ebdSchin #define ISTYPE(f,t) ((t)==DT_UNKNOWN)
125da2e3ebdSchin #define TYPE(f,d)
126da2e3ebdSchin #define SKIP(p,f) ((f)->fts_parent->must == 0 && SKIPLINK(p,f))
127da2e3ebdSchin #endif
128da2e3ebdSchin
129da2e3ebdSchin #ifndef D_FILENO
130da2e3ebdSchin #define D_FILENO(d) (1)
131da2e3ebdSchin #endif
132da2e3ebdSchin
133da2e3ebdSchin /*
134da2e3ebdSchin * NOTE: a malicious dir rename() could change .. underfoot so we
135da2e3ebdSchin * must always verify; undef verify to enable the unsafe code
136da2e3ebdSchin */
137da2e3ebdSchin
138da2e3ebdSchin #define verify 1
139da2e3ebdSchin
140da2e3ebdSchin /*
141da2e3ebdSchin * FTS_NOSTAT requires a dir with
142da2e3ebdSchin * D_TYPE(&dirent_t)!=DT_UNKNOWN
143da2e3ebdSchin * OR
144da2e3ebdSchin * st_nlink>=2
145da2e3ebdSchin */
146da2e3ebdSchin
147da2e3ebdSchin #define FTS_children_resume 1
148da2e3ebdSchin #define FTS_children_return 2
149da2e3ebdSchin #define FTS_error 3
150da2e3ebdSchin #define FTS_popstack 4
151da2e3ebdSchin #define FTS_popstack_resume 5
152da2e3ebdSchin #define FTS_popstack_return 6
153da2e3ebdSchin #define FTS_preorder 7
154da2e3ebdSchin #define FTS_preorder_resume 8
155da2e3ebdSchin #define FTS_preorder_return 9
156da2e3ebdSchin #define FTS_readdir 10
157da2e3ebdSchin #define FTS_terminal 11
158da2e3ebdSchin #define FTS_todo 12
159da2e3ebdSchin #define FTS_top_return 13
160da2e3ebdSchin
161da2e3ebdSchin typedef int (*Notify_f)(FTS*, FTSENT*, void*);
162da2e3ebdSchin
163da2e3ebdSchin typedef struct Notify_s
164da2e3ebdSchin {
165da2e3ebdSchin struct Notify_s* next;
166da2e3ebdSchin Notify_f notifyf;
167da2e3ebdSchin void* context;
168da2e3ebdSchin } Notify_t;
169da2e3ebdSchin
170da2e3ebdSchin static Notify_t* notify;
171da2e3ebdSchin
172da2e3ebdSchin /*
173da2e3ebdSchin * allocate an FTSENT node
174da2e3ebdSchin */
175da2e3ebdSchin
176da2e3ebdSchin static FTSENT*
node(FTS * fts,FTSENT * parent,register char * name,register size_t namelen)17734f9b3eeSRoland Mainz node(FTS* fts, FTSENT* parent, register char* name, register size_t namelen)
178da2e3ebdSchin {
179da2e3ebdSchin register FTSENT* f;
18034f9b3eeSRoland Mainz register size_t n;
181da2e3ebdSchin
182da2e3ebdSchin if (fts->free && namelen < MINNAME)
183da2e3ebdSchin {
184da2e3ebdSchin f = fts->free;
185da2e3ebdSchin fts->free = f->fts_link;
186da2e3ebdSchin }
187da2e3ebdSchin else
188da2e3ebdSchin {
189da2e3ebdSchin n = (namelen < MINNAME ? MINNAME : namelen + 1) - sizeof(int);
190da2e3ebdSchin if (!(f = newof(0, FTSENT, 1, n)))
191da2e3ebdSchin {
192da2e3ebdSchin fts->fts_errno = errno;
193da2e3ebdSchin fts->state = FTS_error;
194da2e3ebdSchin return 0;
195da2e3ebdSchin }
196da2e3ebdSchin f->fts = fts;
197da2e3ebdSchin }
198da2e3ebdSchin TYPE(f, DT_UNKNOWN);
199da2e3ebdSchin f->status = 0;
200da2e3ebdSchin f->symlink = 0;
201da2e3ebdSchin f->fts_level = (f->fts_parent = parent)->fts_level + 1;
20234f9b3eeSRoland Mainz #if __OBSOLETE__ < 20140101
20334f9b3eeSRoland Mainz f->_fts_level = (short)f->fts_level;
20434f9b3eeSRoland Mainz #endif
205da2e3ebdSchin f->fts_link = 0;
206da2e3ebdSchin f->fts_pointer = 0;
207da2e3ebdSchin f->fts_number = 0;
208da2e3ebdSchin f->fts_errno = 0;
209da2e3ebdSchin f->fts_namelen = namelen;
21034f9b3eeSRoland Mainz #if __OBSOLETE__ < 20140101
21134f9b3eeSRoland Mainz f->_fts_namelen = (unsigned short)f->fts_namelen;
21234f9b3eeSRoland Mainz #endif
213da2e3ebdSchin f->fts_name = f->name;
214da2e3ebdSchin f->fts_statp = &f->statb;
215da2e3ebdSchin memcpy(f->fts_name, name, namelen + 1);
216da2e3ebdSchin return f;
217da2e3ebdSchin }
218da2e3ebdSchin
219da2e3ebdSchin /*
220da2e3ebdSchin * compare directories by device/inode
221da2e3ebdSchin */
222da2e3ebdSchin
223da2e3ebdSchin static int
statcmp(FTSENT * const * pf1,FTSENT * const * pf2)224da2e3ebdSchin statcmp(FTSENT* const* pf1, FTSENT* const* pf2)
225da2e3ebdSchin {
226da2e3ebdSchin register const FTSENT* f1 = *pf1;
227da2e3ebdSchin register const FTSENT* f2 = *pf2;
228da2e3ebdSchin
229da2e3ebdSchin if (f1->statb.st_ino < f2->statb.st_ino)
230da2e3ebdSchin return -1;
231da2e3ebdSchin if (f1->statb.st_ino > f2->statb.st_ino)
232da2e3ebdSchin return 1;
233da2e3ebdSchin if (f1->statb.st_dev < f2->statb.st_dev)
234da2e3ebdSchin return -1;
235da2e3ebdSchin if (f1->statb.st_dev > f2->statb.st_dev)
236da2e3ebdSchin return 1;
237da2e3ebdSchin
238da2e3ebdSchin /*
239da2e3ebdSchin * hack for NFS where <dev,ino> may not uniquely identify objects
240da2e3ebdSchin */
241da2e3ebdSchin
242da2e3ebdSchin if (f1->statb.st_mtime < f2->statb.st_mtime)
243da2e3ebdSchin return -1;
244da2e3ebdSchin if (f1->statb.st_mtime > f2->statb.st_mtime)
245da2e3ebdSchin return 1;
246da2e3ebdSchin return 0;
247da2e3ebdSchin }
248da2e3ebdSchin
249da2e3ebdSchin /*
250da2e3ebdSchin * search trees with top-down splaying (a la Tarjan and Sleator)
251da2e3ebdSchin * when used for insertion sort, this implements a stable sort
252da2e3ebdSchin */
253da2e3ebdSchin
254da2e3ebdSchin #define RROTATE(r) (t = r->left, r->left = t->right, t->right = r, r = t)
255da2e3ebdSchin #define LROTATE(r) (t = r->right, r->right = t->left, t->left = r, r = t)
256da2e3ebdSchin
257da2e3ebdSchin static FTSENT*
search(FTSENT * e,FTSENT * root,int (* comparf)(FTSENT * const *,FTSENT * const *),int insert)258da2e3ebdSchin search(FTSENT* e, FTSENT* root, int(*comparf)(FTSENT* const*, FTSENT* const*), int insert)
259da2e3ebdSchin {
260da2e3ebdSchin register int cmp;
261da2e3ebdSchin register FTSENT* t;
262da2e3ebdSchin register FTSENT* left;
263da2e3ebdSchin register FTSENT* right;
264da2e3ebdSchin register FTSENT* lroot;
265da2e3ebdSchin register FTSENT* rroot;
266da2e3ebdSchin
267da2e3ebdSchin left = right = lroot = rroot = 0;
268da2e3ebdSchin while (root)
269da2e3ebdSchin {
270da2e3ebdSchin if (!(cmp = (*comparf)(&e, &root)) && !insert)
271da2e3ebdSchin break;
272da2e3ebdSchin if (cmp < 0)
273da2e3ebdSchin {
274da2e3ebdSchin /*
275da2e3ebdSchin * this is the left zig-zig case
276da2e3ebdSchin */
277da2e3ebdSchin
278da2e3ebdSchin if (root->left && (cmp = (*comparf)(&e, &root->left)) <= 0)
279da2e3ebdSchin {
280da2e3ebdSchin RROTATE(root);
281da2e3ebdSchin if (!cmp && !insert)
282da2e3ebdSchin break;
283da2e3ebdSchin }
284da2e3ebdSchin
285da2e3ebdSchin /*
286da2e3ebdSchin * stick all things > e to the right tree
287da2e3ebdSchin */
288da2e3ebdSchin
289da2e3ebdSchin if (right)
290da2e3ebdSchin right->left = root;
291da2e3ebdSchin else
292da2e3ebdSchin rroot = root;
293da2e3ebdSchin right = root;
294da2e3ebdSchin root = root->left;
295da2e3ebdSchin right->left = 0;
296da2e3ebdSchin }
297da2e3ebdSchin else
298da2e3ebdSchin {
299da2e3ebdSchin /*
300da2e3ebdSchin * this is the right zig-zig case
301da2e3ebdSchin */
302da2e3ebdSchin
303da2e3ebdSchin if (root->right && (cmp = (*comparf)(&e, &root->right)) >= 0)
304da2e3ebdSchin {
305da2e3ebdSchin LROTATE(root);
306da2e3ebdSchin if (!cmp && !insert)
307da2e3ebdSchin break;
308da2e3ebdSchin }
309da2e3ebdSchin
310da2e3ebdSchin /*
311da2e3ebdSchin * stick all things <= e to the left tree
312da2e3ebdSchin */
313da2e3ebdSchin
314da2e3ebdSchin if (left)
315da2e3ebdSchin left->right = root;
316da2e3ebdSchin else
317da2e3ebdSchin lroot = root;
318da2e3ebdSchin left = root;
319da2e3ebdSchin root = root->right;
320da2e3ebdSchin left->right = 0;
321da2e3ebdSchin }
322da2e3ebdSchin }
323da2e3ebdSchin if (!root)
324da2e3ebdSchin root = e;
325da2e3ebdSchin else
326da2e3ebdSchin {
327da2e3ebdSchin if (right)
328da2e3ebdSchin right->left = root->right;
329da2e3ebdSchin else
330da2e3ebdSchin rroot = root->right;
331da2e3ebdSchin if (left)
332da2e3ebdSchin left->right = root->left;
333da2e3ebdSchin else
334da2e3ebdSchin lroot = root->left;
335da2e3ebdSchin }
336da2e3ebdSchin root->left = lroot;
337da2e3ebdSchin root->right = rroot;
338da2e3ebdSchin return root;
339da2e3ebdSchin }
340da2e3ebdSchin
341da2e3ebdSchin /*
342da2e3ebdSchin * delete the root element from the tree
343da2e3ebdSchin */
344da2e3ebdSchin
345da2e3ebdSchin static FTSENT*
deleteroot(register FTSENT * root)346da2e3ebdSchin deleteroot(register FTSENT* root)
347da2e3ebdSchin {
348da2e3ebdSchin register FTSENT* t;
349da2e3ebdSchin register FTSENT* left;
350da2e3ebdSchin register FTSENT* right;
351da2e3ebdSchin
352da2e3ebdSchin right = root->right;
353da2e3ebdSchin if (!(left = root->left))
354da2e3ebdSchin root = right;
355da2e3ebdSchin else
356da2e3ebdSchin {
357da2e3ebdSchin while (left->right)
358da2e3ebdSchin LROTATE(left);
359da2e3ebdSchin left->right = right;
360da2e3ebdSchin root = left;
361da2e3ebdSchin }
362da2e3ebdSchin return root;
363da2e3ebdSchin }
364da2e3ebdSchin
365da2e3ebdSchin /*
366da2e3ebdSchin * generate ordered fts_link list from binary tree at root
367da2e3ebdSchin * FTSENT.stack instead of recursion to avoid blowing the real
368da2e3ebdSchin * stack on big directories
369da2e3ebdSchin */
370da2e3ebdSchin
371da2e3ebdSchin static void
getlist(register FTSENT ** top,register FTSENT ** bot,register FTSENT * root)372da2e3ebdSchin getlist(register FTSENT** top, register FTSENT** bot, register FTSENT* root)
373da2e3ebdSchin {
374da2e3ebdSchin register FTSENT* stack = 0;
375da2e3ebdSchin
376da2e3ebdSchin for (;;)
377da2e3ebdSchin {
378da2e3ebdSchin if (root->left)
379da2e3ebdSchin {
380da2e3ebdSchin root->stack = stack;
381da2e3ebdSchin stack = root;
382da2e3ebdSchin root = root->left;
383da2e3ebdSchin }
384da2e3ebdSchin else
385da2e3ebdSchin {
386da2e3ebdSchin for (;;)
387da2e3ebdSchin {
388da2e3ebdSchin if (*top)
389da2e3ebdSchin *bot = (*bot)->fts_link = root;
390da2e3ebdSchin else
391da2e3ebdSchin *bot = *top = root;
392da2e3ebdSchin if (root->right)
393da2e3ebdSchin {
394da2e3ebdSchin root = root->right;
395da2e3ebdSchin break;
396da2e3ebdSchin }
397da2e3ebdSchin if (!(root = stack))
39834f9b3eeSRoland Mainz {
39934f9b3eeSRoland Mainz (*bot)->fts_link = 0;
400da2e3ebdSchin return;
40134f9b3eeSRoland Mainz }
402da2e3ebdSchin stack = stack->stack;
403da2e3ebdSchin }
404da2e3ebdSchin }
405da2e3ebdSchin }
406da2e3ebdSchin }
407da2e3ebdSchin
408da2e3ebdSchin /*
409da2e3ebdSchin * set directory when curdir is lost in space
410da2e3ebdSchin */
411da2e3ebdSchin
412da2e3ebdSchin static int
setdir(register char * home,register char * path)413da2e3ebdSchin setdir(register char* home, register char* path)
414da2e3ebdSchin {
415da2e3ebdSchin register int cdrv;
416da2e3ebdSchin
417da2e3ebdSchin if (path[0] == '/')
418da2e3ebdSchin cdrv = pathcd(path, NiL);
419da2e3ebdSchin else
420da2e3ebdSchin {
421da2e3ebdSchin /*
422da2e3ebdSchin * note that path and home are in the same buffer
423da2e3ebdSchin */
424da2e3ebdSchin
425da2e3ebdSchin path[-1] = '/';
426da2e3ebdSchin cdrv = pathcd(home, NiL);
427da2e3ebdSchin path[-1] = 0;
428da2e3ebdSchin }
429da2e3ebdSchin if (cdrv < 0)
430da2e3ebdSchin pathcd(home, NiL);
431da2e3ebdSchin return cdrv;
432da2e3ebdSchin }
433da2e3ebdSchin
434da2e3ebdSchin /*
435da2e3ebdSchin * set to parent dir
436da2e3ebdSchin */
437da2e3ebdSchin
438da2e3ebdSchin static int
setpdir(register char * home,register char * path,register char * base)439da2e3ebdSchin setpdir(register char* home, register char* path, register char* base)
440da2e3ebdSchin {
441da2e3ebdSchin register int c;
442da2e3ebdSchin register int cdrv;
443da2e3ebdSchin
444da2e3ebdSchin if (base > path)
445da2e3ebdSchin {
446da2e3ebdSchin c = base[0];
447da2e3ebdSchin base[0] = 0;
448da2e3ebdSchin cdrv = setdir(home, path);
449da2e3ebdSchin base[0] = c;
450da2e3ebdSchin }
451da2e3ebdSchin else
452da2e3ebdSchin cdrv = pathcd(home, NiL);
453da2e3ebdSchin return cdrv;
454da2e3ebdSchin }
455da2e3ebdSchin
456da2e3ebdSchin /*
457da2e3ebdSchin * pop a set of directories
458da2e3ebdSchin */
459da2e3ebdSchin static int
popdirs(FTS * fts)460da2e3ebdSchin popdirs(FTS* fts)
461da2e3ebdSchin {
462da2e3ebdSchin register FTSENT*f;
463da2e3ebdSchin register char* s;
464da2e3ebdSchin register char* e;
465da2e3ebdSchin #ifndef verify
466da2e3ebdSchin register int verify;
467da2e3ebdSchin #endif
468da2e3ebdSchin struct stat sb;
469da2e3ebdSchin char buf[PATH_MAX];
470da2e3ebdSchin
471da2e3ebdSchin if (!(f = fts->curdir) || f->fts_level < 0)
472da2e3ebdSchin return -1;
473da2e3ebdSchin e = buf + sizeof(buf) - 4;
474da2e3ebdSchin #ifndef verify
475da2e3ebdSchin verify = 0;
476da2e3ebdSchin #endif
477da2e3ebdSchin while (fts->nd > 0)
478da2e3ebdSchin {
479da2e3ebdSchin for (s = buf; s < e && fts->nd > 0; fts->nd--)
480da2e3ebdSchin {
481da2e3ebdSchin if (fts->pwd)
482da2e3ebdSchin {
483da2e3ebdSchin #ifndef verify
484da2e3ebdSchin verify |= fts->pwd->symlink;
485da2e3ebdSchin #endif
486da2e3ebdSchin fts->pwd = fts->pwd->pwd;
487da2e3ebdSchin }
488da2e3ebdSchin *s++ = '.';
489da2e3ebdSchin *s++ = '.';
490da2e3ebdSchin *s++ = '/';
491da2e3ebdSchin }
492da2e3ebdSchin *s = 0;
493da2e3ebdSchin if (chdir(buf))
494da2e3ebdSchin return -1;
495da2e3ebdSchin }
496da2e3ebdSchin return (verify && (stat(".", &sb) < 0 || !SAME(&sb, f->fts_statp))) ? -1 : 0;
497da2e3ebdSchin }
498da2e3ebdSchin
499da2e3ebdSchin /*
500da2e3ebdSchin * initialize st from path and fts_info from st
501da2e3ebdSchin */
502da2e3ebdSchin
503da2e3ebdSchin static int
info(FTS * fts,register FTSENT * f,const char * path,struct stat * sp,int flags)504da2e3ebdSchin info(FTS* fts, register FTSENT* f, const char* path, struct stat* sp, int flags)
505da2e3ebdSchin {
506da2e3ebdSchin if (path)
507da2e3ebdSchin {
508da2e3ebdSchin #ifdef S_ISLNK
509da2e3ebdSchin if (!f->symlink && (ISTYPE(f, DT_UNKNOWN) || ISTYPE(f, DT_LNK)))
510da2e3ebdSchin {
511da2e3ebdSchin if (lstat(path, sp) < 0)
512da2e3ebdSchin goto bad;
513da2e3ebdSchin }
514da2e3ebdSchin else
515da2e3ebdSchin #endif
516da2e3ebdSchin if (stat(path, sp) < 0)
517da2e3ebdSchin goto bad;
518da2e3ebdSchin }
519da2e3ebdSchin #ifdef S_ISLNK
520da2e3ebdSchin again:
521da2e3ebdSchin #endif
522da2e3ebdSchin if (S_ISDIR(sp->st_mode))
523da2e3ebdSchin {
524da2e3ebdSchin if ((flags & FTS_NOSTAT) && !fts->fs3d)
525da2e3ebdSchin {
526da2e3ebdSchin f->fts_parent->nlink--;
527da2e3ebdSchin #ifdef D_TYPE
528da2e3ebdSchin if ((f->nlink = sp->st_nlink) < 2)
5297c2fbfb3SApril Chin {
5307c2fbfb3SApril Chin f->must = 2;
531da2e3ebdSchin f->nlink = 2;
5327c2fbfb3SApril Chin }
5337c2fbfb3SApril Chin else
5347c2fbfb3SApril Chin f->must = 0;
535da2e3ebdSchin #else
536da2e3ebdSchin if ((f->nlink = sp->st_nlink) >= 2)
537da2e3ebdSchin f->must = 1;
538da2e3ebdSchin else
539da2e3ebdSchin f->must = 2;
540da2e3ebdSchin #endif
541da2e3ebdSchin }
542da2e3ebdSchin else
543da2e3ebdSchin f->must = 2;
544da2e3ebdSchin TYPE(f, DT_DIR);
545da2e3ebdSchin f->fts_info = FTS_D;
546da2e3ebdSchin }
547da2e3ebdSchin #ifdef S_ISLNK
548da2e3ebdSchin else if (S_ISLNK((sp)->st_mode))
549da2e3ebdSchin {
550da2e3ebdSchin struct stat sb;
551da2e3ebdSchin
552da2e3ebdSchin f->symlink = 1;
553da2e3ebdSchin if (!(flags & FTS_PHYSICAL) && stat(path, &sb) >= 0)
554da2e3ebdSchin {
555da2e3ebdSchin *sp = sb;
556da2e3ebdSchin flags = FTS_PHYSICAL;
557da2e3ebdSchin goto again;
558da2e3ebdSchin }
559da2e3ebdSchin TYPE(f, DT_LNK);
560da2e3ebdSchin f->fts_info = FTS_SL;
561da2e3ebdSchin }
562da2e3ebdSchin #endif
563da2e3ebdSchin else
564da2e3ebdSchin {
565da2e3ebdSchin TYPE(f, DT_REG);
566da2e3ebdSchin f->fts_info = FTS_F;
567da2e3ebdSchin }
568da2e3ebdSchin return 0;
569da2e3ebdSchin bad:
570da2e3ebdSchin TYPE(f, DT_UNKNOWN);
571da2e3ebdSchin f->fts_info = FTS_NS;
572da2e3ebdSchin return -1;
573da2e3ebdSchin }
574da2e3ebdSchin
575da2e3ebdSchin /*
576da2e3ebdSchin * get top list of elements to process
57734f9b3eeSRoland Mainz * ordering delayed until first fts_read()
57834f9b3eeSRoland Mainz * to give caller a chance to set fts->handle
579da2e3ebdSchin */
580da2e3ebdSchin
581da2e3ebdSchin static FTSENT*
toplist(FTS * fts,register char * const * pathnames)582da2e3ebdSchin toplist(FTS* fts, register char* const* pathnames)
583da2e3ebdSchin {
584da2e3ebdSchin register char* path;
585da2e3ebdSchin register FTSENT* f;
58634f9b3eeSRoland Mainz register FTSENT* top;
58734f9b3eeSRoland Mainz register FTSENT* bot;
588da2e3ebdSchin int physical;
589da2e3ebdSchin int metaphysical;
590da2e3ebdSchin char* s;
591da2e3ebdSchin struct stat st;
592da2e3ebdSchin
593da2e3ebdSchin if (fts->flags & FTS_NOSEEDOTDIR)
594da2e3ebdSchin fts->flags &= ~FTS_SEEDOTDIR;
595da2e3ebdSchin physical = (fts->flags & FTS_PHYSICAL);
596da2e3ebdSchin metaphysical = (fts->flags & (FTS_META|FTS_PHYSICAL)) == (FTS_META|FTS_PHYSICAL);
59734f9b3eeSRoland Mainz top = bot = 0;
598da2e3ebdSchin while (path = *pathnames++)
599da2e3ebdSchin {
600da2e3ebdSchin /*
601da2e3ebdSchin * make elements
602da2e3ebdSchin */
603da2e3ebdSchin
604da2e3ebdSchin if (!(f = node(fts, fts->parent, path, strlen(path))))
605da2e3ebdSchin break;
606da2e3ebdSchin path = f->fts_name;
607da2e3ebdSchin if (!physical)
608da2e3ebdSchin f->fts_namelen = (fts->flags & FTS_SEEDOTDIR) ? strlen(path) : (pathcanon(path, 0) - path);
609da2e3ebdSchin else if (*path != '.')
610da2e3ebdSchin {
611da2e3ebdSchin f->fts_namelen = strlen(path);
612da2e3ebdSchin fts->flags |= FTS_SEEDOTDIR;
613da2e3ebdSchin }
614da2e3ebdSchin else
615da2e3ebdSchin {
616da2e3ebdSchin if (fts->flags & FTS_NOSEEDOTDIR)
617da2e3ebdSchin {
618da2e3ebdSchin fts->flags &= ~FTS_SEEDOTDIR;
619da2e3ebdSchin s = path;
620da2e3ebdSchin while (*s++ == '.' && *s++ == '/')
621da2e3ebdSchin {
622da2e3ebdSchin while (*s == '/')
623da2e3ebdSchin s++;
624da2e3ebdSchin if (!*s)
625da2e3ebdSchin break;
626da2e3ebdSchin path = f->fts_name;
627da2e3ebdSchin while (*path++ = *s++);
628da2e3ebdSchin path = f->fts_name;
629da2e3ebdSchin }
630da2e3ebdSchin }
631da2e3ebdSchin else
632da2e3ebdSchin fts->flags |= FTS_SEEDOTDIR;
633da2e3ebdSchin for (s = path + strlen(path); s > path && *(s - 1) == '/'; s--);
634da2e3ebdSchin *s = 0;
635da2e3ebdSchin f->fts_namelen = s - path;
636da2e3ebdSchin }
63734f9b3eeSRoland Mainz #if __OBSOLETE__ < 20140101
63834f9b3eeSRoland Mainz f->_fts_namelen = (unsigned short)f->fts_namelen;
63934f9b3eeSRoland Mainz #endif
640da2e3ebdSchin if (!*path)
641da2e3ebdSchin {
642da2e3ebdSchin errno = ENOENT;
643da2e3ebdSchin f->fts_info = FTS_NS;
644da2e3ebdSchin }
645da2e3ebdSchin else
64634f9b3eeSRoland Mainz info(fts, f, path, f->fts_statp, fts->flags);
647da2e3ebdSchin #ifdef S_ISLNK
648da2e3ebdSchin
649da2e3ebdSchin /*
650da2e3ebdSchin * don't let any standards committee get
651da2e3ebdSchin * away with calling your idea a hack
652da2e3ebdSchin */
653da2e3ebdSchin
654da2e3ebdSchin if (metaphysical && f->fts_info == FTS_SL && stat(path, &st) >= 0)
655da2e3ebdSchin {
65634f9b3eeSRoland Mainz *f->fts_statp = st;
65734f9b3eeSRoland Mainz info(fts, f, NiL, f->fts_statp, 0);
658da2e3ebdSchin }
659da2e3ebdSchin #endif
66034f9b3eeSRoland Mainz if (bot)
661da2e3ebdSchin {
662da2e3ebdSchin bot->fts_link = f;
663da2e3ebdSchin bot = f;
664da2e3ebdSchin }
665da2e3ebdSchin else
666da2e3ebdSchin top = bot = f;
667da2e3ebdSchin }
668da2e3ebdSchin return top;
669da2e3ebdSchin }
670da2e3ebdSchin
671da2e3ebdSchin /*
67234f9b3eeSRoland Mainz * order fts->todo if fts->comparf != 0
67334f9b3eeSRoland Mainz */
67434f9b3eeSRoland Mainz
67534f9b3eeSRoland Mainz static void
order(FTS * fts)67634f9b3eeSRoland Mainz order(FTS* fts)
67734f9b3eeSRoland Mainz {
67834f9b3eeSRoland Mainz register FTSENT* f;
67934f9b3eeSRoland Mainz register FTSENT* root;
68034f9b3eeSRoland Mainz FTSENT* top;
68134f9b3eeSRoland Mainz FTSENT* bot;
68234f9b3eeSRoland Mainz
68334f9b3eeSRoland Mainz top = bot = root = 0;
68434f9b3eeSRoland Mainz for (f = fts->todo; f; f = f->fts_link)
68534f9b3eeSRoland Mainz root = search(f, root, fts->comparf, 1);
68634f9b3eeSRoland Mainz getlist(&top, &bot, root);
68734f9b3eeSRoland Mainz fts->todo = top;
68834f9b3eeSRoland Mainz }
68934f9b3eeSRoland Mainz
69034f9b3eeSRoland Mainz /*
691da2e3ebdSchin * resize the path buffer
692da2e3ebdSchin * note that free() is not used because we may need to chdir(fts->home)
693da2e3ebdSchin * if there isn't enough space to continue
694da2e3ebdSchin */
695da2e3ebdSchin
696da2e3ebdSchin static int
resize(register FTS * fts,size_t inc)69734f9b3eeSRoland Mainz resize(register FTS* fts, size_t inc)
698da2e3ebdSchin {
699da2e3ebdSchin register char* old;
700da2e3ebdSchin register char* newp;
70134f9b3eeSRoland Mainz register size_t n_old;
702da2e3ebdSchin
703da2e3ebdSchin /*
704da2e3ebdSchin * add space for "/." used in testing FTS_DNX
705da2e3ebdSchin */
706da2e3ebdSchin
707da2e3ebdSchin n_old = fts->homesize;
708da2e3ebdSchin fts->homesize = ((fts->homesize + inc + 4) / PATH_MAX + 1) * PATH_MAX;
709da2e3ebdSchin if (!(newp = newof(0, char, fts->homesize, 0)))
710da2e3ebdSchin {
711da2e3ebdSchin fts->fts_errno = errno;
712da2e3ebdSchin fts->state = FTS_error;
713da2e3ebdSchin return -1;
714da2e3ebdSchin }
715da2e3ebdSchin old = fts->home;
716da2e3ebdSchin fts->home = newp;
717da2e3ebdSchin memcpy(newp, old, n_old);
718da2e3ebdSchin if (fts->endbuf)
719da2e3ebdSchin fts->endbuf = newp + fts->homesize - 4;
720da2e3ebdSchin if (fts->path)
721da2e3ebdSchin fts->path = newp + (fts->path - old);
722da2e3ebdSchin if (fts->base)
723da2e3ebdSchin fts->base = newp + (fts->base - old);
724da2e3ebdSchin free(old);
725da2e3ebdSchin return 0;
726da2e3ebdSchin }
727da2e3ebdSchin
728da2e3ebdSchin /*
729da2e3ebdSchin * open a new fts stream on pathnames
730da2e3ebdSchin */
731da2e3ebdSchin
732da2e3ebdSchin FTS*
fts_open(char * const * pathnames,int flags,int (* comparf)(FTSENT * const *,FTSENT * const *))733da2e3ebdSchin fts_open(char* const* pathnames, int flags, int (*comparf)(FTSENT* const*, FTSENT* const*))
734da2e3ebdSchin {
735da2e3ebdSchin register FTS* fts;
736da2e3ebdSchin
737da2e3ebdSchin if (!(fts = newof(0, FTS, 1, sizeof(FTSENT))))
738da2e3ebdSchin return 0;
739da2e3ebdSchin fts->flags = flags;
740da2e3ebdSchin fts->cd = (flags & FTS_NOCHDIR) ? 1 : -1;
741da2e3ebdSchin fts->comparf = comparf;
742da2e3ebdSchin fts->fs3d = fs3d(FS3D_TEST);
743da2e3ebdSchin
744da2e3ebdSchin /*
745da2e3ebdSchin * set up the path work buffer
746da2e3ebdSchin */
747da2e3ebdSchin
748da2e3ebdSchin fts->homesize = 2 * PATH_MAX;
749da2e3ebdSchin for (;;)
750da2e3ebdSchin {
751da2e3ebdSchin if (!(fts->home = newof(fts->home, char, fts->homesize, 0)))
752da2e3ebdSchin {
753da2e3ebdSchin free(fts);
754da2e3ebdSchin return 0;
755da2e3ebdSchin }
756da2e3ebdSchin if (fts->cd > 0 || getcwd(fts->home, fts->homesize))
757da2e3ebdSchin break;
758da2e3ebdSchin if (errno == ERANGE)
759da2e3ebdSchin fts->homesize += PATH_MAX;
760da2e3ebdSchin else
761da2e3ebdSchin fts->cd = 1;
762da2e3ebdSchin }
763da2e3ebdSchin fts->endbuf = fts->home + fts->homesize - 4;
764da2e3ebdSchin
765da2e3ebdSchin /*
766da2e3ebdSchin * initialize the tippity-top
767da2e3ebdSchin */
768da2e3ebdSchin
769da2e3ebdSchin fts->parent = (FTSENT*)(fts + 1);
770da2e3ebdSchin fts->parent->fts_info = FTS_D;
771da2e3ebdSchin memcpy(fts->parent->fts_accpath = fts->parent->fts_path = fts->parent->fts_name = fts->parent->name, ".", 2);
772da2e3ebdSchin fts->parent->fts_level = -1;
77334f9b3eeSRoland Mainz #if __OBSOLETE__ < 20140101
77434f9b3eeSRoland Mainz fts->parent->_fts_level = (short)fts->parent->fts_level;
77534f9b3eeSRoland Mainz #endif
776da2e3ebdSchin fts->parent->fts_statp = &fts->parent->statb;
777da2e3ebdSchin fts->parent->must = 2;
778da2e3ebdSchin fts->parent->type = DT_UNKNOWN;
779da2e3ebdSchin fts->path = fts->home + strlen(fts->home) + 1;
780da2e3ebdSchin
781da2e3ebdSchin /*
782da2e3ebdSchin * make the list of top elements
783da2e3ebdSchin */
784da2e3ebdSchin
785da2e3ebdSchin if (!pathnames || (flags & FTS_ONEPATH) || !*pathnames)
786da2e3ebdSchin {
787da2e3ebdSchin char* v[2];
788da2e3ebdSchin
789da2e3ebdSchin v[0] = pathnames && (flags & FTS_ONEPATH) ? (char*)pathnames : ".";
790da2e3ebdSchin v[1] = 0;
791da2e3ebdSchin fts->todo = toplist(fts, v);
792da2e3ebdSchin }
793da2e3ebdSchin else
794da2e3ebdSchin fts->todo = toplist(fts, pathnames);
795da2e3ebdSchin if (!fts->todo || fts->todo->fts_info == FTS_NS && !fts->todo->fts_link)
796da2e3ebdSchin {
797da2e3ebdSchin fts_close(fts);
798da2e3ebdSchin return 0;
799da2e3ebdSchin }
800da2e3ebdSchin return fts;
801da2e3ebdSchin }
802da2e3ebdSchin
803da2e3ebdSchin /*
804da2e3ebdSchin * return the next FTS entry
805da2e3ebdSchin */
806da2e3ebdSchin
807da2e3ebdSchin FTSENT*
fts_read(register FTS * fts)808da2e3ebdSchin fts_read(register FTS* fts)
809da2e3ebdSchin {
810da2e3ebdSchin register char* s;
811da2e3ebdSchin register int n;
812da2e3ebdSchin register FTSENT* f;
813da2e3ebdSchin struct dirent* d;
81434f9b3eeSRoland Mainz size_t i;
815da2e3ebdSchin FTSENT* t;
816da2e3ebdSchin Notify_t* p;
817da2e3ebdSchin #ifdef verify
818da2e3ebdSchin struct stat sb;
819da2e3ebdSchin #endif
820da2e3ebdSchin
82134f9b3eeSRoland Mainz for (;;)
82234f9b3eeSRoland Mainz switch (fts->state)
823da2e3ebdSchin {
824da2e3ebdSchin
825da2e3ebdSchin case FTS_top_return:
826da2e3ebdSchin
827da2e3ebdSchin f = fts->todo;
828da2e3ebdSchin t = 0;
829da2e3ebdSchin while (f)
830da2e3ebdSchin if (f->status == FTS_SKIP)
831da2e3ebdSchin {
832da2e3ebdSchin if (t)
833da2e3ebdSchin {
834da2e3ebdSchin t->fts_link = f->fts_link;
835da2e3ebdSchin drop(fts, f);
836da2e3ebdSchin f = t->fts_link;
837da2e3ebdSchin }
838da2e3ebdSchin else
839da2e3ebdSchin {
840da2e3ebdSchin fts->todo = f->fts_link;
841da2e3ebdSchin drop(fts, f);
842da2e3ebdSchin f = fts->todo;
843da2e3ebdSchin }
844da2e3ebdSchin }
845da2e3ebdSchin else
846da2e3ebdSchin {
847da2e3ebdSchin t = f;
848da2e3ebdSchin f = f->fts_link;
849da2e3ebdSchin }
850da2e3ebdSchin /*FALLTHROUGH*/
851da2e3ebdSchin
852da2e3ebdSchin case 0:
853da2e3ebdSchin
85434f9b3eeSRoland Mainz if (!fts->state && fts->comparf)
85534f9b3eeSRoland Mainz order(fts);
856da2e3ebdSchin if (!(f = fts->todo))
857da2e3ebdSchin return 0;
858da2e3ebdSchin /*FALLTHROUGH*/
859da2e3ebdSchin
860da2e3ebdSchin case FTS_todo:
861da2e3ebdSchin
862da2e3ebdSchin /*
863da2e3ebdSchin * process the top object on the stack
864da2e3ebdSchin */
865da2e3ebdSchin
866da2e3ebdSchin fts->root = fts->top = fts->bot = 0;
867da2e3ebdSchin
868da2e3ebdSchin /*
869da2e3ebdSchin * initialize the top level
870da2e3ebdSchin */
871da2e3ebdSchin
872da2e3ebdSchin if (f->fts_level == 0)
873da2e3ebdSchin {
874da2e3ebdSchin fts->parent->fts_number = f->fts_number;
875da2e3ebdSchin fts->parent->fts_pointer = f->fts_pointer;
876da2e3ebdSchin fts->parent->fts_statp = f->fts_statp;
877da2e3ebdSchin fts->parent->statb = *f->fts_statp;
878da2e3ebdSchin f->fts_parent = fts->parent;
879da2e3ebdSchin fts->diroot = 0;
880da2e3ebdSchin if (fts->cd == 0)
881da2e3ebdSchin pathcd(fts->home, NiL);
882da2e3ebdSchin else if (fts->cd < 0)
883da2e3ebdSchin fts->cd = 0;
884da2e3ebdSchin fts->pwd = f->fts_parent;
885da2e3ebdSchin fts->curdir = fts->cd ? 0 : f->fts_parent;
886da2e3ebdSchin *(fts->base = fts->path) = 0;
887da2e3ebdSchin }
888da2e3ebdSchin
889da2e3ebdSchin /*
890da2e3ebdSchin * chdir to parent if asked for
891da2e3ebdSchin */
892da2e3ebdSchin
893da2e3ebdSchin if (fts->cd < 0)
894da2e3ebdSchin {
895da2e3ebdSchin fts->cd = setdir(fts->home, fts->path);
896da2e3ebdSchin fts->pwd = f->fts_parent;
897da2e3ebdSchin fts->curdir = fts->cd ? 0 : f->fts_parent;
898da2e3ebdSchin }
899da2e3ebdSchin
900da2e3ebdSchin /*
901da2e3ebdSchin * add object's name to the path
902da2e3ebdSchin */
903da2e3ebdSchin
904da2e3ebdSchin if ((fts->baselen = f->fts_namelen) >= (fts->endbuf - fts->base) && resize(fts, fts->baselen))
905da2e3ebdSchin return 0;
906da2e3ebdSchin memcpy(fts->base, f->name, fts->baselen + 1);
907da2e3ebdSchin fts->name = fts->cd ? fts->path : fts->base;
908da2e3ebdSchin /*FALLTHROUGH*/
909da2e3ebdSchin
910da2e3ebdSchin case FTS_preorder:
911da2e3ebdSchin
912da2e3ebdSchin /*
913da2e3ebdSchin * check for cycle and open dir
914da2e3ebdSchin */
915da2e3ebdSchin
916da2e3ebdSchin if (f->fts_info == FTS_D)
917da2e3ebdSchin {
918da2e3ebdSchin if ((fts->diroot = search(f, fts->diroot, statcmp, 0)) != f || f->fts_level > 0 && (t = f) && statcmp(&t, &f->fts_parent) == 0)
919da2e3ebdSchin {
920da2e3ebdSchin f->fts_info = FTS_DC;
921da2e3ebdSchin f->fts_cycle = fts->diroot;
922da2e3ebdSchin }
923da2e3ebdSchin else if (!(fts->flags & FTS_TOP) && (!(fts->flags & FTS_XDEV) || f->statb.st_dev == f->fts_parent->statb.st_dev))
924da2e3ebdSchin {
925da2e3ebdSchin /*
926da2e3ebdSchin * buffer is known to be large enough here!
927da2e3ebdSchin */
928da2e3ebdSchin
929da2e3ebdSchin if (fts->base[fts->baselen - 1] != '/')
930da2e3ebdSchin memcpy(fts->base + fts->baselen, "/.", 3);
931da2e3ebdSchin if (!(fts->dir = opendir(fts->name)))
932da2e3ebdSchin f->fts_info = FTS_DNX;
933da2e3ebdSchin fts->base[fts->baselen] = 0;
934da2e3ebdSchin if (!fts->dir && !(fts->dir = opendir(fts->name)))
935da2e3ebdSchin f->fts_info = FTS_DNR;
936da2e3ebdSchin }
937da2e3ebdSchin }
938da2e3ebdSchin f->nd = f->fts_info & ~FTS_DNX;
939da2e3ebdSchin if (f->nd || !(fts->flags & FTS_NOPREORDER))
940da2e3ebdSchin {
941da2e3ebdSchin fts->current = f;
942da2e3ebdSchin fts->link = f->fts_link;
943da2e3ebdSchin f->fts_link = 0;
944da2e3ebdSchin f->fts_path = PATH(fts, fts->path, f->fts_level);
945da2e3ebdSchin f->fts_pathlen = (fts->base - f->fts_path) + fts->baselen;
946da2e3ebdSchin f->fts_accpath = ACCESS(fts, f);
947da2e3ebdSchin fts->state = FTS_preorder_return;
948da2e3ebdSchin goto note;
949da2e3ebdSchin }
950da2e3ebdSchin /*FALLTHROUGH*/
951da2e3ebdSchin
952da2e3ebdSchin case FTS_preorder_resume:
953da2e3ebdSchin
954da2e3ebdSchin /*
955da2e3ebdSchin * prune
956da2e3ebdSchin */
957da2e3ebdSchin
958da2e3ebdSchin if (!fts->dir || f->nd || f->status == FTS_SKIP)
959da2e3ebdSchin {
960da2e3ebdSchin if (fts->dir)
961da2e3ebdSchin {
962da2e3ebdSchin closedir(fts->dir);
963da2e3ebdSchin fts->dir = 0;
964da2e3ebdSchin }
965da2e3ebdSchin fts->state = FTS_popstack;
966da2e3ebdSchin continue;
967da2e3ebdSchin }
968da2e3ebdSchin
969da2e3ebdSchin /*
970da2e3ebdSchin * FTS_D or FTS_DNX, about to read children
971da2e3ebdSchin */
972da2e3ebdSchin
973da2e3ebdSchin if (fts->cd == 0)
974da2e3ebdSchin {
975da2e3ebdSchin if ((fts->cd = chdir(fts->name)) < 0)
976da2e3ebdSchin pathcd(fts->home, NiL);
977da2e3ebdSchin else if (fts->pwd != f)
978da2e3ebdSchin {
979da2e3ebdSchin f->pwd = fts->pwd;
980da2e3ebdSchin fts->pwd = f;
981da2e3ebdSchin }
982da2e3ebdSchin fts->curdir = fts->cd < 0 ? 0 : f;
983da2e3ebdSchin }
984da2e3ebdSchin fts->nostat = fts->children > 1 || f->fts_info == FTS_DNX;
985da2e3ebdSchin fts->cpname = fts->cd && !fts->nostat || !fts->children && !fts->comparf;
986da2e3ebdSchin fts->dotdot = 0;
987da2e3ebdSchin fts->endbase = fts->base + fts->baselen;
988da2e3ebdSchin if (fts->endbase[-1] != '/')
989da2e3ebdSchin *fts->endbase++ = '/';
990da2e3ebdSchin fts->current = f;
991da2e3ebdSchin /*FALLTHROUGH*/
992da2e3ebdSchin
993da2e3ebdSchin case FTS_readdir:
994da2e3ebdSchin
995da2e3ebdSchin while (d = readdir(fts->dir))
996da2e3ebdSchin {
997da2e3ebdSchin s = d->d_name;
998da2e3ebdSchin if (s[0] == '.')
999da2e3ebdSchin {
1000da2e3ebdSchin if (s[1] == 0)
1001da2e3ebdSchin {
1002da2e3ebdSchin fts->current->nlink--;
1003da2e3ebdSchin if (!(fts->flags & FTS_SEEDOT))
1004da2e3ebdSchin continue;
1005da2e3ebdSchin n = 1;
1006da2e3ebdSchin }
1007da2e3ebdSchin else if (s[1] == '.' && s[2] == 0)
1008da2e3ebdSchin {
1009da2e3ebdSchin fts->current->nlink--;
1010da2e3ebdSchin if (fts->current->must == 1)
1011da2e3ebdSchin fts->current->must = 0;
1012da2e3ebdSchin if (!(fts->flags & FTS_SEEDOT))
1013da2e3ebdSchin continue;
1014da2e3ebdSchin n = 2;
1015da2e3ebdSchin }
1016da2e3ebdSchin else
1017da2e3ebdSchin n = 0;
1018da2e3ebdSchin }
1019da2e3ebdSchin else
1020da2e3ebdSchin n = 0;
1021da2e3ebdSchin
1022da2e3ebdSchin /*
1023da2e3ebdSchin * make a new entry
1024da2e3ebdSchin */
1025da2e3ebdSchin
1026da2e3ebdSchin i = D_NAMLEN(d);
1027da2e3ebdSchin if (!(f = node(fts, fts->current, s, i)))
1028da2e3ebdSchin return 0;
1029da2e3ebdSchin TYPE(f, D_TYPE(d));
1030da2e3ebdSchin
1031da2e3ebdSchin /*
1032da2e3ebdSchin * check for space
1033da2e3ebdSchin */
1034da2e3ebdSchin
1035da2e3ebdSchin if (i >= fts->endbuf - fts->endbase)
1036da2e3ebdSchin {
1037da2e3ebdSchin if (resize(fts, i))
1038da2e3ebdSchin return 0;
1039da2e3ebdSchin fts->endbase = fts->base + fts->baselen;
1040da2e3ebdSchin if (fts->endbase[-1] != '/')
1041da2e3ebdSchin fts->endbase++;
1042da2e3ebdSchin }
1043da2e3ebdSchin if (fts->cpname)
1044da2e3ebdSchin {
1045da2e3ebdSchin memcpy(fts->endbase, s, i + 1);
1046da2e3ebdSchin if (fts->cd)
1047da2e3ebdSchin s = fts->path;
1048da2e3ebdSchin }
1049da2e3ebdSchin if (n)
1050da2e3ebdSchin {
1051da2e3ebdSchin /*
1052da2e3ebdSchin * don't recurse on . and ..
1053da2e3ebdSchin */
1054da2e3ebdSchin
1055da2e3ebdSchin if (n == 1)
1056da2e3ebdSchin f->fts_statp = fts->current->fts_statp;
1057da2e3ebdSchin else
1058da2e3ebdSchin {
1059da2e3ebdSchin if (f->fts_info != FTS_NS)
1060da2e3ebdSchin fts->dotdot = f;
1061da2e3ebdSchin if (fts->current->fts_parent->fts_level < 0)
1062da2e3ebdSchin {
1063da2e3ebdSchin f->fts_statp = &fts->current->fts_parent->statb;
1064da2e3ebdSchin info(fts, f, s, f->fts_statp, 0);
1065da2e3ebdSchin }
1066da2e3ebdSchin else
1067da2e3ebdSchin f->fts_statp = fts->current->fts_parent->fts_statp;
1068da2e3ebdSchin }
1069da2e3ebdSchin f->fts_info = FTS_DOT;
1070da2e3ebdSchin }
1071da2e3ebdSchin else if ((fts->nostat || SKIP(fts, f)) && (f->fts_info = FTS_NSOK) || info(fts, f, s, &f->statb, fts->flags))
1072da2e3ebdSchin f->statb.st_ino = D_FILENO(d);
1073da2e3ebdSchin if (fts->comparf)
1074da2e3ebdSchin fts->root = search(f, fts->root, fts->comparf, 1);
1075da2e3ebdSchin else if (fts->children || f->fts_info == FTS_D || f->fts_info == FTS_SL)
1076da2e3ebdSchin {
1077da2e3ebdSchin if (fts->top)
1078da2e3ebdSchin fts->bot = fts->bot->fts_link = f;
1079da2e3ebdSchin else
1080da2e3ebdSchin fts->top = fts->bot = f;
1081da2e3ebdSchin }
1082da2e3ebdSchin else
1083da2e3ebdSchin {
1084da2e3ebdSchin /*
1085da2e3ebdSchin * terminal node
1086da2e3ebdSchin */
1087da2e3ebdSchin
1088da2e3ebdSchin f->fts_path = PATH(fts, fts->path, 1);
1089da2e3ebdSchin f->fts_pathlen = fts->endbase - f->fts_path + f->fts_namelen;
1090da2e3ebdSchin f->fts_accpath = ACCESS(fts, f);
1091da2e3ebdSchin fts->previous = fts->current;
1092da2e3ebdSchin fts->current = f;
1093da2e3ebdSchin fts->state = FTS_terminal;
1094da2e3ebdSchin goto note;
1095da2e3ebdSchin }
1096da2e3ebdSchin }
1097da2e3ebdSchin
1098da2e3ebdSchin /*
1099da2e3ebdSchin * done with the directory
1100da2e3ebdSchin */
1101da2e3ebdSchin
1102da2e3ebdSchin closedir(fts->dir);
1103da2e3ebdSchin fts->dir = 0;
1104da2e3ebdSchin if (fts->root)
1105da2e3ebdSchin getlist(&fts->top, &fts->bot, fts->root);
1106da2e3ebdSchin if (fts->children)
1107da2e3ebdSchin {
1108da2e3ebdSchin /*
1109da2e3ebdSchin * try moving back to parent dir
1110da2e3ebdSchin */
1111da2e3ebdSchin
1112da2e3ebdSchin fts->base[fts->baselen] = 0;
1113da2e3ebdSchin if (fts->cd <= 0)
1114da2e3ebdSchin {
1115da2e3ebdSchin f = fts->current->fts_parent;
1116da2e3ebdSchin if (fts->cd < 0
1117da2e3ebdSchin || f != fts->curdir
1118da2e3ebdSchin || !fts->dotdot
1119da2e3ebdSchin || !SAME(f->fts_statp, fts->dotdot->fts_statp)
1120da2e3ebdSchin || fts->pwd && fts->pwd->symlink
1121da2e3ebdSchin || (fts->cd = chdir("..")) < 0
1122da2e3ebdSchin #ifdef verify
1123da2e3ebdSchin || stat(".", &sb) < 0
1124da2e3ebdSchin || !SAME(&sb, fts->dotdot->fts_statp)
1125da2e3ebdSchin #endif
1126da2e3ebdSchin )
1127da2e3ebdSchin fts->cd = setpdir(fts->home, fts->path, fts->base);
1128da2e3ebdSchin if (fts->pwd)
1129da2e3ebdSchin fts->pwd = fts->pwd->pwd;
1130da2e3ebdSchin fts->curdir = fts->cd ? 0 : f;
1131da2e3ebdSchin }
1132da2e3ebdSchin f = fts->current;
1133da2e3ebdSchin fts->link = f->fts_link;
1134da2e3ebdSchin f->fts_link = fts->top;
1135da2e3ebdSchin f->fts_path = PATH(fts, fts->path, f->fts_level);
1136da2e3ebdSchin f->fts_pathlen = (fts->base - f->fts_path) + f->fts_namelen;
1137da2e3ebdSchin f->fts_accpath = ACCESS(fts, f);
1138da2e3ebdSchin fts->state = FTS_children_return;
1139da2e3ebdSchin goto note;
1140da2e3ebdSchin }
1141da2e3ebdSchin /*FALLTHROUGH*/
1142da2e3ebdSchin
1143da2e3ebdSchin case FTS_children_resume:
1144da2e3ebdSchin
1145da2e3ebdSchin fts->base[fts->baselen] = 0;
1146da2e3ebdSchin if (fts->top)
1147da2e3ebdSchin {
1148da2e3ebdSchin fts->bot->fts_link = fts->todo;
1149da2e3ebdSchin fts->todo = fts->top;
1150da2e3ebdSchin fts->top = 0;
1151da2e3ebdSchin }
1152da2e3ebdSchin /*FALLTHROUGH*/
1153da2e3ebdSchin
1154da2e3ebdSchin case FTS_popstack:
1155da2e3ebdSchin
1156da2e3ebdSchin /*
1157da2e3ebdSchin * pop objects completely processed
1158da2e3ebdSchin */
1159da2e3ebdSchin
1160da2e3ebdSchin fts->nd = 0;
1161da2e3ebdSchin f = fts->current;
1162da2e3ebdSchin /*FALLTHROUGH*/
1163da2e3ebdSchin
1164da2e3ebdSchin case FTS_popstack_resume:
1165da2e3ebdSchin
1166da2e3ebdSchin while (fts->todo && f == fts->todo)
1167da2e3ebdSchin {
1168da2e3ebdSchin t = f->fts_parent;
1169da2e3ebdSchin if ((f->fts_info & FTS_DP) == FTS_D)
1170da2e3ebdSchin {
1171da2e3ebdSchin /*
1172da2e3ebdSchin * delete from <dev,ino> tree
1173da2e3ebdSchin */
1174da2e3ebdSchin
1175da2e3ebdSchin if (f != fts->diroot)
1176da2e3ebdSchin fts->diroot = search(f, fts->diroot, statcmp, 0);
1177da2e3ebdSchin fts->diroot = deleteroot(fts->diroot);
1178da2e3ebdSchin if (f == fts->curdir)
1179da2e3ebdSchin {
1180da2e3ebdSchin fts->nd++;
1181da2e3ebdSchin fts->curdir = t;
1182da2e3ebdSchin }
1183da2e3ebdSchin
1184da2e3ebdSchin /*
1185da2e3ebdSchin * perform post-order processing
1186da2e3ebdSchin */
1187da2e3ebdSchin
1188da2e3ebdSchin if (!(fts->flags & FTS_NOPOSTORDER) &&
1189da2e3ebdSchin f->status != FTS_SKIP &&
1190da2e3ebdSchin f->status != FTS_NOPOSTORDER)
1191da2e3ebdSchin {
1192da2e3ebdSchin /*
1193da2e3ebdSchin * move to parent dir
1194da2e3ebdSchin */
1195da2e3ebdSchin
1196da2e3ebdSchin if (fts->nd > 0)
1197da2e3ebdSchin fts->cd = popdirs(fts);
1198da2e3ebdSchin if (fts->cd < 0)
1199da2e3ebdSchin fts->cd = setpdir(fts->home, fts->path, fts->base);
1200da2e3ebdSchin fts->curdir = fts->cd ? 0 : t;
1201da2e3ebdSchin f->fts_info = FTS_DP;
1202da2e3ebdSchin f->fts_path = PATH(fts, fts->path, f->fts_level);
1203da2e3ebdSchin f->fts_pathlen = (fts->base - f->fts_path) + f->fts_namelen;
1204da2e3ebdSchin f->fts_accpath = ACCESS(fts, f);
1205da2e3ebdSchin
1206da2e3ebdSchin /*
1207da2e3ebdSchin * re-stat to update nlink/times
1208da2e3ebdSchin */
1209da2e3ebdSchin
1210da2e3ebdSchin stat(f->fts_accpath, f->fts_statp);
1211da2e3ebdSchin fts->link = f->fts_link;
1212da2e3ebdSchin f->fts_link = 0;
1213da2e3ebdSchin fts->state = FTS_popstack_return;
1214da2e3ebdSchin goto note;
1215da2e3ebdSchin }
1216da2e3ebdSchin }
1217da2e3ebdSchin
1218da2e3ebdSchin /*
1219da2e3ebdSchin * reset base
1220da2e3ebdSchin */
1221da2e3ebdSchin
1222da2e3ebdSchin if (fts->base > fts->path + t->fts_namelen)
1223da2e3ebdSchin fts->base--;
1224da2e3ebdSchin *fts->base = 0;
1225da2e3ebdSchin fts->base -= t->fts_namelen;
1226da2e3ebdSchin
1227da2e3ebdSchin /*
1228da2e3ebdSchin * try again or delete from top of stack
1229da2e3ebdSchin */
1230da2e3ebdSchin
1231da2e3ebdSchin if (f->status == FTS_AGAIN)
1232da2e3ebdSchin {
1233da2e3ebdSchin f->fts_info = FTS_D;
1234da2e3ebdSchin f->status = 0;
1235da2e3ebdSchin }
1236da2e3ebdSchin else
1237da2e3ebdSchin {
1238da2e3ebdSchin fts->todo = fts->todo->fts_link;
1239da2e3ebdSchin drop(fts, f);
1240da2e3ebdSchin }
1241da2e3ebdSchin f = t;
1242da2e3ebdSchin }
1243da2e3ebdSchin
1244da2e3ebdSchin /*
1245da2e3ebdSchin * reset current directory
1246da2e3ebdSchin */
1247da2e3ebdSchin
1248da2e3ebdSchin if (fts->nd > 0 && popdirs(fts) < 0)
1249da2e3ebdSchin {
1250da2e3ebdSchin pathcd(fts->home, NiL);
1251da2e3ebdSchin fts->curdir = 0;
1252da2e3ebdSchin fts->cd = -1;
1253da2e3ebdSchin }
1254da2e3ebdSchin if (fts->todo)
1255da2e3ebdSchin {
1256da2e3ebdSchin if (*fts->base)
1257da2e3ebdSchin fts->base += f->fts_namelen;
1258da2e3ebdSchin if (*(fts->base - 1) != '/')
1259da2e3ebdSchin *fts->base++ = '/';
1260da2e3ebdSchin *fts->base = 0;
1261da2e3ebdSchin f = fts->todo;
1262da2e3ebdSchin fts->state = FTS_todo;
1263da2e3ebdSchin continue;
1264da2e3ebdSchin }
1265da2e3ebdSchin return 0;
1266da2e3ebdSchin
1267da2e3ebdSchin case FTS_children_return:
1268da2e3ebdSchin
1269da2e3ebdSchin f = fts->current;
1270da2e3ebdSchin f->fts_link = fts->link;
1271da2e3ebdSchin
1272da2e3ebdSchin /*
1273da2e3ebdSchin * chdir down again
1274da2e3ebdSchin */
1275da2e3ebdSchin
1276da2e3ebdSchin i = f->fts_info != FTS_DNX;
1277da2e3ebdSchin n = f->status == FTS_SKIP;
1278da2e3ebdSchin if (!n && fts->cd == 0)
1279da2e3ebdSchin {
1280da2e3ebdSchin if ((fts->cd = chdir(fts->base)) < 0)
1281da2e3ebdSchin pathcd(fts->home, NiL);
1282da2e3ebdSchin else if (fts->pwd != f)
1283da2e3ebdSchin {
1284da2e3ebdSchin f->pwd = fts->pwd;
1285da2e3ebdSchin fts->pwd = f;
1286da2e3ebdSchin }
1287da2e3ebdSchin fts->curdir = fts->cd ? 0 : f;
1288da2e3ebdSchin }
1289da2e3ebdSchin
1290da2e3ebdSchin /*
1291da2e3ebdSchin * prune
1292da2e3ebdSchin */
1293da2e3ebdSchin
1294da2e3ebdSchin if (fts->base[fts->baselen - 1] != '/')
1295da2e3ebdSchin fts->base[fts->baselen] = '/';
1296da2e3ebdSchin for (fts->bot = 0, f = fts->top; f; )
1297da2e3ebdSchin if (n || f->status == FTS_SKIP)
1298da2e3ebdSchin {
1299da2e3ebdSchin if (fts->bot)
1300da2e3ebdSchin fts->bot->fts_link = f->fts_link;
1301da2e3ebdSchin else
1302da2e3ebdSchin fts->top = f->fts_link;
1303da2e3ebdSchin drop(fts, f);
1304da2e3ebdSchin f = fts->bot ? fts->bot->fts_link : fts->top;
1305da2e3ebdSchin }
1306da2e3ebdSchin else
1307da2e3ebdSchin {
1308da2e3ebdSchin if (fts->children > 1 && i)
1309da2e3ebdSchin {
1310da2e3ebdSchin if (f->status == FTS_STAT)
1311da2e3ebdSchin info(fts, f, NiL, f->fts_statp, 0);
1312da2e3ebdSchin else if (f->fts_info == FTS_NSOK && !SKIP(fts, f))
1313da2e3ebdSchin {
1314da2e3ebdSchin s = f->fts_name;
1315da2e3ebdSchin if (fts->cd)
1316da2e3ebdSchin {
1317da2e3ebdSchin memcpy(fts->endbase, s, f->fts_namelen + 1);
1318da2e3ebdSchin s = fts->path;
1319da2e3ebdSchin }
1320da2e3ebdSchin info(fts, f, s, f->fts_statp, fts->flags);
1321da2e3ebdSchin }
1322da2e3ebdSchin }
1323da2e3ebdSchin fts->bot = f;
1324da2e3ebdSchin f = f->fts_link;
1325da2e3ebdSchin }
1326da2e3ebdSchin fts->children = 0;
1327da2e3ebdSchin fts->state = FTS_children_resume;
1328da2e3ebdSchin continue;
1329da2e3ebdSchin
1330da2e3ebdSchin case FTS_popstack_return:
1331da2e3ebdSchin
1332da2e3ebdSchin f = fts->todo;
1333da2e3ebdSchin f->fts_link = fts->link;
1334da2e3ebdSchin f->fts_info = f->status == FTS_AGAIN ? FTS_DP : 0;
1335da2e3ebdSchin fts->state = FTS_popstack_resume;
1336da2e3ebdSchin continue;
1337da2e3ebdSchin
1338da2e3ebdSchin case FTS_preorder_return:
1339da2e3ebdSchin
1340da2e3ebdSchin f = fts->current;
1341da2e3ebdSchin f->fts_link = fts->link;
1342da2e3ebdSchin
1343da2e3ebdSchin /*
1344da2e3ebdSchin * follow symlink if asked to
1345da2e3ebdSchin */
1346da2e3ebdSchin
1347da2e3ebdSchin if (f->status == FTS_FOLLOW)
1348da2e3ebdSchin {
1349da2e3ebdSchin f->status = 0;
1350da2e3ebdSchin if (f->fts_info == FTS_SL || ISTYPE(f, DT_LNK) || f->fts_info == FTS_NSOK)
1351da2e3ebdSchin {
1352da2e3ebdSchin info(fts, f, f->fts_accpath, f->fts_statp, 0);
1353da2e3ebdSchin if (f->fts_info != FTS_SL)
1354da2e3ebdSchin {
1355da2e3ebdSchin fts->state = FTS_preorder;
1356da2e3ebdSchin continue;
1357da2e3ebdSchin }
1358da2e3ebdSchin }
1359da2e3ebdSchin }
1360da2e3ebdSchin
1361da2e3ebdSchin /*
1362da2e3ebdSchin * about to prune this f and already at home
1363da2e3ebdSchin */
1364da2e3ebdSchin
1365da2e3ebdSchin if (fts->cd == 0 && f->fts_level == 0 && f->nd)
1366da2e3ebdSchin fts->cd = -1;
1367da2e3ebdSchin fts->state = FTS_preorder_resume;
1368da2e3ebdSchin continue;
1369da2e3ebdSchin
1370da2e3ebdSchin case FTS_terminal:
1371da2e3ebdSchin
1372da2e3ebdSchin f = fts->current;
1373da2e3ebdSchin if (f->status == FTS_FOLLOW)
1374da2e3ebdSchin {
1375da2e3ebdSchin f->status = 0;
1376da2e3ebdSchin if (f->fts_info == FTS_SL || ISTYPE(f, DT_LNK) || f->fts_info == FTS_NSOK)
1377da2e3ebdSchin {
1378da2e3ebdSchin info(fts, f, f->fts_accpath, f->fts_statp, 0);
1379da2e3ebdSchin if (f->symlink && f->fts_info != FTS_SL)
1380da2e3ebdSchin {
1381da2e3ebdSchin if (!(f->fts_link = fts->top))
1382da2e3ebdSchin fts->bot = f;
1383da2e3ebdSchin fts->top = f;
1384da2e3ebdSchin fts->current = fts->previous;
1385da2e3ebdSchin fts->state = FTS_readdir;
1386da2e3ebdSchin continue;
1387da2e3ebdSchin }
1388da2e3ebdSchin }
1389da2e3ebdSchin }
1390da2e3ebdSchin f = f->fts_parent;
1391da2e3ebdSchin drop(fts, fts->current);
1392da2e3ebdSchin fts->current = f;
1393da2e3ebdSchin fts->state = FTS_readdir;
1394da2e3ebdSchin continue;
1395da2e3ebdSchin
1396da2e3ebdSchin case FTS_error:
1397da2e3ebdSchin
1398da2e3ebdSchin return 0;
1399da2e3ebdSchin
1400da2e3ebdSchin default:
1401da2e3ebdSchin
1402da2e3ebdSchin fts->fts_errno = EINVAL;
1403da2e3ebdSchin fts->state = FTS_error;
1404da2e3ebdSchin return 0;
1405da2e3ebdSchin
1406da2e3ebdSchin }
1407da2e3ebdSchin note:
140834f9b3eeSRoland Mainz #if __OBSOLETE__ < 20140101
140934f9b3eeSRoland Mainz f->_fts_pathlen = (unsigned short)f->fts_pathlen;
141034f9b3eeSRoland Mainz #endif
1411da2e3ebdSchin for (p = notify; p; p = p->next)
1412da2e3ebdSchin if ((n = (*p->notifyf)(fts, f, p->context)) > 0)
1413da2e3ebdSchin break;
1414da2e3ebdSchin else if (n < 0)
1415da2e3ebdSchin {
1416da2e3ebdSchin fts->fts_errno = EINVAL;
1417da2e3ebdSchin fts->state = FTS_error;
1418da2e3ebdSchin return 0;
1419da2e3ebdSchin }
1420da2e3ebdSchin return f;
1421da2e3ebdSchin }
1422da2e3ebdSchin
1423da2e3ebdSchin /*
1424da2e3ebdSchin * set stream or entry flags
1425da2e3ebdSchin */
1426da2e3ebdSchin
1427da2e3ebdSchin int
fts_set(register FTS * fts,register FTSENT * f,int status)1428da2e3ebdSchin fts_set(register FTS* fts, register FTSENT* f, int status)
1429da2e3ebdSchin {
1430da2e3ebdSchin if (fts || !f || f->fts->current != f)
1431da2e3ebdSchin return -1;
1432da2e3ebdSchin switch (status)
1433da2e3ebdSchin {
1434da2e3ebdSchin case FTS_AGAIN:
1435da2e3ebdSchin break;
1436da2e3ebdSchin case FTS_FOLLOW:
1437da2e3ebdSchin if (!(f->fts_info & FTS_SL))
1438da2e3ebdSchin return -1;
1439da2e3ebdSchin break;
1440da2e3ebdSchin case FTS_NOPOSTORDER:
1441da2e3ebdSchin break;
1442da2e3ebdSchin case FTS_SKIP:
1443da2e3ebdSchin if ((f->fts_info & (FTS_D|FTS_P)) != FTS_D)
1444da2e3ebdSchin return -1;
1445da2e3ebdSchin break;
1446da2e3ebdSchin default:
1447da2e3ebdSchin return -1;
1448da2e3ebdSchin }
1449da2e3ebdSchin f->status = status;
1450da2e3ebdSchin return 0;
1451da2e3ebdSchin }
1452da2e3ebdSchin
1453da2e3ebdSchin /*
1454da2e3ebdSchin * return the list of child entries
1455da2e3ebdSchin */
1456da2e3ebdSchin
1457da2e3ebdSchin FTSENT*
fts_children(register FTS * fts,int flags)1458da2e3ebdSchin fts_children(register FTS* fts, int flags)
1459da2e3ebdSchin {
1460da2e3ebdSchin register FTSENT* f;
1461da2e3ebdSchin
1462da2e3ebdSchin switch (fts->state)
1463da2e3ebdSchin {
1464da2e3ebdSchin
1465da2e3ebdSchin case 0:
1466da2e3ebdSchin
146734f9b3eeSRoland Mainz if (fts->comparf)
146834f9b3eeSRoland Mainz order(fts);
1469da2e3ebdSchin fts->state = FTS_top_return;
1470da2e3ebdSchin return fts->todo;
1471da2e3ebdSchin
1472da2e3ebdSchin case FTS_preorder_return:
1473da2e3ebdSchin
1474da2e3ebdSchin fts->children = ((flags | fts->flags) & FTS_NOSTAT) ? 2 : 1;
1475da2e3ebdSchin if (f = fts_read(fts))
1476da2e3ebdSchin f = f->fts_link;
1477da2e3ebdSchin return f;
1478da2e3ebdSchin
1479da2e3ebdSchin }
1480da2e3ebdSchin return 0;
1481da2e3ebdSchin }
1482da2e3ebdSchin
1483da2e3ebdSchin /*
1484da2e3ebdSchin * return default (FTS_LOGICAL|FTS_META|FTS_PHYSICAL|FTS_SEEDOTDIR) flags
1485da2e3ebdSchin * conditioned by astconf()
1486da2e3ebdSchin */
1487da2e3ebdSchin
1488da2e3ebdSchin int
fts_flags(void)1489da2e3ebdSchin fts_flags(void)
1490da2e3ebdSchin {
1491da2e3ebdSchin register char* s;
1492da2e3ebdSchin
1493da2e3ebdSchin s = astconf("PATH_RESOLVE", NiL, NiL);
1494da2e3ebdSchin if (streq(s, "logical"))
1495da2e3ebdSchin return FTS_LOGICAL;
1496da2e3ebdSchin if (streq(s, "physical"))
1497da2e3ebdSchin return FTS_PHYSICAL|FTS_SEEDOTDIR;
1498da2e3ebdSchin return FTS_META|FTS_PHYSICAL|FTS_SEEDOTDIR;
1499da2e3ebdSchin }
1500da2e3ebdSchin
1501da2e3ebdSchin /*
15027c2fbfb3SApril Chin * return 1 if ent is mounted on a local filesystem
15037c2fbfb3SApril Chin */
15047c2fbfb3SApril Chin
15057c2fbfb3SApril Chin int
fts_local(FTSENT * ent)15067c2fbfb3SApril Chin fts_local(FTSENT* ent)
15077c2fbfb3SApril Chin {
15087c2fbfb3SApril Chin #ifdef ST_LOCAL
15097c2fbfb3SApril Chin struct statvfs fs;
15107c2fbfb3SApril Chin
15117c2fbfb3SApril Chin return statvfs(ent->fts_path, &fs) || (fs.f_flag & ST_LOCAL);
15127c2fbfb3SApril Chin #else
15137c2fbfb3SApril Chin return !strgrpmatch(fmtfs(ent->fts_statp), "([an]fs|samb)", NiL, 0, STR_LEFT|STR_ICASE);
15147c2fbfb3SApril Chin #endif
15157c2fbfb3SApril Chin }
15167c2fbfb3SApril Chin
15177c2fbfb3SApril Chin /*
1518da2e3ebdSchin * close an open fts stream
1519da2e3ebdSchin */
1520da2e3ebdSchin
1521da2e3ebdSchin int
fts_close(register FTS * fts)1522da2e3ebdSchin fts_close(register FTS* fts)
1523da2e3ebdSchin {
1524da2e3ebdSchin register FTSENT* f;
1525da2e3ebdSchin register FTSENT* x;
1526da2e3ebdSchin
1527da2e3ebdSchin if (fts->dir)
1528da2e3ebdSchin closedir(fts->dir);
1529da2e3ebdSchin if (fts->cd == 0)
1530da2e3ebdSchin pathcd(fts->home, NiL);
1531da2e3ebdSchin free(fts->home);
1532da2e3ebdSchin if (fts->state == FTS_children_return)
1533da2e3ebdSchin fts->current->fts_link = fts->link;
1534da2e3ebdSchin if (fts->top)
1535da2e3ebdSchin {
1536da2e3ebdSchin fts->bot->fts_link = fts->todo;
1537da2e3ebdSchin fts->todo = fts->top;
1538da2e3ebdSchin }
1539da2e3ebdSchin for (f = fts->todo; f; f = x)
1540da2e3ebdSchin {
1541da2e3ebdSchin x = f->fts_link;
1542da2e3ebdSchin free(f);
1543da2e3ebdSchin }
1544da2e3ebdSchin for (f = fts->free; f; f = x)
1545da2e3ebdSchin {
1546da2e3ebdSchin x = f->fts_link;
1547da2e3ebdSchin free(f);
1548da2e3ebdSchin }
15497c2fbfb3SApril Chin free(fts);
1550da2e3ebdSchin return 0;
1551da2e3ebdSchin }
1552da2e3ebdSchin
1553da2e3ebdSchin /*
1554da2e3ebdSchin * register function to be called for each fts_read() entry
15557c2fbfb3SApril Chin * context==0 => unregister notifyf
1556da2e3ebdSchin */
1557da2e3ebdSchin
1558da2e3ebdSchin int
fts_notify(Notify_f notifyf,void * context)1559da2e3ebdSchin fts_notify(Notify_f notifyf, void* context)
1560da2e3ebdSchin {
1561da2e3ebdSchin register Notify_t* np;
15627c2fbfb3SApril Chin register Notify_t* pp;
1563da2e3ebdSchin
15647c2fbfb3SApril Chin if (context)
15657c2fbfb3SApril Chin {
1566da2e3ebdSchin if (!(np = newof(0, Notify_t, 1, 0)))
1567da2e3ebdSchin return -1;
1568da2e3ebdSchin np->notifyf = notifyf;
1569da2e3ebdSchin np->context = context;
1570da2e3ebdSchin np->next = notify;
1571da2e3ebdSchin notify = np;
15727c2fbfb3SApril Chin }
15737c2fbfb3SApril Chin else
15747c2fbfb3SApril Chin {
15757c2fbfb3SApril Chin for (np = notify, pp = 0; np; pp = np, np = np->next)
15767c2fbfb3SApril Chin if (np->notifyf == notifyf)
15777c2fbfb3SApril Chin {
15787c2fbfb3SApril Chin if (pp)
15797c2fbfb3SApril Chin pp->next = np->next;
15807c2fbfb3SApril Chin else
15817c2fbfb3SApril Chin notify = np->next;
15827c2fbfb3SApril Chin free(np);
15837c2fbfb3SApril Chin return 0;
15847c2fbfb3SApril Chin }
15857c2fbfb3SApril Chin return -1;
15867c2fbfb3SApril Chin }
1587da2e3ebdSchin return 0;
1588da2e3ebdSchin }
1589