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 }