summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2003-08-28 00:26:05 +0000
committerLennart Poettering <lennart@poettering.net>2003-08-28 00:26:05 +0000
commit98f36517251b5bccdb80d90d698c173c18ee4a29 (patch)
treebdcbb19a48d0f4fb06c96fb7376cf5b549539e68
parent7ea422bfaf6c9d22346cd415fd6b97712322fd81 (diff)
implemented merging an patch making
git-svn-id: file:///home/lennart/svn/public/syrep/trunk@9 07ea20a6-d2c5-0310-9e02-9ef735347d72
-rw-r--r--doc/package.txt15
-rw-r--r--doc/todo.txt12
-rw-r--r--src/Makefile2
-rw-r--r--src/context.c26
-rw-r--r--src/extract.c93
-rw-r--r--src/makepatch.c72
-rw-r--r--src/makepatch.h8
-rw-r--r--src/merge.c69
-rw-r--r--src/merge.h2
-rw-r--r--src/package.c60
-rw-r--r--src/package.h3
-rw-r--r--src/syrep.c74
-rw-r--r--src/syrep.ggo11
-rw-r--r--src/util.c151
-rw-r--r--src/util.h4
-rw-r--r--test/Makefile10
16 files changed, 460 insertions, 152 deletions
diff --git a/doc/package.txt b/doc/package.txt
new file mode 100644
index 0000000..e20274c
--- /dev/null
+++ b/doc/package.txt
@@ -0,0 +1,15 @@
+
+
+File format for patches and snapshots:
+
+
+8 bytes: id SYREPLP0
+
+Multiple items of:
+
+ 4 bytes: flags
+ 32 bytes: name as asciiz string
+ 4 bytes: length of item
+
+
+$Id$
diff --git a/doc/todo.txt b/doc/todo.txt
index a9da376..0bd0835 100644
--- a/doc/todo.txt
+++ b/doc/todo.txt
@@ -1,10 +1,16 @@
-1. merge/makepatch
+1. merge/makepatch DONE
2. gzip
3. url merges
-4. better usage info
+4. better usage info on --help
5. documentation/man pages
6. stat() before and after md5 as consistency check
7. md5 before delete/replace/link
-8. mmap usage package.c
+8. mmap usage in package.c
+9. Warn if hostname != origin
+10. Recursive directory creation
+11. Locking/Atomicity
+12. Prune empty directories
+13. Handle conflicts
+14. -q mode
$Id$
diff --git a/src/Makefile b/src/Makefile
index addd2e8..a7e55ec 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -4,7 +4,7 @@ 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
+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
$(CC) -g $^ -o $@ -ldb
cmdline.c cmdline.h: syrep.ggo Makefile
diff --git a/src/context.c b/src/context.c
index 00455ea..6512f0d 100644
--- a/src/context.c
+++ b/src/context.c
@@ -80,7 +80,7 @@ struct syrep_db_context* db_context_open(const char *filename) {
if (!(c->package = package_open(filename)))
goto fail;
- path = package_get_item(c->package, "timestamp");
+ path = package_get_item(c->package, "timestamp", 1);
if ((f = fopen(path, "r"))) {
if (fscanf(f, "%i", &c->timestamp) != 1)
c->timestamp = 0;
@@ -90,14 +90,14 @@ struct syrep_db_context* db_context_open(const char *filename) {
if (!c->timestamp)
c->timestamp = time(NULL);
- path = package_get_item(c->package, "version");
+ path = package_get_item(c->package, "version", 1);
if ((f = fopen(path, "r"))) {
if (fscanf(f, "%u", &c->version) != 1)
c->version = 0;
fclose(f);
}
- path = package_get_item(c->package, "origin");
+ path = package_get_item(c->package, "origin", 1);
if ((f = fopen(path, "r"))) {
char hn[256];
if (fgets(hn, sizeof(hn), f)) {
@@ -123,27 +123,27 @@ struct syrep_db_context* db_context_open(const char *filename) {
}
/* Creating database id_meta */
- if (!(c->db_id_meta = open_db(package_get_item(c->package, "id_meta"), 0)))
+ if (!(c->db_id_meta = open_db(package_get_item(c->package, "id_meta", 1), 0)))
goto fail;
/* Creating database md_name */
- if (!(c->db_md_name = open_db(package_get_item(c->package, "md_name"), 1)))
+ if (!(c->db_md_name = open_db(package_get_item(c->package, "md_name", 1), 1)))
goto fail;
/* Creating database name_md */
- if (!(c->db_name_md = open_db(package_get_item(c->package, "name_md"), 1)))
+ if (!(c->db_name_md = open_db(package_get_item(c->package, "name_md", 1), 1)))
goto fail;
/* Creating database name_lastmd */
- if (!(c->db_name_lastmd = open_db(package_get_item(c->package, "name_lastmd"), 0)))
+ if (!(c->db_name_lastmd = open_db(package_get_item(c->package, "name_lastmd", 1), 0)))
goto fail;
/* Creating database md_lastname */
- if (!(c->db_md_lastname = open_db(package_get_item(c->package, "md_lastname"), 0)))
+ if (!(c->db_md_lastname = open_db(package_get_item(c->package, "md_lastname", 1), 0)))
goto fail;
/* Creating database version_timestamp */
- if (!(c->db_version_timestamp = open_db(package_get_item(c->package, "version_timestamp"), 0)))
+ if (!(c->db_version_timestamp = open_db(package_get_item(c->package, "version_timestamp", 1), 0)))
goto fail;
return c;
@@ -157,7 +157,7 @@ fail:
int db_context_save(struct syrep_db_context *c, const char *filename) {
FILE *f;
- assert(c && c->package && filename);
+ assert(c && c->package);
if (c->db_id_meta)
c->db_id_meta->sync(c->db_id_meta, 0);
@@ -177,19 +177,19 @@ int db_context_save(struct syrep_db_context *c, const char *filename) {
if (c->db_version_timestamp)
c->db_version_timestamp->sync(c->db_version_timestamp, 0);
- if (!(f = fopen(package_get_item(c->package, "timestamp"), "w+")))
+ if (!(f = fopen(package_get_item(c->package, "timestamp", 1), "w+")))
return -1;
fprintf(f, "%i\n", c->timestamp);
fclose(f);
- if (!(f = fopen(package_get_item(c->package, "version"), "w+")))
+ if (!(f = fopen(package_get_item(c->package, "version", 1), "w+")))
return -1;
fprintf(f, "%u\n", c->version);
fclose(f);
- if (!(f = fopen(package_get_item(c->package, "origin"), "w+")))
+ if (!(f = fopen(package_get_item(c->package, "origin", 1), "w+")))
return -1;
fprintf(f, "%s\n", c->origin);
diff --git a/src/extract.c b/src/extract.c
index 06d95df..616b8d1 100644
--- a/src/extract.c
+++ b/src/extract.c
@@ -1,4 +1,3 @@
-#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
@@ -10,91 +9,7 @@
#include "package.h"
#include "extract.h"
-
-#define MMAPSIZE (100*1024*1024)
-#define BUFSIZE (1024*1024)
-
-int copy_file(const char *src, const char *dst, uint32_t l) {
- int sfd = -1, dfd = -1, r = -1;
- uint32_t m;
- off_t o;
- void *src_p, *dst_p;
- void *buf = NULL;
-
- if ((sfd = open(src, O_RDONLY)) < 0) {
- fprintf(stderr, "open(%s, O_RDONLY): %s\n", src, strerror(errno));
- goto finish;
- }
-
- if ((dfd = open(dst, O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) {
- fprintf(stderr, "open(%s, O_WRONLY): %s\n", dst, strerror(errno));
- goto finish;
- }
-
- if (ftruncate(dfd, l) < 0) {
- fprintf(stderr, "ftruncate(): %s\n", strerror(errno));
- goto finish;
- }
-
- o = 0;
- m = l < MMAPSIZE ? l : MMAPSIZE;
-
- while (l > 0) {
- if ((src_p = mmap(NULL, m, PROT_READ, MAP_SHARED, sfd, o)) == MAP_FAILED)
- break;
-
- if ((dst_p = mmap(NULL, m, PROT_READ|PROT_WRITE, MAP_SHARED, dfd, o)) == MAP_FAILED) {
- munmap(src_p, m);
- break;
- }
-
- memcpy(dst_p, src_p, m);
-
- munmap(src_p, m);
- munmap(dst_p, m);
-
- o += m;
- l -= m;
- m = l < MMAPSIZE ? l : MMAPSIZE;
- }
-
- if (l > 0) {
- fprintf(stderr, "mmap() failed: %s\n", strerror(errno));
-
- if (!(buf = malloc(BUFSIZE)))
- goto finish;
-
- for (;;) {
- ssize_t r;
-
- if ((m = read(sfd, buf, BUFSIZE)) < 0) {
- fprintf(stderr, "read(): %s\n", strerror(errno));
- goto finish;
- }
-
- if (!m)
- break;
-
- if ((r = write(dfd, buf, m)) < 0) {
- fprintf(stderr, "write(): %s\n", strerror(errno));
- goto finish;
- }
- }
- }
-
-
- r = 0;
-
-finish:
-
- if (sfd >= 0)
- close(sfd);
-
- if (dfd >= 0)
- close(dfd);
-
- return r;
-}
+#include "util.h"
static int cb(struct package *p, const char *name, const char *path, void *u) {
struct stat st;
@@ -110,8 +25,10 @@ static int cb(struct package *p, const char *name, const char *path, void *u) {
} else
size = (uint32_t) st.st_size;
- if (size)
- return copy_file(path, name, size);
+ if (size) {
+ fprintf(stderr, "Extracting %s ...\n", name);
+ return copy_file(path, name);
+ }
return 0;
}
diff --git a/src/makepatch.c b/src/makepatch.c
new file mode 100644
index 0000000..1ddeb93
--- /dev/null
+++ b/src/makepatch.c
@@ -0,0 +1,72 @@
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "package.h"
+#include "makepatch.h"
+#include "diff.h"
+#include "dbutil.h"
+#include "md5util.h"
+
+struct cb_info {
+ struct syrep_db_context *c1;
+ struct syrep_db_context *c2;
+ const char *root;
+};
+
+static int cb(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) {
+ struct cb_info *cb_info = p;
+ struct syrep_md md;
+ char path[PATH_MAX+1];
+ char d[SYREP_DIGESTLENGTH*2+1];
+ int f;
+
+ assert(ddb && name && de && p);
+
+ if (de->action != DIFF_COPY && de->action != DIFF_CONFLICT)
+ return 0;
+
+ if ((f = get_current_md_by_name(cb_info->c1, name, &md)) < 0)
+ return -1;
+
+ if (!f)
+ return 0;
+
+ fhex(md.digest, SYREP_DIGESTLENGTH, d);
+ d[SYREP_DIGESTLENGTH*2] = 0;
+
+ snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path);
+
+ fprintf(stderr, "Adding %s (%s) to patch.\n", name->path, d);
+
+ if (!package_get_item(cb_info->c1->package, d, 0))
+ if (package_add_file(cb_info->c1->package, d, path) < 0)
+ return -1;
+
+ return 0;
+}
+
+int makepatch(struct syrep_db_context *c1, struct syrep_db_context *c2, const char *root) {
+ struct cb_info cb_info;
+ DB *ddb = NULL;
+ int r = -1;
+
+ memset(&cb_info, 0, sizeof(cb_info));
+ cb_info.c1 = c1;
+ cb_info.c2 = c2;
+ cb_info.root = root;
+
+ if (!(ddb = make_diff(c1, c2)))
+ goto finish;
+
+ if (diff_foreach(ddb, cb, &cb_info) < 0)
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (ddb)
+ ddb->close(ddb, 0);
+
+ return r;
+}
diff --git a/src/makepatch.h b/src/makepatch.h
new file mode 100644
index 0000000..f6836ae
--- /dev/null
+++ b/src/makepatch.h
@@ -0,0 +1,8 @@
+#ifndef foomakepatchhfoo
+#define foomakepatchhfoo
+
+#include "context.h"
+
+int makepatch(struct syrep_db_context *c1, struct syrep_db_context *c2, const char *dir);
+
+#endif
diff --git a/src/merge.c b/src/merge.c
index aef3f8f..059523e 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -7,6 +7,8 @@
#include "md5util.h"
#include "diff.h"
#include "dbutil.h"
+#include "package.h"
+#include "util.h"
struct cb_info {
struct syrep_db_context *c1;
@@ -14,8 +16,10 @@ struct cb_info {
const char *root;
};
-int conflict_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) {
+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 f1, f2;
char path[PATH_MAX+1];
assert(ddb && name && de && p);
@@ -23,13 +27,34 @@ int conflict_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void
if (de->action != DIFF_CONFLICT)
return 0;
+ if ((f1 = get_current_md_by_name(cb_info->c1, name, &md1)) < 0)
+ return -1;
+
+ if ((f2 = get_current_md_by_name(cb_info->c2, name, &md2)) < 0)
+ return -1;
+
snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path);
- fprintf(stderr, "QUERY %s\n", path);
+ if (f1 && f2) {
+ char d1[SYREP_DIGESTLENGTH*2+1], d2[SYREP_DIGESTLENGTH*2+1];
+
+ 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);
+ } 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');
+ }
+
return 0;
}
-int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) {
+static int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) {
struct cb_info *cb_info = p;
struct syrep_name name2;
struct syrep_md md;
@@ -50,7 +75,6 @@ int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p)
if ((f = get_current_md_by_name(cb_info->c1, name, &md)) < 0)
return -1;
-
if (!f) {
fprintf(stderr, "Diff invalid!\n");
return -1;
@@ -59,26 +83,33 @@ int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p)
fhex(md.digest, SYREP_DIGESTLENGTH, d);
d[SYREP_DIGESTLENGTH*2] = 0;
- fprintf(stderr, "Searching for %s\n", d);
-
if ((f = get_current_name_by_md(cb_info->c2, &md, &name2)) < 0)
return -1;
if (f) {
char path2[PATH_MAX+1];
snprintf(path2, sizeof(path2), "%s/%s", cb_info->root, name2.path);
- fprintf(stderr, "Linking file <%s> to <%s>\n", path2, path);
- if (link(path2, path) < 0) {
- fprintf(stderr, "Failed to link: %s\n", strerror(errno));
+ fprintf(stderr, "COPY: Linking existing file <%s> to <%s>.\n", path2, path);
+
+ if (copy_or_link_file(path2, path) < 0)
return -1;
- }
- } else
- fprintf(stderr, "MISSING FILE %s\n", path);
+
+ } else {
+ const char* a;
+
+ if ((a = package_get_item(cb_info->c1->package, d, 0))) {
+ fprintf(stderr, "COPY: Copying file <%s> from patch.\n", path);
+
+ if (copy_or_link_file(a, path) < 0)
+ return -1;
+ } else
+ fprintf(stderr, "COPY: File <%s> is missing.\n", path);
+ }
return 0;
}
-int delete_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) {
+static int delete_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) {
struct cb_info *cb_info = p;
char path[PATH_MAX+1];
@@ -91,10 +122,11 @@ int delete_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *
return 0;
snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path);
- fprintf(stderr, "Deleting file <%s>\n", path);
+
+ fprintf(stderr, "DELETE: Deleting file <%s>\n", path);
if (unlink(path) < 0) {
- fprintf(stderr, "Failed to unlink: %s\n", strerror(errno));
+ fprintf(stderr, "unlink(%s): %s\n", path, strerror(errno));
return -1;
}
@@ -102,9 +134,10 @@ int delete_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *
}
/* Merges c1 into c2 in directory "root" */
-int merge_snapshot(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* root) {
+int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* root) {
struct cb_info cb_info;
DB *ddb = NULL;
+ int r = -1;
memset(&cb_info, 0, sizeof(cb_info));
cb_info.c1 = c1;
@@ -122,11 +155,13 @@ int merge_snapshot(struct syrep_db_context *c1, struct syrep_db_context *c2, con
if (diff_foreach(ddb, delete_phase, &cb_info) < 0)
goto finish;
+
+ r = 0;
finish:
if (ddb)
ddb->close(ddb, 0);
- return 0;
+ return r;
}
diff --git a/src/merge.h b/src/merge.h
index 2b88712..17d3fc0 100644
--- a/src/merge.h
+++ b/src/merge.h
@@ -3,6 +3,6 @@
#include "context.h"
-int merge_snapshot(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* root);
+int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* root);
#endif
diff --git a/src/package.c b/src/package.c
index 5a741eb..8f8bd23 100644
--- a/src/package.c
+++ b/src/package.c
@@ -16,6 +16,7 @@ struct package_item;
struct package_item {
char *name;
char *path;
+ int remove;
struct package_item *next;
};
@@ -61,19 +62,27 @@ static char *tmp(char *fn, int l) {
return fn;
}
-static struct package_item *item_new(const char *name, const char *path) {
+static struct package_item *item_new(const char *name, const char *path, int r) {
struct package_item *i = NULL;
- if (!(i = malloc(sizeof(struct package_item))))
- return NULL;
+ if (!(i = malloc(sizeof(struct package_item)))) {
+ fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
+ goto fail;
+ }
memset(i, 0, sizeof(struct package_item));
- if (!(i->name = strdup(name)))
+ if (!(i->name = strdup(name))) {
+ fprintf(stderr, "strdup() failed: %s\n", strerror(errno));
goto fail;
+ }
- if (!(i->path = strdup(path)))
+ if (!(i->path = strdup(path))) {
+ fprintf(stderr, "strdup() failed: %s\n", strerror(errno));
goto fail;
+ }
+
+ i->remove = r;
return i;
@@ -148,7 +157,7 @@ struct package* package_open(const char *fn) {
}
fclose(d);
- if (!(pi = item_new(name, path))) {
+ if (!(pi = item_new(name, path, 1))) {
unlink(path);
fprintf(stderr, "Failed to allocate memory.\n");
goto finish;
@@ -183,9 +192,11 @@ int package_save(struct package *p, const char *fn) {
int r = 0;
struct package_item *i;
- assert(p && fn);
+ assert(p);
- if (!(f = fopen(fn, "w+")))
+ if (!fn)
+ f = stdout;
+ else if (!(f = fopen(fn, "w+")))
return -1;
for (i = p->items; i; i = i->next) {
@@ -234,8 +245,9 @@ int package_save(struct package *p, const char *fn) {
if (s)
fclose(s);
-
- fclose(f);
+
+ if (fn)
+ fclose(f);
if (r != 0)
unlink(fn);
@@ -243,19 +255,21 @@ int package_save(struct package *p, const char *fn) {
return r;
}
-const char *package_get_item(struct package* p, const char *name) {
+const char *package_get_item(struct package* p, const char *name, int c) {
struct package_item *i;
char path[PATH_MAX];
assert(p && name);
- for (i = p->items; i; i = i->next) {
+ for (i = p->items; i; i = i->next)
if (strncmp(name, i->name, PACKAGE_ITEM_NAME_LEN) == 0)
return i->path;
- }
+ if (!c)
+ return NULL;
+
snprintf(path, sizeof(path), "%s/%i", p->base, p->count++);
- if (!(i = item_new(name, path))) {
+ if (!(i = item_new(name, path, 1))) {
unlink(path);
return NULL;
}
@@ -271,6 +285,22 @@ const char *package_get_item(struct package* p, const char *name) {
return i->path;
}
+int package_add_file(struct package *p, const char *name, const char *fn) {
+ struct package_item *i;
+
+ if (!(i = item_new(name, fn, 0)))
+ return -1;
+
+ if (p->last) {
+ p->last->next = i;
+ p->last = i;
+ } else
+ p->items = p->last = i;
+
+ return 0;
+}
+
+
void package_remove(struct package *p) {
struct package_item *i, *n;
assert(p);
@@ -278,7 +308,7 @@ void package_remove(struct package *p) {
for (i = p->items; i; i = n) {
n = i->next;
- if (i->path)
+ if (i->remove && i->path)
if (unlink(i->path))
if (errno != ENOENT)
fprintf(stderr, "Failed to remove <%s>: %s\n", i->path, strerror(errno));
diff --git a/src/package.h b/src/package.h
index 56a3d34..da9b571 100644
--- a/src/package.h
+++ b/src/package.h
@@ -8,7 +8,8 @@ struct package;
struct package* package_open(const char *fn);
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);
+const char *package_get_item(struct package* p, const char *name, int c);
+int package_add_file(struct package *p, const char *name, const char *fn);
int package_foreach(struct package *p, int (*cb) (struct package *p, const char *name, const char *path, void *u), void *u);
#endif
diff --git a/src/syrep.c b/src/syrep.c
index aaf98f4..ad7619a 100644
--- a/src/syrep.c
+++ b/src/syrep.c
@@ -27,10 +27,11 @@
#include "history.h"
#include "dump.h"
#include "extract.h"
+#include "makepatch.h"
struct gengetopt_args_info args;
-int do_diff(void) {
+static int do_diff(void) {
struct syrep_db_context *c1 = NULL, *c2 = NULL;
char *path1 = NULL, *path2 = NULL;
DB *ddb = NULL;
@@ -85,7 +86,7 @@ finish:
return r;
}
-int do_merge(void) {
+static int do_merge(void) {
struct syrep_db_context *c1 = NULL, *c2 = NULL;
char *path1 = NULL, *path2 = NULL;
int r = 1;
@@ -107,7 +108,60 @@ int do_merge(void) {
goto finish;
if (!strcmp(path1, path2)) {
- fprintf(stderr, "ERROR: diff command requires two distinct snapshots as arguments\n");
+ fprintf(stderr, "ERROR: merge command requires two distinct snapshots as arguments\n");
+ goto finish;
+ }
+
+ if (!(c1 = db_context_open(path1)))
+ goto finish;
+
+ if (!(c2 = db_context_open(path2)))
+ goto finish;
+
+ if (merge(c1, c2, args.inputs[1]) < 0)
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (c1)
+ db_context_free(c1);
+
+ if (c2)
+ db_context_free(c2);
+
+ if (path1)
+ free(path1);
+
+ if (path2)
+ free(path2);
+
+ return r;
+}
+
+static int do_makepatch(void) {
+ struct syrep_db_context *c1 = NULL, *c2 = NULL;
+ char *path1 = NULL, *path2 = NULL;
+ int r = 1;
+
+ if (args.inputs_num != 2) {
+ fprintf(stderr, "ERROR: Need exactly one repository and one repository snapshot for makepatch command\n");
+ goto finish;
+ }
+
+ if (isdirectory(args.inputs[0]) <= 0) {
+ fprintf(stderr, "ERROR: %s is not a directory\n", args.inputs[1]);
+ goto finish;
+ }
+
+ if (!(path1 = strdup(get_attached_filename(args.inputs[0], SYREP_SNAPSHOTFILENAME))))
+ goto finish;
+
+ if (!(path2 = strdup(get_attached_filename(args.inputs[1], SYREP_SNAPSHOTFILENAME))))
+ goto finish;
+
+ if (!strcmp(path1, path2)) {
+ fprintf(stderr, "ERROR: makepatch command requires two distinct snapshots as arguments\n");
goto finish;
}
@@ -117,7 +171,13 @@ int do_merge(void) {
if (!(c2 = db_context_open(path2)))
goto finish;
- if (merge_snapshot(c1, c2, args.inputs[1]) < 0)
+ if (makepatch(c1, c2, args.inputs[0]) < 0)
+ goto finish;
+
+
+ if (!args.output_file_given && isatty(fileno(stdout)))
+ fprintf(stderr, "Sorry, I am not going to write the patch data to a tty.\n");
+ else if (db_context_save(c1, args.output_file_given ? args.output_file_arg : NULL) < 0)
goto finish;
r = 0;
@@ -138,7 +198,7 @@ finish:
return r;
}
-int do_foreach(int (*func) (struct syrep_db_context *c), int m) {
+static int do_foreach(int (*func) (struct syrep_db_context *c), int m) {
char *path = NULL;
int r = 1, i;
struct syrep_db_context *c = NULL;
@@ -206,7 +266,7 @@ finish:
return r;
}
-int do_update(void) {
+static int do_update(void) {
char *path = NULL;
int r = 1, i;
struct syrep_db_context *c = NULL;
@@ -321,6 +381,8 @@ int main(int argc, char *argv[]) {
return do_foreach(dump, 0);
else if (args.extract_flag)
return do_foreach(extract, 1);
+ else if (args.makepatch_flag)
+ return do_makepatch();
cmdline_parser_print_help();
diff --git a/src/syrep.ggo b/src/syrep.ggo
index 216a43d..91f9b2d 100644
--- a/src/syrep.ggo
+++ b/src/syrep.ggo
@@ -2,7 +2,7 @@ purpose "Synchronize Repositories"
package "syrep"
version "0.1"
-option "verbose" - "Enable verbose operation" flag off
+option "verbose" v "Enable verbose operation" flag off
option "list" - "List a repository snapshot" flag off
option "show-deleted" - "list: Show deleted entries of repository snapshot" flag off
@@ -19,12 +19,15 @@ option "update" - "Update a repository snapshot" flag off
option "no-cache" - "update: Don't use a message digest cache" flag off
option "no-purge" - "update: Don't pruge obsolete entries from cache after update run" flag off
option "ro-cache" - "update: Use read only cache" flag off
- option "progress" - "update: Show progress" flag off
+ option "progress" p "update: Show progress" flag off
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" - "merge: Ask a question before each action" flag off
+ option "question" q "merge: Ask a question before each action" 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" - "extract: Write output to specified directory" string no
+ option "output-directory" D "extract: Write output to specified directory" string no
diff --git a/src/util.c b/src/util.c
index 91954dd..ed93e6b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -6,6 +6,9 @@
#include <errno.h>
#include <limits.h>
#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
#include "util.h"
void statistics(DB *db) {
@@ -104,3 +107,151 @@ int isdirectory(const char *path) {
return !!S_ISDIR(st.st_mode);
}
+
+
+#define MMAPSIZE (100*1024*1024)
+#define BUFSIZE (1024*1024)
+
+int copy_fd(int sfd, int dfd, uint32_t l) {
+ off_t src_o, dst_o;
+ void *src_p, *dst_p;
+ void *buf = NULL;
+ int r = -1;
+ struct stat st;
+
+ if ((src_o = lseek(sfd, 0, SEEK_CUR)) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (fstat(sfd, &st) < 0) {
+ fprintf(stderr, "fstat(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (l == (uint32_t) -1 || l >= st.st_size - src_o)
+ l = st.st_size - src_o;
+
+ if ((dst_o = lseek(dfd, 0, SEEK_CUR)) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (fstat(dfd, &st) < 0) {
+ fprintf(stderr, "fstat(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (dst_o+l > st.st_size)
+ if (ftruncate(dfd, dst_o+l) < 0) {
+ fprintf(stderr, "ftruncate(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (l > BUFSIZE) {
+ uint32_t m = l < MMAPSIZE ? l : MMAPSIZE;
+
+ while (l > 0) {
+ if ((src_p = mmap(NULL, m, PROT_READ, MAP_SHARED, sfd, src_o)) == MAP_FAILED)
+ break;
+
+ if ((dst_p = mmap(NULL, m, PROT_READ|PROT_WRITE, MAP_SHARED, dfd, dst_o)) == MAP_FAILED) {
+ munmap(src_p, m);
+ break;
+ }
+
+ memcpy(dst_p, src_p, m);
+
+ munmap(src_p, m);
+ munmap(dst_p, m);
+
+ src_o += m;
+ dst_o += m;
+ l -= m;
+
+ m = l < MMAPSIZE ? l : MMAPSIZE;
+ }
+
+
+ if (lseek(sfd, src_o, SEEK_SET) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (lseek(dfd, dst_o, SEEK_SET) == (off_t) -1) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+ }
+
+ if (l > 0) {
+ if (!(buf = malloc(BUFSIZE)))
+ goto finish;
+
+ for (;;) {
+ ssize_t m;
+
+ if ((m = read(sfd, buf, BUFSIZE)) < 0) {
+ fprintf(stderr, "read(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (!m)
+ break;
+
+ if (write(dfd, buf, m) < 0) {
+ fprintf(stderr, "write(): %s\n", strerror(errno));
+ goto finish;
+ }
+ }
+ }
+
+ r = 0;
+
+finish:
+
+ return r;
+}
+
+int copy_file(const char *src, const char *dst) {
+ int sfd = -1, dfd = -1, r = -1;
+
+ if ((sfd = open(src, O_RDONLY)) < 0) {
+ fprintf(stderr, "open(%s, O_RDONLY): %s\n", src, strerror(errno));
+ goto finish;
+ }
+
+ if ((dfd = open(dst, O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) {
+ fprintf(stderr, "open(%s, O_RDWR|O_TRUNC|O_CREAT): %s\n", dst, strerror(errno));
+ goto finish;
+ }
+
+ if (copy_fd(sfd, dfd, (uint32_t) -1) < 0)
+ goto finish;
+
+ r = 0;
+
+finish:
+
+ if (sfd >= 0)
+ close(sfd);
+
+ if (dfd >= 0)
+ close(dfd);
+
+ return r;
+}
+
+int copy_or_link_file(const char *src, const char *dst) {
+
+ if (link(src, dst) < 0) {
+
+ if (errno == EXDEV || errno == EPERM)
+ return copy_file(src, dst);
+
+ fprintf(stderr, "link(%s, %s): %s\n", src, dst, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/util.h b/src/util.h
index dbdb165..2460ab9 100644
--- a/src/util.h
+++ b/src/util.h
@@ -2,12 +2,16 @@
#define fooutilhfoo
#include <db.h>
+#include <stdint.h>
void statistics(DB *db);
char* normalize_path(char *s);
void rotdash(void);
const char* get_attached_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 copy_or_link_file(const char *src, const char *dst);
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
diff --git a/test/Makefile b/test/Makefile
index f5d2ae0..344a559 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,8 +1,12 @@
-SYREP=../syrep
+SYREP=../src/syrep
+
+ifdef VERBOSE
+VERBOSE=-v
+endif
%:
- mkdir -p rep1 rep2
- $(SYREP) --show-deleted --show-times --$@ rep1 rep2
+ @mkdir -p rep1 rep2
+ $(SYREP) $(VERBOSE) --output-directory=extract -opatch --show-deleted --show-times --$@ rep1 rep2
all: update