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