1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#define FOR_du
37#include "toys.h"
38
39GLOBALS(
40 long d;
41
42 unsigned long depth, total;
43 dev_t st_dev;
44 void *inodes;
45)
46
47typedef struct node_size {
48 struct dirtree *node;
49 long size;
50} node_size;
51
52
53static void print(long long size, struct dirtree *node)
54{
55 char *name = "total";
56
57 if (TT.depth > TT.d) return;
58
59 if (toys.optflags & FLAG_h) {
60 human_readable(toybuf, size, 0);
61 printf("%s", toybuf);
62 } else {
63 int bits = 10;
64
65 if (toys.optflags & FLAG_K) bits = 9;
66 else if (toys.optflags & FLAG_m) bits = 20;
67
68 printf("%llu", (size>>bits)+!!(size&((1<<bits)-1)));
69 }
70 if (node) name = dirtree_path(node, NULL);
71 xprintf("\t%s\n", name);
72 if (node) free(name);
73}
74
75
76
77static int seen_inode(void **list, struct stat *st)
78{
79 if (!st) llist_traverse(st, free);
80
81
82
83
84
85 else if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
86 struct inode_list {
87 struct inode_list *next;
88 ino_t ino;
89 dev_t dev;
90 } *new;
91
92 for (new = *list; new; new = new->next)
93 if(new->ino == st->st_ino && new->dev == st->st_dev)
94 return 1;
95
96 new = xzalloc(sizeof(*new));
97 new->ino = st->st_ino;
98 new->dev = st->st_dev;
99 new->next = *list;
100 *list = new;
101 }
102
103 return 0;
104}
105
106
107static int do_du(struct dirtree *node)
108{
109 unsigned long blocks;
110
111 if (!node->parent) TT.st_dev = node->st.st_dev;
112 else if (!dirtree_notdotdot(node)) return 0;
113
114
115 if ((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev))
116 return 0;
117
118
119 if (toys.optflags & FLAG_L) {
120 struct dirtree *try = node;
121
122 while ((try = try->parent))
123 if (node->st.st_dev==try->st.st_dev && node->st.st_ino==try->st.st_ino)
124 return 0;
125 }
126
127
128 if (!(toys.optflags & FLAG_l) && !node->again)
129 if (seen_inode(&TT.inodes, &node->st)) return 0;
130
131
132 if (S_ISDIR(node->st.st_mode)) {
133 if (!node->again) {
134 TT.depth++;
135 return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_L));
136 } else TT.depth--;
137 }
138
139
140
141 blocks = node->st.st_blocks + (unsigned long)node->extra;
142 node->extra = blocks;
143 if (node->parent)
144 node->parent->extra = (unsigned long)node->parent->extra+blocks;
145 else TT.total += node->extra;
146
147 if ((toys.optflags & FLAG_a) || !node->parent
148 || (S_ISDIR(node->st.st_mode) && !(toys.optflags & FLAG_s)))
149 {
150 blocks = node->extra;
151 print(blocks*512LL, node);
152 }
153
154 return 0;
155}
156
157void du_main(void)
158{
159 char *noargs[] = {".", 0}, **args;
160
161
162 for (args = toys.optc ? toys.optargs : noargs; *args; args++)
163 dirtree_flagread(*args, DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)),
164 do_du);
165 if (toys.optflags & FLAG_c) print(TT.total*512, 0);
166
167 if (CFG_TOYBOX_FREE) seen_inode(TT.inodes, 0);
168}
169