Download raw body.
fix 'got patch' for patches which lack \n at EOF
If the patch file lacks a trailing newline just before end-of-file
then 'got patch' will exit with an "unexpected privsep message" error.
Regression test and fix below.
ok?
M lib/patch.c | 9+ 5-
M libexec/got-read-patch/got-read-patch.c | 2+ 2-
M regress/cmdline/patch.sh | 50+ 0-
3 files changed, 61 insertions(+), 7 deletions(-)
commit - a906b277aa501d5897960b8e9f4466450d91dcac
commit + d218513d2a6e949086ab5cfccb56f041a5d24e69
blob - edb26e01b7ce7ae6f0582ad4b4cb1a56c500e3d4
blob + f1fcd303993ffad10e3920c2e052f7bdf51b2175
--- lib/patch.c
+++ lib/patch.c
@@ -164,13 +164,13 @@ pushline(struct got_patch_hunk *h, const char *line, s
h->cap = newcap;
}
- if ((t = malloc(len - 1)) == NULL)
+ t = strdup(line + 1); /* skip the line type */
+ if (t == NULL)
return got_error_from_errno("malloc");
- memcpy(t, line + 1, len - 1); /* skip the line type */
h->lines[h->len].mode = *line;
h->lines[h->len].line = t;
- h->lines[h->len].len = len - 2; /* line type and trailing NUL */
+ h->lines[h->len].len = strlen(t);
h->len++;
return NULL;
}
@@ -300,8 +300,12 @@ recv_patch(struct imsgbuf *ibuf, int *done, struct got
goto done;
}
t = imsg.data;
+ if (memchr(t, '\0', datalen) == NULL) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ goto done;
+ }
/* at least one char */
- if (datalen < 2 || t[datalen-1] != '\0') {
+ if (datalen < 2) {
err = got_error(GOT_ERR_PRIVSEP_MSG);
goto done;
}
@@ -312,7 +316,7 @@ recv_patch(struct imsgbuf *ibuf, int *done, struct got
}
if (*t != '\\')
- err = pushline(h, t, datalen);
+ err = pushline(h, t, strlen(t));
else if (lastmode == '-')
h->old_nonl = 1;
else if (lastmode == '+')
blob - 14537c5cce57d708e10787a44cfd196c34bb6263
blob + bbb4fdeb0e8ad7491f1ffe1cec7450ea6bb923c2
--- libexec/got-read-patch/got-read-patch.c
+++ libexec/got-read-patch/got-read-patch.c
@@ -467,7 +467,7 @@ send_line(const char *line, size_t len)
}
iov[iovcnt].iov_base = (void *)line;
- iov[iovcnt].iov_len = len;
+ iov[iovcnt].iov_len = len + 1; /* send NUL terminator */
iovcnt++;
if (imsg_composev(&ibuf, GOT_IMSG_PATCH_LINE, 0, 0, -1,
@@ -585,7 +585,7 @@ parse_hunk(FILE *fp, int *done)
goto done;
}
- err = send_line(line, linelen);
+ err = send_line(line, strlen(line));
if (err)
goto done;
blob - e5504f42e6a08f89598536b78ff4c5ed56bfb461
blob + f41077edecd7463beacb0b7995d2081ff27c3bff
--- regress/cmdline/patch.sh
+++ regress/cmdline/patch.sh
@@ -2147,6 +2147,55 @@ test_patch_commit_keywords() {
test_done $testroot $ret
}
+test_patch_no_newline_at_end_of_patch() {
+ local testroot=`test_init patch_no_newline_at_end_of_patch`
+
+ 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
+--- alpha
++++ alpha
+@@ -1 +1 @@
+-alpha
++alpha is my favourite character
+EOF
+
+ head -n 4 $testroot/wt/patch > $testroot/wt/patch.noeol
+ tail -n 1 $testroot/wt/patch | tr -d '\n' >> $testroot/wt/patch.noeol
+
+ (cd $testroot/wt && got patch < patch.noeol) > $testroot/stdout
+ if [ $ret -ne 0 ]; then
+ test_done "$testroot" $ret
+ return 1
+ fi
+
+ echo 'M alpha' > $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done $testroot $ret
+ return 1
+ fi
+
+ echo 'alpha is my favourite character' > $testroot/wt/alpha.expected
+ cmp -s $testroot/wt/alpha.expected $testroot/wt/alpha
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/wt/alpha.expected $testroot/wt/alpha
+ test_done "$testroot" $ret
+ return 1
+ fi
+
+ test_done $testroot $ret
+}
+
test_parseargs "$@"
run_test test_patch_basic
run_test test_patch_dont_apply
@@ -2179,3 +2228,4 @@ run_test test_patch_newfile_xbit_git_diff
run_test test_patch_umask
run_test test_patch_remove_binary_file
run_test test_patch_commit_keywords
+run_test test_patch_no_newline_at_end_of_patch
fix 'got patch' for patches which lack \n at EOF