du.c 3.1 KB

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