commit db59069162efd1ccd4f236abe7d8eb3ca4b791e4 from: Stefan Sperling date: Wed Jun 02 09:24:51 2021 UTC make merge_file() accept FILEs instead of paths for orig and deriv inputs commit - 67a666476ff7ffc6e95f7d9b994a8f7b01cb86e5 commit + db59069162efd1ccd4f236abe7d8eb3ca4b791e4 blob - b26da2a0b727f30ffdba6e4970dafa32b3856f53 blob + f17dddcabf8aa19fd01c17dec68dc1a8ec2dd748 --- lib/buf.c +++ lib/buf.c @@ -83,38 +83,34 @@ buf_alloc(BUF **b, size_t len) * Sets errno on error. */ const struct got_error * -buf_load(BUF **buf, const char *path) +buf_load(BUF **buf, FILE *f) { const struct got_error *err = NULL; - int fd; - ssize_t ret; + size_t ret; size_t len; u_char *bp; struct stat st; *buf = NULL; - fd = open(path, O_RDONLY, 0600); - if (fd == -1) - return got_error_from_errno2("open", path); - - if (fstat(fd, &st) == -1) { - err = got_error_from_errno2("fstat", path); + if (fstat(fileno(f), &st) == -1) { + err = got_error_from_errno("fstat"); goto out; } if ((uintmax_t)st.st_size > SIZE_MAX) { - err = got_error_set_errno(EFBIG, path); + err = got_error_set_errno(EFBIG, + "cannot fit file into memory buffer"); goto out; } err = buf_alloc(buf, st.st_size); if (err) goto out; - for (bp = (*buf)->cb_buf; ; bp += (size_t)ret) { + for (bp = (*buf)->cb_buf; ; bp += ret) { len = SIZE_LEFT(*buf); - ret = read(fd, bp, len); - if (ret == -1) { - err = got_error_from_errno2("read", path); + ret = fread(bp, 1, len, f); + if (ret == 0 && ferror(f)) { + err = got_ferror(f, GOT_ERR_IO); goto out; } else if (ret == 0) break; @@ -123,8 +119,6 @@ buf_load(BUF **buf, const char *path) } out: - if (close(fd) == -1 && err == NULL) - err = got_error_from_errno2("close", path); if (err) { buf_free(*buf); *buf = NULL; blob - 9422c0f343fd6d75cb7d237cc91e732a5f60405e blob + 354d7c4ea8684b77bc84fa0fcad6b6c8e2b2be80 --- lib/buf.h +++ lib/buf.h @@ -50,7 +50,7 @@ struct buf { }; const struct got_error *buf_alloc(BUF **, size_t); -const struct got_error *buf_load(BUF **, const char *); +const struct got_error *buf_load(BUF **, FILE *); void buf_free(BUF *); void *buf_release(BUF *); u_char buf_getc(BUF *, size_t); blob - f9cd08718072cece748caacb6f92cb0c91edc747 blob + b8c328a2f9b853caabcc322afe5c68eefd3b4ccb --- lib/diff3.c +++ lib/diff3.c @@ -234,10 +234,14 @@ diffreg(BUF **d, const char *path1, const char *path2) if (fflush(outfile) != 0) { err = got_error_from_errno2("fflush", outpath); + goto done; + } + if (fseek(outfile, 0L, SEEK_SET) == -1) { + err = got_ferror(outfile, GOT_ERR_IO); goto done; } - err = buf_load(d, outpath); + err = buf_load(d, outfile); done: if (outpath) { if (unlink(outpath) == -1 && err == NULL) @@ -257,8 +261,8 @@ done: * For merge(1). */ const struct got_error * -got_merge_diff3(int *overlapcnt, int outfd, const char *p1, const char *p2, - const char *p3, const char *label1, const char *label2, const char *label3) +got_merge_diff3(int *overlapcnt, int outfd, FILE *f1, FILE *f2, + FILE *f3, const char *label1, const char *label2, const char *label3) { const struct got_error *err = NULL; char *dp13, *dp23, *path1, *path2, *path3; @@ -277,13 +281,13 @@ got_merge_diff3(int *overlapcnt, int outfd, const char dp13 = dp23 = path1 = path2 = path3 = NULL; data = patch = NULL; - err = buf_load(&b1, p1); + err = buf_load(&b1, f1); if (err) goto out; - err = buf_load(&b2, p2); + err = buf_load(&b2, f2); if (err) goto out; - err = buf_load(&b3, p3); + err = buf_load(&b3, f3); if (err) goto out; blob - ae0e6d73bc7b11bc4dac33b1f7aca5cda1ce9071 blob + c056426dd1569f33cd5459cba2caaa263be5224d --- lib/got_lib_diff.h +++ lib/got_lib_diff.h @@ -62,8 +62,8 @@ const struct got_error *got_diffreg_result_free_right( const struct got_error *got_diffreg_close(FILE *, char *, size_t, FILE *, char *, size_t); -const struct got_error *got_merge_diff3(int *, int, const char *, const char *, - const char *, const char *, const char *, const char *); +const struct got_error *got_merge_diff3(int *, int, FILE *, FILE *, FILE *, + const char *, const char *, const char *); const struct got_error *got_diff_files(struct got_diffreg_result **, FILE *, const char *, FILE *, const char *, int, int, int, FILE *); blob - 327fa4b95e7666dd758028cbf51f74aee94184b3 blob + 016b6dc14971cb46b8d7c725a70ebbaf4d909336 --- lib/worktree.c +++ lib/worktree.c @@ -728,25 +728,19 @@ check_file_contents_equal(int *same, FILE *f1, FILE *f } static const struct got_error * -check_files_equal(int *same, const char *f1_path, const char *f2_path) +check_files_equal(int *same, FILE *f1, FILE *f2) { - const struct got_error *err = NULL; struct stat sb; size_t size1, size2; - FILE *f1 = NULL, *f2 = NULL; *same = 1; - if (lstat(f1_path, &sb) != 0) { - err = got_error_from_errno2("lstat", f1_path); - goto done; - } + if (fstat(fileno(f1), &sb) != 0) + return got_error_from_errno("fstat"); size1 = sb.st_size; - if (lstat(f2_path, &sb) != 0) { - err = got_error_from_errno2("lstat", f2_path); - goto done; - } + if (fstat(fileno(f2), &sb) != 0) + return got_error_from_errno("fstat"); size2 = sb.st_size; if (size1 != size2) { @@ -754,48 +748,35 @@ check_files_equal(int *same, const char *f1_path, cons return NULL; } - f1 = fopen(f1_path, "r"); - if (f1 == NULL) - return got_error_from_errno2("fopen", f1_path); + if (fseek(f1, 0L, SEEK_SET) == -1) + return got_ferror(f1, GOT_ERR_IO); + if (fseek(f2, 0L, SEEK_SET) == -1) + return got_ferror(f2, GOT_ERR_IO); - f2 = fopen(f2_path, "r"); - if (f2 == NULL) { - err = got_error_from_errno2("fopen", f2_path); - goto done; - } - - err = check_file_contents_equal(same, f1, f2); -done: - if (f1 && fclose(f1) == EOF && err == NULL) - err = got_error_from_errno("fclose"); - if (f2 && fclose(f2) == EOF && err == NULL) - err = got_error_from_errno("fclose"); - - return err; + return check_file_contents_equal(same, f1, f2); } /* - * Perform a 3-way merge where the file at orig_path acts as the common - * ancestor, the file at deriv_path acts as the first derived version, - * and the file at ondisk_path acts as the second derived version. + * 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 */ static const struct got_error * merge_file(int *local_changes_subsumed, struct got_worktree *worktree, - const char *orig_path, const char *ondisk_path, - const char *path, uint16_t st_mode, const char *deriv_path, + FILE *f_orig, const char *ondisk_path, + const char *path, uint16_t st_mode, FILE *f_deriv, const char *label_orig, const char *label_deriv, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; int merged_fd = -1; - FILE *f_empty = NULL; - char *f_empty_path = NULL; + FILE *f_merged = NULL; char *merged_path = NULL, *base_path = NULL; int overlapcnt = 0; char *parent = NULL; - char *symlink_path = NULL; - FILE *symlinkf = NULL; + FILE *f = NULL; *local_changes_subsumed = 0; @@ -812,25 +793,8 @@ merge_file(int *local_changes_subsumed, struct got_wor if (err) goto done; - free(base_path); - if (asprintf(&base_path, "%s/got-merge-blob-orig", parent) == -1) { - err = got_error_from_errno("asprintf"); - base_path = NULL; - goto done; - } - - if (orig_path == NULL) { - /* - * If the file has no blob, this is an "add vs add" conflict, - * and we simply use an empty ancestor file to make both files - * appear in the merged result in their entirety. - */ - err = got_opentemp_named(&f_empty_path, &f_empty, 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. */ @@ -846,29 +810,46 @@ merge_file(int *local_changes_subsumed, struct got_wor base_path = NULL; goto done; } - err = got_opentemp_named(&symlink_path, &symlinkf, base_path); - if (err) + 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, symlinkf); + n = fwrite(target_path, 1, target_len, f); if (n != target_len) { - err = got_ferror(symlinkf, GOT_ERR_IO); + err = got_ferror(f, GOT_ERR_IO); goto done; } - if (fflush(symlinkf) == EOF) { - err = got_error_from_errno2("fflush", symlink_path); + 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, deriv_path, - orig_path ? orig_path : f_empty_path, - symlink_path ? symlink_path : ondisk_path, + err = got_merge_diff3(&overlapcnt, merged_fd, f_deriv, f_orig, f, label_deriv, label_orig, NULL); if (err) goto done; @@ -883,15 +864,22 @@ merge_file(int *local_changes_subsumed, struct got_wor goto done; } + f_merged = fdopen(merged_fd, "r"); + if (f_merged == NULL) { + err = got_error_from_errno("fdopen"); + goto done; + } + merged_fd = -1; + /* Check if a clean merge has subsumed all local changes. */ if (overlapcnt == 0) { - err = check_files_equal(local_changes_subsumed, deriv_path, - merged_path); + err = check_files_equal(local_changes_subsumed, f_deriv, + f_merged); if (err) goto done; } - if (fchmod(merged_fd, st_mode) != 0) { + if (fchmod(fileno(f_merged), st_mode) != 0) { err = got_error_from_errno2("fchmod", merged_path); goto done; } @@ -906,24 +894,14 @@ done: if (merged_path) unlink(merged_path); } - if (symlink_path) { - if (unlink(symlink_path) == -1 && err == NULL) - err = got_error_from_errno2("unlink", symlink_path); - } - if (symlinkf && fclose(symlinkf) == EOF && err == NULL) - err = got_error_from_errno2("fclose", symlink_path); - free(symlink_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_empty && fclose(f_empty) == EOF && err == NULL) + if (f_merged && fclose(f_merged) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(merged_path); free(base_path); - if (f_empty_path) { - if (unlink(f_empty_path) == -1 && err == NULL) - err = got_error_from_errno2("unlink", f_empty_path); - free(f_empty_path); - } free(parent); return err; } @@ -1157,8 +1135,18 @@ merge_blob(int *local_changes_subsumed, struct got_wor blob_orig); if (err) goto done; - free(base_path); + } else { + /* + * No common ancestor exists. This is an "add vs add" conflict + * and we simply use an empty ancestor file to make both files + * appear in the merged result in their entirety. + */ + f_orig = got_opentemp(); + if (f_orig == NULL) { + err = got_error_from_errno("got_opentemp"); + goto done; + } } if (asprintf(&base_path, "%s/got-merge-blob-deriv", parent) == -1) { @@ -1184,9 +1172,9 @@ merge_blob(int *local_changes_subsumed, struct got_wor goto done; } - err = merge_file(local_changes_subsumed, worktree, blob_orig_path, - ondisk_path, path, st_mode, blob_deriv_path, label_orig, - label_deriv, repo, progress_cb, progress_arg); + err = merge_file(local_changes_subsumed, worktree, f_orig, + ondisk_path, path, st_mode, f_deriv, 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"); @@ -7800,9 +7788,9 @@ unstage_hunks(struct got_object_id *staged_blob_id, goto done; err = merge_file(&local_changes_subsumed, worktree, - blob_base_path, ondisk_path, ie->path, + f_base, ondisk_path, ie->path, got_fileindex_perms_to_st(ie), - path_unstaged_content, label_orig, "unstaged", + f, label_orig, "unstaged", repo, progress_cb, progress_arg); } if (err)