2e665410 |
1 | #include <windows.h> |
2 | |
3 | #include <stdio.h> |
4 | #include <string.h> |
5 | |
6 | #define lenof(x) (sizeof((x))/sizeof(*(x))) |
7 | |
8 | #define snew(type) \ |
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)) ) |
15 | #define sfree free |
16 | char *dupstr(const char *s) { |
17 | char *r = malloc(1+strlen(s)); |
18 | strcpy(r,s); |
19 | return r; |
20 | } |
21 | |
22 | typedef struct { |
23 | HANDLE hdl; |
24 | WIN32_FIND_DATA fdata; |
25 | int got_one, eod; |
26 | } dirhandle; |
27 | |
28 | |
29 | |
30 | int open_dir(char *path, dirhandle *dh) |
31 | { |
32 | strcat(path, "\\*"); |
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) { |
37 | dh->eod = 1; |
38 | dh->got_one = 0; |
39 | return 0; |
40 | } else { |
41 | return -err; |
42 | } |
43 | } else { |
44 | dh->eod = 0; |
45 | dh->got_one = 1; |
46 | return 0; |
47 | } |
48 | } |
49 | |
50 | const char *read_dir(dirhandle *dh) |
51 | { |
52 | if (!dh->got_one) { |
53 | if (dh->eod) |
54 | return NULL; |
55 | |
56 | if (FindNextFile(dh->hdl, &dh->fdata)) { |
57 | dh->got_one = 1; |
58 | } else { |
59 | dh->eod = 1; |
60 | return NULL; |
61 | } |
62 | } |
63 | |
64 | dh->got_one = 0; |
65 | return dh->fdata.cFileName; |
66 | } |
67 | |
68 | void close_dir(dirhandle *dh) |
69 | { |
70 | CloseHandle(dh->hdl); |
71 | } |
72 | |
73 | static int str_cmp(const void *av, const void *bv) |
74 | { |
75 | return strcmp(*(const char **)av, *(const char **)bv); |
76 | } |
77 | |
78 | typedef int (*gotdata_fn_t)(void *ctx, const char *pathname, |
79 | WIN32_FIND_DATA *dat); |
80 | |
81 | static void du_recurse(char **path, size_t pathlen, size_t *pathsize, |
82 | gotdata_fn_t gotdata, void *gotdata_ctx) |
83 | { |
84 | const char *name; |
85 | dirhandle d; |
86 | char **names; |
87 | int error; |
88 | size_t i, nnames, namesize; |
89 | WIN32_FIND_DATA dat; |
90 | HANDLE h; |
91 | |
92 | if (*pathsize <= pathlen + 10) { |
93 | *pathsize = pathlen * 3 / 2 + 256; |
94 | *path = sresize(*path, *pathsize, char); |
95 | } |
96 | |
97 | h = FindFirstFile(*path, &dat); |
98 | if (h != INVALID_HANDLE_VALUE) { |
99 | CloseHandle(h); |
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); |
111 | CloseHandle(h); |
112 | } |
113 | } |
114 | |
115 | if (!gotdata(gotdata_ctx, *path, &dat)) |
116 | return; |
117 | |
118 | if (!(GetFileAttributes(*path) & FILE_ATTRIBUTE_DIRECTORY)) |
119 | return; |
120 | |
121 | names = NULL; |
122 | nnames = namesize = 0; |
123 | |
124 | if ((error = open_dir(*path, &d)) < 0) { |
125 | char buf[4096]; |
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); |
132 | return; |
133 | } |
134 | while ((name = read_dir(&d)) != NULL) { |
135 | if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2]))) { |
136 | /* do nothing - we skip "." and ".." */ |
137 | } else { |
138 | if (nnames >= namesize) { |
139 | namesize = nnames * 3 / 2 + 64; |
140 | names = sresize(names, namesize, char *); |
141 | } |
142 | names[nnames++] = dupstr(name); |
143 | } |
144 | } |
145 | close_dir(&d); |
146 | |
147 | if (nnames == 0) |
148 | return; |
149 | |
150 | qsort(names, nnames, sizeof(*names), str_cmp); |
151 | |
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); |
157 | } |
158 | /* |
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). |
161 | */ |
162 | if (pathlen > 0 && (*path)[pathlen-1] == '\\') { |
163 | strcpy(*path + pathlen, names[i]); |
164 | newpathlen--; |
165 | } else { |
166 | sprintf(*path + pathlen, "\\%s", names[i]); |
167 | } |
168 | |
169 | du_recurse(path, newpathlen, pathsize, gotdata, gotdata_ctx); |
170 | |
171 | sfree(names[i]); |
172 | } |
173 | sfree(names); |
174 | } |
175 | |
176 | void du(const char *inpath, gotdata_fn_t gotdata, void *gotdata_ctx) |
177 | { |
178 | char *path; |
179 | size_t pathlen, pathsize; |
180 | |
181 | pathlen = strlen(inpath); |
182 | pathsize = pathlen + 256; |
183 | path = snewn(pathsize, char); |
184 | strcpy(path, inpath); |
185 | |
186 | du_recurse(&path, pathlen, &pathsize, gotdata, gotdata_ctx); |
187 | } |
188 | |
189 | int gd(void *ctx, const char *pathname, WIN32_FIND_DATA *dat) |
190 | { |
191 | unsigned long long size, t; |
192 | FILETIME ft; |
193 | const char *p; |
194 | |
195 | size = dat->nFileSizeHigh; |
196 | size = (size << 32) | dat->nFileSizeLow; |
197 | printf("%llu ", size); |
198 | |
199 | if (dat->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
200 | ft = dat->ftLastWriteTime; |
201 | else |
202 | ft = dat->ftLastAccessTime; |
203 | t = ft.dwHighDateTime; |
204 | t = (t << 32) | ft.dwLowDateTime; |
205 | t /= 10000000; |
206 | /* |
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. |
209 | * |
210 | * That's 369 years, of which 92 were divisible by 4, but |
211 | * three of those were century points. |
212 | */ |
213 | t -= (369 * 365 + 92 - 3) * 86400; |
214 | printf("%llu ", t); |
215 | |
216 | for (p = pathname; *p; p++) { |
217 | if (*p >= ' ' && *p < 127 && *p != '%') |
218 | putchar(*p); |
219 | else |
220 | printf("%%%02x", (unsigned char)*p); |
221 | } |
222 | putchar('\n'); |
223 | return 1; |
224 | } |
225 | |
226 | int main(int argc, char **argv) |
227 | { |
228 | char *dir; |
229 | int dirlen, dirsize; |
230 | |
231 | if (argc > 1) |
232 | SetCurrentDirectory(argv[1]); |
233 | |
234 | dirsize = 512; |
235 | dir = snewn(dirsize, char); |
236 | while ((dirlen = GetCurrentDirectory(dirsize, dir)) >= dirsize) { |
237 | dirsize = dirlen + 256; |
238 | dir = sresize(dir, dirsize, char); |
239 | } |
240 | |
241 | printf("agedu dump file. pathsep=5c\n"); |
242 | |
243 | du(dir, gd, NULL); |
244 | } |