X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/34def293ab70a0341c38227c54e04b0844a6c58287bc7b6294e319ea90bdedd2..76773709652d84c08c604d5c8238f3815e1c2ab33a5c24f2c9bfd9d091b4608b:/gitweb.perl diff --git a/gitweb.perl b/gitweb.perl index 64af897..0f4c1c3 100755 --- a/gitweb.perl +++ b/gitweb.perl @@ -212,19 +212,9 @@ if (defined $project) { } } +# We have to handle those containing any characters: our $file_name = $cgi->param('f'); -if (defined $file_name) { - if (!validate_input($file_name)) { - die_error(undef, "Invalid file parameter"); - } -} - our $file_parent = $cgi->param('fp'); -if (defined $file_parent) { - if (!validate_input($file_parent)) { - die_error(undef, "Invalid file parent parameter"); - } -} our $hash = $cgi->param('h'); if (defined $hash) { @@ -300,11 +290,12 @@ sub evaluate_path_info { $pathname =~ s,^/+,,; if (!$pathname || substr($pathname, -1) eq "/") { $action ||= "tree"; + $pathname =~ s,/$,,; } else { $action ||= "blob_plain"; } $hash_base ||= validate_input($refname); - $file_name ||= validate_input($pathname); + $file_name ||= $pathname; } elsif (defined $refname) { # we got "project.git/branch" $action ||= "shortlog"; @@ -415,7 +406,7 @@ sub validate_input { # correct, but quoted slashes look too horrible in bookmarks sub esc_param { my $str = shift; - $str =~ s/([^A-Za-z0-9\-_.~();\/;?:@&=])/sprintf("%%%02X", ord($1))/eg; + $str =~ s/([^A-Za-z0-9\-_.~()\/:@])/sprintf("%%%02X", ord($1))/eg; $str =~ s/\+/%2B/g; $str =~ s/ /\+/g; return $str; @@ -717,6 +708,7 @@ sub git_get_project_config { sub git_get_hash_by_path { my $base = shift; my $path = shift || return undef; + my $type = shift; my $tree = $base; @@ -727,6 +719,10 @@ sub git_get_hash_by_path { #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/; + if (defined $type && $type ne $2) { + # type doesn't match + return undef; + } return $3; } @@ -746,7 +742,7 @@ sub git_get_project_description { sub git_get_project_url_list { my $path = shift; - open my $fd, "$projectroot/$path/cloneurl" or return undef; + open my $fd, "$projectroot/$path/cloneurl" or return; my @git_project_url_list = map { chomp; $_ } <$fd>; close $fd; @@ -1134,7 +1130,8 @@ sub parse_ls_tree_line ($;%) { ## parse to array of hashes functions sub git_get_refs_list { - my $ref_dir = shift; + my $type = shift || ""; + my %refs; my @reflist; my @refs; @@ -1142,14 +1139,21 @@ sub git_get_refs_list { or return; while (my $line = <$fd>) { chomp $line; - if ($line =~ m/^([0-9a-fA-F]{40})\t$ref_dir\/?([^\^]+)$/) { - push @refs, { hash => $1, name => $2 }; - } elsif ($line =~ m/^[0-9a-fA-F]{40}\t$ref_dir\/?(.*)\^\{\}$/ && - $1 eq $refs[-1]{'name'}) { - # most likely a tag is followed by its peeled - # (deref) one, and when that happens we know the - # previous one was of type 'tag'. - $refs[-1]{'type'} = "tag"; + if ($line =~ m/^([0-9a-fA-F]{40})\trefs\/($type\/?([^\^]+))(\^\{\})?$/) { + if (defined $refs{$1}) { + push @{$refs{$1}}, $2; + } else { + $refs{$1} = [ $2 ]; + } + + if (! $4) { # unpeeled, direct reference + push @refs, { hash => $1, name => $3 }; # without type + } elsif ($3 eq $refs[-1]{'name'}) { + # most likely a tag is followed by its peeled + # (deref) one, and when that happens we know the + # previous one was of type 'tag'. + $refs[-1]{'type'} = "tag"; + } } } close $fd; @@ -1165,7 +1169,7 @@ sub git_get_refs_list { } # sort refs by age @reflist = sort {$b->{'epoch'} <=> $a->{'epoch'}} @reflist; - return \@reflist; + return (\@reflist, \%refs); } ## ---------------------------------------------------------------------- @@ -1268,7 +1272,7 @@ sub git_header_html { if (defined $action) { $title .= "/$action"; if (defined $file_name) { - $title .= " - $file_name"; + $title .= " - " . esc_html($file_name); if ($action eq "tree" && $file_name !~ m|/$|) { $title .= "/"; } @@ -1505,12 +1509,15 @@ sub git_print_page_path { my $fullname = ''; print "
| " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " . - $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . + $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . " | " . + $cgi->a({-href => href(action=>"tree", hash=>$tag{'name'}, hash_base=>$tag{'name'})}, "tree") . " | \n" . ""; } @@ -2266,7 +2268,8 @@ sub git_project_list { "" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary") . " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"shortlog")}, "shortlog") . " | " . - $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . + $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " . + $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") . " | \n" . "\n"; } @@ -2306,7 +2309,19 @@ sub git_summary { my $owner = git_get_project_owner($project); - my $refs = git_get_references(); + my ($reflist, $refs) = git_get_refs_list(); + + my @taglist; + my @headlist; + foreach my $ref (@$reflist) { + if ($ref->{'name'} =~ s!^heads/!!) { + push @headlist, $ref; + } else { + $ref->{'name'} =~ s!^tags/!!; + push @taglist, $ref; + } + } + git_header_html(); git_print_page_nav('summary','', $head); @@ -2336,17 +2351,15 @@ sub git_summary { git_shortlog_body(\@revlist, 0, 15, $refs, $cgi->a({-href => href(action=>"shortlog")}, "...")); - my $taglist = git_get_refs_list("refs/tags"); - if (defined @$taglist) { + if (@taglist) { git_print_header_div('tags'); - git_tags_body($taglist, 0, 15, + git_tags_body(\@taglist, 0, 15, $cgi->a({-href => href(action=>"tags")}, "...")); } - my $headlist = git_get_refs_list("refs/heads"); - if (defined @$headlist) { + if (@headlist) { git_print_header_div('heads'); - git_heads_body($headlist, $head, 0, 15, + git_heads_body(\@headlist, $head, 0, 15, $cgi->a({-href => href(action=>"heads")}, "...")); } @@ -2407,15 +2420,18 @@ sub git_blame2 { if ($ftype !~ "blob") { die_error("400 Bad Request", "Object is not a blob"); } - open ($fd, "-|", git_cmd(), "blame", '-l', $file_name, $hash_base) + open ($fd, "-|", git_cmd(), "blame", '-l', '--', $file_name, $hash_base) or die_error(undef, "Open git-blame failed"); git_header_html(); my $formats_nav = $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, "blob") . " | " . + $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, + "history") . + " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, - "head"); + "HEAD"); git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); git_print_page_path($file_name, $ftype, $hash_base); @@ -2480,8 +2496,11 @@ sub git_blame { $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, "blob") . " | " . + $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, + "history") . + " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, - "head"); + "HEAD"); git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); git_print_page_path($file_name, 'blob', $hash_base); @@ -2557,8 +2576,8 @@ sub git_tags { git_print_page_nav('','', $head,undef,$head); git_print_header_div('summary', $project); - my $taglist = git_get_refs_list("refs/tags"); - if (defined @$taglist) { + my ($taglist) = git_get_refs_list("tags"); + if (@$taglist) { git_tags_body($taglist); } git_footer_html(); @@ -2570,9 +2589,9 @@ sub git_heads { git_print_page_nav('','', $head,undef,$head); git_print_header_div('summary', $project); - my $taglist = git_get_refs_list("refs/heads"); - if (defined @$taglist) { - git_heads_body($taglist, $head); + my ($headlist) = git_get_refs_list("heads"); + if (@$headlist) { + git_heads_body($headlist, $head); } git_footer_html(); } @@ -2655,16 +2674,20 @@ sub git_blob { " | "; } $formats_nav .= + $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + hash=>$hash, file_name=>$file_name)}, + "history") . + " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$hash, file_name=>$file_name)}, - "plain") . + "raw") . " | " . $cgi->a({-href => href(action=>"blob", hash_base=>"HEAD", file_name=>$file_name)}, - "head"); + "HEAD"); } else { $formats_nav .= - $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "plain"); + $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "raw"); } git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); @@ -2690,6 +2713,9 @@ sub git_blob { } sub git_tree { + my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); + my $have_snapshot = (defined $ctype && defined $suffix); + if (!defined $hash) { $hash = git_get_head_hash($project); if (defined $file_name) { @@ -2713,7 +2739,23 @@ sub git_tree { my $base = ""; my ($have_blame) = gitweb_check_feature('blame'); if (defined $hash_base && (my %co = parse_commit($hash_base))) { - git_print_page_nav('tree','', $hash_base); + my @views_nav = (); + if (defined $file_name) { + push @views_nav, + $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + hash=>$hash, file_name=>$file_name)}, + "history"), + $cgi->a({-href => href(action=>"tree", + hash_base=>"HEAD", file_name=>$file_name)}, + "HEAD"), + } + if ($have_snapshot) { + # FIXME: Should be available when we have no hash base as well. + push @views_nav, + $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, + "snapshot"); + } + git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav)); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base); } else { undef $hash_base; @@ -2818,6 +2860,8 @@ sub git_log { $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . + " | " . + $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . "