1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
$OpenBSD: Ustar.pod,v 1.1 2020/12/20 15:30:58 daniel Exp $
=head1 NAME
OpenBSD::Ustar - simple access to Ustar C<tar(1)> archives
=head1 SYNOPSIS
use OpenBSD::Ustar;
# for reading
open(my $in, "<", $arcnameforreading) or die;
$rdarc = OpenBSD::Ustar->new($in, $state, $destdir);
$rdarc->set_description($arcnameforreading);
while (my $o = $rdarc->next) {
# decide whether we want to extract it, change object attributes
$o->create;
}
$rdarc->close;
# for writing
open(my $out, ">", $arcnameforwriting) or die;
$wrarc = OpenBSD::Ustar->new($fh, $state, $destdir);
# loop
my $o = $wrarc->prepare($filename);
# tweak some entry parameters
$o->write;
$wrarc->close;
# for copying
open(my $in, "<", $arcnameforreading) or die;
$rdarc = OpenBSD::Ustar->new($in, $state, $destdir);
open(my $out, ">", $arcnameforwriting) or die;
$wrarc = OpenBSD::Ustar->new($fh, $state, $destdir);
while (my $o = $rdarc->next) {
$o->copy($wrarc);
}
$rdarc->close;
$wrarc->close;
=head1 DESCRIPTION
C<OpenBSD::Ustar> provides an API to read, write and copy archives compatible
with C<tar(1)>.
For the time being, it can only handle the USTAR archive format,
but is supports the C<XHDR> (x blocktype) extension for accurately
representing long hard links and symbolic links.
It also accurately recognize some common extensions that it doesn't process.
A filehandle C<$fh> is associated with an C<OpenBSD::Ustar> object through
C<new>. For archive reading, the filehandle should support
C<read>. C<OpenBSD::Ustar> does not rely on C<seek> or C<rewind> in order
to be usable on pipe outputs. For archive writing, the filehandle should
support C<print>.
Error messages and fatal errors will be handled through the C<$state> object,
which should conform to C<OpenBSD::State(3p)> (uses C<errsay> and C<fatal>).
Note that read and write support are mutually exclusive, though there is
no need to specify the mode used at creation time; it is implicitly
provided by the underlying filehandle.
Read access to an archive object C<$rdarc> occurs through a loop that
repeatedly calls C<$o = $rdarc-E<gt>next> to obtain the next archive entry.
It returns an archive entry object C<$o> that can be
queried to decide whether to extract this entry or not.
Write access to an archive object C<$wrarc> occurs through a user-directed
loop: obtain an archive entry through C<$o = $wrarc-E<gt>prepare($filename)>,
which can be tweaked manually and then written to the archive.
C<prepare> takes an optional C<$destdir> parameter that will override the
archive destdination directory.
This can be used to prepare an archive entry from a temporary file, that
will be used for the real checks and contents of the archive, then set
the name to save before writing the actual entry:
$o = $wrarc->prepare($tempfile, '');
$o->set_name("othername");
$o->write;
Most client software will specialize C<OpenBSD::Ustar> to their own needs.
Note however that C<OpenBSD::Ustar> is not designed for inheritance.
Composition (putting a C<OpenBSD::Ustar> object inside your class) and
forwarding methods (writing C<create> or C<next> methods that call the
corresponding C<OpenBSD::Ustar> method) are the correct way to use this API.
Note that C<OpenBSD::Ustar> does not do any caching. The client
code is responsible for retrieving and storing archives if it
needs to scan through them multiple times in a row.
Actual extraction is performed through C<$o-E<gt>create> and is not
mandatory. Thus, client code can control whether it wants to extract archive
elements or not.
In case of errors, the archive will call C<$state-E<gt>fatal> with a suitable
error message that contains the last index name processed. The user may
set an optional archive description with C<set_description>.
The C<create> method can take an optional C<$callback> argument, which will
be called regularly while extracting large objects, as C<&$callback($donesize)>,
with C<$donesize> the number of bytes already extracted.
Small files can also be directly extracted to a scalar using
C<$v = $o-E<gt>contents>.
Actual writing is performed through C<$o-E<gt>write> and is not mandatory
either.
Archives should be closed using C<$wrarc-E<gt>close>, which will
pad the archive as needed and close the underlying file handle.
In particular, this is mandatory for write access, since valid archives
require blank-filled blocks.
This is equivalent to calling C<$wrarc-E<gt>pad>, which will
complete the archive with blank-filled blocks, then closing the
associated file handle manually.
Client code may decide to abort archive extraction early, or to run it through
until C<$arc-E<gt>next> returns false. The C<OpenBSD::Ustar> object doesn't
hold any hidden resources and doesn't need any specific clean-up.
Client code is only responsible for closing the underlying filehandle and
terminating any associated pipe process.
An object C<$o> returned through C<next> or through C<prepare> holds all
the characteristics of the archive header:
=over 20
=item C<$o-E<gt>IsDir>
true if archive entry is a directory
=item C<$o-E<gt>isFile>
true if archive entry is a file
=item C<$o-E<gt>isLink>
true if archive entry is any kind of link
=item C<$o-E<gt>isSymLink>
true if archive entry is a symbolic link
=item C<$o-E<gt>isHardLink>
true if archive entry is a hard link
=item C<$o-E<gt>{name}>
filename
=item C<$o-E<gt>{mode}>
C<chmod(2)> mode
=item C<$o-E<gt>{atime}>
C<utime(2)> access time
=item C<$o-E<gt>{mtime}>
C<utime(2)> modification time
=item C<$o-E<gt>{uid}>
owner user ID
=item C<$o-E<gt>{gid}>
owner group ID
=item C<$o-E<gt>{uname}>
owner user name
=item C<$o-E<gt>{gname}>
owner group name
=item C<$o-E<gt>{linkname}>
name of the source link, if applicable
=back
The fields C<name>, C<mode>, C<atime>, C<mtime>, C<uid>, C<gid> and C<linkname>
can be altered before calling C<$o-E<gt>create> or C<$o-E<gt>write>,
and will properly influence the resulting file.
C<atime> and C<mtime> can be undef to set those to the current time.
The relationship between C<uid> and C<uname>, and C<gid> and C<gname>
conforms to the USTAR format usual behavior.
In addition, client code may define C<$o-E<gt>{cwd}> in a way similar
to C<tar(1)>'s C<-C> option to affect the creation of hard links.
All creation commands happen relative to the current destdir of
the C<$arc> C<OpenBSD::Ustar> object. This is set at creation, and can
later be changed through C<$arc-E<gt>destdir($value)>.
During writing, hard link status is determined according to already written
archive entries: a name that references a file which has already been written
will be granted hard link status.
Hard links can not be copied from one archive to another unless the original
file has also been copied. Calling C<$o-E<gt>alias($arc, $name)> will trick
the destination archive C<$arc> into believing C<$o> has been copied under the
given C<$name>, so that further hard links will be copied over.
Archives can be copied by creating separate archives for reading and writing.
Calling C<$o = $rdarc-E<gt>next> and C<$o-E<gt>copy($wrarc)> will copy
an entry obtained from C<$rdarc> to C<$wrarc>.
|