6 #define lenof(x) (sizeof((x))/sizeof(*(x)))
9 ( (type *) malloc (sizeof (type)) )
10 #define snewn(number, type) \
11 ( (type *) malloc ((number) * sizeof (type)) )
12 #define sresize(array, number, type) \
13 ( (void)sizeof((array)-(type *)0), \
14 (type *) realloc ((array), (number) * sizeof (type)) )
16 char *dupstr(const char *s
) {
17 char *r
= malloc(1+strlen(s
));
24 WIN32_FIND_DATA fdata
;
30 int open_dir(char *path
, dirhandle
*dh
)
33 dh
->hdl
= FindFirstFile(path
, &dh
->fdata
);
34 if (dh
->hdl
== INVALID_HANDLE_VALUE
) {
35 int err
= GetLastError();
36 if (err
== ERROR_FILE_NOT_FOUND
) {
50 const char *read_dir(dirhandle
*dh
)
56 if (FindNextFile(dh
->hdl
, &dh
->fdata
)) {
65 return dh
->fdata
.cFileName
;
68 void close_dir(dirhandle
*dh
)
73 static int str_cmp(const void *av
, const void *bv
)
75 return strcmp(*(const char **)av
, *(const char **)bv
);
78 typedef int (*gotdata_fn_t
)(void *ctx
, const char *pathname
,
79 WIN32_FIND_DATA
*dat
);
81 static void du_recurse(char **path
, size_t pathlen
, size_t *pathsize
,
82 gotdata_fn_t gotdata
, void *gotdata_ctx
)
88 size_t i
, nnames
, namesize
;
92 if (*pathsize
<= pathlen
+ 10) {
93 *pathsize
= pathlen
* 3 / 2 + 256;
94 *path
= sresize(*path
, *pathsize
, char);
97 h
= FindFirstFile(*path
, &dat
);
98 if (h
!= INVALID_HANDLE_VALUE
) {
100 } else if (pathlen
> 0 && (*path
)[pathlen
-1] == '\\') {
101 dat
.nFileSizeHigh
= dat
.nFileSizeLow
= 0;
102 dat
.ftLastWriteTime
.dwHighDateTime
= 0x19DB1DE;
103 dat
.ftLastWriteTime
.dwLowDateTime
= 0xD53E8000;
104 dat
.ftLastAccessTime
.dwHighDateTime
= 0x19DB1DE;
105 dat
.ftLastAccessTime
.dwLowDateTime
= 0xD53E8000;
106 h
= CreateFile(*path
, GENERIC_READ
, FILE_SHARE_WRITE
, NULL
,
107 OPEN_EXISTING
, 0, NULL
);
108 if (h
!= INVALID_HANDLE_VALUE
) {
109 GetFileTime(h
, &dat
.ftCreationTime
, &dat
.ftLastAccessTime
,
110 &dat
.ftLastWriteTime
);
115 if (!gotdata(gotdata_ctx
, *path
, &dat
))
118 if (!(GetFileAttributes(*path
) & FILE_ATTRIBUTE_DIRECTORY
))
122 nnames
= namesize
= 0;
124 if ((error
= open_dir(*path
, &d
)) < 0) {
126 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, -error
, 0,
127 buf
, lenof(buf
), NULL
);
128 buf
[lenof(buf
)-1] = '\0';
129 if (buf
[strlen(buf
)-1] == '\n')
130 buf
[strlen(buf
)-1] = '\0';
131 fprintf(stderr
, "Unable to open directory '%s': %s\n", *path
, buf
);
134 while ((name
= read_dir(&d
)) != NULL
) {
135 if (name
[0] == '.' && (!name
[1] || (name
[1] == '.' && !name
[2]))) {
136 /* do nothing - we skip "." and ".." */
138 if (nnames
>= namesize
) {
139 namesize
= nnames
* 3 / 2 + 64;
140 names
= sresize(names
, namesize
, char *);
142 names
[nnames
++] = dupstr(name
);
150 qsort(names
, nnames
, sizeof(*names
), str_cmp
);
152 for (i
= 0; i
< nnames
; i
++) {
153 size_t newpathlen
= pathlen
+ 1 + strlen(names
[i
]);
154 if (*pathsize
<= newpathlen
) {
155 *pathsize
= newpathlen
* 3 / 2 + 256;
156 *path
= sresize(*path
, *pathsize
, char);
159 * Avoid duplicating a slash if we got a trailing one to
160 * begin with (i.e. if we're starting the scan in '\\' itself).
162 if (pathlen
> 0 && (*path
)[pathlen
-1] == '\\') {
163 strcpy(*path
+ pathlen
, names
[i
]);
166 sprintf(*path
+ pathlen
, "\\%s", names
[i
]);
169 du_recurse(path
, newpathlen
, pathsize
, gotdata
, gotdata_ctx
);
176 void du(const char *inpath
, gotdata_fn_t gotdata
, void *gotdata_ctx
)
179 size_t pathlen
, pathsize
;
181 pathlen
= strlen(inpath
);
182 pathsize
= pathlen
+ 256;
183 path
= snewn(pathsize
, char);
184 strcpy(path
, inpath
);
186 du_recurse(&path
, pathlen
, &pathsize
, gotdata
, gotdata_ctx
);
189 int gd(void *ctx
, const char *pathname
, WIN32_FIND_DATA
*dat
)
191 unsigned long long size
, t
;
195 size
= dat
->nFileSizeHigh
;
196 size
= (size
<< 32) | dat
->nFileSizeLow
;
197 printf("%llu ", size
);
199 if (dat
->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
200 ft
= dat
->ftLastWriteTime
;
202 ft
= dat
->ftLastAccessTime
;
203 t
= ft
.dwHighDateTime
;
204 t
= (t
<< 32) | ft
.dwLowDateTime
;
207 * Correction factor: number of seconds between Windows's file
208 * time epoch of 1 Jan 1601 and Unix's time_t epoch of 1 Jan 1970.
210 * That's 369 years, of which 92 were divisible by 4, but
211 * three of those were century points.
213 t
-= (369 * 365 + 92 - 3) * 86400;
216 for (p
= pathname
; *p
; p
++) {
217 if (*p
>= ' ' && *p
< 127 && *p
!= '%')
220 printf("%%%02x", (unsigned char)*p
);
226 int main(int argc
, char **argv
)
232 SetCurrentDirectory(argv
[1]);
235 dir
= snewn(dirsize
, char);
236 while ((dirlen
= GetCurrentDirectory(dirsize
, dir
)) >= dirsize
) {
237 dirsize
= dirlen
+ 256;
238 dir
= sresize(dir
, dirsize
, char);
241 printf("agedu dump file. pathsep=5c\n");