9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

du.c (3101B)


      1 #include <u.h>
      2 #include <libc.h>
      3 
      4 extern	vlong	du(char*, Dir*);
      5 extern	vlong	k(vlong);
      6 extern	void	err(char*);
      7 extern	int	warn(char*);
      8 extern	int	seen(Dir*);
      9 
     10 int	aflag;
     11 int	fflag;
     12 int	nflag;
     13 int	sflag;
     14 int	tflag;
     15 int	uflag;
     16 int	qflag;
     17 char	*fmt = "%llud\t%s\n";
     18 vlong	blocksize = 1024LL;
     19 
     20 void
     21 main(int argc, char *argv[])
     22 {
     23 	int i;
     24 	char *s, *ss;
     25 
     26 	ARGBEGIN {
     27 	case 'a':	/* all files */
     28 		aflag = 1;
     29 		break;
     30 	case 's':	/* only top level */
     31 		sflag = 1;
     32 		break;
     33 	case 'f':	/* ignore errors */
     34 		fflag = 1;
     35 		break;
     36 	case 'n':	/* all files, number of bytes */
     37 		aflag = 1;
     38 		nflag = 1;
     39 		break;
     40 	case 't':	/* return modified/accessed time */
     41 		tflag = 1;
     42 		break;
     43 	case 'u':	/* accessed time */
     44 		uflag = 1;
     45 		break;
     46 	case 'q':	/* qid */
     47 		fmt = "%.16llux\t%s\n";
     48 		qflag = 1;
     49 		break;
     50 	case 'b':	/* block size */
     51 		s = ARGF();
     52 		if(s) {
     53 			blocksize = strtoul(s, &ss, 0);
     54 			if(s == ss)
     55 				blocksize = 1;
     56 			if(*ss == 'k')
     57 				blocksize *= 1024;
     58 		}
     59 		break;
     60 	} ARGEND
     61 	if(argc==0)
     62 		print(fmt, du(".", dirstat(".")), ".");
     63 	else
     64 		for(i=0; i<argc; i++)
     65 			print(fmt, du(argv[i], dirstat(argv[i])), argv[i]);
     66 	exits(0);
     67 }
     68 
     69 vlong
     70 du(char *name, Dir *dir)
     71 {
     72 	int fd, i, n;
     73 	Dir *buf, *d;
     74 	char file[256];
     75 	vlong nk, t;
     76 
     77 	if(dir == nil)
     78 		return warn(name);
     79 
     80 	fd = open(name, OREAD);
     81 	if(fd < 0)
     82 		return warn(name);
     83 
     84 	if((dir->qid.type&QTDIR) == 0)
     85 		nk = k(dir->length);
     86 	else{
     87 		nk = 0;
     88 		while((n=dirread(fd, &buf)) > 0) {
     89 			d = buf;
     90 			for(i=0; i<n; i++, d++) {
     91 				if((d->qid.type&QTDIR) == 0) {
     92 					t = k(d->length);
     93 					nk += t;
     94 					if(aflag) {
     95 						sprint(file, "%s/%s", name, d->name);
     96 						if(tflag) {
     97 							t = d->mtime;
     98 							if(uflag)
     99 								t = d->atime;
    100 						}
    101 						if(qflag)
    102 							t = d->qid.path;
    103 						print(fmt, t, file);
    104 					}
    105 					continue;
    106 				}
    107 				if(strcmp(d->name, ".") == 0 ||
    108 				   strcmp(d->name, "..") == 0 ||
    109 				   seen(d))
    110 					continue;
    111 				sprint(file, "%s/%s", name, d->name);
    112 				t = du(file, d);
    113 				nk += t;
    114 				if(tflag) {
    115 					t = d->mtime;
    116 					if(uflag)
    117 						t = d->atime;
    118 				}
    119 				if(qflag)
    120 					t = d->qid.path;
    121 				if(!sflag)
    122 					print(fmt, t, file);
    123 			}
    124 			free(buf);
    125 		}
    126 		if(n < 0)
    127 			warn(name);
    128 	}
    129 	close(fd);
    130 	if(tflag) {
    131 		if(uflag)
    132 			return dir->atime;
    133 		return dir->mtime;
    134 	}
    135 	if(qflag)
    136 		return dir->qid.path;
    137 	return nk;
    138 }
    139 
    140 #define	NCACHE	128	/* must be power of two */
    141 typedef	struct	Cache	Cache;
    142 struct	Cache
    143 {
    144 	Dir*	cache;
    145 	int	n;
    146 	int	max;
    147 } cache[NCACHE];
    148 
    149 int
    150 seen(Dir *dir)
    151 {
    152 	Dir *dp;
    153 	int i;
    154 	Cache *c;
    155 
    156 	c = &cache[dir->qid.path&(NCACHE-1)];
    157 	dp = c->cache;
    158 	for(i=0; i<c->n; i++, dp++)
    159 		if(dir->qid.path == dp->qid.path &&
    160 		   dir->type == dp->type &&
    161 		   dir->dev == dp->dev)
    162 			return 1;
    163 	if(c->n == c->max){
    164 		c->cache = realloc(c->cache, (c->max+=20)*sizeof(Dir));
    165 		if(c->cache == 0)
    166 			err("malloc failure");
    167 	}
    168 	c->cache[c->n++] = *dir;
    169 	return 0;
    170 }
    171 
    172 void
    173 err(char *s)
    174 {
    175 	fprint(2, "du: %s: %r\n", s);
    176 	exits(s);
    177 }
    178 
    179 int
    180 warn(char *s)
    181 {
    182 	if(fflag == 0)
    183 		fprint(2, "du: %s: %r\n", s);
    184 	return 0;
    185 }
    186 
    187 vlong
    188 k(vlong n)
    189 {
    190 	if(nflag)
    191 		return n;
    192 	n = (n+blocksize-1)/blocksize;
    193 	return n*blocksize/1024LL;
    194 }