Update to PathTools-3.22.
[p5sagit/p5-mst-13.2.git] / lib / CPAN / Tarzip.pm
CommitLineData
e82b9348 1# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 2 -*-
2package CPAN::Tarzip;
3use strict;
4use vars qw($VERSION @ISA $BUGHUNTING);
5use CPAN::Debug;
0cf35e6a 6use File::Basename ();
7d97ad34 7$VERSION = sprintf "%.6f", substr(q$Rev: 956 $,4)/1000000 + 5.4;
e82b9348 8# module is internal to CPAN.pm
9
10@ISA = qw(CPAN::Debug);
2ccf00a7 11$BUGHUNTING ||= 0; # released code must have turned off
e82b9348 12
13# it's ok if file doesn't exist, it just matters if it is .gz or .bz2
14sub new {
15 my($class,$file) = @_;
0cf35e6a 16 $CPAN::Frontend->mydie("new called without arg") unless defined $file;
1a43333d 17 if (0) {
18 # nonono, we get e.g. 01mailrc.txt uncompressed if only wget is available
19 $CPAN::Frontend->mydie("file[$file] doesn't match /\\.(bz2|gz|zip|tgz)\$/")
20 unless $file =~ /\.(bz2|gz|zip|tgz)$/i;
21 }
e82b9348 22 my $me = { FILE => $file };
23 if (0) {
24 } elsif ($file =~ /\.bz2$/i) {
25 unless ($me->{UNGZIPPRG} = $CPAN::Config->{bzip2}) {
26 my $bzip2;
27 if ($CPAN::META->has_inst("File::Which")) {
28 $bzip2 = File::Which::which("bzip2");
29 }
30 if ($bzip2) {
ed84aac9 31 $me->{UNGZIPPRG} = $bzip2 || "bzip2";
e82b9348 32 } else {
33 $CPAN::Frontend->mydie(qq{
34CPAN.pm needs the external program bzip2 in order to handle '$file'.
35Please install it now and run 'o conf init' to register it as external
36program.
37});
38 }
39 }
40 } else {
41 # yes, we let gzip figure it out in *any* other case
ed84aac9 42 $me->{UNGZIPPRG} = $CPAN::Config->{gzip} || "gzip";
e82b9348 43 }
44 bless $me, $class;
45}
46
47sub gzip {
48 my($self,$read) = @_;
49 my $write = $self->{FILE};
50 if ($CPAN::META->has_inst("Compress::Zlib")) {
51 my($buffer,$fhw);
52 $fhw = FileHandle->new($read)
53 or $CPAN::Frontend->mydie("Could not open $read: $!");
54 my $cwd = `pwd`;
55 my $gz = Compress::Zlib::gzopen($write, "wb")
56 or $CPAN::Frontend->mydie("Cannot gzopen $write: $! (pwd is $cwd)\n");
57 $gz->gzwrite($buffer)
58 while read($fhw,$buffer,4096) > 0 ;
59 $gz->gzclose() ;
60 $fhw->close;
61 return 1;
62 } else {
ed84aac9 63 my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
64 system(qq{$command -c "$read" > "$write"})==0;
e82b9348 65 }
66}
67
68
69sub gunzip {
70 my($self,$write) = @_;
71 my $read = $self->{FILE};
72 if ($CPAN::META->has_inst("Compress::Zlib")) {
73 my($buffer,$fhw);
74 $fhw = FileHandle->new(">$write")
75 or $CPAN::Frontend->mydie("Could not open >$write: $!");
76 my $gz = Compress::Zlib::gzopen($read, "rb")
77 or $CPAN::Frontend->mydie("Cannot gzopen $read: $!\n");
78 $fhw->print($buffer)
79 while $gz->gzread($buffer) > 0 ;
80 $CPAN::Frontend->mydie("Error reading from $read: $!\n")
81 if $gz->gzerror != Compress::Zlib::Z_STREAM_END();
82 $gz->gzclose() ;
83 $fhw->close;
84 return 1;
85 } else {
ed84aac9 86 my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
87 system(qq{$command -dc "$read" > "$write"})==0;
e82b9348 88 }
89}
90
91
92sub gtest {
93 my($self) = @_;
87892b73 94 return $self->{GTEST} if exists $self->{GTEST};
95 my $read = $self->{FILE} or die;
96 my $success;
e82b9348 97 # After I had reread the documentation in zlib.h, I discovered that
98 # uncompressed files do not lead to an gzerror (anymore?).
99 if ( $CPAN::META->has_inst("Compress::Zlib") ) {
100 my($buffer,$len);
101 $len = 0;
102 my $gz = Compress::Zlib::gzopen($read, "rb")
103 or $CPAN::Frontend->mydie(sprintf("Cannot gzopen %s: %s\n",
104 $read,
105 $Compress::Zlib::gzerrno));
106 while ($gz->gzread($buffer) > 0 ){
107 $len += length($buffer);
108 $buffer = "";
109 }
110 my $err = $gz->gzerror;
87892b73 111 $success = ! $err || $err == Compress::Zlib::Z_STREAM_END();
e82b9348 112 if ($len == -s $read){
113 $success = 0;
114 CPAN->debug("hit an uncompressed file") if $CPAN::DEBUG;
115 }
116 $gz->gzclose();
117 CPAN->debug("err[$err]success[$success]") if $CPAN::DEBUG;
e82b9348 118 } else {
ed84aac9 119 my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
120 $success = 0==system(qq{$command -qdt "$read"});
e82b9348 121 }
87892b73 122 return $self->{GTEST} = $success;
e82b9348 123}
124
125
126sub TIEHANDLE {
127 my($class,$file) = @_;
128 my $ret;
129 $class->debug("file[$file]");
87892b73 130 my $self = $class->new($file);
131 if (0) {
132 } elsif (!$self->gtest) {
133 my $fh = FileHandle->new($file) or die "Could not open file[$file]: $!";
134 binmode $fh;
135 $self->{FH} = $fh;
7d97ad34 136 $class->debug("via uncompressed FH");
87892b73 137 } elsif ($CPAN::META->has_inst("Compress::Zlib")) {
e82b9348 138 my $gz = Compress::Zlib::gzopen($file,"rb") or
139 die "Could not gzopen $file";
87892b73 140 $self->{GZ} = $gz;
7d97ad34 141 $class->debug("via Compress::Zlib");
e82b9348 142 } else {
ed84aac9 143 my $gzip = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
144 my $pipe = "$gzip -dc $file |";
e82b9348 145 my $fh = FileHandle->new($pipe) or die "Could not pipe[$pipe]: $!";
146 binmode $fh;
87892b73 147 $self->{FH} = $fh;
7d97ad34 148 $class->debug("via external gzip");
e82b9348 149 }
87892b73 150 $self;
e82b9348 151}
152
153
154sub READLINE {
155 my($self) = @_;
156 if (exists $self->{GZ}) {
157 my $gz = $self->{GZ};
158 my($line,$bytesread);
159 $bytesread = $gz->gzreadline($line);
160 return undef if $bytesread <= 0;
161 return $line;
162 } else {
163 my $fh = $self->{FH};
164 return scalar <$fh>;
165 }
166}
167
168
169sub READ {
170 my($self,$ref,$length,$offset) = @_;
171 die "read with offset not implemented" if defined $offset;
172 if (exists $self->{GZ}) {
173 my $gz = $self->{GZ};
174 my $byteread = $gz->gzread($$ref,$length);# 30eaf79e8b446ef52464b5422da328a8
175 return $byteread;
176 } else {
177 my $fh = $self->{FH};
178 return read($fh,$$ref,$length);
179 }
180}
181
182
183sub DESTROY {
184 my($self) = @_;
185 if (exists $self->{GZ}) {
186 my $gz = $self->{GZ};
187 $gz->gzclose() if defined $gz; # hard to say if it is allowed
188 # to be undef ever. AK, 2000-09
189 } else {
190 my $fh = $self->{FH};
191 $fh->close if defined $fh;
192 }
193 undef $self;
194}
195
196
197sub untar {
198 my($self) = @_;
199 my $file = $self->{FILE};
200 my($prefer) = 0;
201
202 if (0) { # makes changing order easier
203 } elsif ($BUGHUNTING){
204 $prefer=2;
205 } elsif (MM->maybe_command($self->{UNGZIPPRG})
206 &&
ed84aac9 207 MM->maybe_command($CPAN::Config->{tar})) {
e82b9348 208 # should be default until Archive::Tar handles bzip2
209 $prefer = 1;
210 } elsif (
211 $CPAN::META->has_inst("Archive::Tar")
212 &&
213 $CPAN::META->has_inst("Compress::Zlib") ) {
e82b9348 214 $prefer = 2;
215 } else {
216 $CPAN::Frontend->mydie(qq{
217CPAN.pm needs either the external programs tar, gzip and bzip2
218installed. Can't continue.
219});
220 }
221 if ($prefer==1) { # 1 => external gzip+tar
222 my($system);
223 my $is_compressed = $self->gtest();
ed84aac9 224 my $tarcommand = CPAN::HandleConfig->safe_quote($CPAN::Config->{tar}) || "tar";
e82b9348 225 if ($is_compressed) {
ed84aac9 226 my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
227 $system = qq{$command -dc }.
228 qq{< "$file" | $tarcommand xvf -};
e82b9348 229 } else {
ed84aac9 230 $system = qq{$tarcommand xvf "$file"};
e82b9348 231 }
232 if (system($system) != 0) {
233 # people find the most curious tar binaries that cannot handle
234 # pipes
235 if ($is_compressed) {
236 (my $ungzf = $file) =~ s/\.gz(?!\n)\Z//;
0cf35e6a 237 $ungzf = File::Basename::basename($ungzf);
238 my $ct = CPAN::Tarzip->new($file);
239 if ($ct->gunzip($ungzf)) {
e82b9348 240 $CPAN::Frontend->myprint(qq{Uncompressed $file successfully\n});
241 } else {
242 $CPAN::Frontend->mydie(qq{Couldn\'t uncompress $file\n});
243 }
244 $file = $ungzf;
245 }
ed84aac9 246 $system = qq{$tarcommand xvf "$file"};
e82b9348 247 $CPAN::Frontend->myprint(qq{Using Tar:$system:\n});
248 if (system($system)==0) {
249 $CPAN::Frontend->myprint(qq{Untarred $file successfully\n});
250 } else {
251 $CPAN::Frontend->mydie(qq{Couldn\'t untar $file\n});
252 }
253 return 1;
254 } else {
255 return 1;
256 }
257 } elsif ($prefer==2) { # 2 => modules
2ccf00a7 258 unless ($CPAN::META->has_inst("Archive::Tar")) {
259 $CPAN::Frontend->mydie("Archive::Tar not installed, please install it to continue");
260 }
e82b9348 261 my $tar = Archive::Tar->new($file,1);
262 my $af; # archive file
263 my @af;
264 if ($BUGHUNTING) {
265 # RCS 1.337 had this code, it turned out unacceptable slow but
266 # it revealed a bug in Archive::Tar. Code is only here to hunt
267 # the bug again. It should never be enabled in published code.
268 # GDGraph3d-0.53 was an interesting case according to Larry
269 # Virden.
270 warn(">>>Bughunting code enabled<<< " x 20);
271 for $af ($tar->list_files) {
272 if ($af =~ m!^(/|\.\./)!) {
273 $CPAN::Frontend->mydie("ALERT: Archive contains ".
274 "illegal member [$af]");
275 }
276 $CPAN::Frontend->myprint("$af\n");
277 $tar->extract($af); # slow but effective for finding the bug
278 return if $CPAN::Signal;
279 }
280 } else {
281 for $af ($tar->list_files) {
282 if ($af =~ m!^(/|\.\./)!) {
283 $CPAN::Frontend->mydie("ALERT: Archive contains ".
284 "illegal member [$af]");
285 }
286 $CPAN::Frontend->myprint("$af\n");
287 push @af, $af;
288 return if $CPAN::Signal;
289 }
0cf35e6a 290 $tar->extract(@af) or
291 $CPAN::Frontend->mydie("Could not untar with Archive::Tar.");
e82b9348 292 }
293
294 Mac::BuildTools::convert_files([$tar->list_files], 1)
295 if ($^O eq 'MacOS');
296
297 return 1;
298 }
299}
300
301sub unzip {
302 my($self) = @_;
303 my $file = $self->{FILE};
304 if ($CPAN::META->has_inst("Archive::Zip")) {
305 # blueprint of the code from Archive::Zip::Tree::extractTree();
306 my $zip = Archive::Zip->new();
307 my $status;
308 $status = $zip->read($file);
309 die "Read of file[$file] failed\n" if $status != Archive::Zip::AZ_OK();
310 $CPAN::META->debug("Successfully read file[$file]") if $CPAN::DEBUG;
311 my @members = $zip->members();
312 for my $member ( @members ) {
313 my $af = $member->fileName();
314 if ($af =~ m!^(/|\.\./)!) {
315 $CPAN::Frontend->mydie("ALERT: Archive contains ".
316 "illegal member [$af]");
317 }
318 $status = $member->extractToFileNamed( $af );
319 $CPAN::META->debug("af[$af]status[$status]") if $CPAN::DEBUG;
320 die "Extracting of file[$af] from zipfile[$file] failed\n" if
321 $status != Archive::Zip::AZ_OK();
322 return if $CPAN::Signal;
323 }
324 return 1;
325 } else {
326 my $unzip = $CPAN::Config->{unzip} or
327 $CPAN::Frontend->mydie("Cannot unzip, no unzip program available");
328 my @system = ($unzip, $file);
329 return system(@system) == 0;
330 }
331}
332
3331;
334
26844e27 335__END__
336
337=head1 LICENSE
338
339This program is free software; you can redistribute it and/or
340modify it under the same terms as Perl itself.
341
342=cut