Download raw body.
got patch: check x-bit for new files
Quick recap from IRC:
I recently shared a diff with a new file that had the x-bit set, and
stsp reported that `got patch` failed to set this when applying the
patch.
The problem was, we only carry over file modes from currently versioned
files on disk. The below diff makes `got patch` parse `{got,git} diff`
patches for file perms so that we apply the x-bit to new files. Includes
regress for both got and git diffs.
diff /home/mark/src/got
commit - 6f04a73d17761092a3a7ab07632cd1a89d4bfd21
path + /home/mark/src/got
blob - 28d77bb457c59dd0fa56e815055a611a3c6fdd07
file + lib/got_lib_privsep.h
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
@@ -641,6 +641,7 @@ struct got_imsg_remotes {
*/
struct got_imsg_patch {
int git;
+ int xbit;
char old[PATH_MAX];
char new[PATH_MAX];
char cid[41];
blob - 4b795cc39551259dc64fe67a92381bb2c0591143
file + lib/patch.c
--- lib/patch.c
+++ lib/patch.c
@@ -74,6 +74,7 @@ struct got_patch_hunk {
STAILQ_HEAD(got_patch_hunk_head, got_patch_hunk);
struct got_patch {
+ int xbit;
char *old;
char *new;
char cid[41];
@@ -196,6 +197,8 @@ recv_patch(struct imsgbuf *ibuf, int *done, struct got
if (*patch.blob != '\0')
strlcpy(p->blob, patch.blob, sizeof(p->blob));
+ p->xbit = patch.xbit;
+
/* automatically set strip=1 for git-style diffs */
if (strip == -1 && patch.git &&
(*patch.old == '\0' || !strncmp(patch.old, "a/", 2)) &&
@@ -833,7 +836,8 @@ apply_patch(int *overlapcnt, struct got_worktree *work
goto done;
}
mode = sb.st_mode;
- }
+ } else if (p->xbit)
+ mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
err = got_opentemp_named(&tmppath, &tmpfile, template);
if (err)
blob - 73996be84412da8b6da8967a3b861c8e404900d5
file + libexec/got-read-patch/got-read-patch.c
--- libexec/got-read-patch/got-read-patch.c
+++ libexec/got-read-patch/got-read-patch.c
@@ -62,7 +62,7 @@ struct imsgbuf ibuf;
static const struct got_error *
send_patch(const char *oldname, const char *newname, const char *commitid,
- const char *blob, int git)
+ const char *blob, const int xbit, int git)
{
struct got_imsg_patch p;
@@ -80,6 +80,7 @@ send_patch(const char *oldname, const char *newname, c
if (blob != NULL)
strlcpy(p.blob, blob, sizeof(p.blob));
+ p.xbit = xbit;
p.git = git;
if (imsg_compose(&ibuf, GOT_IMSG_PATCH, 0, 0, -1, &p, sizeof(p)) == -1)
return got_error_from_errno("imsg_compose GOT_IMSG_PATCH");
@@ -127,6 +128,18 @@ filename(const char *at, char **name)
return NULL;
}
+static int
+filexbit(const char *line)
+{
+ char *m;
+
+ m = strchr(line, '(');
+ if (m && !strncmp(m + 1, "mode ", 5))
+ return strncmp(m + 6, "755", 3) == 0;
+
+ return 0;
+}
+
static const struct got_error *
blobid(const char *line, char **blob, int git)
{
@@ -199,7 +212,7 @@ find_diff(int *done, int *next, FILE *fp, int git, con
char *line = NULL;
size_t linesize = 0;
ssize_t linelen;
- int create, rename = 0;
+ int create, rename = 0, xbit = 0;
*done = 0;
*next = 0;
@@ -218,6 +231,8 @@ find_diff(int *done, int *next, FILE *fp, int git, con
} else if (!strncmp(line, "+++ ", 4)) {
free(new);
err = filename(line+4, &new);
+ } else if (!strncmp(line, "blob + ", 7)) {
+ xbit = filexbit(line);
} else if (!git && !strncmp(line, "blob - ", 7)) {
free(blob);
err = blobid(line + 7, &blob, git);
@@ -226,6 +241,8 @@ find_diff(int *done, int *next, FILE *fp, int git, con
err = filename(line + 10, &new);
} else if (git && !strncmp(line, "similarity index 100%", 21))
rename = 1;
+ else if (git && !strncmp(line, "new file mode 100", 17))
+ xbit = strncmp(line + 17, "755", 3) == 0;
else if (git && !strncmp(line, "index ", 6)) {
free(blob);
err = blobid(line + 6, &blob, git);
@@ -248,7 +265,7 @@ find_diff(int *done, int *next, FILE *fp, int git, con
if (rename && old != NULL && new != NULL) {
*done = 1;
err = send_patch(old, new, commitid,
- blob, git);
+ blob, xbit, git);
break;
}
@@ -259,7 +276,7 @@ find_diff(int *done, int *next, FILE *fp, int git, con
err = got_error(GOT_ERR_PATCH_MALFORMED);
else
err = send_patch(old, new, commitid,
- blob, git);
+ blob, xbit, git);
if (err)
break;
blob - 1854b36c0fa1e88ead530f05e4b4011f623a055c
file + regress/cmdline/patch.sh
--- regress/cmdline/patch.sh
+++ regress/cmdline/patch.sh
@@ -1763,6 +1763,93 @@ EOF
test_done $testroot $ret
}
+test_patch_newfile_xbit_got_diff() {
+ local testroot=`test_init patch_newfile_xbit`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ test_done $testroot $ret
+ return 1
+ fi
+
+ cat <<EOF > $testroot/wt/patch
+blob - /dev/null
+blob + abcdef0123456789abcdef012345678901234567 (mode 755)
+--- /dev/null
++++ xfile
+@@ -0,0 +1,1 @@
++xfile
+EOF
+
+ (cd $testroot/wt && got patch patch) > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ test_done $testroot $ret
+ return 1
+ fi
+
+ if [ ! -x $testroot/wt/xfile ]; then
+ echo "failed to set xbit on newfile" >&2
+ test_done $testroot 1
+ return 1
+ fi
+
+ echo xfile > $testroot/wt/xfile.expected
+ cmp -s $testroot/wt/xfile $testroot/wt/xfile.expected
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "fail"
+ diff -u $testroot/wt/xfile $testroot/wt/xfile.expected
+ fi
+
+ test_done $testroot $ret
+}
+
+test_patch_newfile_xbit_git_diff() {
+ local testroot=`test_init patch_newfile_xbit`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ test_done $testroot $ret
+ return 1
+ fi
+
+ cat <<EOF > $testroot/wt/patch
+diff --git a/xfile b/xfile
+new file mode 100755
+index 00000000..abcdef01
+--- /dev/null
++++ b/xfile
+@@ -0,0 +1,1 @@
++xfile
+EOF
+
+ (cd $testroot/wt && got patch patch) > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ test_done $testroot $ret
+ return 1
+ fi
+
+ if [ ! -x $testroot/wt/xfile ]; then
+ echo "failed to set xbit on newfile" >&2
+ test_done $testroot 1
+ return 1
+ fi
+
+ echo xfile > $testroot/wt/xfile.expected
+ cmp -s $testroot/wt/xfile $testroot/wt/xfile.expected
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "fail"
+ diff -u $testroot/wt/xfile $testroot/wt/xfile.expected
+ fi
+
+ test_done $testroot $ret
+}
+
test_parseargs "$@"
run_test test_patch_basic
run_test test_patch_dont_apply
@@ -1789,3 +1876,5 @@ run_test test_patch_merge_base_provided
run_test test_patch_merge_conflict
run_test test_patch_merge_unknown_blob
run_test test_patch_merge_reverse
+run_test test_patch_newfile_xbit_got_diff
+run_test test_patch_newfile_xbit_git_diff
--
Mark Jamsek <fnc.bsdbox.org>
GPG: F2FF 13DE 6A06 C471 CA80 E6E2 2930 DC66 86EE CF68
got patch: check x-bit for new files