From 1d542a5487f788874f18cca0d23b7b680fa04119 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Fri, 30 Jun 2017 10:49:09 +0100 Subject: [PATCH 1/4] add -i: move unquote_path() to Git.pm Move unquote_path() from git-add--interactive to Git.pm so it can be used by other scripts. Note this is a straight copy, it does not handle '\a'. That will be fixed in the next commit. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- git-add--interactive.perl | 43 +------------------------------ perl/Git.pm | 53 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 709a5f6ce6..7ea3591edc 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -3,7 +3,7 @@ use 5.008; use strict; use warnings; -use Git; +use Git qw(unquote_path); use Git::I18N; binmode(STDOUT, ":raw"); @@ -175,47 +175,6 @@ if (!defined $GIT_DIR) { } chomp($GIT_DIR); -my %cquote_map = ( - "b" => chr(8), - "t" => chr(9), - "n" => chr(10), - "v" => chr(11), - "f" => chr(12), - "r" => chr(13), - "\\" => "\\", - "\042" => "\042", -); - -sub unquote_path { - local ($_) = @_; - my ($retval, $remainder); - if (!/^\042(.*)\042$/) { - return $_; - } - ($_, $retval) = ($1, ""); - while (/^([^\\]*)\\(.*)$/) { - $remainder = $2; - $retval .= $1; - for ($remainder) { - if (/^([0-3][0-7][0-7])(.*)$/) { - $retval .= chr(oct($1)); - $_ = $2; - last; - } - if (/^([\\\042btnvfr])(.*)$/) { - $retval .= $cquote_map{$1}; - $_ = $2; - last; - } - # This is malformed -- just return it as-is for now. - return $_[0]; - } - $_ = $remainder; - } - $retval .= $_; - return $retval; -} - sub refresh { my $fh; open $fh, 'git update-index --refresh |' diff --git a/perl/Git.pm b/perl/Git.pm index bfce1f795d..cf7a7e6a51 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -61,7 +61,8 @@ require Exporter; remote_refs prompt get_tz_offset get_record credential credential_read credential_write - temp_acquire temp_is_locked temp_release temp_reset temp_path); + temp_acquire temp_is_locked temp_release temp_reset temp_path + unquote_path); =head1 DESCRIPTION @@ -1451,6 +1452,56 @@ sub prefix_lines { return $string; } +=item unquote_path ( PATH ) + +Unquote a quoted path containing c-escapes as returned by ls-files etc. +when not using -z or when parsing the output of diff -u. + +=cut + +{ + my %cquote_map = ( + "b" => chr(8), + "t" => chr(9), + "n" => chr(10), + "v" => chr(11), + "f" => chr(12), + "r" => chr(13), + "\\" => "\\", + "\042" => "\042", + ); + + sub unquote_path { + local ($_) = @_; + my ($retval, $remainder); + if (!/^\042(.*)\042$/) { + return $_; + } + ($_, $retval) = ($1, ""); + while (/^([^\\]*)\\(.*)$/) { + $remainder = $2; + $retval .= $1; + for ($remainder) { + if (/^([0-3][0-7][0-7])(.*)$/) { + $retval .= chr(oct($1)); + $_ = $2; + last; + } + if (/^([\\\042btnvfr])(.*)$/) { + $retval .= $cquote_map{$1}; + $_ = $2; + last; + } + # This is malformed -- just return it as-is for now. + return $_[0]; + } + $_ = $remainder; + } + $retval .= $_; + return $retval; + } +} + =item get_comment_line_char ( ) Gets the core.commentchar configuration value. From 4cebfac94412ccbd077c6776f7c8db1914bafde2 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Fri, 30 Jun 2017 10:49:10 +0100 Subject: [PATCH 2/4] Git::unquote_path(): handle '\a' unquote_path() does not handle quoted paths containing '\a', even though quote.c::unquote_c_style() does, and quote.c:sq_lookup[] tells quote.c::sq_must_quote() that '\007' must be quoted as '\a'. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- perl/Git.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/perl/Git.pm b/perl/Git.pm index cf7a7e6a51..3179e6efb2 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -1461,6 +1461,7 @@ when not using -z or when parsing the output of diff -u. { my %cquote_map = ( + "a" => chr(7), "b" => chr(8), "t" => chr(9), "n" => chr(10), @@ -1487,7 +1488,7 @@ when not using -z or when parsing the output of diff -u. $_ = $2; last; } - if (/^([\\\042btnvfr])(.*)$/) { + if (/^([\\\042abtnvfr])(.*)$/) { $retval .= $cquote_map{$1}; $_ = $2; last; From d5f28b724192e9172d0a013dd7b2ca20fd1bbb9b Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Fri, 30 Jun 2017 10:49:11 +0100 Subject: [PATCH 3/4] Git::unquote_path(): throw an exception on bad path This is what the other routines in Git.pm do if there's an error. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- perl/Git.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index 3179e6efb2..f4b56e6d4d 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -1493,8 +1493,8 @@ when not using -z or when parsing the output of diff -u. $_ = $2; last; } - # This is malformed -- just return it as-is for now. - return $_[0]; + # This is malformed + throw Error::Simple("invalid quoted path $_[0]"); } $_ = $remainder; } From 3f9c637ec7c28dc9de5937b45334ee11875e9fe8 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Fri, 30 Jun 2017 10:49:12 +0100 Subject: [PATCH 4/4] t9700: add tests for Git::unquote_path() Check that unquote_path() handles spaces and escape sequences properly. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- t/t9700/test.pl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 1b75c91965..34cd01366f 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -133,6 +133,13 @@ close TEMPFILE3; unlink $tmpfile3; chdir($abs_repo_dir); +# unquoting paths +is(Git::unquote_path('abc'), 'abc', 'unquote unquoted path'); +is(Git::unquote_path('"abc def"'), 'abc def', 'unquote simple quoted path'); +is(Git::unquote_path('"abc\"\\\\ \a\b\t\n\v\f\r\001\040"'), + "abc\"\\ \x07\x08\x09\x0a\x0b\x0c\x0d\x01 ", + 'unquote escape sequences'); + printf "1..%d\n", Test::More->builder->current_test; my $is_passing = eval { Test::More->is_passing };