line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##- Nanar |
2
|
|
|
|
|
|
|
##- |
3
|
|
|
|
|
|
|
##- This program is free software; you can redistribute it and/or modify |
4
|
|
|
|
|
|
|
##- it under the terms of the GNU General Public License as published by |
5
|
|
|
|
|
|
|
##- the Free Software Foundation; either version 2, or (at your option) |
6
|
|
|
|
|
|
|
##- any later version. |
7
|
|
|
|
|
|
|
##- |
8
|
|
|
|
|
|
|
##- This program is distributed in the hope that it will be useful, |
9
|
|
|
|
|
|
|
##- but WITHOUT ANY WARRANTY; without even the implied warranty of |
10
|
|
|
|
|
|
|
##- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11
|
|
|
|
|
|
|
##- GNU General Public License for more details. |
12
|
|
|
|
|
|
|
##- |
13
|
|
|
|
|
|
|
##- You should have received a copy of the GNU General Public License |
14
|
|
|
|
|
|
|
##- along with this program; if not, write to the Free Software |
15
|
|
|
|
|
|
|
##- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# $Id: Packdrakeng.pm 225631 2007-08-09 11:45:44Z nanardon $ |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
package MDV::Packdrakeng; |
20
|
|
|
|
|
|
|
|
21
|
2
|
|
|
2
|
|
1724
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
74
|
|
22
|
2
|
|
|
2
|
|
1643
|
use POSIX qw(O_WRONLY O_TRUNC O_CREAT O_RDONLY O_APPEND); |
|
2
|
|
|
|
|
15335
|
|
|
2
|
|
|
|
|
14
|
|
23
|
2
|
|
|
2
|
|
2071
|
use File::Path qw(mkpath); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
10210
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
our $VERSION = '1.13'; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
my ($toc_header, $toc_footer) = |
28
|
|
|
|
|
|
|
('cz[0', '0]cz'); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# File::Temp qw(tempfile) hack to not require it |
31
|
|
|
|
|
|
|
sub tempfile { |
32
|
7
|
|
|
7
|
0
|
1122
|
my ($count, $fname, $handle) = (0, undef, undef); |
33
|
7
|
|
|
|
|
28
|
do { |
34
|
7
|
50
|
|
|
|
26
|
++$count > 10 and do { |
35
|
0
|
|
|
|
|
0
|
warn "Can't create temporary file ($fname)"; |
36
|
0
|
|
|
|
|
0
|
return (undef, undef); |
37
|
|
|
|
|
|
|
}; |
38
|
35
|
|
|
|
|
123
|
$fname = sprintf("%s/packdrakeng.%s.%s", |
39
|
|
|
|
|
|
|
$ENV{TMPDIR} || '/tmp', |
40
|
|
|
|
|
|
|
$$, |
41
|
|
|
|
|
|
|
# Generating an random name |
42
|
7
|
100
|
50
|
|
|
101
|
join("", map { $_=rand(51); $_ += $_ > 25 && $_ < 32 ? 91 : 65 ; chr($_) } (0 .. 4))); |
|
35
|
|
100
|
|
|
140
|
|
|
35
|
|
|
|
|
1293
|
|
43
|
|
|
|
|
|
|
} while !sysopen($handle, $fname, O_WRONLY | O_APPEND | O_CREAT); |
44
|
7
|
|
|
|
|
58
|
return ($handle, $fname); |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
10
|
|
|
10
|
0
|
94
|
sub method_info { "external $_[0]->{compress_method}/$_[0]->{uncompress_method} $VERSION" } |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub _new { |
50
|
16
|
|
|
16
|
|
97
|
my ($class, %options) = @_; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
my $pack = { |
53
|
|
|
|
|
|
|
filename => $options{archive}, |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
compress_method => $options{compress}, |
56
|
|
|
|
|
|
|
uncompress_method => $options{uncompress}, |
57
|
|
|
|
|
|
|
force_extern => $options{extern} || 0, # Don't use perl-zlib |
58
|
|
|
|
|
|
|
noargs => $options{noargs}, |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# compression level, aka -X gzip or bzip option |
61
|
|
|
|
|
|
|
level => defined($options{comp_level}) ? $options{comp_level} : 6, |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# A compressed block will contain 400k of compressed data |
64
|
|
|
|
|
|
|
block_size => defined($options{block_size}) ? $options{block_size} : 400 * 1024, |
65
|
|
|
|
|
|
|
bufsize => $options{bufsize} || 65536, # Arbitrary buffer size to read files |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# Internal data |
68
|
|
|
|
|
|
|
handle => undef, # Archive handle |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# Toc information |
71
|
|
|
|
|
|
|
files => {}, # filename => { off, size, coff, csize } |
72
|
|
|
|
|
|
|
dir => {}, # dir => no matter what value |
73
|
|
|
|
|
|
|
'symlink' => {}, # file => link |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
coff => 0, # end of current compressed data |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# Data we need keep in memory to achieve the storage |
78
|
|
|
|
|
|
|
current_block_files => {}, # Files in pending compressed block |
79
|
|
|
|
|
|
|
current_block_csize => 0, # Actual size in pending compressed block |
80
|
|
|
|
|
|
|
current_block_coff => 0, # The block block location (offset) |
81
|
|
|
|
|
|
|
current_block_off => 0, # Actual uncompressed file offset within the pending block |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
cstream_data => undef, # Wrapper data we need to keep in memory (compression) |
84
|
|
|
|
|
|
|
ustream_data => undef, # Wrapper data we need to keep in memory (uncompression) |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# log and verbose function: |
87
|
|
|
|
|
|
|
log => $options{quiet} |
88
|
0
|
|
|
0
|
|
0
|
? sub { our $error = "$_[0]\n" } |
89
|
0
|
|
|
0
|
|
0
|
: sub { our $error = "$_[0]\n"; warn $error }, |
|
0
|
|
|
|
|
0
|
|
90
|
|
|
|
|
|
|
debug => $options{debug} |
91
|
0
|
|
|
0
|
|
0
|
? sub { my @w = @_; $w[0] = "Debug: $w[0]\n"; printf STDERR @w } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
92
|
76
|
|
|
76
|
|
255
|
: sub {}, |
93
|
16
|
50
|
100
|
|
|
1533
|
}; |
|
|
50
|
50
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
94
|
|
|
|
|
|
|
|
95
|
16
|
|
|
|
|
112
|
bless($pack, $class) |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub new { |
99
|
8
|
|
|
8
|
1
|
1526667
|
my ($class, %options) = @_; |
100
|
8
|
|
|
|
|
86
|
my $pack = _new($class, %options); |
101
|
8
|
50
|
|
|
|
1145
|
sysopen($pack->{handle}, $pack->{filename}, O_WRONLY | O_TRUNC | O_CREAT) or do { |
102
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't open $pack->{filename}: $!"); |
103
|
0
|
|
|
|
|
0
|
return undef; |
104
|
|
|
|
|
|
|
}; |
105
|
8
|
|
|
|
|
75
|
$pack->choose_compression_method(); |
106
|
8
|
|
|
|
|
40
|
$pack->{need_build_toc} = 1; |
107
|
8
|
|
|
|
|
60
|
$pack->{debug}( |
108
|
|
|
|
|
|
|
"Creating new archive with %s.", |
109
|
|
|
|
|
|
|
$pack->method_info(), |
110
|
|
|
|
|
|
|
); |
111
|
8
|
|
|
|
|
112
|
$pack |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub open { |
115
|
8
|
|
|
8
|
1
|
170
|
my ($class, %options) = @_; |
116
|
8
|
|
|
|
|
69
|
my $pack = _new($class, %options); |
117
|
8
|
50
|
|
|
|
546
|
sysopen($pack->{handle}, $pack->{filename}, O_RDONLY) or do { |
118
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't open $pack->{filename}: $!"); |
119
|
0
|
|
|
|
|
0
|
return undef; |
120
|
|
|
|
|
|
|
}; |
121
|
8
|
50
|
|
|
|
75
|
$pack->read_toc() or return undef; |
122
|
8
|
|
|
|
|
54
|
$pack->{debug}("Opening archive with %s.", |
123
|
|
|
|
|
|
|
$pack->method_info(), |
124
|
|
|
|
|
|
|
); |
125
|
8
|
|
|
|
|
94
|
$pack |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# look $pack->{(un)compressed_method} and setup functions/commands to use |
129
|
|
|
|
|
|
|
# Have some facility about detecting we want gzip/bzip |
130
|
|
|
|
|
|
|
sub choose_compression_method { |
131
|
16
|
|
|
16
|
0
|
37
|
my ($pack) = @_; |
132
|
|
|
|
|
|
|
|
133
|
16
|
100
|
66
|
|
|
149
|
(!defined($pack->{compress_method}) && !defined($pack->{uncompress_method})) |
134
|
|
|
|
|
|
|
and $pack->{compress_method} = "gzip"; |
135
|
16
|
|
66
|
|
|
89
|
my $test_method = $pack->{compress_method} || $pack->{uncompress_method}; |
136
|
|
|
|
|
|
|
|
137
|
16
|
100
|
|
|
|
119
|
$test_method =~ m/^bzip2|^bunzip2/ and do { |
138
|
2
|
|
50
|
|
|
22
|
$pack->{compress_method} ||= "bzip2"; |
139
|
|
|
|
|
|
|
}; |
140
|
16
|
100
|
|
|
|
193
|
$test_method =~ m/^gzip|^gunzip/ and do { |
141
|
12
|
|
100
|
|
|
55
|
$pack->{compress_method} ||= "gzip"; |
142
|
12
|
100
|
|
|
|
40
|
if (!$pack->{force_extern}) { |
143
|
8
|
|
|
|
|
26
|
eval { |
144
|
8
|
|
|
|
|
1605
|
require Compress::Zlib; #- need this to ensure that Packdrakeng::zlib will load properly |
145
|
8
|
|
|
|
|
97733
|
require MDV::Packdrakeng::zlib; |
146
|
|
|
|
|
|
|
|
147
|
8
|
|
|
|
|
51
|
bless($pack, 'MDV::Packdrakeng::zlib'); |
148
|
|
|
|
|
|
|
}; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
}; |
151
|
16
|
100
|
|
|
|
123
|
if (!$pack->{noargs}) { |
152
|
12
|
|
66
|
|
|
106
|
$pack->{uncompress_method} ||= "$pack->{compress_method} -d"; |
153
|
12
|
50
|
|
|
|
108
|
$pack->{compress_method} = $pack->{compress_method} ? "$pack->{compress_method} -$pack->{level}" : ""; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub DESTROY { |
158
|
16
|
|
|
16
|
|
4077
|
my ($pack) = @_; |
159
|
16
|
50
|
|
|
|
79
|
$pack->{destroyed} and return; #- allow calling DESTROY |
160
|
16
|
|
|
|
|
74
|
$pack->{destroyed} = 1; |
161
|
|
|
|
|
|
|
|
162
|
16
|
|
|
|
|
94
|
$pack->uncompress_handle(undef, undef); |
163
|
16
|
50
|
|
|
|
115
|
$pack->build_toc() == 1 or die "Can't write toc into archive\n"; |
164
|
16
|
50
|
|
|
|
600
|
close($pack->{handle}) if $pack->{handle}; |
165
|
16
|
50
|
|
|
|
1011
|
close($pack->{ustream_data}{handle}) if $pack->{ustream_data}{handle}; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# Flush current compressed block |
169
|
|
|
|
|
|
|
# Write |
170
|
|
|
|
|
|
|
sub build_toc { |
171
|
16
|
|
|
16
|
0
|
33
|
my ($pack) = @_; |
172
|
16
|
100
|
|
|
|
110
|
$pack->{need_build_toc} or return 1; |
173
|
8
|
|
|
|
|
61
|
$pack->end_block(); |
174
|
8
|
50
|
|
|
|
62
|
$pack->end_seek() or do { |
175
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't seek into archive"); |
176
|
0
|
|
|
|
|
0
|
return 0; |
177
|
|
|
|
|
|
|
}; |
178
|
8
|
|
|
|
|
22
|
my ($toc_length, $cf, $cd, $cl) = (0, 0, 0, 0); |
179
|
|
|
|
|
|
|
|
180
|
8
|
|
|
|
|
14
|
foreach my $entry (keys %{$pack->{'dir'}}) { |
|
8
|
|
|
|
|
60
|
|
181
|
2
|
|
|
|
|
8
|
$cd++; |
182
|
2
|
50
|
|
|
|
33
|
my $w = syswrite($pack->{handle}, $entry . "\n") or do { |
183
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't write toc into archive"); |
184
|
0
|
|
|
|
|
0
|
return 0; |
185
|
|
|
|
|
|
|
}; |
186
|
2
|
|
|
|
|
5
|
$toc_length += $w; |
187
|
|
|
|
|
|
|
} |
188
|
8
|
|
|
|
|
27
|
foreach my $entry (keys %{$pack->{'symlink'}}) { |
|
8
|
|
|
|
|
30
|
|
189
|
2
|
|
|
|
|
3
|
$cl++; |
190
|
2
|
50
|
|
|
|
36
|
my $w = syswrite($pack->{handle}, sprintf("%s\n%s\n", $entry, $pack->{'symlink'}{$entry})) or do { |
191
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't write toc into archive"); |
192
|
0
|
|
|
|
|
0
|
return 0; |
193
|
|
|
|
|
|
|
}; |
194
|
2
|
|
|
|
|
4
|
$toc_length += $w |
195
|
|
|
|
|
|
|
} |
196
|
8
|
|
|
|
|
22
|
foreach my $entry (sort keys %{$pack->{files}}) { |
|
8
|
|
|
|
|
87
|
|
197
|
64
|
|
|
|
|
62
|
$cf++; |
198
|
64
|
50
|
|
|
|
786
|
my $w = syswrite($pack->{handle}, $entry ."\n") or do { |
199
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't write toc into archive"); |
200
|
0
|
|
|
|
|
0
|
return 0; |
201
|
|
|
|
|
|
|
}; |
202
|
64
|
|
|
|
|
144
|
$toc_length += $w; |
203
|
|
|
|
|
|
|
} |
204
|
8
|
|
|
|
|
24
|
foreach my $file (sort keys %{$pack->{files}}) { |
|
8
|
|
|
|
|
82
|
|
205
|
64
|
|
|
|
|
201
|
my $entry = $pack->{files}{$file}; |
206
|
64
|
50
|
|
|
|
778
|
syswrite($pack->{handle}, pack('NNNN', $entry->{coff}, $entry->{csize}, $entry->{off}, $entry->{size})) or do { |
207
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't write toc into archive"); |
208
|
0
|
|
|
|
|
0
|
return 0; |
209
|
|
|
|
|
|
|
}; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
syswrite($pack->{handle}, pack("a4NNNNa40a4", |
212
|
|
|
|
|
|
|
$toc_header, |
213
|
|
|
|
|
|
|
$cd, $cl, $cf, |
214
|
|
|
|
|
|
|
$toc_length, |
215
|
|
|
|
|
|
|
$pack->{uncompress_method}, |
216
|
8
|
50
|
|
|
|
243
|
$toc_footer)) or do { |
217
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't write toc into archive"); |
218
|
0
|
|
|
|
|
0
|
return 0; |
219
|
|
|
|
|
|
|
}; |
220
|
8
|
|
|
|
|
32
|
1; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub read_toc { |
224
|
8
|
|
|
8
|
0
|
30
|
my ($pack) = @_; |
225
|
8
|
|
|
|
|
48
|
sysseek($pack->{handle}, -64, 2) ; #or return 0; |
226
|
8
|
|
|
|
|
343
|
sysread($pack->{handle}, my $buf, 64);# == 64 or return 0; |
227
|
8
|
|
|
|
|
115
|
my ($header, $toc_d_count, $toc_l_count, $toc_f_count, $toc_str_size, $uncompress, $trailer) = |
228
|
|
|
|
|
|
|
unpack("a4NNNNZ40a4", $buf); |
229
|
8
|
50
|
33
|
|
|
80
|
$header eq $toc_header && $trailer eq $toc_footer or do { |
230
|
0
|
|
|
|
|
0
|
$pack->{log}("Error reading toc: wrong header/trailer"); |
231
|
0
|
|
|
|
|
0
|
return 0; |
232
|
|
|
|
|
|
|
}; |
233
|
|
|
|
|
|
|
|
234
|
8
|
|
66
|
|
|
43
|
$pack->{uncompress_method} ||= $uncompress; |
235
|
8
|
|
|
|
|
37
|
$pack->choose_compression_method(); |
236
|
|
|
|
|
|
|
|
237
|
8
|
|
|
|
|
51
|
sysseek($pack->{handle}, -64 - ($toc_str_size + 16 * $toc_f_count) ,2); |
238
|
8
|
|
|
|
|
59
|
sysread($pack->{handle}, my $fileslist, $toc_str_size); |
239
|
8
|
|
|
|
|
113
|
my @filenames = split("\n", $fileslist); |
240
|
8
|
|
|
|
|
57
|
sysread($pack->{handle}, my $sizes_offsets, 16 * $toc_f_count); |
241
|
8
|
|
|
|
|
124
|
my @size_offset = unpack("N" . 4*$toc_f_count, $sizes_offsets); |
242
|
|
|
|
|
|
|
|
243
|
8
|
|
|
|
|
45
|
foreach (1 .. $toc_d_count) { |
244
|
2
|
|
|
|
|
9
|
$pack->{dir}{shift(@filenames)} = 1; |
245
|
|
|
|
|
|
|
} |
246
|
8
|
|
|
|
|
31
|
foreach (1 .. $toc_l_count) { |
247
|
2
|
|
|
|
|
4
|
my $n = shift(@filenames); |
248
|
2
|
|
|
|
|
8
|
$pack->{'symlink'}{$n} = shift(@filenames); |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
8
|
|
|
|
|
22
|
foreach (1 .. $toc_f_count) { |
252
|
64
|
|
|
|
|
95
|
my $f = shift(@filenames); |
253
|
64
|
|
|
|
|
259
|
$pack->{files}{$f}{coff} = shift(@size_offset); |
254
|
64
|
|
|
|
|
158
|
$pack->{files}{$f}{csize} = shift(@size_offset); |
255
|
64
|
|
|
|
|
118
|
$pack->{files}{$f}{off} = shift(@size_offset); |
256
|
64
|
|
|
|
|
150
|
$pack->{files}{$f}{size} = shift(@size_offset); |
257
|
|
|
|
|
|
|
# looking for offset for this archive |
258
|
64
|
100
|
|
|
|
306
|
$pack->{files}{$f}{coff} + $pack->{files}{$f}{csize} > $pack->{coff} |
259
|
|
|
|
|
|
|
and $pack->{coff} = $pack->{files}{$f}{coff} + $pack->{files}{$f}{csize}; |
260
|
|
|
|
|
|
|
} |
261
|
8
|
|
|
|
|
52
|
$pack->{toc_f_count} = $toc_f_count; |
262
|
8
|
|
|
|
|
38
|
1; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub sort_files_by_packing { |
266
|
8
|
|
|
8
|
0
|
38
|
my ($pack, @files) = @_; |
267
|
124
|
100
|
33
|
|
|
1070
|
sort { |
|
|
50
|
|
|
|
|
|
268
|
8
|
|
|
|
|
66
|
defined($pack->{files}{$a}) && defined($pack->{files}{$b}) ? |
269
|
|
|
|
|
|
|
($pack->{files}{$a}{coff} == $pack->{files}{$b}{coff} ? |
270
|
|
|
|
|
|
|
$pack->{files}{$a}{off} <=> $pack->{files}{$b}{off} : |
271
|
|
|
|
|
|
|
$pack->{files}{$a}{coff} <=> $pack->{files}{$b}{coff}) : |
272
|
|
|
|
|
|
|
$a cmp $b |
273
|
|
|
|
|
|
|
} @files; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# Goto to the end of written compressed data |
277
|
|
|
|
|
|
|
sub end_seek { |
278
|
89
|
|
|
89
|
0
|
196
|
my ($pack) = @_; |
279
|
89
|
100
|
|
|
|
399
|
my $seekvalue = $pack->direct_write ? $pack->{coff} + $pack->{current_block_csize} : $pack->{coff}; |
280
|
89
|
|
|
|
|
1257
|
sysseek($pack->{handle}, $seekvalue, 0) == $seekvalue |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
#- To terminate a compressed block, flush the pending compressed data, |
284
|
|
|
|
|
|
|
#- fill toc data still unknown |
285
|
|
|
|
|
|
|
sub end_block { |
286
|
17
|
|
|
17
|
0
|
34
|
my ($pack) = @_; |
287
|
17
|
50
|
|
|
|
71
|
$pack->end_seek() or return 0; |
288
|
17
|
|
|
|
|
67
|
my (undef, $csize) = $pack->compress_handle(undef); |
289
|
17
|
|
|
|
|
44
|
$pack->{current_block_csize} += $csize; |
290
|
17
|
|
|
|
|
33
|
foreach (keys %{$pack->{current_block_files}}) { |
|
17
|
|
|
|
|
143
|
|
291
|
64
|
|
|
|
|
165
|
$pack->{files}{$_} = $pack->{current_block_files}{$_}; |
292
|
64
|
|
|
|
|
156
|
$pack->{files}{$_}{csize} = $pack->{current_block_csize}; |
293
|
|
|
|
|
|
|
} |
294
|
17
|
|
|
|
|
47
|
$pack->{coff} += $pack->{current_block_csize}; |
295
|
17
|
|
|
|
|
47
|
$pack->{current_block_coff} += $pack->{current_block_csize}; |
296
|
17
|
|
|
|
|
29
|
$pack->{current_block_csize} = 0; |
297
|
17
|
|
|
|
|
36
|
$pack->{current_block_files} = {}; |
298
|
17
|
|
|
|
|
59
|
$pack->{current_block_off} = 0; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
####################### |
302
|
|
|
|
|
|
|
# Compression wrapper # |
303
|
|
|
|
|
|
|
####################### |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# true if wrapper writes directly in archive and not into temp file |
306
|
53
|
|
|
53
|
0
|
222
|
sub direct_write { 0; } |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub compress_handle { |
309
|
49
|
|
|
49
|
0
|
93
|
my ($pack, $sourcefh) = @_; |
310
|
49
|
|
|
|
|
72
|
my ($insize, $outsize) = (0, 0); # aka uncompressed / compressed data length |
311
|
|
|
|
|
|
|
|
312
|
49
|
100
|
|
|
|
481
|
if (!defined($sourcefh)) { # bloc flush call |
313
|
4
|
|
|
|
|
20
|
return 0, $pack->compress_data(); |
314
|
|
|
|
|
|
|
} else { |
315
|
45
|
|
|
|
|
1994
|
while (my $length = sysread($sourcefh, my $data, $pack->{bufsize})) { |
316
|
406
|
|
|
|
|
1743
|
$outsize += $pack->compress_data($data); |
317
|
406
|
|
|
|
|
64963
|
$insize += $length; |
318
|
|
|
|
|
|
|
} |
319
|
45
|
|
|
|
|
179
|
return ($insize, $outsize) |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub compress_data { |
324
|
410
|
|
|
410
|
0
|
1012
|
my ($pack, $data) = ($_[0], \$_[1]); |
325
|
410
|
|
|
|
|
1103
|
my ($outsize) = (0); # aka uncompressed / compressed data length |
326
|
410
|
|
|
|
|
615
|
my $hout; # handle for gzip |
327
|
|
|
|
|
|
|
|
328
|
410
|
100
|
|
|
|
1715
|
if (defined($pack->{cstream_data})) { |
329
|
406
|
|
|
|
|
1330
|
$hout = $pack->{cstream_data}{hout}; |
330
|
|
|
|
|
|
|
} |
331
|
410
|
100
|
|
|
|
986
|
if (defined($$data)) { |
|
|
100
|
|
|
|
|
|
332
|
406
|
100
|
|
|
|
33879
|
if (!defined($pack->{cstream_data})) { |
333
|
3
|
|
|
|
|
4
|
my $hin; |
334
|
3
|
|
|
|
|
24
|
($hin, $pack->{cstream_data}{file_block}) = tempfile(); |
335
|
3
|
|
|
|
|
44
|
close($hin); # ensure the flush |
336
|
|
|
|
|
|
|
$pack->{cstream_data}{pid} = CORE::open($hout, |
337
|
3
|
50
|
|
|
|
17968
|
"|$pack->{compress_method} > $pack->{cstream_data}{file_block}") or do { |
338
|
0
|
|
|
|
|
0
|
$pack->{log}("Unable to start $pack->{compress_method}"); |
339
|
0
|
|
|
|
|
0
|
return 0; |
340
|
|
|
|
|
|
|
}; |
341
|
3
|
|
|
|
|
52
|
$pack->{cstream_data}{hout} = $hout; |
342
|
3
|
|
|
|
|
154
|
binmode $hout; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
# until we have data to push or data to read |
345
|
|
|
|
|
|
|
# pushing data to compressor |
346
|
406
|
50
|
|
|
|
6758005
|
(syswrite($hout, $$data)) == length($$data) or do { |
347
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't push all data to compressor"); |
348
|
|
|
|
|
|
|
}; |
349
|
406
|
|
|
|
|
2233
|
return 0; # We can't be sure about data really written in the pipe |
350
|
|
|
|
|
|
|
# because of multitasking and buffer, so nothing has been |
351
|
|
|
|
|
|
|
# written |
352
|
|
|
|
|
|
|
} elsif (defined($pack->{cstream_data})) { |
353
|
|
|
|
|
|
|
# If $data is not set, this mean we want a flush(), for end_block() |
354
|
3
|
|
|
|
|
98670
|
close($hout); |
355
|
3
|
|
|
|
|
55
|
waitpid $pack->{cstream_data}{pid}, 0; |
356
|
|
|
|
|
|
|
# copy temp bloc to archive |
357
|
3
|
50
|
|
|
|
346
|
sysopen(my $hin, $pack->{cstream_data}{file_block}, O_RDONLY) or do { |
358
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't open temp block file: $!"); |
359
|
0
|
|
|
|
|
0
|
return 0; |
360
|
|
|
|
|
|
|
}; |
361
|
3
|
|
|
|
|
329
|
unlink($pack->{cstream_data}{file_block}); |
362
|
3
|
|
|
|
|
374
|
while (my $length = sysread($hin, my $tdata, $pack->{bufsize})) { |
363
|
384
|
50
|
|
|
|
1331268
|
(my $l = syswrite($pack->{handle}, $tdata)) == $length or do { |
364
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't write all data in archive"); |
365
|
|
|
|
|
|
|
}; |
366
|
384
|
|
|
|
|
22504
|
$outsize += $l; |
367
|
|
|
|
|
|
|
} |
368
|
3
|
|
|
|
|
2680732
|
close($hin); |
369
|
3
|
|
|
|
|
31
|
$pack->{cstream_data} = undef; |
370
|
|
|
|
|
|
|
# TODO current_block_csize isn't 0 ? |
371
|
3
|
|
|
|
|
127
|
return $outsize - $pack->{current_block_csize} |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub uncompress_handle { |
376
|
53
|
|
|
53
|
0
|
138
|
my ($pack, $destfh, $fileinfo) = @_; |
377
|
|
|
|
|
|
|
|
378
|
53
|
100
|
66
|
|
|
704
|
if (defined($pack->{ustream_data}) && ( |
|
|
|
66
|
|
|
|
|
379
|
|
|
|
|
|
|
!defined($fileinfo) || |
380
|
|
|
|
|
|
|
($fileinfo->{coff} != $pack->{ustream_data}{coff} || $fileinfo->{off} < $pack->{ustream_data}{off}) |
381
|
|
|
|
|
|
|
)) { |
382
|
3
|
|
|
|
|
144
|
close($pack->{ustream_data}{handle}); |
383
|
3
|
|
|
|
|
26016
|
unlink($pack->{ustream_data}{tempname}); # deleting temp file |
384
|
3
|
|
|
|
|
34
|
$pack->{ustream_data} = undef; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
53
|
100
|
|
|
|
256
|
defined($fileinfo) or return 0; |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
# We have to first extract the block to a temp file, burk ! |
390
|
45
|
100
|
|
|
|
138
|
if (!defined($pack->{ustream_data})) { |
391
|
3
|
|
|
|
|
6
|
my $tempfh; |
392
|
3
|
|
|
|
|
14
|
$pack->{ustream_data}{coff} = $fileinfo->{coff}; |
393
|
3
|
|
|
|
|
20
|
$pack->{ustream_data}{read} = 0; |
394
|
|
|
|
|
|
|
|
395
|
3
|
|
|
|
|
18
|
($tempfh, $pack->{ustream_data}{tempname}) = tempfile(); |
396
|
|
|
|
|
|
|
|
397
|
3
|
|
|
|
|
8
|
my $cread = 0; |
398
|
3
|
|
|
|
|
12
|
while ($cread < $fileinfo->{csize}) { |
399
|
|
|
|
|
|
|
my $cl = sysread($pack->{handle}, my $data, |
400
|
|
|
|
|
|
|
$cread + $pack->{bufsize} > $fileinfo->{csize} ? |
401
|
|
|
|
|
|
|
$fileinfo->{csize} - $cread : |
402
|
384
|
100
|
|
|
|
24934
|
$pack->{bufsize}) or do { |
|
|
50
|
|
|
|
|
|
403
|
0
|
|
|
|
|
0
|
$pack->{log}("Unexpected end of file"); |
404
|
0
|
|
|
|
|
0
|
close($tempfh); |
405
|
0
|
|
|
|
|
0
|
unlink($pack->{ustream_data}{tempname}); |
406
|
0
|
|
|
|
|
0
|
$pack->{ustream_data} = undef; |
407
|
0
|
|
|
|
|
0
|
return -1; |
408
|
|
|
|
|
|
|
}; |
409
|
384
|
|
|
|
|
444
|
$cread += $cl; |
410
|
384
|
50
|
|
|
|
129561
|
syswrite($tempfh, $data) == length($data) or do { |
411
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't write all data into temp file"); |
412
|
0
|
|
|
|
|
0
|
close($tempfh); |
413
|
0
|
|
|
|
|
0
|
unlink($pack->{ustream_data}{tempname}); |
414
|
0
|
|
|
|
|
0
|
$pack->{ustream_data} = undef; |
415
|
0
|
|
|
|
|
0
|
return -1; |
416
|
|
|
|
|
|
|
}; |
417
|
|
|
|
|
|
|
} |
418
|
3
|
|
|
|
|
265
|
close($tempfh); |
419
|
|
|
|
|
|
|
|
420
|
3
|
100
|
100
|
|
|
72
|
my $cmd = $pack->{uncompress_method} eq 'gzip -d' || $pack->{uncompress_method} eq 'bzip2 -d' ? |
421
|
|
|
|
|
|
|
"$pack->{uncompress_method} -c '$pack->{ustream_data}{tempname}'" : |
422
|
|
|
|
|
|
|
"$pack->{uncompress_method} < '$pack->{ustream_data}{tempname}'"; |
423
|
3
|
50
|
|
|
|
14177
|
CORE::open($pack->{ustream_data}{handle}, "$cmd |") or do { |
424
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't start $pack->{uncompress_method} to uncompress data"); |
425
|
0
|
|
|
|
|
0
|
unlink($pack->{ustream_data}{tempname}); |
426
|
0
|
|
|
|
|
0
|
$pack->{ustream_data} = undef; |
427
|
0
|
|
|
|
|
0
|
return -1; |
428
|
|
|
|
|
|
|
}; |
429
|
3
|
|
|
|
|
175
|
binmode($pack->{ustream_data}{handle}); |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
|
432
|
45
|
|
|
|
|
129
|
my $byteswritten = 0; |
433
|
45
|
|
|
|
|
138
|
$pack->{ustream_data}{off} = $fileinfo->{off}; |
434
|
|
|
|
|
|
|
|
435
|
45
|
|
|
|
|
175
|
while ($byteswritten < $fileinfo->{size}) { |
436
|
1809
|
|
|
|
|
4137
|
my $data = $pack->{ustream_data}{buf}; |
437
|
1809
|
|
|
|
|
2888
|
$pack->{ustream_data}{buf} = undef; |
438
|
1809
|
|
|
|
|
1790
|
my $length; |
439
|
1809
|
100
|
|
|
|
3611
|
if (!defined($data)) { |
440
|
1771
|
50
|
|
|
|
1711370
|
$length = sysread($pack->{ustream_data}{handle}, $data, $pack->{bufsize}) or do { |
441
|
0
|
|
|
|
|
0
|
$pack->{log}("Unexpected end of stream $pack->{ustream_data}{tempname}"); |
442
|
0
|
|
|
|
|
0
|
unlink($pack->{ustream_data}{tempname}); |
443
|
0
|
|
|
|
|
0
|
close($pack->{ustream_data}{handle}); |
444
|
0
|
|
|
|
|
0
|
$pack->{ustream_data} = undef; |
445
|
0
|
|
|
|
|
0
|
return -1; |
446
|
|
|
|
|
|
|
}; |
447
|
|
|
|
|
|
|
} else { |
448
|
38
|
|
|
|
|
66
|
$length = length($data); |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
|
451
|
1809
|
50
|
33
|
|
|
9339
|
if ($pack->{ustream_data}{read} < $fileinfo->{off} && $pack->{ustream_data}{read} + $length > $fileinfo->{off}) { |
452
|
0
|
|
|
|
|
0
|
$data = substr($data, $fileinfo->{off} - $pack->{ustream_data}{read}); |
453
|
|
|
|
|
|
|
} |
454
|
1809
|
|
|
|
|
3473
|
$pack->{ustream_data}{read} += $length; |
455
|
1809
|
50
|
|
|
|
4778
|
if ($pack->{ustream_data}{read} <= $fileinfo->{off}) { next } |
|
0
|
|
|
|
|
0
|
|
456
|
|
|
|
|
|
|
|
457
|
1809
|
|
|
|
|
2407
|
my $bw; |
458
|
1809
|
100
|
|
|
|
5345
|
if ($byteswritten + length($data) > $fileinfo->{size}) { |
459
|
38
|
|
|
|
|
86
|
$bw = $fileinfo->{size} - $byteswritten; |
460
|
38
|
|
|
|
|
800
|
$pack->{ustream_data}{buf} = substr($data, $bw); # keeping track of unwritten uncompressed data |
461
|
38
|
|
|
|
|
103
|
$pack->{ustream_data}{read} -= length($pack->{ustream_data}{buf}); |
462
|
|
|
|
|
|
|
} else { |
463
|
1771
|
|
|
|
|
2446
|
$bw = length($data); |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
1809
|
50
|
|
|
|
199282
|
syswrite($destfh, $data, $bw) == $bw or do { |
467
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't write data into dest"); |
468
|
0
|
|
|
|
|
0
|
return -1; |
469
|
|
|
|
|
|
|
}; |
470
|
1809
|
|
|
|
|
5800
|
$byteswritten += $bw; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
$byteswritten |
474
|
|
|
|
|
|
|
|
475
|
45
|
|
|
|
|
362
|
} |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
################### |
478
|
|
|
|
|
|
|
# Debug functions # |
479
|
|
|
|
|
|
|
################### |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
# This function extracts in $dest the whole block containing $file, can be useful for debugging |
482
|
|
|
|
|
|
|
sub extract_block { |
483
|
0
|
|
|
0
|
0
|
0
|
my ($pack, $dest, $file) = @_; |
484
|
|
|
|
|
|
|
|
485
|
0
|
0
|
|
|
|
0
|
sysopen(my $handle, $dest, O_WRONLY | O_TRUNC | O_CREAT) or do { |
486
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't open $dest: $!"); |
487
|
0
|
|
|
|
|
0
|
return -1; |
488
|
|
|
|
|
|
|
}; |
489
|
|
|
|
|
|
|
|
490
|
0
|
0
|
|
|
|
0
|
sysseek($pack->{handle}, $pack->{files}{$file}->{coff}, 0) == $pack->{files}{$file}->{coff} or do { |
491
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't seek to offset $pack->{files}{$file}->{coff}"); |
492
|
0
|
|
|
|
|
0
|
close($handle); |
493
|
0
|
|
|
|
|
0
|
return -1; |
494
|
|
|
|
|
|
|
}; |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
{ |
497
|
0
|
|
|
|
|
0
|
my $l; |
|
0
|
|
|
|
|
0
|
|
498
|
0
|
0
|
|
|
|
0
|
$l = sysread($pack->{handle}, my $buf, $pack->{files}{$file}->{csize}) == $pack->{files}{$file}{csize} |
499
|
|
|
|
|
|
|
or $pack->{log}("Read only $l / $pack->{files}{$file}->{csize} bytes"); |
500
|
0
|
|
|
|
|
0
|
syswrite($handle, $buf); |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
|
503
|
0
|
|
|
|
|
0
|
foreach ($pack->sort_files_by_packing(keys %{$pack->{files}})) { |
|
0
|
|
|
|
|
0
|
|
504
|
0
|
0
|
|
|
|
0
|
$pack->{files}{$_}{coff} == $pack->{files}{$file}->{coff} or next; |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
0
|
close($handle); |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
################################## |
512
|
|
|
|
|
|
|
# Really working functions # |
513
|
|
|
|
|
|
|
# Aka function people should use # |
514
|
|
|
|
|
|
|
################################## |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
sub add_virtual { |
517
|
68
|
|
|
68
|
1
|
284
|
my ($pack, $type, $filename, $data) = @_; |
518
|
68
|
100
|
|
|
|
229
|
$type eq 'l' and do { |
519
|
2
|
|
|
|
|
8
|
$pack->{'symlink'}{$filename} = $data; |
520
|
2
|
|
|
|
|
6
|
$pack->{need_build_toc} = 1; |
521
|
2
|
|
|
|
|
9
|
return 1; |
522
|
|
|
|
|
|
|
}; |
523
|
66
|
100
|
|
|
|
161
|
$type eq 'd' and do { |
524
|
2
|
|
|
|
|
10
|
$pack->{dir}{$filename}++; |
525
|
2
|
|
|
|
|
4
|
$pack->{need_build_toc} = 1; |
526
|
2
|
|
|
|
|
11
|
return 1; |
527
|
|
|
|
|
|
|
}; |
528
|
64
|
50
|
|
|
|
168
|
$type eq 'f' and do { |
529
|
|
|
|
|
|
|
# Be sure we are at the end, allow extract + add in only one instance |
530
|
64
|
50
|
|
|
|
264
|
$pack->end_seek() or do { |
531
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't seek to offset $pack->{coff}"); |
532
|
0
|
|
|
|
|
0
|
next; |
533
|
|
|
|
|
|
|
}; |
534
|
|
|
|
|
|
|
|
535
|
64
|
100
|
|
|
|
390
|
my ($size, $csize) = (ref($data) eq 'GLOB') ? |
536
|
|
|
|
|
|
|
$pack->compress_handle($data) : |
537
|
|
|
|
|
|
|
(length($data), $pack->compress_data($data)); |
538
|
64
|
|
|
|
|
1077
|
$pack->{current_block_files}{$filename} = { |
539
|
|
|
|
|
|
|
size => $size, |
540
|
|
|
|
|
|
|
off => $pack->{current_block_off}, |
541
|
|
|
|
|
|
|
coff => $pack->{current_block_coff}, |
542
|
|
|
|
|
|
|
csize => -1, # Still unknown, will be fill by end_block |
543
|
|
|
|
|
|
|
}; # Storing in toc structure availlable info |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
# Updating internal info about current block |
546
|
64
|
|
|
|
|
213
|
$pack->{current_block_off} += $size; |
547
|
64
|
|
|
|
|
167
|
$pack->{current_block_csize} += $csize; |
548
|
64
|
|
|
|
|
150
|
$pack->{need_build_toc} = 1; |
549
|
64
|
100
|
66
|
|
|
563
|
if ($pack->{block_size} > 0 && $pack->{current_block_csize} >= $pack->{block_size}) { |
550
|
9
|
|
|
|
|
90
|
$pack->end_block(); |
551
|
|
|
|
|
|
|
} |
552
|
64
|
|
|
|
|
239
|
return 1; |
553
|
|
|
|
|
|
|
}; |
554
|
0
|
|
|
|
|
0
|
0 |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub add { |
558
|
4
|
|
|
4
|
1
|
23
|
my ($pack, $prefix, @files) = @_; |
559
|
4
|
|
50
|
|
|
78
|
$prefix ||= ""; |
560
|
4
|
|
|
|
|
21
|
foreach my $file (@files) { |
561
|
60
|
|
|
|
|
256
|
$file =~ s://+:/:; |
562
|
60
|
50
|
|
|
|
262
|
my $srcfile = $prefix ? "$prefix/$file" : $file; |
563
|
60
|
|
|
|
|
325
|
$pack->{debug}("Adding '%s' as '%s' into archive", $srcfile, $file); |
564
|
|
|
|
|
|
|
|
565
|
60
|
50
|
|
|
|
1879
|
-l $srcfile and do { |
566
|
0
|
|
|
|
|
0
|
$pack->add_virtual('l', $file, readlink($srcfile)); |
567
|
0
|
|
|
|
|
0
|
next; |
568
|
|
|
|
|
|
|
}; |
569
|
60
|
50
|
|
|
|
763
|
-d $srcfile and do { # dir simple case |
570
|
0
|
|
|
|
|
0
|
$pack->add_virtual('d', $file); |
571
|
0
|
|
|
|
|
0
|
next; |
572
|
|
|
|
|
|
|
}; |
573
|
60
|
50
|
|
|
|
675
|
-f $srcfile and do { |
574
|
60
|
50
|
|
|
|
3479
|
sysopen(my $htocompress, $srcfile, O_RDONLY) or do { |
575
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't add $srcfile: $!"); |
576
|
0
|
|
|
|
|
0
|
next; |
577
|
|
|
|
|
|
|
}; |
578
|
60
|
|
|
|
|
303
|
$pack->add_virtual('f', $file, $htocompress); |
579
|
60
|
|
|
|
|
2275
|
close($htocompress); |
580
|
60
|
|
|
|
|
621
|
next; |
581
|
|
|
|
|
|
|
}; |
582
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't pack $srcfile"); |
583
|
|
|
|
|
|
|
} |
584
|
4
|
|
|
|
|
154
|
1; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
sub extract_virtual { |
588
|
64
|
|
|
64
|
1
|
208
|
my ($pack, $destfh, $filename) = @_; |
589
|
64
|
50
|
|
|
|
208
|
defined($pack->{files}{$filename}) or return -1; |
590
|
64
|
50
|
|
|
|
714
|
sysseek($pack->{handle}, $pack->{files}{$filename}->{coff}, 0) == $pack->{files}{$filename}->{coff} or do { |
591
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't seek to offset $pack->{files}{$filename}->{coff}"); |
592
|
0
|
|
|
|
|
0
|
return -1; |
593
|
|
|
|
|
|
|
}; |
594
|
64
|
|
|
|
|
316
|
$pack->uncompress_handle($destfh, $pack->{files}{$filename}); |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub extract { |
598
|
8
|
|
|
8
|
1
|
961
|
my ($pack, $destdir, @files) = @_; |
599
|
8
|
|
|
|
|
48
|
foreach my $f ($pack->sort_files_by_packing(@files)) { |
600
|
64
|
50
|
|
|
|
470
|
my $dest = $destdir ? "$destdir/$f" : "$f"; |
601
|
64
|
|
|
|
|
932
|
my ($dir) = $dest =~ m!(.*)/.*!; |
602
|
64
|
|
50
|
|
|
224
|
$dir ||= "."; |
603
|
64
|
100
|
|
|
|
549
|
if (exists($pack->{dir}{$f})) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
604
|
2
|
50
|
33
|
|
|
565
|
-d $dest || mkpath($dest) |
605
|
|
|
|
|
|
|
or $pack->{log}("Unable to create dir $dest: $!"); |
606
|
2
|
|
|
|
|
7
|
next; |
607
|
|
|
|
|
|
|
} elsif (exists($pack->{'symlink'}{$f})) { |
608
|
2
|
50
|
33
|
|
|
31
|
-d $dir || mkpath($dir) or |
609
|
|
|
|
|
|
|
$pack->{log}("Unable to create dir $dest: $!"); |
610
|
2
|
50
|
|
|
|
35
|
-l $dest and unlink $dest; |
611
|
2
|
50
|
|
|
|
105
|
symlink($pack->{'symlink'}{$f}, $dest) |
612
|
|
|
|
|
|
|
or $pack->{log}("Unable to extract symlink $f: $!"); |
613
|
2
|
|
|
|
|
8
|
next; |
614
|
|
|
|
|
|
|
} elsif (exists($pack->{files}{$f})) { |
615
|
60
|
50
|
33
|
|
|
1769
|
-d $dir || mkpath($dir) or do { |
616
|
0
|
|
|
|
|
0
|
$pack->{log}("Unable to create dir $dir"); |
617
|
|
|
|
|
|
|
}; |
618
|
60
|
50
|
|
|
|
1812
|
if (-l $dest) { |
619
|
0
|
0
|
|
|
|
0
|
unlink($dest) or do { |
620
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't remove link $dest: $!"); |
621
|
0
|
|
|
|
|
0
|
next; # Don't overwrite a file because where the symlink point to |
622
|
|
|
|
|
|
|
}; |
623
|
|
|
|
|
|
|
} |
624
|
60
|
|
|
|
|
100
|
my $destfh; |
625
|
60
|
50
|
|
|
|
150
|
if (defined $destdir) { |
626
|
60
|
50
|
|
|
|
6694
|
sysopen($destfh, $dest, O_CREAT | O_TRUNC | O_WRONLY) or do { |
627
|
0
|
|
|
|
|
0
|
$pack->{log}("Unable to extract $dest: $!"); |
628
|
0
|
|
|
|
|
0
|
next; |
629
|
|
|
|
|
|
|
}; |
630
|
|
|
|
|
|
|
} else { |
631
|
0
|
|
|
|
|
0
|
$destfh = \*STDOUT; |
632
|
|
|
|
|
|
|
} |
633
|
60
|
|
|
|
|
332
|
my $written = $pack->extract_virtual($destfh, $f); |
634
|
60
|
50
|
|
|
|
194
|
$written == -1 and $pack->{log}("Unable to extract file $f"); |
635
|
60
|
|
|
|
|
1855
|
close($destfh); |
636
|
60
|
|
|
|
|
645
|
next; |
637
|
|
|
|
|
|
|
} else { |
638
|
0
|
|
|
|
|
0
|
$pack->{log}("Can't find $f in archive"); |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
} |
641
|
8
|
|
|
|
|
173
|
1; |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
# Return \@dir, \@files, \@symlink list |
645
|
|
|
|
|
|
|
sub getcontent { |
646
|
0
|
|
|
0
|
1
|
0
|
my ($pack) = @_; |
647
|
|
|
|
|
|
|
return( |
648
|
0
|
|
|
|
|
0
|
[ keys(%{$pack->{dir}})], |
|
0
|
|
|
|
|
0
|
|
649
|
0
|
|
|
|
|
0
|
[ $pack->sort_files_by_packing(keys %{$pack->{files}}) ], |
650
|
0
|
|
|
|
|
0
|
[ keys(%{$pack->{'symlink'}}) ] |
651
|
|
|
|
|
|
|
); |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
sub infofile { |
655
|
8
|
|
|
8
|
1
|
3050
|
my ($pack, $file) = @_; |
656
|
8
|
100
|
|
|
|
44
|
if (defined($pack->{files}{$file})) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
657
|
2
|
|
|
|
|
11
|
return ('f', $pack->{files}{$file}{size}); |
658
|
|
|
|
|
|
|
} elsif (defined($pack->{'symlink'}{$file})) { |
659
|
2
|
|
|
|
|
16
|
return ('l', $pack->{'symlink'}{$file}); |
660
|
|
|
|
|
|
|
} elsif (defined($pack->{dir}{$file})) { |
661
|
2
|
|
|
|
|
17
|
return ('d', undef); |
662
|
|
|
|
|
|
|
} else { |
663
|
2
|
|
|
|
|
8
|
return(undef, undef); |
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
sub list { |
668
|
0
|
|
|
0
|
0
|
|
my ($pack, $handle) = @_; |
669
|
0
|
|
0
|
|
|
|
$handle ||= *STDOUT; |
670
|
0
|
|
|
|
|
|
foreach my $file (keys %{$pack->{dir}}) { |
|
0
|
|
|
|
|
|
|
671
|
0
|
|
|
|
|
|
printf "d %13c %s\n", ' ', $file; |
672
|
|
|
|
|
|
|
} |
673
|
0
|
|
|
|
|
|
foreach my $file (keys %{$pack->{'symlink'}}) { |
|
0
|
|
|
|
|
|
|
674
|
0
|
|
|
|
|
|
printf "l %13c %s -> %s\n", ' ', $file, $pack->{'symlink'}{$file}; |
675
|
|
|
|
|
|
|
} |
676
|
0
|
|
|
|
|
|
foreach my $file ($pack->sort_files_by_packing(keys %{$pack->{files}})) { |
|
0
|
|
|
|
|
|
|
677
|
0
|
|
|
|
|
|
printf "f %12d %s\n", $pack->{files}{$file}{size}, $file; |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
# Print toc info |
682
|
|
|
|
|
|
|
sub dumptoc { |
683
|
0
|
|
|
0
|
1
|
|
my ($pack, $handle) = @_; |
684
|
0
|
|
0
|
|
|
|
$handle ||= *STDOUT; |
685
|
0
|
|
|
|
|
|
foreach my $file (keys %{$pack->{dir}}) { |
|
0
|
|
|
|
|
|
|
686
|
0
|
|
|
|
|
|
printf $handle "d %13c %s\n", ' ', $file; |
687
|
|
|
|
|
|
|
} |
688
|
0
|
|
|
|
|
|
foreach my $file (keys %{$pack->{'symlink'}}) { |
|
0
|
|
|
|
|
|
|
689
|
0
|
|
|
|
|
|
printf $handle "l %13c %s -> %s\n", ' ', $file, $pack->{'symlink'}{$file}; |
690
|
|
|
|
|
|
|
} |
691
|
0
|
|
|
|
|
|
foreach my $file ($pack->sort_files_by_packing(keys %{$pack->{files}})) { |
|
0
|
|
|
|
|
|
|
692
|
0
|
|
|
|
|
|
printf $handle "f %d %d %d %d %s\n", $pack->{files}{$file}{size}, $pack->{files}{$file}{off}, $pack->{files}{$file}{csize}, $pack->{files}{$file}{coff}, $file; |
693
|
|
|
|
|
|
|
} |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
1; |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
__END__ |