summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2003-08-29 01:21:11 +0000
committerLennart Poettering <lennart@poettering.net>2003-08-29 01:21:11 +0000
commitdb3b96fc0014a5e860df1efc729b38d629662826 (patch)
tree9076f5b7c6a14c6239b562d442cdf46d755c9ff0
parent0d7460e9592c501b48fe9ab05d8e7fd52cb5bb4d (diff)
many fixes
--cleanup implemented git-svn-id: file:///home/lennart/svn/public/syrep/trunk@13 07ea20a6-d2c5-0310-9e02-9ef735347d72
-rw-r--r--doc/todo.txt25
-rw-r--r--src/Makefile5
-rw-r--r--src/cache.c1
-rw-r--r--src/cleanup.c92
-rw-r--r--src/cleanup.h26
-rw-r--r--src/context.c26
-rw-r--r--src/context.h4
-rw-r--r--src/diff.c12
-rw-r--r--src/diff.h7
-rw-r--r--src/md5util.c10
-rw-r--r--src/merge.c131
-rw-r--r--src/merge.h1
-rw-r--r--src/package.c95
-rw-r--r--src/package.h2
-rw-r--r--src/syrep.c104
-rw-r--r--src/syrep.ggo5
-rw-r--r--src/syrep.h2
-rw-r--r--src/update.c26
-rw-r--r--src/util.c153
-rw-r--r--src/util.h16
-rw-r--r--test/Makefile2
21 files changed, 590 insertions, 155 deletions
diff --git a/doc/todo.txt b/doc/todo.txt
index 622ea0b..78e828e 100644
--- a/doc/todo.txt
+++ b/doc/todo.txt
@@ -1,20 +1,29 @@
+pre-0.1:
- merge/makepatch DONE
- Mode -T DONE
- Recursive directory creation DONE
- Prune empty directories DONE
-- Handle conflicts
+- Handle conflicts DONE
- stat() before and after md5 as consistency check DONE
+- -q mode DONE
+- check of non-static symbols DONE
+- warn if hostname != origin DONE
+- signal handling DONE
+- add --cleanup DONE
+- package.c rewrite: add progressive, mmap, sendfile, gzip support, atomicity
- better usage info on --help
- documentation/man pages
-- package.c rewrite: add progressive, mmap, sendfile, gzip support, atomicity
-- -q mode
-- url merges
+- autoconf
+- testing
+
+post-0.1:
+- continue merge on copy failure
+- url/ssh merges
- bi-directory merges
-- md5 before delete/replace/link
-- Warn if hostname != origin
+- digest check before delete/replace/link
- some more asserts
-- check of non-static symbols
- PATH_MAX or PATH_MAX+1?
-- explicit link or copy
+- add --always-copy
+- add --forget
$Id$
diff --git a/src/Makefile b/src/Makefile
index a7e55ec..2032e76 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,10 +1,9 @@
-CFLAGS=-Wall -pipe -O0 -g
+CFLAGS=-Wall -pipe -O0 -g -DARCH_IS_BIG_ENDIAN=0
CC=gcc
-
all: syrep
-syrep: cache.o update.o util.o syrep.o md5.o md5util.o context.o package.o dbutil.o cmdline.o info.o history.o dump.o list.o diff.o merge.o extract.o makepatch.o
+syrep: cache.o update.o util.o syrep.o md5.o md5util.o context.o package.o dbutil.o cmdline.o info.o history.o dump.o list.o diff.o merge.o extract.o makepatch.o cleanup.o
$(CC) -g $^ -o $@ -ldb
cmdline.c cmdline.h: syrep.ggo Makefile
diff --git a/src/cache.c b/src/cache.c
index 2e893f2..925cd69 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -183,7 +183,6 @@ int md_cache_get(struct syrep_md_cache *c, const char *path, uint8_t digest[16])
if ((j = get(c, &k, digest)) < 0)
goto finish;
-
if (!j)
if (fdmd5(fd, st.st_size, digest) < 0)
goto finish;
diff --git a/src/cleanup.c b/src/cleanup.c
new file mode 100644
index 0000000..6f096f9
--- /dev/null
+++ b/src/cleanup.c
@@ -0,0 +1,92 @@
+/* $Id$ */
+
+/***
+ This file is part of syrep.
+
+ syrep is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ syrep is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with syrep; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+***/
+
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "syrep.h"
+#include "util.h"
+
+int cleanup(const char *root) {
+ char p[PATH_MAX];
+
+ if (args.cleanup_level_arg >= 1) {
+
+ if (args.verbose_flag)
+ fprintf(stderr, "Emptying trash ...\n");
+
+ snprintf(p, sizeof(p), "%s/.syrep/" SYREP_TRASHDIR, root);
+
+ if (rm_rf(p, 0) < 0)
+ return -1;
+
+ if (args.verbose_flag)
+ fprintf(stderr, "Removing temporary directories ...\n");
+
+ snprintf(p, sizeof(p), "%s/.syrep/" SYREP_TEMPDIR, root);
+
+ if (rm_rf(p, 1) < 0)
+ return -1;
+ }
+
+ if (args.cleanup_level_arg >= 2) {
+
+ if (args.verbose_flag)
+ fprintf(stderr, "Removing digest cache ...\n");
+
+ snprintf(p, sizeof(p), "%s/.syrep/" SYREP_MDCACHEFILENAME, root);
+
+ if (unlink(p) < 0) {
+ if (errno != ENOENT) {
+ fprintf(stderr, "unlink(\"%s\"): %s\n", p, strerror(errno));
+ return -1;
+ }
+ }
+ }
+
+ if (args.cleanup_level_arg >= 3) {
+
+ if (args.verbose_flag)
+ fprintf(stderr, "Removing status data ...\n");
+
+ snprintf(p, sizeof(p), "%s/.syrep/" SYREP_SNAPSHOTFILENAME, root);
+
+ if (unlink(p) < 0) {
+ if (errno != ENOENT) {
+ fprintf(stderr, "unlink(\"%s\"): %s\n", p, strerror(errno));
+ return -1;
+ }
+ }
+
+ snprintf(p, sizeof(p), "%s/.syrep", root);
+
+ if (rmdir(p) < 0) {
+ if (errno != ENOENT) {
+ fprintf(stderr, "rmdir(\"%s\"): %s\n", p, strerror(errno));
+ return -1;
+ }
+ }
+ }
+
+
+ return 0;
+}
diff --git a/src/cleanup.h b/src/cleanup.h
new file mode 100644
index 0000000..51fd15b
--- /dev/null
+++ b/src/cleanup.h
@@ -0,0 +1,26 @@
+#ifndef foocleanuphfoo
+#define foocleanuphfoo
+
+/* $Id$ */
+
+/***
+ This file is part of syrep.
+
+ syrep is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ syrep is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with syrep; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+***/
+
+int cleanup(const char *root);
+
+#endif
diff --git a/src/context.c b/src/context.c
index f64040a..7052bad 100644
--- a/src/context.c
+++ b/src/context.c
@@ -29,6 +29,7 @@
#include "context.h"
#include "package.h"
+#include "util.h"
int db_context_free(struct syrep_db_context* c) {
if (c) {
@@ -87,7 +88,7 @@ static DB* open_db(const char*path, int dup) {
return db;
}
-struct syrep_db_context* db_context_open(const char *filename) {
+struct syrep_db_context* db_context_open(const char *filename, int force) {
struct syrep_db_context *c = NULL;
const char* path;
FILE *f;
@@ -97,7 +98,7 @@ struct syrep_db_context* db_context_open(const char *filename) {
memset(c, 0, sizeof(struct syrep_db_context));
- if (!(c->package = package_open(filename)))
+ if (!(c->package = package_open(filename, force)))
goto fail;
path = package_get_item(c->package, "timestamp", 1);
@@ -217,3 +218,24 @@ int db_context_save(struct syrep_db_context *c, const char *filename) {
return package_save(c->package, filename);
}
+
+int db_context_origin_warn(struct syrep_db_context *c) {
+ char hn[256];
+
+ assert(c);
+
+ if (gethostname(hn, sizeof(hn)) < 0)
+ return -1;
+
+ if (strcmp(hn, c->origin)) {
+ int q;
+
+ if (!(q = question("WARNING: Snapshot is not from local host! Continue?", "ny")))
+ return -1;
+
+ if (q != 'y')
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/context.h b/src/context.h
index e4617c9..96f4dcf 100644
--- a/src/context.h
+++ b/src/context.h
@@ -41,8 +41,10 @@ struct syrep_db_context {
char* origin;
};
-struct syrep_db_context* db_context_open(const char *path);
+struct syrep_db_context* db_context_open(const char *path, int force);
int db_context_save(struct syrep_db_context *c, const char *path);
int db_context_free(struct syrep_db_context* c);
+int db_context_origin_warn(struct syrep_db_context *c);
+
#endif
diff --git a/src/diff.c b/src/diff.c
index a9a20bd..54185b2 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -182,10 +182,13 @@ static int enumerate(DB *ddb, struct syrep_db_context *c1, struct syrep_db_conte
struct syrep_id *id = (struct syrep_id*) key.data;
struct syrep_meta *meta = (struct syrep_meta*) data.data;
-
-
assert(id && meta);
+ if (interrupted) {
+ fprintf(stderr, "Canceled.\n");
+ goto finish;
+ }
+
if (meta->last_seen != c1->version)
continue;
@@ -344,6 +347,11 @@ int diff_foreach(DB *ddb, int (*cb)(DB *ddb, struct syrep_name *name, struct dif
struct syrep_name *name = (struct syrep_name*) key.data;
struct diff_entry *de = (struct diff_entry*) data.data;
+ if (interrupted) {
+ fprintf(stderr, "Canceled.\n");
+ goto finish;
+ }
+
if ((t = cb(ddb, name, de, p)) < 0) {
r = t;
goto finish;
diff --git a/src/diff.h b/src/diff.h
index a746092..2c1c134 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -24,7 +24,12 @@
#include "context.h"
#include "dbstruct.h"
-enum { DIFF_COPY, DIFF_DELETE, DIFF_CONFLICT, DIFF_IGNORE };
+/*
+ * Please note that DIFF_REPLACE is never set by make_diff(). Instead
+ * it is used for conflict resolution in merge.c
+ */
+
+enum { DIFF_COPY, DIFF_DELETE, DIFF_CONFLICT, DIFF_REPLACE };
struct diff_entry {
int action;
diff --git a/src/md5util.c b/src/md5util.c
index e4c3269..6b9a1e2 100644
--- a/src/md5util.c
+++ b/src/md5util.c
@@ -28,6 +28,7 @@
#include "md5util.h"
#include "md5.h"
+#include "syrep.h"
void fhex(const unsigned char *bin,int len, char *txt) {
const static char hex[] = "0123456789abcdef";
@@ -46,7 +47,7 @@ int fdmd5(int fd, size_t l, char *md) {
void *d;
off_t o = 0;
size_t m;
- int r = 0;
+ int r = -1;
md5_state_t s;
struct stat pre, post;
void *p = NULL;
@@ -65,6 +66,11 @@ int fdmd5(int fd, size_t l, char *md) {
while (l && ((d = mmap(NULL, m, PROT_READ, MAP_SHARED, fd, o)) != MAP_FAILED)) {
md5_append(&s, d, m);
munmap(d, m);
+
+ if (interrupted) {
+ fprintf(stderr, "Canceled.\n");
+ goto finish;
+ }
o += m;
l -= m;
@@ -112,6 +118,8 @@ int fdmd5(int fd, size_t l, char *md) {
md5_finish(&s, md);
+ r = 0;
+
finish:
if (p)
diff --git a/src/merge.c b/src/merge.c
index c37cb53..b281b06 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -44,6 +44,7 @@ struct cb_info {
static int conflict_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) {
struct cb_info *cb_info = p;
struct syrep_md md1, md2;
+ int writeback = 0;
int f1, f2;
char path[PATH_MAX+1];
@@ -62,18 +63,73 @@ static int conflict_phase(DB *ddb, struct syrep_name *name, struct diff_entry *d
if (f1 && f2) {
char d1[SYREP_DIGESTLENGTH*2+1], d2[SYREP_DIGESTLENGTH*2+1];
+ int q;
fhex(md1.digest, SYREP_DIGESTLENGTH, d1);
fhex(md2.digest, SYREP_DIGESTLENGTH, d2);
d1[SYREP_DIGESTLENGTH*2] = d2[SYREP_DIGESTLENGTH*2] = 0;
- fprintf(stderr, "CONFLICT: New file '%s' apparead: %s in A vs. %s in B\n", path, d1, d2);
+ fprintf(stderr, "CONFLICT: New file '%s': %s in *local* vs. %s in *remote* repository.\n", path, d2, d1);
+
+ if (!(q = question("Replace in local repository?", "ny")))
+ return -1;
+
+ if (q == 'y') {
+ de->action = DIFF_REPLACE;
+ de->repository = cb_info->c1;
+ writeback = 1;
+ }
+
} else if (f1 || f2) {
char d[SYREP_DIGESTLENGTH*2+1];
+
fhex(f1 ? md1.digest : md2.digest, SYREP_DIGESTLENGTH, d);
d[SYREP_DIGESTLENGTH*2] = 0;
- fprintf(stderr, "CONFLICT: File '%s' (%s) appeared in %c, removed in %c\n", path, d, f1 ? 'A' : 'B', f2 ? 'A' : 'B');
+ fprintf(stderr, "CONFLICT: File '%s' (%s) appeared in *%s*, removed in *%s* repository.\n", path, d, f1 ? "remote" : "local", f2 ? "remote" : "local");
+
+ if (f1) {
+ int q;
+
+ if (!(q = question("Add to local repository?", "yn")))
+ return -1;
+
+ if (q == 'y') {
+ de->action = DIFF_COPY;
+ de->repository = cb_info->c1;
+ writeback = 1;
+ }
+ } else {
+ int q;
+
+ if (!(q = question("Remove from local repository?", "ny")))
+ return -1;
+
+ if (q == 'y') {
+ de->action = DIFF_DELETE;
+ de->repository = cb_info->c2;
+ writeback = 1;
+ }
+ }
+ }
+
+ if (writeback) {
+ DBT key, data;
+ int ret;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ key.data = (void*) name;
+ key.size = sizeof(struct syrep_name);
+
+ data.data = (void*) de;
+ data.size = sizeof(struct diff_entry);
+
+ if ((ret = ddb->put(ddb, NULL, &key, &data, 0))) {
+ ddb->err(ddb, ret, "ddb::put()");
+ return -1;
+ }
}
return 0;
@@ -112,7 +168,7 @@ static int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, v
assert(ddb && name && de && p);
- if (de->action != DIFF_COPY)
+ if (de->action != DIFF_COPY && de->action != DIFF_REPLACE)
return 0;
if (de->repository == cb_info->c2)
@@ -153,7 +209,7 @@ static int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, v
escape_path(name2.path, path2+l, sizeof(path2)-l);
if (!access(path2, R_OK)) {
- if (copy_or_link_file(path2, path, 0) < 0)
+ if (copy_or_link_file(path2, path, de->action == DIFF_REPLACE) < 0)
return -1;
}
@@ -169,7 +225,7 @@ static int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, v
if (makeprefixpath(path, 0777) < 0)
return -1;
- if (copy_or_link_file(a, path, 0) < 0)
+ if (copy_or_link_file(a, path, de->action == DIFF_REPLACE) < 0)
return -1;
} else
fprintf(stderr, "COPY: File <%s> is missing.\n", name->path);
@@ -191,6 +247,19 @@ static int delete_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de,
if (de->repository == cb_info->c1)
return 0;
+ if (args.question_flag) {
+ char text[256];
+ int q;
+
+ snprintf(text, sizeof(text), "Delete %s?", name->path);
+
+ if ((q = question(text, "yn")) < 0)
+ return -1;
+
+ if (q != 'y')
+ return 0;
+ }
+
snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path);
snprintf(target, sizeof(target), "%s/", cb_info->trash_dir);
@@ -209,47 +278,6 @@ static int delete_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de,
return 0;
}
-static int empty_trash(const char *trash) {
- DIR *dir = NULL;
- int r = -1;
- struct dirent *de;
-
- if (!(dir = opendir(trash))) {
- fprintf(stderr, "opendir(\"%s\"): %s", trash, strerror(errno));
- goto finish;
- }
-
- while ((de = readdir(dir))) {
- char path[PATH_MAX];
-
- if (!strcmp(de->d_name, "."))
- continue;
-
- if (!strcmp(de->d_name, ".."))
- continue;
-
- snprintf(path, sizeof(path), "%s/%s", trash, de->d_name);
-
- if (unlink(path) < 0) {
- fprintf(stderr, "unlink(\"%s\"): %s\n", path, strerror(errno));
- goto finish;
- }
- }
-
- if (rmdir(trash) < 0) {
- fprintf(stderr, "rmdir(\"%s\"): %s\n", trash, strerror(errno));
- goto finish;
- }
-
- r = 0;
-
-finish:
- if (dir)
- closedir(dir);
-
- return r;
-}
-
/* Merges c1 into c2 in directory "root" */
int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* root) {
struct cb_info cb_info;
@@ -260,9 +288,9 @@ int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char*
cb_info.c1 = c1;
cb_info.c2 = c2;
cb_info.root = root;
-
- snprintf(cb_info.trash_dir, sizeof(cb_info.trash_dir), "%s/.syrep-trash", root);
- mkdir(cb_info.trash_dir, 0777);
+
+ snprintf(cb_info.trash_dir, sizeof(cb_info.trash_dir), "%s/.syrep/trash", root);
+ mkdir_p(cb_info.trash_dir, 0777);
if (!(ddb = make_diff(c1, c2)))
goto finish;
@@ -276,8 +304,9 @@ int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char*
if (diff_foreach(ddb, copy_phase, &cb_info) < 0)
goto finish;
- if (empty_trash(cb_info.trash_dir) < 0)
- goto finish;
+ if (!args.keep_trash_flag)
+ if (rm_rf(cb_info.trash_dir, 0) < 0)
+ goto finish;
r = 0;
diff --git a/src/merge.h b/src/merge.h
index 4e5b766..02c1a9e 100644
--- a/src/merge.h
+++ b/src/merge.h
@@ -24,5 +24,6 @@
#include "context.h"
int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* root);
+int empty_trash(const char *trash);
#endif
diff --git a/src/package.c b/src/package.c
index 464918c..2c396be 100644
--- a/src/package.c
+++ b/src/package.c
@@ -118,7 +118,7 @@ fail:
return NULL;
}
-struct package* package_open(const char *fn) {
+struct package* package_open(const char *fn, int force) {
struct package *p;
FILE *f = NULL;
char path[PATH_MAX];
@@ -143,56 +143,63 @@ struct package* package_open(const char *fn) {
if (fn) {
if (!(f = fopen(fn, "r"))) {
- fprintf(stderr, "Failed to open <%s>: %s\n", fn, strerror(errno));
- goto finish;
- }
-
- for (;;) {
- uint32_t len;
- char name[PACKAGE_ITEM_NAME_LEN+1];
- FILE *d = NULL;
- struct package_item *pi;
-
- if (!fread(name, sizeof(name)-1, 1, f))
- break;
- name[sizeof(name)-1] = 0;
-
- if (fread(&len, sizeof(len), 1, f) != 1) {
- fprintf(stderr, "Short read while reading length: %s\n", strerror(errno));
+ if (errno != ENOENT || !force) {
+ fprintf(stderr, "Failed to open <%s>: %s\n", fn, strerror(errno));
goto finish;
}
+ }
- snprintf(path, sizeof(path), "%s/%i", p->base, p->count++);
- if (!(d = fopen(path, "w+"))) {
- fprintf(stderr, "Failed to open target file: %s\n", strerror(errno));
- goto finish;
- }
+ if (f) {
+
+ for (;;) {
+ uint32_t len;
+ char name[PACKAGE_ITEM_NAME_LEN+1];
+ FILE *d = NULL;
+ struct package_item *pi;
+
+ if (!fread(name, sizeof(name)-1, 1, f))
+ break;
+
+ name[sizeof(name)-1] = 0;
+
+ if (fread(&len, sizeof(len), 1, f) != 1) {
+ fprintf(stderr, "Short read while reading length: %s\n", strerror(errno));
+ goto finish;
+ }
+
+ snprintf(path, sizeof(path), "%s/%i", p->base, p->count++);
+ if (!(d = fopen(path, "w+"))) {
+ fprintf(stderr, "Failed to open target file: %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (copy(f, d, len) < 0) {
+ fprintf(stderr, "Copy failed: %s\n", strerror(errno));
+ fclose(d);
+ unlink(path);
+ goto finish;
+ }
- if (copy(f, d, len) < 0) {
- fprintf(stderr, "Copy failed: %s\n", strerror(errno));
fclose(d);
- unlink(path);
- goto finish;
- }
+ if (!(pi = item_new(name, path, 1))) {
+ unlink(path);
+ fprintf(stderr, "Failed to allocate memory.\n");
+ goto finish;
+ }
- fclose(d);
- if (!(pi = item_new(name, path, 1))) {
- unlink(path);
- fprintf(stderr, "Failed to allocate memory.\n");
- goto finish;
+ assert(!!p->last == !!p->items);
+
+ if (p->last) {
+ p->last->next = pi;
+ p->last = pi;
+ } else
+ p->items = p->last = pi;
}
- assert(!!p->last == !!p->items);
-
- if (p->last) {
- p->last->next = pi;
- p->last = pi;
- } else
- p->items = p->last = pi;
- }
- fclose(f);
+ fclose(f);
+ }
}
return p;
@@ -339,8 +346,10 @@ void package_remove(struct package *p) {
}
if (p->base) {
- if (rmdir(p->base))
- fprintf(stderr, "Failed to remove <%s>: %s\n", p->base, strerror(errno));
+ if (rmdir(p->base)) {
+ if (errno != ENOENT)
+ fprintf(stderr, "Failed to remove <%s>: %s\n", p->base, strerror(errno));
+ }
free(p->base);
}
diff --git a/src/package.h b/src/package.h
index 57b2daf..9a7bfd2 100644
--- a/src/package.h
+++ b/src/package.h
@@ -25,7 +25,7 @@
struct package;
-struct package* package_open(const char *fn);
+struct package* package_open(const char *fn, int force);
void package_remove(struct package *p);
int package_save(struct package *p, const char *fn);
const char *package_get_item(struct package* p, const char *name, int c);
diff --git a/src/syrep.c b/src/syrep.c
index fadb7e5..f95f086 100644
--- a/src/syrep.c
+++ b/src/syrep.c
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
+#include <signal.h>
#include "md5util.h"
#include "md5.h"
@@ -48,6 +49,9 @@
#include "dump.h"
#include "extract.h"
#include "makepatch.h"
+#include "cleanup.h"
+
+volatile int interrupted = 0;
struct gengetopt_args_info args;
@@ -63,15 +67,15 @@ static int do_diff(void) {
}
if (args.local_temp_flag && isdirectory(args.inputs[0]) >= 1) {
- const char *p = get_attached_filename(args.inputs[0], SYREP_TEMPDIR);
+ const char *p = get_snapshot_filename(args.inputs[0], SYREP_TEMPDIR);
mkdir(p, 0777);
setenv("TMPDIR", p, 1);
}
- if (!(path1 = strdup(get_attached_filename(args.inputs[0], SYREP_SNAPSHOTFILENAME))))
+ if (!(path1 = strdup(get_snapshot_filename(args.inputs[0], SYREP_SNAPSHOTFILENAME))))
goto finish;
- if (!(path2 = strdup(get_attached_filename(args.inputs[1], SYREP_SNAPSHOTFILENAME))))
+ if (!(path2 = strdup(get_snapshot_filename(args.inputs[1], SYREP_SNAPSHOTFILENAME))))
goto finish;
if (!strcmp(path1, path2)) {
@@ -79,10 +83,10 @@ static int do_diff(void) {
goto finish;
}
- if (!(c1 = db_context_open(path1)))
+ if (!(c1 = db_context_open(path1, 0)))
goto finish;
- if (!(c2 = db_context_open(path2)))
+ if (!(c2 = db_context_open(path2, 0)))
goto finish;
if (!(ddb = make_diff(c1, c2)))
@@ -128,15 +132,15 @@ static int do_merge(void) {
}
if (args.local_temp_flag) {
- const char *p = get_attached_filename(args.inputs[1], SYREP_TEMPDIR);
+ const char *p = get_snapshot_filename(args.inputs[1], SYREP_TEMPDIR);
mkdir(p, 0777);
setenv("TMPDIR", p, 1);
}
- if (!(path1 = strdup(get_attached_filename(args.inputs[0], SYREP_SNAPSHOTFILENAME))))
+ if (!(path1 = strdup(get_snapshot_filename(args.inputs[0], SYREP_SNAPSHOTFILENAME))))
goto finish;
- if (!(path2 = strdup(get_attached_filename(args.inputs[1], SYREP_SNAPSHOTFILENAME))))
+ if (!(path2 = strdup(get_snapshot_filename(args.inputs[1], SYREP_SNAPSHOTFILENAME))))
goto finish;
if (!strcmp(path1, path2)) {
@@ -144,10 +148,13 @@ static int do_merge(void) {
goto finish;
}
- if (!(c1 = db_context_open(path1)))
+ if (!(c1 = db_context_open(path1, 0)))
goto finish;
- if (!(c2 = db_context_open(path2)))
+ if (!(c2 = db_context_open(path2, 0)))
+ goto finish;
+
+ if (db_context_origin_warn(c2))
goto finish;
if (merge(c1, c2, args.inputs[1]) < 0)
@@ -187,15 +194,15 @@ static int do_makepatch(void) {
}
if (args.local_temp_flag) {
- const char *p = get_attached_filename(args.inputs[0], SYREP_TEMPDIR);
+ const char *p = get_snapshot_filename(args.inputs[0], SYREP_TEMPDIR);
mkdir(p, 0777);
setenv("TMPDIR", p, 1);
}
- if (!(path1 = strdup(get_attached_filename(args.inputs[0], SYREP_SNAPSHOTFILENAME))))
+ if (!(path1 = strdup(get_snapshot_filename(args.inputs[0], SYREP_SNAPSHOTFILENAME))))
goto finish;
- if (!(path2 = strdup(get_attached_filename(args.inputs[1], SYREP_SNAPSHOTFILENAME))))
+ if (!(path2 = strdup(get_snapshot_filename(args.inputs[1], SYREP_SNAPSHOTFILENAME))))
goto finish;
if (!strcmp(path1, path2)) {
@@ -203,12 +210,15 @@ static int do_makepatch(void) {
goto finish;
}
- if (!(c1 = db_context_open(path1)))
+ if (!(c1 = db_context_open(path1, 0)))
goto finish;
- if (!(c2 = db_context_open(path2)))
+ if (db_context_origin_warn(c1))
goto finish;
+ if (!(c2 = db_context_open(path2, 0)))
+ goto finish;
+
if (makepatch(c1, c2, args.inputs[0]) < 0)
goto finish;
@@ -248,15 +258,15 @@ static int do_foreach(int (*func) (struct syrep_db_context *c), int m) {
static char saved_cwd[PATH_MAX];
if (args.local_temp_flag && isdirectory(args.inputs[i]) >= 1) {
- const char *p = get_attached_filename(args.inputs[i], SYREP_TEMPDIR);
+ const char *p = get_snapshot_filename(args.inputs[i], SYREP_TEMPDIR);
mkdir(p, 0777);
setenv("TMPDIR", p, 1);
}
- if (!(path = strdup(get_attached_filename(args.inputs[i], SYREP_SNAPSHOTFILENAME))))
+ if (!(path = strdup(get_snapshot_filename(args.inputs[i], SYREP_SNAPSHOTFILENAME))))
goto finish;
- if (!(c = db_context_open(path)))
+ if (!(c = db_context_open(path, 0)))
goto finish;
if (args.inputs_num > 1)
@@ -333,26 +343,26 @@ static int do_update(void) {
}
if (args.local_temp_flag) {
- const char *p = get_attached_filename(args.inputs[i], SYREP_TEMPDIR);
+ const char *p = get_snapshot_filename(args.inputs[i], SYREP_TEMPDIR);
mkdir(p, 0777);
setenv("TMPDIR", p, 1);
}
- if (!(path = strdup(get_attached_filename(args.inputs[i], SYREP_SNAPSHOTFILENAME))))
+ if (!(path = strdup(get_snapshot_filename(args.inputs[i], SYREP_SNAPSHOTFILENAME))))
goto finish;
- if (!(c = db_context_open(path))) {
- fprintf(stderr, "Initializing repository.\n");
- if (!(c = db_context_open(NULL)))
- goto finish;
- }
+ if (!(c = db_context_open(path, 1)))
+ goto finish;
+
+ if (db_context_origin_warn(c))
+ goto finish;
if (!args.no_cache_flag) {
const char *p;
if (args.cache_given)
cache = md_cache_open(args.cache_arg, args.ro_cache_flag);
- else if ((p = get_attached_filename(args.inputs[i], SYREP_MDCACHEFILENAME)))
+ else if ((p = get_snapshot_filename(args.inputs[i], SYREP_MDCACHEFILENAME)))
cache = md_cache_open(p, args.ro_cache_flag);
}
@@ -407,8 +417,48 @@ finish:
return r;
}
+static int do_cleanup(void) {
+ int r = 1, i;
+
+ if (args.inputs_num < 1)
+ fprintf(stderr, "WARNING: No repository specified!\n");
+
+ for (i = 0; i < args.inputs_num; i++) {
+
+ if (isdirectory(args.inputs[i]) <= 0) {
+ fprintf(stderr, "%s is not a directory\n", args.inputs[i]);
+ goto finish;
+ }
+
+ if (args.inputs_num > 1)
+ fprintf(stderr, "*** %s ***\n", args.inputs[i]);
+
+ if (cleanup(args.inputs[i]) < 0)
+ goto finish;
+
+ if (args.inputs_num > 1 && i < args.inputs_num-1)
+ fprintf(stderr, "\n");
+ }
+
+ r = 0;
+
+finish:
+
+ return r;
+
+}
+
+static void sigint(int s) {
+ interrupted = 1;
+}
+
int main(int argc, char *argv[]) {
char *b;
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sigint;
+ sigaction(SIGINT, &sa, NULL);
if ((b = strrchr(argv[0], '/')))
argv[0] = b+1;
@@ -433,6 +483,8 @@ int main(int argc, char *argv[]) {
return do_foreach(extract, 1);
else if (args.makepatch_flag)
return do_makepatch();
+ else if (args.cleanup_flag)
+ return do_cleanup();
cmdline_parser_print_help();
diff --git a/src/syrep.ggo b/src/syrep.ggo
index e0a5f02..b3e16ef 100644
--- a/src/syrep.ggo
+++ b/src/syrep.ggo
@@ -22,6 +22,7 @@ version "0.1"
option "verbose" v "Enable verbose operation" flag off
option "local-temp" T "Use temporary directory inside repository" flag off
+option "ignore-origin" - "update: Don't warn if snapshot not local in update, merge, makepatch" flag off
option "list" - "List a repository snapshot" flag off
option "show-deleted" - "list: Show deleted entries of repository snapshot" flag off
@@ -45,9 +46,13 @@ option "diff" - "Show difference between two repositories or snapshots" flag off
option "merge" - "Merge a snapshot or a repository into a repository" flag off
option "question" q "merge: Ask a question before each action" flag off
option "prune-empty" - "merge: Prune empty directories" flag off
+ option "keep-trash" - "merge: Don't empty trash" flag off
option "makepatch" - "Make a patch against the specified repository" flag off
option "output-file" o "makepatch: Write output to specified file instead of STDOUT" string no
option "extract" - "Extract the context of a snapshot or patch" flag off
option "output-directory" D "extract: Write output to specified directory" string no
+
+option "cleanup" - "Remove syrep info from repository" flag off
+ option "cleanup-level" - "cleanup: 1 - just remove temporary data and trash (default); 2 - remove MD cache as well; 3 - remove all syrep data" int default="1" no
diff --git a/src/syrep.h b/src/syrep.h
index 29b709d..f3f4d5e 100644
--- a/src/syrep.h
+++ b/src/syrep.h
@@ -32,4 +32,6 @@
extern struct gengetopt_args_info args;
+extern volatile int interrupted;
+
#endif
diff --git a/src/update.c b/src/update.c
index f063686..e0e7f9c 100644
--- a/src/update.c
+++ b/src/update.c
@@ -126,6 +126,7 @@ static int handle_file(struct syrep_db_context *c, uint32_t version, const char
}
static int iterate_dir(struct syrep_db_context *c, struct syrep_md_cache *cache, uint32_t version, const char *root) {
+ int r = -1;
DIR *dir;
struct dirent *de;
char p[PATH_MAX];
@@ -143,6 +144,11 @@ static int iterate_dir(struct syrep_db_context *c, struct syrep_md_cache *cache,
if (!strncmp(de->d_name, ".syrep", 6))
continue;
+ if (interrupted) {
+ fprintf(stderr, "Canceled.\n");
+ goto finish;
+ }
+
if (args.progress_flag)
rotdash();
@@ -157,21 +163,24 @@ static int iterate_dir(struct syrep_db_context *c, struct syrep_md_cache *cache,
if (S_ISDIR(st.st_mode)) {
if (iterate_dir(c, cache, version, p) < 0)
- fprintf(stderr, "iterate_dir(%s) failed: %s\n", p, strerror(errno));
+ goto finish;
+
} else if (S_ISREG(st.st_mode)) {
if (md_cache_get(cache, p, md.digest) < 0)
- continue;
+ goto finish;
- if ((handle_file(c, version, p, &md)) < 0) {
- fprintf(stderr, "handle_file(%s) failed.\n", p);
- return -1;
- }
+ if ((handle_file(c, version, p, &md)) < 0)
+ goto finish;
}
}
+
+ r = 0;
+
+finish:
closedir(dir);
- return 0;
+ return r;
}
static int new_version(struct syrep_db_context *c, uint32_t v, uint32_t t) {
@@ -217,6 +226,9 @@ int update(struct syrep_db_context *c, struct syrep_md_cache *cache) {
if (iterate_dir(c, cache, version, ".") < 0)
return -1;
+ if (args.progress_flag)
+ rotdash_hide();
+
if (new_version(c, version, now) < 0)
return -1;
diff --git a/src/util.c b/src/util.c
index 2a4eb59..f0d66d1 100644
--- a/src/util.c
+++ b/src/util.c
@@ -30,12 +30,17 @@
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
+#include <ctype.h>
+#include <dirent.h>
#ifdef USE_SENDFILE
#include <sys/sendfile.h>
#endif
#include "util.h"
+#include "syrep.h"
+
+static int stderr_tty = -1;
void statistics(DB *db) {
DB_BTREE_STAT *statp;
@@ -90,7 +95,10 @@ void rotdash(void) {
static const char dashes[] = /* ".oOo"; */ "|/-\\";
const static char *d = dashes;
- if (isatty(fileno(stderr))) {
+ if (stderr_tty < 0)
+ stderr_tty = isatty(fileno(stderr));
+
+ if (stderr_tty) {
fprintf(stderr, "%c\b", *d);
d++;
@@ -99,7 +107,15 @@ void rotdash(void) {
}
}
-const char* get_attached_filename(const char *path, const char *fn) {
+void rotdash_hide(void) {
+ if (stderr_tty < 0)
+ stderr_tty = isatty(fileno(stderr));
+
+ if (stderr_tty)
+ fputs(" \b", stderr);
+}
+
+const char* get_snapshot_filename(const char *path, const char *fn) {
static char npath[PATH_MAX];
struct stat st;
@@ -213,6 +229,11 @@ int copy_fd(int sfd, int dfd, uint32_t l) {
munmap(src_p, m);
munmap(dst_p, m);
+
+ if (interrupted) {
+ fprintf(stderr, "Canceled.\n");
+ goto finish;
+ }
src_o += m;
dst_o += m;
@@ -243,6 +264,11 @@ int copy_fd(int sfd, int dfd, uint32_t l) {
for (;;) {
ssize_t m;
+ if (interrupted) {
+ fprintf(stderr, "Canceled.\n");
+ goto finish;
+ }
+
if ((m = read(sfd, buf, BUFSIZE)) < 0) {
fprintf(stderr, "read(): %s\n", strerror(errno));
goto finish;
@@ -421,3 +447,126 @@ int makeprefixpath(const char *path, mode_t m) {
return mkdir_p(tmp, m);
}
+
+int question(const char *text, const char *replies) {
+ int r = 0;
+ FILE *f;
+
+ assert(text && replies && *replies);
+
+ if (!(f = fopen("/dev/tty", "r")))
+ f = stdin;
+
+ for (;;) {
+ const char *q;
+ char reply[256];
+
+ if (interrupted) {
+ fprintf(stderr, "Canceled.\n");
+ goto finish;
+ }
+
+ fprintf(stderr, "\r%s [", text);
+
+ for (q = replies; *q; q++) {
+ fputc(q == replies ? toupper(*q) : tolower(*q), stderr);
+
+ if (*(q+1))
+ fputc('|', stderr);
+ }
+
+ fprintf(stderr, "] ");
+
+ if (!fgets(reply, sizeof(reply), f))
+ goto finish;
+
+ if (reply[0] == '\r' || reply[0] == '\n')
+ reply[0] = *replies;
+
+ reply[0] = tolower(reply[0]);
+
+ for (q = replies; *q; q++)
+
+ if (tolower(*q) == reply[0]) {
+ r = *q;
+ goto finish;
+ }
+ }
+
+
+finish:
+
+ fputc('\r', stderr);
+
+ if (f != stdin)
+ fclose(f);
+
+ return r;
+
+}
+
+
+int rm_rf(const char *root, int rec) {
+ DIR *dir = NULL;
+ int r = -1;
+ struct dirent *de;
+
+ if (!(dir = opendir(root))) {
+
+ if (errno == ENOENT) {
+ r = 0;
+ goto finish;
+ }
+
+ fprintf(stderr, "opendir(\"%s\"): %s", root, strerror(errno));
+ goto finish;
+ }
+
+ while ((de = readdir(dir))) {
+ char path[PATH_MAX];
+
+ if (!strcmp(de->d_name, "."))
+ continue;
+
+ if (!strcmp(de->d_name, ".."))
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", root, de->d_name);
+
+ if (rec) {
+ struct stat st;
+
+ if (stat(path, &st) < 0) {
+ fprintf(stderr, "stat(\"%s\"): %s\n", path, strerror(errno));
+ goto finish;
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+
+ if (rm_rf(path, rec) < 0)
+ return -1;
+
+ continue;
+ }
+ }
+
+ if (unlink(path) < 0) {
+ fprintf(stderr, "unlink(\"%s\"): %s\n", path, strerror(errno));
+ goto finish;
+ }
+ }
+
+ if (rmdir(root) < 0) {
+ fprintf(stderr, "rmdir(\"%s\"): %s\n", root, strerror(errno));
+ goto finish;
+ }
+
+ r = 0;
+
+finish:
+ if (dir)
+ closedir(dir);
+
+ return r;
+}
+
diff --git a/src/util.h b/src/util.h
index 2aa7215..a44c598 100644
--- a/src/util.h
+++ b/src/util.h
@@ -24,13 +24,19 @@
#include <db.h>
#include <stdint.h>
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
void statistics(DB *db);
char* normalize_path(char *s);
void rotdash(void);
-const char* get_attached_filename(const char *path, const char *fn);
+void rotdash_hide(void);
+const char* get_snapshot_filename(const char *path, const char *fn);
int isdirectory(const char *path);
int copy_fd(int sfd, int dfd, uint32_t l);
int copy_file(const char *src, const char *dst, int c);
+int move_file(const char *src, const char *dst, int c);
int copy_or_link_file(const char *src, const char *dst, int c);
/* Remove all directories between path and root if they are empty. */
@@ -42,10 +48,10 @@ int mkdir_p(const char *path, mode_t m);
/* Create all leading directories in path */
int makeprefixpath(const char *path, mode_t m);
-int move_file(const char *src, const char *dst, int c);
+int question(const char *q, const char *resp);
+
+/* Same as /bin/rm -rf in the shell */
+int rm_rf(const char *root, int rec);
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
#endif
diff --git a/test/Makefile b/test/Makefile
index 491c59a..fc92e0e 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -31,7 +31,7 @@ mergepatch:
clean:
mrproper:
- rm -rf rep?/.syrep*
+ $(SYREP) -v --cleanup-level=3 --cleanup rep1 rep2
.PHONY: all merge clean mrproper mergepatch