From 4950eed520ce3dbb786e33fe8a8dc48e492998b4 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 3 Aug 2014 01:44:08 +0000 Subject: [PATCH] git svn: info: correctly handle absolute path args Calling "git svn info $(pwd)" would hit: "Reading from filehandle failed at ..." errors due to improper prefixing and canonicalization. Strip the toplevel path from absolute filesystem paths to ensure downstream canonicalization routines are only exposed to paths tracked in git (or SVN). v2: Thanks to Andrej Manduch for originally noticing the issue and fixing my original version of this to handle more corner cases such as "/path/to/top/../top" and "/path/to/top/../top/file" as shown in the new test cases. v3: Fix pathname portability problems pointed out by Johannes Sixt with a hint from brian m. carlson. Cc: Johannes Sixt Cc: "brian m. carlson" Signed-off-by: Andrej Manduch Signed-off-by: Eric Wong --- git-svn.perl | 39 +++++++++++++++++++++++++++++++++------ t/t9119-git-svn-info.sh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index 1f41ee14b4..40565cd6eb 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1477,10 +1477,37 @@ sub cmd_commit_diff { } } - sub cmd_info { - my $path = canonicalize_path(defined($_[0]) ? $_[0] : "."); - my $fullpath = canonicalize_path($cmd_dir_prefix . $path); + my $path_arg = defined($_[0]) ? $_[0] : '.'; + my $path = $path_arg; + if (File::Spec->file_name_is_absolute($path)) { + $path = canonicalize_path($path); + + my $toplevel = eval { + my @cmd = qw/rev-parse --show-toplevel/; + command_oneline(\@cmd, STDERR => 0); + }; + + # remove $toplevel from the absolute path: + my ($vol, $dirs, $file) = File::Spec->splitpath($path); + my (undef, $tdirs, $tfile) = File::Spec->splitpath($toplevel); + my @dirs = File::Spec->splitdir($dirs); + my @tdirs = File::Spec->splitdir($tdirs); + pop @dirs if $dirs[-1] eq ''; + pop @tdirs if $tdirs[-1] eq ''; + push @dirs, $file; + push @tdirs, $tfile; + while (@tdirs && @dirs && $tdirs[0] eq $dirs[0]) { + shift @dirs; + shift @tdirs; + } + $dirs = File::Spec->catdir(@dirs); + $path = File::Spec->catpath($vol, $dirs); + + $path = canonicalize_path($path); + } else { + $path = canonicalize_path($cmd_dir_prefix . $path); + } if (exists $_[1]) { die "Too many arguments specified\n"; } @@ -1501,14 +1528,14 @@ sub cmd_info { # canonicalize_path() will return "" to make libsvn 1.5.x happy, $path = "." if $path eq ""; - my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) ); + my $full_url = canonicalize_url( add_path_to_url( $url, $path ) ); if ($_url) { print "$full_url\n"; return; } - my $result = "Path: $path\n"; + my $result = "Path: $path_arg\n"; $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir"; $result .= "URL: $full_url\n"; @@ -1539,7 +1566,7 @@ sub cmd_info { } my ($lc_author, $lc_rev, $lc_date_utc); - my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $fullpath); + my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $path); my $log = command_output_pipe(@args); my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; while (<$log>) { diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh index ff19695e77..f16f3234a1 100755 --- a/t/t9119-git-svn-info.sh +++ b/t/t9119-git-svn-info.sh @@ -74,6 +74,36 @@ test_expect_success 'info .' " test_cmp_info expected.info-dot actual.info-dot " +test_expect_success 'info $(pwd)' ' + (cd svnwc; svn info "$(pwd)") >expected.info-pwd && + (cd gitwc; git svn info "$(pwd)") >actual.info-pwd && + grep -v ^Path: expected.info-np && + grep -v ^Path: actual.info-np && + test_cmp_info expected.info-np actual.info-np && + test "$(sed -ne \"/^Path:/ s!/svnwc!!\" expected.info-pwd && + (cd gitwc; git svn info "$(pwd)/../gitwc") >actual.info-pwd && + grep -v ^Path: expected.info-np && + grep -v ^Path: actual.info-np && + test_cmp_info expected.info-np actual.info-np && + test "$(sed -ne \"/^Path:/ s!/svnwc!!\" expected.info-pwd && + (cd gitwc; git svn info "$(pwd)/../gitwc//file") >actual.info-pwd && + grep -v ^Path: expected.info-np && + grep -v ^Path: actual.info-np && + test_cmp_info expected.info-np actual.info-np && + test "$(sed -ne \"/^Path:/ s!/svnwc!!\"