In the description of3111908b03, it says that the functions must be able to handle st being NULL, but recurse always passes a valid pointer. The only function that was ever passed NULL was rm(), but this was changed to go through recurse in2f4ab52739, so now the checks are pointless.
116 lines
2.1 KiB
C
116 lines
2.1 KiB
C
/* See LICENSE file for copyright and license details. */
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
#include "fs.h"
|
|
#include "util.h"
|
|
|
|
static size_t maxdepth = SIZE_MAX;
|
|
static size_t blksize = 512;
|
|
|
|
static int aflag = 0;
|
|
static int sflag = 0;
|
|
static int hflag = 0;
|
|
|
|
static void
|
|
printpath(off_t n, const char *path)
|
|
{
|
|
if (hflag)
|
|
printf("%s\t%s\n", humansize(n * blksize), path);
|
|
else
|
|
printf("%jd\t%s\n", (intmax_t)n, path);
|
|
}
|
|
|
|
static off_t
|
|
nblks(blkcnt_t blocks)
|
|
{
|
|
return (512 * blocks + blksize - 1) / blksize;
|
|
}
|
|
|
|
static void
|
|
du(const char *path, struct stat *st, void *total, struct recursor *r)
|
|
{
|
|
off_t subtotal = 0;
|
|
|
|
if (S_ISDIR(st->st_mode))
|
|
recurse(path, &subtotal, r);
|
|
*((off_t *)total) += subtotal + nblks(st->st_blocks);
|
|
|
|
if (!sflag && r->depth <= maxdepth && r->depth && (S_ISDIR(st->st_mode) || aflag))
|
|
printpath(subtotal + nblks(st->st_blocks), path);
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
eprintf("usage: %s [-a | -s] [-d depth] [-h] [-k] [-H | -L | -P] [-x] [file ...]\n", argv0);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct recursor r = { .fn = du, .hist = NULL, .depth = 0, .maxdepth = 0,
|
|
.follow = 'P', .flags = 0 };
|
|
off_t n = 0;
|
|
int kflag = 0, dflag = 0;
|
|
char *bsize;
|
|
|
|
ARGBEGIN {
|
|
case 'a':
|
|
aflag = 1;
|
|
break;
|
|
case 'd':
|
|
dflag = 1;
|
|
maxdepth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
|
|
break;
|
|
case 'h':
|
|
hflag = 1;
|
|
break;
|
|
case 'k':
|
|
kflag = 1;
|
|
break;
|
|
case 's':
|
|
sflag = 1;
|
|
break;
|
|
case 'x':
|
|
r.flags |= SAMEDEV;
|
|
break;
|
|
case 'H':
|
|
case 'L':
|
|
case 'P':
|
|
r.follow = ARGC();
|
|
break;
|
|
default:
|
|
usage();
|
|
} ARGEND
|
|
|
|
if ((aflag && sflag) || (dflag && sflag))
|
|
usage();
|
|
|
|
bsize = getenv("BLOCKSIZE");
|
|
if (bsize)
|
|
blksize = estrtonum(bsize, 1, MIN(LLONG_MAX, SIZE_MAX));
|
|
if (kflag)
|
|
blksize = 1024;
|
|
|
|
if (!argc) {
|
|
recurse(".", &n, &r);
|
|
printpath(n, ".");
|
|
} else {
|
|
for (; *argv; argc--, argv++) {
|
|
n = 0;
|
|
recurse(*argv, &n, &r);
|
|
printpath(n, *argv);
|
|
}
|
|
}
|
|
|
|
return fshut(stdout, "<stdout>") || recurse_status;
|
|
}
|