-#!/bin/perl -T
+#!/bin/perl
#============================================================= -*-perl-*-
#
# BackupPC_zipCreate: create a zip archive of an existing dump
#
# DESCRIPTION
#
-# Usage: BackupPC_zipCreate [-t] [-h host] [-n dumpNum] [-s shareName]
-# [-r pathRemove] [-p pathAdd] [-c compressionLevel]
-# files/directories...
+# Usage: BackupPC_zipCreate [options] files/directories...
#
# Flags:
# Required options:
-#
# -h host host from which the zip archive is created
# -n dumpNum dump number from which the zip archive is created
+# A negative number means relative to the end (eg -1
+# means the most recent dump, -2 2nd most recent etc).
# -s shareName share name from which the zip archive is created
#
# Other options:
# -r pathRemove path prefix that will be replaced with pathAdd
# -p pathAdd new path prefix
# -c level compression level (default is 0, no compression)
+# -e charset charset for encoding file names (default: value of
+# $Conf{ClientCharset} when backup was done)
#
# The -h, -n and -s options specify which dump is used to generate
# the zip archive. The -r and -p options can be used to relocate
# Based on Backup_tarCreate by Craig Barratt <cbarratt@users.sourceforge.net>
#
# COPYRIGHT
-# Copyright (C) 2002 Craig Barratt and Guillaume Filion
+# Copyright (C) 2002-2003 Craig Barratt and Guillaume Filion
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
#
#========================================================================
#
-# Version 2.0.0, released 14 Jun 2003.
+# Version 3.0.0, released 28 Jan 2007.
#
# See http://backuppc.sourceforge.net.
#
use Archive::Zip qw(:ERROR_CODES);
use File::Path;
use Getopt::Std;
+use Encode qw/from_to/;
use IO::Handle;
use BackupPC::Lib;
use BackupPC::Attrib qw(:all);
my %opts;
-if ( !getopts("th:n:p:r:s:c:", \%opts) || @ARGV < 1 ) {
- print(STDERR "usage: $0 [-t] [-h host] [-n dumpNum] [-s shareName]"
- . " [-r pathRemove] [-p pathAdd] [-c compressionLevel]"
- . " files/directories...\n");
+if ( !getopts("te:h:n:p:r:s:c:", \%opts) || @ARGV < 1 ) {
+ print STDERR <<EOF;
+usage: $0 [options] files/directories...
+ Required options:
+ -h host host from which the zip archive is created
+ -n dumpNum dump number from which the tar archive is created
+ A negative number means relative to the end (eg -1
+ means the most recent dump, -2 2nd most recent etc).
+ -s shareName share name from which the zip archive is created
+
+ Other options:
+ -t print summary totals
+ -r pathRemove path prefix that will be replaced with pathAdd
+ -p pathAdd new path prefix
+ -c level compression level (default is 0, no compression)
+ -e charset charset for encoding file names (default: value of
+ \$Conf{ClientCharset} when backup was done)
+EOF
exit(1);
}
-if ( $opts{h} !~ /^([\w\.\s-]+)$/ ) {
+if ( $opts{h} !~ /^([\w\.\s-]+)$/
+ || $opts{h} =~ m{(^|/)\.\.(/|$)} ) {
print(STDERR "$0: bad host name '$opts{h}'\n");
exit(1);
}
my $Host = $opts{h};
-if ( $opts{n} !~ /^(\d+)$/ ) {
+if ( $opts{n} !~ /^(-?\d+)$/ ) {
print(STDERR "$0: bad dump number '$opts{n}'\n");
exit(1);
}
my $Num = $opts{n};
+
$opts{c} = 0 if ( $opts{c} eq "" );
if ( $opts{c} !~ /^(\d+)$/ ) {
print(STDERR "$0: invalid compression level '$opts{c}'. 0=none, 9=max\n");
my $compLevel = $opts{c};
my @Backups = $bpc->BackupInfoRead($Host);
-my($i);
my $FileCnt = 0;
my $ByteCnt = 0;
my $DirCnt = 0;
my $SpecialCnt = 0;
my $ErrorCnt = 0;
+my $i;
+$Num = $Backups[@Backups + $Num]{num} if ( -@Backups <= $Num && $Num < 0 );
for ( $i = 0 ; $i < @Backups ; $i++ ) {
last if ( $Backups[$i]{num} == $Num );
}
exit(1);
}
+my $Charset = $Backups[$i]{charset};
+$Charset = $opts{e} if ( $opts{e} ne "" );
+
my $PathRemove = $1 if ( $opts{r} =~ /(.+)/ );
my $PathAdd = $1 if ( $opts{p} =~ /(.+)/ );
-if ( $opts{s} !~ /^([\w\s\.\/\$-]+)$/ ) {
+if ( $opts{s} =~ m{(^|/)\.\.(/|$)} ) {
print(STDERR "$0: bad share name '$opts{s}'\n");
exit(1);
}
$ErrorCnt++;
return;
}
+ $dir = "/" if ( $dir eq "." );
$view->find($Num, $ShareName, $dir, 0, \&ZipWriteFile,
$zipfh, $zipPathOverride);
}
&& substr($tarPath, 0, length($PathRemove)) eq $PathRemove ) {
substr($tarPath, 0, length($PathRemove)) = $PathAdd;
}
- $tarPath = "./" . $tarPath if ( $tarPath !~ /^\.\// );
+ $tarPath = $1 if ( $tarPath =~ m{^\.?/+(.*)} );
$tarPath =~ s{//+}{/}g;
$hdr->{name} = $tarPath;
+ return if ( $tarPath eq "." || $tarPath eq "./" || $tarPath eq "" );
my $zipmember; # Container to hold the file/directory to zip.
# Directory: just write the header
#
$hdr->{name} .= "/" if ( $hdr->{name} !~ m{/$} );
+ from_to($hdr->{name}, "utf8", $Charset) if ( $Charset ne "" );
$zipmember = Archive::Zip::Member->newDirectoryNamed($hdr->{name});
$DirCnt++;
} elsif ( $hdr->{type} == BPC_FTYPE_FILE ) {
#
# Regular file: write the header and file
#
+ from_to($hdr->{name}, "utf8", $Charset) if ( $Charset ne "" );
$zipmember = BackupPC::Zip::FileMember->newFromFileNamed(
$hdr->{fullPath},
$hdr->{name},
}
return if ( !$zipmember );
- # Set the attributes and permissions
- $zipmember->setLastModFileDateTimeFromUnix($hdr->{mtime});
+ #
+ # Set the attributes and permissions. The standard zip file
+ # header cannot handle dates prior to 1/1/1980, or 315561600
+ # unix seconds, so we round up the mtime.
+ #
+ my $mtime = $hdr->{mtime};
+ $mtime = 315561600 if ( $mtime < 315561600 );
+ $zipmember->setLastModFileDateTimeFromUnix($mtime);
$zipmember->unixFileAttributes($hdr->{mode});
# Zip files don't accept uid and gid, so we put them in the comment field.
$zipmember->fileComment("uid=".$hdr->{uid}." gid=".$hdr->{gid})