| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Sys::Export::CPIO; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: Write CPIO archives needed for Linux initrd |
|
4
|
|
|
|
|
|
|
our $VERSION = '0.005'; # VERSION |
|
5
|
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
185653
|
use v5.26; |
|
|
1
|
|
|
|
|
3
|
|
|
7
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
38
|
|
|
8
|
1
|
|
|
1
|
|
4
|
use experimental qw( signatures ); |
|
|
1
|
|
|
|
|
15
|
|
|
|
1
|
|
|
|
|
5
|
|
|
9
|
1
|
|
|
1
|
|
106
|
use Fcntl qw( S_IFDIR S_IFMT ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
44
|
|
|
10
|
1
|
|
|
1
|
|
3
|
use Scalar::Util 'blessed'; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
37
|
|
|
11
|
1
|
|
|
1
|
|
419
|
use Encode (); |
|
|
1
|
|
|
|
|
11916
|
|
|
|
1
|
|
|
|
|
49
|
|
|
12
|
1
|
|
|
1
|
|
9
|
use Carp; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
1191
|
|
|
13
|
|
|
|
|
|
|
our @CARP_NOT= qw( Sys::Export Sys::Export::Unix ); |
|
14
|
|
|
|
|
|
|
require Sys::Export::Unix; # for _dev_major_minor |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
1
|
146471
|
sub new($class, $f, @attrs) { |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
18
|
1
|
50
|
|
|
|
4
|
croak "Expected even-length key/value list after filename" if @attrs & 1; |
|
19
|
1
|
|
|
|
|
2
|
my $filename; |
|
20
|
|
|
|
|
|
|
my $fh= blessed $f && $f->can('print')? $f |
|
21
|
1
|
50
|
33
|
|
|
4
|
: do { $filename= $f; open my $x, '>:raw', $f or die "open($f): $!"; $x }; |
|
|
1
|
50
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
15
|
|
|
|
1
|
|
|
|
|
2
|
|
|
22
|
1
|
|
|
|
|
21
|
my $self= bless { |
|
23
|
|
|
|
|
|
|
fh => $fh, |
|
24
|
|
|
|
|
|
|
seen_inode => {}, |
|
25
|
|
|
|
|
|
|
ino => 0, |
|
26
|
|
|
|
|
|
|
virtual_inodes => 1, |
|
27
|
|
|
|
|
|
|
filename => $filename, |
|
28
|
|
|
|
|
|
|
autoclose => defined $filename, |
|
29
|
|
|
|
|
|
|
}, $class; |
|
30
|
|
|
|
|
|
|
|
|
31
|
1
|
|
|
|
|
3
|
while (@attrs) { |
|
32
|
0
|
|
|
|
|
0
|
my ($attr, $val)= splice(@attrs, 0, 2); |
|
33
|
0
|
|
|
|
|
0
|
$self->$attr($val); |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
|
|
36
|
1
|
|
|
|
|
3
|
$self; |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub autoclose { |
|
41
|
0
|
0
|
|
0
|
1
|
0
|
$_[0]{autoclose}= !!$_[1] if @_ > 1; # cast to boolean |
|
42
|
|
|
|
|
|
|
$_[0]{autoclose} |
|
43
|
0
|
|
|
|
|
0
|
} |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub filename { |
|
46
|
0
|
0
|
|
0
|
1
|
0
|
$_[0]{filename}= $_[1] if @_ > 1; |
|
47
|
|
|
|
|
|
|
$_[0]{filename} |
|
48
|
0
|
|
|
|
|
0
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub virtual_inodes { |
|
51
|
3
|
50
|
|
3
|
1
|
6
|
$_[0]{virtual_inodes}= !!$_[1] if @_ > 1; # cast to boolean |
|
52
|
|
|
|
|
|
|
$_[0]{virtual_inodes} |
|
53
|
3
|
|
|
|
|
9
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
|
|
56
|
3
|
|
|
3
|
1
|
5842
|
sub add($self, $fileinfo) { |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
4
|
|
|
57
|
|
|
|
|
|
|
my ($dev, $dev_major, $dev_minor, $ino, $mode, $nlink, $uid, $gid, $rdev, $rdev_major, $rdev_minor, $mtime) |
|
58
|
3
|
|
|
|
|
4
|
= @{$fileinfo}{qw( dev dev_major dev_minor ino mode nlink uid gid rdev rdev_major rdev_minor mtime )}; |
|
|
3
|
|
|
|
|
11
|
|
|
59
|
3
|
|
|
|
|
7
|
my $name= _fileinfo_get_name_bytes($fileinfo); |
|
60
|
|
|
|
|
|
|
# best-effort to extract major/minor from dev and rdev, unless user specified them |
|
61
|
3
|
50
|
0
|
|
|
8
|
($dev_major, $dev_minor)= Sys::Export::Unix::_dev_major_minor($dev) |
|
|
|
|
33
|
|
|
|
|
|
62
|
|
|
|
|
|
|
if defined $dev and !defined $dev_major || !defined $dev_minor; |
|
63
|
3
|
100
|
33
|
|
|
13
|
($rdev_major, $rdev_minor)= Sys::Export::Unix::_dev_major_minor($rdev) |
|
|
|
|
66
|
|
|
|
|
|
64
|
|
|
|
|
|
|
if defined $rdev and !defined $rdev_major || !defined $rdev_minor; |
|
65
|
3
|
50
|
|
|
|
6
|
defined $mode or croak "require 'mode'"; |
|
66
|
3
|
50
|
|
|
|
6
|
defined $name or croak "require 'name'"; |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# Die on encoding mistakes |
|
69
|
3
|
|
|
|
|
4
|
my ($size, $data_ref)= (0); |
|
70
|
3
|
50
|
|
|
|
7
|
if (defined $fileinfo->{data}) { |
|
71
|
0
|
0
|
|
|
|
0
|
$data_ref= ref $fileinfo->{data}? $fileinfo->{data} : \$fileinfo->{data}; |
|
72
|
0
|
0
|
0
|
|
|
0
|
croak "->{data} must be 8-bit, but encountered wide character at $name" |
|
73
|
|
|
|
|
|
|
if utf8::is_utf8($$data_ref) && !utf8::downgrade($$data_ref, 1); |
|
74
|
0
|
|
|
|
|
0
|
$size= length $$data_ref; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
# Handle hard links |
|
77
|
3
|
50
|
66
|
|
|
22
|
if ($nlink && $nlink > 1 && ($mode & S_IFMT) != S_IFDIR) { |
|
|
|
50
|
66
|
|
|
|
|
|
78
|
0
|
|
|
|
|
0
|
my $hardlink_key= "$dev_major:$dev_minor:$ino"; |
|
79
|
0
|
0
|
|
|
|
0
|
if ($self->virtual_inodes) { |
|
80
|
|
|
|
|
|
|
# the previous virtual inode is stored in the seen_inode hash |
|
81
|
0
|
0
|
|
|
|
0
|
if ($ino= $self->{seen_inode}{$hardlink_key}) { |
|
82
|
0
|
|
|
|
|
0
|
$size= 0; |
|
83
|
|
|
|
|
|
|
} else { |
|
84
|
0
|
|
|
|
|
0
|
$ino= $self->{seen_inode}{$hardlink_key}= ++$self->{ino}; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
0
|
|
|
|
|
0
|
($dev_major, $dev_minor)= (0,0); |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
else { |
|
89
|
0
|
0
|
|
|
|
0
|
$size= 0 if $self->{seen_inode}{$hardlink_key}++; |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
elsif ($self->virtual_inodes) { |
|
93
|
3
|
|
|
|
|
5
|
($dev_major, $dev_minor, $ino)= (0,0); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
3
|
|
33
|
|
|
30
|
$ino //= ++$self->{ino}; |
|
96
|
|
|
|
|
|
|
|
|
97
|
3
|
|
50
|
|
|
43
|
my $header= sprintf "070701%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%s\0%s", |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
98
|
|
|
|
|
|
|
$ino, $mode, $uid//0, $gid//0, $nlink//1, $mtime//0, $size, |
|
99
|
|
|
|
|
|
|
$dev_major//0, $dev_minor//0, $rdev_major//0, $rdev_minor//0, |
|
100
|
|
|
|
|
|
|
1+length $name, 0, $name, |
|
101
|
|
|
|
|
|
|
"\0"x((4 - ((13*8+6+length($name)+1) & 3)) & 3); # pad to multiple of 4 |
|
102
|
3
|
50
|
|
|
|
5
|
die "BUG" if length $header & 3; |
|
103
|
|
|
|
|
|
|
|
|
104
|
3
|
50
|
|
|
|
17
|
$self->{fh}->print($header) || die "write: $!"; |
|
105
|
|
|
|
|
|
|
# This is written in multiple parts like this because $fileinfo->{data} might be a memory- |
|
106
|
|
|
|
|
|
|
# mapped file, and optimal to pass that directly back to fprint without a perl-side |
|
107
|
|
|
|
|
|
|
# concatenation. |
|
108
|
3
|
50
|
0
|
|
|
24
|
$self->{fh}->print($$data_ref) || die "write: $!" |
|
109
|
|
|
|
|
|
|
if $size; |
|
110
|
3
|
50
|
0
|
|
|
4
|
$self->{fh}->print("\0"x(4-($size & 3))) || die "write: $!" |
|
111
|
|
|
|
|
|
|
if $size & 3; # pad to multiple of 4 |
|
112
|
3
|
|
|
|
|
7
|
$self; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
3
|
|
|
3
|
|
5
|
sub _fileinfo_get_name_bytes($f) { |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
2
|
|
|
116
|
3
|
50
|
|
|
|
8
|
if (defined (my $name= $f->{name})) { |
|
|
|
0
|
|
|
|
|
|
|
117
|
3
|
50
|
33
|
|
|
11
|
!utf8::is_utf8($name) or utf8::downgrade($name, 1) |
|
118
|
|
|
|
|
|
|
or croak "->{name} must be encoded as bytes, but encountered wide character at $name"; |
|
119
|
3
|
|
|
|
|
5
|
return $name; |
|
120
|
|
|
|
|
|
|
} elsif (defined $f->{uname}) { |
|
121
|
0
|
|
|
|
|
|
return Encode::encode('UTF-8', $f->{uname}, Encode::FB_CROAK|Encode::LEAVE_SRC); |
|
122
|
|
|
|
|
|
|
} else { |
|
123
|
0
|
|
|
|
|
|
croak "Must specify either 'name' or 'uname'"; |
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
|
128
|
0
|
|
|
0
|
1
|
|
sub finish($self) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
$self->add({ mode => 0, ino => 0, name => 'TRAILER!!!' }); |
|
130
|
0
|
|
|
|
|
|
$self->{fh}->flush; |
|
131
|
0
|
0
|
|
|
|
|
$self->{fh}->close if $self->autoclose; |
|
132
|
0
|
|
|
|
|
|
$self; |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# Avoiding dependency on namespace::clean |
|
136
|
|
|
|
|
|
|
delete @{Sys::Export::CPIO::}{qw( S_IFDIR S_IFMT blessed carp croak confess )}; |
|
137
|
|
|
|
|
|
|
1; |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
__END__ |