--- /dev/null
+#include <windows.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#define lenof(x) (sizeof((x))/sizeof(*(x)))
+
+#define snew(type) \
+ ( (type *) malloc (sizeof (type)) )
+#define snewn(number, type) \
+ ( (type *) malloc ((number) * sizeof (type)) )
+#define sresize(array, number, type) \
+ ( (void)sizeof((array)-(type *)0), \
+ (type *) realloc ((array), (number) * sizeof (type)) )
+#define sfree free
+char *dupstr(const char *s) {
+ char *r = malloc(1+strlen(s));
+ strcpy(r,s);
+ return r;
+}
+
+typedef struct {
+ HANDLE hdl;
+ WIN32_FIND_DATA fdata;
+ int got_one, eod;
+} dirhandle;
+
+
+
+int open_dir(char *path, dirhandle *dh)
+{
+ strcat(path, "\\*");
+ dh->hdl = FindFirstFile(path, &dh->fdata);
+ if (dh->hdl == INVALID_HANDLE_VALUE) {
+ int err = GetLastError();
+ if (err == ERROR_FILE_NOT_FOUND) {
+ dh->eod = 1;
+ dh->got_one = 0;
+ return 0;
+ } else {
+ return -err;
+ }
+ } else {
+ dh->eod = 0;
+ dh->got_one = 1;
+ return 0;
+ }
+}
+
+const char *read_dir(dirhandle *dh)
+{
+ if (!dh->got_one) {
+ if (dh->eod)
+ return NULL;
+
+ if (FindNextFile(dh->hdl, &dh->fdata)) {
+ dh->got_one = 1;
+ } else {
+ dh->eod = 1;
+ return NULL;
+ }
+ }
+
+ dh->got_one = 0;
+ return dh->fdata.cFileName;
+}
+
+void close_dir(dirhandle *dh)
+{
+ CloseHandle(dh->hdl);
+}
+
+static int str_cmp(const void *av, const void *bv)
+{
+ return strcmp(*(const char **)av, *(const char **)bv);
+}
+
+typedef int (*gotdata_fn_t)(void *ctx, const char *pathname,
+ WIN32_FIND_DATA *dat);
+
+static void du_recurse(char **path, size_t pathlen, size_t *pathsize,
+ gotdata_fn_t gotdata, void *gotdata_ctx)
+{
+ const char *name;
+ dirhandle d;
+ char **names;
+ int error;
+ size_t i, nnames, namesize;
+ WIN32_FIND_DATA dat;
+ HANDLE h;
+
+ if (*pathsize <= pathlen + 10) {
+ *pathsize = pathlen * 3 / 2 + 256;
+ *path = sresize(*path, *pathsize, char);
+ }
+
+ h = FindFirstFile(*path, &dat);
+ if (h != INVALID_HANDLE_VALUE) {
+ CloseHandle(h);
+ } else if (pathlen > 0 && (*path)[pathlen-1] == '\\') {
+ dat.nFileSizeHigh = dat.nFileSizeLow = 0;
+ dat.ftLastWriteTime.dwHighDateTime = 0x19DB1DE;
+ dat.ftLastWriteTime.dwLowDateTime = 0xD53E8000;
+ dat.ftLastAccessTime.dwHighDateTime = 0x19DB1DE;
+ dat.ftLastAccessTime.dwLowDateTime = 0xD53E8000;
+ h = CreateFile(*path, GENERIC_READ, FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, 0, NULL);
+ if (h != INVALID_HANDLE_VALUE) {
+ GetFileTime(h, &dat.ftCreationTime, &dat.ftLastAccessTime,
+ &dat.ftLastWriteTime);
+ CloseHandle(h);
+ }
+ }
+
+ if (!gotdata(gotdata_ctx, *path, &dat))
+ return;
+
+ if (!(GetFileAttributes(*path) & FILE_ATTRIBUTE_DIRECTORY))
+ return;
+
+ names = NULL;
+ nnames = namesize = 0;
+
+ if ((error = open_dir(*path, &d)) < 0) {
+ char buf[4096];
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, -error, 0,
+ buf, lenof(buf), NULL);
+ buf[lenof(buf)-1] = '\0';
+ if (buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = '\0';
+ fprintf(stderr, "Unable to open directory '%s': %s\n", *path, buf);
+ return;
+ }
+ while ((name = read_dir(&d)) != NULL) {
+ if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2]))) {
+ /* do nothing - we skip "." and ".." */
+ } else {
+ if (nnames >= namesize) {
+ namesize = nnames * 3 / 2 + 64;
+ names = sresize(names, namesize, char *);
+ }
+ names[nnames++] = dupstr(name);
+ }
+ }
+ close_dir(&d);
+
+ if (nnames == 0)
+ return;
+
+ qsort(names, nnames, sizeof(*names), str_cmp);
+
+ for (i = 0; i < nnames; i++) {
+ size_t newpathlen = pathlen + 1 + strlen(names[i]);
+ if (*pathsize <= newpathlen) {
+ *pathsize = newpathlen * 3 / 2 + 256;
+ *path = sresize(*path, *pathsize, char);
+ }
+ /*
+ * Avoid duplicating a slash if we got a trailing one to
+ * begin with (i.e. if we're starting the scan in '\\' itself).
+ */
+ if (pathlen > 0 && (*path)[pathlen-1] == '\\') {
+ strcpy(*path + pathlen, names[i]);
+ newpathlen--;
+ } else {
+ sprintf(*path + pathlen, "\\%s", names[i]);
+ }
+
+ du_recurse(path, newpathlen, pathsize, gotdata, gotdata_ctx);
+
+ sfree(names[i]);
+ }
+ sfree(names);
+}
+
+void du(const char *inpath, gotdata_fn_t gotdata, void *gotdata_ctx)
+{
+ char *path;
+ size_t pathlen, pathsize;
+
+ pathlen = strlen(inpath);
+ pathsize = pathlen + 256;
+ path = snewn(pathsize, char);
+ strcpy(path, inpath);
+
+ du_recurse(&path, pathlen, &pathsize, gotdata, gotdata_ctx);
+}
+
+int gd(void *ctx, const char *pathname, WIN32_FIND_DATA *dat)
+{
+ unsigned long long size, t;
+ FILETIME ft;
+ const char *p;
+
+ size = dat->nFileSizeHigh;
+ size = (size << 32) | dat->nFileSizeLow;
+ printf("%llu ", size);
+
+ if (dat->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ ft = dat->ftLastWriteTime;
+ else
+ ft = dat->ftLastAccessTime;
+ t = ft.dwHighDateTime;
+ t = (t << 32) | ft.dwLowDateTime;
+ t /= 10000000;
+ /*
+ * Correction factor: number of seconds between Windows's file
+ * time epoch of 1 Jan 1601 and Unix's time_t epoch of 1 Jan 1970.
+ *
+ * That's 369 years, of which 92 were divisible by 4, but
+ * three of those were century points.
+ */
+ t -= (369 * 365 + 92 - 3) * 86400;
+ printf("%llu ", t);
+
+ for (p = pathname; *p; p++) {
+ if (*p >= ' ' && *p < 127 && *p != '%')
+ putchar(*p);
+ else
+ printf("%%%02x", (unsigned char)*p);
+ }
+ putchar('\n');
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ char *dir;
+ int dirlen, dirsize;
+
+ if (argc > 1)
+ SetCurrentDirectory(argv[1]);
+
+ dirsize = 512;
+ dir = snewn(dirsize, char);
+ while ((dirlen = GetCurrentDirectory(dirsize, dir)) >= dirsize) {
+ dirsize = dirlen + 256;
+ dir = sresize(dir, dirsize, char);
+ }
+
+ printf("agedu dump file. pathsep=5c\n");
+
+ du(dir, gd, NULL);
+}