X-Git-Url: https://git.saurik.com/apple/file_cmds.git/blobdiff_plain/864a4b6e4495e8bb9744303352b4f19fccc90738..refs/heads/master:/du/du.c?ds=sidebyside diff --git a/du/du.c b/du/du.c index 4a426ee..9aea790 100644 --- a/du/du.c +++ b/du/du.c @@ -34,8 +34,9 @@ * SUCH DAMAGE. */ +#include #ifndef lint -static const char copyright[] = +__used static const char copyright[] = "@(#) Copyright (c) 1989, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ @@ -52,6 +53,7 @@ __FBSDID("$FreeBSD: src/usr.bin/du/du.c,v 1.38 2005/04/09 14:31:40 stefanf Exp $ #include #include #include +#include #include #include @@ -68,6 +70,7 @@ __FBSDID("$FreeBSD: src/usr.bin/du/du.c,v 1.38 2005/04/09 14:31:40 stefanf Exp $ #ifdef __APPLE__ #include +#include #else #define COMPAT_MODE(func, mode) (1) #endif @@ -90,8 +93,6 @@ __FBSDID("$FreeBSD: src/usr.bin/du/du.c,v 1.38 2005/04/09 14:31:40 stefanf Exp $ #define TERA_SI_SZ (TERA_SZ(1000ULL)) #define PETA_SI_SZ (PETA_SZ(1000ULL)) -#define TWO_TB (2LL * 1024LL * 1024LL * 1024LL * 1024LL) - unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ}; unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ}; unsigned long long *valp; @@ -107,6 +108,7 @@ struct ignentry { }; static int linkchk(FTSENT *); +static int dirlinkchk(FTSENT *); static void usage(void); void prthumanval(double); unit_t unit_adjust(double *); @@ -134,11 +136,11 @@ main(int argc, char *argv[]) Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = hflag = 0; save = argv; - ftsoptions = 0; + ftsoptions = FTS_NOCHDIR; depth = INT_MAX; SLIST_INIT(&ignores); - while ((ch = getopt(argc, argv, "HI:LPasd:chkmrx")) != -1) + while ((ch = getopt(argc, argv, "HI:LPasd:cghkmrx")) != -1) switch (ch) { case 'H': Lflag = Pflag = 0; @@ -186,6 +188,10 @@ main(int argc, char *argv[]) hflag = 0; putenv("BLOCKSIZE=1048576"); break; + case 'g': + hflag = 0; + putenv("BLOCKSIZE=1g"); + break; case 'r': /* Compatibility. */ break; case 'x': @@ -196,7 +202,7 @@ main(int argc, char *argv[]) usage(); } - argc -= optind; +// argc -= optind; argv += optind; /* @@ -248,6 +254,13 @@ main(int argc, char *argv[]) (void) getbsize(¬used, &blocksize); blocksize /= 512; +#ifdef __APPLE__ + // "du" should not have any side effect on disk usage, + // so prevent materializing dataless directories upon traversal + rval = 1; + (void) sysctlbyname("vfs.nspace.prevent_materialization", NULL, NULL, &rval, sizeof(rval)); +#endif /* __APPLE__ */ + rval = 0; if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) @@ -255,8 +268,8 @@ main(int argc, char *argv[]) while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { - case FTS_D: /* Ignore. */ - if (ignorep(p)) + case FTS_D: + if (ignorep(p) || dirlinkchk(p)) fts_set(fts, p, FTS_SKIP); break; case FTS_DP: @@ -265,11 +278,7 @@ main(int argc, char *argv[]) ftsparnum = (off_t *)&p->fts_parent->fts_number; ftsnum = (off_t *)&p->fts_number; - if (p->fts_statp->st_size < TWO_TB) { - ftsparnum[0] += ftsnum[0] += p->fts_statp->st_blocks; - } else { - ftsparnum[0] += ftsnum[0] += howmany(p->fts_statp->st_size, 512LL); - } + ftsparnum[0] += ftsnum[0] += p->fts_statp->st_blocks; if (p->fts_level <= depth) { if (hflag) { @@ -310,33 +319,18 @@ main(int argc, char *argv[]) if (listall || p->fts_level == 0) { if (hflag) { - if (p->fts_statp->st_size < TWO_TB) { (void) prthumanval(howmany(p->fts_statp->st_blocks, blocksize)); - } else { - (void) prthumanval(howmany(howmany(p->fts_statp->st_size, 512LL), - blocksize)); - } (void) printf("\t%s\n", p->fts_path); } else { - if (p->fts_statp->st_size < TWO_TB) { (void) printf("%jd\t%s\n", (intmax_t)howmany(p->fts_statp->st_blocks, blocksize), p->fts_path); - } else { - (void) printf("%jd\t%s\n", - (intmax_t)howmany(howmany(p->fts_statp->st_size, 512LL), blocksize), - p->fts_path); - } } } ftsparnum = (off_t *)&p->fts_parent->fts_number; - if (p->fts_statp->st_size < TWO_TB) { - ftsparnum[0] += p->fts_statp->st_blocks; - } else { - ftsparnum[0] += p->fts_statp->st_size / 512LL; - } + ftsparnum[0] += p->fts_statp->st_blocks; } savednumber = ((off_t *)&p->fts_parent->fts_number)[0]; } @@ -490,6 +484,150 @@ linkchk(FTSENT *p) return (0); } +static int +dirlinkchk(FTSENT *p) +{ + struct links_entry { + struct links_entry *next; + struct links_entry *previous; + int links; + dev_t dev; + ino_t ino; + }; + static const size_t links_hash_initial_size = 8192; + static struct links_entry **buckets; + static struct links_entry *free_list; + static size_t number_buckets; + static unsigned long number_entries; + static char stop_allocating; + struct links_entry *le, **new_buckets; + struct stat *st; + size_t i, new_size; + int hash; + struct attrbuf { + int size; + int linkcount; + } buf; + struct attrlist attrList; + + memset(&attrList, 0, sizeof(attrList)); + attrList.bitmapcount = ATTR_BIT_MAP_COUNT; + attrList.dirattr = ATTR_DIR_LINKCOUNT; + if (-1 == getattrlist(p->fts_path, &attrList, &buf, sizeof(buf), 0)) + return 0; + if (buf.linkcount == 1) + return 0; + st = p->fts_statp; + + /* If necessary, initialize the hash table. */ + if (buckets == NULL) { + number_buckets = links_hash_initial_size; + buckets = malloc(number_buckets * sizeof(buckets[0])); + if (buckets == NULL) + errx(1, "No memory for directory hardlink detection"); + for (i = 0; i < number_buckets; i++) + buckets[i] = NULL; + } + + /* If the hash table is getting too full, enlarge it. */ + if (number_entries > number_buckets * 10 && !stop_allocating) { + new_size = number_buckets * 2; + new_buckets = malloc(new_size * sizeof(struct links_entry *)); + + /* Try releasing the free list to see if that helps. */ + if (new_buckets == NULL && free_list != NULL) { + while (free_list != NULL) { + le = free_list; + free_list = le->next; + free(le); + } + new_buckets = malloc(new_size * sizeof(new_buckets[0])); + } + + if (new_buckets == NULL) { + stop_allocating = 1; + warnx("No more memory for tracking directory hard links"); + } else { + memset(new_buckets, 0, + new_size * sizeof(struct links_entry *)); + for (i = 0; i < number_buckets; i++) { + while (buckets[i] != NULL) { + /* Remove entry from old bucket. */ + le = buckets[i]; + buckets[i] = le->next; + + /* Add entry to new bucket. */ + hash = (le->dev ^ le->ino) % new_size; + + if (new_buckets[hash] != NULL) + new_buckets[hash]->previous = + le; + le->next = new_buckets[hash]; + le->previous = NULL; + new_buckets[hash] = le; + } + } + free(buckets); + buckets = new_buckets; + number_buckets = new_size; + } + } + + /* Try to locate this entry in the hash table. */ + hash = ( st->st_dev ^ st->st_ino ) % number_buckets; + for (le = buckets[hash]; le != NULL; le = le->next) { + if (le->dev == st->st_dev && le->ino == st->st_ino) { + /* + * Save memory by releasing an entry when we've seen + * all of it's links. + */ + if (--le->links <= 0) { + if (le->previous != NULL) + le->previous->next = le->next; + if (le->next != NULL) + le->next->previous = le->previous; + if (buckets[hash] == le) + buckets[hash] = le->next; + number_entries--; + /* Recycle this node through the free list */ + if (stop_allocating) { + free(le); + } else { + le->next = free_list; + free_list = le; + } + } + return (1); + } + } + + if (stop_allocating) + return (0); + /* Add this entry to the links cache. */ + if (free_list != NULL) { + /* Pull a node from the free list if we can. */ + le = free_list; + free_list = le->next; + } else + /* Malloc one if we have to. */ + le = malloc(sizeof(struct links_entry)); + if (le == NULL) { + stop_allocating = 1; + warnx("No more memory for tracking hard links"); + return (0); + } + le->dev = st->st_dev; + le->ino = st->st_ino; + le->links = buf.linkcount - 1; + number_entries++; + le->next = buckets[hash]; + le->previous = NULL; + if (buckets[hash] != NULL) + buckets[hash]->previous = le; + buckets[hash] = le; + return (0); +} + /* * Output in "human-readable" format. Uses 3 digits max and puts * unit suffixes at the end. Makes output compact and easy to read, @@ -537,7 +675,7 @@ static void usage(void) { (void)fprintf(stderr, - "usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k | -m] [-x] [-I mask] [file ...]\n"); + "usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k | -m | -g] [-x] [-I mask] [file ...]\n"); exit(EX_USAGE); } @@ -577,7 +715,7 @@ ignorep(FTSENT *ent) if (S_ISDIR(ent->fts_statp->st_mode) && !strcmp("fd", ent->fts_name)) { struct statfs sfsb; int rc = statfs(ent->fts_accpath, &sfsb); - if (rc >= 0 && !strcmp("fdesc", sfsb.f_fstypename)) { + if (rc >= 0 && !strcmp("devfs", sfsb.f_fstypename)) { /* Don't cd into /dev/fd/N since one of those is likely to be the cwd as of the start of du which causes all manner of unpleasant surprises */