du.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <String.h>
  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. int aflag;
  10. int fflag;
  11. int nflag;
  12. int sflag;
  13. int tflag;
  14. int uflag;
  15. int qflag;
  16. char *fmt = "%llud\t%q\n";
  17. vlong blocksize = 1024LL;
  18. void
  19. usage(void)
  20. {
  21. fprint(2, "usage: du [-afnqstu] [-b size] [file ...]\n");
  22. exits("usage");
  23. }
  24. void
  25. main(int argc, char *argv[])
  26. {
  27. int i;
  28. char *s, *ss;
  29. doquote = needsrcquote;
  30. quotefmtinstall();
  31. ARGBEGIN {
  32. case 'a': /* all files */
  33. aflag = 1;
  34. break;
  35. case 's': /* only top level */
  36. sflag = 1;
  37. break;
  38. case 'f': /* ignore errors */
  39. fflag = 1;
  40. break;
  41. case 'n': /* all files, number of bytes */
  42. aflag = 1;
  43. nflag = 1;
  44. break;
  45. case 't': /* return modified/accessed time */
  46. tflag = 1;
  47. break;
  48. case 'u': /* accessed time */
  49. uflag = 1;
  50. break;
  51. case 'q': /* qid */
  52. fmt = "%.16llux\t%q\n";
  53. qflag = 1;
  54. break;
  55. case 'b': /* block size */
  56. s = ARGF();
  57. if(s) {
  58. blocksize = strtoul(s, &ss, 0);
  59. if(s == ss)
  60. blocksize = 1;
  61. if(*ss == 'k')
  62. blocksize *= 1024;
  63. }
  64. break;
  65. default:
  66. usage();
  67. } ARGEND
  68. if(argc==0)
  69. print(fmt, du(".", dirstat(".")), ".");
  70. else
  71. for(i=0; i<argc; i++)
  72. print(fmt, du(argv[i], dirstat(argv[i])), argv[i]);
  73. exits(0);
  74. }
  75. vlong
  76. du(char *name, Dir *dir)
  77. {
  78. int fd, i, n;
  79. Dir *buf, *d;
  80. String *file;
  81. vlong nk, t;
  82. if(dir == nil)
  83. return warn(name);
  84. fd = open(name, OREAD);
  85. if(fd < 0)
  86. return warn(name);
  87. if((dir->qid.type&QTDIR) == 0)
  88. nk = k(dir->length);
  89. else{
  90. nk = 0;
  91. while((n=dirread(fd, &buf)) > 0) {
  92. d = buf;
  93. for(i=0; i<n; i++, d++) {
  94. if((d->qid.type&QTDIR) == 0) {
  95. t = k(d->length);
  96. nk += t;
  97. if(aflag) {
  98. file = s_copy(name);
  99. s_append(file, "/");
  100. s_append(file, d->name);
  101. if(tflag) {
  102. t = d->mtime;
  103. if(uflag)
  104. t = d->atime;
  105. }
  106. if(qflag)
  107. t = d->qid.path;
  108. print(fmt, t, s_to_c(file));
  109. s_free(file);
  110. }
  111. continue;
  112. }
  113. if(strcmp(d->name, ".") == 0 ||
  114. strcmp(d->name, "..") == 0 ||
  115. seen(d))
  116. continue;
  117. file = s_copy(name);
  118. s_append(file, "/");
  119. s_append(file, d->name);
  120. t = du(s_to_c(file), d);
  121. nk += t;
  122. if(tflag) {
  123. t = d->mtime;
  124. if(uflag)
  125. t = d->atime;
  126. }
  127. if(qflag)
  128. t = d->qid.path;
  129. if(!sflag)
  130. print(fmt, t, s_to_c(file));
  131. s_free(file);
  132. }
  133. free(buf);
  134. }
  135. if(n < 0)
  136. warn(name);
  137. }
  138. close(fd);
  139. if(tflag) {
  140. if(uflag)
  141. return dir->atime;
  142. return dir->mtime;
  143. }
  144. if(qflag)
  145. return dir->qid.path;
  146. return nk;
  147. }
  148. #define NCACHE 128 /* must be power of two */
  149. typedef struct Cache Cache;
  150. struct Cache
  151. {
  152. Dir* cache;
  153. int n;
  154. int max;
  155. } cache[NCACHE];
  156. int
  157. seen(Dir *dir)
  158. {
  159. Dir *dp;
  160. int i;
  161. Cache *c;
  162. c = &cache[dir->qid.path&(NCACHE-1)];
  163. dp = c->cache;
  164. for(i=0; i<c->n; i++, dp++)
  165. if(dir->qid.path == dp->qid.path &&
  166. dir->type == dp->type &&
  167. dir->dev == dp->dev)
  168. return 1;
  169. if(c->n == c->max){
  170. c->cache = realloc(c->cache, (c->max+=20)*sizeof(Dir));
  171. if(cache == 0)
  172. err("malloc failure");
  173. }
  174. c->cache[c->n++] = *dir;
  175. return 0;
  176. }
  177. void
  178. err(char *s)
  179. {
  180. fprint(2, "du: %s: %r\n", s);
  181. exits(s);
  182. }
  183. int
  184. warn(char *s)
  185. {
  186. if(fflag == 0)
  187. fprint(2, "du: %s: %r\n", s);
  188. return 0;
  189. }
  190. vlong
  191. k(vlong n)
  192. {
  193. if(nflag)
  194. return n;
  195. n = (n+blocksize-1)/blocksize;
  196. return n*blocksize/1024LL;
  197. }