diff options
author | Andreas Gruenbacher <agruen@suse.de> | 2009-06-15 16:20:41 +0200 |
---|---|---|
committer | Andreas Gruenbacher <agruen@suse.de> | 2009-06-15 21:29:19 +0200 |
commit | 2d14c314da040244ce65069d5723fa3a51db3e6e (patch) | |
tree | 6bfed4ce16508184c686cc5e2c7b434986056bf7 /lib | |
parent | c60ec97737f46fda9fa9cb96f874768f5ccfb57b (diff) | |
download | quilt-2d14c314da040244ce65069d5723fa3a51db3e6e.tar.gz |
Concurrent readdir() + unlink() compatibility fix
Diffstat (limited to 'lib')
-rw-r--r-- | lib/backup-files.c | 50 |
1 files changed, 35 insertions, 15 deletions
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; } |