Git fork

apply: split quoted filename handling into new function

The new find_name_gnu() function handles new-style '--- "a/foo"'
patch header lines, leaving find_name() itself a bit less
daunting.

Functional change: do not clobber the p-value when there are not
enough path components in a quoted file name to honor it.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Jonathan Nieder and committed by
Junio C Hamano
bb7306b5 64fdc08d

+70 -33
+38 -30
builtin/apply.c
··· 416 return name; 417 } 418 419 static char *find_name(const char *line, char *def, int p_value, int terminate) 420 { 421 int len; 422 const char *start = NULL; 423 424 - if (p_value == 0) 425 - start = line; 426 - 427 if (*line == '"') { 428 - struct strbuf name = STRBUF_INIT; 429 - 430 - /* 431 - * Proposed "new-style" GNU patch/diff format; see 432 - * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 433 - */ 434 - if (!unquote_c_style(&name, line, NULL)) { 435 - char *cp; 436 - 437 - for (cp = name.buf; p_value; p_value--) { 438 - cp = strchr(cp, '/'); 439 - if (!cp) 440 - break; 441 - cp++; 442 - } 443 - if (cp) { 444 - /* name can later be freed, so we need 445 - * to memmove, not just return cp 446 - */ 447 - strbuf_remove(&name, 0, cp - name.buf); 448 - free(def); 449 - if (root) 450 - strbuf_insert(&name, 0, root, root_len); 451 - return squash_slash(strbuf_detach(&name, NULL)); 452 - } 453 - } 454 - strbuf_release(&name); 455 } 456 457 for (;;) { 458 char c = *line; 459
··· 416 return name; 417 } 418 419 + static char *find_name_gnu(const char *line, char *def, int p_value) 420 + { 421 + struct strbuf name = STRBUF_INIT; 422 + char *cp; 423 + 424 + /* 425 + * Proposed "new-style" GNU patch/diff format; see 426 + * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 427 + */ 428 + if (unquote_c_style(&name, line, NULL)) { 429 + strbuf_release(&name); 430 + return NULL; 431 + } 432 + 433 + for (cp = name.buf; p_value; p_value--) { 434 + cp = strchr(cp, '/'); 435 + if (!cp) { 436 + strbuf_release(&name); 437 + return NULL; 438 + } 439 + cp++; 440 + } 441 + 442 + /* name can later be freed, so we need 443 + * to memmove, not just return cp 444 + */ 445 + strbuf_remove(&name, 0, cp - name.buf); 446 + free(def); 447 + if (root) 448 + strbuf_insert(&name, 0, root, root_len); 449 + return squash_slash(strbuf_detach(&name, NULL)); 450 + } 451 + 452 static char *find_name(const char *line, char *def, int p_value, int terminate) 453 { 454 int len; 455 const char *start = NULL; 456 457 if (*line == '"') { 458 + char *name = find_name_gnu(line, def, p_value); 459 + if (name) 460 + return name; 461 } 462 463 + if (p_value == 0) 464 + start = line; 465 for (;;) { 466 char c = *line; 467
+32 -3
t/t4120-apply-popt.sh
··· 10 test_expect_success setup ' 11 mkdir sub && 12 echo A >sub/file1 && 13 - cp sub/file1 file1 && 14 git add sub/file1 && 15 echo B >sub/file1 && 16 git diff >patch.file && 17 - rm sub/file1 && 18 - rmdir sub 19 ' 20 21 test_expect_success 'apply git diff with -p2' ' 22 git apply -p2 patch.file 23 ' 24 25 test_expect_success 'apply with too large -p' ' 26 test_must_fail git apply --stat -p3 patch.file 2>err && 27 grep "removing 3 leading" err 28 ' 29
··· 10 test_expect_success setup ' 11 mkdir sub && 12 echo A >sub/file1 && 13 + cp sub/file1 file1.saved && 14 git add sub/file1 && 15 echo B >sub/file1 && 16 git diff >patch.file && 17 + git checkout -- sub/file1 && 18 + git mv sub süb && 19 + echo B >süb/file1 && 20 + git diff >patch.escaped && 21 + grep "[\]" patch.escaped && 22 + rm süb/file1 && 23 + rmdir süb 24 ' 25 26 test_expect_success 'apply git diff with -p2' ' 27 + cp file1.saved file1 && 28 git apply -p2 patch.file 29 ' 30 31 test_expect_success 'apply with too large -p' ' 32 + cp file1.saved file1 && 33 test_must_fail git apply --stat -p3 patch.file 2>err && 34 + grep "removing 3 leading" err 35 + ' 36 + 37 + test_expect_success 'apply (-p2) traditional diff with funny filenames' ' 38 + cat >patch.quotes <<-\EOF && 39 + diff -u "a/"sub/file1 "b/"sub/file1 40 + --- "a/"sub/file1 41 + +++ "b/"sub/file1 42 + @@ -1 +1 @@ 43 + -A 44 + +B 45 + EOF 46 + echo B >expected && 47 + 48 + cp file1.saved file1 && 49 + git apply -p2 patch.quotes && 50 + test_cmp expected file1 51 + ' 52 + 53 + test_expect_success 'apply with too large -p and fancy filename' ' 54 + cp file1.saved file1 && 55 + test_must_fail git apply --stat -p3 patch.escaped 2>err && 56 grep "removing 3 leading" err 57 ' 58