Commit Diff


commit - dd6c3779b6533ba060e07dc68fdaf6b1e0e49d30
commit + 5b67f96efbfbf2e5a3f75f6ab91e45dd3013c77f
blob - 478ade488151adafcb6e73d746f9a7ba2e84acdf
blob + 71695e64b89d1a1b07daab61fb55d3c1883760ec
--- lib/patch.c
+++ lib/patch.c
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/uio.h>
 
 #include <errno.h>
@@ -456,7 +457,15 @@ patch_file(struct got_patch *p, const char *path, FILE
 		}
 	}
 
-	if (!feof(orig))
+	
+	if (p->new == NULL) {
+		struct stat sb;
+
+		if (fstat(fileno(orig), &sb) == -1)
+			err = got_error_from_errno("fstat");
+		else if (sb.st_size != copypos)
+			err = got_error(GOT_ERR_PATCH_DONT_APPLY);
+	} else if (!feof(orig))
 		err = copy(tmp, orig, copypos, -1);
 
 done:
@@ -584,16 +593,6 @@ apply_patch(struct got_worktree *worktree, struct got_
 	if (err)
 		goto done;
 
-	if (p->old != NULL && p->new == NULL) {
-		/*
-		 * special case: delete a file.  don't try to match
-		 * the lines but just schedule the removal.
-		 */
-		err = got_worktree_schedule_delete(worktree, &oldpaths,
-		    0, NULL, delete_cb, delete_arg, repo, 0, 0);
-		goto done;
-	}
-
 	if (asprintf(&template, "%s/got-patch",
 	    got_worktree_get_root_path(worktree)) == -1) {
 		err = got_error_from_errno(template);
@@ -607,6 +606,12 @@ apply_patch(struct got_worktree *worktree, struct got_
 	if (err)
 		goto done;
 
+	if (p->old != NULL && p->new == NULL) {
+		err = got_worktree_schedule_delete(worktree, &oldpaths,
+		    0, NULL, delete_cb, delete_arg, repo, 0, 0);
+		goto done;
+	}
+
 	if (rename(tmppath, newpath) == -1) {
 		err = got_error_from_errno3("rename", tmppath, newpath);
 		goto done;
blob - 36c9ef55d45f97cd15c3f787c35d5a7623def72a
blob + 9a300a816a79b7eacef07263e7bd7cbce706ae25
--- regress/cmdline/patch.sh
+++ regress/cmdline/patch.sh
@@ -436,9 +436,47 @@ EOF
 	if [ $ret -ne 0 ]; then
 		diff -u $testroot/stderr.expected $testroot/stderr
 		test_done $testroot $ret
+		return 1
+	fi
+
+	# try to delete a file with a patch that doesn't match
+	jot 100 > $testroot/wt/numbers
+	(cd $testroot/wt && got add numbers && got commit -m 'add numbers') \
+		>/dev/null
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		test_done $testroot $ret
+		return 1
+	fi
+
+	cat <<EOF > $testroot/wt/patch
+--- numbers
++++ /dev/null
+@@ -1,9 +0,0 @@
+-1
+-2
+-3
+-4
+-5
+-6
+-7
+-8
+-9
+EOF
+
+	(cd $testroot/wt && got patch patch) > /dev/null 2> $testroot/stderr
+	ret=$?
+	if [ $ret -eq 0 ]; then # should fail
+		test_done $testroot 1
 		return 1
 	fi
 
+	echo "got: patch doesn't apply" > $testroot/stderr.expected
+	cmp -s $testroot/stderr.expected $testroot/stderr
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stderr.expected $testroot/stderr
+	fi
 	test_done $testroot $ret
 }