You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-06-20 01:17:49 +02:00
Manifest is working (unit tests at least).
This commit is contained in:
@@ -158,13 +158,22 @@ if ($strOperation eq OP_MANIFEST)
|
||||
|
||||
my %oManifestHash;
|
||||
$oFile->manifest(PATH_ABSOLUTE, $strPath, \%oManifestHash);
|
||||
my $bFirst = true;
|
||||
|
||||
print "name\ttype\tuser\tgroup\tpermission\tmodification_time\tinode\tsize\tlink_destination";
|
||||
|
||||
foreach my $strName (sort(keys $oManifestHash{name}))
|
||||
{
|
||||
$bFirst ? $bFirst = false : print "\n";
|
||||
|
||||
print "${strName}";
|
||||
print "\n${strName}\t" .
|
||||
$oManifestHash{name}{"${strName}"}{type} . "\t" .
|
||||
(defined($oManifestHash{name}{"${strName}"}{user}) ? $oManifestHash{name}{"${strName}"}{user} : "") . "\t" .
|
||||
(defined($oManifestHash{name}{"${strName}"}{group}) ? $oManifestHash{name}{"${strName}"}{group} : "") . "\t" .
|
||||
(defined($oManifestHash{name}{"${strName}"}{permission}) ? $oManifestHash{name}{"${strName}"}{permission} : "") . "\t" .
|
||||
(defined($oManifestHash{name}{"${strName}"}{modification_time}) ?
|
||||
$oManifestHash{name}{"${strName}"}{modification_time} : "") . "\t" .
|
||||
(defined($oManifestHash{name}{"${strName}"}{inode}) ? $oManifestHash{name}{"${strName}"}{inode} : "") . "\t" .
|
||||
(defined($oManifestHash{name}{"${strName}"}{size}) ? $oManifestHash{name}{"${strName}"}{size} : "") . "\t" .
|
||||
(defined($oManifestHash{name}{"${strName}"}{link_destination}) ?
|
||||
$oManifestHash{name}{"${strName}"}{link_destination} : "");
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
+156
-11
@@ -4,16 +4,18 @@
|
||||
package pg_backrest_file;
|
||||
|
||||
use threads;
|
||||
|
||||
use Moose;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp;
|
||||
|
||||
use Moose;
|
||||
use Net::OpenSSH;
|
||||
use IPC::Open3;
|
||||
use File::Basename;
|
||||
use IPC::System::Simple qw(capture);
|
||||
use Digest::SHA;
|
||||
use File::stat;
|
||||
use Fcntl ':mode';
|
||||
|
||||
use lib dirname($0);
|
||||
use pg_backrest_utility;
|
||||
@@ -62,8 +64,10 @@ has iThreadIdx => (is => 'bare');
|
||||
####################################################################################################################################
|
||||
use constant
|
||||
{
|
||||
COMMAND_ERR_FILE_MISSING => 1,
|
||||
COMMAND_ERR_FILE_READ => 2
|
||||
COMMAND_ERR_FILE_MISSING => 1,
|
||||
COMMAND_ERR_FILE_READ => 2,
|
||||
COMMAND_ERR_FILE_TYPE => 3,
|
||||
COMMAND_ERR_LINK_READ => 4
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
@@ -1078,7 +1082,6 @@ sub remove
|
||||
}
|
||||
|
||||
confess &log(ERROR, "${strErrorPrefix}: " . $strError);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1121,23 +1124,165 @@ sub manifest
|
||||
confess &log(ERROR, "${strErrorPrefix} remote (${strCommand}): " . (defined($strOutput) ? $strOutput : $oSSH->error));
|
||||
}
|
||||
|
||||
return data_hash_build("name\ttype\tuser\tgroup\tpermission\tmodification_time\tinode\tsize\tlink_destination\n" .
|
||||
$strOutput, "\t", ".");
|
||||
return data_hash_build($oManifestHashRef, $strOutput, "\t", ".");
|
||||
}
|
||||
# Run locally
|
||||
else
|
||||
{
|
||||
manifest_recurse($strPathOp, $oManifestHashRef);
|
||||
manifest_recurse($strPathType, $strPathOp, undef, 0, $oManifestHashRef);
|
||||
}
|
||||
}
|
||||
|
||||
sub manifest_recurse
|
||||
{
|
||||
my $strPath = shift;
|
||||
my $strPathType = shift;
|
||||
my $strPathOp = shift;
|
||||
my $strPathFileOp = shift;
|
||||
my $iDepth = shift;
|
||||
my $oManifestHashRef = shift;
|
||||
|
||||
${$oManifestHashRef}{name}{dude1}{user} = "dsteele";
|
||||
${$oManifestHashRef}{name}{dude2}{user} = "dsteele";
|
||||
my $strErrorPrefix = "File->manifest";
|
||||
my $strPathRead = $strPathOp . (defined($strPathFileOp) ? "/${strPathFileOp}" : "");
|
||||
my $hPath;
|
||||
|
||||
if (!opendir($hPath, $strPathRead))
|
||||
{
|
||||
my $strError = "${strPathRead} could not be read:" . $!;
|
||||
my $iErrorCode = 2;
|
||||
|
||||
unless (-e $strPathRead)
|
||||
{
|
||||
$strError = "${strPathRead} does not exist";
|
||||
$iErrorCode = 1;
|
||||
}
|
||||
|
||||
if ($strPathType eq PATH_ABSOLUTE)
|
||||
{
|
||||
print $strError;
|
||||
exit ($iErrorCode);
|
||||
}
|
||||
|
||||
confess &log(ERROR, "${strErrorPrefix}: " . $strError);
|
||||
}
|
||||
|
||||
my @stryFileList = grep(!/^\..$/i, readdir($hPath));
|
||||
|
||||
close($hPath);
|
||||
|
||||
foreach my $strFile (@stryFileList)
|
||||
{
|
||||
my $strPathFile = "${strPathRead}/$strFile";
|
||||
my $bCurrentDir = $strFile eq ".";
|
||||
|
||||
if ($iDepth != 0)
|
||||
{
|
||||
if ($bCurrentDir)
|
||||
{
|
||||
$strFile = $strPathFileOp;
|
||||
$strPathFile = $strPathRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
$strFile = "${strPathFileOp}/${strFile}";
|
||||
}
|
||||
}
|
||||
|
||||
my $oStat = lstat($strPathFile);
|
||||
|
||||
if (!defined($oStat))
|
||||
{
|
||||
if (-e $strPathFile)
|
||||
{
|
||||
my $strError = "${strPathFile} could not be read: " . $!;
|
||||
|
||||
if ($strPathType eq PATH_ABSOLUTE)
|
||||
{
|
||||
print $strError;
|
||||
exit COMMAND_ERR_FILE_READ;
|
||||
}
|
||||
|
||||
confess &log(ERROR, "${strErrorPrefix}: " . $strError);
|
||||
}
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
# Check for regular file
|
||||
if (S_ISREG($oStat->mode))
|
||||
{
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{type} = "f";
|
||||
|
||||
# Get inode
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{inode} = $oStat->ino;
|
||||
|
||||
# Get size
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{size} = $oStat->size;
|
||||
|
||||
# Get modification time
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{modification_time} = $oStat->mtime;
|
||||
}
|
||||
# Check for directory
|
||||
elsif (S_ISDIR($oStat->mode))
|
||||
{
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{type} = "d";
|
||||
}
|
||||
# Check for link
|
||||
elsif (S_ISLNK($oStat->mode))
|
||||
{
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{type} = "l";
|
||||
|
||||
# Get link destination
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{link_destination} = readlink($strPathFile);
|
||||
|
||||
if (!defined(${$oManifestHashRef}{name}{"${strFile}"}{link_destination}))
|
||||
{
|
||||
if (-e $strPathFile)
|
||||
{
|
||||
my $strError = "${strPathFile} error reading link: " . $!;
|
||||
|
||||
if ($strPathType eq PATH_ABSOLUTE)
|
||||
{
|
||||
print $strError;
|
||||
exit COMMAND_ERR_LINK_READ;
|
||||
}
|
||||
|
||||
confess &log(ERROR, "${strErrorPrefix}: " . $strError);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my $strError = "${strPathFile} is not of type directory, file, or link";
|
||||
|
||||
if ($strPathType eq PATH_ABSOLUTE)
|
||||
{
|
||||
print $strError;
|
||||
exit COMMAND_ERR_FILE_TYPE;
|
||||
}
|
||||
|
||||
confess &log(ERROR, "${strErrorPrefix}: " . $strError);
|
||||
}
|
||||
|
||||
# Get user name
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{user} = getpwuid($oStat->uid);
|
||||
|
||||
# Get group name
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{group} = getgrgid($oStat->gid);
|
||||
|
||||
# Get permissions
|
||||
if (${$oManifestHashRef}{name}{"${strFile}"}{type} ne "l")
|
||||
{
|
||||
${$oManifestHashRef}{name}{"${strFile}"}{permission} = sprintf("%04o", S_IMODE($oStat->mode));
|
||||
}
|
||||
|
||||
# Recurse into directories
|
||||
if (${$oManifestHashRef}{name}{"${strFile}"}{type} eq "d" && !$bCurrentDir)
|
||||
{
|
||||
manifest_recurse($strPathType, $strPathOp,
|
||||
$strFile,
|
||||
$iDepth + 1, $oManifestHashRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
no Moose;
|
||||
|
||||
@@ -114,6 +114,7 @@ sub lock_file_remove
|
||||
####################################################################################################################################
|
||||
sub data_hash_build
|
||||
{
|
||||
my $oHashRef = shift;
|
||||
my $strData = shift;
|
||||
my $strDelimiter = shift;
|
||||
my $strUndefinedKey = shift;
|
||||
@@ -121,8 +122,6 @@ sub data_hash_build
|
||||
my @stryFile = split("\n", $strData);
|
||||
my @stryHeader = split($strDelimiter, $stryFile[0]);
|
||||
|
||||
my %oHash;
|
||||
|
||||
for (my $iLineIdx = 1; $iLineIdx < scalar @stryFile; $iLineIdx++)
|
||||
{
|
||||
my @stryLine = split($strDelimiter, $stryFile[$iLineIdx]);
|
||||
@@ -134,16 +133,17 @@ sub data_hash_build
|
||||
|
||||
for (my $iColumnIdx = 1; $iColumnIdx < scalar @stryHeader; $iColumnIdx++)
|
||||
{
|
||||
if (defined($oHash{"$stryHeader[0]"}{"$stryLine[0]"}{"$stryHeader[$iColumnIdx]"}))
|
||||
if (defined(${$oHashRef}{"$stryHeader[0]"}{"$stryLine[0]"}{"$stryHeader[$iColumnIdx]"}))
|
||||
{
|
||||
confess "the first column must be unique to build the hash";
|
||||
}
|
||||
|
||||
$oHash{"$stryHeader[0]"}{"$stryLine[0]"}{"$stryHeader[$iColumnIdx]"} = $stryLine[$iColumnIdx];
|
||||
if (defined($stryLine[$iColumnIdx]) && $stryLine[$iColumnIdx] ne "")
|
||||
{
|
||||
${$oHashRef}{"$stryHeader[0]"}{"$stryLine[0]"}{"$stryHeader[$iColumnIdx]"} = $stryLine[$iColumnIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return %oHash;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
|
||||
@@ -12,7 +12,7 @@ use english;
|
||||
|
||||
use Carp;
|
||||
use File::Basename;
|
||||
use Cwd 'abs_path';
|
||||
use Cwd 'abs_path';
|
||||
|
||||
use lib dirname($0) . "/..";
|
||||
use pg_backrest_file;
|
||||
@@ -30,10 +30,144 @@ sub BackRestTestFile
|
||||
my $strStanza = "db";
|
||||
my $strCommand = "/Users/dsteele/pg_backrest/bin/pg_backrest_command.pl";
|
||||
my $strHost = "127.0.0.1";
|
||||
my $strUser = "dsteele";
|
||||
my $strUser = getpwuid($<);
|
||||
my $strGroup = getgrgid($();
|
||||
|
||||
umask(0);
|
||||
|
||||
# print "user = ${strUser}, group = ${strGroup}";
|
||||
|
||||
# log_level_set(TRACE, TRACE);
|
||||
|
||||
# Test manifest()
|
||||
$iRun = 0;
|
||||
|
||||
print "\ntest File->manifest()\n";
|
||||
|
||||
# Create the test data
|
||||
system("rm -rf test");
|
||||
|
||||
system("mkdir -m 750 ${strTestPath}") == 0 or confess "Unable to create test directory";
|
||||
system("mkdir -m 750 ${strTestPath}/sub1") == 0 or confess "Unable to create test directory";
|
||||
system("mkdir -m 750 ${strTestPath}/sub1/sub2") == 0 or confess "Unable to create test directory";
|
||||
|
||||
system("echo 'TESTDATA' > ${strTestPath}/test.txt");
|
||||
utime(1111111111, 1111111111, "${strTestPath}/test.txt");
|
||||
system("chmod 1640 ${strTestPath}/test.txt");
|
||||
|
||||
system("echo 'TESTDATA_' > ${strTestPath}/sub1/test-sub1.txt");
|
||||
utime(1111111112, 1111111112, "${strTestPath}/sub1/test-sub1.txt");
|
||||
system("chmod 0640 ${strTestPath}/sub1/test-sub1.txt");
|
||||
|
||||
system("echo 'TESTDATA__' > ${strTestPath}/sub1/sub2/test-sub2.txt");
|
||||
utime(1111111113, 1111111113, "${strTestPath}/sub1/sub2/test-sub2.txt");
|
||||
system("chmod 0646 ${strTestPath}/sub1/test-sub1.txt");
|
||||
|
||||
system("ln ${strTestPath}/test.txt ${strTestPath}/sub1/test-hardlink.txt");
|
||||
system("ln ${strTestPath}/test.txt ${strTestPath}/sub1/sub2/test-hardlink.txt");
|
||||
|
||||
system("ln -s .. ${strTestPath}/sub1/test");
|
||||
system("chmod 0700 ${strTestPath}/sub1/test");
|
||||
system("ln -s ../.. ${strTestPath}/sub1/sub2/test");
|
||||
system("chmod 0750 ${strTestPath}/sub1/sub2/test");
|
||||
|
||||
my $strManifestCompare =
|
||||
".,d,${strUser},${strGroup},0750,,,,\n" .
|
||||
"sub1,d,${strUser},${strGroup},0750,,,,\n" .
|
||||
"sub1/sub2,d,${strUser},${strGroup},0750,,,,\n" .
|
||||
"sub1/sub2/test,l,${strUser},${strGroup},,,,,../..\n" .
|
||||
"sub1/sub2/test-hardlink.txt,f,${strUser},${strGroup},1640,1111111111,0,9,\n" .
|
||||
"sub1/sub2/test-sub2.txt,f,${strUser},${strGroup},0666,1111111113,0,11,\n" .
|
||||
"sub1/test,l,${strUser},${strGroup},,,,,..\n" .
|
||||
"sub1/test-hardlink.txt,f,${strUser},${strGroup},1640,1111111111,0,9,\n" .
|
||||
"sub1/test-sub1.txt,f,${strUser},${strGroup},0646,1111111112,0,10,\n" .
|
||||
"test.txt,f,${strUser},${strGroup},1640,1111111111,0,9,";
|
||||
|
||||
for (my $bRemote = 0; $bRemote <= 1; $bRemote++)
|
||||
{
|
||||
my $oFile = pg_backrest_file->new
|
||||
(
|
||||
strStanza => $strStanza,
|
||||
bNoCompression => true,
|
||||
strCommand => $strCommand,
|
||||
strBackupClusterPath => ${strTestPath},
|
||||
strBackupPath => ${strTestPath},
|
||||
strBackupHost => $bRemote ? $strHost : undef,
|
||||
strBackupUser => $bRemote ? $strUser : undef
|
||||
);
|
||||
|
||||
for (my $bError = 0; $bError <= 1; $bError++)
|
||||
{
|
||||
$iRun++;
|
||||
|
||||
print "run ${iRun} - " .
|
||||
"remote $bRemote, error $bError\n";
|
||||
|
||||
my $strPath = $strTestPath;
|
||||
|
||||
if ($bError)
|
||||
{
|
||||
$strPath .= "-error";
|
||||
}
|
||||
|
||||
# Execute in eval in case of error
|
||||
eval
|
||||
{
|
||||
my %oManifestHash;
|
||||
$oFile->manifest(PATH_BACKUP_ABSOLUTE, $strPath, \%oManifestHash);
|
||||
|
||||
my $strManifest;
|
||||
|
||||
foreach my $strName (sort(keys $oManifestHash{name}))
|
||||
{
|
||||
if (!defined($strManifest))
|
||||
{
|
||||
$strManifest = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
$strManifest .= "\n";
|
||||
}
|
||||
|
||||
if (defined($oManifestHash{name}{"${strName}"}{inode}))
|
||||
{
|
||||
$oManifestHash{name}{"${strName}"}{inode} = 0;
|
||||
}
|
||||
|
||||
$strManifest .=
|
||||
"${strName}," .
|
||||
$oManifestHash{name}{"${strName}"}{type} . "," .
|
||||
(defined($oManifestHash{name}{"${strName}"}{user}) ?
|
||||
$oManifestHash{name}{"${strName}"}{user} : "") . "," .
|
||||
(defined($oManifestHash{name}{"${strName}"}{group}) ?
|
||||
$oManifestHash{name}{"${strName}"}{group} : "") . "," .
|
||||
(defined($oManifestHash{name}{"${strName}"}{permission}) ?
|
||||
$oManifestHash{name}{"${strName}"}{permission} : "") . "," .
|
||||
(defined($oManifestHash{name}{"${strName}"}{modification_time}) ?
|
||||
$oManifestHash{name}{"${strName}"}{modification_time} : "") . "," .
|
||||
(defined($oManifestHash{name}{"${strName}"}{inode}) ?
|
||||
$oManifestHash{name}{"${strName}"}{inode} : "") . "," .
|
||||
(defined($oManifestHash{name}{"${strName}"}{size}) ?
|
||||
$oManifestHash{name}{"${strName}"}{size} : "") . "," .
|
||||
(defined($oManifestHash{name}{"${strName}"}{link_destination}) ?
|
||||
$oManifestHash{name}{"${strName}"}{link_destination} : "");
|
||||
}
|
||||
|
||||
if ($strManifest ne $strManifestCompare)
|
||||
{
|
||||
confess "manifest is not equal:\n\n${strManifest}\n\ncompare:\n\n${strManifestCompare}\n\n";
|
||||
}
|
||||
};
|
||||
|
||||
if ($@ && !$bError)
|
||||
{
|
||||
confess "error raised: " . $@ . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
# Test list()
|
||||
$iRun = 0;
|
||||
|
||||
@@ -124,7 +258,7 @@ sub BackRestTestFile
|
||||
|
||||
if ($@ && $bExists)
|
||||
{
|
||||
confess " error raised: " . $@ . "\n";
|
||||
confess "error raised: " . $@ . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +321,7 @@ sub BackRestTestFile
|
||||
|
||||
if ($@ && $bExists)
|
||||
{
|
||||
confess " error raised: " . $@ . "\n";
|
||||
confess "error raised: " . $@ . "\n";
|
||||
}
|
||||
|
||||
if (-e ($strFile . ($bTemp ? ".backrest.tmp" : "")))
|
||||
@@ -249,7 +383,7 @@ sub BackRestTestFile
|
||||
{
|
||||
if ($bExists)
|
||||
{
|
||||
confess " error raised: " . $@ . "\n";
|
||||
confess "error raised: " . $@ . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,7 +437,7 @@ sub BackRestTestFile
|
||||
|
||||
if ($@)
|
||||
{
|
||||
confess " error raised: " . $@ . "\n";
|
||||
confess "error raised: " . $@ . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,12 +548,12 @@ sub BackRestTestFile
|
||||
elsif ($bError)
|
||||
{
|
||||
my $strError = $oFile->error_get();
|
||||
|
||||
|
||||
if (!defined($strError) || ($strError eq ''))
|
||||
{
|
||||
confess 'no error message returned';
|
||||
}
|
||||
|
||||
|
||||
print " error raised: ${strError}\n";
|
||||
next;
|
||||
}
|
||||
@@ -449,12 +583,11 @@ sub BackRestTestFile
|
||||
{
|
||||
confess 'no error message returned';
|
||||
}
|
||||
|
||||
|
||||
print " error returned: ${strError}\n";
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -465,7 +598,7 @@ sub BackRestTestFile
|
||||
|
||||
print " true was returned\n";
|
||||
}
|
||||
|
||||
|
||||
# Check for errors after copy
|
||||
if ($bDestinationCompressed)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user