diff options
-rwxr-xr-x | gitweb/gitweb.perl | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index d3816b884..d90291396 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2008,6 +2008,48 @@ sub git_get_link_target { return $link_target; } +# given link target, and the directory (basedir) the link is in, +# return target of link relative to top directory (top tree); +# return undef if it is not possible (including absolute links). +sub normalize_link_target { + my ($link_target, $basedir, $hash_base) = @_; + + # we can normalize symlink target only if $hash_base is provided + return unless $hash_base; + + # absolute symlinks (beginning with '/') cannot be normalized + return if (substr($link_target, 0, 1) eq '/'); + + # normalize link target to path from top (root) tree (dir) + my $path; + if ($basedir) { + $path = $basedir . '/' . $link_target; + } else { + # we are in top (root) tree (dir) + $path = $link_target; + } + + # remove //, /./, and /../ + my @path_parts; + foreach my $part (split('/', $path)) { + # discard '.' and '' + next if (!$part || $part eq '.'); + # handle '..' + if ($part eq '..') { + if (@path_parts) { + pop @path_parts; + } else { + # link leads outside repository (outside top dir) + return; + } + } else { + push @path_parts, $part; + } + } + $path = join('/', @path_parts); + + return $path; +} # print tree entry (row of git_tree), but without encompassing <tr> element sub git_print_tree_entry { @@ -2029,7 +2071,15 @@ sub git_print_tree_entry { if (S_ISLNK(oct $t->{'mode'})) { my $link_target = git_get_link_target($t->{'hash'}); if ($link_target) { - print " -> " . esc_path($link_target); + my $norm_target = normalize_link_target($link_target, $basedir, $hash_base); + if (defined $norm_target) { + print " -> " . + $cgi->a({-href => href(action=>"object", hash_base=>$hash_base, + file_name=>$norm_target), + -title => $norm_target}, esc_path($link_target)); + } else { + print " -> " . esc_path($link_target); + } } } print "</td>\n"; |