From 2e6654103f93c61206cf60b65bc261ecd164e424 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 25 Aug 2009 17:42:07 +0000 Subject: [PATCH] Add a somewhat unpolished Windows utility to generate an agedu scan 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 | 8 +++ winscan.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 winscan.c diff --git a/Buildscr b/Buildscr index 0ed40e3..e885667 100644 --- 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 index 0000000..a612e89 --- /dev/null +++ b/winscan.c @@ -0,0 +1,244 @@ +#include + +#include +#include + +#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); +} -- 2.11.0