#include #include #include #include #include #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; }