got patch: don't loose the x bit when merging with diff3 This fixes a regression introduced with the diff3 merge: files merged this way have their permissions resetted after patch. The issue is due the fact that patch_file looks at a temporary files and not at the original "old file". Reported by and ok stsp@
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
diff --git a/lib/patch.c b/lib/patch.c
index 6b6915f..2cd5efa 100644
--- a/lib/patch.c
+++ b/lib/patch.c
@@ -469,7 +469,7 @@ apply_hunk(FILE *tmp, struct got_patch_hunk *h, int *lineno)
}
static const struct got_error *
-patch_file(struct got_patch *p, FILE *orig, FILE *tmp, mode_t *mode)
+patch_file(struct got_patch *p, FILE *orig, FILE *tmp)
{
const struct got_error *err = NULL;
struct got_patch_hunk *h;
@@ -489,7 +489,6 @@ patch_file(struct got_patch *p, FILE *orig, FILE *tmp, mode_t *mode)
if (fstat(fileno(orig), &sb) == -1)
return got_error_from_errno("fstat");
- *mode = sb.st_mode;
copypos = 0;
STAILQ_FOREACH(h, &p->head, entries) {
@@ -651,6 +650,7 @@ apply_patch(int *overlapcnt, struct got_worktree *worktree,
struct patch_args *pa, got_cancel_cb cancel_cb, void *cancel_arg)
{
const struct got_error *err = NULL;
+ struct stat sb;
int do_merge = 0, file_renamed = 0;
char *oldlabel = NULL, *newlabel = NULL, *anclabel = NULL;
char *oldpath = NULL, *newpath = NULL;
@@ -698,9 +698,16 @@ apply_patch(int *overlapcnt, struct got_worktree *worktree,
goto done;
}
- if (p->old != NULL && (oldfile = fopen(oldpath, "r")) == NULL) {
- err = got_error_from_errno2("open", oldpath);
- goto done;
+ if (p->old != NULL) {
+ if ((oldfile = fopen(oldpath, "r")) == NULL) {
+ err = got_error_from_errno2("open", oldpath);
+ goto done;
+ }
+ if (fstat(fileno(oldfile), &sb) == -1) {
+ err = got_error_from_errno2("fstat", oldpath);
+ goto done;
+ }
+ mode = sb.st_mode;
}
err = got_opentemp_named(&tmppath, &tmpfile, template);
@@ -708,7 +715,7 @@ apply_patch(int *overlapcnt, struct got_worktree *worktree,
goto done;
outpath = tmppath;
outfd = fileno(tmpfile);
- err = patch_file(p, afile != NULL ? afile : oldfile, tmpfile, &mode);
+ err = patch_file(p, afile != NULL ? afile : oldfile, tmpfile);
if (err)
goto done;
diff --git a/regress/cmdline/patch.sh b/regress/cmdline/patch.sh
index a7ff83e..c16e62c 100755
--- a/regress/cmdline/patch.sh
+++ b/regress/cmdline/patch.sh
@@ -1458,6 +1458,7 @@ test_patch_merge_simple() {
fi
jot 10 > $testroot/wt/numbers
+ chmod +x $testroot/wt/numbers
(cd $testroot/wt && got add numbers && got commit -m +numbers) \
> /dev/null
ret=$?
@@ -1507,6 +1508,14 @@ test_patch_merge_simple() {
ret=$?
if [ $ret -ne 0 ]; then
diff -u $testroot/wt/numbers $testroot/wt/numbers.expected
+ test_done $testroot $ret
+ return 1
+ fi
+
+ test -x $testroot/wt/numbers
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "numbers lost the executable bit" >&2
fi
test_done $testroot $ret
}