X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/cc9317038d98be2d64e1bd7215a0cc64d13a06ab033b10f18d83e1f9fe2a7f18..2f619acf24f3099cf37a5e95832c1890368a2145e83312547652772c2a7ab9a6:/gitweb.perl diff --git a/gitweb.perl b/gitweb.perl index a147659..b011a47 100755 --- a/gitweb.perl +++ b/gitweb.perl @@ -189,9 +189,6 @@ do $GITWEB_CONFIG if -e $GITWEB_CONFIG; # version of the core git binary our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown"; -# path to the current git repository -our $git_dir; - $projects_list ||= $projectroot; # ====================================================================== @@ -259,7 +256,7 @@ if (defined $hash_parent_base) { our $page = $cgi->param('pg'); if (defined $page) { - if ($page =~ m/[^0-9]$/) { + if ($page =~ m/[^0-9]/) { die_error(undef, "Invalid page parameter"); } } @@ -273,30 +270,52 @@ if (defined $searchtext) { } # now read PATH_INFO and use it as alternative to parameters -our $path_info = $ENV{"PATH_INFO"}; -$path_info =~ s|^/||; -$path_info =~ s|/$||; -if (validate_input($path_info) && !defined $project) { +sub evaluate_path_info { + return if defined $project; + my $path_info = $ENV{"PATH_INFO"}; + return if !$path_info; + $path_info =~ s,^/+,,; + return if !$path_info; + # find which part of PATH_INFO is project $project = $path_info; + $project =~ s,/+$,,; while ($project && !-e "$projectroot/$project/HEAD") { $project =~ s,/*[^/]*$,,; } - if (defined $project) { - $project = undef unless $project; - } - if ($path_info =~ m,^$project/([^/]+)/(.+)$,) { - # we got "project.git/branch/filename" - $action ||= "blob_plain"; - $hash_base ||= $1; - $file_name ||= $2; - } elsif ($path_info =~ m,^$project/([^/]+)$,) { + # validate project + $project = validate_input($project); + if (!$project || + ($export_ok && !-e "$projectroot/$project/$export_ok") || + ($strict_export && !project_in_list($project))) { + undef $project; + return; + } + # do not change any parameters if an action is given using the query string + return if $action; + $path_info =~ s,^$project/*,,; + my ($refname, $pathname) = split(/:/, $path_info, 2); + if (defined $pathname) { + # we got "project.git/branch:filename" or "project.git/branch:dir/" + # we could use git_get_type(branch:pathname), but it needs $git_dir + $pathname =~ s,^/+,,; + if (!$pathname || substr($pathname, -1) eq "/") { + $action ||= "tree"; + } else { + $action ||= "blob_plain"; + } + $hash_base ||= validate_input($refname); + $file_name ||= validate_input($pathname); + } elsif (defined $refname) { # we got "project.git/branch" $action ||= "shortlog"; - $hash ||= $1; + $hash ||= validate_input($refname); } } +evaluate_path_info(); -$git_dir = "$projectroot/$project"; +# path to the current git repository +our $git_dir; +$git_dir = "$projectroot/$project" if $project; # dispatch my %actions = ( @@ -333,6 +352,10 @@ if (defined $project) { if (!defined($actions{$action})) { die_error(undef, "Unknown action"); } +if ($action !~ m/^(opml|project_list|project_index)$/ && + !$project) { + die_error(undef, "Project needed"); +} $actions{$action}->(); exit; @@ -820,16 +843,10 @@ sub git_get_project_owner { sub git_get_references { my $type = shift || ""; my %refs; - my $fd; # 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c refs/tags/v2.6.11 # c39ae07f393806ccf406ef966e9a15afc43cc36a refs/tags/v2.6.11^{} - if (-f "$projectroot/$project/info/refs") { - open $fd, "$projectroot/$project/info/refs" - or return; - } else { - open $fd, "-|", git_cmd(), "ls-remote", "." - or return; - } + open my $fd, "-|", $GIT, "peek-remote", "$projectroot/$project/" + or return; while (my $line = <$fd>) { chomp $line; @@ -1117,7 +1134,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; @@ -1125,14 +1143,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; @@ -1148,7 +1173,7 @@ sub git_get_refs_list { } # sort refs by age @reflist = sort {$b->{'epoch'} <=> $a->{'epoch'}} @reflist; - return \@reflist; + return (\@reflist, \%refs); } ## ---------------------------------------------------------------------- @@ -1189,7 +1214,7 @@ sub mimetype_guess_file { } close(MIME); - $filename =~ /\.(.*?)$/; + $filename =~ /\.([^.]*)$/; return $mimemap{$1}; } @@ -2112,14 +2137,14 @@ sub git_tags_body { sub git_heads_body { # uses global variable $project - my ($taglist, $head, $from, $to, $extra) = @_; + my ($headlist, $head, $from, $to, $extra) = @_; $from = 0 unless defined $from; - $to = $#{$taglist} if (!defined $to || $#{$taglist} < $to); + $to = $#{$headlist} if (!defined $to || $#{$headlist} < $to); print "