1 # Copyright (C) 2014-2015 all contributors <meta@public-inbox.org>
2 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
3 # This is based on code in Git.pm which is GPLv2, but modified to avoid
4 # dependence on environment variables for compatibility with mod_perl.
5 # There are also API changes to simplify our usage and data set.
6 package PublicInbox::GitCatFile;
12 my ($class, $git_dir) = @_;
13 bless { git_dir => $git_dir }, $class;
18 return if $self->{pid};
19 my ($in_r, $in_w, $out_r, $out_w);
21 pipe($in_r, $in_w) or die "pipe failed: $!\n";
22 pipe($out_r, $out_w) or die "pipe failed: $!\n";
24 my @cmd = ('git', "--git-dir=$self->{git_dir}", qw(cat-file --batch));
26 defined $pid or die "fork failed: $!\n";
28 dup2(fileno($out_r), 0) or die "redirect stdin failed: $!\n";
29 dup2(fileno($in_w), 1) or die "redirect stdout failed: $!\n";
30 exec(@cmd) or die 'exec `' . join(' '). "' failed: $!\n";
32 close $out_r or die "close failed: $!\n";
33 close $in_w or die "close failed: $!\n";
36 $self->{out} = $out_w;
41 my ($self, $object, $sizeref) = @_;
44 my $len = bytes::length($object);
46 $self->_cat_file_begin;
47 my $written = syswrite($self->{out}, $object);
48 if (!defined $written) {
49 die "pipe write error: $!\n";
50 } elsif ($written != $len) {
51 die "wrote too little to pipe ($written < $len)\n";
56 $head =~ / missing$/ and return undef;
57 $head =~ /^[0-9a-f]{40} \S+ (\d+)$/ or
58 die "Unexpected result from git cat-file: $head\n";
61 $$sizeref = $size if $sizeref;
62 my $bytes_left = $size;
67 my $read = read($in, $rv, $bytes_left, $offset);
68 defined($read) or die "sysread pipe failed: $!\n";
73 my $read = read($in, my $buf, 1);
74 defined($read) or die "read pipe failed: $!\n";
75 if ($read != 1 || $buf ne "\n") {
76 die "newline missing after blob\n";
83 my $pid = $self->{pid} or return;
85 foreach my $f (qw(in out)) {