diff --git a/lib/backup-files.c b/lib/backup-files.c index fe40a8a..c4ae56f 100644 --- a/lib/backup-files.c +++ b/lib/backup-files.c @@ -413,38 +413,58 @@ foreachdir_rec(const char *path, struct stat *st, DIR *dir; struct dirent *dp; int failed = 0; - char *p = malloc_nofail(PATH_MAX); + + struct path { + char *name; + struct path *next; + }; + struct path *paths = NULL, *last_path = NULL; if (access(path, R_OK|X_OK) || !(dir = opendir(path))) return walk(path, NULL); while ((dp = readdir(dir))) { + struct path *p; + size_t size; + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; - if (strlen(path) + 1 + strlen(dp->d_name) + 1 > PATH_MAX) { - fprintf(stderr, "%s/%s: name too long\n", path, - dp->d_name); - failed = -1; - goto out; - } - sprintf(p, "%s/%s", path, dp->d_name); - - if (lstat(p, st)) + + p = malloc_nofail(sizeof(*p)); + if (!last_path) + paths = p; + else + last_path->next = p; + p->next = NULL; + last_path = p; + + size = strlen(path) + 1 + strlen(dp->d_name) + 1; + p->name = malloc_nofail(size); + sprintf(p->name, "%s/%s", path, dp->d_name); + } + if (closedir(dir) != 0) + failed = -1; + + while (paths != NULL) { + struct path *next; + + if (lstat(paths->name, st)) continue; /* file has disappeared meanwhile */ if (S_ISDIR(st->st_mode)) { - failed = foreachdir_rec(p, st, walk); + failed = foreachdir_rec(paths->name, st, walk); if (failed) goto out; } else { - failed = walk(p, st); + failed = walk(paths->name, st); if (failed) goto out; } + next = paths->next; + free(paths->name); + free(paths); + paths = next; } - if (closedir(dir) != 0) - failed = -1; out: - free(p); return failed; }