file_cmds-242.tar.gz
[apple/file_cmds.git] / du / du.c
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
46 static 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
97 unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ};
98 unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
99 unsigned long long *valp;
100
101 typedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t;
102
103 int unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA };
104
105 SLIST_HEAD(ignhead, ignentry) ignores;
106 struct ignentry {
107 char *mask;
108 SLIST_ENTRY(ignentry) next;
109 };
110
111 static int linkchk(FTSENT *);
112 static int dirlinkchk(FTSENT *);
113 static void usage(void);
114 void prthumanval(double);
115 unit_t unit_adjust(double *);
116 void ignoreadd(const char *);
117 void ignoreclean(void);
118 int ignorep(FTSENT *);
119
120 int
121 main(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
367 static int
368 linkchk(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
500 static int
501 dirlinkchk(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 */
650 unit_t
651 unit_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
671 void
672 prthumanval(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
687 static void
688 usage(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
695 void
696 ignoreadd(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
709 void
710 ignoreclean(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
722 int
723 ignorep(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 }