commit - 67a666476ff7ffc6e95f7d9b994a8f7b01cb86e5
commit + db59069162efd1ccd4f236abe7d8eb3ca4b791e4
blob - b26da2a0b727f30ffdba6e4970dafa32b3856f53
blob + f17dddcabf8aa19fd01c17dec68dc1a8ec2dd748
--- lib/buf.c
+++ lib/buf.c
* 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;
}
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
};
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
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)
* 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;
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
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
}
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) {
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;
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.
*/
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;
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;
}
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;
}
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) {
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");
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)