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