/* * Read contents a file with conflicts, normalize the conflicts * by (1) discarding the common ancestor version in diff3-style, * (2) reordering our side and their side so that whichever sorts * alphabetically earlier comes before the other one, while * computing the "conflict ID", which is just an SHA-1 hash of * one side of the conflict, NUL, the other side of the conflict, * and NUL concatenated together. * * Return 1 if conflict hunks are found, 0 if there are no conflict * hunks and -1 if an error occured. */ static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size) { git_SHA_CTX ctx; struct strbuf buf = STRBUF_INIT, out = STRBUF_INIT; int has_conflicts = 0; if (sha1) git_SHA1_Init(&ctx); while (!io->getline(&buf, io)) { if (is_cmarker(buf.buf, '<', marker_size)) { has_conflicts = handle_conflict(&out, io, marker_size, sha1 ? &ctx : NULL); if (has_conflicts < 0) break; rerere_io_putmem(out.buf, out.len, io); strbuf_reset(&out); } else rerere_io_putstr(buf.buf, io); } strbuf_release(&buf); strbuf_release(&out); if (sha1) git_SHA1_Final(sha1, &ctx); return has_conflicts; }
/* * Read contents a file with conflicts, normalize the conflicts * by (1) discarding the common ancestor version in diff3-style, * (2) reordering our side and their side so that whichever sorts * alphabetically earlier comes before the other one, while * computing the "conflict ID", which is just an SHA-1 hash of * one side of the conflict, NUL, the other side of the conflict, * and NUL concatenated together. * * Return 1 if conflict hunks are found, 0 if there are no conflict * hunks and -1 if an error occured. */ static int handle_path(unsigned char *hash, struct rerere_io *io, int marker_size) { git_hash_ctx ctx; struct strbuf buf = STRBUF_INIT, out = STRBUF_INIT; int has_conflicts = 0; if (hash) the_hash_algo->init_fn(&ctx); while (!io->getline(&buf, io)) { if (is_cmarker(buf.buf, '<', marker_size)) { has_conflicts = handle_conflict(&out, io, marker_size, hash ? &ctx : NULL); if (has_conflicts < 0) break; rerere_io_putmem(out.buf, out.len, io); strbuf_reset(&out); } else rerere_io_putstr(buf.buf, io); } strbuf_release(&buf); strbuf_release(&out); if (hash) the_hash_algo->final_fn(hash, &ctx); return has_conflicts; }
static int handle_conflict(struct strbuf *out, struct rerere_io *io, int marker_size, git_hash_ctx *ctx) { enum { RR_SIDE_1 = 0, RR_SIDE_2, RR_ORIGINAL } hunk = RR_SIDE_1; struct strbuf one = STRBUF_INIT, two = STRBUF_INIT; struct strbuf buf = STRBUF_INIT, conflict = STRBUF_INIT; int has_conflicts = -1; while (!io->getline(&buf, io)) { if (is_cmarker(buf.buf, '<', marker_size)) { if (handle_conflict(&conflict, io, marker_size, NULL) < 0) break; if (hunk == RR_SIDE_1) strbuf_addbuf(&one, &conflict); else strbuf_addbuf(&two, &conflict); strbuf_release(&conflict); } else if (is_cmarker(buf.buf, '|', marker_size)) { if (hunk != RR_SIDE_1) break; hunk = RR_ORIGINAL; } else if (is_cmarker(buf.buf, '=', marker_size)) { if (hunk != RR_SIDE_1 && hunk != RR_ORIGINAL) break; hunk = RR_SIDE_2; } else if (is_cmarker(buf.buf, '>', marker_size)) { if (hunk != RR_SIDE_2) break; if (strbuf_cmp(&one, &two) > 0) strbuf_swap(&one, &two); has_conflicts = 1; rerere_strbuf_putconflict(out, '<', marker_size); strbuf_addbuf(out, &one); rerere_strbuf_putconflict(out, '=', marker_size); strbuf_addbuf(out, &two); rerere_strbuf_putconflict(out, '>', marker_size); if (ctx) { the_hash_algo->update_fn(ctx, one.buf ? one.buf : "", one.len + 1); the_hash_algo->update_fn(ctx, two.buf ? two.buf : "", two.len + 1); } break; } else if (hunk == RR_SIDE_1) strbuf_addbuf(&one, &buf); else if (hunk == RR_ORIGINAL) ; /* discard */ else if (hunk == RR_SIDE_2) strbuf_addbuf(&two, &buf); } strbuf_release(&one); strbuf_release(&two); strbuf_release(&buf); return has_conflicts; }
static int do_attach_branch(struct wim_dentry *branch, const utf16lechar *target, struct update_command_journal *j, int add_flags, wimlib_progress_func_t progfunc, void *progctx) { struct wim_dentry *parent; struct wim_dentry *existing; const utf16lechar empty_name[1] = {0}; const utf16lechar *cur_component_name; size_t cur_component_nbytes; const utf16lechar *next_component_name; int ret; /* Attempt to create root directory before proceeding to the "real" * first component */ parent = NULL; existing = *j->root_p; cur_component_name = empty_name; cur_component_nbytes = 0; /* Skip leading slashes */ next_component_name = target; while (*next_component_name == cpu_to_le16(WIM_PATH_SEPARATOR)) next_component_name++; while (*next_component_name) { /* While not the last component ... */ const utf16lechar *end; if (existing) { /* Descend into existing directory */ if (!dentry_is_directory(existing)) { ERROR("\"%"TS"\" in the WIM image " "is not a directory!", dentry_full_path(existing)); return WIMLIB_ERR_NOTDIR; } } else { /* A parent directory of the target didn't exist. Make * the way by creating a filler directory. */ struct wim_dentry *filler; ret = new_filler_directory(&filler); if (ret) return ret; ret = dentry_set_name_utf16le(filler, cur_component_name, cur_component_nbytes); if (ret) { free_dentry(filler); return ret; } ret = journaled_link(j, filler, parent); if (ret) { free_dentry(filler); return ret; } existing = filler; } /* Advance to next component */ cur_component_name = next_component_name; end = cur_component_name + 1; while (*end && *end != cpu_to_le16(WIM_PATH_SEPARATOR)) end++; next_component_name = end; if (*end) { /* There will still be more components after this. */ do { } while (*++next_component_name == cpu_to_le16(WIM_PATH_SEPARATOR)); wimlib_assert(*next_component_name); /* No trailing slashes */ } else { /* This will be the last component */ next_component_name = end; } parent = existing; cur_component_nbytes = (end - cur_component_name) * sizeof(utf16lechar); existing = get_dentry_child_with_utf16le_name( parent, cur_component_name, cur_component_nbytes, WIMLIB_CASE_PLATFORM_DEFAULT); } /* Last component */ if (existing) { return handle_conflict(branch, existing, j, add_flags, progfunc, progctx); } else { return journaled_link(j, branch, parent); } }
static int handle_conflict(struct wim_dentry *branch, struct wim_dentry *existing, struct update_command_journal *j, int add_flags, wimlib_progress_func_t progfunc, void *progctx) { bool branch_is_dir = dentry_is_directory(branch); bool existing_is_dir = dentry_is_directory(existing); if (branch_is_dir != existing_is_dir) { if (existing_is_dir) { ERROR("\"%"TS"\" is a directory!\n" " Specify the path at which " "to place the file inside this directory.", dentry_full_path(existing)); return WIMLIB_ERR_IS_DIRECTORY; } else { ERROR("Can't place directory at \"%"TS"\" because " "a nondirectory file already exists there!", dentry_full_path(existing)); return WIMLIB_ERR_NOTDIR; } } if (branch_is_dir) { /* Directory overlay */ while (dentry_has_children(branch)) { struct wim_dentry *new_child; struct wim_dentry *existing_child; int ret; new_child = dentry_any_child(branch); existing_child = get_dentry_child_with_utf16le_name(existing, new_child->file_name, new_child->file_name_nbytes, WIMLIB_CASE_PLATFORM_DEFAULT); unlink_dentry(new_child); if (existing_child) { ret = handle_conflict(new_child, existing_child, j, add_flags, progfunc, progctx); } else { ret = journaled_link(j, new_child, existing); } if (ret) { dentry_add_child(branch, new_child); return ret; } } free_dentry_tree(branch, j->lookup_table); return 0; } else if (add_flags & WIMLIB_ADD_FLAG_NO_REPLACE) { /* Can't replace nondirectory file */ ERROR("Refusing to overwrite nondirectory file \"%"TS"\"", dentry_full_path(existing)); return WIMLIB_ERR_INVALID_OVERLAY; } else { /* Replace nondirectory file */ struct wim_dentry *parent; int ret; parent = existing->d_parent; ret = calculate_dentry_full_path(existing); if (ret) return ret; if (add_flags & WIMLIB_ADD_FLAG_VERBOSE) { union wimlib_progress_info info; info.replace.path_in_wim = existing->_full_path; ret = call_progress(progfunc, WIMLIB_PROGRESS_MSG_REPLACE_FILE_IN_WIM, &info, progctx); if (ret) return ret; } ret = journaled_unlink(j, existing); if (ret) return ret; return journaled_link(j, branch, parent); } }