1/*
2 * Copyright (c) 1989, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Newcomb.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#include <sys/cdefs.h>
38#ifndef lint
39__used static const char copyright[] =
40"@(#) Copyright (c) 1989, 1993, 1994\n\
41	The Regents of the University of California.  All rights reserved.\n";
42#endif /* not lint */
43
44#ifndef lint
45#if 0
46static const char sccsid[] = "@(#)du.c	8.5 (Berkeley) 5/4/95";
47#endif
48#endif /* not lint */
49#include <sys/cdefs.h>
50__FBSDID("$FreeBSD: src/usr.bin/du/du.c,v 1.38 2005/04/09 14:31:40 stefanf Exp $");
51
52#include <sys/mount.h>
53#include <sys/param.h>
54#include <sys/queue.h>
55#include <sys/stat.h>
56#include <sys/attr.h>
57
58#include <err.h>
59#include <errno.h>
60#include <fnmatch.h>
61#include <fts.h>
62#include <locale.h>
63#include <math.h>
64#include <stdint.h>
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <sysexits.h>
69#include <unistd.h>
70
71#ifdef __APPLE__
72#include <get_compat.h>
73#else
74#define COMPAT_MODE(func, mode) (1)
75#endif
76
77#define	KILO_SZ(n) (n)
78#define	MEGA_SZ(n) ((n) * (n))
79#define	GIGA_SZ(n) ((n) * (n) * (n))
80#define	TERA_SZ(n) ((n) * (n) * (n) * (n))
81#define	PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
82
83#define	KILO_2_SZ (KILO_SZ(1024ULL))
84#define	MEGA_2_SZ (MEGA_SZ(1024ULL))
85#define	GIGA_2_SZ (GIGA_SZ(1024ULL))
86#define	TERA_2_SZ (TERA_SZ(1024ULL))
87#define	PETA_2_SZ (PETA_SZ(1024ULL))
88
89#define	KILO_SI_SZ (KILO_SZ(1000ULL))
90#define	MEGA_SI_SZ (MEGA_SZ(1000ULL))
91#define	GIGA_SI_SZ (GIGA_SZ(1000ULL))
92#define	TERA_SI_SZ (TERA_SZ(1000ULL))
93#define	PETA_SI_SZ (PETA_SZ(1000ULL))
94
95#define TWO_TB  (2LL * 1024LL * 1024LL * 1024LL * 1024LL)
96
97unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ};
98unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
99unsigned long long *valp;
100
101typedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t;
102
103int unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA };
104
105SLIST_HEAD(ignhead, ignentry) ignores;
106struct ignentry {
107	char			*mask;
108	SLIST_ENTRY(ignentry)	next;
109};
110
111static int	linkchk(FTSENT *);
112static int	dirlinkchk(FTSENT *);
113static void	usage(void);
114void		prthumanval(double);
115unit_t		unit_adjust(double *);
116void		ignoreadd(const char *);
117void		ignoreclean(void);
118int		ignorep(FTSENT *);
119
120int
121main(int argc, char *argv[])
122{
123	FTS		*fts;
124	FTSENT		*p;
125	off_t		savednumber = 0;
126	long		blocksize;
127	int		ftsoptions;
128	int		listall;
129	int		depth;
130	int		Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag, hflag, ch, notused, rval;
131	char 		**save;
132	static char	dot[] = ".";
133	off_t           *ftsnum, *ftsparnum;
134
135	setlocale(LC_ALL, "");
136
137	Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = hflag = 0;
138
139	save = argv;
140	ftsoptions = FTS_NOCHDIR;
141	depth = INT_MAX;
142	SLIST_INIT(&ignores);
143
144	while ((ch = getopt(argc, argv, "HI:LPasd:cghkmrx")) != -1)
145		switch (ch) {
146			case 'H':
147				Lflag = Pflag = 0;
148				Hflag = 1;
149				break;
150			case 'I':
151				ignoreadd(optarg);
152				break;
153			case 'L':
154				Hflag = Pflag = 0;
155				Lflag = 1;
156				break;
157			case 'P':
158				Hflag = Lflag = 0;
159				Pflag = 1;
160				break;
161			case 'a':
162				aflag = 1;
163				break;
164			case 's':
165				sflag = 1;
166				break;
167			case 'd':
168				dflag = 1;
169				errno = 0;
170				depth = atoi(optarg);
171				if (errno == ERANGE || depth < 0) {
172					warnx("invalid argument to option d: %s", optarg);
173					usage();
174				}
175				break;
176			case 'c':
177				cflag = 1;
178				break;
179			case 'h':
180				putenv("BLOCKSIZE=512");
181				hflag = 1;
182				valp = vals_base2;
183				break;
184			case 'k':
185				hflag = 0;
186				putenv("BLOCKSIZE=1024");
187				break;
188			case 'm':
189				hflag = 0;
190				putenv("BLOCKSIZE=1048576");
191				break;
192			case 'g':
193				hflag = 0;
194				putenv("BLOCKSIZE=1g");
195				break;
196			case 'r':		 /* Compatibility. */
197				break;
198			case 'x':
199				ftsoptions |= FTS_XDEV;
200				break;
201			case '?':
202			default:
203				usage();
204		}
205
206//	argc -= optind;
207	argv += optind;
208
209	/*
210	 * XXX
211	 * Because of the way that fts(3) works, logical walks will not count
212	 * the blocks actually used by symbolic links.  We rationalize this by
213	 * noting that users computing logical sizes are likely to do logical
214	 * copies, so not counting the links is correct.  The real reason is
215	 * that we'd have to re-implement the kernel's symbolic link traversing
216	 * algorithm to get this right.  If, for example, you have relative
217	 * symbolic links referencing other relative symbolic links, it gets
218	 * very nasty, very fast.  The bottom line is that it's documented in
219	 * the man page, so it's a feature.
220	 */
221
222	if (Hflag + Lflag + Pflag > 1)
223		usage();
224
225	if (Hflag + Lflag + Pflag == 0)
226		Pflag = 1;			/* -P (physical) is default */
227
228	if (Hflag)
229		ftsoptions |= FTS_COMFOLLOW;
230
231	if (Lflag)
232		ftsoptions |= FTS_LOGICAL;
233
234	if (Pflag)
235		ftsoptions |= FTS_PHYSICAL;
236
237	listall = 0;
238
239	if (aflag) {
240		if (sflag || dflag)
241			usage();
242		listall = 1;
243	} else if (sflag) {
244		if (dflag)
245			usage();
246		depth = 0;
247	}
248
249	if (!*argv) {
250		argv = save;
251		argv[0] = dot;
252		argv[1] = NULL;
253	}
254
255	(void) getbsize(&notused, &blocksize);
256	blocksize /= 512;
257
258	rval = 0;
259
260	if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
261		err(1, "fts_open");
262
263	while ((p = fts_read(fts)) != NULL) {
264		switch (p->fts_info) {
265			case FTS_D:
266				if (ignorep(p) || dirlinkchk(p))
267					fts_set(fts, p, FTS_SKIP);
268				break;
269			case FTS_DP:
270				if (ignorep(p))
271					break;
272
273				ftsparnum = (off_t *)&p->fts_parent->fts_number;
274				ftsnum = (off_t *)&p->fts_number;
275				if (p->fts_statp->st_size < TWO_TB) {
276				    ftsparnum[0] += ftsnum[0] += p->fts_statp->st_blocks;
277				} else {
278				    ftsparnum[0] += ftsnum[0] += howmany(p->fts_statp->st_size, 512LL);
279				}
280
281				if (p->fts_level <= depth) {
282					if (hflag) {
283						(void) prthumanval(howmany(*ftsnum, blocksize));
284						(void) printf("\t%s\n", p->fts_path);
285					} else {
286					(void) printf("%jd\t%s\n",
287					    (intmax_t)howmany(*ftsnum, blocksize),
288					    p->fts_path);
289					}
290				}
291				break;
292			case FTS_DC:			/* Ignore. */
293				if (COMPAT_MODE("bin/du", "unix2003")) {
294					errx(1, "Can't follow symlink cycle from %s to %s", p->fts_path, p->fts_cycle->fts_path);
295				}
296				break;
297			case FTS_DNR:			/* Warn, continue. */
298			case FTS_ERR:
299			case FTS_NS:
300				warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
301				rval = 1;
302				break;
303			case FTS_SLNONE:
304				if (COMPAT_MODE("bin/du", "unix2003")) {
305					struct stat sb;
306					int rc = stat(p->fts_path, &sb);
307					if (rc < 0 && errno == ELOOP) {
308						errx(1, "Too many symlinks at %s", p->fts_path);
309					}
310				}
311			default:
312				if (ignorep(p))
313					break;
314
315				if (p->fts_statp->st_nlink > 1 && linkchk(p))
316					break;
317
318				if (listall || p->fts_level == 0) {
319					if (hflag) {
320					    if (p->fts_statp->st_size < TWO_TB) {
321						(void) prthumanval(howmany(p->fts_statp->st_blocks,
322							blocksize));
323					    } else {
324						(void) prthumanval(howmany(howmany(p->fts_statp->st_size, 512LL),
325							blocksize));
326					    }
327						(void) printf("\t%s\n", p->fts_path);
328					} else {
329					    if (p->fts_statp->st_size < TWO_TB) {
330						(void) printf("%jd\t%s\n",
331							(intmax_t)howmany(p->fts_statp->st_blocks, blocksize),
332							p->fts_path);
333					    } else {
334						(void) printf("%jd\t%s\n",
335							(intmax_t)howmany(howmany(p->fts_statp->st_size, 512LL), blocksize),
336							p->fts_path);
337					    }
338					}
339				}
340
341				ftsparnum = (off_t *)&p->fts_parent->fts_number;
342				if (p->fts_statp->st_size < TWO_TB) {
343				    ftsparnum[0] += p->fts_statp->st_blocks;
344				} else {
345				    ftsparnum[0] += p->fts_statp->st_size / 512LL;
346				}
347		}
348		savednumber = ((off_t *)&p->fts_parent->fts_number)[0];
349	}
350
351	if (errno)
352		err(1, "fts_read");
353
354	if (cflag) {
355		if (hflag) {
356			(void) prthumanval(howmany(savednumber, blocksize));
357			(void) printf("\ttotal\n");
358		} else {
359			(void) printf("%jd\ttotal\n", (intmax_t)howmany(savednumber, blocksize));
360		}
361	}
362
363	ignoreclean();
364	exit(rval);
365}
366
367static int
368linkchk(FTSENT *p)
369{
370	struct links_entry {
371		struct links_entry *next;
372		struct links_entry *previous;
373		int	 links;
374		dev_t	 dev;
375		ino_t	 ino;
376	};
377	static const size_t links_hash_initial_size = 8192;
378	static struct links_entry **buckets;
379	static struct links_entry *free_list;
380	static size_t number_buckets;
381	static unsigned long number_entries;
382	static char stop_allocating;
383	struct links_entry *le, **new_buckets;
384	struct stat *st;
385	size_t i, new_size;
386	int hash;
387
388	st = p->fts_statp;
389
390	/* If necessary, initialize the hash table. */
391	if (buckets == NULL) {
392		number_buckets = links_hash_initial_size;
393		buckets = malloc(number_buckets * sizeof(buckets[0]));
394		if (buckets == NULL)
395			errx(1, "No memory for hardlink detection");
396		for (i = 0; i < number_buckets; i++)
397			buckets[i] = NULL;
398	}
399
400	/* If the hash table is getting too full, enlarge it. */
401	if (number_entries > number_buckets * 10 && !stop_allocating) {
402		new_size = number_buckets * 2;
403		new_buckets = malloc(new_size * sizeof(struct links_entry *));
404
405		/* Try releasing the free list to see if that helps. */
406		if (new_buckets == NULL && free_list != NULL) {
407			while (free_list != NULL) {
408				le = free_list;
409				free_list = le->next;
410				free(le);
411			}
412			new_buckets = malloc(new_size * sizeof(new_buckets[0]));
413		}
414
415		if (new_buckets == NULL) {
416			stop_allocating = 1;
417			warnx("No more memory for tracking hard links");
418		} else {
419			memset(new_buckets, 0,
420			    new_size * sizeof(struct links_entry *));
421			for (i = 0; i < number_buckets; i++) {
422				while (buckets[i] != NULL) {
423					/* Remove entry from old bucket. */
424					le = buckets[i];
425					buckets[i] = le->next;
426
427					/* Add entry to new bucket. */
428					hash = (le->dev ^ le->ino) % new_size;
429
430					if (new_buckets[hash] != NULL)
431						new_buckets[hash]->previous =
432						    le;
433					le->next = new_buckets[hash];
434					le->previous = NULL;
435					new_buckets[hash] = le;
436				}
437			}
438			free(buckets);
439			buckets = new_buckets;
440			number_buckets = new_size;
441		}
442	}
443
444	/* Try to locate this entry in the hash table. */
445	hash = ( st->st_dev ^ st->st_ino ) % number_buckets;
446	for (le = buckets[hash]; le != NULL; le = le->next) {
447		if (le->dev == st->st_dev && le->ino == st->st_ino) {
448			/*
449			 * Save memory by releasing an entry when we've seen
450			 * all of it's links.
451			 */
452			if (--le->links <= 0) {
453				if (le->previous != NULL)
454					le->previous->next = le->next;
455				if (le->next != NULL)
456					le->next->previous = le->previous;
457				if (buckets[hash] == le)
458					buckets[hash] = le->next;
459				number_entries--;
460				/* Recycle this node through the free list */
461				if (stop_allocating) {
462					free(le);
463				} else {
464					le->next = free_list;
465					free_list = le;
466				}
467			}
468			return (1);
469		}
470	}
471
472	if (stop_allocating)
473		return (0);
474
475	/* Add this entry to the links cache. */
476	if (free_list != NULL) {
477		/* Pull a node from the free list if we can. */
478		le = free_list;
479		free_list = le->next;
480	} else
481		/* Malloc one if we have to. */
482		le = malloc(sizeof(struct links_entry));
483	if (le == NULL) {
484		stop_allocating = 1;
485		warnx("No more memory for tracking hard links");
486		return (0);
487	}
488	le->dev = st->st_dev;
489	le->ino = st->st_ino;
490	le->links = st->st_nlink - 1;
491	number_entries++;
492	le->next = buckets[hash];
493	le->previous = NULL;
494	if (buckets[hash] != NULL)
495		buckets[hash]->previous = le;
496	buckets[hash] = le;
497	return (0);
498}
499
500static int
501dirlinkchk(FTSENT *p)
502{
503	struct links_entry {
504		struct links_entry *next;
505		struct links_entry *previous;
506		int	 links;
507		dev_t	 dev;
508		ino_t	 ino;
509	};
510	static const size_t links_hash_initial_size = 8192;
511	static struct links_entry **buckets;
512	static struct links_entry *free_list;
513	static size_t number_buckets;
514	static unsigned long number_entries;
515	static char stop_allocating;
516	struct links_entry *le, **new_buckets;
517	struct stat *st;
518	size_t i, new_size;
519	int hash;
520	struct attrbuf {
521		int size;
522		int linkcount;
523	} buf;
524	struct attrlist attrList;
525
526	memset(&attrList, 0, sizeof(attrList));
527	attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
528	attrList.dirattr = ATTR_DIR_LINKCOUNT;
529	if (-1 == getattrlist(p->fts_path, &attrList, &buf, sizeof(buf), 0))
530		return 0;
531	if (buf.linkcount == 1)
532		return 0;
533	st = p->fts_statp;
534
535	/* If necessary, initialize the hash table. */
536	if (buckets == NULL) {
537		number_buckets = links_hash_initial_size;
538		buckets = malloc(number_buckets * sizeof(buckets[0]));
539		if (buckets == NULL)
540			errx(1, "No memory for directory hardlink detection");
541		for (i = 0; i < number_buckets; i++)
542			buckets[i] = NULL;
543	}
544
545	/* If the hash table is getting too full, enlarge it. */
546	if (number_entries > number_buckets * 10 && !stop_allocating) {
547		new_size = number_buckets * 2;
548		new_buckets = malloc(new_size * sizeof(struct links_entry *));
549
550		/* Try releasing the free list to see if that helps. */
551		if (new_buckets == NULL && free_list != NULL) {
552			while (free_list != NULL) {
553				le = free_list;
554				free_list = le->next;
555				free(le);
556			}
557			new_buckets = malloc(new_size * sizeof(new_buckets[0]));
558		}
559
560		if (new_buckets == NULL) {
561			stop_allocating = 1;
562			warnx("No more memory for tracking directory hard links");
563		} else {
564			memset(new_buckets, 0,
565			    new_size * sizeof(struct links_entry *));
566			for (i = 0; i < number_buckets; i++) {
567				while (buckets[i] != NULL) {
568					/* Remove entry from old bucket. */
569					le = buckets[i];
570					buckets[i] = le->next;
571
572					/* Add entry to new bucket. */
573					hash = (le->dev ^ le->ino) % new_size;
574
575					if (new_buckets[hash] != NULL)
576						new_buckets[hash]->previous =
577						    le;
578					le->next = new_buckets[hash];
579					le->previous = NULL;
580					new_buckets[hash] = le;
581				}
582			}
583			free(buckets);
584			buckets = new_buckets;
585			number_buckets = new_size;
586		}
587	}
588
589	/* Try to locate this entry in the hash table. */
590	hash = ( st->st_dev ^ st->st_ino ) % number_buckets;
591	for (le = buckets[hash]; le != NULL; le = le->next) {
592		if (le->dev == st->st_dev && le->ino == st->st_ino) {
593			/*
594			 * Save memory by releasing an entry when we've seen
595			 * all of it's links.
596			 */
597			if (--le->links <= 0) {
598				if (le->previous != NULL)
599					le->previous->next = le->next;
600				if (le->next != NULL)
601					le->next->previous = le->previous;
602				if (buckets[hash] == le)
603					buckets[hash] = le->next;
604				number_entries--;
605				/* Recycle this node through the free list */
606				if (stop_allocating) {
607					free(le);
608				} else {
609					le->next = free_list;
610					free_list = le;
611				}
612			}
613			return (1);
614		}
615	}
616
617	if (stop_allocating)
618		return (0);
619	/* Add this entry to the links cache. */
620	if (free_list != NULL) {
621		/* Pull a node from the free list if we can. */
622		le = free_list;
623		free_list = le->next;
624	} else
625		/* Malloc one if we have to. */
626		le = malloc(sizeof(struct links_entry));
627	if (le == NULL) {
628		stop_allocating = 1;
629		warnx("No more memory for tracking hard links");
630		return (0);
631	}
632	le->dev = st->st_dev;
633	le->ino = st->st_ino;
634	le->links = buf.linkcount - 1;
635	number_entries++;
636	le->next = buckets[hash];
637	le->previous = NULL;
638	if (buckets[hash] != NULL)
639		buckets[hash]->previous = le;
640	buckets[hash] = le;
641	return (0);
642}
643
644/*
645 * Output in "human-readable" format.  Uses 3 digits max and puts
646 * unit suffixes at the end.  Makes output compact and easy to read,
647 * especially on huge disks.
648 *
649 */
650unit_t
651unit_adjust(double *val)
652{
653	double abval;
654	unit_t unit;
655	unsigned int unit_sz;
656
657	abval = fabs(*val);
658
659	unit_sz = abval ? ilogb(abval) / 10 : 0;
660
661	if (unit_sz >= UNIT_MAX) {
662		unit = NONE;
663	} else {
664		unit = unitp[unit_sz];
665		*val /= (double)valp[unit_sz];
666	}
667
668	return (unit);
669}
670
671void
672prthumanval(double bytes)
673{
674	unit_t unit;
675
676	bytes *= 512;
677	unit = unit_adjust(&bytes);
678
679	if (bytes == 0)
680		(void)printf("  0B");
681	else if (bytes > 10)
682		(void)printf("%3.0f%c", bytes, "BKMGTPE"[unit]);
683	else
684		(void)printf("%3.1f%c", bytes, "BKMGTPE"[unit]);
685}
686
687static void
688usage(void)
689{
690	(void)fprintf(stderr,
691		"usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k | -m | -g] [-x] [-I mask] [file ...]\n");
692	exit(EX_USAGE);
693}
694
695void
696ignoreadd(const char *mask)
697{
698	struct ignentry *ign;
699
700	ign = calloc(1, sizeof(*ign));
701	if (ign == NULL)
702		errx(1, "cannot allocate memory");
703	ign->mask = strdup(mask);
704	if (ign->mask == NULL)
705		errx(1, "cannot allocate memory");
706	SLIST_INSERT_HEAD(&ignores, ign, next);
707}
708
709void
710ignoreclean(void)
711{
712	struct ignentry *ign;
713
714	while (!SLIST_EMPTY(&ignores)) {
715		ign = SLIST_FIRST(&ignores);
716		SLIST_REMOVE_HEAD(&ignores, next);
717		free(ign->mask);
718		free(ign);
719	}
720}
721
722int
723ignorep(FTSENT *ent)
724{
725	struct ignentry *ign;
726
727#ifdef __APPLE__
728	if (S_ISDIR(ent->fts_statp->st_mode) && !strcmp("fd", ent->fts_name)) {
729		struct statfs sfsb;
730		int rc = statfs(ent->fts_accpath, &sfsb);
731		if (rc >= 0 && !strcmp("devfs", sfsb.f_fstypename)) {
732			/* Don't cd into /dev/fd/N since one of those is likely to be
733			  the cwd as of the start of du which causes all manner of
734			  unpleasant surprises */
735			return 1;
736		}
737	}
738#endif /* __APPLE__ */
739	SLIST_FOREACH(ign, &ignores, next)
740		if (fnmatch(ign->mask, ent->fts_name, 0) != FNM_NOMATCH)
741			return 1;
742	return 0;
743}
744