BackupPC_zipCreate (BackupPC-4.3.2) | : | BackupPC_zipCreate (BackupPC-4.4.0) | ||
---|---|---|---|---|
skipping to change at line 55 | skipping to change at line 55 | |||
# This program is distributed in the hope that it will be useful, | # This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# GNU General Public License for more details. | # GNU General Public License for more details. | |||
# | # | |||
# You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | |||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
# | # | |||
#======================================================================== | #======================================================================== | |||
# | # | |||
# Version 4.3.2, released 17 Feb 2020. | # Version 4.4.0, released 20 Jun 2020. | |||
# | # | |||
# See http://backuppc.sourceforge.net. | # See http://backuppc.sourceforge.net. | |||
# | # | |||
#======================================================================== | #======================================================================== | |||
use strict; | use strict; | |||
no utf8; | no utf8; | |||
use lib "__INSTALLDIR__/lib"; | use lib "__INSTALLDIR__/lib"; | |||
use Archive::Zip qw(:ERROR_CODES); | use Archive::Zip qw(:ERROR_CODES); | |||
use File::Path; | use File::Path; | |||
use Getopt::Std; | use Getopt::Std; | |||
use Encode qw/from_to/; | use Encode qw/from_to/; | |||
use IO::Handle; | use IO::Handle; | |||
use BackupPC::Lib; | use BackupPC::Lib; | |||
use BackupPC::XS qw( :all ); | use BackupPC::XS qw( :all ); | |||
use BackupPC::Zip::FileMember; | use BackupPC::Zip::FileMember; | |||
use BackupPC::View; | use BackupPC::View; | |||
skipping to change at line 122 | skipping to change at line 123 | |||
print(STDERR "$0: bad dump number '$opts{n}'\n"); | print(STDERR "$0: bad dump number '$opts{n}'\n"); | |||
exit(1); | exit(1); | |||
} | } | |||
my $Num = $opts{n}; | my $Num = $opts{n}; | |||
$opts{c} = 0 if ( $opts{c} eq "" ); | $opts{c} = 0 if ( $opts{c} eq "" ); | |||
if ( $opts{c} !~ /^(\d+)$/ ) { | if ( $opts{c} !~ /^(\d+)$/ ) { | |||
print(STDERR "$0: invalid compression level '$opts{c}'. 0=none, 9=max\n"); | print(STDERR "$0: invalid compression level '$opts{c}'. 0=none, 9=max\n"); | |||
exit(1); | exit(1); | |||
} | } | |||
if ( !$opts{m} && !defined($bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPo | if ( !$opts{m} | |||
rt})) | && !defined($bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort})) | |||
&& (my $status = $bpc->ServerMesg("hostMutex $Host 1 BackupPC_zipC | && (my $status = $bpc->ServerMesg("hostMutex $Host 1 BackupPC_zipCreate")) = | |||
reate")) =~ /fail/ ) { | ~ /fail/ ) { | |||
print(STDERR "$0: $status (use -m option to force running)\n"); | print(STDERR "$0: $status (use -m option to force running)\n"); | |||
exit(1); | exit(1); | |||
} | } | |||
my $compLevel = $opts{c}; | my $compLevel = $opts{c}; | |||
my @Backups = $bpc->BackupInfoRead($Host); | my @Backups = $bpc->BackupInfoRead($Host); | |||
my $FileCnt = 0; | my $FileCnt = 0; | |||
my $ByteCnt = 0; | my $ByteCnt = 0; | |||
my $DirCnt = 0; | my $DirCnt = 0; | |||
my $SpecialCnt = 0; | my $SpecialCnt = 0; | |||
my $ErrorCnt = 0; | my $ErrorCnt = 0; | |||
my $i; | my $i; | |||
$Num = $Backups[@Backups + $Num]{num} if ( -@Backups <= $Num && $Num < 0 ); | $Num = $Backups[@Backups + $Num]{num} if ( -@Backups <= $Num && $Num < 0 ); | |||
for ( $i = 0 ; $i < @Backups ; $i++ ) { | for ( $i = 0 ; $i < @Backups ; $i++ ) { | |||
last if ( $Backups[$i]{num} == $Num ); | last if ( $Backups[$i]{num} == $Num ); | |||
} | } | |||
if ( $i >= @Backups ) { | if ( $i >= @Backups ) { | |||
print(STDERR "$0: bad backup number $Num for host $Host\n"); | print(STDERR "$0: bad backup number $Num for host $Host\n"); | |||
exit(1); | exit(1); | |||
} | } | |||
my $Charset = ""; # default: utf8 | my $Charset = ""; # default: utf8 | |||
$Charset = $opts{e} if ( $opts{e} ne "" ); | $Charset = $opts{e} if ( $opts{e} ne "" ); | |||
my $PathRemove = $1 if ( $opts{r} =~ /(.+)/ ); | my $PathRemove = $1 if ( $opts{r} =~ /(.+)/ ); | |||
my $PathAdd = $1 if ( $opts{p} =~ /(.+)/ ); | my $PathAdd = $1 if ( $opts{p} =~ /(.+)/ ); | |||
if ( $opts{s} =~ m{(^|/)\.\.(/|$)} ) { | if ( $opts{s} =~ m{(^|/)\.\.(/|$)} ) { | |||
print(STDERR "$0: bad share name '$opts{s}'\n"); | print(STDERR "$0: bad share name '$opts{s}'\n"); | |||
exit(1); | exit(1); | |||
} | } | |||
my $ShareName = $opts{s}; | my $ShareName = $opts{s}; | |||
my $BufSize = 1048576; # 1MB or 2^20 | my $BufSize = 1048576; # 1MB or 2^20 | |||
my(%UidCache, %GidCache); | my(%UidCache, %GidCache); | |||
#my $fh = *STDOUT; | #my $fh = *STDOUT; | |||
my $fh = new IO::Handle; | my $fh = new IO::Handle; | |||
$fh->fdopen(fileno(STDOUT),"w"); | $fh->fdopen(fileno(STDOUT), "w"); | |||
my $zipfh = Archive::Zip->new(); | my $zipfh = Archive::Zip->new(); | |||
binmode(STDOUT); | binmode(STDOUT); | |||
foreach my $dir ( @ARGV ) { | foreach my $dir ( @ARGV ) { | |||
archiveWrite($zipfh, $dir); | archiveWrite($zipfh, $dir); | |||
} | } | |||
sub archiveWrite | sub archiveWrite | |||
{ | { | |||
my($zipfh, $dir, $zipPathOverride) = @_; | my($zipfh, $dir, $zipPathOverride) = @_; | |||
my $view = BackupPC::View->new($bpc, $Host, \@Backups); | my $view = BackupPC::View->new($bpc, $Host, \@Backups); | |||
if ( $dir =~ m{(^|/)\.\.(/|$)} || $dir !~ /^(.*)$/ ) { | if ( $dir =~ m{(^|/)\.\.(/|$)} || $dir !~ /^(.*)$/ ) { | |||
print(STDERR "$0: bad directory '$dir'\n"); | print(STDERR "$0: bad directory '$dir'\n"); | |||
$ErrorCnt++; | $ErrorCnt++; | |||
return; | return; | |||
} | } | |||
$dir = "/" if ( $dir eq "." ); | $dir = "/" if ( $dir eq "." ); | |||
$view->find($Num, $ShareName, $dir, 0, \&ZipWriteFile, | $view->find($Num, $ShareName, $dir, 0, \&ZipWriteFile, $zipfh, $zipPathOverr | |||
$zipfh, $zipPathOverride); | ide); | |||
} | } | |||
# Create Zip file | # Create Zip file | |||
print STDERR "Can't write Zip file\n" | print STDERR "Can't write Zip file\n" | |||
unless $zipfh->writeToFileHandle($fh, 0) == Archive::Zip::AZ_OK; | unless $zipfh->writeToFileHandle($fh, 0) == Archive::Zip::AZ_OK; | |||
# | # | |||
# print out totals if requested | # print out totals if requested | |||
# | # | |||
if ( $opts{t} ) { | if ( $opts{t} ) { | |||
print STDERR "Done: $FileCnt files, $ByteCnt bytes, $DirCnt dirs,", | print STDERR "Done: $FileCnt files, $ByteCnt bytes, $DirCnt dirs,", | |||
" $SpecialCnt specials ignored, $ErrorCnt errors\n"; | " $SpecialCnt specials ignored, $ErrorCnt errors\n"; | |||
} | } | |||
exit(0); | exit(0); | |||
########################################################################### | ########################################################################### | |||
# Subroutines | # Subroutines | |||
########################################################################### | ########################################################################### | |||
sub UidLookup | sub UidLookup | |||
{ | { | |||
my($uid) = @_; | my($uid) = @_; | |||
skipping to change at line 229 | skipping to change at line 233 | |||
my $AttrDir; | my $AttrDir; | |||
sub ZipWriteFile | sub ZipWriteFile | |||
{ | { | |||
my($hdr, $zipfh, $zipPathOverride) = @_; | my($hdr, $zipfh, $zipPathOverride) = @_; | |||
my $tarPath = $hdr->{relPath}; | my $tarPath = $hdr->{relPath}; | |||
$tarPath = $zipPathOverride if ( defined($zipPathOverride) ); | $tarPath = $zipPathOverride if ( defined($zipPathOverride) ); | |||
if ( defined($PathRemove) | if ( defined($PathRemove) | |||
&& substr($tarPath, 0, length($PathRemove)) eq $PathRemove ) { | && substr($tarPath, 0, length($PathRemove)) eq $PathRemove ) { | |||
substr($tarPath, 0, length($PathRemove)) = $PathAdd; | substr($tarPath, 0, length($PathRemove)) = $PathAdd; | |||
} | } | |||
$tarPath = $1 if ( $tarPath =~ m{^\.?/+(.*)} ); | $tarPath = $1 if ( $tarPath =~ m{^\.?/+(.*)} ); | |||
$tarPath =~ s{//+}{/}g; | $tarPath =~ s{//+}{/}g; | |||
$hdr->{name} = $tarPath; | $hdr->{name} = $tarPath; | |||
return if ( $tarPath eq "." || $tarPath eq "./" || $tarPath eq "" ); | return if ( $tarPath eq "." || $tarPath eq "./" || $tarPath eq "" ); | |||
my $zipmember; # Container to hold the file/directory to zip. | my $zipmember; # Container to hold the file/directory to zip. | |||
if ( $hdr->{type} == BPC_FTYPE_DIR ) { | if ( $hdr->{type} == BPC_FTYPE_DIR ) { | |||
# | # | |||
# Directory: just write the header | # Directory: just write the header | |||
# | # | |||
$hdr->{name} .= "/" if ( $hdr->{name} !~ m{/$} ); | $hdr->{name} .= "/" if ( $hdr->{name} !~ m{/$} ); | |||
from_to($hdr->{name}, "utf8", $Charset) if ( $Charset ne "" ); | from_to($hdr->{name}, "utf8", $Charset) if ( $Charset ne "" ); | |||
$zipmember = Archive::Zip::Member->newDirectoryNamed($hdr->{name}); | $zipmember = Archive::Zip::Member->newDirectoryNamed($hdr->{name}); | |||
$DirCnt++; | $DirCnt++; | |||
} elsif ( $hdr->{type} == BPC_FTYPE_FILE ) { | } elsif ( $hdr->{type} == BPC_FTYPE_FILE ) { | |||
# | # | |||
# Regular file: write the header and file | # Regular file: write the header and file | |||
# | # | |||
from_to($hdr->{name}, "utf8", $Charset) if ( $Charset ne "" ); | from_to($hdr->{name}, "utf8", $Charset) if ( $Charset ne "" ); | |||
$zipmember = BackupPC::Zip::FileMember->newFromFileNamed( | $zipmember = | |||
$hdr->{fullPath}, | BackupPC::Zip::FileMember->newFromFileNamed($hdr->{fullPath}, $hdr->{n | |||
$hdr->{name}, | ame}, $hdr->{size}, $hdr->{compress}); | |||
$hdr->{size}, | $FileCnt++; | |||
$hdr->{compress} | $ByteCnt += $hdr->{size}; | |||
); | ||||
$FileCnt++; | ||||
$ByteCnt += $hdr->{size}; | ||||
} elsif ( $hdr->{type} == BPC_FTYPE_HARDLINK ) { | } elsif ( $hdr->{type} == BPC_FTYPE_HARDLINK ) { | |||
# | # | |||
# Hardlink file: not supported by Zip, so just make a copy | # Hardlink file: not supported by Zip, so just make a copy | |||
# of the pointed-to file. | # of the pointed-to file. | |||
# | ||||
# Start by reading the contents of the link. | ||||
# | # | |||
# Start by reading the contents of the link. | ||||
# | ||||
my $f = BackupPC::XS::FileZIO::open($hdr->{fullPath}, 0, $hdr->{compress }); | my $f = BackupPC::XS::FileZIO::open($hdr->{fullPath}, 0, $hdr->{compress }); | |||
if ( !defined($f) ) { | if ( !defined($f) ) { | |||
print(STDERR "Unable to open file $hdr->{fullPath}\n"); | print(STDERR "Unable to open file $hdr->{fullPath}\n"); | |||
$ErrorCnt++; | $ErrorCnt++; | |||
return; | return; | |||
} | } | |||
my $data; | my $data; | |||
while ( $f->read(\$data, $BufSize) > 0 ) { | while ( $f->read(\$data, $BufSize) > 0 ) { | |||
$hdr->{linkname} .= $data; | $hdr->{linkname} .= $data; | |||
} | } | |||
$f->close; | $f->close; | |||
# | # | |||
# Dump the original file. Just call the top-level | # Dump the original file. Just call the top-level | |||
# routine, so that we save the hassle of dealing with | # routine, so that we save the hassle of dealing with | |||
# mangling, merging and attributes. | # mangling, merging and attributes. | |||
# | # | |||
archiveWrite($zipfh, $hdr->{linkname}, $hdr->{name}); | archiveWrite($zipfh, $hdr->{linkname}, $hdr->{name}); | |||
} elsif ( $hdr->{type} == BPC_FTYPE_SYMLINK ) { | } elsif ( $hdr->{type} == BPC_FTYPE_SYMLINK ) { | |||
# | # | |||
# Symlinks can't be Zipped. 8( | # Symlinks can't be Zipped. 8( | |||
# We could zip the pointed-to dir/file (just like hardlink), but we | # We could zip the pointed-to dir/file (just like hardlink), but we | |||
# have to avoid the infinite-loop case of a symlink pointed to a | # have to avoid the infinite-loop case of a symlink pointed to a | |||
# directory above us. Ignore for now. Could be a command-line | # directory above us. Ignore for now. Could be a command-line | |||
# option later. | # option later. | |||
# | # | |||
$SpecialCnt++; | $SpecialCnt++; | |||
} elsif ( $hdr->{type} == BPC_FTYPE_CHARDEV | } elsif ( $hdr->{type} == BPC_FTYPE_CHARDEV | |||
|| $hdr->{type} == BPC_FTYPE_BLOCKDEV | || $hdr->{type} == BPC_FTYPE_BLOCKDEV | |||
|| $hdr->{type} == BPC_FTYPE_FIFO ) { | || $hdr->{type} == BPC_FTYPE_FIFO ) { | |||
# | # | |||
# Special files can't be Zipped. 8( | # Special files can't be Zipped. 8( | |||
# | # | |||
$SpecialCnt++; | $SpecialCnt++; | |||
} else { | } else { | |||
print(STDERR "Got unknown type $hdr->{type} for $hdr->{name}\n"); | print(STDERR "Got unknown type $hdr->{type} for $hdr->{name}\n"); | |||
$ErrorCnt++; | $ErrorCnt++; | |||
} | } | |||
return if ( !$zipmember ); | return if ( !$zipmember ); | |||
# | # | |||
# Set the attributes and permissions. The standard zip file | # Set the attributes and permissions. The standard zip file | |||
# header cannot handle dates prior to 1/1/1980, or 315561600 | # header cannot handle dates prior to 1/1/1980, or 315561600 | |||
# unix seconds, so we round up the mtime. | # unix seconds, so we round up the mtime. | |||
# | # | |||
my $mtime = $hdr->{mtime}; | my $mtime = $hdr->{mtime}; | |||
$mtime = 315561600 if ( $mtime < 315561600 ); | $mtime = 315561600 if ( $mtime < 315561600 ); | |||
$zipmember->setLastModFileDateTimeFromUnix($mtime); | $zipmember->setLastModFileDateTimeFromUnix($mtime); | |||
$zipmember->unixFileAttributes($hdr->{mode}); | $zipmember->unixFileAttributes($hdr->{mode}); | |||
# Zip files don't accept uid and gid, so we put them in the comment field. | # Zip files don't accept uid and gid, so we put them in the comment field. | |||
$zipmember->fileComment("uid=".$hdr->{uid}." gid=".$hdr->{gid}) | $zipmember->fileComment("uid=" . $hdr->{uid} . " gid=" . $hdr->{gid}) | |||
if ( $hdr->{uid} || $hdr->{gid} ); | if ( $hdr->{uid} || $hdr->{gid} ); | |||
# Specify the compression level for this member | # Specify the compression level for this member | |||
$zipmember->desiredCompressionLevel($compLevel) if ($compLevel =~ /[0-9]/); | $zipmember->desiredCompressionLevel($compLevel) if ( $compLevel =~ /[0-9]/ ) ; | |||
if ( $Charset =~ /^(?:utf[-_]?8)?$/i ) { | if ( $Charset =~ /^(?:utf[-_]?8)?$/i ) { | |||
# Set general purpose bit 11 for UTF-8 code page | # Set general purpose bit 11 for UTF-8 code page | |||
$zipmember->{bitFlag} = $zipmember->{bitFlag} | 0x0800 ; | $zipmember->{bitFlag} = $zipmember->{bitFlag} | 0x0800; | |||
} elsif ( $Charset =~ /^cp(?:437|720|737|775|85[02578]|86[069]|874|93[26]|94 9|950)$/i ) { | } elsif ( $Charset =~ /^cp(?:437|720|737|775|85[02578]|86[069]|874|93[26]|94 9|950)$/i ) { | |||
# Set "version made by" field to 0 (MS-DOS) for OEM code pages | # Set "version made by" field to 0 (MS-DOS) for OEM code pages | |||
$zipmember->fileAttributeFormat('FA_MSDOS'); | $zipmember->fileAttributeFormat('FA_MSDOS'); | |||
} | } | |||
# Finally Zip the member | # Finally Zip the member | |||
$zipfh->addMember($zipmember); | $zipfh->addMember($zipmember); | |||
} | } | |||
End of changes. 33 change blocks. | ||||
56 lines changed or deleted | 60 lines changed or added |