6df4dd6d5705e4f52effab05a1c4cd6dfd3187e8
2 * du.c: implementation of du.h.
13 #include <sys/types.h>
24 #include <linux/types.h>
25 #include <linux/dirent.h>
26 #include <linux/unistd.h>
27 typedef int dirhandle
;
29 struct dirent data
[32];
33 _syscall3(int, getdents
, uint
, fd
, struct dirent
*, dirp
, uint
, count
)
34 #define OPENDIR(f) open(f, O_RDONLY | O_NOATIME | O_DIRECTORY)
35 #define DIRVALID(dh) ((dh) >= 0)
36 #define READDIR(dh,de) ((de).curr = (de).data, (de).pos = 0, \
37 ((de).endpos = getdents((dh), (de).data, sizeof((de).data))) > 0)
38 #define DENAME(de) ((de).curr->d_name)
39 #define DEDONE(de) ((de).pos >= (de).endpos)
40 #define DEADVANCE(de) ((de).pos += (de).curr->d_reclen, \
41 (de).curr = (struct dirent *)((char *)(de).data + (de).pos))
42 #define CLOSEDIR(dh) close(dh)
45 typedef DIR *dirhandle
;
46 typedef struct dirent
*direntry
;
47 #define OPENDIR(f) opendir(f)
48 #define DIRVALID(dh) ((dh) != NULL)
49 #define READDIR(dh,de) (((de) = readdir(dh)) ? 1 : 0)
50 #define DENAME(de) ((de)->d_name)
51 #define DEDONE(de) ((de) == NULL)
52 #define DEADVANCE(de) ((de) = NULL)
53 #define CLOSEDIR(dh) closedir(dh)
56 static int str_cmp(const void *av
, const void *bv
)
58 return strcmp(*(const char **)av
, *(const char **)bv
);
61 static void du_recurse(char **path
, size_t pathlen
, size_t *pathsize
,
62 gotdata_fn_t gotdata
, void *gotdata_ctx
)
68 size_t i
, nnames
, namesize
;
70 if (lstat64(*path
, &st
) < 0) {
71 fprintf(stderr
, "%s: lstat: %s\n", *path
, strerror(errno
));
75 if (!gotdata(gotdata_ctx
, *path
, &st
))
78 if (!S_ISDIR(st
.st_mode
))
82 nnames
= namesize
= 0;
86 fprintf(stderr
, "%s: opendir: %s\n", *path
, strerror(errno
));
89 while (READDIR(d
, de
)) {
91 const char *name
= DENAME(de
);
92 if (name
[0] == '.' && (!name
[1] || (name
[1] == '.' && !name
[2]))) {
93 /* do nothing - we skip "." and ".." */
95 if (nnames
>= namesize
) {
96 namesize
= nnames
* 3 / 2 + 64;
97 names
= sresize(names
, namesize
, char *);
99 names
[nnames
++] = dupstr(name
);
102 } while (!DEDONE(de
));
109 qsort(names
, nnames
, sizeof(*names
), str_cmp
);
111 for (i
= 0; i
< nnames
; i
++) {
112 size_t newpathlen
= pathlen
+ 1 + strlen(names
[i
]);
113 if (*pathsize
<= newpathlen
) {
114 *pathsize
= newpathlen
* 3 / 2 + 256;
115 *path
= sresize(*path
, *pathsize
, char);
118 * Avoid duplicating a slash if we got a trailing one to
119 * begin with (i.e. if we're starting the scan in '/' itself).
121 if (pathlen
> 0 && (*path
)[pathlen
-1] == '/') {
122 strcpy(*path
+ pathlen
, names
[i
]);
125 sprintf(*path
+ pathlen
, "/%s", names
[i
]);
128 du_recurse(path
, newpathlen
, pathsize
, gotdata
, gotdata_ctx
);
135 void du(const char *inpath
, gotdata_fn_t gotdata
, void *gotdata_ctx
)
138 size_t pathlen
, pathsize
;
140 pathlen
= strlen(inpath
);
141 pathsize
= pathlen
+ 256;
142 path
= snewn(pathsize
, char);
143 strcpy(path
, inpath
);
145 du_recurse(&path
, pathlen
, &pathsize
, gotdata
, gotdata_ctx
);