diff options
Diffstat (limited to 'src/merge.c')
-rw-r--r-- | src/merge.c | 132 |
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; +} + |