Add a somewhat unpolished Windows utility to generate an agedu scan
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 25 Aug 2009 17:42:07 +0000 (17:42 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 25 Aug 2009 17:42:07 +0000 (17:42 +0000)
dump on Windows. The rest of agedu only runs on Unix, but this way
you can at least do a scan of a Windows machine and then load the
resulting log file index into an agedu running elsewhere.

git-svn-id: svn://svn.tartarus.org/sgt/agedu@8629 cda61777-01e9-0310-a592-d414129be87e

Buildscr
winscan.c [new file with mode: 0644]

index 0ed40e3..e885667 100644 (file)
--- a/Buildscr
+++ b/Buildscr
@@ -23,3 +23,11 @@ in agedu do halibut --html=manpage.html agedu.but
 
 deliver agedu-r$(revision).tar.gz $@
 deliver agedu/manpage.html $@
+
+delegate windows
+  # FIXME: Cygwin alternative?
+  in agedu do cmd /c vcvars32 \& cl winscan.c
+  return agedu/winscan.exe
+enddelegate
+
+deliver agedu/winscan.exe $@
diff --git a/winscan.c b/winscan.c
new file mode 100644 (file)
index 0000000..a612e89
--- /dev/null
+++ b/winscan.c
@@ -0,0 +1,244 @@
+#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);
+}