1 #============================================================= -*-perl-*-
3 # BackupPC::Attrib package
7 # This library defines a BackupPC::Attrib class for maintaining
8 # file attribute data. One object instance stores attributes for
9 # all the files in a single directory.
12 # Craig Barratt <cbarratt@users.sourceforge.net>
15 # Copyright (C) 2001 Craig Barratt
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 # GNU General Public License for more details.
27 # You should have received a copy of the GNU General Public License
28 # along with this program; if not, write to the Free Software
29 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #========================================================================
33 # Version 1.5.0, released 2 Aug 2002.
35 # See http://backuppc.sourceforge.net.
37 #========================================================================
39 package BackupPC::Attrib;
45 use BackupPC::FileZIO;
48 use vars qw( @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS );
51 # These must match the file types used by tar
53 use constant BPC_FTYPE_FILE => 0;
54 use constant BPC_FTYPE_HARDLINK => 1;
55 use constant BPC_FTYPE_SYMLINK => 2;
56 use constant BPC_FTYPE_CHARDEV => 3;
57 use constant BPC_FTYPE_BLOCKDEV => 4;
58 use constant BPC_FTYPE_DIR => 5;
59 use constant BPC_FTYPE_FIFO => 6;
60 use constant BPC_FTYPE_SOCKET => 8;
61 use constant BPC_FTYPE_UNKNOWN => 9;
76 # The indexes in this list must match the numbers above
91 # Type of attribute file. This is saved as a magic number at the
92 # start of the file. Later there might be other types.
94 use constant BPC_ATTRIB_TYPE_UNIX => 0x17555555;
96 my @ATTRIB_TYPES = qw(
110 'all' => [ @EXPORT_OK ],
114 # These fields are packed using the "w" pack format (variable length
115 # base 128). We use two values to store up to 64 bit size: sizeDiv4GB
116 # is size / 4GB and sizeMod4GB is size % 4GB (although perl can
117 # only represent around 2^52, the size of an IEEE double mantissa).
119 my @FldsUnixW = qw(type mode uid gid sizeDiv4GB sizeMod4GB);
122 # These fields are packed using the "N" pack format (32 bit integer)
124 my @FldsUnixN = qw(mtime);
128 my($class, $options) = @_;
131 type => BPC_ATTRIB_TYPE_UNIX,
140 my($a, $fileName, $attrib) = @_;
142 $a->{files}{$fileName} = $attrib;
147 my($a, $fileName) = @_;
148 return $a->{files}{$fileName};
154 return "?" if ( $type < 0 || $type >= @FileType2Text );
155 return $FileType2Text[$type];
162 return scalar(keys(%{$a->{files}}));
167 my($a, $fileName) = @_;
168 if ( defined($fileName) ) {
169 delete($a->{files}{$fileName});
176 # Given the directory, return the full path of the attribute file.
180 my($a, $dir, $file) = @_;
182 $file = "attrib" if ( !defined($file) );
188 my($a, $dir, $file) = @_;
191 $file = $a->fileName($dir, $file);
192 my $fd = BackupPC::FileZIO->open($file, 0, $a->{compress});
194 $a->{_errStr} = "Can't open $file";
197 $fd->read(\$data, 65536);
198 if ( length($data) < 4 ) {
199 $a->{_errStr} = "Can't read magic number from $file";
203 (my $magic, $data) = unpack("N a*", $data);
204 if ( $magic != $a->{type} ) {
205 $a->{_errStr} = sprintf("Wrong magic number in $file"
206 . " (got 0x%x, expected 0x%x)",
211 while ( length($data) ) {
213 if ( length($data) < 4 ) {
214 $fd->read(\$newData, 65536);
216 if ( length($data) < 4 ) {
217 $a->{_errStr} = "Can't read file length from $file";
222 (my $len, $data) = unpack("w a*", $data);
223 if ( length($data) < $len ) {
224 $fd->read(\$newData, $len + 65536);
226 if ( length($data) < $len ) {
227 $a->{_errStr} = "Can't read file name (length $len)"
233 (my $fileName, $data) = unpack("a$len a*", $data);
234 my $nFldsW = @FldsUnixW;
235 my $nFldsN = @FldsUnixN;
236 if ( length($data) < 5 * $nFldsW + 4 * $nFldsN ) {
237 $fd->read(\$newData, 65536);
241 @{$a->{files}{$fileName}}{@FldsUnixW},
242 @{$a->{files}{$fileName}}{@FldsUnixN},
244 ) = unpack("w$nFldsW N$nFldsN a*", $data);
245 if ( $a->{files}{$fileName}{$FldsUnixN[-1]} eq "" ) {
246 $a->{_errStr} = "Can't read attributes for $fileName"
252 # Convert the two 32 bit size values into a single size
254 $a->{files}{$fileName}{size} = $a->{files}{$fileName}{sizeMod4GB}
255 + $a->{files}{$fileName}{sizeDiv4GB} * 4096 * 1024 * 1024;
267 $data = pack("N", BPC_ATTRIB_TYPE_UNIX);
268 foreach my $file ( sort(keys(%{$a->{files}})) ) {
269 my $nFldsW = @FldsUnixW;
270 my $nFldsN = @FldsUnixN;
272 # Convert the size into two 32 bit size values.
274 $a->{files}{$file}{sizeMod4GB}
275 = $a->{files}{$file}{size} % (4096 * 1024 * 1024);
276 $a->{files}{$file}{sizeDiv4GB}
277 = int($a->{files}{$file}{size} / (4096 * 1024 * 1024));
278 $data .= pack("w a* w$nFldsW N$nFldsN", length($file), $file,
279 @{$a->{files}{$file}}{@FldsUnixW},
280 @{$a->{files}{$file}}{@FldsUnixN},
288 my($a, $dir, $file) = @_;
289 my($data) = $a->writeData;
291 $file = $a->fileName($dir, $file);
292 mkpath($dir, 0, 0777) if ( !-d $dir );
293 my $fd = BackupPC::FileZIO->open($file, 1, $a->{compress});
295 $a->{_errStr} = "Can't open/write to $file";
298 if ( $fd->write(\$data) != length($data) ) {
299 $a->{_errStr} = "Can't write to $file";
312 foreach my $f ( keys(%{$a2->{files}}) ) {
313 next if ( defined($a1->{files}{$f}) );
314 $a1->{files}{$f} = $a2->{files}{$f};
322 return $a->{_errStr};