summaryrefslogtreecommitdiffstats
path: root/lib/backup-files.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2006-01-26 03:40:50 +0000
committerAndreas Gruenbacher <agruen@suse.de>2006-01-26 03:40:50 +0000
commitf96155d58b601c1cc17a97566f9123af0fdeef24 (patch)
tree45467b92489ff3e3b80dbd76ac05cb942cdf396c /lib/backup-files.c
parentaff07add99f56ae67ac58cb334881d3197d97a21 (diff)
downloadquilt-f96155d58b601c1cc17a97566f9123af0fdeef24.tar.gz
- lib/backup-files.c: Stop using ftw and implement our own dir
walking: ftw is a portability nightmare. The foreachdir function is based a proposal from Gary V. Vaughan <gary@gnu.org>, thanks!
Diffstat (limited to 'lib/backup-files.c')
-rw-r--r--lib/backup-files.c85
1 files changed, 68 insertions, 17 deletions
diff --git a/lib/backup-files.c b/lib/backup-files.c
index 79f3e55..f28e89c 100644
--- a/lib/backup-files.c
+++ b/lib/backup-files.c
@@ -1,8 +1,8 @@
/*
File: backup-files.c
- Copyright (C) 2003 Andreas Gruenbacher <agruen@suse.de>
- SuSE Labs, SuSE Linux AG
+ Copyright (C) 2003, 2004, 2005, 2006
+ Andreas Gruenbacher <agruen@suse.de>, SuSE Labs
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -40,7 +40,7 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
-#include <ftw.h>
+#include <dirent.h>
#if !defined(HAVE_MKSTEMP) && defined(HAVE_MKTEMP)
# define mkstemp(x) creat(mktemp(x), 0600)
@@ -57,7 +57,7 @@ int opt_nolinks, opt_touch;
#define LINE_LENGTH 1024
-void
+static void
usage(void)
{
printf("Usage: %s [-B prefix] [-z suffix] [-f {file|-}] [-s] [-b|-r|-x] [-L] {file|-} ...\n"
@@ -84,13 +84,13 @@ malloc_nofail(size_t size)
{
void *p = malloc(size);
if (!p) {
- fprintf(stderr, "%s\n", strerror(ENOMEM));
+ perror(NULL);
exit(1);
}
return p;
}
-void
+static void
create_parents(const char *filename)
{
struct stat st;
@@ -120,7 +120,7 @@ out:
free(fn);
}
-void
+static void
remove_parents(const char *filename)
{
char *fn = malloc_nofail(strlen(filename) + 1), *f;
@@ -273,7 +273,7 @@ ensure_nolinks(const char *filename)
return 0;
}
-int
+static int
process_file(const char *file)
{
char *backup = malloc_nofail(
@@ -375,19 +375,72 @@ fail:
return 1;
}
-int
-walk(const char *path, const struct stat *stat, int flag)
+static int
+foreachdir_rec(const char *path, struct stat *st,
+ int (*walk)(const char *, const struct stat *))
+{
+ DIR *dir;
+ struct dirent *dp;
+ char *p = NULL;
+ int failed = 0;
+
+ if (!(dir = opendir(path)))
+ return walk(path, NULL);
+ while ((dp = readdir(dir))) {
+ char *p0 = p;
+
+ if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+ continue;
+ if (!(p = realloc(p, strlen(path) + 1 +
+ strlen(dp->d_name) + 1))) {
+ free(p0);
+ return -1;
+ }
+ sprintf(p, "%s/%s", path, dp->d_name);
+ if (lstat(p, st))
+ continue; /* file has disappeared meanwhile */
+ if (S_ISDIR(st->st_mode)) {
+ failed = foreachdir_rec(p, st, walk);
+ if (failed)
+ goto out;
+ } else {
+ failed = walk(p, st);
+ if (failed)
+ goto out;
+ }
+ }
+ if (closedir(dir) != 0)
+ failed = -1;
+
+out:
+ free(p);
+ return failed;
+}
+
+static int
+foreachdir(const char *path,
+ int (*walk)(const char *, const struct stat *))
+{
+ struct stat st;
+
+ if (lstat(path, &st))
+ return walk(path, NULL);
+ return foreachdir_rec(path, &st, walk);
+}
+
+static int
+walk(const char *path, const struct stat *st)
{
size_t prefix_len=strlen(opt_prefix), suffix_len=strlen(opt_suffix);
size_t len = strlen(path);
char *p;
int ret;
- if (flag == FTW_DNR) {
+ if (!st) {
perror(path);
return 1;
}
- if (!S_ISREG(stat->st_mode))
+ if (!S_ISREG(st->st_mode))
return 0;
if (strncmp(opt_prefix, path, prefix_len))
return 0; /* prefix does not match */
@@ -493,14 +546,12 @@ main(int argc, char *argv[])
if (strcmp(argv[optind], "-") == 0) {
char *dir = strdup(opt_prefix), *d = strrchr(dir, '/');
if (d)
- *(d+1) = '\0';
+ *d = '\0';
else
d = ".";
- status = ftw(dir, walk, 0);
- /* An error here indicates a problem somewhere
- * during the walk */
+ status = foreachdir(dir, walk);
if (status == -1)
- perror("ftw");
+ perror(dir);
free(dir);
} else