du.c - 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", na… | |
96 if(tflag) { | |
97 t = d->mtime; | |
98 if(uflag) | |
99 t = d->a… | |
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 } |