6 |
# |
# |
7 |
# DESCRIPTION |
# DESCRIPTION |
8 |
# |
# |
9 |
# Usage: BackupPC_tarIncCreate [options] files/directories... |
# Usage: BackupPC_tarIncCreate [options] |
10 |
# |
# |
11 |
# Flags: |
# Flags: |
12 |
# Required options: |
# Required options: |
31 |
# |
# |
32 |
# AUTHOR |
# AUTHOR |
33 |
# Craig Barratt <cbarratt@users.sourceforge.net> |
# Craig Barratt <cbarratt@users.sourceforge.net> |
34 |
|
# Ivan Klaric <iklaric@gmail.com> |
35 |
|
# Dobrica Pavlinusic <dpavlin@rot13.org> |
36 |
# |
# |
37 |
# COPYRIGHT |
# COPYRIGHT |
38 |
# Copyright (C) 2001-2003 Craig Barratt |
# Copyright (C) 2001-2003 Craig Barratt |
70 |
use BackupPC::FileZIO; |
use BackupPC::FileZIO; |
71 |
use BackupPC::View; |
use BackupPC::View; |
72 |
use BackupPC::SearchLib; |
use BackupPC::SearchLib; |
73 |
use Data::Dumper; |
use Time::HiRes qw/time/; |
74 |
|
use POSIX qw/strftime/; |
75 |
|
use Data::Dumper; ### FIXME |
76 |
|
|
77 |
die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) ); |
die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) ); |
78 |
my $TopDir = $bpc->TopDir(); |
my $TopDir = $bpc->TopDir(); |
79 |
my $BinDir = $bpc->BinDir(); |
my $BinDir = $bpc->BinDir(); |
80 |
my %Conf = $bpc->Conf(); |
my %Conf = $bpc->Conf(); |
|
my @DBCache; |
|
|
my $db_done = 0; |
|
81 |
my %opts; |
my %opts; |
82 |
|
my $in_backup_increment; |
83 |
|
|
84 |
if ( !getopts("th:n:p:r:s:b:w:", \%opts) || @ARGV < 1 ) { |
|
85 |
|
if ( !getopts("th:n:p:r:s:b:w:", \%opts) ) { |
86 |
print STDERR <<EOF; |
print STDERR <<EOF; |
87 |
usage: $0 [options] files/directories... |
usage: $0 [options] |
88 |
Required options: |
Required options: |
89 |
-h host host from which the tar archive is created |
-h host host from which the tar archive is created |
90 |
-n dumpNum dump number from which the tar archive is created |
-n dumpNum dump number from which the tar archive is created |
164 |
# |
# |
165 |
binmode(STDOUT); |
binmode(STDOUT); |
166 |
my $fh = *STDOUT; |
my $fh = *STDOUT; |
167 |
if ( $ShareName eq "*" ) { |
|
168 |
my $PathRemoveOrig = $PathRemove; |
if (seedCache($Host, $ShareName, $Num)) { |
169 |
my $PathAddOrig = $PathAdd; |
archiveWrite($fh, '/'); |
170 |
foreach $ShareName ( $view->shareList($Num) ) { |
archiveWriteHardLinks($fh); |
|
#print(STDERR "Doing share ($ShareName)\n"); |
|
|
$PathRemove = "/" if ( !defined($PathRemoveOrig) ); |
|
|
($PathAdd = "/$ShareName/$PathAddOrig") =~ s{//+}{/}g; |
|
|
foreach my $dir ( @ARGV ) { |
|
|
archiveWrite($fh, $dir); |
|
|
} |
|
|
archiveWriteHardLinks($fh); |
|
|
} |
|
171 |
} else { |
} else { |
172 |
foreach my $dir ( @ARGV ) { |
print STDERR "NOTE: no files found for $Host:$ShareName, increment $Num\n"; |
|
archiveWrite($fh, $dir); |
|
|
} |
|
|
archiveWriteHardLinks($fh); |
|
173 |
} |
} |
174 |
|
|
175 |
# |
# |
383 |
} |
} |
384 |
|
|
385 |
# |
# |
386 |
# returns 1 if a given directory has files somewhere under it |
# seed cache of files in this increment |
|
# in a given dump of a given share |
|
387 |
# |
# |
388 |
sub checkSubDirs($$$$) { |
sub seedCache($$$) { |
389 |
my ($dir, $share, $host, $dumpNo) = @_; |
my ($host, $share, $dumpNo) = @_; |
390 |
my $ret; |
|
391 |
my $dsn = $Conf{SearchDSN}; |
my $dsn = $Conf{SearchDSN}; |
392 |
my $db_user = $Conf{SearchUser} || ''; |
my $db_user = $Conf{SearchUser} || ''; |
|
my $search_sql; |
|
393 |
|
|
394 |
print(STDERR $dir); |
print STDERR curr_time(), "getting files for $host:$share increment $dumpNo..."; |
395 |
# erase first dot |
my $sql = q{ |
396 |
if (substr($dir, 0, 1) == '.') |
SELECT path |
397 |
{ |
FROM files |
398 |
$dir = substr($dir, 1, length($dir)); |
JOIN shares on shares.id = shareid |
399 |
} |
JOIN hosts on hosts.id = shares.hostid |
400 |
# erase first slash |
WHERE hosts.name = ? and shares.name = ? and backupnum = ? |
401 |
if (substr($dir, 0, 1) == '/') |
}; |
402 |
{ |
|
403 |
$dir = substr($dir, 1, length($dir)); |
my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1} ); |
404 |
} |
my $sth = $dbh->prepare($sql); |
405 |
# erase last slash |
$sth->execute($host, $share, $dumpNo); |
406 |
if (substr($dir, length($dir)-1, 1) == '/') |
my $count = $sth->rows; |
407 |
{ |
print STDERR " found $count items\n"; |
408 |
$dir = substr($dir, 0, length($dir)-1); |
while (my $row = $sth->fetchrow_arrayref) { |
409 |
} |
print STDERR "+ ", $row->[0],"\n"; |
410 |
|
$in_backup_increment->{ $row->[0] }++; |
|
if (! $db_done) |
|
|
{ |
|
|
print STDERR "doing db..."; |
|
|
my $search_sql = q{ |
|
|
SELECT hosts.name, shares.name, startfiles.name, COUNT(files.*) AS subfiles |
|
|
FROM files startfiles |
|
|
INNER JOIN shares ON (shares.id=startfiles.shareid) |
|
|
INNER JOIN hosts ON (hosts.id=shares.hostid) |
|
|
INNER JOIN backups ON ( |
|
|
backups.num=startfiles.backupnum AND |
|
|
backups.hostid=hosts.id AND backups.shareid=shares.id |
|
|
) |
|
|
LEFT JOIN files ON ( |
|
|
files.backupnum=startfiles.backupnum AND |
|
|
files.shareid=startfiles.shareid AND |
|
|
files.path LIKE startfiles.path || '/%' AND |
|
|
files.type<>startfiles.type AND |
|
|
files.id <> startfiles.id |
|
|
) |
|
|
WHERE |
|
|
hosts.name=? AND |
|
|
shares.name=? AND |
|
|
startfiles.type=? AND |
|
|
startfiles.backupnum=? |
|
|
GROUP BY hosts.name, shares.name, startfiles.name, startfiles.backupnum; |
|
|
}; |
|
|
my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1} ); |
|
|
my $sth = $dbh->prepare($search_sql); |
|
|
$sth->execute($host, $share, BPC_FTYPE_DIR, $dumpNo); |
|
|
print STDERR "done\n"; |
|
|
while (my @r_data = $sth->fetchrow_array()) |
|
|
{ |
|
|
$DBCache[$r_data[0]][$r_data[1]][$r_data[2]] = 1; |
|
|
} |
|
|
|
|
|
$sth->finish(); |
|
|
|
|
|
$DBCache[$host][$share][$dir] = $ret; |
|
|
$dbh->disconnect(); |
|
|
$db_done = 1; |
|
411 |
} |
} |
412 |
|
|
413 |
|
$sth->finish(); |
414 |
|
$dbh->disconnect(); |
415 |
|
|
416 |
if ($DBCache[$host][$share][$dir] != undef && $DBCache[$host][$share][$dir] == 1) |
return $count; |
|
{ |
|
|
return 1; |
|
|
} |
|
|
return 0; |
|
417 |
} |
} |
418 |
|
|
419 |
my $Attr; |
my $Attr; |
423 |
{ |
{ |
424 |
my($hdr, $fh, $tarPathOverride) = @_; |
my($hdr, $fh, $tarPathOverride) = @_; |
425 |
|
|
|
|
|
426 |
my $tarPath = $hdr->{relPath}; |
my $tarPath = $hdr->{relPath}; |
427 |
$tarPath = $tarPathOverride if ( defined($tarPathOverride) ); |
$tarPath = $tarPathOverride if ( defined($tarPathOverride) ); |
428 |
|
|
429 |
$tarPath =~ s{//+}{/}g; |
$tarPath =~ s{//+}{/}g; |
430 |
|
|
431 |
|
#print STDERR "? $tarPath\n"; |
432 |
|
return unless ($in_backup_increment->{$tarPath}); |
433 |
|
print STDERR "A $tarPath\n"; |
434 |
|
|
435 |
if ( defined($PathRemove) |
if ( defined($PathRemove) |
436 |
&& substr($tarPath, 0, length($PathRemove)) eq $PathRemove ) { |
&& substr($tarPath, 0, length($PathRemove)) eq $PathRemove ) { |
437 |
substr($tarPath, 0, length($PathRemove)) = $PathAdd; |
substr($tarPath, 0, length($PathRemove)) = $PathAdd; |
447 |
|
|
448 |
|
|
449 |
$hdr->{name} .= "/" if ( $hdr->{name} !~ m{/$} ); |
$hdr->{name} .= "/" if ( $hdr->{name} !~ m{/$} ); |
450 |
# check if it has files under it in the database |
TarWriteFileInfo($fh, $hdr); |
451 |
if ( checkSubDirs($hdr->{path}, $ShareName, $Host, $Num) != 0 ) |
$DirCnt++; |
|
{ |
|
|
TarWriteFileInfo($fh, $hdr); |
|
|
$DirCnt++; |
|
|
} |
|
452 |
} elsif ( $hdr->{type} == BPC_FTYPE_FILE ) { |
} elsif ( $hdr->{type} == BPC_FTYPE_FILE ) { |
453 |
# |
# |
454 |
# Regular file: write the header and file |
# Regular file: write the header and file |
488 |
$hdr->{linkname} .= $data; |
$hdr->{linkname} .= $data; |
489 |
} |
} |
490 |
$f->close; |
$f->close; |
|
# |
|
|
# Check @ARGV and the list of hardlinked files we have explicity |
|
|
# dumped to see if we have dumped this file or not |
|
|
# |
|
491 |
my $done = 0; |
my $done = 0; |
492 |
my $name = $hdr->{linkname}; |
my $name = $hdr->{linkname}; |
493 |
$name =~ s{^\./}{/}; |
$name =~ s{^\./}{/}; |
494 |
if ( $HardLinkExtraFiles{$name} ) { |
if ( $HardLinkExtraFiles{$name} ) { |
|
$done = 1; |
|
|
} else { |
|
|
foreach my $arg ( @ARGV ) { |
|
|
$arg =~ s{^\./+}{/}; |
|
|
$arg =~ s{/+$}{}; |
|
|
$done = 1 if ( $name eq $arg || $name =~ /^\Q$arg\// ); |
|
|
} |
|
|
} |
|
|
if ( $done ) { |
|
495 |
# |
# |
496 |
# Target file will be or was written, so just remember |
# Target file will be or was written, so just remember |
497 |
# the hardlink so we can dump it later. |
# the hardlink so we can dump it later. |
558 |
$ErrorCnt++; |
$ErrorCnt++; |
559 |
} |
} |
560 |
} |
} |
561 |
|
|
562 |
|
my $t_fmt = '%Y-%m-%d %H:%M:%S'; |
563 |
|
sub curr_time { |
564 |
|
return strftime($t_fmt,localtime()); |
565 |
|
} |