File Coverage

blib/lib/Archive/Cpio.pm
Criterion Covered Total %
statement 15 92 16.3
branch 0 20 0.0
condition 0 14 0.0
subroutine 5 19 26.3
pod 10 11 90.9
total 30 156 19.2


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