summaryrefslogtreecommitdiffstats
path: root/src/merge.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/merge.c')
-rw-r--r--src/merge.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/merge.c b/src/merge.c
new file mode 100644
index 0000000..aef3f8f
--- /dev/null
+++ b/src/merge.c
@@ -0,0 +1,132 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "md5util.h"
+#include "diff.h"
+#include "dbutil.h"
+
+struct cb_info {
+ struct syrep_db_context *c1;
+ struct syrep_db_context *c2;
+ const char *root;
+};
+
+int conflict_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) {
+ struct cb_info *cb_info = p;
+ char path[PATH_MAX+1];
+
+ assert(ddb && name && de && p);
+
+ if (de->action != DIFF_CONFLICT)
+ return 0;
+
+ snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path);
+ fprintf(stderr, "QUERY %s\n", path);
+
+ return 0;
+}
+
+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;
+ char path[PATH_MAX+1];
+ int f;
+ char d[SYREP_DIGESTLENGTH*2+1];
+
+ assert(ddb && name && de && p);
+
+ if (de->action != DIFF_COPY)
+ return 0;
+
+ if (de->repository == cb_info->c2)
+ return 0;
+
+ snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path);
+
+ if ((f = get_current_md_by_name(cb_info->c1, name, &md)) < 0)
+ return -1;
+
+
+ if (!f) {
+ fprintf(stderr, "Diff invalid!\n");
+ return -1;
+ }
+
+ 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));
+ return -1;
+ }
+ } else
+ fprintf(stderr, "MISSING FILE %s\n", path);
+
+ return 0;
+}
+
+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];
+
+ assert(ddb && name && de && p);
+
+ if (de->action != DIFF_DELETE)
+ return 0;
+
+ if (de->repository == cb_info->c1)
+ return 0;
+
+ snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path);
+ fprintf(stderr, "Deleting file <%s>\n", path);
+
+ if (unlink(path) < 0) {
+ fprintf(stderr, "Failed to unlink: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Merges c1 into c2 in directory "root" */
+int merge_snapshot(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* root) {
+ struct cb_info cb_info;
+ DB *ddb = NULL;
+
+ 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, conflict_phase, &cb_info) < 0)
+ goto finish;
+
+ if (diff_foreach(ddb, copy_phase, &cb_info) < 0)
+ goto finish;
+
+ if (diff_foreach(ddb, delete_phase, &cb_info) < 0)
+ goto finish;
+
+finish:
+ if (ddb)
+ ddb->close(ddb, 0);
+
+ return 0;
+}
+