File Coverage

blib/lib/Archive/Cpio.pm
Criterion Covered Total %
statement 9 77 11.6
branch 0 16 0.0
condition 0 5 0.0
subroutine 3 15 20.0
pod 10 11 90.9
total 22 124 17.7


line stmt bran cond sub pod time code
1             package Archive::Cpio;
2              
3             our $VERSION = 0.09;
4              
5 1     1   9027 use Archive::Cpio::Common;
  1         3  
  1         68  
6 1     1   850 use Archive::Cpio::File;
  1         2  
  1         35  
7 1     1   707 use Archive::Cpio::OldBinary;
  1         3  
  1         1336  
8              
9             =head1 NAME
10              
11             Archive::Cpio - module for manipulations of cpio archives
12              
13             =head1 SYNOPSIS
14              
15             use Archive::Cpio;
16              
17             # simple example removing entry "foo"
18              
19             my $cpio = Archive::Cpio->new;
20             $cpio->read($file);
21             $cpio->remove('foo');
22             $cio->write($file);
23              
24             # more complex example, filtering on the fly
25              
26             my $cpio = Archive::Cpio->new;
27             $cpio->read_with_handler(\*STDIN,
28             sub {
29             my ($e) = @_;
30             if ($e->name ne 'foo') {
31             $cpio->write_one(\*STDOUT, $e);
32             }
33             });
34             $cpio->write_trailer(\*STDOUT);
35              
36             =head1 DESCRIPTION
37              
38             Archive::Cpio provides a few functions to read and write cpio files.
39              
40             =cut
41              
42              
43             =head2 Archive::Cpio->new()
44              
45             Create an object
46              
47             =cut
48              
49             sub new {
50 0     0 1   my ($class, %options) = @_;
51 0           bless \%options, $class;
52             }
53              
54             =head2 $cpio->read($filename)
55              
56             =head2 $cpio->read($filehandle)
57              
58             Reads the cpio file
59              
60             =cut
61              
62             sub read {
63 0     0 1   my ($cpio, $file) = @_;
64            
65 0           my $IN;
66 0 0         if (ref $file) {
67 0           $IN = $file;
68             } else {
69 0 0         open($IN, '<', $file) or die "can't open $file: $!\n";
70             }
71              
72             read_with_handler($cpio, $IN, sub {
73 0     0     my ($e) = @_;
74 0           push @{$cpio->{list}}, $e;
  0            
75 0           });
76             }
77              
78             =head2 $cpio->write($filename)
79              
80             =head2 $cpio->write($filehandle)
81              
82             Writes the entries and the trailer
83              
84             =cut
85              
86             sub write {
87 0     0 1   my ($cpio, $file) = @_;
88              
89 0           my $OUT;
90 0 0         if (ref $file) {
91 0           $OUT = $file;
92             } else {
93 0 0         open($OUT, '>', $file) or die "can't open $file: $!\n";
94             }
95              
96 0           $cpio->write_one($OUT, $_) foreach @{$cpio->{list}};
  0            
97 0           $cpio->write_trailer($OUT);
98             }
99              
100             =head2 $cpio->remove(@filenames)
101              
102             Removes any entries with names matching any of the given filenames from the in-memory archive
103              
104             =cut
105              
106             sub remove {
107 0     0 1   my ($cpio, @filenames) = @_;
108 0 0         $cpio->{list} or die "can't remove from nothing\n";
109              
110 0           my %filenames = map { $_ => 1 } @filenames;
  0            
111              
112 0           @{$cpio->{list}} = grep { !$filenames{$_->name} } @{$cpio->{list}};
  0            
  0            
  0            
113             }
114              
115             =head2 $cpio->get_files([ @filenames ])
116              
117             Returns a list of C (after a C<$cpio->read>)
118              
119             =cut
120              
121             sub get_files {
122 0     0 1   my ($cpio, @list) = @_;
123 0 0         if (@list) {
124 0           map { get_file($cpio, $_) } @list;
  0            
125             } else {
126 0           @{$cpio->{list}};
  0            
127             }
128             }
129              
130             =head2 $cpio->get_file($filename)
131              
132             Returns the C matching C<$filename< (after a C<$cpio->read>)
133              
134             =cut
135              
136             sub get_file {
137 0     0 1   my ($cpio, $file) = @_;
138 0           foreach (@{$cpio->{list}}) {
  0            
139 0 0         $_->name eq $file and return $_;
140             }
141 0           undef;
142             }
143              
144             =head2 $cpio->add_data($filename, $data, $opthashref)
145              
146             Takes a filename, a scalar full of data and optionally a reference to a hash with specific options.
147              
148             Will add a file to the in-memory archive, with name C<$filename> and content C<$data>.
149             Specific properties can be set using C<$opthashref>.
150              
151             =cut
152              
153             sub add_data {
154 0     0 1   my ($cpio, $filename, $data, $opthashref) = @_;
155 0   0       my $entry = $opthashref || {};
156 0           $entry->{name} = $filename;
157 0           $entry->{data} = $data;
158 0           $entry->{nlink} = 1;
159 0           $entry->{mode} = 0100644;
160 0           push @{$cpio->{list}}, Archive::Cpio::File->new($entry);
  0            
161             }
162              
163             =head2 $cpio->read_with_handler($filehandle, $coderef)
164              
165             Calls the handler function on each header. An C is passed as a parameter
166              
167             =cut
168              
169             sub read_with_handler {
170 0     0 1   my ($cpio, $F, $handler) = @_;
171              
172 0           my $FHwp = Archive::Cpio::FileHandle_with_pushback->new($F);
173 0   0       $cpio->{archive_format} ||= detect_archive_format($FHwp);
174              
175 0           while (my $entry = $cpio->{archive_format}->read_one($FHwp)) {
176 0           $entry = Archive::Cpio::File->new($entry);
177 0           $handler->($entry);
178             }
179             }
180              
181             =head2 $cpio->write_one($filehandle, $entry)
182              
183             Writes a C (beware, a valid cpio needs a trailer using C)
184              
185             =cut
186              
187             sub write_one {
188 0     0 1   my ($cpio, $F, $entry) = @_;
189 0           $cpio->{archive_format}->write_one($F, $entry);
190             }
191              
192             =head2 $cpio->write_trailer($filehandle)
193              
194             Writes the trailer to finish the cpio file
195              
196             =cut
197              
198             sub write_trailer {
199 0     0 1   my ($cpio, $F) = @_;
200 0           $cpio->{archive_format}->write_trailer($F);
201             }
202              
203              
204             sub detect_archive_format {
205 0     0 0   my ($FHwp) = @_;
206              
207 0           my $magics = Archive::Cpio::Common::magics();
208              
209 0           my $max_length = max(map { length $_ } values %$magics);
  0            
210 0           my $s = $FHwp->read_ahead($max_length);
211              
212 0           foreach my $magic (keys %$magics) {
213 0           my $archive_format = $magics->{$magic};
214 0 0         begins_with($s, $magic) or next;
215            
216             #warn "found magic for $archive_format\n";
217              
218             # perl_checker: require Archive::Cpio::NewAscii
219             # perl_checker: require Archive::Cpio::OldBinary
220 0           my $class = "Archive::Cpio::$archive_format";
221 0           eval "require $class";
222 0           return $class->new($magic, $s);
223             }
224 0           die "invalid archive\n";
225             }
226              
227             =head1 AUTHOR
228              
229             Pascal Rigaux
230              
231             =cut