releasing/cbrtools/perl/Archive/Tar.pm
changeset 602 3145852acc89
equal deleted inserted replaced
600:6d08f4a05d93 602:3145852acc89
       
     1 # Copyright 1997 Calle Dybedahl. All rights reserved.
       
     2 # Copyright 1998 Stephen Zander. All rights reserved.
       
     3 #
       
     4 # It is currently developed by Stephen Zander <gibreel@pobox.com>
       
     5 #
       
     6 # This library is free software; you can redistribute it and/or modify
       
     7 # it under the same terms as Perl itself.
       
     8 
       
     9 package Archive::Tar;
       
    10 
       
    11 use strict;
       
    12 use Carp qw(carp);
       
    13 use Cwd;
       
    14 use Fcntl qw(O_RDONLY O_RDWR O_WRONLY O_CREAT O_TRUNC F_DUPFD F_GETFL);
       
    15 use File::Basename;
       
    16 use Symbol;
       
    17 require Time::Local if $^O eq "MacOS";
       
    18 
       
    19 use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS);
       
    20 $VERSION = do { my @a=q$Name: version_0_22 $ =~ /\d+/g; sprintf "%d." . ("%02d" x $#a ),@a };
       
    21 
       
    22 require Exporter;
       
    23 @ISA = qw(Exporter);
       
    24 
       
    25 @EXPORT_OK = qw(FILE HARDLINK SYMLINK 
       
    26 		CHARDEV BLOCKDEV DIR
       
    27 		FIFO SOCKET INVALID);
       
    28 %EXPORT_TAGS = (filetypes => \@EXPORT_OK);
       
    29 
       
    30 # Check if symbolic links are available
       
    31 my $symlinks = eval { readlink $0 or 1; };
       
    32 carp "Symbolic links not available"
       
    33     unless $symlinks || !$^W;
       
    34 
       
    35 # Check if Compress::Zlib is available
       
    36 my $compression = eval { 
       
    37     local $SIG{__DIE__};
       
    38     require Compress::Zlib; 
       
    39     sub Compress::Zlib::gzFile::gzseek {
       
    40 	my $tmp;
       
    41 
       
    42 	$_[0]->gzread ($tmp, 4096), $_[1] -= 4096
       
    43 	    while ($_[1] > 4096);
       
    44 
       
    45 	$_[0]->gzread ($tmp, $_[1])
       
    46 	  if $_[1];
       
    47     }
       
    48     1;
       
    49 };
       
    50 carp "Compression not available"
       
    51     unless $compression || !$^W;
       
    52 
       
    53 # Check for get* (they don't exist on WinNT)
       
    54 my $fake_getpwuid;
       
    55 $fake_getpwuid = "unknown"
       
    56     unless eval { $_ = getpwuid (0); }; # Pointless assigment to make -w shut up
       
    57 
       
    58 my $fake_getgrgid;
       
    59 $fake_getgrgid = "unknown"
       
    60     unless eval { $_ = getgrgid (0); }; # Pointless assigment to make -w shut up
       
    61 
       
    62 # Automagically detect gziped files if they start with this
       
    63 my $gzip_magic_number = "^(?:\037\213|\037\235)";
       
    64 
       
    65 my $tar_unpack_header 
       
    66     = 'A100 A8 A8 A8 A12 A12 A8 A1 A100 A6 A2 A32 A32 A8 A8 A155 x12';
       
    67 my $tar_pack_header
       
    68     = 'a100 a8 a8 a8 a12 a12 A8 a1 a100 a6 a2 a32 a32 a8 a8 a155 x12',
       
    69 my $tar_header_length = 512;
       
    70 
       
    71 my $time_offset = ($^O eq "MacOS") ? Time::Local::timelocal(0,0,0,1,0,70) : 0;
       
    72 
       
    73 ## Subroutines to return type constants 
       
    74 sub FILE() { return 0; }
       
    75 sub HARDLINK() { return 1; }
       
    76 sub SYMLINK() { return 2; }
       
    77 sub CHARDEV() { return 3; }
       
    78 sub BLOCKDEV() { return 4; }
       
    79 sub DIR() { return 5; }
       
    80 sub FIFO() { return 6; }
       
    81 sub SOCKET() { return 8; }
       
    82 sub UNKNOWN() { return 9; }
       
    83 
       
    84 ###
       
    85 ### Non-method functions
       
    86 ###
       
    87 
       
    88 my $error;
       
    89 sub _drat {
       
    90     $error = $! . '';
       
    91     return;
       
    92 }
       
    93 
       
    94 sub error {
       
    95     $error;
       
    96 }
       
    97 
       
    98 sub set_error {
       
    99     shift;
       
   100     $error = "@_";
       
   101 }
       
   102 
       
   103 ## filetype -- Determine the type value for a given file
       
   104 sub filetype {
       
   105     my $file = shift;
       
   106 
       
   107     return SYMLINK
       
   108 	if (-l $file);		# Symlink
       
   109 
       
   110     return FILE
       
   111 	if (-f _);		# Plain file
       
   112 
       
   113     return DIR
       
   114 	if (-d _);		# Directory
       
   115 
       
   116     return FIFO
       
   117 	if (-p _);		# Named pipe
       
   118 
       
   119     return SOCKET
       
   120 	if (-S _);		# Socket
       
   121 
       
   122     return BLOCKDEV
       
   123 	if (-b _);		# Block special
       
   124 
       
   125     return CHARDEV
       
   126 	if (-c _);		# Character special
       
   127 
       
   128     return UNKNOWN;		# Something else (like what?)
       
   129 }
       
   130 
       
   131 sub _make_special_file_UNIX {
       
   132     # $file is the last component of $entry->{name}
       
   133     my ($entry, $file) = @_;
       
   134 
       
   135     if ($entry->{type} == SYMLINK) {
       
   136 	symlink $entry->{linkname}, $file or
       
   137 	    $^W && carp ("Making symbolic link from ", $entry->{linkname}, 
       
   138 			 " to ", $entry->{name}, ", failed.\n");
       
   139     }
       
   140     elsif ($entry->{type} == HARDLINK) {
       
   141 	link $entry->{linkname}, $file or
       
   142 	    $^W && carp ("Hard linking ", $entry->{linkname}, 
       
   143 			 " to ", $entry->{name}, ", failed.\n");
       
   144     }
       
   145     elsif ($entry->{type} == FIFO) {
       
   146 	system("mknod","$file","p") or
       
   147 	    $^W && carp "Making fifo ", $entry->{name}, ", failed.\n";
       
   148     }
       
   149     elsif ($entry->{type} == BLOCKDEV) {
       
   150 	system("mknod","$file","b",$entry->{devmajor},$entry->{devminor}) or
       
   151 	    $^W && carp ("Making block device ", $entry->{name},
       
   152 			 " (maj=", $entry->{devmajor}, 
       
   153 			 ", min=", $entry->{devminor}, "), failed.\n");
       
   154     }
       
   155     elsif ($entry->{type} == CHARDEV) {
       
   156 	system("mknod", "$file", "c", $entry->{devmajor}, $entry->{devminor}) or
       
   157 	    $^W && carp ("Making block device ", $entry->{name}, 
       
   158 			 " (maj=", $entry->{devmajor}, 
       
   159 			 " ,min=", $entry->{devminor}, "), failed.\n");
       
   160     }
       
   161 }
       
   162 
       
   163 sub _make_special_file_Win32 {
       
   164     # $file is the last component of $entry->{name}
       
   165     my ($entry, $file) = @_;
       
   166 
       
   167     if ($entry->{type} == SYMLINK) {
       
   168 	$^W && carp ("Making symbolic link from ", $entry->{linkname}, 
       
   169 		     " to ", $entry->{name}, ", failed.\n");
       
   170     }
       
   171     elsif ($entry->{type} == HARDLINK) {
       
   172 	link $entry->{linkname}, $file or
       
   173 	    $^W && carp ("Making hard link from ", $entry->{linkname}, 
       
   174 			 " to ", $entry->{name}, ", failed.\n");
       
   175     }
       
   176     elsif ($entry->{type} == FIFO) {
       
   177 	$^W && carp "Making fifo ", $entry->{name}, ", failed.\n";
       
   178     }
       
   179     elsif ($entry->{type} == BLOCKDEV) {
       
   180 	$^W && carp ("Making block device ", $entry->{name},
       
   181 		     " (maj=", $entry->{devmajor}, 
       
   182 		     ", min=", $entry->{devminor}, "), failed.\n");
       
   183     }
       
   184     elsif ($entry->{type} == CHARDEV) {
       
   185 	$^W && carp ("Making block device ", $entry->{name},
       
   186 		     " (maj=", $entry->{devmajor}, 
       
   187 		     " ,min=", $entry->{devminor}, "), failed.\n");
       
   188     }
       
   189 }
       
   190 
       
   191 *_make_special_file = $^O eq "MSWin32" ? 
       
   192     \&_make_special_file_Win32 : \&_make_special_file_UNIX;
       
   193 
       
   194 sub _munge_file {
       
   195 #
       
   196 #  Mac path to the Unix like equivalent to be used in tar archives
       
   197 #
       
   198     my $inpath = $_[0];
       
   199 #
       
   200 #  If there are no :'s in the name at all, assume it's a single item in the
       
   201 #  current directory.  Return it, changing any / in the name into :
       
   202 #
       
   203     if ($inpath !~ m,:,) {
       
   204 	$inpath =~ s,/,:,g;
       
   205 	return $inpath;
       
   206     }
       
   207 #
       
   208 #  If we now split on :, there will be just as many nulls in the list as
       
   209 #  there should be up requests, except if it begins with a :, where there
       
   210 #  will be one extra.
       
   211 #
       
   212     my @names = split (/:/, $inpath);
       
   213     shift (@names)
       
   214 	if ($names[0] eq "");
       
   215     my @outname = ();
       
   216 #
       
   217 #  Work from the end.
       
   218 #
       
   219     my $i;
       
   220     for ($i = $#names; $i >= 0; --$i) {
       
   221 	if ($names[$i] eq "") {
       
   222 	    unshift (@outname, "..");
       
   223 	} 
       
   224 	else {
       
   225 	    $names[$i] =~ s,/,:,g;
       
   226 	    unshift (@outname, $names[$i]);
       
   227 	}
       
   228     }
       
   229     my $netpath = join ("/", @outname);
       
   230     $netpath = $netpath . "/" if ($inpath =~ /:$/);
       
   231     if ($inpath !~ m,^:,) {
       
   232 	return "/".$netpath;
       
   233     } 
       
   234     else {
       
   235 	return $netpath;
       
   236     }
       
   237 }
       
   238 
       
   239 sub _get_handle {
       
   240     my ($fh, $flags, $mode);
       
   241 
       
   242     sysseek ($_[0], 0, 0)
       
   243 	or goto &_drat;
       
   244 
       
   245     if ($^O eq "MSWin32") {
       
   246 	$fh = $_[0];
       
   247     }
       
   248     else {
       
   249 	$fh = fcntl ($_[0], F_DUPFD, 0)
       
   250 	    or goto &_drat;
       
   251     }
       
   252     if ($compression && (@_ < 2 || $_[1] != 0)) {
       
   253 	$mode = $#_ ? (int($_[1]) > 1 ?
       
   254 			  "wb".int($_[1]) : "wb") : "rb";
       
   255 
       
   256 	$fh = Compress::Zlib::gzdopen_ ($fh, $mode, 0)
       
   257 	    or &_drat;
       
   258     }
       
   259     else {
       
   260 	$flags = fcntl ($_[0], F_GETFL, 0) & (O_RDONLY | O_WRONLY | O_RDWR);
       
   261 	$mode = ($flags == O_WRONLY) ? ">&=$fh" : 
       
   262 	    ($flags == O_RDONLY) ? "<&=$fh" : "+>&=$fh";
       
   263 	$fh = gensym;
       
   264 	open ($fh, $mode)
       
   265 	  or goto &_drat;
       
   266 
       
   267 	$fh = bless *{$fh}{IO}, "Archive::Tar::_io";
       
   268 	binmode $fh
       
   269 	    or goto &_drat;
       
   270     }
       
   271 
       
   272     return $fh;
       
   273 }
       
   274 
       
   275 sub _read_tar {
       
   276     my ($file, $seekable, $extract) = @_;
       
   277     my $tarfile = [];
       
   278     my ($head, $offset, $size);
       
   279 
       
   280     $file->gzread ($head, $tar_header_length)
       
   281 	or goto &_drat;
       
   282 
       
   283     if (substr ($head, 0, 2) =~ /$gzip_magic_number/o) {
       
   284 	$error =
       
   285 	    "Compression not available\n";
       
   286 	return undef;
       
   287     }
       
   288 
       
   289     $offset = $tar_header_length
       
   290 	if $seekable;
       
   291 
       
   292  READLOOP:
       
   293     while (length ($head) == $tar_header_length) {
       
   294 	my ($name,		# string
       
   295 	    $mode,		# octal number
       
   296 	    $uid,		# octal number
       
   297 	    $gid,		# octal number
       
   298 	    $size,		# octal number
       
   299 	    $mtime,		# octal number
       
   300 	    $chksum,		# octal number
       
   301 	    $type,		# character
       
   302 	    $linkname,		# string
       
   303 	    $magic,		# string
       
   304 	    $version,		# two bytes
       
   305 	    $uname,		# string
       
   306 	    $gname,		# string
       
   307 	    $devmajor,		# octal number
       
   308 	    $devminor,		# octal number
       
   309 	    $prefix) = unpack ($tar_unpack_header, $head);
       
   310 	my ($data, $block, $entry);
       
   311 
       
   312 	$mode = oct $mode;
       
   313 	$uid = oct $uid;
       
   314 	$gid = oct $gid;
       
   315 	$size = oct $size;
       
   316 	$mtime = oct $mtime;
       
   317 	$chksum = oct $chksum;
       
   318 	$devmajor = oct $devmajor;
       
   319 	$devminor = oct $devminor;
       
   320 	$name = $prefix."/".$name if $prefix;
       
   321 	$prefix = "";
       
   322 	# some broken tar-s don't set the type for directories
       
   323 	# so we ass_u_me a directory if the name ends in slash
       
   324 	$type = DIR
       
   325 	    if $name =~ m|/$| and $type == FILE;
       
   326 
       
   327 	last READLOOP if $head eq "\0" x 512; # End of archive
       
   328 	# Apparently this should really be two blocks of 512 zeroes,
       
   329 	# but GNU tar sometimes gets it wrong. See comment in the
       
   330 	# source code (tar.c) to GNU cpio.
       
   331 
       
   332 	substr ($head, 148, 8) = "        ";
       
   333 	if (unpack ("%16C*", $head) != $chksum) {
       
   334 	   warn "$name: checksum error.\n";
       
   335 	}
       
   336 
       
   337 	unless ($extract || $type != FILE) {
       
   338 	    # Always read in full 512 byte blocks
       
   339 	    $block = $size & 0x01ff ? ($size & ~0x01ff) + 512 : $size;
       
   340 	    if ($seekable) {
       
   341 		while ($block > 4096) {
       
   342 		    $file->gzread ($data, 4096)
       
   343 			or goto &_drat;
       
   344 		    $block -= 4096;
       
   345 		}
       
   346 		$file->gzread ($data, $block)
       
   347 		    or goto &_drat
       
   348 			if ($block);
       
   349 
       
   350 		# Ignore everything we've just read.
       
   351 		undef $data;
       
   352 	    } else {
       
   353 		if ($file->gzread ($data, $block) < $block) {
       
   354 		    $error = "Read error on tarfile.";
       
   355 		    return undef;
       
   356 		}
       
   357 
       
   358 		# Throw away any trailing garbage
       
   359 		substr ($data, $size) = "";
       
   360 	    }
       
   361 	}
       
   362 
       
   363 	# Guard against tarfiles with garbage at the end
       
   364 	last READLOOP if $name eq ''; 
       
   365 
       
   366 	$entry = {name => $name,		    
       
   367 		  mode => $mode,
       
   368 		  uid => $uid,
       
   369 		  gid => $gid,
       
   370 		  size => $size,
       
   371 		  mtime => $mtime,
       
   372 		  chksum => $chksum,
       
   373 		  type => $type,
       
   374 		  linkname => $linkname,
       
   375 		  magic => $magic,
       
   376 		  version => $version,
       
   377 		  uname => $uname,
       
   378 		  gname => $gname,
       
   379 		  devmajor => $devmajor,
       
   380 		  devminor => $devminor,
       
   381 		  prefix => $prefix,
       
   382 		  offset => $offset,
       
   383 		  data => $data};
       
   384 
       
   385 	if ($extract) {
       
   386 	    _extract_file ($entry, $file);
       
   387 	    $file->gzread ($head, 512 - ($size & 0x1ff)) 
       
   388 		or goto &_drat
       
   389 		    if ($size & 0x1ff && $type == FILE);
       
   390 	}
       
   391 	else {
       
   392 	    push @$tarfile, $entry;
       
   393 	}
       
   394 
       
   395 	if ($seekable) {
       
   396 	    $offset += $tar_header_length;
       
   397 	    $offset += ($size & 0x01ff) ? ($size & ~0x01ff) + 512 : $size
       
   398 		if $type == FILE;
       
   399 	}
       
   400 	$file->gzread ($head, $tar_header_length) 
       
   401 	    or goto &_drat;
       
   402     }
       
   403 
       
   404     $file->gzclose ()
       
   405 	unless $seekable;
       
   406 
       
   407     return $tarfile
       
   408 	unless $extract;
       
   409 }
       
   410 
       
   411 sub _format_tar_entry {
       
   412     my ($ref) = shift;
       
   413     my ($tmp,$file,$prefix,$pos);
       
   414 
       
   415     $file = $ref->{name};
       
   416     if (length ($file) > 99) {
       
   417 	$pos = index $file, "/", (length ($file) - 100);
       
   418 	next
       
   419 	    if $pos == -1;	# Filename longer than 100 chars!
       
   420 
       
   421 	$prefix = substr $file,0,$pos;
       
   422 	$file = substr $file,$pos+1;
       
   423 	substr ($prefix, 0, -155) = ""
       
   424 	    if length($prefix)>154;
       
   425     }
       
   426     else {
       
   427 	$prefix="";
       
   428     }
       
   429 
       
   430     $tmp = pack ($tar_pack_header,
       
   431 		 $file,
       
   432 		 sprintf("%06o ",$ref->{mode}),
       
   433 		 sprintf("%06o ",$ref->{uid}),
       
   434 		 sprintf("%06o ",$ref->{gid}),
       
   435 		 sprintf("%11o ",$ref->{size}),
       
   436 		 sprintf("%11o ",$ref->{mtime}),
       
   437 		 "",		#checksum field - space padded by pack("A8")
       
   438 		 $ref->{type},
       
   439 		 $ref->{linkname},
       
   440 		 $ref->{magic},
       
   441 		 $ref->{version} || '00',
       
   442 		 $ref->{uname},
       
   443 		 $ref->{gname},
       
   444 		 sprintf("%6o ",$ref->{devmajor}),
       
   445 		 sprintf("%6o ",$ref->{devminor}),
       
   446 		 $prefix);
       
   447     substr($tmp,148,7) = sprintf("%6o\0", unpack("%16C*",$tmp));
       
   448 
       
   449     return $tmp;
       
   450 }
       
   451 
       
   452 sub _format_tar_file {
       
   453     my @tarfile = @_;
       
   454     my $file = "";
       
   455 
       
   456     foreach (@tarfile) {
       
   457 	$file .= _format_tar_entry $_;
       
   458 	$file .= $_->{data};
       
   459 	$file .= "\0" x (512 - ($_->{size} & 0x1ff))
       
   460 	    if ($_->{size} & 0x1ff);
       
   461     }
       
   462     $file .= "\0" x 1024;
       
   463 
       
   464     return $file;
       
   465 }
       
   466 
       
   467 sub _write_tar {
       
   468     my $file = shift;
       
   469     my $entry;
       
   470 
       
   471     foreach $entry ((ref ($_[0]) eq 'ARRAY') ? @{$_[0]} : @_) {
       
   472 	next
       
   473 	    unless (ref ($entry) eq 'HASH');
       
   474 
       
   475 	my $src;
       
   476         if ($^O eq "MacOS") {  #convert back from Unix to Mac path
       
   477             my @parts = split(/\//, $entry->{name});
       
   478 
       
   479             $src = $parts[0] ? ":" : "";
       
   480             foreach (@parts) {
       
   481 		next if !$_ || $_ eq ".";  
       
   482                 s,:,/,g;
       
   483 
       
   484 		$_ = ":"
       
   485 		    if ($_ eq "..");
       
   486 
       
   487 		$src .= ($src =~ /:$/) ? $_ : ":$_";
       
   488 	    }
       
   489         }
       
   490 	else {
       
   491             $src = $entry->{name};
       
   492         }
       
   493 	sysopen (FH, $src, O_RDONLY)
       
   494 	    && binmode (FH)
       
   495 		or next
       
   496 		    unless $entry->{type} != FILE || $entry->{data};
       
   497 
       
   498 	$file->gzwrite (_format_tar_entry ($entry))
       
   499 	    or goto &_drat;
       
   500 
       
   501 	if ($entry->{type} == FILE) {
       
   502 	    if ($entry->{data}) {
       
   503 		$file->gzwrite ($entry->{data})
       
   504 		    or goto &_drat;
       
   505 	    }
       
   506 	    else {
       
   507 		my $size = $entry->{size};
       
   508 		my $data;
       
   509 		while ($size >= 4096) {
       
   510 		    sysread (FH, $data, 4096)
       
   511 			&& $file->gzwrite ($data)
       
   512 			    or goto &_drat;
       
   513 		    $size -= 4096;
       
   514 		}
       
   515 		sysread (FH, $data, $size)
       
   516 		    && $file->gzwrite ($data)
       
   517 			or goto &_drat
       
   518 			    if $size;
       
   519 		close FH;
       
   520 	    }
       
   521 	    $file->gzwrite ("\0" x (512 - ($entry->{size} & 511)))
       
   522 		or goto &_drat
       
   523 		    if ($entry->{size} & 511);
       
   524 	}
       
   525     }
       
   526 
       
   527     $file->gzwrite ("\0" x 1024)
       
   528 	and !$file->gzclose ()
       
   529 	    or goto &_drat;
       
   530 }
       
   531 
       
   532 sub _add_file {
       
   533     my $file = shift;
       
   534     my ($mode,$nlnk,$uid,$gid,$rdev,$size,$mtime,$type,$linkname);
       
   535 
       
   536     if (($mode,$nlnk,$uid,$gid,$rdev,$size,$mtime) = (lstat $file)[2..7,9]) {
       
   537 	$linkname = "";
       
   538 	$type = filetype ($file);
       
   539 
       
   540 	$linkname = readlink $file
       
   541 	    if ($type == SYMLINK) && $symlinks;
       
   542 
       
   543 	$file = _munge_file ($file)
       
   544 	    if ($^O eq "MacOS");
       
   545 
       
   546 	return +{name => $file,		    
       
   547 		 mode => $mode,
       
   548 		 uid => $uid,
       
   549 		 gid => $gid,
       
   550 		 size => $size,
       
   551 		 mtime => (($mtime - $time_offset) | 0),
       
   552 		 chksum => "      ",
       
   553 		 type => $type, 
       
   554 		 linkname => $linkname,
       
   555 		 magic => "ustar",
       
   556 		 version => "00",
       
   557 		 # WinNT protection
       
   558 		 uname => ($fake_getpwuid || scalar getpwuid($uid)),
       
   559 		 gname => ($fake_getgrgid || scalar getgrgid ($gid)),
       
   560 		 devmajor => 0, # We don't handle this yet
       
   561 		 devminor => 0, # We don't handle this yet
       
   562 		 prefix => "",
       
   563 		 data => undef,
       
   564 		};
       
   565     }
       
   566 }
       
   567 
       
   568 sub _extract_file {
       
   569     my ($entry, $handle) = @_;
       
   570     my ($file, $cwd, @path);
       
   571 
       
   572     # For the moment, we assume that all paths in tarfiles
       
   573     # are given according to Unix standards.
       
   574     # Which they *are*, according to the tar format spec!
       
   575     @path = split(/\//,$entry->{name});
       
   576     $path[0] = '/' unless defined $path[0]; # catch absolute paths
       
   577     $file = pop @path;
       
   578     $file =~ s,:,/,g
       
   579 	if $^O eq "MacOS";
       
   580     $cwd = cwd
       
   581 	if @path;
       
   582     foreach (@path) {
       
   583 	if ($^O eq "MacOS") {
       
   584 	    s,:,/,g;
       
   585 	    $_ = "::" if $_ eq "..";
       
   586 	    $_ = ":" if $_ eq ".";
       
   587 	}
       
   588 	if (-e $_ && ! -d _) {
       
   589 	    $^W && carp "$_ exists but is not a directory!\n";
       
   590 	    next;
       
   591 	}
       
   592 	mkdir $_, 0777 unless -d _;
       
   593 	chdir $_;
       
   594     }
       
   595 
       
   596     if ($entry->{type} == FILE) {	# Ordinary file
       
   597 	sysopen (FH, $file, O_WRONLY|O_CREAT|O_TRUNC)
       
   598 	    and binmode FH
       
   599 		or goto &_drat;
       
   600 
       
   601 	if ($handle) {
       
   602 	    my $size = $entry->{size};
       
   603 	    my $data;
       
   604 	    while ($size > 4096) {
       
   605 		$handle->gzread ($data, 4096)
       
   606 		    and syswrite (FH, $data, length $data)
       
   607 			or goto &_drat;
       
   608 		$size -= 4096;
       
   609 	    }
       
   610 	    $handle->gzread ($data, $size)
       
   611 		and syswrite (FH, $data, length $data)
       
   612 		    or goto &_drat
       
   613 			if ($size);
       
   614 	}
       
   615 	else {
       
   616 	    syswrite FH, $entry->{data}, $entry->{size}
       
   617 		or goto &_drat
       
   618 	}
       
   619 	close FH
       
   620 	    or goto &_drat
       
   621     }
       
   622     elsif ($entry->{type} == DIR) { # Directory
       
   623 	goto &_drat
       
   624 	    if (-e $file && ! -d $file);
       
   625 
       
   626 	mkdir $file,0777
       
   627 	    unless -d $file;
       
   628     }
       
   629     elsif ($entry->{type} == UNKNOWN) {
       
   630 	$error = "unknown file type: $_->{type}";
       
   631 	return undef;
       
   632     }
       
   633     else {
       
   634 	_make_special_file ($entry, $file);
       
   635     }
       
   636     utime time, $entry->{mtime} + $time_offset, $file;
       
   637 
       
   638     # We are root, and chown exists
       
   639     chown $entry->{uid}, $entry->{gid}, $file
       
   640 	if ($> == 0 and $^O ne "MacOS" and $^O ne "MSWin32");
       
   641 
       
   642     # chmod is done last, in case it makes file readonly
       
   643     # (this accomodates DOSish OSes)
       
   644     chmod $entry->{mode}, $file;
       
   645     chdir $cwd
       
   646 	if @path;
       
   647 }
       
   648 
       
   649 ###
       
   650 ### Methods
       
   651 ###
       
   652 
       
   653 ##
       
   654 ## Class methods
       
   655 ##
       
   656 
       
   657 # Perfom the equivalent of ->new()->add_files(), ->write() without the
       
   658 # overhead of maintaining an Archive::Tar object.
       
   659 sub create_archive {
       
   660     my ($handle, $file, $compress) = splice (@_, 0, 3);
       
   661 
       
   662     if ($compress && !$compression) {
       
   663 	$error = "Compression not available.\n";
       
   664 	return undef;
       
   665     }
       
   666 
       
   667     $handle = gensym;
       
   668     open $handle, ref ($file) ? ">&". fileno ($file) : ">" . $file
       
   669 	and binmode ($handle)
       
   670 	    or goto &_drat;
       
   671 
       
   672     _write_tar (_get_handle ($handle, int ($compress)),
       
   673 		map {_add_file ($_)} @_);
       
   674 }
       
   675 
       
   676 # Perfom the equivalent of ->new()->list_files() without the overhead
       
   677 # of maintaining an Archive::Tar object.
       
   678 sub list_archive {
       
   679     my ($handle, $file, $fields) = @_;
       
   680 
       
   681     $handle = gensym;
       
   682     open $handle, ref ($file) ? "<&". fileno ($file) : "<" . $file
       
   683 	and binmode ($handle)
       
   684 	    or goto &_drat;
       
   685 
       
   686     my $data = _read_tar (_get_handle ($handle), 1);
       
   687 
       
   688     return map {my %h; @h{@$fields} = @$_{@$fields}; \%h} @$data
       
   689         if (ref $fields eq 'ARRAY'
       
   690 	    && (@$fields > 1 || $fields->[0] ne 'name'));
       
   691 
       
   692     return map {$_->{name}} @$data;
       
   693 }
       
   694 
       
   695 # Perform the equivalen of ->new()->extract() without the overhead of
       
   696 # maintaining an Archive::Tar object.
       
   697 sub extract_archive {
       
   698     my ($handle, $file) = @_;
       
   699 
       
   700     $handle = gensym;
       
   701     open $handle, ref ($file) ? "<&". fileno ($file) : "<" . $file
       
   702 	and binmode ($handle)
       
   703 	    or goto &_drat;
       
   704 
       
   705     _read_tar (_get_handle ($handle), 0, 1);
       
   706 }
       
   707 
       
   708 # Constructor. Reads tarfile if given an argument that's the name of a
       
   709 # readable file.
       
   710 sub new {
       
   711     my ($class, $file) = @_;
       
   712 
       
   713     my $self = bless {}, $class;
       
   714 
       
   715     $self->read ($file)
       
   716       if defined $file;
       
   717 
       
   718     return $self;
       
   719 }
       
   720 
       
   721 
       
   722 # Read a tarfile. Returns number of component files.
       
   723 sub read {
       
   724     my ($self, $file) = @_;
       
   725 
       
   726     $self->{_data} = [];
       
   727 
       
   728     $self->{_handle} = gensym;
       
   729     open $self->{_handle}, ref ($file) ? "<&". fileno ($file) : "<" . $file
       
   730 	and binmode ($self->{_handle})
       
   731 	    or goto &_drat;
       
   732 
       
   733     $self->{_data} = _read_tar (_get_handle ($self->{_handle}), 
       
   734 				  sysseek $self->{_handle}, 0, 1);
       
   735     return scalar @{$self->{_data}};
       
   736 }
       
   737 
       
   738 # Write a tar archive to file
       
   739 sub write {
       
   740     my ($self, $file, $compress) = @_;
       
   741 
       
   742     return _format_tar_file (@{$self->{_data}})
       
   743 	unless (@_ > 1);
       
   744 
       
   745     my $handle = gensym;
       
   746     open $handle, ref ($file) ? ">&". fileno ($file) : ">" . $file
       
   747 	and binmode ($handle)
       
   748 	    or goto &_drat;
       
   749 
       
   750     if ($compress && !$compression) {
       
   751 	$error = "Compression not available.\n";
       
   752 	return undef;
       
   753     }
       
   754 
       
   755     _write_tar (_get_handle ($handle, $compress || 0), $self->{_data});
       
   756 }
       
   757 
       
   758 # Add files to the archive. Returns number of successfully added files.
       
   759 sub add_files {
       
   760     my $self = shift;
       
   761     my ($counter, $file, $entry);
       
   762 
       
   763     foreach $file (@_) {
       
   764 	if ($entry = _add_file ($file)) {
       
   765 	    push (@{$self->{'_data'}}, $entry);
       
   766 	    ++$counter;
       
   767 	}
       
   768     }
       
   769 
       
   770     return $counter;
       
   771 }
       
   772 
       
   773 # Add data as a file
       
   774 sub add_data {
       
   775     my ($self, $file, $data, $opt) = @_;
       
   776     my $ref = {};
       
   777     my ($key);
       
   778 
       
   779     if($^O eq "MacOS") {
       
   780 	$file = _munge_file($file);
       
   781     }
       
   782     $ref->{'data'} = $data;
       
   783     $ref->{name} = $file;
       
   784     $ref->{mode} = 0666 & (0777 - umask);
       
   785     $ref->{uid} = $>;
       
   786     $ref->{gid} = (split(/ /,$)))[0]; # Yuck
       
   787     $ref->{size} = length $data;
       
   788     $ref->{mtime} = ((time - $time_offset) | 0),
       
   789     $ref->{chksum} = "      ";	# Utterly pointless
       
   790     $ref->{type} = FILE;		# Ordinary file
       
   791     $ref->{linkname} = "";
       
   792     $ref->{magic} = "ustar";
       
   793     $ref->{version} = "00";
       
   794     # WinNT protection
       
   795     $ref->{uname} = $fake_getpwuid || getpwuid ($>);
       
   796     $ref->{gname} = $fake_getgrgid || getgrgid ($ref->{gid});
       
   797     $ref->{devmajor} = 0;
       
   798     $ref->{devminor} = 0;
       
   799     $ref->{prefix} = "";
       
   800 
       
   801     if ($opt) {
       
   802 	foreach $key (keys %$opt) {
       
   803 	    $ref->{$key} = $opt->{$key}
       
   804 	}
       
   805     }
       
   806 
       
   807     push (@{$self->{'_data'}}, $ref);
       
   808     return 1;
       
   809 }
       
   810 
       
   811 sub rename {
       
   812     my ($self) = shift;
       
   813     my $entry;
       
   814 
       
   815     foreach $entry (@{$self->{_data}}) {
       
   816 	@{$self->{_data}} = grep {$_->{name} ne $entry} @{$self->{'_data'}};
       
   817     }
       
   818     return $self;
       
   819 }
       
   820 
       
   821 sub remove {
       
   822     my ($self) = shift;
       
   823     my $entry;
       
   824 
       
   825     foreach $entry (@_) {
       
   826 	@{$self->{_data}} = grep {$_->{name} ne $entry} @{$self->{'_data'}};
       
   827     }
       
   828     return $self;
       
   829 }
       
   830 
       
   831 # Get the content of a file
       
   832 sub get_content {
       
   833     my ($self, $file) = @_;
       
   834     my ($entry, $data);
       
   835 
       
   836     foreach $entry (@{$self->{_data}}) {
       
   837 	next
       
   838 	    unless $entry->{name} eq $file;
       
   839 
       
   840 	return $entry->{data}
       
   841 	    unless $entry->{offset};
       
   842 
       
   843 	my $handle = _get_handle ($self->{_handle});
       
   844 	$handle->gzseek ($entry->{offset}, 0)
       
   845 	    or goto &_drat;
       
   846 
       
   847 	$handle->gzread ($data, $entry->{size}) != -1
       
   848 	    or goto &_drat;
       
   849 
       
   850 	return $data;
       
   851     }
       
   852 
       
   853     return;
       
   854 }
       
   855 
       
   856 # Replace the content of a file
       
   857 sub replace_content {
       
   858     my ($self, $file, $content) = @_;
       
   859     my $entry;
       
   860 
       
   861     foreach $entry (@{$self->{_data}}) {
       
   862 	next
       
   863 	    unless $entry->{name} eq $file;
       
   864 
       
   865 	$entry->{data} = $content;
       
   866 	$entry->{size} = length $content;
       
   867 	$entry->{offset} = undef;
       
   868 	return 1;
       
   869     }
       
   870 }
       
   871 
       
   872 # Write a single (probably) file from the in-memory archive to disk
       
   873 sub extract {
       
   874     my $self = shift;
       
   875     my @files = @_;
       
   876     my ($file, $entry);
       
   877 
       
   878     @files = list_files ($self) unless @files;
       
   879     foreach $entry (@{$self->{_data}}) {
       
   880 	my $cnt = 0;
       
   881 	foreach $file (@files) {
       
   882 	    ++$cnt, next
       
   883 		unless $entry->{name} eq $file;
       
   884 	    my $handle = $entry->{offset} && _get_handle ($self->{_handle});
       
   885 	    $handle->gzseek ($entry->{offset}, 0)
       
   886 		or goto &_drat
       
   887 		    if $handle;
       
   888 	    _extract_file ($entry, $handle);
       
   889 	    splice (@_, $cnt, 1);
       
   890 	    last;
       
   891 	}
       
   892 	last
       
   893 	    unless @_;
       
   894     }
       
   895     $self;
       
   896 }
       
   897 
       
   898 
       
   899 # Return a list names or attribute hashes for all files in the
       
   900 # in-memory archive.
       
   901 sub list_files {
       
   902  my ($self, $fields) = @_;
       
   903 
       
   904     return map {my %h; @h{@$fields} = @$_{@$fields}; \%h} @{$self->{'_data'}}
       
   905     if (ref $fields eq 'ARRAY' && (@$fields > 1 || $fields->[0] ne 'name'));
       
   906 
       
   907     return map {$_->{name}} @{$self->{'_data'}}
       
   908 }
       
   909 
       
   910 
       
   911 ### Standard end of module :-)
       
   912 1;
       
   913 
       
   914 # 
       
   915 # Sub-package to hide I/O differences between compressed &
       
   916 # uncompressed archives.
       
   917 #
       
   918 # Yes, I could have used the IO::* class hierarchy here, but I'm
       
   919 # trying to minimise the necessity for non-core modules on perl5
       
   920 # environments < 5.004
       
   921 
       
   922 package Archive::Tar::_io;
       
   923 
       
   924 sub gzseek {
       
   925     sysseek $_[0], $_[1], $_[2];
       
   926 }
       
   927 
       
   928 sub gzread {
       
   929     sysread $_[0], $_[1], $_[2];
       
   930 }
       
   931 
       
   932 sub gzwrite {
       
   933     syswrite $_[0], $_[1], length $_[1];
       
   934 }
       
   935 
       
   936 sub gzclose {
       
   937     !close $_[0];
       
   938 }
       
   939 
       
   940 1;
       
   941 
       
   942 __END__
       
   943 
       
   944 =head1 NAME
       
   945 
       
   946 Tar - module for manipulation of tar archives.
       
   947 
       
   948 =head1 SYNOPSIS
       
   949 
       
   950   use Archive::Tar;
       
   951 
       
   952   Archive::Tar->create_archive ("my.tar.gz", 9, "/this/file", "/that/file");
       
   953   print join "\n", Archive::Tar->list_archive ("my.tar.gz"), "";
       
   954 
       
   955   $tar = Archive::Tar->new();
       
   956   $tar->read("origin.tar.gz",1);
       
   957   $tar->add_files("file/foo.c", "file/bar.c");
       
   958   $tar->add_data("file/baz.c","This is the file contents");
       
   959   $tar->write("files.tar");
       
   960 
       
   961 =head1 DESCRIPTION
       
   962 
       
   963 This is a module for the handling of tar archives. 
       
   964 
       
   965 Archive::Tar provides an object oriented mechanism for handling tar
       
   966 files.  It provides class methods for quick and easy files handling
       
   967 while also allowing for the creation of tar file objects for custom
       
   968 manipulation.  If you have the Compress::Zlib module installed,
       
   969 Archive::Tar will also support compressed or gzipped tar files.
       
   970 
       
   971 =head2 Class Methods
       
   972 
       
   973 The class methods should be sufficient for most tar file interaction.
       
   974 
       
   975 =over 4
       
   976 
       
   977 =item create_archive ($file, $compression, @filelist)
       
   978 
       
   979 Creates a tar file from the list of files provided.  The first
       
   980 argument can either be the name of the tar file to create or a
       
   981 reference to an open file handle (e.g. a GLOB reference).
       
   982 
       
   983 The second argument specifies the level of compression to be used, if
       
   984 any.  Compression of tar files requires the installation of the
       
   985 Compress::Zlib module.  Specific levels or compression may be
       
   986 requested by passing a value between 2 and 9 as the second argument.
       
   987 Any other value evaluating as true will result in the default
       
   988 compression level being used.
       
   989 
       
   990 The remaining arguments list the files to be included in the tar file.
       
   991 These files must all exist.  Any files which don\'t exist or can\'t be
       
   992 read are silently ignored.
       
   993 
       
   994 If the archive creation fails for any reason, C<create_archive> will
       
   995 return undef.  Please use the C<error> method to find the cause of the
       
   996 failure.
       
   997 
       
   998 =item list_archive ($file, ['property', 'property',...])
       
   999 
       
  1000 =item list_archive ($file)
       
  1001 
       
  1002 Returns a list of the names of all the files in the archive.  The
       
  1003 first argument can either be the name of the tar file to create or a
       
  1004 reference to an open file handle (e.g. a GLOB reference).
       
  1005 
       
  1006 If C<list_archive()> is passed an array reference as its second
       
  1007 argument it returns a list of hash references containing the requested
       
  1008 properties of each file.  The following list of properties is
       
  1009 supported: name, size, mtime (last modified date), mode, uid, gid,
       
  1010 linkname, uname, gname, devmajor, devminor, prefix.
       
  1011 
       
  1012 Passing an array reference containing only one element, 'name', is
       
  1013 special cased to return a list of names rather than a list of hash
       
  1014 references.
       
  1015 
       
  1016 =item extract_archive ($file)
       
  1017 
       
  1018 Extracts the contents of the tar file.  The first argument can either
       
  1019 be the name of the tar file to create or a reference to an open file
       
  1020 handle (e.g. a GLOB reference).  All relative paths in the tar file will
       
  1021 be created underneath the current working directory.
       
  1022 
       
  1023 If the archive extraction fails for any reason, C<extract_archive>
       
  1024 will return undef.  Please use the C<error> method to find the cause
       
  1025 of the failure.
       
  1026 
       
  1027 =item new ($file)
       
  1028 
       
  1029 =item new ()
       
  1030 
       
  1031 Returns a new Tar object. If given any arguments, C<new()> calls the
       
  1032 C<read()> method automatically, parsing on the arguments provided L<read()>.
       
  1033 
       
  1034 If C<new()> is invoked with arguments and the read method fails for
       
  1035 any reason, C<new()> returns undef.
       
  1036 
       
  1037 =back
       
  1038 
       
  1039 =head2 Instance Methods
       
  1040 
       
  1041 =over 4
       
  1042 
       
  1043 =item read ($ref, $compressed)
       
  1044 
       
  1045 Read the given tar file into memory. The first argument can either be
       
  1046 the name of a file or a reference to an already open file handle (e.g. a
       
  1047 GLOB reference).  The second argument indicates whether the file
       
  1048 referenced by the first argument is compressed.
       
  1049 
       
  1050 The second argument is now optional as Archive::Tar will automatically
       
  1051 detect compressed archives.
       
  1052 
       
  1053 The C<read> will I<replace> any previous content in C<$tar>!
       
  1054 
       
  1055 =item add_files(@filenamelist)
       
  1056 
       
  1057 Takes a list of filenames and adds them to the in-memory archive.  On
       
  1058 MacOS, the path to the file is automatically converted to a Unix like
       
  1059 equivalent for use in the archive, and the file\'s modification time
       
  1060 is converted from the MacOS epoch to the Unix epoch.  So tar archives
       
  1061 created on MacOS with B<Archive::Tar> can be read both with I<tar> on
       
  1062 Unix and applications like I<suntar> or I<Stuffit Expander> on MacOS.
       
  1063 Be aware that the file\'s type/creator and resource fork will be lost,
       
  1064 which is usually what you want in cross-platform archives.
       
  1065 
       
  1066 =item add_data ($filename, $data, $opthashref)
       
  1067 
       
  1068 Takes a filename, a scalar full of data and optionally a reference to
       
  1069 a hash with specific options. Will add a file to the in-memory
       
  1070 archive, with name C<$filename> and content C<$data>. Specific
       
  1071 properties can be set using C<$opthashref>, The following list of
       
  1072 properties is supported: name, size, mtime (last modified date), mode,
       
  1073 uid, gid, linkname, uname, gname, devmajor, devminor, prefix.  (On
       
  1074 MacOS, the file\'s path and modification times are converted to Unix
       
  1075 equivalents.)
       
  1076 
       
  1077 =item remove (@filenamelist)
       
  1078 
       
  1079 Removes any entries with names matching any of the given filenames
       
  1080 from the in-memory archive. String comparisons are done with C<eq>.
       
  1081 
       
  1082 =item write ($file, $compressed)
       
  1083 
       
  1084 Write the in-memory archive to disk.  The first argument can either be
       
  1085 the name of a file or a reference to an already open file handle (be a
       
  1086 GLOB reference).  If the second argument is true, the module will use
       
  1087 Compress::Zlib to write the file in a compressed format.  If
       
  1088 Compress:Zlib is not available, the C<write> method will fail.
       
  1089 Specific levels of compression can be chosen by passing the values 2
       
  1090 through 9 as the second parameter.
       
  1091 
       
  1092 If no arguments are given, C<write> returns the entire formatted
       
  1093 archive as a string, which could be useful if you\'d like to stuff the
       
  1094 archive into a socket or a pipe to gzip or something.  This
       
  1095 functionality may be deprecated later, however, as you can also do
       
  1096 this using a GLOB reference for the first argument.
       
  1097 
       
  1098 =item extract(@filenames)
       
  1099 
       
  1100 Write files whose names are equivalent to any of the names in
       
  1101 C<@filenames> to disk, creating subdirectories as necessary. This
       
  1102 might not work too well under VMS.  Under MacPerl, the file\'s
       
  1103 modification time will be converted to the MacOS zero of time, and
       
  1104 appropriate conversions will be done to the path.  However, the length
       
  1105 of each element of the path is not inspected to see whether it\'s
       
  1106 longer than MacOS currently allows (32 characters).
       
  1107 
       
  1108 If C<extract> is called without a list of file names, the entire
       
  1109 contents of the archive are extracted.
       
  1110 
       
  1111 =item list_files(['property', 'property',...])
       
  1112 
       
  1113 =item list_files()
       
  1114 
       
  1115 Returns a list of the names of all the files in the archive.
       
  1116 
       
  1117 If C<list_files()> is passed an array reference as its first argument
       
  1118 it returns a list of hash references containing the requested
       
  1119 properties of each file.  The following list of properties is
       
  1120 supported: name, size, mtime (last modified date), mode, uid, gid,
       
  1121 linkname, uname, gname, devmajor, devminor, prefix.
       
  1122 
       
  1123 Passing an array reference containing only one element, 'name', is
       
  1124 special cased to return a list of names rather than a list of hash
       
  1125 references.
       
  1126 
       
  1127 =item get_content($file)
       
  1128 
       
  1129 Return the content of the named file.
       
  1130 
       
  1131 =item replace_content($file,$content)
       
  1132 
       
  1133 Make the string $content be the content for the file named $file.
       
  1134 
       
  1135 =back
       
  1136 
       
  1137 =head1 CHANGES
       
  1138 
       
  1139 =over 4
       
  1140 
       
  1141 =item Version 0.20
       
  1142 
       
  1143 Added class methods for creation, extraction and listing of tar files.
       
  1144 No longer maintain a complete copy of the tar file in memory.  Removed
       
  1145 the C<data()> method.
       
  1146 
       
  1147 =item Version 0.10
       
  1148 
       
  1149 Numerous changes. Brought source under CVS.  All changes now recorded
       
  1150 in ChangeLog file in distribution.
       
  1151 
       
  1152 =item Version 0.08
       
  1153 
       
  1154 New developer/maintainer.  Calle has carpal-tunnel syndrome and cannot
       
  1155 type a great deal. Get better as soon as you can, Calle.
       
  1156 
       
  1157 Added proper support for MacOS.  Thanks to Paul J. Schinder
       
  1158 <schinder@leprss.gsfc.nasa.gov>.
       
  1159 
       
  1160 =item Version 0.071
       
  1161 
       
  1162 Minor release.
       
  1163 
       
  1164 Arrange to chmod() at the very end in case it makes the file read only.
       
  1165 Win32 is actually picky about that.
       
  1166 
       
  1167 SunOS 4.x tar makes tarfiles that contain directory entries that
       
  1168 don\'t have typeflag set properly.  We use the trailing slash to
       
  1169 recognise directories in such tar files.
       
  1170 
       
  1171 =item Version 0.07
       
  1172 
       
  1173 Fixed (hopefully) broken portability to MacOS, reported by Paul J.
       
  1174 Schinder at Goddard Space Flight Center.
       
  1175 
       
  1176 Fixed two bugs with symlink handling, reported in excellent detail by
       
  1177 an admin at teleport.com called Chris.
       
  1178 
       
  1179 Primitive tar program (called ptar) included with distribution. Usage
       
  1180 should be pretty obvious if you\'ve used a normal tar program.
       
  1181 
       
  1182 Added methods get_content and replace_content.
       
  1183 
       
  1184 Added support for paths longer than 100 characters, according to
       
  1185 POSIX. This is compatible with just about everything except GNU tar.
       
  1186 Way to go, GNU tar (use a better tar, or GNU cpio).
       
  1187 
       
  1188 NOTE: When adding files to an archive, files with basenames longer
       
  1189       than 100 characters will be silently ignored. If the prefix part
       
  1190       of a path is longer than 155 characters, only the last 155
       
  1191       characters will be stored.
       
  1192 
       
  1193 =item Version 0.06
       
  1194 
       
  1195 Added list_files() method, as requested by Michael Wiedman.
       
  1196 
       
  1197 Fixed a couple of dysfunctions when run under Windows NT. Michael
       
  1198 Wiedmann reported the bugs.
       
  1199 
       
  1200 Changed the documentation to reflect reality a bit better.
       
  1201 
       
  1202 Fixed bug in format_tar_entry. Bug reported by Michael Schilli.
       
  1203 
       
  1204 =item Version 0.05
       
  1205 
       
  1206 Quoted lots of barewords to make C<use strict;> stop complaining under
       
  1207 perl version 5.003.
       
  1208 
       
  1209 Ties to L<Compress::Zlib> put in. Will warn if it isn\'t available.
       
  1210 
       
  1211 $tar->write() with no argument now returns the formatted archive.
       
  1212 
       
  1213 =item Version 0.04
       
  1214 
       
  1215 Made changes to write_tar so that Solaris tar likes the resulting
       
  1216 archives better.
       
  1217 
       
  1218 Protected the calls to readlink() and symlink(). AFAIK this module
       
  1219 should now run just fine on Windows NT.
       
  1220 
       
  1221 Add method to write a single entry to disk (extract)
       
  1222 
       
  1223 Added method to add entries entirely from scratch (add_data)
       
  1224 
       
  1225 Changed name of add() to add_file()
       
  1226 
       
  1227 All calls to croak() removed and replaced with returning undef and
       
  1228 setting Tar::error.
       
  1229 
       
  1230 Better handling of tarfiles with garbage at the end.
       
  1231 
       
  1232 =head1 COPYRIGHT
       
  1233 
       
  1234 Archive::Tar is Copyright 1997 Calle Dybedahl. All rights reserved.
       
  1235                 Copyright 1998 Stephen Zander. All rights reserved.
       
  1236 
       
  1237 It is currently developed by Stephen Zander <gibreel@pobox.com>
       
  1238 
       
  1239 This library is free software; you can redistribute it and/or modify
       
  1240 it under the same terms as Perl itself.
       
  1241 
       
  1242 =cut