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 <j6t@kdbg.org> Cc: "brian m. carlson" <sandals@crustytoothpaste.net> Signed-off-by: Andrej Manduch <amanduch@gmail.com> Signed-off-by: Eric Wong <normalperson@yhbt.net>

Eric Wong committed Aug 3, 2014 at 01:44 UTC 4950eed520ce3dbb786e33fe8a8dc48e492998b4
2 files changed +63 -6
git-svn.perl
+33 -6
@@ -1477,10 +1477,37 @@ sub cmd_commit_diff {
1477 }
1478 }
1479
1480 -
1480 sub cmd_info {
1482 - my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
1483 - my $fullpath = canonicalize_path($cmd_dir_prefix . $path);
1481 + my $path_arg = defined($_[0]) ? $_[0] : '.';
1482 + my $path = $path_arg;
1483 + if (File::Spec->file_name_is_absolute($path)) {
1484 + $path = canonicalize_path($path);
1485 +
1486 + my $toplevel = eval {
1487 + my @cmd = qw/rev-parse --show-toplevel/;
1488 + command_oneline(\@cmd, STDERR => 0);
1489 + };
1490 +
1491 + # remove $toplevel from the absolute path:
1492 + my ($vol, $dirs, $file) = File::Spec->splitpath($path);
1493 + my (undef, $tdirs, $tfile) = File::Spec->splitpath($toplevel);
1494 + my @dirs = File::Spec->splitdir($dirs);
1495 + my @tdirs = File::Spec->splitdir($tdirs);
1496 + pop @dirs if $dirs[-1] eq '';
1497 + pop @tdirs if $tdirs[-1] eq '';
1498 + push @dirs, $file;
1499 + push @tdirs, $tfile;
1500 + while (@tdirs && @dirs && $tdirs[0] eq $dirs[0]) {
1501 + shift @dirs;
1502 + shift @tdirs;
1503 + }
1504 + $dirs = File::Spec->catdir(@dirs);
1505 + $path = File::Spec->catpath($vol, $dirs);
1506 +
1507 + $path = canonicalize_path($path);
1508 + } else {
1509 + $path = canonicalize_path($cmd_dir_prefix . $path);
1510 + }
1511 if (exists $_[1]) {
1512 die "Too many arguments specified\n";
1513 }
@@ -1501,14 +1528,14 @@ sub cmd_info {
1528 # canonicalize_path() will return "" to make libsvn 1.5.x happy,
1529 $path = "." if $path eq "";
1530
1504 - my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) );
1531 + my $full_url = canonicalize_url( add_path_to_url( $url, $path ) );
1532
1533 if ($_url) {
1534 print "$full_url\n";
1535 return;
1536 }
1537
1511 - my $result = "Path: $path\n";
1538 + my $result = "Path: $path_arg\n";
1539 $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir";
1540 $result .= "URL: $full_url\n";
1541
@@ -1539,7 +1566,7 @@ sub cmd_info {
1566 }
1567
1568 my ($lc_author, $lc_rev, $lc_date_utc);
1542 - my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $fullpath);
1569 + my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $path);
1570 my $log = command_output_pipe(@args);
1571 my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
1572 while (<$log>) {
t/t9119-git-svn-info.sh
+30
@@ -74,6 +74,36 @@ test_expect_success 'info .' "
74 test_cmp_info expected.info-dot actual.info-dot
75 "
76
77 +test_expect_success 'info $(pwd)' '
78 + (cd svnwc; svn info "$(pwd)") >expected.info-pwd &&
79 + (cd gitwc; git svn info "$(pwd)") >actual.info-pwd &&
80 + grep -v ^Path: <expected.info-pwd >expected.info-np &&
81 + grep -v ^Path: <actual.info-pwd >actual.info-np &&
82 + test_cmp_info expected.info-np actual.info-np &&
83 + test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \
84 + "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)"
85 + '
86 +
87 +test_expect_success 'info $(pwd)/../___wc' '
88 + (cd svnwc; svn info "$(pwd)/../svnwc") >expected.info-pwd &&
89 + (cd gitwc; git svn info "$(pwd)/../gitwc") >actual.info-pwd &&
90 + grep -v ^Path: <expected.info-pwd >expected.info-np &&
91 + grep -v ^Path: <actual.info-pwd >actual.info-np &&
92 + test_cmp_info expected.info-np actual.info-np &&
93 + test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \
94 + "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)"
95 + '
96 +
97 +test_expect_success 'info $(pwd)/../___wc//file' '
98 + (cd svnwc; svn info "$(pwd)/../svnwc//file") >expected.info-pwd &&
99 + (cd gitwc; git svn info "$(pwd)/../gitwc//file") >actual.info-pwd &&
100 + grep -v ^Path: <expected.info-pwd >expected.info-np &&
101 + grep -v ^Path: <actual.info-pwd >actual.info-np &&
102 + test_cmp_info expected.info-np actual.info-np &&
103 + test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \
104 + "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)"
105 + '
106 +
107 test_expect_success 'info --url .' '
108 test "$(cd gitwc; git svn info --url .)" = "$quoted_svnrepo"
109 '