home *** CD-ROM | disk | FTP | other *** search
/ Netrunner 2004 October / NETRUNNER0410.ISO / regular / ActivePerl-5.8.4.810-MSWin32-x86.msi / _d773016debcaa18c5cac0b4b91f4068a < prev    next >
Encoding:
Text File  |  2004-06-01  |  13.3 KB  |  540 lines

  1. package Archive::Tar::File;
  2. use strict;
  3.  
  4. use IO::File;
  5. use File::Spec::Unix ();
  6. use File::Spec ();
  7. use File::Basename ();
  8. use Archive::Tar::Constant;
  9.  
  10. use vars qw[@ISA $VERSION];
  11. @ISA        = qw[Archive::Tar];
  12. $VERSION    = 0.01;
  13.  
  14. ### set value to 1 to oct() it during the unpack ###
  15. my $tmpl = [
  16.         name        => 0,   # string   
  17.         mode        => 1,   # octal
  18.         uid         => 1,   # octal
  19.         gid         => 1,   # octal
  20.         size        => 1,   # octal
  21.         mtime       => 1,   # octal
  22.         chksum      => 1,   # octal
  23.         type        => 0,   # character
  24.         linkname    => 0,   # string
  25.         magic       => 0,   # string
  26.         version     => 0,   # 2 bytes
  27.         uname       => 0,   # string
  28.         gname       => 0,   # string
  29.         devmajor    => 1,   # octal
  30.         devminor    => 1,   # octal
  31.         prefix      => 0,
  32.  
  33. ### end UNPACK items ###    
  34.         raw         => 0,   # the raw data chunk
  35.         data        => 0,   # the data associated with the file -- 
  36.                             # This  might be very memory intensive
  37. ];
  38.  
  39. ### install get/set accessors for this object.
  40. for ( my $i=0; $i<scalar @$tmpl ; $i+=2 ) {
  41.     my $key = $tmpl->[$i];
  42.     no strict 'refs';
  43.     *{__PACKAGE__."::$key"} = sub {
  44.         my $self = shift;
  45.         $self->{$key} = $_[0] if @_;
  46.         
  47.         ### just in case the key is not there or undef or something ###    
  48.         {   local $^W = 0;
  49.             return $self->{$key};
  50.         }
  51.     }
  52. }
  53.  
  54. =head1 NAME
  55.  
  56. Archive::Tar::File - a subclass for in-memory extracted file from Archive::Tar
  57.  
  58. =head1 SYNOPSIS
  59.  
  60.     my @items = $tar->get_files;
  61.  
  62.     print $_->name, ' ', $_->size, "\n" for @items;
  63.  
  64.     print $object->get_content;
  65.     $object->replace_content('new content');
  66.  
  67.     $object->rename( 'new/full/path/to/file.c' );
  68.  
  69. =head1 DESCRIPTION
  70.  
  71. Archive::Tar::Files provides a neat little object layer for in-memory
  72. extracted files. It's mostly used internally in Archive::Tar to tidy
  73. up the code, but there's no reason users shouldn't use this API as 
  74. well.
  75.  
  76. =head2 Accessors
  77.  
  78. A lot of the methods in this package are accessors to the various
  79. fields in the tar header:
  80.  
  81. =over 4
  82.  
  83. =item name
  84.  
  85. The file's name
  86.  
  87. =item mode
  88.  
  89. The file's mode
  90.  
  91. =item uid
  92.  
  93. The user id owning the file
  94.  
  95. =item gid
  96.  
  97. The group id owning the file
  98.  
  99. =item size
  100.  
  101. File size in bytes
  102.  
  103. =item mtime
  104.  
  105. Modification time. Adjusted to mac-time on MacOs if required
  106.  
  107. =item chksum
  108.  
  109. Checksum field for the tar header
  110.  
  111. =item type
  112.  
  113. File type -- numeric, but comparable to exported constants -- see
  114. Archive::Tar's documentation
  115.  
  116. =item linkname
  117.  
  118. If the file is a symlink, the file it's pointing to
  119.  
  120. =item magic
  121.  
  122. Tar magic string -- not useful for most users
  123.  
  124. =item version
  125.  
  126. Tar version string -- not useful for most users
  127.  
  128. =item uname
  129.  
  130. The user name that owns the file
  131.  
  132. =item gname
  133.  
  134. The group name that owns the file
  135.  
  136. =item devmajor
  137.  
  138. Device major number in case of a special file
  139.  
  140. =item devminor
  141.  
  142. Device minor number in case of a special file
  143.  
  144. =item prefix
  145.  
  146. Any directory to prefix to the extraction path, if any
  147.  
  148. =item raw
  149.  
  150. Raw tar header -- not useful for most users
  151.  
  152. =back
  153.  
  154. =head1 Methods
  155.  
  156. =head2 new( file => $path )
  157.  
  158. Returns a new Archive::Tar::File object from an existing file.
  159.  
  160. Returns undef on failure.
  161.  
  162. =head2 new( data => $path, $data, $opt )
  163.  
  164. Returns a new Archive::Tar::File object from data.
  165.  
  166. C<$path> defines the file name (which need not exist), C<$data> the
  167. file contents, and C<$opt> is a reference to a hash of attributes
  168. which may be used to override the default attributes (fields in the
  169. tar header), which are described above in the Accessors section.
  170.  
  171. Returns undef on failure.
  172.  
  173. =head2 new( chunk => $chunk )
  174.  
  175. Returns a new Archive::Tar::File object from a raw 512-byte tar
  176. archive chunk.
  177.  
  178. Returns undef on failure.
  179.  
  180. =cut
  181.  
  182. sub new {
  183.     my $class   = shift;
  184.     my $what    = shift;
  185.     
  186.     my $obj =   ($what eq 'chunk') ? __PACKAGE__->_new_from_chunk( @_ ) :
  187.                 ($what eq 'file' ) ? __PACKAGE__->_new_from_file( @_ ) :
  188.                 ($what eq 'data' ) ? __PACKAGE__->_new_from_data( @_ ) :
  189.                 undef;
  190.     
  191.     return $obj;
  192. }
  193.  
  194. sub _new_from_chunk {
  195.     my $class = shift;
  196.     my $chunk = shift or return undef;
  197.     
  198.     ### makes it start at 0 actually... :) ###
  199.     my $i = -1;
  200.     my %entry = map { 
  201.         $tmpl->[++$i] => $tmpl->[++$i] ? oct $_ : $_    
  202.     } map { /^([^\0]*)/ } unpack( UNPACK, $chunk );
  203.     
  204.     my $obj = bless \%entry, $class;
  205.  
  206.     ### magic is a filetype string.. it should have something like 'ustar' or
  207.     ### something similar... if the chunk is garbage, skip it
  208.     return unless $obj->magic !~ /\W/;
  209.  
  210.     ### store the original chunk ###
  211.     $obj->raw( $chunk );
  212.  
  213.     ### do some cleaning up ###
  214.     ### all paths are unix paths as per tar format spec ###
  215.     $obj->name( File::Spec::Unix->catfile( $obj->prefix, $obj->name ) ) if $obj->prefix;
  216.     
  217.     ### no reason to drop it, makes writing it out easier ###
  218.     #$obj->prefix('');
  219.     
  220.     $obj->type(FILE) if ( (!length $obj->type) or ($obj->type =~ /\W/) );
  221.     $obj->type(DIR)  if ( ($obj->is_file) && ($obj->name =~ m|/$|) );    
  222.  
  223.     ### weird thing in tarfiles -- if the file is actually a @LongLink,
  224.     ### the data part seems to have a trailing ^@ (unprintable) char.
  225.     ### to display, pipe output through less.
  226.     ### at any rate, we better remove that character here, or tests like
  227.     ### 'eq' and hashlook ups based on names will SO not work
  228.     $obj->size( $obj->size - 1 ) if $obj->is_longlink;
  229.              
  230.     return $obj;
  231. }
  232.  
  233. sub _new_from_file {
  234.     my $class       = shift;
  235.     my $path        = shift or return undef;
  236.     my $type        = __PACKAGE__->_filetype($path);
  237.     my $data        = '';
  238.  
  239.     unless ($type == DIR) {
  240.         my $fh = IO::File->new;
  241.         $fh->open($path) or return undef;
  242.         
  243.         ### binmode needed to read files properly on win32 ###
  244.         binmode $fh;
  245.         $data = do { local $/; <$fh> };
  246.         close $fh;
  247.     }
  248.  
  249.     my ($prefix,$file) = $class->_prefix_and_file($path);
  250.  
  251.     my @items       = qw[mode uid gid size mtime];
  252.     my %hash        = map { shift(@items), $_ } (lstat $path)[2,4,5,7,9];
  253.     $hash{mtime}    -= TIME_OFFSET;
  254.  
  255.     ### probably requires some file path munging here ... ###
  256.     my $obj = {
  257.         %hash,
  258.         name        => $file,
  259.         chksum      => CHECK_SUM,
  260.         type        => $type,         
  261.         linkname    => ($type == SYMLINK and CAN_READLINK) ? readlink $path : '',
  262.         magic       => MAGIC,
  263.         version     => TAR_VERSION,
  264.         uname       => UNAME->( $hash{uid} ),
  265.         gname       => GNAME->( $hash{gid} ),
  266.         devmajor    => 0,   # not handled
  267.         devminor    => 0,   # not handled
  268.         prefix      => $prefix,
  269.         data        => $data,
  270.     };      
  271.  
  272.     return bless $obj, $class;
  273. }
  274.  
  275. sub _new_from_data {
  276.     my $class   = shift;
  277.     my $path    = shift     or return undef;
  278.     my $data    = shift;    return undef unless defined $data;
  279.     my $opt     = shift;
  280.     
  281.     my ($prefix,$file) = $class->_prefix_and_file($path);
  282.  
  283.     my $obj = {
  284.         data        => $data,
  285.         name        => $file,
  286.         mode        => MODE,
  287.         uid         => UID,
  288.         gid         => GID,
  289.         size        => length $data,
  290.         mtime       => time - TIME_OFFSET,
  291.         chksum      => CHECK_SUM,
  292.         type        => FILE,
  293.         linkname    => '',
  294.         magic       => MAGIC,
  295.         version     => TAR_VERSION,
  296.         uname       => UNAME->( UID ),
  297.         gname       => GNAME->( GID ),
  298.         devminor    => 0,
  299.         devmajor    => 0,
  300.         prefix      => $prefix,
  301.     };      
  302.     
  303.     ### overwrite with user options, if provided ###
  304.     if( $opt and ref $opt eq 'HASH' ) {
  305.         for my $key ( keys %$opt ) {
  306.             
  307.             ### don't write bogus options ###
  308.             next unless exists $obj->{$key};
  309.             $obj->{$key} = $opt->{$key};
  310.         }
  311.     }
  312.  
  313.     return bless $obj, $class;
  314.  
  315. }
  316.  
  317. sub _prefix_and_file {
  318.     my $self = shift;
  319.     my $path = shift;
  320.     
  321.     my ($vol, $dirs, $file) = File::Spec->splitpath( $path );
  322.       
  323.     my $prefix = File::Spec::Unix->catdir(
  324.                         grep { length } 
  325.                         $vol,
  326.                         File::Spec->splitdir( $dirs ),
  327.                     );           
  328.     return( $prefix, $file );
  329. }
  330.     
  331. sub _filetype {
  332.     my $self = shift;
  333.     my $file = shift or return undef;
  334.  
  335.     return SYMLINK  if (-l $file);    # Symlink
  336.  
  337.     return FILE     if (-f _);        # Plain file
  338.  
  339.     return DIR      if (-d _);        # Directory
  340.  
  341.     return FIFO     if (-p _);        # Named pipe
  342.  
  343.     return SOCKET   if (-S _);        # Socket
  344.  
  345.     return BLOCKDEV if (-b _);        # Block special
  346.  
  347.     return CHARDEV  if (-c _);        # Character special
  348.     
  349.     ### shouldn't happen, this is when making archives, not reading ###
  350.     return LONGLINK if ( $file eq LONGLINK_NAME );
  351.  
  352.     return UNKNOWN;                    # Something else (like what?)
  353.  
  354. }
  355.  
  356. ### this method 'downgrades' a file to plain file -- this is used for
  357. ### symlinks when FOLLOW_SYMLINKS is true.
  358. sub _downgrade_to_plainfile {
  359.     my $entry = shift;
  360.     $entry->type( FILE );
  361.     $entry->mode( MODE );
  362.     $entry->linkname('');   
  363.  
  364.     return 1;
  365. }    
  366.  
  367. =head2 validate
  368.  
  369. Done by Archive::Tar internally when reading the tar file:
  370. validate the header against the checksum to ensure integer tar file.
  371.  
  372. Returns true on success, false on failure
  373.  
  374. =cut
  375.  
  376. sub validate {
  377.     my $self = shift;
  378.     
  379.     my $raw = $self->raw;    
  380.     
  381.     ### don't know why this one is different from the one we /write/ ###
  382.     substr ($raw, 148, 8) = "        ";
  383.     return unpack ("%16C*", $raw) == $self->chksum ? 1 : 0;    
  384. }
  385.  
  386. =head2 has_content
  387.  
  388. Returns a boolean to indicate whether the current object has content.
  389. Some special files like directories and so on never will have any
  390. content. This method is mainly to make sure you don't get warnings 
  391. for using unitialized values when looking at an objects's content.
  392.  
  393. =cut
  394.  
  395. sub has_content {
  396.     my $self = shift;
  397.     return defined $self->data() && length $self->data() ? 1 : 0;
  398. }
  399.  
  400. =head2 get_content
  401.  
  402. Returns the current content for the in-memory file
  403.  
  404. =cut
  405.  
  406. sub get_content {
  407.     my $self = shift;
  408.     $self->data( );
  409. }
  410.  
  411. =head2 get_content_by_ref
  412.  
  413. Returns the current content for the in-memory file as a scalar 
  414. reference. Normal users won't need this, but it will save memory if 
  415. you are dealing with very large data files in your tar archive, since
  416. it will pass the contents by reference, rather than make a copy of it
  417. first.
  418.  
  419. =cut
  420.  
  421. sub get_content_by_ref {
  422.     my $self = shift;
  423.     
  424.     return \$self->{data};
  425. }
  426.  
  427. =head2 replace_content( $content )
  428.  
  429. Replace the current content of the file with the new content. This
  430. only affects the in-memory archive, not the on-disk version until
  431. you write it. 
  432.  
  433. Returns true on success, false on failure.
  434.  
  435. =cut
  436.  
  437. sub replace_content {
  438.     my $self = shift;
  439.     my $data = shift || '';
  440.     
  441.     $self->data( $data );
  442.     $self->size( length $data );
  443.     return 1;
  444. }
  445.  
  446. =head2 rename( $new_name )
  447.  
  448. Rename the current file to $new_name.
  449.  
  450. Note that you must specify a Unix path for $new_name, since per tar
  451. standard, all files in the archive must be Unix paths.
  452.  
  453. Returns true on success and false on failure.
  454.  
  455. =cut
  456.  
  457. sub rename {
  458.     my $self = shift;
  459.     my $path = shift or return undef;
  460.     
  461.     my ($prefix,$file) = $self->_prefix_and_file( $path );    
  462.     
  463.     $self->name( $file );
  464.     $self->prefix( $prefix );
  465.  
  466.     return 1;
  467. }
  468.  
  469. =head1 Convenience methods
  470.  
  471. To quickly check the type of a C<Archive::Tar::File> object, you can
  472. use the following methods:
  473.  
  474. =over 4
  475.  
  476. =item is_file
  477.  
  478. Returns true if the file is of type C<file>
  479.  
  480. =item is_dir
  481.  
  482. Returns true if the file is of type C<dir>
  483.  
  484. =item is_hardlink
  485.  
  486. Returns true if the file is of type C<hardlink>
  487.  
  488. =item is_symlink
  489.  
  490. Returns true if the file is of type C<symlink>
  491.  
  492. =item is_chardev
  493.  
  494. Returns true if the file is of type C<chardev>
  495.  
  496. =item is_blockdev
  497.  
  498. Returns true if the file is of type C<blockdev>
  499.  
  500. =item is_fifo
  501.  
  502. Returns true if the file is of type C<fifo>
  503.  
  504. =item is_socket
  505.  
  506. Returns true if the file is of type C<socket>
  507.  
  508. =item is_longlink
  509.  
  510. Returns true if the file is of type C<LongLink>. 
  511. Should not happen after a succesful C<read>.
  512.  
  513. =item is_label
  514.  
  515. Returns true if the file is of type C<Label>.
  516. Should not happen after a succesful C<read>.
  517.  
  518. =item is_unknown
  519.  
  520. Returns true if the file type is C<unknown>
  521.  
  522. =back
  523.  
  524. =cut
  525.  
  526. #stupid perl5.5.3 needs to warn if it's not numeric 
  527. sub is_file     { local $^W;    FILE      == $_[0]->type }    
  528. sub is_dir      { local $^W;    DIR       == $_[0]->type }
  529. sub is_hardlink { local $^W;    HARDLINK  == $_[0]->type }
  530. sub is_symlink  { local $^W;    SYMLINK   == $_[0]->type }
  531. sub is_chardev  { local $^W;    CHARDEV   == $_[0]->type }
  532. sub is_blockdev { local $^W;    BLOCKDEV  == $_[0]->type }
  533. sub is_fifo     { local $^W;    FIFO      == $_[0]->type }
  534. sub is_socket   { local $^W;    SOCKET    == $_[0]->type }
  535. sub is_unknown  { local $^W;    UNKNOWN   == $_[0]->type } 
  536. sub is_longlink { local $^W;    LONGLINK  eq $_[0]->type }
  537. sub is_label    { local $^W;    LABEL     eq $_[0]->type }
  538.  
  539. 1;
  540.