10 /* should turn these flags into a mask */
15 long maxdepth = ~(1<<31);
29 char buf[1024]; /* arbitrary */
32 if((n = snprint(buf, sizeof(buf), "%s: ", argv0)) < 0)
33 sysfatal("snprint: %r");
35 vseprint(buf+n, buf+sizeof(buf), fmt, arg);
39 fprint(2, "%s\n", buf);
43 dofile(char *path, Dir *f, int pathonly)
49 || (tflag && ! (f->qid.type & QTTMP))
50 || (xflag && ! (f->mode & DMEXEC))
54 for(p = s_to_c(stfmt); *p != '\0'; p++){
56 case 'U': Bwrite(bout, f->uid, strlen(f->uid)); break;
57 case 'G': Bwrite(bout, f->gid, strlen(f->gid)); break;
58 case 'M': Bwrite(bout, f->muid, strlen(f->muid)); break;
59 case 'a': Bprint(bout, "%uld", f->atime); break;
60 case 'm': Bprint(bout, "%uld", f->mtime); break;
61 case 'n': Bwrite(bout, f->name, strlen(f->name)); break;
64 Bwrite(bout, path, strlen(path));
65 if(! (f->qid.type & QTDIR) && !pathonly){
68 Bwrite(bout, f->name, strlen(f->name));
71 case 'q': Bprint(bout, "%ullx.%uld.%.2uhhx", f->qid.path, f->qid.vers, f->qid.type); break;
72 case 's': Bprint(bout, "%lld", f->length); break;
73 case 'x': Bprint(bout, "%ulo", f->mode); break;
89 walk(char *path, Dir *cf, long depth)
97 warn("path: %s: %r", path);
101 if(depth >= maxdepth)
104 if((fd = open(path, OREAD)) < 0){
105 warn("couldn't open %s: %r", path);
109 while((n = dirread(fd, &dirs)) > 0){
111 for(f = dirs; f < fe; f++){
114 if(! (f->qid.type & QTDIR)){
115 if(fflag && depth >= mindepth)
117 } else if(strcmp(f->name, ".") == 0 || strcmp(f->name, "..") == 0){
118 warn(". or .. named file: %s/%s", path, f->name);
120 if(depth+1 > maxdepth){
123 } else if(path == dotpath){
124 if((file = s_new()) == nil)
125 sysfatal("s_new: %r");
127 if((file = s_copy(path)) == nil)
128 sysfatal("s_copy: %r");
129 if(s_len(file) != 1 || *s_to_c(file) != '/')
132 s_append(file, f->name);
134 walk(s_to_c(file), f, depth+1);
142 warn("%s: %r", path);
146 if(dflag && depth >= mindepth)
156 if(q>s && *q=='/' && *(q-1)=='/')
164 } while(p>s && *p=='/');
170 estrtol(char *as, char **aas, int base)
175 n = strtol(as, &p, base);
176 if(p == as || *p != '\0')
177 sysfatal("estrtol: bad input '%s'", as);
189 sysfatal("empty depth argument");
191 if(q = strchr(p, ',')){
194 mindepth = estrtol(p, nil, 0);
200 maxdepth = estrtol(p, nil, 0);
206 fprint(2, "usage: %s [-udftx] [-n mind,maxd] [-e statfmt] [file ...]\n", argv0);
211 Last I checked (commit 3dd6a31881535615389c24ab9a139af2798c462c),
212 libString calls sysfatal when things go wrong; in my local
213 copy of libString, failed calls return nil and errstr is set.
215 There are various nil checks in this code when calling libString
216 functions, but since they are a no-op and libString needs
217 a rework, I left them in - BurnZeZ
221 main(int argc, char **argv)
228 case 'C': Cflag++; break; /* undocumented; do not cleanname() the args */
229 case 'u': uflag++; break; /* unbuffered output */
231 case 'd': dflag++; fflag = 0; break; /* only dirs */
232 case 'f': fflag++; dflag = 0; break; /* only non-dirs */
233 case 't': tflag++; break; /* only tmp files */
234 case 'x': xflag++; break; /* only executable permission */
236 case 'n': elimdepth(EARGF(usage())); break;
238 if((stfmt = s_reset(stfmt)) == nil)
239 sysfatal("s_reset: %r");
240 s_append(stfmt, EARGF(usage()));
241 i = strspn(s_to_c(stfmt), "UGMamnpqsx");
242 if(i != s_len(stfmt))
243 sysfatal("bad stfmt: %s\n", s_to_c(stfmt));
249 if((bout = Bfdopen(1, OWRITE)) == nil)
250 sysfatal("Bfdopen: %r");
253 if((stfmt = s_new()) == nil)
254 sysfatal("s_new: %r");
258 if(maxdepth != ~(1<<31))
261 dotdir = dirstat(".");
262 walk(dotpath, dotdir, 1);
263 } else for(i=0; i<argc; i++){
264 if(strncmp(argv[i], "#/", 2) == 0)
265 slashslash(argv[i]+2);
271 if((d = dirstat(argv[i])) != nil && ! (d->qid.type & QTDIR)){
272 if(fflag && !seen(d) && mindepth < 1)
273 dofile(argv[i], d, 1);
283 /* below pilfered from /sys/src/cmd/du.c
284 * NOTE: I did not check for bugs */
286 #define NCACHE 256 /* must be power of two */
303 c = &cache[dir->qid.path&(NCACHE-1)];
305 for(i=0; i<c->n; i++, dp++)
306 if(dir->qid.path == dp->qid.path &&
307 dir->type == dp->type &&
315 c->cache = realloc(c->cache, c->max*sizeof(Dir));
317 sysfatal("realloc: %r");
319 c->cache[c->n++] = *dir;