| 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 } |