commit eec2f5a957bde0458cfa8ee022528e4aeabb708e from: Stefan Sperling date: Thu Jun 03 12:14:35 2021 UTC decouple merge_file() parameters for 2nd derived version and merge target file commit - dc082d4a7ad5857602ab64aaea1f836ce47b689b commit + eec2f5a957bde0458cfa8ee022528e4aeabb708e blob - 12aa78911429fdc83d9687a9b65a66678594b1c6 blob + 5912a6838c3bd1d1e07865b39b522dbe23acb39a --- lib/worktree.c +++ lib/worktree.c @@ -759,12 +759,13 @@ check_files_equal(int *same, FILE *f1, FILE *f2) /* * Perform a 3-way merge where the file f_orig acts as the common * ancestor, the file f_deriv acts as the first derived version, - * and the file at ondisk_path acts as both the target and the - * second derived version + * and the file f_deriv2 acts as the second derived version. + * The merge result will be written to a new file at ondisk_path; any + * existing file at this path will be replaced. */ static const struct got_error * merge_file(int *local_changes_subsumed, struct got_worktree *worktree, - FILE *f_orig, FILE *f_deriv, const char *ondisk_path, + FILE *f_orig, FILE *f_deriv, FILE *f_deriv2, const char *ondisk_path, const char *path, uint16_t st_mode, const char *label_orig, const char *label_deriv, struct got_repository *repo, @@ -776,7 +777,6 @@ merge_file(int *local_changes_subsumed, struct got_wor char *merged_path = NULL, *base_path = NULL; int overlapcnt = 0; char *parent = NULL; - FILE *f = NULL; *local_changes_subsumed = 0; @@ -792,58 +792,9 @@ merge_file(int *local_changes_subsumed, struct got_wor err = got_opentemp_named_fd(&merged_path, &merged_fd, base_path); if (err) goto done; - - /* - * Open the merge target file. - * In order the run a 3-way merge with a symlink we copy the symlink's - * target path into a temporary file and use that file with diff3. - */ - if (S_ISLNK(st_mode)) { - char target_path[PATH_MAX]; - ssize_t target_len; - size_t n; - f = got_opentemp(); - if (f == NULL) { - err = got_error_from_errno("got_opentemp"); - goto done; - } - target_len = readlink(ondisk_path, target_path, - sizeof(target_path)); - if (target_len == -1) { - err = got_error_from_errno2("readlink", ondisk_path); - goto done; - } - n = fwrite(target_path, 1, target_len, f); - if (n != target_len) { - err = got_ferror(f, GOT_ERR_IO); - goto done; - } - if (fflush(f) == EOF) { - err = got_error_from_errno("fflush"); - goto done; - } - if (fseek(f, 0L, SEEK_SET) == -1) { - err = got_ferror(f, GOT_ERR_IO); - goto done; - } - } else { - int fd; - fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW); - if (fd == -1) { - err = got_error_from_errno2("open", ondisk_path); - goto done; - } - f = fdopen(fd, "r"); - if (f == NULL) { - err = got_error_from_errno2("fdopen", ondisk_path); - close(fd); - goto done; - } - } - - err = got_merge_diff3(&overlapcnt, merged_fd, f_deriv, f_orig, f, - label_deriv, label_orig, NULL); + err = got_merge_diff3(&overlapcnt, merged_fd, f_deriv, f_orig, + f_deriv2, label_deriv, label_orig, NULL); if (err) goto done; @@ -887,8 +838,6 @@ done: if (merged_path) unlink(merged_path); } - if (f && fclose(f) == EOF && err == NULL) - err = got_error_from_errno("fclose"); if (merged_fd != -1 && close(merged_fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (f_merged && fclose(f_merged) == EOF && err == NULL) @@ -1085,6 +1034,46 @@ merge_symlink(struct got_worktree *worktree, done: free(ancestor_target); + return err; +} + +static const struct got_error * +dump_symlink_target_path_to_file(FILE **outfile, const char *ondisk_path) +{ + const struct got_error *err = NULL; + char target_path[PATH_MAX]; + ssize_t target_len; + size_t n; + FILE *f; + + *outfile = NULL; + + f = got_opentemp(); + if (f == NULL) + return got_error_from_errno("got_opentemp"); + target_len = readlink(ondisk_path, target_path, sizeof(target_path)); + if (target_len == -1) { + err = got_error_from_errno2("readlink", ondisk_path); + goto done; + } + n = fwrite(target_path, 1, target_len, f); + if (n != target_len) { + err = got_ferror(f, GOT_ERR_IO); + goto done; + } + if (fflush(f) == EOF) { + err = got_error_from_errno("fflush"); + goto done; + } + if (fseek(f, 0L, SEEK_SET) == -1) { + err = got_ferror(f, GOT_ERR_IO); + goto done; + } +done: + if (err) + fclose(f); + else + *outfile = f; return err; } @@ -1102,7 +1091,7 @@ merge_blob(int *local_changes_subsumed, struct got_wor got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; - FILE *f_orig = NULL, *f_deriv = NULL; + FILE *f_orig = NULL, *f_deriv = NULL, *f_deriv2 = NULL; char *blob_orig_path = NULL; char *blob_deriv_path = NULL, *base_path = NULL, *id_str = NULL; char *label_deriv = NULL, *parent = NULL; @@ -1163,15 +1152,40 @@ merge_blob(int *local_changes_subsumed, struct got_wor GOT_MERGE_LABEL_MERGED, id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; + } + + /* + * In order the run a 3-way merge with a symlink we copy the symlink's + * target path into a temporary file and use that file with diff3. + */ + if (S_ISLNK(st_mode)) { + err = dump_symlink_target_path_to_file(&f_deriv2, ondisk_path); + if (err) + goto done; + } else { + int fd; + fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW); + if (fd == -1) { + err = got_error_from_errno2("open", ondisk_path); + goto done; + } + f_deriv2 = fdopen(fd, "r"); + if (f_deriv2 == NULL) { + err = got_error_from_errno2("fdopen", ondisk_path); + close(fd); + goto done; + } } err = merge_file(local_changes_subsumed, worktree, f_orig, f_deriv, - ondisk_path, path, st_mode, label_orig, label_deriv, + f_deriv2, ondisk_path, path, st_mode, label_orig, label_deriv, repo, progress_cb, progress_arg); done: if (f_orig && fclose(f_orig) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f_deriv && fclose(f_deriv) == EOF && err == NULL) + err = got_error_from_errno("fclose"); + if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(base_path); if (blob_orig_path) { @@ -7711,7 +7725,7 @@ unstage_hunks(struct got_object_id *staged_blob_id, char *parent = NULL, *base_path = NULL; char *blob_base_path = NULL; struct got_object_id *new_staged_blob_id = NULL; - FILE *f = NULL, *f_base = NULL; + FILE *f = NULL, *f_base = NULL, *f_deriv2 = NULL; struct stat sb; err = create_unstaged_content(&path_unstaged_content, @@ -7780,8 +7794,32 @@ unstage_hunks(struct got_object_id *staged_blob_id, if (err) goto done; + /* + * In order the run a 3-way merge with a symlink we copy the symlink's + * target path into a temporary file and use that file with diff3. + */ + if (S_ISLNK(got_fileindex_perms_to_st(ie))) { + err = dump_symlink_target_path_to_file(&f_deriv2, + ondisk_path); + if (err) + goto done; + } else { + int fd; + fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW); + if (fd == -1) { + err = got_error_from_errno2("open", ondisk_path); + goto done; + } + f_deriv2 = fdopen(fd, "r"); + if (f_deriv2 == NULL) { + err = got_error_from_errno2("fdopen", ondisk_path); + close(fd); + goto done; + } + } + err = merge_file(&local_changes_subsumed, worktree, - f_base, f, ondisk_path, ie->path, + f_base, f, f_deriv2, ondisk_path, ie->path, got_fileindex_perms_to_st(ie), label_orig, "unstaged", repo, progress_cb, progress_arg); @@ -7810,6 +7848,8 @@ done: err = got_error_from_errno2("fclose", path_unstaged_content); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", path_unstaged_content); + if (f_deriv2 && fclose(f_deriv2) == EOF && err == NULL) + err = got_error_from_errno2("fclose", ondisk_path); free(path_unstaged_content); free(path_new_staged_content); free(blob_base_path);