#include #include #include #include #include #include #include #include #include void die(const char *fmtstr, ...) { va_list ap; fprintf(stderr, "CLEANER: "); va_start(ap, fmtstr); vfprintf(stderr, fmtstr, ap); va_end(ap); exit(EXIT_FAILURE); } int creation_time(const char *path) { struct stat attrib; stat(path, &attrib); return attrib.st_ctim.tv_sec; } char* aprintf(const char *fmtstr, ...) { va_list ap, cpy; size_t nb; char *str; va_copy(cpy, ap); va_start(cpy, fmtstr); nb = vsnprintf(NULL, 0, fmtstr, cpy); va_end(cpy); if (nb <= 0) die("Invalid fmtstr!\n"); str = malloc(nb+1); if (!str) die("Alloc of fmtstr failed\n"); va_start(ap, fmtstr); nb = vsnprintf(str, nb+1, fmtstr, ap); va_end(ap); return str; } void recdel(const char *path) { struct stat attrib; struct dirent *de; char *subpath; DIR *d; stat(path, &attrib); if (S_ISDIR(attrib.st_mode)) { d = opendir(path); while ((de = readdir(d))) { if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; subpath = aprintf("%s/%s", path, de->d_name); recdel(subpath); free(subpath); } closedir(d); rmdir(path); } else { remove(path); } } int main(int argc, const char **argv) { char buf[256], *end, *path, **paths, *oldpath, *newpath; unsigned long reftime; int i, pathc, pathcap, nread; const char *dirpath; FILE *f, *fn; if (argc != 3) die("USAGE: cleaner DIR REFTIME\n"); dirpath = argv[1]; reftime = strtoul(argv[2], &end, 10); if (end && *end) die("Invalid unix time reference\n"); oldpath = aprintf("%s/.index", dirpath); if (!(f = fopen(oldpath, "r+"))) die("Missing index file: %s\n", oldpath); flock(fileno(f), LOCK_EX); fflush(f); newpath = aprintf("%s/.index.next", dirpath); if (!(fn = fopen(newpath, "w+"))) die("Failed to create index file: %s\n", newpath); pathc = 0; pathcap = 1024; paths = malloc(pathcap * sizeof(char*)); if (!paths) die("OOM - allocating initial path array\n"); while (fgets(buf, sizeof(buf), f)) { if (*buf && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; path = aprintf("%s/%s", dirpath, buf); if (creation_time(path) < reftime) { paths[pathc] = strdup(path); if (!paths[pathc++]) die("OOM - during path str alloc\n"); if (pathc == pathcap) { pathcap *= 2; paths = realloc(paths, pathcap * sizeof(char*)); if (!paths) die("OOM - too many paths to alloc\n"); } } else { fwrite(buf, 1, strlen(buf), fn); putc('\n', fn); } free(path); } fseek(f, 0, SEEK_SET); fseek(fn, 0, SEEK_SET); while ((nread = fread(buf, 1, sizeof(buf), fn)) > 0) fwrite(buf, 1, nread, f); ftruncate(fileno(f), ftell(f)); fflush(f); flock(fileno(f), LOCK_UN); fclose(f); fclose(fn); for (i = 0; i < pathc; i++) { recdel(paths[i]); printf("CLEANER: REMOVED %s\n", paths[i]); } }