xref: /plan9-contrib/sys/src/cmd/du.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 
4 #define	ISDIR	0x80000000L
5 
6 long	du(char *, Dir *);
7 long	k(long);
8 void	err(char *);
9 int	warn(char *);
10 int	seen(Dir *);
11 int	aflag=0;
12 char	fmt[] = "%lud\t%s\n";
13 long	blocksize = 1024;
14 
15 void
16 main(int argc, char *argv[])
17 {
18 	int i;
19 	char *s, *ss;
20 
21 	ARGBEGIN{
22 	case 'a':	aflag=1; break;
23 	case 'b':
24 		s = ARGF();
25 		blocksize = strtoul(s, &ss, 0);
26 		if(s == ss)
27 			blocksize = 1;
28 		if(*ss == 'k')
29 			blocksize *= 1024;
30 		break;
31 	}ARGEND
32 	if(argc==0)
33 		print(fmt, du(".", (Dir*)0), ".");
34 	else
35 	for(i=0; i<argc; i++)
36 		print(fmt, du(argv[i], (Dir*)0), argv[i]);
37 	exits(0);
38 }
39 
40 long
41 du(char *name, Dir *dir)
42 {
43 	int fd, i, n;
44 	Dir buf[25], b;
45 	char file[256];
46 	long nk, t;
47 
48 	if(dir==0){
49 		dir=&buf[0];
50 		if(dirstat(name, dir)<0)
51 			return warn(name);
52 		if((dir->mode&ISDIR)==0)
53 			return k(dir->length);
54 	}
55 	fd=open(name, OREAD);
56 	if(fd<0)
57 		return warn(name);
58 	nk=0;
59 	while((n=dirread(fd, buf, sizeof buf))>0){
60 		n/=sizeof(Dir);
61 		dir=buf;
62 		for(i=0; i<n; i++, dir++){
63 			if((dir->mode&ISDIR)==0){
64 				t=k(dir->length);
65 				nk+=t;
66 				if(aflag){
67 					sprint(file, "%s/%s", name, dir->name);
68 					print(fmt, t, file);
69 				}
70 				continue;
71 			}
72 			if(strcmp(dir->name, ".")==0 || strcmp(dir->name, "..")==0 || seen(dir))
73 				continue;
74 			sprint(file, "%s/%s", name, dir->name);
75 			if(dirstat(file, &b)<0){
76 				warn(file);
77 				continue;
78 			}
79 			if(b.qid.path!=dir->qid.path ||
80 			   b.dev!=dir->dev || b.type!=dir->type)
81 				continue;	/* file is hidden */
82 			t=du(file, dir);
83 			print(fmt, t, file);
84 			nk+=t;
85 		}
86 	}
87 	if(n<0)
88 		warn("name");
89 	close(fd);
90 	return nk;
91 }
92 
93 #define	NCACHE	128	/* must be power of two */
94 struct cache
95 {
96 	Dir	*cache;
97 	int	n;
98 	int	max;
99 } cache[NCACHE];
100 
101 int
102 seen(Dir *dir)
103 {
104 	Dir *dp;
105 	int i;
106 	struct cache *c;
107 
108 	c = &cache[dir->qid.path&(NCACHE-1)];
109 	dp = c->cache;
110 	for(i=0; i<c->n; i++,dp++)
111 		if(dir->qid.path==dp->qid.path &&
112 		   dir->type==dp->type && dir->dev==dp->dev)
113 			return 1;
114 	if(c->n == c->max){
115 		c->cache = realloc(c->cache, (c->max+=20)*sizeof(Dir));
116 		if(cache == 0)
117 			err("malloc failure");
118 	}
119 	c->cache[c->n++] = *dir;
120 	return 0;
121 }
122 
123 void
124 err(char *s)
125 {
126 	fprint(2, "du: ");
127 	perror(s);
128 	exits(s);
129 }
130 
131 int
132 warn(char *s)
133 {
134 	fprint(2, "du: ");
135 	perror(s);
136 	return 0;
137 }
138 
139 long
140 k(long n)
141 {
142 	n = (n+blocksize-1)/blocksize;
143 	return n*blocksize/1024;
144 }
145