1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2026-05-22 10:15:16 +02:00
Files
pgbackrest/src/perl/embed.auto.c
T
David Steele e4cc008b98 Remove duplicated hint.
At some point this hint got added to the underlying code so it is no longer needed here.
2019-05-22 11:31:38 -04:00

19746 lines
744 KiB
C

/***********************************************************************************************************************************
Embed Perl modules
Automatically generated by Build.pm -- do not modify directly.
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Embedded Perl modules
***********************************************************************************************************************************/
static const EmbeddedModule embeddedModule[] =
{
{
.name = "pgBackRest/Archive/Common.pm",
.data =
"\n\n\n"
"package pgBackRest::Archive::Common;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Config;\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Fcntl qw(SEEK_CUR O_RDONLY);\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Db;\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n"
"use constant REGEX_ARCHIVE_DIR_DB_VERSION => '^[0-9]+(\\.[0-9]+)*-[0-9]+$';\n"
"push @EXPORT, qw(REGEX_ARCHIVE_DIR_DB_VERSION);\n"
"use constant REGEX_ARCHIVE_DIR_WAL => '^[0-F]{16}$';\n"
"push @EXPORT, qw(REGEX_ARCHIVE_DIR_WAL);\n"
"\n\n\n\n"
"use constant PG_WAL_SYSTEM_ID_OFFSET_GTE_93 => 12 + $Config{ptrsize};\n"
"push @EXPORT, qw(PG_WAL_SYSTEM_ID_OFFSET_GTE_93);\n"
"use constant PG_WAL_SYSTEM_ID_OFFSET_LT_93 => 12;\n"
"push @EXPORT, qw(PG_WAL_SYSTEM_ID_OFFSET_LT_93);\n"
"\n\n\n\n"
"use constant PG_WAL_SEGMENT_SIZE => 16777216;\n"
"push @EXPORT, qw(PG_WAL_SEGMENT_SIZE);\n"
"\n\n\n\n\n\n"
"sub lsnNormalize\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strLsn,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::lsnFile', \\@_,\n"
"{name => 'strLsn', trace => true},\n"
");\n"
"\n\n"
"my @stryLsnSplit = split('/', $strLsn);\n"
"\n"
"if (@stryLsnSplit != 2)\n"
"{\n"
"confess &log(ASSERT, \"invalid lsn ${strLsn}\");\n"
"}\n"
"\n"
"my $strLsnNormal = uc(sprintf(\"%08s%08s\", $stryLsnSplit[0], $stryLsnSplit[1]));\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strLsnNormal', value => $strLsnNormal, trace => true}\n"
");\n"
"\n"
"}\n"
"\n"
"push @EXPORT, qw(lsnNormalize);\n"
"\n\n\n\n\n\n\n"
"sub lsnFileRange\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strLsnStart,\n"
"$strLsnStop,\n"
"$strDbVersion,\n"
"$iWalSegmentSize,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::lsnFileRange', \\@_,\n"
"{name => 'strLsnStart'},\n"
"{name => 'strLsnStop'},\n"
"{name => '$strDbVersion'},\n"
"{name => '$iWalSegmentSize'},\n"
");\n"
"\n\n"
"my @stryArchive;\n"
"my $iArchiveIdx = 0;\n"
"my $bSkipFF = $strDbVersion < PG_VERSION_93;\n"
"\n\n"
"my @stryArchiveSplit = split('/', $strLsnStart);\n"
"my $iStartMajor = hex($stryArchiveSplit[0]);\n"
"my $iStartMinor = int(hex($stryArchiveSplit[1]) / $iWalSegmentSize);\n"
"\n"
"@stryArchiveSplit = split('/', $strLsnStop);\n"
"my $iStopMajor = hex($stryArchiveSplit[0]);\n"
"my $iStopMinor = int(hex($stryArchiveSplit[1]) / $iWalSegmentSize);\n"
"\n"
"$stryArchive[$iArchiveIdx] = uc(sprintf(\"%08x%08x\", $iStartMajor, $iStartMinor));\n"
"$iArchiveIdx += 1;\n"
"\n"
"while (!($iStartMajor == $iStopMajor && $iStartMinor == $iStopMinor))\n"
"{\n"
"$iStartMinor += 1;\n"
"\n"
"if ($bSkipFF && $iStartMinor == 255 || !$bSkipFF && $iStartMinor > int(0xFFFFFFFF / $iWalSegmentSize))\n"
"{\n"
"$iStartMajor += 1;\n"
"$iStartMinor = 0;\n"
"}\n"
"\n"
"$stryArchive[$iArchiveIdx] = uc(sprintf(\"%08x%08x\", $iStartMajor, $iStartMinor));\n"
"$iArchiveIdx += 1;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryWalFileName', value => \\@stryArchive}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(lsnFileRange);\n"
"\n\n\n\n\n\n\n"
"sub walSegmentFind\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oStorageRepo,\n"
"$strArchiveId,\n"
"$strWalSegment,\n"
"$iWaitSeconds,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::walSegmentFind', \\@_,\n"
"{name => 'oStorageRepo'},\n"
"{name => 'strArchiveId'},\n"
"{name => 'strWalSegment'},\n"
"{name => 'iWaitSeconds', required => false},\n"
");\n"
"\n\n"
"if (!walIsSegment($strWalSegment))\n"
"{\n"
"confess &log(ERROR, \"${strWalSegment} is not a WAL segment\", ERROR_ASSERT);\n"
"}\n"
"\n\n"
"my $oWait = waitInit($iWaitSeconds);\n"
"my @stryWalFileName;\n"
"\n"
"do\n"
"{\n"
"\n"
"push(@stryWalFileName, $oStorageRepo->list(\n"
"STORAGE_REPO_ARCHIVE . \"/${strArchiveId}/\" . substr($strWalSegment, 0, 16),\n"
"{strExpression =>\n"
"'^' . substr($strWalSegment, 0, 24) . (walIsPartial($strWalSegment) ? \"\\\\.partial\" : '') .\n"
"\"-[0-f]{40}(\\\\.\" . COMPRESS_EXT . \"){0,1}\\$\",\n"
"bIgnoreMissing => true}));\n"
"}\n"
"while (@stryWalFileName == 0 && waitMore($oWait));\n"
"\n\n\n"
"if (@stryWalFileName > 1)\n"
"{\n"
"confess &log(ERROR,\n"
"\"duplicates found in archive for WAL segment ${strWalSegment}: \" . join(', ', @stryWalFileName) .\n"
"\"\\nHINT: are multiple primaries archiving to this stanza?\",\n"
"ERROR_ARCHIVE_DUPLICATE);\n"
"}\n"
"\n\n"
"if (@stryWalFileName == 0 && defined($iWaitSeconds))\n"
"{\n"
"confess &log(\n"
"ERROR,\n"
"\"could not find WAL segment ${strWalSegment} after ${iWaitSeconds} second(s)\" .\n"
"\"\\nHINT: is archive_command configured correctly?\" .\n"
"\"\\nHINT: use the check command to verify that PostgreSQL is archiving.\",\n"
"ERROR_ARCHIVE_TIMEOUT);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strWalFileName', value => $stryWalFileName[0]}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(walSegmentFind);\n"
"\n\n\n\n\n\n"
"sub walIsSegment\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strWalFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::walIsSegment', \\@_,\n"
"{name => 'strWalFile', trace => true},\n"
");\n"
"\n"
"return $strWalFile =~ /^[0-F]{24}(\\.partial){0,1}$/ ? true : false;\n"
"}\n"
"\n"
"push @EXPORT, qw(walIsSegment);\n"
"\n\n\n\n\n\n"
"sub walIsPartial\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strWalFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::walIsPartial', \\@_,\n"
"{name => 'strWalFile', trace => true},\n"
");\n"
"\n"
"return walIsSegment($strWalFile) && $strWalFile =~ /\\.partial$/ ? true : false;\n"
"}\n"
"\n"
"push @EXPORT, qw(walIsPartial);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Archive/Get/File.pm",
.data =
"\n\n\n"
"package pgBackRest::Archive::Get::File;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(basename dirname);\n"
"\n"
"use pgBackRest::Archive::Common;\n"
"use pgBackRest::Archive::Info;\n"
"use pgBackRest::Db;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Lock;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Filter::Gzip;\n"
"use pgBackRest::Storage::Filter::Sha;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n\n"
"sub archiveGetCheck\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
"$strFile,\n"
"$bCheck,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::archiveGetCheck', \\@_,\n"
"{name => 'strDbVersion', required => false},\n"
"{name => 'ullDbSysId', required => false},\n"
"{name => 'strFile', required => false},\n"
"{name => 'bCheck', required => false, default => true},\n"
");\n"
"\n"
"my @stryArchiveId = ();\n"
"my $strArchiveId;\n"
"my $strArchiveFile;\n"
"my $strCipherPass;\n"
"\n\n"
"if (!defined($strDbVersion) || !defined($ullDbSysId) )\n"
"{\n"
"\n"
"($strDbVersion, my $iControlVersion, my $iCatalogVersion, $ullDbSysId) = dbMasterGet()->info();\n"
"}\n"
"\n\n"
"if (!isRepoLocal())\n"
"{\n"
"($strArchiveId, $strArchiveFile, $strCipherPass) = protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(\n"
"OP_ARCHIVE_GET_CHECK, [$strDbVersion, $ullDbSysId, $strFile, $bCheck], true);\n"
"}\n"
"else\n"
"{\n"
"my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), true);\n"
"\n\n"
"if ($bCheck)\n"
"{\n"
"push(@stryArchiveId, $oArchiveInfo->check($strDbVersion, $ullDbSysId));\n"
"}\n"
"\n"
"else\n"
"{\n"
"@stryArchiveId = $oArchiveInfo->archiveIdList($strDbVersion, $ullDbSysId);\n"
"}\n"
"\n\n\n"
"$strArchiveId = $stryArchiveId[0];\n"
"\n\n"
"if (defined($strFile))\n"
"{\n"
"foreach my $strId (@stryArchiveId)\n"
"{\n"
"\n"
"if (walIsSegment($strFile))\n"
"{\n"
"$strArchiveFile = walSegmentFind(storageRepo(), $strId, $strFile);\n"
"}\n"
"\n"
"elsif (storageRepo()->exists(STORAGE_REPO_ARCHIVE . \"/${strId}/${strFile}\"))\n"
"{\n"
"$strArchiveFile = $strFile;\n"
"}\n"
"\n\n"
"if (defined($strArchiveFile))\n"
"{\n"
"$strArchiveId = $strId;\n"
"last;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"$strCipherPass = $oArchiveInfo->cipherPassSub();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strArchiveId', value => $strArchiveId},\n"
"{name => 'strArchiveFile', value => $strArchiveFile},\n"
"{name => 'strCipherPass', value => $strCipherPass, redact => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(archiveGetCheck);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Archive/Info.pm",
.data =
"\n\n\n\n\n\n\n"
"package pgBackRest::Archive::Info;\n"
"use parent 'pgBackRest::Common::Ini';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname basename);\n"
"\n"
"use pgBackRest::Archive::Common;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::InfoCommon;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Filter::Gzip;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n"
"use constant ARCHIVE_INFO_FILE => 'archive.info';\n"
"push @EXPORT, qw(ARCHIVE_INFO_FILE);\n"
"\n\n\n\n"
"use constant INFO_ARCHIVE_SECTION_DB => INFO_BACKUP_SECTION_DB;\n"
"push @EXPORT, qw(INFO_ARCHIVE_SECTION_DB);\n"
"use constant INFO_ARCHIVE_SECTION_DB_HISTORY => INFO_BACKUP_SECTION_DB_HISTORY;\n"
"push @EXPORT, qw(INFO_ARCHIVE_SECTION_DB_HISTORY);\n"
"\n"
"use constant INFO_ARCHIVE_KEY_DB_VERSION => MANIFEST_KEY_DB_VERSION;\n"
"push @EXPORT, qw(INFO_ARCHIVE_KEY_DB_VERSION);\n"
"use constant INFO_ARCHIVE_KEY_DB_ID => MANIFEST_KEY_DB_ID;\n"
"push @EXPORT, qw(INFO_ARCHIVE_KEY_DB_ID);\n"
"use constant INFO_ARCHIVE_KEY_DB_SYSTEM_ID => MANIFEST_KEY_SYSTEM_ID;\n"
"push @EXPORT, qw(INFO_ARCHIVE_KEY_DB_SYSTEM_ID);\n"
"\n\n\n\n"
"my $strArchiveInfoMissingMsg =\n"
"ARCHIVE_INFO_FILE . \" does not exist but is required to push/get WAL segments\\n\" .\n"
"\"HINT: is archive_command configured in postgresql.conf?\\n\" .\n"
"\"HINT: has a stanza-create been performed?\\n\" .\n"
"\"HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving scheme.\";\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strArchiveClusterPath,\n"
"$bRequired,\n"
"$bLoad,\n"
"$bIgnoreMissing, # Don't error on missing files\n"
"$strCipherPassSub,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strArchiveClusterPath'},\n"
"{name => 'bRequired', default => true},\n"
"{name => 'bLoad', optional => true, default => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
"{name => 'strCipherPassSub', optional => true},\n"
");\n"
"\n\n"
"my $strArchiveInfoFile = \"${strArchiveClusterPath}/\" . ARCHIVE_INFO_FILE;\n"
"my $self = {};\n"
"my $iResult = 0;\n"
"my $strResultMessage;\n"
"\n\n"
"eval\n"
"{\n"
"$self = $class->SUPER::new($strArchiveInfoFile, {bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing,\n"
"oStorage => storageRepo(), strCipherPass => storageRepo()->cipherPassUser(),\n"
"strCipherPassSub => $strCipherPassSub});\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n"
"if ($iResult != 0)\n"
"{\n"
"\n\n"
"if ($iResult == ERROR_FILE_MISSING)\n"
"{\n"
"if ($bRequired)\n"
"{\n"
"confess &log(ERROR, $strArchiveInfoMissingMsg, ERROR_FILE_MISSING);\n"
"}\n"
"}\n"
"elsif ($iResult == ERROR_CRYPTO && $strResultMessage =~ \"^unable to flush\")\n"
"{\n"
"confess &log(ERROR, \"unable to parse '$strArchiveInfoFile'\\nHINT: Is or was the repo encrypted?\", $iResult);\n"
"}\n"
"else\n"
"{\n"
"confess $EVAL_ERROR;\n"
"}\n"
"}\n"
"\n"
"$self->{strArchiveClusterPath} = $strArchiveClusterPath;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub check\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
"$bRequired,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->check', \\@_,\n"
"{name => 'strDbVersion'},\n"
"{name => 'ullDbSysId'},\n"
"{name => 'bRequired', default => true},\n"
");\n"
"\n\n"
"if ($bRequired)\n"
"{\n"
"\n"
"$self->confirmExists();\n"
"}\n"
"\n"
"my $strError = undef;\n"
"\n"
"if (!$self->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef, $strDbVersion))\n"
"{\n"
"$strError = \"WAL segment version ${strDbVersion} does not match archive version \" .\n"
"$self->get(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION);\n"
"}\n"
"\n"
"if (!$self->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID, undef, $ullDbSysId))\n"
"{\n"
"$strError = (defined($strError) ? ($strError . \"\\n\") : \"\") .\n"
"\"WAL segment system-id ${ullDbSysId} does not match archive system-id \" .\n"
"$self->get(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID);\n"
"}\n"
"\n"
"if (defined($strError))\n"
"{\n"
"confess &log(ERROR, \"${strError}\\nHINT: are you archiving to the correct stanza?\", ERROR_ARCHIVE_MISMATCH);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strArchiveId', value => $self->archiveId()}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub archiveId\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
") = logDebugParam\n"
"(\n"
"__PACKAGE__ . '->archiveId', \\@_,\n"
"{name => 'strDbVersion', optional => true},\n"
"{name => 'ullDbSysId', optional => true},\n"
");\n"
"\n"
"my $strArchiveId = undef;\n"
"\n\n"
"if (!defined($strDbVersion) && !defined($ullDbSysId))\n"
"{\n"
"$strArchiveId = $self->get(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION) . \"-\" .\n"
"$self->get(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_ID);\n"
"}\n"
"\n"
"elsif (defined($strDbVersion) && defined($ullDbSysId))\n"
"{\n"
"\n"
"$strArchiveId = ($self->archiveIdList($strDbVersion, $ullDbSysId))[0];\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strArchiveId', value => $strArchiveId}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub archiveIdList\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
") = logDebugParam\n"
"(\n"
"__PACKAGE__ . '->archiveIdList', \\@_,\n"
"{name => 'strDbVersion'},\n"
"{name => 'ullDbSysId'},\n"
");\n"
"\n"
"my @stryArchiveId;\n"
"\n\n"
"my $hDbList = $self->dbHistoryList();\n"
"\n"
"foreach my $iDbHistoryId (sort {$a <=> $b} keys %$hDbList)\n"
"{\n"
"\n"
"if (($hDbList->{$iDbHistoryId}{&INFO_DB_VERSION} eq $strDbVersion) &&\n"
"($hDbList->{$iDbHistoryId}{&INFO_SYSTEM_ID} eq $ullDbSysId))\n"
"{\n"
"unshift(@stryArchiveId, $strDbVersion . \"-\" . $iDbHistoryId);\n"
"}\n"
"}\n"
"\n\n"
"if (@stryArchiveId == 0)\n"
"{\n"
"confess &log(\n"
"ERROR, \"unable to retrieve the archive id for database version '$strDbVersion' and system-id '$ullDbSysId'\",\n"
"ERROR_ARCHIVE_MISMATCH);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryArchiveId', value => \\@stryArchiveId}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub create\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
"$bSave,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->create', \\@_,\n"
"{name => 'strDbVersion'},\n"
"{name => 'ullDbSysId'},\n"
"{name => 'bSave', default => true},\n"
");\n"
"\n\n"
"$self->dbSectionSet($strDbVersion, $ullDbSysId, $self->dbHistoryIdGet(false));\n"
"\n"
"if ($bSave)\n"
"{\n"
"$self->save();\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub reconstruct\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strCurrentDbVersion,\n"
"$ullCurrentDbSysId,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->reconstruct', \\@_,\n"
"{name => 'strCurrentDbVersion'},\n"
"{name => 'ullCurrentDbSysId'},\n"
");\n"
"\n"
"my $strInvalidFileStructure = undef;\n"
"\n"
"my @stryArchiveId = storageRepo()->list(\n"
"$self->{strArchiveClusterPath}, {strExpression => REGEX_ARCHIVE_DIR_DB_VERSION, bIgnoreMissing => true});\n"
"my %hDbHistoryVersion;\n"
"\n\n"
"foreach my $strArchiveId (@stryArchiveId)\n"
"{\n"
"my ($strDbVersion, $iDbHistoryId) = split(\"-\", $strArchiveId);\n"
"$hDbHistoryVersion{$iDbHistoryId} = $strDbVersion;\n"
"}\n"
"\n\n"
"foreach my $iDbHistoryId (sort {$a <=> $b} keys %hDbHistoryVersion)\n"
"{\n"
"my $strDbVersion = $hDbHistoryVersion{$iDbHistoryId};\n"
"my $strVersionDir = $strDbVersion . \"-\" . $iDbHistoryId;\n"
"\n\n"
"my $strArchiveDir = (storageRepo()->list(\n"
"$self->{strArchiveClusterPath} . \"/${strVersionDir}\",\n"
"{strExpression => REGEX_ARCHIVE_DIR_WAL, bIgnoreMissing => true}))[0];\n"
"\n\n"
"if (!defined($strArchiveDir))\n"
"{\n"
"$strInvalidFileStructure = \"found empty directory \" . $self->{strArchiveClusterPath} . \"/${strVersionDir}\";\n"
"next;\n"
"}\n"
"\n\n"
"my $strArchiveFile = (storageRepo()->list(\n"
"$self->{strArchiveClusterPath} . \"/${strVersionDir}/${strArchiveDir}\",\n"
"{strExpression => \"^[0-F]{24}(\\\\.partial){0,1}(-[0-f]+){0,1}(\\\\.\" . COMPRESS_EXT . \"){0,1}\\$\",\n"
"bIgnoreMissing => true}))[0];\n"
"\n\n"
"if (!defined($strArchiveFile))\n"
"{\n"
"$strInvalidFileStructure =\n"
"\"found empty directory \" . $self->{strArchiveClusterPath} . \"/${strVersionDir}/${strArchiveDir}\";\n"
"next;\n"
"}\n"
"\n\n"
"my $strArchiveFilePath = $self->{strArchiveClusterPath}.\"/${strVersionDir}/${strArchiveDir}/${strArchiveFile}\";\n"
"\n\n"
"my $iSysIdOffset = $strDbVersion >= PG_VERSION_93 ? PG_WAL_SYSTEM_ID_OFFSET_GTE_93 : PG_WAL_SYSTEM_ID_OFFSET_LT_93;\n"
"\n\n"
"my $tBlock;\n"
"\n\n"
"if (!storageRepo()->encryptionValid(storageRepo()->encrypted($strArchiveFilePath)))\n"
"{\n"
"confess &log(ERROR, \"encryption incompatible for '$strArchiveFilePath'\" .\n"
"\"\\nHINT: Is or was the repo encrypted?\", ERROR_CRYPTO);\n"
"}\n"
"\n\n"
"my $oFileIo = storageRepo()->openRead(\n"
"$strArchiveFilePath,\n"
"{rhyFilter => $strArchiveFile =~ ('\\.' . COMPRESS_EXT . '$') ?\n"
"[{strClass => STORAGE_FILTER_GZIP, rxyParam => [{strCompressType => STORAGE_DECOMPRESS}]}] : undef,\n"
"strCipherPass => $self->cipherPassSub()});\n"
"\n"
"$oFileIo->read(\\$tBlock, 512, true);\n"
"$oFileIo->close();\n"
"\n\n"
"my ($iMagic, $iFlag, $junk, $ullDbSysId) = unpack('SSa' . $iSysIdOffset . 'Q', $tBlock);\n"
"\n"
"if (!defined($ullDbSysId))\n"
"{\n"
"confess &log(ERROR, \"unable to read database system identifier\", ERROR_FILE_READ);\n"
"}\n"
"\n\n"
"$self->dbSectionSet($strDbVersion, $ullDbSysId, $iDbHistoryId);\n"
"}\n"
"\n\n"
"if (!$self->test(INFO_ARCHIVE_SECTION_DB))\n"
"{\n"
"$self->create($strCurrentDbVersion, $ullCurrentDbSysId, false);\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"logDisable();\n"
"\n"
"eval\n"
"{\n"
"$self->check($strCurrentDbVersion, $ullCurrentDbSysId, false);\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"logEnable();\n"
"\n\n"
"confess $EVAL_ERROR if (exceptionCode($EVAL_ERROR) != ERROR_ARCHIVE_MISMATCH);\n"
"\n\n"
"$self->dbSectionSet($strCurrentDbVersion, $ullCurrentDbSysId, $self->dbHistoryIdGet(false)+1);\n"
"};\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strInvalidFileStructure', value => $strInvalidFileStructure}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbHistoryIdGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bFileRequired,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->dbHistoryIdGet', \\@_,\n"
"{name => 'bFileRequired', default => true},\n"
");\n"
"\n\n"
"if ($bFileRequired)\n"
"{\n"
"$self->confirmExists();\n"
"}\n"
"\n\n"
"my $iDbHistoryId = (!$self->test(INFO_ARCHIVE_SECTION_DB))\n"
"? 1 : $self->numericGet(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_ID);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iDbHistoryId', value => $iDbHistoryId}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbHistoryList\n"
"{\n"
"my $self = shift;\n"
"my\n"
"(\n"
"$strOperation,\n"
") = logDebugParam\n"
"(\n"
"__PACKAGE__ . '->dbHistoryList',\n"
");\n"
"\n"
"my %hDbHash;\n"
"\n"
"foreach my $iHistoryId ($self->keys(INFO_ARCHIVE_SECTION_DB_HISTORY))\n"
"{\n"
"$hDbHash{$iHistoryId}{&INFO_DB_VERSION} =\n"
"$self->get(INFO_ARCHIVE_SECTION_DB_HISTORY, $iHistoryId, INFO_ARCHIVE_KEY_DB_VERSION);\n"
"$hDbHash{$iHistoryId}{&INFO_SYSTEM_ID} =\n"
"$self->get(INFO_ARCHIVE_SECTION_DB_HISTORY, $iHistoryId, INFO_ARCHIVE_KEY_DB_ID);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hDbHash', value => \\%hDbHash}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbSectionSet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
"$iDbHistoryId,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->dbSectionSet', \\@_,\n"
"{name => 'strDbVersion', trace => true},\n"
"{name => 'ullDbSysId', trace => true},\n"
"{name => 'iDbHistoryId', trace => true}\n"
");\n"
"\n\n"
"$self->numericSet(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID, undef, $ullDbSysId);\n"
"$self->set(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef, $strDbVersion);\n"
"$self->numericSet(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_ID, undef, $iDbHistoryId);\n"
"\n\n"
"$self->numericSet(INFO_ARCHIVE_SECTION_DB_HISTORY, $iDbHistoryId, INFO_ARCHIVE_KEY_DB_ID, $ullDbSysId);\n"
"$self->set(INFO_ARCHIVE_SECTION_DB_HISTORY, $iDbHistoryId, INFO_ARCHIVE_KEY_DB_VERSION, $strDbVersion);\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub confirmExists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"if (!$self->test(INFO_ARCHIVE_SECTION_DB) || !$self->{bExists})\n"
"{\n"
"confess &log(ERROR, $strArchiveInfoMissingMsg, ERROR_FILE_MISSING);\n"
"}\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Backup/Backup.pm",
.data =
"\n\n\n"
"package pgBackRest::Backup::Backup;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"use File::Basename;\n"
"\n"
"use pgBackRest::Archive::Common;\n"
"use pgBackRest::Backup::Common;\n"
"use pgBackRest::Backup::File;\n"
"use pgBackRest::Backup::Info;\n"
"use pgBackRest::Common::Cipher;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Db;\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Local::Process;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Common::Io::Handle;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Filter::Gzip;\n"
"use pgBackRest::Storage::Filter::Sha;\n"
"use pgBackRest::Storage::Helper;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub resumeClean\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oStorageRepo,\n"
"$strBackupLabel,\n"
"$oManifest,\n"
"$oAbortedManifest,\n"
"$bOnline,\n"
"$bDelta,\n"
"$strTimelineCurrent,\n"
"$strTimelineLast,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->resumeClean', \\@_,\n"
"{name => 'oStorageRepo'},\n"
"{name => 'strBackupLabel'},\n"
"{name => 'oManifest'},\n"
"{name => 'oAbortedManifest'},\n"
"{name => 'bOnline'},\n"
"{name => 'bDelta'},\n"
"{name => 'strTimelineCurrent', required => false},\n"
"{name => 'strTimelineLast', required => false},\n"
");\n"
"\n"
"&log(DETAIL, 'clean resumed backup path: ' . $oStorageRepo->pathGet(STORAGE_REPO_BACKUP . \"/${strBackupLabel}\"));\n"
"\n\n"
"my $hFile = $oStorageRepo->manifest(STORAGE_REPO_BACKUP . \"/${strBackupLabel}\");\n"
"\n\n"
"my $bCompressed = $oAbortedManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS);\n"
"\n"
"if (!$bDelta)\n"
"{\n"
"\n"
"$bDelta = $oAbortedManifest->checkDelta(\n"
"'resumed', $oAbortedManifest->boolTest(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE, undef, $bOnline),\n"
"$strTimelineCurrent, $strTimelineLast);\n"
"\n\n"
"if (!$bDelta)\n"
"{\n"
"my @stryFileList = ();\n"
"\n"
"foreach my $strName (sort(keys(%{$hFile})))\n"
"{\n"
"\n"
"if ($strName eq FILE_MANIFEST_COPY ||\n"
"$strName eq '.')\n"
"{\n"
"next;\n"
"}\n"
"\n"
"if ($hFile->{$strName}{type} eq 'f')\n"
"{\n"
"\n"
"my $strFile = $strName;\n"
"\n"
"if ($bCompressed)\n"
"{\n"
"$strFile = substr($strFile, 0, length($strFile) - 3);\n"
"}\n"
"\n\n\n"
"if ($oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strFile) &&\n"
"!$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_REFERENCE) &&\n"
"$oAbortedManifest->test(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM))\n"
"{\n"
"push(@stryFileList, $strFile);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (@stryFileList)\n"
"{\n"
"$bDelta = $oManifest->checkDeltaFile(\\@stryFileList, $oAbortedManifest, undef);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"my @stryFile;\n"
"\n"
"foreach my $strName (sort(keys(%{$hFile})))\n"
"{\n"
"\n"
"if ($strName eq FILE_MANIFEST_COPY ||\n"
"$strName eq '.')\n"
"{\n"
"next;\n"
"}\n"
"\n\n"
"my $cType = $hFile->{$strName}{type};\n"
"\n\n"
"if ($cType eq 'd')\n"
"{\n"
"if ($oManifest->test(MANIFEST_SECTION_TARGET_PATH, $strName))\n"
"{\n"
"next;\n"
"}\n"
"}\n"
"\n"
"elsif ($cType eq 'f')\n"
"{\n"
"\n"
"my $strFile = $strName;\n"
"\n"
"if ($bCompressed)\n"
"{\n"
"$strFile = substr($strFile, 0, length($strFile) - 3);\n"
"}\n"
"\n\n"
"if ($oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strFile) &&\n"
"!$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_REFERENCE))\n"
"{\n"
"\n"
"my $strChecksum = $oAbortedManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM, false);\n"
"\n\n\n\n\n"
"if (defined($strChecksum) &&\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_SIZE) ==\n"
"$oAbortedManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_SIZE) &&\n"
"($bDelta ||\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_TIMESTAMP) ==\n"
"$oAbortedManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_TIMESTAMP)))\n"
"{\n"
"$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksum);\n"
"\n\n"
"my $bChecksumPage =\n"
"$oAbortedManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, false);\n"
"\n"
"if (defined($bChecksumPage))\n"
"{\n"
"$oManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, $bChecksumPage);\n"
"\n"
"if (!$bChecksumPage &&\n"
"$oAbortedManifest->test(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR))\n"
"{\n"
"$oManifest->set(\n"
"MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR,\n"
"$oAbortedManifest->get(\n"
"MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR));\n"
"}\n"
"}\n"
"\n"
"next;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if ($cType eq 'd')\n"
"{\n"
"logDebugMisc($strOperation, \"remove path ${strName}\");\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strName}\", {bRecurse => true});\n"
"}\n"
"\n"
"else\n"
"{\n"
"logDebugMisc($strOperation, \"remove file ${strName}\");\n"
"push(@stryFile, STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strName}\");\n"
"}\n"
"}\n"
"\n\n"
"if (@stryFile > 0)\n"
"{\n"
"$oStorageRepo->remove(\\@stryFile);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bDelta', value => $bDelta, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub processManifest\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbMasterPath,\n"
"$strDbCopyPath,\n"
"$strType,\n"
"$strDbVersion,\n"
"$bCompress,\n"
"$bHardLink,\n"
"$oBackupManifest,\n"
"$strBackupLabel,\n"
"$strLsnStart,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->processManifest', \\@_,\n"
"{name => 'strDbMasterPath'},\n"
"{name => 'strDbCopyPath'},\n"
"{name => 'strType'},\n"
"{name => 'strDbVersion'},\n"
"{name => 'bCompress'},\n"
"{name => 'bHardLink'},\n"
"{name => 'oBackupManifest'},\n"
"{name => 'strBackupLabel'},\n"
"{name => 'strLsnStart', required => false},\n"
");\n"
"\n\n"
"&log(TEST, TEST_BACKUP_START);\n"
"\n\n"
"my $oProtocolMaster =\n"
"!isDbLocal({iRemoteIdx => $self->{iMasterRemoteIdx}}) ?\n"
"protocolGet(CFGOPTVAL_REMOTE_TYPE_DB, $self->{iMasterRemoteIdx}) : undef;\n"
"defined($oProtocolMaster) && $oProtocolMaster->noOp();\n"
"\n\n"
"my $oBackupProcess = new pgBackRest::Protocol::Local::Process(CFGOPTVAL_LOCAL_TYPE_DB);\n"
"\n"
"if ($self->{iCopyRemoteIdx} != $self->{iMasterRemoteIdx})\n"
"{\n"
"$oBackupProcess->hostAdd($self->{iMasterRemoteIdx}, 1);\n"
"}\n"
"\n"
"$oBackupProcess->hostAdd($self->{iCopyRemoteIdx}, cfgOption(CFGOPT_PROCESS_MAX));\n"
"\n\n"
"my $lFileTotal = 0;\n"
"my $lSizeTotal = 0;\n"
"\n\n"
"if ($bHardLink || $strType eq CFGOPTVAL_BACKUP_TYPE_FULL)\n"
"{\n"
"\n"
"foreach my $strPath ($oBackupManifest->keys(MANIFEST_SECTION_TARGET_PATH))\n"
"{\n"
"storageRepo()->pathCreate(STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strPath}\", {bIgnoreExists => true});\n"
"}\n"
"\n"
"if (storageRepo()->driver()->capability(STORAGE_CAPABILITY_LINK))\n"
"{\n"
"for my $strTarget ($oBackupManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"if ($oBackupManifest->isTargetTablespace($strTarget))\n"
"{\n"
"storageRepo()->linkCreate(\n"
"STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strTarget}\",\n"
"STORAGE_REPO_BACKUP . \"/${strBackupLabel}/\" . MANIFEST_TARGET_PGDATA . \"/${strTarget}\",\n"
"{bRelative => true});\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"my $hStartLsnParam =\n"
"{\n"
"iWalId => defined($strLsnStart) ? hex((split('/', $strLsnStart))[0]) : 0xFFFF,\n"
"iWalOffset => defined($strLsnStart) ? hex((split('/', $strLsnStart))[1]) : 0xFFFF,\n"
"};\n"
"\n\n"
"foreach my $strRepoFile (\n"
"sort {sprintf(\"%016d-%s\", $oBackupManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $b, MANIFEST_SUBKEY_SIZE), $b) cmp\n"
"sprintf(\"%016d-%s\", $oBackupManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $a, MANIFEST_SUBKEY_SIZE), $a)}\n"
"($oBackupManifest->keys(MANIFEST_SECTION_TARGET_FILE, INI_SORT_NONE)))\n"
"{\n"
"\n\n"
"my $strReference = $oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REFERENCE, false);\n"
"\n"
"if (defined($strReference))\n"
"{\n"
"\n\n"
"if (!cfgOption(CFGOPT_DELTA) ||\n"
"$oBackupManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE) == 0)\n"
"{\n"
"\n"
"next;\n"
"}\n"
"}\n"
"\n\n"
"my $strQueueKey = MANIFEST_TARGET_PGDATA;\n"
"\n\n"
"if (index($strRepoFile, DB_PATH_PGTBLSPC . '/') == 0)\n"
"{\n"
"$strQueueKey = DB_PATH_PGTBLSPC . '/' . (split('\\/', $strRepoFile))[1];\n"
"}\n"
"\n\n"
"my $bIgnoreMissing = true;\n"
"my $strDbFile = $oBackupManifest->dbPathGet($strDbCopyPath, $strRepoFile);\n"
"my $iHostConfigIdx = $self->{iCopyRemoteIdx};\n"
"\n\n"
"if ($oBackupManifest->boolGet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_MASTER))\n"
"{\n"
"$strDbFile = $oBackupManifest->dbPathGet($strDbMasterPath, $strRepoFile);\n"
"$iHostConfigIdx = $self->{iMasterRemoteIdx};\n"
"}\n"
"\n\n"
"if ($strRepoFile eq MANIFEST_TARGET_PGDATA . '/' . DB_FILE_PGCONTROL)\n"
"{\n"
"$bIgnoreMissing = false;\n"
"}\n"
"\n\n"
"my $lSize = $oBackupManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE);\n"
"\n"
"$lFileTotal++;\n"
"$lSizeTotal += $lSize;\n"
"\n\n"
"$oBackupProcess->queueJob(\n"
"$iHostConfigIdx, $strQueueKey, $strRepoFile, OP_BACKUP_FILE,\n"
"[$strDbFile, $strRepoFile, $lSize,\n"
"$oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM, false),\n"
"cfgOption(CFGOPT_CHECKSUM_PAGE) ? isChecksumPage($strRepoFile) : false, $strBackupLabel, $bCompress,\n"
"cfgOption(CFGOPT_COMPRESS_LEVEL), $oBackupManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile,\n"
"MANIFEST_SUBKEY_TIMESTAMP, false), $bIgnoreMissing,\n"
"cfgOption(CFGOPT_CHECKSUM_PAGE) && isChecksumPage($strRepoFile) ? $hStartLsnParam : undef,\n"
"cfgOption(CFGOPT_DELTA), defined($strReference) ? true : false],\n"
"{rParamSecure => $oBackupManifest->cipherPassSub() ? [$oBackupManifest->cipherPassSub()] : undef});\n"
"\n\n"
"$oBackupManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE);\n"
"$oBackupManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM);\n"
"}\n"
"\n\n"
"if (!$oBackupManifest->test(MANIFEST_SECTION_TARGET_FILE, MANIFEST_FILE_PGCONTROL) && cfgOption(CFGOPT_ONLINE))\n"
"{\n"
"confess &log(ERROR, DB_FILE_PGCONTROL . \" must be present in all online backups\\n\" .\n"
"'HINT: is something wrong with the clock or filesystem timestamps?', ERROR_FILE_MISSING);\n"
"}\n"
"\n\n\n"
"if ($lFileTotal == 0 && !cfgOption(CFGOPT_TEST))\n"
"{\n"
"confess &log(ERROR, \"no files have changed since the last backup - this seems unlikely\", ERROR_FILE_MISSING);\n"
"}\n"
"\n\n"
"my $lSizeCurrent = 0;\n"
"\n\n"
"my $lManifestSaveCurrent = 0;\n"
"my $lManifestSaveSize = int($lSizeTotal / 100);\n"
"\n"
"if (cfgOptionSource(CFGOPT_MANIFEST_SAVE_THRESHOLD) ne CFGDEF_SOURCE_DEFAULT ||\n"
"$lManifestSaveSize < cfgOption(CFGOPT_MANIFEST_SAVE_THRESHOLD))\n"
"{\n"
"$lManifestSaveSize = cfgOption(CFGOPT_MANIFEST_SAVE_THRESHOLD);\n"
"}\n"
"\n\n"
"while (my $hyJob = $oBackupProcess->process())\n"
"{\n"
"foreach my $hJob (@{$hyJob})\n"
"{\n"
"($lSizeCurrent, $lManifestSaveCurrent) = backupManifestUpdate(\n"
"$oBackupManifest, cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $hJob->{iHostConfigIdx}), false),\n"
"$hJob->{iProcessId}, @{$hJob->{rParam}}[0..4], @{$hJob->{rResult}}, $lSizeTotal, $lSizeCurrent, $lManifestSaveSize,\n"
"$lManifestSaveCurrent);\n"
"}\n"
"\n\n\n"
"protocolKeepAlive();\n"
"}\n"
"\n"
"foreach my $strFile ($oBackupManifest->keys(MANIFEST_SECTION_TARGET_FILE))\n"
"{\n"
"\n\n"
"my $strReference = $oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_REFERENCE, false);\n"
"\n"
"if ($strReference)\n"
"{\n"
"\n"
"if ($bHardLink)\n"
"{\n"
"&log(DETAIL, \"hardlink ${strFile} to ${strReference}\");\n"
"\n"
"storageRepo()->linkCreate(\n"
"STORAGE_REPO_BACKUP . \"/${strReference}/${strFile}\" . ($bCompress ? qw{.} . COMPRESS_EXT : ''),\n"
"STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strFile}\" . ($bCompress ? qw{.} . COMPRESS_EXT : ''),\n"
"{bHard => true});\n"
"}\n"
"\n\n"
"else\n"
"{\n"
"logDebugMisc($strOperation, \"reference ${strFile} to ${strReference}\");\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"$oBackupManifest->validate();\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'lSizeTotal', value => $lSizeTotal}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');\n"
"\n\n"
"my $lTimestampStart = time();\n"
"\n\n"
"my $oStorageRepo = storageRepo();\n"
"\n\n"
"my $strType = cfgOption(CFGOPT_TYPE);\n"
"my $bCompress = cfgOption(CFGOPT_COMPRESS);\n"
"my $bHardLink = cfgOption(CFGOPT_REPO_HARDLINK);\n"
"\n\n"
"my $oBackupInfo = new pgBackRest::Backup::Info($oStorageRepo->pathGet(STORAGE_REPO_BACKUP));\n"
"\n\n"
"my $strCipherPassManifest = $oBackupInfo->cipherPassSub();\n"
"my $strCipherPassBackupSet;\n"
"\n\n"
"my $oDbMaster = undef;\n"
"my $oDbStandby = undef;\n"
"\n\n"
"($oDbMaster, $self->{iMasterRemoteIdx}, $oDbStandby, $self->{iCopyRemoteIdx}) = dbObjectGet();\n"
"\n\n"
"if (!defined($self->{iCopyRemoteIdx}))\n"
"{\n"
"$self->{iCopyRemoteIdx} = $self->{iMasterRemoteIdx};\n"
"}\n"
"\n\n\n"
"if (!defined($oDbStandby) && cfgOption(CFGOPT_BACKUP_STANDBY))\n"
"{\n"
"cfgOptionSet(CFGOPT_BACKUP_STANDBY, false);\n"
"&log(WARN, 'option backup-standby is enabled but standby is not properly configured - ' .\n"
"'backups will be performed from the master');\n"
"}\n"
"\n\n"
"my $oStorageDbMaster = storageDb({iRemoteIdx => $self->{iMasterRemoteIdx}});\n"
"\n\n"
"my $strDbMasterPath = cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $self->{iMasterRemoteIdx}));\n"
"my $strDbCopyPath = cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $self->{iCopyRemoteIdx}));\n"
"\n\n"
"my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = $oDbMaster->info();\n"
"\n"
"my $iDbHistoryId = $oBackupInfo->check($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);\n"
"\n\n"
"my $oLastManifest;\n"
"my $strBackupLastPath;\n"
"my $strTimelineLast;\n"
"\n"
"if ($strType ne CFGOPTVAL_BACKUP_TYPE_FULL)\n"
"{\n"
"$strBackupLastPath = $oBackupInfo->last(\n"
"$strType eq CFGOPTVAL_BACKUP_TYPE_DIFF ? CFGOPTVAL_BACKUP_TYPE_FULL : CFGOPTVAL_BACKUP_TYPE_INCR);\n"
"\n\n"
"if (defined($strBackupLastPath) && $oBackupInfo->confirmDb($strBackupLastPath, $strDbVersion, $ullDbSysId))\n"
"{\n"
"$oLastManifest = new pgBackRest::Manifest(\n"
"$oStorageRepo->pathGet(STORAGE_REPO_BACKUP . \"/${strBackupLastPath}/\" . FILE_MANIFEST),\n"
"{strCipherPass => $strCipherPassManifest});\n"
"\n\n"
"$strCipherPassBackupSet = $oLastManifest->cipherPassSub();\n"
"\n\n"
"if ($oLastManifest->test(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP))\n"
"{\n"
"$strTimelineLast = substr($oLastManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP), 0, 8);\n"
"}\n"
"\n"
"&log(INFO, 'last backup label = ' . $oLastManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL) .\n"
"', version = ' . $oLastManifest->get(INI_SECTION_BACKREST, INI_KEY_VERSION));\n"
"\n\n"
"my $strKey;\n"
"\n\n"
"if (!$oLastManifest->boolTest(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef, $bCompress))\n"
"{\n"
"&log(WARN, \"${strType} backup cannot alter compress option to '\" . boolFormat($bCompress) .\n"
"\"', reset to value in ${strBackupLastPath}\");\n"
"$bCompress = $oLastManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS);\n"
"}\n"
"\n\n"
"if (!$oLastManifest->boolTest(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK, undef, $bHardLink))\n"
"{\n"
"&log(WARN, \"${strType} backup cannot alter hardlink option to '\" . boolFormat($bHardLink) .\n"
"\"', reset to value in ${strBackupLastPath}\");\n"
"$bHardLink = $oLastManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK);\n"
"}\n"
"}\n"
"else\n"
"{\n"
"&log(WARN, \"no prior backup exists, ${strType} backup has been changed to full\");\n"
"$strType = CFGOPTVAL_BACKUP_TYPE_FULL;\n"
"$strBackupLastPath = undef;\n"
"}\n"
"}\n"
"\n\n"
"my $strBackupLabel;\n"
"my $oAbortedManifest;\n"
"my $strBackupPath;\n"
"my $strTimelineAborted;\n"
"\n"
"foreach my $strAbortedBackup ($oStorageRepo->list(\n"
"STORAGE_REPO_BACKUP, {strExpression => backupRegExpGet(true, true, true), strSortOrder => 'reverse'}))\n"
"{\n"
"\n"
"if ($oStorageRepo->exists(STORAGE_REPO_BACKUP . \"/${strAbortedBackup}/\" . FILE_MANIFEST_COPY) &&\n"
"!$oStorageRepo->exists(STORAGE_REPO_BACKUP . \"/${strAbortedBackup}/\" . FILE_MANIFEST))\n"
"{\n"
"my $bUsable;\n"
"my $strReason = \"resume is disabled\";\n"
"$strBackupPath = $oStorageRepo->pathGet(STORAGE_REPO_BACKUP . \"/${strAbortedBackup}\");\n"
"\n\n\n"
"if (cfgOption(CFGOPT_RESUME))\n"
"{\n"
"$strReason = \"unable to read ${strBackupPath}/\" . FILE_MANIFEST;\n"
"\n"
"eval\n"
"{\n"
"\n"
"$oAbortedManifest = new pgBackRest::Manifest(\"${strBackupPath}/\" . FILE_MANIFEST,\n"
"{strCipherPass => $strCipherPassManifest});\n"
"\n\n"
"my $strKey;\n"
"my $strValueNew;\n"
"my $strValueAborted;\n"
"\n\n"
"if ($oAbortedManifest->get(INI_SECTION_BACKREST, INI_KEY_VERSION) ne PROJECT_VERSION)\n"
"{\n"
"$strKey = INI_KEY_VERSION;\n"
"$strValueNew = PROJECT_VERSION;\n"
"$strValueAborted = $oAbortedManifest->get(INI_SECTION_BACKREST, INI_KEY_VERSION);\n"
"}\n"
"\n"
"elsif ($oAbortedManifest->get(INI_SECTION_BACKREST, INI_KEY_FORMAT) ne REPOSITORY_FORMAT)\n"
"{\n"
"$strKey = INI_KEY_FORMAT;\n"
"$strValueNew = REPOSITORY_FORMAT;\n"
"$strValueAborted = $oAbortedManifest->get(INI_SECTION_BACKREST, INI_KEY_FORMAT);\n"
"}\n"
"\n"
"elsif ($oAbortedManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE) ne $strType)\n"
"{\n"
"$strKey = MANIFEST_KEY_TYPE;\n"
"$strValueNew = $strType;\n"
"$strValueAborted = $oAbortedManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE);\n"
"}\n"
"\n"
"elsif ($oAbortedManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_PRIOR, undef, false, '<undef>') ne\n"
"(defined($strBackupLastPath) ? $strBackupLastPath : '<undef>'))\n"
"{\n"
"$strKey = MANIFEST_KEY_PRIOR;\n"
"$strValueNew = defined($strBackupLastPath) ? $strBackupLastPath : '<undef>';\n"
"$strValueAborted =\n"
"$oAbortedManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_PRIOR, undef, false, '<undef>');\n"
"}\n"
"\n"
"elsif ($oAbortedManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS) !=\n"
"cfgOption(CFGOPT_COMPRESS))\n"
"{\n"
"$strKey = MANIFEST_KEY_COMPRESS;\n"
"$strValueNew = cfgOption(CFGOPT_COMPRESS);\n"
"$strValueAborted = $oAbortedManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS);\n"
"}\n"
"\n"
"elsif ($oAbortedManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK) !=\n"
"cfgOption(CFGOPT_REPO_HARDLINK))\n"
"{\n"
"$strKey = MANIFEST_KEY_HARDLINK;\n"
"$strValueNew = cfgOption(CFGOPT_REPO_HARDLINK);\n"
"$strValueAborted = $oAbortedManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK);\n"
"}\n"
"\n\n"
"if (defined($strKey))\n"
"{\n"
"$strReason = \"new ${strKey} '${strValueNew}' does not match aborted ${strKey} '${strValueAborted}'\";\n"
"}\n"
"\n"
"else\n"
"{\n"
"$bUsable = true;\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"$bUsable = false;\n"
"}\n"
"}\n"
"\n\n"
"if ($bUsable)\n"
"{\n"
"$strBackupLabel = $strAbortedBackup;\n"
"\n\n"
"if (defined($strCipherPassManifest))\n"
"{\n"
"$strCipherPassBackupSet = $oAbortedManifest->cipherPassSub();\n"
"}\n"
"\n\n\n"
"if ($oAbortedManifest->test(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP))\n"
"{\n"
"$strTimelineAborted = substr($oAbortedManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP), 0, 8);\n"
"}\n"
"elsif ($oAbortedManifest->test(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_START))\n"
"{\n"
"$strTimelineAborted = substr($oAbortedManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_START), 0, 8);\n"
"}\n"
"}\n"
"else\n"
"{\n"
"&log(WARN, \"aborted backup ${strAbortedBackup} cannot be resumed: ${strReason}\");\n"
"&log(TEST, TEST_BACKUP_NORESUME);\n"
"\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strAbortedBackup}\", {bRecurse => true});\n"
"undef($oAbortedManifest);\n"
"}\n"
"\n"
"last;\n"
"}\n"
"}\n"
"\n\n"
"if (defined($strCipherPassManifest) && !defined($strCipherPassBackupSet) && $strType eq CFGOPTVAL_BACKUP_TYPE_FULL)\n"
"{\n"
"$strCipherPassBackupSet = cipherPassGen();\n"
"}\n"
"\n\n"
"if (!defined($strBackupLabel))\n"
"{\n"
"$strBackupLabel = backupLabel($oStorageRepo, $strType, $strBackupLastPath, $lTimestampStart);\n"
"$strBackupPath = $oStorageRepo->pathGet(STORAGE_REPO_BACKUP . \"/${strBackupLabel}\");\n"
"}\n"
"\n\n\n\n"
"my $oBackupManifest = new pgBackRest::Manifest(\"$strBackupPath/\" . FILE_MANIFEST,\n"
"{bLoad => false, strDbVersion => $strDbVersion, iDbCatalogVersion => $iCatalogVersion,\n"
"strCipherPass => defined($strCipherPassManifest) ? $strCipherPassManifest : undef,\n"
"strCipherPassSub => defined($strCipherPassManifest) ? $strCipherPassBackupSet : undef});\n"
"\n\n"
"$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE, undef, $strType);\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_START, undef, $lTimestampStart);\n"
"$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_BACKUP_STANDBY, undef, cfgOption(CFGOPT_BACKUP_STANDBY));\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_BUFFER_SIZE, undef, cfgOption(CFGOPT_BUFFER_SIZE));\n"
"$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef, $bCompress);\n"
"$oBackupManifest->numericSet(\n"
"MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS_LEVEL, undef, cfgOption(CFGOPT_COMPRESS_LEVEL));\n"
"$oBackupManifest->numericSet(\n"
"MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS_LEVEL_NETWORK, undef, cfgOption(CFGOPT_COMPRESS_LEVEL_NETWORK));\n"
"$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK, undef, $bHardLink);\n"
"$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE, undef, cfgOption(CFGOPT_ONLINE));\n"
"$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_COPY, undef,\n"
"!cfgOption(CFGOPT_ONLINE) ||\n"
"(cfgOption(CFGOPT_ARCHIVE_CHECK) && cfgOption(CFGOPT_ARCHIVE_COPY)));\n"
"$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_CHECK, undef,\n"
"!cfgOption(CFGOPT_ONLINE) || cfgOption(CFGOPT_ARCHIVE_CHECK));\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_PROCESS_MAX, undef, cfgOption(CFGOPT_PROCESS_MAX));\n"
"\n\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID, undef, $iDbHistoryId);\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL, undef, $iControlVersion);\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef, $ullDbSysId);\n"
"\n\n"
"if (cfgOption(CFGOPT_ONLINE) && cfgOption(CFGOPT_BACKUP_STANDBY) && $strDbVersion < PG_VERSION_BACKUP_STANDBY)\n"
"{\n"
"confess &log(ERROR,\n"
"'option \\'' . cfgOptionName(CFGOPT_BACKUP_STANDBY) . '\\' not valid for PostgreSQL < ' . PG_VERSION_BACKUP_STANDBY,\n"
"ERROR_CONFIG);\n"
"}\n"
"\n\n"
"my $strArchiveStart = undef;\n"
"my $strLsnStart = undef;\n"
"my $iWalSegmentSize = undef;\n"
"my $hTablespaceMap = undef;\n"
"my $hDatabaseMap = undef;\n"
"my $strTimelineCurrent = undef;\n"
"\n\n"
"if (!cfgOption(CFGOPT_ONLINE))\n"
"{\n"
"\n\n\n"
"if (!cfgOptionTest(CFGOPT_CHECKSUM_PAGE))\n"
"{\n"
"cfgOptionSet(CFGOPT_CHECKSUM_PAGE, false);\n"
"}\n"
"\n\n"
"if ($oStorageDbMaster->exists($strDbMasterPath . '/' . DB_FILE_POSTMASTERPID))\n"
"{\n"
"if (cfgOption(CFGOPT_FORCE))\n"
"{\n"
"&log(WARN, '--no-online passed and ' . DB_FILE_POSTMASTERPID . ' exists but --force was passed so backup will ' .\n"
"'continue though it looks like the postmaster is running and the backup will probably not be ' .\n"
"'consistent');\n"
"}\n"
"else\n"
"{\n"
"confess &log(ERROR, '--no-online passed but ' . DB_FILE_POSTMASTERPID . ' exists - looks like the postmaster is ' .\n"
"'running. Shutdown the postmaster and try again, or use --force.', ERROR_POSTMASTER_RUNNING);\n"
"}\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"($strArchiveStart, $strLsnStart, $iWalSegmentSize) =\n"
"$oDbMaster->backupStart(\n"
"PROJECT_NAME . ' backup started at ' . timestampFormat(undef, $lTimestampStart), cfgOption(CFGOPT_START_FAST));\n"
"\n\n"
"$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_START, undef, $strArchiveStart);\n"
"$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LSN_START, undef, $strLsnStart);\n"
"&log(INFO, \"backup start archive = ${strArchiveStart}, lsn = ${strLsnStart}\");\n"
"\n\n"
"$strTimelineCurrent = substr($strArchiveStart, 0, 8);\n"
"\n\n"
"$hTablespaceMap = $oDbMaster->tablespaceMapGet();\n"
"\n\n"
"$hDatabaseMap = $oDbMaster->databaseMapGet();\n"
"\n\n"
"if (cfgOption(CFGOPT_BACKUP_STANDBY))\n"
"{\n"
"my ($strStandbyDbVersion, $iStandbyControlVersion, $iStandbyCatalogVersion, $ullStandbyDbSysId) = $oDbStandby->info();\n"
"$oBackupInfo->check($strStandbyDbVersion, $iStandbyControlVersion, $iStandbyCatalogVersion, $ullStandbyDbSysId);\n"
"\n"
"$oDbStandby->configValidate();\n"
"\n"
"&log(INFO, \"wait for replay on the standby to reach ${strLsnStart}\");\n"
"\n"
"my ($strReplayedLSN, $strCheckpointLSN) = $oDbStandby->replayWait($strLsnStart);\n"
"\n"
"&log(\n"
"INFO,\n"
"\"replay on the standby reached ${strReplayedLSN}\" .\n"
"(defined($strCheckpointLSN) ? \", checkpoint ${strCheckpointLSN}\" : ''));\n"
"\n\n"
"undef($oDbStandby);\n"
"protocolDestroy(CFGOPTVAL_REMOTE_TYPE_DB, $self->{iCopyRemoteIdx}, true);\n"
"}\n"
"}\n"
"\n\n\n"
"if ($strType ne CFGOPTVAL_BACKUP_TYPE_FULL && defined($strBackupLastPath))\n"
"{\n"
"\n\n"
"if (!$oLastManifest->test(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_CHECKSUM_PAGE))\n"
"{\n"
"cfgOptionSet(CFGOPT_CHECKSUM_PAGE, false);\n"
"}\n"
"else\n"
"{\n"
"my $bChecksumPageLast =\n"
"$oLastManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_CHECKSUM_PAGE);\n"
"\n"
"if ($bChecksumPageLast != cfgOption(CFGOPT_CHECKSUM_PAGE))\n"
"{\n"
"&log(WARN,\n"
"\"${strType} backup cannot alter '\" . cfgOptionName(CFGOPT_CHECKSUM_PAGE) . \"' option to '\" .\n"
"boolFormat(cfgOption(CFGOPT_CHECKSUM_PAGE)) . \"', reset to '\" . boolFormat($bChecksumPageLast) .\n"
"\"' from ${strBackupLastPath}\");\n"
"cfgOptionSet(CFGOPT_CHECKSUM_PAGE, $bChecksumPageLast);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_CHECKSUM_PAGE, undef, cfgOption(CFGOPT_CHECKSUM_PAGE));\n"
"\n\n"
"cfgOptionSet(CFGOPT_DELTA, $oBackupManifest->build(\n"
"$oStorageDbMaster, $strDbMasterPath, $oLastManifest, cfgOption(CFGOPT_ONLINE), cfgOption(CFGOPT_DELTA), $hTablespaceMap,\n"
"$hDatabaseMap, cfgOption(CFGOPT_EXCLUDE, false), $strTimelineCurrent, $strTimelineLast));\n"
"\n"
"&log(TEST, TEST_MANIFEST_BUILD);\n"
"\n\n"
"if (defined($oAbortedManifest))\n"
"{\n"
"&log(WARN, \"aborted backup ${strBackupLabel} of same type exists, will be cleaned to remove invalid files and resumed\");\n"
"&log(TEST, TEST_BACKUP_RESUME);\n"
"\n\n\n"
"cfgOptionSet(CFGOPT_DELTA, $self->resumeClean($oStorageRepo, $strBackupLabel, $oBackupManifest, $oAbortedManifest,\n"
"cfgOption(CFGOPT_ONLINE), cfgOption(CFGOPT_DELTA), $strTimelineCurrent, $strTimelineAborted));\n"
"}\n"
"\n"
"else\n"
"{\n"
"logDebugMisc($strOperation, \"create backup path ${strBackupPath}\");\n"
"$oStorageRepo->pathCreate(STORAGE_REPO_BACKUP . \"/${strBackupLabel}\");\n"
"}\n"
"\n\n"
"$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_DELTA, undef, cfgOption(CFGOPT_DELTA));\n"
"\n\n"
"$oBackupManifest->saveCopy();\n"
"\n\n"
"my $lBackupSizeTotal =\n"
"$self->processManifest(\n"
"$strDbMasterPath, $strDbCopyPath, $strType, $strDbVersion, $bCompress, $bHardLink, $oBackupManifest, $strBackupLabel,\n"
"$strLsnStart);\n"
"&log(INFO, \"${strType} backup size = \" . fileSizeFormat($lBackupSizeTotal));\n"
"\n\n"
"undef($oStorageDbMaster);\n"
"\n\n"
"my $strArchiveStop = undef;\n"
"my $strLsnStop = undef;\n"
"\n"
"if (cfgOption(CFGOPT_ONLINE))\n"
"{\n"
"($strArchiveStop, $strLsnStop, my $strTimestampDbStop, my $oFileHash) = $oDbMaster->backupStop();\n"
"\n"
"$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP, undef, $strArchiveStop);\n"
"$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LSN_STOP, undef, $strLsnStop);\n"
"&log(INFO, \"backup stop archive = ${strArchiveStop}, lsn = ${strLsnStop}\");\n"
"\n\n"
"foreach my $strFile (sort(keys(%{$oFileHash})))\n"
"{\n"
"\n"
"if (defined($oFileHash->{$strFile}))\n"
"{\n"
"my $rhyFilter = [{strClass => STORAGE_FILTER_SHA}];\n"
"\n\n"
"if ($bCompress)\n"
"{\n"
"push(@{$rhyFilter}, {strClass => STORAGE_FILTER_GZIP});\n"
"}\n"
"\n\n\n"
"my $oDestinationFileIo = $oStorageRepo->openWrite(\n"
"STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strFile}\" . ($bCompress ? qw{.} . COMPRESS_EXT : ''),\n"
"{rhyFilter => $rhyFilter,\n"
"strCipherPass => defined($strCipherPassBackupSet) ? $strCipherPassBackupSet : undef});\n"
"\n\n"
"$oStorageRepo->put($oDestinationFileIo, $oFileHash->{$strFile});\n"
"\n\n"
"$oBackupManifest->fileAdd(\n"
"$strFile, time(), length($oFileHash->{$strFile}), $oDestinationFileIo->result(STORAGE_FILTER_SHA), true);\n"
"\n"
"&log(DETAIL, \"wrote '${strFile}' file returned from pg_stop_backup()\");\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"&log(TEST, TEST_BACKUP_STOP);\n"
"\n"
"undef($oDbMaster);\n"
"protocolDestroy(undef, undef, true);\n"
"\n\n\n\n"
"if (cfgOption(CFGOPT_ONLINE) && cfgOption(CFGOPT_ARCHIVE_CHECK))\n"
"{\n"
"\n"
"$oBackupManifest->saveCopy();\n"
"\n\n"
"my $lModificationTime = time();\n"
"\n\n"
"logDebugMisc($strOperation, \"retrieve archive logs ${strArchiveStart}:${strArchiveStop}\");\n"
"\n"
"my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE), true);\n"
"my $strArchiveId = $oArchiveInfo->archiveId();\n"
"my @stryArchive = lsnFileRange($strLsnStart, $strLsnStop, $strDbVersion, $iWalSegmentSize);\n"
"\n"
"foreach my $strArchive (@stryArchive)\n"
"{\n"
"my $strArchiveFile = walSegmentFind(\n"
"$oStorageRepo, $strArchiveId, substr($strArchiveStop, 0, 8) . $strArchive, cfgOption(CFGOPT_ARCHIVE_TIMEOUT));\n"
"\n"
"$strArchive = substr($strArchiveFile, 0, 24);\n"
"\n"
"if (cfgOption(CFGOPT_ARCHIVE_COPY))\n"
"{\n"
"logDebugMisc($strOperation, \"archive: ${strArchive} (${strArchiveFile})\");\n"
"\n\n"
"my $bArchiveCompressed = $strArchiveFile =~ ('^.*\\.' . COMPRESS_EXT . '\\$');\n"
"\n"
"$oStorageRepo->copy(\n"
"$oStorageRepo->openRead(STORAGE_REPO_ARCHIVE . \"/${strArchiveId}/${strArchiveFile}\",\n"
"{strCipherPass => $oArchiveInfo->cipherPassSub()}),\n"
"$oStorageRepo->openWrite(STORAGE_REPO_BACKUP . \"/${strBackupLabel}/\" . MANIFEST_TARGET_PGDATA . qw{/} .\n"
"$oBackupManifest->walPath() . \"/${strArchive}\" . ($bCompress ? qw{.} . COMPRESS_EXT : ''),\n"
"{bPathCreate => true, strCipherPass => $strCipherPassBackupSet})\n"
");\n"
"\n\n"
"my $strPathLog = MANIFEST_TARGET_PGDATA . qw{/} . $oBackupManifest->walPath();\n"
"my $strFileLog = \"${strPathLog}/${strArchive}\";\n"
"\n\n"
"$oBackupManifest->fileAdd(\n"
"$strFileLog, $lModificationTime, PG_WAL_SEGMENT_SIZE, substr($strArchiveFile, 25, 40), true);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"my $lTimestampStop = time();\n"
"$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_STOP, undef, $lTimestampStop + 0);\n"
"$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL, undef, $strBackupLabel);\n"
"\n\n"
"if ($oStorageRepo->driver()->capability(STORAGE_CAPABILITY_PATH_SYNC))\n"
"{\n"
"\n"
"$oStorageRepo->pathSync(STORAGE_REPO_BACKUP . \"/${strBackupLabel}\");\n"
"\n"
"foreach my $strPath ($oBackupManifest->keys(MANIFEST_SECTION_TARGET_PATH))\n"
"{\n"
"my $strPathSync = $oStorageRepo->pathGet(STORAGE_REPO_BACKUP . \"/${strBackupLabel}/$strPath\");\n"
"\n\n"
"if ($strType eq CFGOPTVAL_BACKUP_TYPE_FULL || $oStorageRepo->pathExists($strPathSync))\n"
"{\n"
"$oStorageRepo->pathSync($strPathSync);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"$oBackupManifest->save();\n"
"\n"
"&log(INFO, \"new backup label = ${strBackupLabel}\");\n"
"\n\n\n"
"my $strHistoryPath = $oStorageRepo->pathGet(\n"
"STORAGE_REPO_BACKUP . qw{/} . PATH_BACKUP_HISTORY . qw{/} . substr($strBackupLabel, 0, 4));\n"
"\n"
"$oStorageRepo->copy(\n"
"$oStorageRepo->openRead(STORAGE_REPO_BACKUP . \"/${strBackupLabel}/\" . FILE_MANIFEST,\n"
"{'strCipherPass' => $strCipherPassManifest}),\n"
"$oStorageRepo->openWrite(\n"
"\"${strHistoryPath}/${strBackupLabel}.manifest.\" . COMPRESS_EXT,\n"
"{rhyFilter => [{strClass => STORAGE_FILTER_GZIP}],\n"
"bPathCreate => true, bAtomic => true,\n"
"strCipherPass => defined($strCipherPassManifest) ? $strCipherPassManifest : undef}));\n"
"\n\n"
"if ($oStorageRepo->driver()->capability(STORAGE_CAPABILITY_PATH_SYNC))\n"
"{\n"
"$oStorageRepo->pathSync(STORAGE_REPO_BACKUP . qw{/} . PATH_BACKUP_HISTORY);\n"
"$oStorageRepo->pathSync($strHistoryPath);\n"
"}\n"
"\n\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . qw(/) . LINK_LATEST);\n"
"\n"
"if (storageRepo()->driver()->capability(STORAGE_CAPABILITY_LINK))\n"
"{\n"
"$oStorageRepo->linkCreate(\n"
"STORAGE_REPO_BACKUP . \"/${strBackupLabel}\", STORAGE_REPO_BACKUP . qw{/} . LINK_LATEST, {bRelative => true});\n"
"}\n"
"\n\n"
"$oBackupInfo->add($oBackupManifest);\n"
"\n\n"
"if ($oStorageRepo->driver()->capability(STORAGE_CAPABILITY_PATH_SYNC))\n"
"{\n"
"$oStorageRepo->pathSync(STORAGE_REPO_BACKUP);\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Backup/Common.pm",
.data =
"\n\n\n"
"package pgBackRest::Backup::Common;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename;\n"
"\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Helper;\n"
"use pgBackRest::Manifest;\n"
"\n\n\n\n"
"use constant LINK_LATEST => 'latest';\n"
"push @EXPORT, qw(LINK_LATEST);\n"
"\n\n\n\n\n\n"
"sub backupRegExpGet\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bFull,\n"
"$bDifferential,\n"
"$bIncremental,\n"
"$bAnchor\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::backupRegExpGet', \\@_,\n"
"{name => 'bFull', default => false},\n"
"{name => 'bDifferential', default => false},\n"
"{name => 'bIncremental', default => false},\n"
"{name => 'bAnchor', default => true}\n"
");\n"
"\n\n"
"if (!($bFull || $bDifferential || $bIncremental))\n"
"{\n"
"confess &log(ASSERT, 'at least one backup type must be selected');\n"
"}\n"
"\n\n"
"my $strDateTimeRegExp = \"[0-9]{8}\\\\-[0-9]{6}\";\n"
"\n"
"my $strRegExp = ($bAnchor ? '^' : '') . $strDateTimeRegExp . 'F';\n"
"\n\n"
"if ($bDifferential || $bIncremental)\n"
"{\n"
"\n"
"if ($bFull)\n"
"{\n"
"$strRegExp .= \"(\\\\_\";\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strRegExp .= \"\\\\_\";\n"
"}\n"
"\n\n"
"$strRegExp .= $strDateTimeRegExp;\n"
"\n\n"
"if ($bDifferential && $bIncremental)\n"
"{\n"
"$strRegExp .= '(D|I)';\n"
"}\n"
"\n"
"elsif ($bDifferential)\n"
"{\n"
"$strRegExp .= 'D';\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strRegExp .= 'I';\n"
"}\n"
"\n\n"
"if ($bFull)\n"
"{\n"
"$strRegExp .= '){0,1}';\n"
"}\n"
"}\n"
"\n\n"
"$strRegExp .= $bAnchor ? \"\\$\" : '';\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strRegExp', value => $strRegExp}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(backupRegExpGet);\n"
"\n\n\n\n\n\n"
"sub backupLabelFormat\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strType,\n"
"$strBackupLabelLast,\n"
"$lTimestampStart\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::backupLabelFormat', \\@_,\n"
"{name => 'strType', trace => true},\n"
"{name => 'strBackupLabelLast', required => false, trace => true},\n"
"{name => 'lTimestampTart', trace => true}\n"
");\n"
"\n\n"
"my $strBackupLabel;\n"
"\n"
"if ($strType eq CFGOPTVAL_BACKUP_TYPE_FULL)\n"
"{\n"
"\n"
"if (defined($strBackupLabelLast))\n"
"{\n"
"confess &log(ASSERT, \"strBackupLabelLast must not be defined when strType = '${strType}'\");\n"
"}\n"
"\n\n"
"$strBackupLabel = timestampFileFormat(undef, $lTimestampStart) . 'F';\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if (!defined($strBackupLabelLast))\n"
"{\n"
"confess &log(ASSERT, \"strBackupLabelLast must be defined when strType = '${strType}'\");\n"
"}\n"
"\n\n"
"$strBackupLabel = substr($strBackupLabelLast, 0, 16);\n"
"\n\n"
"$strBackupLabel .= '_' . timestampFileFormat(undef, $lTimestampStart);\n"
"\n\n"
"if ($strType eq CFGOPTVAL_BACKUP_TYPE_DIFF)\n"
"{\n"
"$strBackupLabel .= 'D';\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strBackupLabel .= 'I';\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strBackupLabel', value => $strBackupLabel, trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(backupLabelFormat);\n"
"\n\n\n\n\n\n"
"sub backupLabel\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oStorageRepo,\n"
"$strType,\n"
"$strBackupLabelLast,\n"
"$lTimestampStart\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::backupLabelFormat', \\@_,\n"
"{name => 'oStorageRepo', trace => true},\n"
"{name => 'strType', trace => true},\n"
"{name => 'strBackupLabelLast', required => false, trace => true},\n"
"{name => 'lTimestampStart', trace => true}\n"
");\n"
"\n\n"
"my $strBackupLabel = backupLabelFormat($strType, $strBackupLabelLast, $lTimestampStart);\n"
"\n\n\n\n\n"
"if ($oStorageRepo->list(\n"
"STORAGE_REPO_BACKUP,\n"
"{strExpression =>\n"
"($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStart) .\n"
"($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? 'F' : '(D|I)$')}) ||\n"
"$oStorageRepo->list(\n"
"STORAGE_REPO_BACKUP . qw{/} . PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTimestampStart),\n"
"{strExpression =>\n"
"($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStart) .\n"
"($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? 'F' : '(D|I)\\.manifest\\.' . COMPRESS_EXT . qw{$}),\n"
"bIgnoreMissing => true}))\n"
"{\n"
"waitRemainder();\n"
"$strBackupLabel = backupLabelFormat($strType, $strBackupLabelLast, time());\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strBackupLabel', value => $strBackupLabel, trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(backupLabel);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Backup/File.pm",
.data =
"\n\n\n"
"package pgBackRest::Backup::File;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname);\n"
"use Storable qw(dclone);\n"
"\n"
"use pgBackRest::Backup::Filter::PageChecksum;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Handle;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Filter::Gzip;\n"
"use pgBackRest::Storage::Filter::Sha;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n"
"use constant BACKUP_FILE_CHECKSUM => 0;\n"
"push @EXPORT, qw(BACKUP_FILE_CHECKSUM);\n"
"use constant BACKUP_FILE_COPY => 1;\n"
"push @EXPORT, qw(BACKUP_FILE_COPY);\n"
"use constant BACKUP_FILE_RECOPY => 2;\n"
"push @EXPORT, qw(BACKUP_FILE_RECOPY);\n"
"use constant BACKUP_FILE_SKIP => 3;\n"
"push @EXPORT, qw(BACKUP_FILE_SKIP);\n"
"use constant BACKUP_FILE_NOOP => 4;\n"
"push @EXPORT, qw(BACKUP_FILE_NOOP);\n"
"\n\n\n\n"
"sub backupFile\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbFile,\n"
"$strRepoFile,\n"
"$lSizeFile,\n"
"$strChecksum,\n"
"$bChecksumPage,\n"
"$strBackupLabel,\n"
"$bCompress,\n"
"$iCompressLevel,\n"
"$lModificationTime,\n"
"$bIgnoreMissing,\n"
"$hExtraParam,\n"
"$bDelta,\n"
"$bHasReference,\n"
"$strCipherPass,\n"
"\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::backupFile', \\@_,\n"
"{name => 'strDbFile', trace => true},\n"
"{name => 'strRepoFile', trace => true},\n"
"{name => 'lSizeFile', trace => true},\n"
"{name => 'strChecksum', required => false, trace => true},\n"
"{name => 'bChecksumPage', trace => true},\n"
"{name => 'strBackupLabel', trace => true},\n"
"{name => 'bCompress', trace => true},\n"
"{name => 'iCompressLevel', trace => true},\n"
"{name => 'lModificationTime', trace => true},\n"
"{name => 'bIgnoreMissing', default => true, trace => true},\n"
"{name => 'hExtraParam', required => false, trace => true},\n"
"{name => 'bDelta', trace => true},\n"
"{name => 'bHasReference', trace => true},\n"
"{name => 'strCipherPass', required => false, trace => true},\n"
");\n"
"\n"
"my $oStorageRepo = storageRepo();\n"
"my $iCopyResult = BACKUP_FILE_COPY;\n"
"my $strCopyChecksum;\n"
"my $rExtra;\n"
"my $lCopySize;\n"
"my $lRepoSize;\n"
"\n\n"
"my $strFileOp = $strRepoFile . ($bCompress ? '.' . COMPRESS_EXT : '');\n"
"\n"
"my $bCopy = true;\n"
"\n\n\n"
"if (defined($strChecksum))\n"
"{\n"
"\n"
"if ($bDelta)\n"
"{\n"
"($strCopyChecksum, $lCopySize) = storageDb()->hashSize($strDbFile, {bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n"
"if (defined($strCopyChecksum))\n"
"{\n"
"$bCopy = !($strCopyChecksum eq $strChecksum && $lCopySize == $lSizeFile);\n"
"\n\n\n\n"
"if (!$bCopy && $bHasReference)\n"
"{\n"
"$iCopyResult = BACKUP_FILE_NOOP;\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"$iCopyResult = BACKUP_FILE_SKIP;\n"
"$bCopy = false;\n"
"}\n"
"}\n"
"\n\n\n\n"
"if (!$bDelta || !$bHasReference)\n"
"{\n"
"\n\n"
"if ($iCopyResult == BACKUP_FILE_SKIP)\n"
"{\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strFileOp}\");\n"
"}\n"
"elsif (!$bDelta || !$bCopy)\n"
"{\n"
"\n"
"my $rhyFilter;\n"
"\n"
"if ($bCompress)\n"
"{\n"
"push(@{$rhyFilter}, {strClass => STORAGE_FILTER_GZIP, rxyParam => [{strCompressType => STORAGE_DECOMPRESS}]});\n"
"}\n"
"\n\n"
"($strCopyChecksum, $lCopySize) = $oStorageRepo->hashSize(\n"
"$oStorageRepo->openRead(STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strFileOp}\",\n"
"{rhyFilter => $rhyFilter, strCipherPass => $strCipherPass}));\n"
"\n\n"
"$bCopy = !($strCopyChecksum eq $strChecksum && $lCopySize == $lSizeFile);\n"
"\n\n"
"$iCopyResult = $bCopy ? BACKUP_FILE_RECOPY : BACKUP_FILE_CHECKSUM;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if ($bCopy)\n"
"{\n"
"\n"
"my $rhyFilter = [{strClass => STORAGE_FILTER_SHA}];\n"
"\n\n"
"if ($bChecksumPage)\n"
"{\n"
"\n"
"my $iSegmentNo = ($strDbFile =~ /\\.[0-9]+$/) ? substr(($strDbFile =~ m/\\.[0-9]+$/g)[0], 1) + 0 : 0;\n"
"\n"
"push(\n"
"@{$rhyFilter},\n"
"{strClass => BACKUP_FILTER_PAGECHECKSUM,\n"
"rxyParam => [$iSegmentNo, $hExtraParam->{iWalId}, $hExtraParam->{iWalOffset}]});\n"
"};\n"
"\n\n"
"if ($bCompress)\n"
"{\n"
"push(@{$rhyFilter}, {strClass => STORAGE_FILTER_GZIP, rxyParam => [{iLevel => $iCompressLevel}]});\n"
"}\n"
"\n\n"
"my $oSourceFileIo = storageDb()->openRead($strDbFile, {rhyFilter => $rhyFilter, bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n"
"if (defined($oSourceFileIo))\n"
"{\n"
"my $oDestinationFileIo = $oStorageRepo->openWrite(\n"
"STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strFileOp}\",\n"
"{bPathCreate => true, bProtocolCompress => !$bCompress, strCipherPass => $strCipherPass});\n"
"\n\n"
"$oStorageRepo->copy($oSourceFileIo, $oDestinationFileIo);\n"
"\n\n"
"$strCopyChecksum = $oSourceFileIo->result(STORAGE_FILTER_SHA);\n"
"$lCopySize = $oSourceFileIo->result(COMMON_IO_HANDLE);\n"
"$lRepoSize = $oDestinationFileIo->result(COMMON_IO_HANDLE);\n"
"\n"
"if (!defined($lRepoSize))\n"
"{\n"
"confess &log(ERROR, \"REPO_SIZE IS NOT SET\");\n"
"}\n"
"\n\n"
"$rExtra = $bChecksumPage ? $oSourceFileIo->result(BACKUP_FILTER_PAGECHECKSUM) : undef;\n"
"}\n"
"\n"
"else\n"
"{\n"
"$iCopyResult = BACKUP_FILE_SKIP;\n"
"}\n"
"}\n"
"\n\n\n\n\n\n"
"if ((($iCopyResult == BACKUP_FILE_COPY || $iCopyResult == BACKUP_FILE_RECOPY) &&\n"
"$oStorageRepo->driver()->capability(STORAGE_CAPABILITY_SIZE_DIFF)) ||\n"
"$iCopyResult == BACKUP_FILE_CHECKSUM)\n"
"{\n"
"$lRepoSize = ($oStorageRepo->info(STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strFileOp}\"))->size();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iCopyResult', value => $iCopyResult, trace => true},\n"
"{name => 'lCopySize', value => $lCopySize, trace => true},\n"
"{name => 'lRepoSize', value => $lRepoSize, trace => true},\n"
"{name => 'strCopyChecksum', value => $strCopyChecksum, trace => true},\n"
"{name => 'rExtra', value => $rExtra, trace => true},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(backupFile);\n"
"\n\n\n\n"
"sub backupManifestUpdate\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oManifest,\n"
"$strHost,\n"
"$iLocalId,\n"
"$strDbFile,\n"
"$strRepoFile,\n"
"$lSize,\n"
"$strChecksum,\n"
"$bChecksumPage,\n"
"$iCopyResult,\n"
"$lSizeCopy,\n"
"$lSizeRepo,\n"
"$strChecksumCopy,\n"
"$rExtra,\n"
"$lSizeTotal,\n"
"$lSizeCurrent,\n"
"$lManifestSaveSize,\n"
"$lManifestSaveCurrent\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::backupManifestUpdate', \\@_,\n"
"{name => 'oManifest', trace => true},\n"
"{name => 'strHost', required => false, trace => true},\n"
"{name => 'iLocalId', required => false, trace => true},\n"
"\n\n"
"{name => 'strDbFile', trace => true},\n"
"{name => 'strRepoFile', trace => true},\n"
"{name => 'lSize', required => false, trace => true},\n"
"{name => 'strChecksum', required => false, trace => true},\n"
"{name => 'bChecksumPage', trace => true},\n"
"\n\n"
"{name => 'iCopyResult', trace => true},\n"
"{name => 'lSizeCopy', required => false, trace => true},\n"
"{name => 'lSizeRepo', required => false, trace => true},\n"
"{name => 'strChecksumCopy', required => false, trace => true},\n"
"{name => 'rExtra', required => false, trace => true},\n"
"\n\n"
"{name => 'lSizeTotal', trace => true},\n"
"{name => 'lSizeCurrent', trace => true},\n"
"{name => 'lManifestSaveSize', trace => true},\n"
"{name => 'lManifestSaveCurrent', trace => true}\n"
");\n"
"\n\n"
"$lSizeCurrent += $lSize;\n"
"\n\n"
"if ($iCopyResult == BACKUP_FILE_NOOP)\n"
"{\n"
"\n"
"$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE, $lSizeCopy);\n"
"$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksumCopy);\n"
"\n"
"&log(DETAIL,\n"
"'match file from prior backup ' . (defined($strHost) ? \"${strHost}:\" : '') . \"${strDbFile} (\" .\n"
"fileSizeFormat($lSizeCopy) . ', ' . int($lSizeCurrent * 100 / $lSizeTotal) . '%)' .\n"
"($lSizeCopy != 0 ? \" checksum ${strChecksumCopy}\" : ''),\n"
"undef, undef, undef, $iLocalId);\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if ($iCopyResult == BACKUP_FILE_RECOPY)\n"
"{\n"
"&log(\n"
"WARN,\n"
"\"resumed backup file ${strRepoFile} does not have expected checksum ${strChecksum}. The file will be recopied and\" .\n"
"\" backup will continue but this may be an issue unless the resumed backup path in the repository is known to be\" .\n"
"\" corrupted.\\n\" .\n"
"\"NOTE: this does not indicate a problem with the PostgreSQL page checksums.\");\n"
"}\n"
"\n\n"
"if ($iCopyResult == BACKUP_FILE_COPY || $iCopyResult == BACKUP_FILE_RECOPY || $iCopyResult == BACKUP_FILE_CHECKSUM)\n"
"{\n"
"\n"
"&log($iCopyResult == BACKUP_FILE_CHECKSUM ? DETAIL : INFO,\n"
"($iCopyResult == BACKUP_FILE_CHECKSUM ?\n"
"'checksum resumed file ' : 'backup file ' . (defined($strHost) ? \"${strHost}:\" : '')) .\n"
"\"${strDbFile} (\" . fileSizeFormat($lSizeCopy) .\n"
"', ' . int($lSizeCurrent * 100 / $lSizeTotal) . '%)' .\n"
"($lSizeCopy != 0 ? \" checksum ${strChecksumCopy}\" : ''), undef, undef, undef, $iLocalId);\n"
"\n"
"$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE, $lSizeCopy);\n"
"\n"
"if ($lSizeRepo != $lSizeCopy)\n"
"{\n"
"$oManifest->numericSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REPO_SIZE, $lSizeRepo);\n"
"}\n"
"\n"
"if ($lSizeCopy > 0)\n"
"{\n"
"$oManifest->set(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksumCopy);\n"
"}\n"
"\n\n"
"if ($iCopyResult == BACKUP_FILE_COPY || $iCopyResult == BACKUP_FILE_RECOPY)\n"
"{\n"
"$oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REFERENCE);\n"
"}\n"
"\n\n"
"if ($bChecksumPage)\n"
"{\n"
"\n"
"if (defined($rExtra->{bValid}))\n"
"{\n"
"\n"
"$oManifest->boolSet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM_PAGE, $rExtra->{bValid});\n"
"\n\n"
"if (!$rExtra->{bValid})\n"
"{\n"
"\n"
"if ($lSizeCopy % PG_PAGE_SIZE != 0)\n"
"{\n"
"\n"
"if (!defined($rExtra->{bAlign}) || $rExtra->{bAlign})\n"
"{\n"
"confess &log(ASSERT, 'bAlign flag should have been set for misaligned page');\n"
"}\n"
"\n\n"
"&log(WARN,\n"
"'page misalignment in file ' . (defined($strHost) ? \"${strHost}:\" : '') .\n"
"\"${strDbFile}: file size ${lSizeCopy} is not divisible by page size \" . PG_PAGE_SIZE);\n"
"}\n"
"\n"
"else\n"
"{\n"
"$oManifest->set(\n"
"MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR,\n"
"dclone($rExtra->{iyPageError}));\n"
"\n\n"
"my $strPageError;\n"
"my $iPageErrorTotal = 0;\n"
"\n"
"foreach my $iyPage (@{$rExtra->{iyPageError}})\n"
"{\n"
"$strPageError .= (defined($strPageError) ? ', ' : '');\n"
"\n\n"
"if (ref($iyPage))\n"
"{\n"
"$strPageError .= $$iyPage[0] . '-' . $$iyPage[1];\n"
"$iPageErrorTotal += ($$iyPage[1] - $$iyPage[0]) + 1;\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strPageError .= $iyPage;\n"
"$iPageErrorTotal += 1;\n"
"}\n"
"}\n"
"\n\n"
"if ($iPageErrorTotal == 0)\n"
"{\n"
"confess &log(ASSERT, 'page checksum error list should have at least one entry');\n"
"}\n"
"\n\n"
"&log(WARN,\n"
"'invalid page checksum' . ($iPageErrorTotal > 1 ? 's' : '') .\n"
"' found in file ' . (defined($strHost) ? \"${strHost}:\" : '') . \"${strDbFile} at page\" .\n"
"($iPageErrorTotal > 1 ? 's' : '') . \" ${strPageError}\");\n"
"}\n"
"}\n"
"}\n"
"\n"
"elsif (!$oManifest->test(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM_PAGE))\n"
"{\n"
"confess &log(ASSERT, \"${strDbFile} should have calculated page checksums\");\n"
"}\n"
"}\n"
"}\n"
"\n"
"elsif ($iCopyResult == BACKUP_FILE_SKIP)\n"
"{\n"
"&log(DETAIL, 'skip file removed by database ' . (defined($strHost) ? \"${strHost}:\" : '') . $strDbFile);\n"
"$oManifest->remove(MANIFEST_SECTION_TARGET_FILE, $strRepoFile);\n"
"}\n"
"}\n"
"\n\n"
"$lManifestSaveCurrent += $lSize;\n"
"\n"
"if ($lManifestSaveCurrent >= $lManifestSaveSize)\n"
"{\n"
"$oManifest->saveCopy();\n"
"\n"
"logDebugMisc\n"
"(\n"
"$strOperation, 'save manifest',\n"
"{name => 'lManifestSaveSize', value => $lManifestSaveSize},\n"
"{name => 'lManifestSaveCurrent', value => $lManifestSaveCurrent}\n"
");\n"
"\n"
"$lManifestSaveCurrent = 0;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'lSizeCurrent', value => $lSizeCurrent, trace => true},\n"
"{name => 'lManifestSaveCurrent', value => $lManifestSaveCurrent, trace => true},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(backupManifestUpdate);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Backup/Filter/PageChecksum.pm",
.data =
"\n\n\n"
"package pgBackRest::Backup::Filter::PageChecksum;\n"
"use parent 'pgBackRest::Common::Io::Filter';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::DbVersion qw(PG_PAGE_SIZE);\n"
"use pgBackRest::LibC qw(:checksum);\n"
"\n\n\n\n"
"use constant BACKUP_FILTER_PAGECHECKSUM => __PACKAGE__;\n"
"push @EXPORT, qw(BACKUP_FILTER_PAGECHECKSUM);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oParent,\n"
"$iSegmentNo,\n"
"$iWalId,\n"
"$iWalOffset,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oParent', trace => true},\n"
"{name => 'iSegmentNo', trace => true},\n"
"{name => 'iWalId', trace => true},\n"
"{name => 'iWalOffset', trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($oParent);\n"
"bless $self, $class;\n"
"\n\n"
"$self->{iSegmentNo} = $iSegmentNo;\n"
"$self->{iWalId} = $iWalId;\n"
"$self->{iWalOffset} = $iWalOffset;\n"
"\n\n"
"$self->{hResult}{bValid} = true;\n"
"$self->{hResult}{bAlign} = true;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub read\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"my $iSize = shift;\n"
"\n\n"
"my $iActualSize = $self->parent()->read($rtBuffer, $iSize);\n"
"\n\n"
"if ($iActualSize > 0)\n"
"{\n"
"\n"
"if (!$self->{hResult}{bAlign} || ($iActualSize % PG_PAGE_SIZE != 0))\n"
"{\n"
"if (!$self->{hResult}{bAlign})\n"
"{\n"
"confess &log(ASSERT, \"should not be possible to see two misaligned blocks in a row\");\n"
"}\n"
"\n"
"$self->{hResult}{bValid} = false;\n"
"$self->{hResult}{bAlign} = false;\n"
"delete($self->{hResult}{iyPageError});\n"
"}\n"
"else\n"
"{\n"
"\n"
"my $iBlockOffset = int(($self->size() - $iActualSize) / PG_PAGE_SIZE) + ($self->{iSegmentNo} * 131072);\n"
"\n"
"if (!pageChecksumBufferTest(\n"
"$$rtBuffer, $iActualSize, $iBlockOffset, PG_PAGE_SIZE, $self->{iWalId},\n"
"$self->{iWalOffset}))\n"
"{\n"
"$self->{hResult}{bValid} = false;\n"
"\n\n\n"
"for (my $iBlockNo = 0; $iBlockNo < int($iActualSize / PG_PAGE_SIZE); $iBlockNo++)\n"
"{\n"
"my $iBlockNoStart = $iBlockOffset + $iBlockNo;\n"
"\n"
"if (!pageChecksumTest(\n"
"substr($$rtBuffer, $iBlockNo * PG_PAGE_SIZE, PG_PAGE_SIZE), $iBlockNoStart, PG_PAGE_SIZE,\n"
"$self->{iWalId}, $self->{iWalOffset}))\n"
"{\n"
"my $iLastIdx = defined($self->{hResult}{iyPageError}) ? @{$self->{hResult}{iyPageError}} - 1 : 0;\n"
"my $iyLast = defined($self->{hResult}{iyPageError}) ? $self->{hResult}{iyPageError}[$iLastIdx] : undef;\n"
"\n"
"if (!defined($iyLast) || (!ref($iyLast) && $iyLast != $iBlockNoStart - 1) ||\n"
"(ref($iyLast) && $iyLast->[1] != $iBlockNoStart - 1))\n"
"{\n"
"push(@{$self->{hResult}{iyPageError}}, $iBlockNoStart);\n"
"}\n"
"elsif (!ref($iyLast))\n"
"{\n"
"$self->{hResult}{iyPageError}[$iLastIdx] = undef;\n"
"push(@{$self->{hResult}{iyPageError}[$iLastIdx]}, $iyLast);\n"
"push(@{$self->{hResult}{iyPageError}[$iLastIdx]}, $iBlockNoStart);\n"
"}\n"
"else\n"
"{\n"
"$self->{hResult}{iyPageError}[$iLastIdx][1] = $iBlockNoStart;\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return $iActualSize;\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n"
"if (defined($self->{hResult}))\n"
"{\n"
"\n"
"$self->resultSet(BACKUP_FILTER_PAGECHECKSUM, $self->{hResult});\n"
"\n\n"
"undef($self->{hResult});\n"
"\n\n"
"return $self->parent()->close();\n"
"}\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Backup/Info.pm",
.data =
"\n\n\n"
"package pgBackRest::Backup::Info;\n"
"use parent 'pgBackRest::Common::Ini';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname basename);\n"
"use File::stat;\n"
"\n"
"use pgBackRest::Archive::Info;\n"
"use pgBackRest::Backup::Common;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::InfoCommon;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n"
"use constant FILE_BACKUP_INFO => 'backup.info';\n"
"push @EXPORT, qw(FILE_BACKUP_INFO);\n"
"\n\n\n\n"
"use constant INFO_BACKUP_SECTION_BACKUP => MANIFEST_SECTION_BACKUP;\n"
"push @EXPORT, qw(INFO_BACKUP_SECTION_BACKUP);\n"
"use constant INFO_BACKUP_SECTION_BACKUP_CURRENT => INFO_BACKUP_SECTION_BACKUP . ':current';\n"
"push @EXPORT, qw(INFO_BACKUP_SECTION_BACKUP_CURRENT);\n"
"\n"
"use constant INFO_BACKUP_KEY_ARCHIVE_CHECK => MANIFEST_KEY_ARCHIVE_CHECK;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_CHECK);\n"
"use constant INFO_BACKUP_KEY_ARCHIVE_COPY => MANIFEST_KEY_ARCHIVE_COPY;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_COPY);\n"
"use constant INFO_BACKUP_KEY_ARCHIVE_START => MANIFEST_KEY_ARCHIVE_START;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_START);\n"
"use constant INFO_BACKUP_KEY_ARCHIVE_STOP => MANIFEST_KEY_ARCHIVE_STOP;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_STOP);\n"
"use constant INFO_BACKUP_KEY_BACKUP_STANDBY => MANIFEST_KEY_BACKUP_STANDBY;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_STANDBY);\n"
"use constant INFO_BACKUP_KEY_BACKUP_REPO_SIZE => 'backup-info-repo-size';\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_REPO_SIZE);\n"
"use constant INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA => 'backup-info-repo-size-delta';\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA);\n"
"use constant INFO_BACKUP_KEY_BACKUP_SIZE => 'backup-info-size';\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_SIZE);\n"
"use constant INFO_BACKUP_KEY_BACKUP_SIZE_DELTA => 'backup-info-size-delta';\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_SIZE_DELTA);\n"
"use constant INFO_BACKUP_KEY_CATALOG => MANIFEST_KEY_CATALOG;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_CATALOG);\n"
"use constant INFO_BACKUP_KEY_CONTROL => MANIFEST_KEY_CONTROL;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_CONTROL);\n"
"use constant INFO_BACKUP_KEY_COMPRESS => MANIFEST_KEY_COMPRESS;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_COMPRESS);\n"
"use constant INFO_BACKUP_KEY_CHECKSUM_PAGE => MANIFEST_KEY_CHECKSUM_PAGE;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_CHECKSUM_PAGE);\n"
"use constant INFO_BACKUP_KEY_DB_VERSION => MANIFEST_KEY_DB_VERSION;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_DB_VERSION);\n"
"use constant INFO_BACKUP_KEY_FORMAT => INI_KEY_FORMAT;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_FORMAT);\n"
"use constant INFO_BACKUP_KEY_HARDLINK => MANIFEST_KEY_HARDLINK;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_HARDLINK);\n"
"use constant INFO_BACKUP_KEY_HISTORY_ID => MANIFEST_KEY_DB_ID;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_HISTORY_ID);\n"
"use constant INFO_BACKUP_KEY_LABEL => MANIFEST_KEY_LABEL;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_LABEL);\n"
"use constant INFO_BACKUP_KEY_PRIOR => MANIFEST_KEY_PRIOR;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_PRIOR);\n"
"use constant INFO_BACKUP_KEY_REFERENCE => 'backup-reference';\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_REFERENCE);\n"
"use constant INFO_BACKUP_KEY_ONLINE => MANIFEST_KEY_ONLINE;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_ONLINE);\n"
"use constant INFO_BACKUP_KEY_SYSTEM_ID => MANIFEST_KEY_SYSTEM_ID;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_SYSTEM_ID);\n"
"use constant INFO_BACKUP_KEY_TIMESTAMP_START => MANIFEST_KEY_TIMESTAMP_START;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_TIMESTAMP_START);\n"
"use constant INFO_BACKUP_KEY_TIMESTAMP_STOP => MANIFEST_KEY_TIMESTAMP_STOP;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_TIMESTAMP_STOP);\n"
"use constant INFO_BACKUP_KEY_TYPE => MANIFEST_KEY_TYPE;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_TYPE);\n"
"use constant INFO_BACKUP_KEY_VERSION => INI_KEY_VERSION;\n"
"push @EXPORT, qw(INFO_BACKUP_KEY_VERSION);\n"
"\n\n\n\n"
"my $strBackupInfoMissingMsg =\n"
"FILE_BACKUP_INFO . \" does not exist and is required to perform a backup.\\n\" .\n"
"\"HINT: has a stanza-create been performed?\";\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strBackupClusterPath,\n"
"$bValidate,\n"
"$bRequired,\n"
"$oStorage,\n"
"$bLoad,\n"
"$bIgnoreMissing, # Don't error on missing files\n"
"$strCipherPassSub,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strBackupClusterPath'},\n"
"{name => 'bValidate', default => true},\n"
"{name => 'bRequired', default => true},\n"
"{name => 'oStorage', optional => true, default => storageRepo()},\n"
"{name => 'bLoad', optional => true, default => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
"{name => 'strCipherPassSub', optional => true},\n"
");\n"
"\n\n"
"my $strBackupInfoFile = \"${strBackupClusterPath}/\" . FILE_BACKUP_INFO;\n"
"my $self = {};\n"
"my $iResult = 0;\n"
"my $strResultMessage;\n"
"\n\n"
"eval\n"
"{\n"
"$self = $class->SUPER::new($strBackupInfoFile, {bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing,\n"
"oStorage => $oStorage, strCipherPass => $oStorage->cipherPassUser(),\n"
"strCipherPassSub => $strCipherPassSub});\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n"
"if ($iResult != 0)\n"
"{\n"
"\n\n"
"if ($iResult == ERROR_FILE_MISSING)\n"
"{\n"
"if ($bRequired)\n"
"{\n"
"confess &log(ERROR, \"${strBackupClusterPath}/$strBackupInfoMissingMsg\", ERROR_FILE_MISSING);\n"
"}\n"
"}\n"
"elsif ($iResult == ERROR_CRYPTO && $strResultMessage =~ \"^unable to flush\")\n"
"{\n"
"confess &log(ERROR, \"unable to parse '$strBackupInfoFile'\\nHINT: Is or was the repo encrypted?\", $iResult);\n"
"}\n"
"else\n"
"{\n"
"confess $EVAL_ERROR;\n"
"}\n"
"}\n"
"\n"
"$self->{strBackupClusterPath} = $strBackupClusterPath;\n"
"$self->{oStorage} = $oStorage;\n"
"\n\n"
"if ($bValidate)\n"
"{\n"
"$self->validate();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub validate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->validate');\n"
"\n\n"
"$self->confirmExists();\n"
"\n"
"$self->reconstruct();\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub reconstruct\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bSave,\n"
"$bRequired,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
"$iControlVersion,\n"
"$iCatalogVersion,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->reconstruct', \\@_,\n"
"{name => 'bSave', default => true},\n"
"{name => 'bRequired', default => true},\n"
"{name => 'strDbVersion', required => false},\n"
"{name => 'ullDbSysId', required => false},\n"
"{name => 'iControlVersion', required => false},\n"
"{name => 'iCatalogVersion', required => false},\n"
");\n"
"\n\n"
"foreach my $strBackup ($self->{oStorage}->list(\n"
"$self->{strBackupClusterPath}, {strExpression => backupRegExpGet(true, true, true)}))\n"
"{\n"
"my $strManifestFile = \"$self->{strBackupClusterPath}/${strBackup}/\" . FILE_MANIFEST;\n"
"\n\n\n\n"
"if (!$self->current($strBackup) && $self->{oStorage}->exists($strManifestFile))\n"
"{\n"
"my $oManifest = pgBackRest::Manifest->new($strManifestFile,\n"
"{strCipherPass => ($self->{oStorage}->encrypted($strManifestFile)) ? $self->cipherPassSub() : undef});\n"
"\n\n\n"
"if (!$bRequired)\n"
"{\n"
"my $hDbList = $self->dbHistoryList();\n"
"my $iDbId = $oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID);\n"
"my $iDbIdMax = 0;\n"
"my $ullDbSysId = $oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID);\n"
"my $strDbVersion = $oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION);\n"
"\n\n"
"foreach my $iDbHistoryId (keys %{$hDbList})\n"
"{\n"
"\n"
"if ($iDbHistoryId > $iDbIdMax)\n"
"{\n"
"$iDbIdMax = $iDbHistoryId;\n"
"}\n"
"}\n"
"\n"
"if ($iDbId >= $iDbIdMax)\n"
"{\n"
"$self->dbSectionSet($strDbVersion, $oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL),\n"
"$oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG), $ullDbSysId, $iDbId);\n"
"}\n"
"}\n"
"\n"
"&log(WARN, \"backup ${strBackup} found in repository added to \" . FILE_BACKUP_INFO);\n"
"\n"
"$self->add($oManifest, $bSave, $bRequired);\n"
"}\n"
"}\n"
"\n\n"
"if (!$bRequired)\n"
"{\n"
"\n"
"if (!defined($strDbVersion) || !defined($ullDbSysId) || !defined($iControlVersion) || !defined($iCatalogVersion))\n"
"{\n"
"confess &log(ASSERT, \"backup info cannot be reconstructed without database information\");\n"
"}\n"
"\n"
"elsif (!$self->test(INFO_BACKUP_SECTION_DB))\n"
"{\n"
"$self->create($strDbVersion, $ullDbSysId, $iControlVersion, $iCatalogVersion, $bSave);\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"logDisable();\n"
"\n"
"eval\n"
"{\n"
"$self->check($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId, $bRequired);\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"logEnable();\n"
"\n\n"
"confess $EVAL_ERROR if (exceptionCode($EVAL_ERROR) != ERROR_BACKUP_MISMATCH);\n"
"\n\n"
"$self->dbSectionSet($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId, $self->dbHistoryIdGet(false)+1);\n"
"};\n"
"}\n"
"}\n"
"\n\n"
"foreach my $strBackup ($self->keys(INFO_BACKUP_SECTION_BACKUP_CURRENT))\n"
"{\n"
"my $strManifestFile = \"$self->{strBackupClusterPath}/${strBackup}/\" . FILE_MANIFEST;\n"
"my $strBackupPath = \"$self->{strBackupClusterPath}/${strBackup}\";\n"
"\n"
"if (!$self->{oStorage}->pathExists($strBackupPath))\n"
"{\n"
"&log(WARN, \"backup ${strBackup} missing in repository removed from \" . FILE_BACKUP_INFO);\n"
"$self->delete($strBackup);\n"
"}\n"
"elsif (!$self->{oStorage}->exists($strManifestFile))\n"
"{\n"
"&log(WARN, \"backup ${strBackup} missing manifest removed from \" . FILE_BACKUP_INFO);\n"
"$self->delete($strBackup);\n"
"}\n"
"}\n"
"\n\n\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub check\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$iControlVersion,\n"
"$iCatalogVersion,\n"
"$ullDbSysId,\n"
"$bRequired,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->check', \\@_,\n"
"{name => 'strDbVersion', trace => true},\n"
"{name => 'iControlVersion', trace => true},\n"
"{name => 'iCatalogVersion', trace => true},\n"
"{name => 'ullDbSysId', trace => true},\n"
"{name => 'bRequired', default => true},\n"
");\n"
"\n\n"
"if ($bRequired)\n"
"{\n"
"$self->confirmExists();\n"
"}\n"
"\n"
"if (!$self->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID, undef, $ullDbSysId) ||\n"
"!$self->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef, $strDbVersion))\n"
"{\n"
"confess &log(ERROR, \"database version = ${strDbVersion}, system-id ${ullDbSysId} does not match backup version = \" .\n"
"$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION) . \", system-id = \" .\n"
"$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID) . \"\\n\" .\n"
"\"HINT: is this the correct stanza?\", ERROR_BACKUP_MISMATCH);\n"
"}\n"
"\n"
"if (!$self->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CATALOG, undef, $iCatalogVersion) ||\n"
"!$self->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CONTROL, undef, $iControlVersion))\n"
"{\n"
"confess &log(ERROR, \"database control-version = ${iControlVersion}, catalog-version ${iCatalogVersion}\" .\n"
"\" does not match backup control-version = \" .\n"
"$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CONTROL) . \", catalog-version = \" .\n"
"$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CATALOG) . \"\\n\" .\n"
"\"HINT: this may be a symptom of database or repository corruption!\", ERROR_BACKUP_MISMATCH);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iDbHistoryId', value => $self->numericGet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID)}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub add\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oBackupManifest,\n"
"$bSave,\n"
"$bRequired,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->add', \\@_,\n"
"{name => 'oBackupManifest', trace => true},\n"
"{name => 'bSave', default => true, trace => true},\n"
"{name => 'bRequired', default => true, trace => true},\n"
");\n"
"\n\n"
"if ($bRequired)\n"
"{\n"
"$self->confirmExists();\n"
"}\n"
"\n\n"
"my $strBackupLabel = $oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL);\n"
"\n\n"
"my $lBackupSize = 0;\n"
"my $lBackupSizeDelta = 0;\n"
"my $lBackupRepoSize = 0;\n"
"my $lBackupRepoSizeDelta = 0;\n"
"my $oReferenceHash = undef;\n"
"\n"
"foreach my $strFileKey ($oBackupManifest->keys(MANIFEST_SECTION_TARGET_FILE))\n"
"{\n"
"my $lFileSize =\n"
"$oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFileKey, MANIFEST_SUBKEY_SIZE);\n"
"my $lRepoSize =\n"
"$oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFileKey, MANIFEST_SUBKEY_REPO_SIZE, false, $lFileSize);\n"
"my $strFileReference =\n"
"$oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFileKey, MANIFEST_SUBKEY_REFERENCE, false);\n"
"\n\n"
"$lBackupSize += $lFileSize;\n"
"$lBackupRepoSize += $lRepoSize;\n"
"\n"
"if (defined($strFileReference))\n"
"{\n"
"$$oReferenceHash{$strFileReference} = true;\n"
"}\n"
"else\n"
"{\n"
"$lBackupSizeDelta += $lFileSize;\n"
"$lBackupRepoSizeDelta += $lRepoSize;\n"
"}\n"
"}\n"
"\n\n"
"$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_SIZE, $lBackupSize);\n"
"$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_SIZE_DELTA, $lBackupSizeDelta);\n"
"$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_REPO_SIZE, $lBackupRepoSize);\n"
"$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA,\n"
"$lBackupRepoSizeDelta);\n"
"\n"
"$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ARCHIVE_CHECK,\n"
"$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_CHECK));\n"
"$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ARCHIVE_COPY,\n"
"$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_COPY));\n"
"$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ARCHIVE_START,\n"
"$oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_START, undef, false));\n"
"$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ARCHIVE_STOP,\n"
"$oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP, undef, false));\n"
"$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_STANDBY,\n"
"$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_BACKUP_STANDBY));\n"
"$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_CHECKSUM_PAGE,\n"
"$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_CHECKSUM_PAGE));\n"
"$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_COMPRESS,\n"
"$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS));\n"
"$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_FORMAT,\n"
"$oBackupManifest->numericGet(INI_SECTION_BACKREST, INI_KEY_FORMAT));\n"
"$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_HARDLINK,\n"
"$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK));\n"
"$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ONLINE,\n"
"$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE));\n"
"$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_TIMESTAMP_START,\n"
"$oBackupManifest->numericGet(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_START));\n"
"$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_TIMESTAMP_STOP,\n"
"$oBackupManifest->numericGet(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_STOP));\n"
"$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_TYPE,\n"
"$oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE));\n"
"$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_VERSION,\n"
"$oBackupManifest->get(INI_SECTION_BACKREST, INI_KEY_VERSION));\n"
"\n"
"if ($bRequired)\n"
"{\n"
"$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_HISTORY_ID,\n"
"$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID));\n"
"}\n"
"\n"
"else\n"
"{\n"
"$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_HISTORY_ID,\n"
"$oBackupManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID));\n"
"}\n"
"\n"
"if (!$oBackupManifest->test(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE, undef, CFGOPTVAL_BACKUP_TYPE_FULL))\n"
"{\n"
"my @stryReference = sort(keys(%$oReferenceHash));\n"
"\n"
"$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_PRIOR,\n"
"$oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_PRIOR));\n"
"$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_REFERENCE,\n"
"\\@stryReference);\n"
"}\n"
"\n"
"if ($bSave)\n"
"{\n"
"$self->save();\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub current\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strBackup\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->current', \\@_,\n"
"{name => 'strBackup'}\n"
");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bTest', value => $self->test(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup)}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub list\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFilter,\n"
"$strOrder\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->list', \\@_,\n"
"{name => 'strFilter', required => false},\n"
"{name => 'strOrder', default => 'forward'}\n"
");\n"
"\n\n"
"my @stryBackup;\n"
"\n\n"
"for my $strBackup ($self->keys(INFO_BACKUP_SECTION_BACKUP_CURRENT))\n"
"{\n"
"if (!defined($strFilter) || $strBackup =~ $strFilter)\n"
"{\n"
"if ($strOrder eq 'reverse')\n"
"{\n"
"unshift(@stryBackup, $strBackup)\n"
"}\n"
"else\n"
"{\n"
"push(@stryBackup, $strBackup)\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryBackup', value => \\@stryBackup}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub backupArchiveDbHistoryId\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strArchiveId,\n"
"$strPathBackupArchive,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->backupArchiveDbHistoryId', \\@_,\n"
"{name => 'strArchiveId'},\n"
"{name => 'strPathBackupArchive'},\n"
");\n"
"\n\n"
"my @stryArchiveBackup;\n"
"\n\n"
"my $oArchiveInfo = new pgBackRest::Archive::Info($strPathBackupArchive, true);\n"
"my $hDbListArchive = $oArchiveInfo->dbHistoryList();\n"
"my $hDbListBackup = $self->dbHistoryList();\n"
"my $iDbHistoryId = undef;\n"
"\n\n"
"my ($strDbVersionArchive, $iDbIdArchive) = split(\"-\", $strArchiveId);\n"
"\n\n"
"if (exists($hDbListArchive->{$iDbIdArchive}))\n"
"{\n"
"my $ullDbSysIdArchive = $$hDbListArchive{$iDbIdArchive}{&INFO_SYSTEM_ID};\n"
"\n\n\n"
"foreach my $iDbIdBackup (sort {$b <=> $a} keys %{$hDbListBackup})\n"
"{\n"
"if ($$hDbListBackup{$iDbIdBackup}{&INFO_SYSTEM_ID} == $ullDbSysIdArchive &&\n"
"$$hDbListBackup{$iDbIdBackup}{&INFO_DB_VERSION} eq $strDbVersionArchive)\n"
"{\n"
"$iDbHistoryId = $iDbIdBackup;\n"
"last;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (!defined($iDbHistoryId))\n"
"{\n"
"\n"
"if (!($oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef,\n"
"($self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION)))) ||\n"
"!($oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID, undef,\n"
"($self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID)))))\n"
"{\n"
"\n"
"confess &log(ASSERT, \"the archive and backup database sections do not match\", ERROR_FILE_INVALID);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iDbHistoryId', value => $iDbHistoryId}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub listByArchiveId\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strArchiveId,\n"
"$strPathBackupArchive,\n"
"$stryBackup,\n"
"$strOrder,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->listByArchiveId', \\@_,\n"
"{name => 'strArchiveId'},\n"
"{name => 'strPathBackupArchive'},\n"
"{name => 'stryBackup'},\n"
"{name => 'strOrder', default => 'forward'}\n"
");\n"
"\n\n"
"my @stryArchiveBackup;\n"
"\n"
"my $iDbHistoryId = $self->backupArchiveDbHistoryId($strArchiveId, $strPathBackupArchive);\n"
"\n\n"
"if (defined($iDbHistoryId))\n"
"{\n"
"\n"
"foreach my $strBackup (@$stryBackup)\n"
"{\n"
"\n"
"if ($self->test(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_HISTORY_ID, $iDbHistoryId))\n"
"{\n"
"if ($strOrder eq 'reverse')\n"
"{\n"
"unshift(@stryArchiveBackup, $strBackup)\n"
"}\n"
"else\n"
"{\n"
"push(@stryArchiveBackup, $strBackup)\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryArchiveBackup', value => \\@stryArchiveBackup}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub last\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strType\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->last', \\@_,\n"
"{name => 'strType'}\n"
");\n"
"\n"
"my $strFilter = backupRegExpGet(true, $strType ne CFGOPTVAL_BACKUP_TYPE_FULL, $strType eq CFGOPTVAL_BACKUP_TYPE_INCR);\n"
"my $strBackup = ($self->list($strFilter, 'reverse'))[0];\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strBackup', value => $strBackup}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub delete\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strBackupLabel\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->delete', \\@_,\n"
"{name => 'strBackupLabel'}\n"
");\n"
"\n"
"$self->remove(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel);\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub create\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
"$iControlVersion,\n"
"$iCatalogVersion,\n"
"$bSave,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->create', \\@_,\n"
"{name => 'strDbVersion'},\n"
"{name => 'ullDbSysId'},\n"
"{name => 'iControlVersion'},\n"
"{name => 'iCatalogVersion'},\n"
"{name => 'bSave', default => true},\n"
");\n"
"\n\n"
"$self->dbSectionSet($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId, $self->dbHistoryIdGet(false));\n"
"\n"
"if ($bSave)\n"
"{\n"
"$self->save();\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbHistoryIdGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bFileRequired,\n"
") = logDebugParam\n"
"(\n"
"__PACKAGE__ . '->dbHistoryIdGet', \\@_,\n"
"{name => 'bFileRequired', default => true},\n"
");\n"
"\n\n"
"if ($bFileRequired)\n"
"{\n"
"$self->confirmExists();\n"
"}\n"
"\n\n"
"my $iDbHistoryId = (!$self->test(INFO_BACKUP_SECTION_DB))\n"
"? 1 : $self->numericGet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iDbHistoryId', value => $iDbHistoryId}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbHistoryList\n"
"{\n"
"my $self = shift;\n"
"my\n"
"(\n"
"$strOperation,\n"
") = logDebugParam\n"
"(\n"
"__PACKAGE__ . '->dbHistoryList',\n"
");\n"
"\n"
"my %hDbHash;\n"
"\n"
"foreach my $iHistoryId ($self->keys(INFO_BACKUP_SECTION_DB_HISTORY))\n"
"{\n"
"$hDbHash{$iHistoryId}{&INFO_DB_VERSION} =\n"
"$self->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_DB_VERSION);\n"
"$hDbHash{$iHistoryId}{&INFO_SYSTEM_ID} =\n"
"$self->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_SYSTEM_ID);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hDbHash', value => \\%hDbHash}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbSectionSet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$iControlVersion,\n"
"$iCatalogVersion,\n"
"$ullDbSysId,\n"
"$iDbHistoryId,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->dbSectionSet', \\@_,\n"
"{name => 'strDbVersion', trace => true},\n"
"{name => 'iControlVersion', trace => true},\n"
"{name => 'iCatalogVersion', trace => true},\n"
"{name => 'ullDbSysId', trace => true},\n"
"{name => 'iDbHistoryId', trace => true},\n"
");\n"
"\n\n"
"$self->numericSet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CATALOG, undef, $iCatalogVersion);\n"
"$self->numericSet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CONTROL, undef, $iControlVersion);\n"
"$self->numericSet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID, undef, $ullDbSysId);\n"
"$self->set(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef, $strDbVersion);\n"
"$self->numericSet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID, undef, $iDbHistoryId);\n"
"\n\n"
"$self->numericSet(INFO_BACKUP_SECTION_DB_HISTORY, $iDbHistoryId, INFO_BACKUP_KEY_CATALOG, $iCatalogVersion);\n"
"$self->numericSet(INFO_BACKUP_SECTION_DB_HISTORY, $iDbHistoryId, INFO_BACKUP_KEY_CONTROL, $iControlVersion);\n"
"$self->numericSet(INFO_BACKUP_SECTION_DB_HISTORY, $iDbHistoryId, INFO_BACKUP_KEY_SYSTEM_ID, $ullDbSysId);\n"
"$self->set(INFO_BACKUP_SECTION_DB_HISTORY, $iDbHistoryId, INFO_BACKUP_KEY_DB_VERSION, $strDbVersion);\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub confirmDb\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strBackup,\n"
"$strDbVersion,\n"
"$ullDbSysId,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->confirmDb', \\@_,\n"
"{name => 'strBackup', trace => true},\n"
"{name => 'strDbVersion', trace => true},\n"
"{name => 'ullDbSysId', trace => true},\n"
");\n"
"\n"
"my $bConfirmDb = undef;\n"
"\n\n"
"my $iDbHistoryId = $self->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_HISTORY_ID);\n"
"\n\n"
"my $hDbList = $self->dbHistoryList();\n"
"\n\n"
"if (exists $hDbList->{$iDbHistoryId})\n"
"{\n"
"\n"
"if (($hDbList->{$iDbHistoryId}{&INFO_DB_VERSION} eq $strDbVersion) &&\n"
"($hDbList->{$iDbHistoryId}{&INFO_SYSTEM_ID} eq $ullDbSysId))\n"
"{\n"
"$bConfirmDb = true;\n"
"}\n"
"else\n"
"{\n"
"$bConfirmDb = false;\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"confess &log(ERROR, \"backup info file is missing database history information for an existing backup\", ERROR_FILE_INVALID);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bConfirmDb', value => $bConfirmDb}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub confirmExists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"if (!$self->test(INFO_BACKUP_SECTION_DB) || !$self->{bExists})\n"
"{\n"
"confess &log(ERROR, $self->{strBackupClusterPath} . \"/\" . $strBackupInfoMissingMsg, ERROR_FILE_MISSING);\n"
"}\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Check/Check.pm",
.data =
"\n\n\n"
"package pgBackRest::Check::Check;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use pgBackRest::Archive::Common;\n"
"use pgBackRest::Archive::Get::File;\n"
"use pgBackRest::Backup::Info;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Db;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my $strOperation = logDebugParam(__PACKAGE__ . '->process');\n"
"\n\n"
"my $iArchiveTimeout = cfgOption(CFGOPT_ARCHIVE_TIMEOUT);\n"
"\n"
"my $iResult = 0;\n"
"my $strResultMessage = undef;\n"
"\n"
"my $strArchiveId = undef;\n"
"my $strArchiveFile = undef;\n"
"my $strWalSegment = undef;\n"
"\n\n"
"my ($oDb) = dbMasterGet();\n"
"\n\n"
"my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = $oDb->info();\n"
"\n\n"
"logLevelSet(undef, OFF);\n"
"\n\n"
"for (my $iRemoteIdx = 1; $iRemoteIdx <= cfgOptionIndexTotal(CFGOPT_PG_HOST); $iRemoteIdx++)\n"
"{\n"
"\n"
"if (cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)) ||\n"
"cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iRemoteIdx)))\n"
"{\n"
"eval\n"
"{\n"
"\n\n"
"my $oBackupManifest = new pgBackRest::Manifest(\"/dev/null/manifest.chk\",\n"
"{bLoad => false, strDbVersion => $strDbVersion, iDbCatalogVersion => $iCatalogVersion,\n"
"strCipherPass => 'x', strCipherPassSub => 'x'});\n"
"\n\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID, undef, 1);\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL, undef, $iControlVersion);\n"
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef, $ullDbSysId);\n"
"\n"
"$oBackupManifest->build(\n"
"storageDb({iRemoteIdx => $iRemoteIdx}), cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)), undef,\n"
"cfgOptionValid(CFGOPT_ONLINE) && cfgOption(CFGOPT_ONLINE), false, $oDb->tablespaceMapGet());\n"
"\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"$strResultMessage = \"Database: ${strDbVersion} ${ullDbSysId} \" . exceptionMessage($EVAL_ERROR) .\n"
"(($iResult != 0) ? \"\\n[$iResult] : $strResultMessage\" : \"\");\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"};\n"
"}\n"
"}\n"
"\n\n"
"logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE));\n"
"\n\n"
"if ($iResult == 0)\n"
"{\n"
"\n\n"
"($oDb) = dbObjectGet();\n"
"\n\n"
"$oDb->configValidate();\n"
"\n\n"
"logLevelSet(undef, OFF);\n"
"\n\n"
"eval\n"
"{\n"
"\n"
"$self->backupInfoCheck();\n"
"return true;\n"
"}\n"
"\n"
"or do\n"
"{\n"
"\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n\n"
"if ($iResult == 0)\n"
"{\n"
"eval\n"
"{\n"
"\n"
"($strArchiveId) = archiveGetCheck();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"}\n"
"\n\n"
"if ($iResult == 0 && !$oDb->isStandby())\n"
"{\n"
"$strWalSegment = $oDb->walSwitch();\n"
"\n"
"eval\n"
"{\n"
"$strArchiveFile = walSegmentFind(storageRepo(), $strArchiveId, $strWalSegment, $iArchiveTimeout);\n"
"return true;\n"
"}\n"
"\n"
"or do\n"
"{\n"
"\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"}\n"
"\n\n"
"logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE));\n"
"}\n"
"\n\n\n"
"if ($iResult == 0)\n"
"{\n"
"if (!$oDb->isStandby())\n"
"{\n"
"&log(INFO,\n"
"\"WAL segment ${strWalSegment} successfully stored in the archive at '\" .\n"
"storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . \"/$strArchiveId/${strArchiveFile}\") . \"'\");\n"
"}\n"
"else\n"
"{\n"
"&log(INFO, 'switch ' . $oDb->walId() . ' cannot be performed on the standby, all other checks passed successfully');\n"
"}\n"
"}\n"
"else\n"
"{\n"
"\n"
"&log(ERROR, $strResultMessage, $iResult);\n"
"\n\n"
"if (defined($strWalSegment) && !defined($strArchiveFile))\n"
"{\n"
"&log(WARN,\n"
"\"WAL segment ${strWalSegment} did not reach the archive:\" . (defined($strArchiveId) ? $strArchiveId : '') . \"\\n\" .\n"
"\"HINT: Check the archive_command to ensure that all options are correct (especially --stanza).\\n\" .\n"
"\"HINT: Check the PostgreSQL server log for errors.\");\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iResult', value => $iResult, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub backupInfoCheck\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbVersion,\n"
"$iControlVersion,\n"
"$iCatalogVersion,\n"
"$ullDbSysId,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->backupInfoCheck', \\@_,\n"
"{name => 'strDbVersion', required => false},\n"
"{name => 'iControlVersion', required => false},\n"
"{name => 'iCatalogVersion', required => false},\n"
"{name => 'ullDbSysId', required => false}\n"
");\n"
"\n\n"
"my $iDbHistoryId;\n"
"\n"
"if (!defined($strDbVersion) || !defined($iControlVersion) || !defined($iCatalogVersion) || !defined($ullDbSysId))\n"
"{\n"
"\n"
"($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = dbMasterGet()->info();\n"
"}\n"
"\n"
"if (!isRepoLocal())\n"
"{\n"
"$iDbHistoryId = protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(\n"
"OP_CHECK_BACKUP_INFO_CHECK, [$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId]);\n"
"}\n"
"else\n"
"{\n"
"$iDbHistoryId = (new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP)))->check(\n"
"$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iDbHistoryId', value => $iDbHistoryId, trace => true}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Cipher.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Cipher;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::LibC qw(:random :encode);\n"
"\n\n\n\n"
"sub cipherPassGen\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iKeySizeInBytes,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::cipherPassGen', \\@_,\n"
"{name => 'iKeySizeInBytes', default => 48},\n"
");\n"
"\n\n"
"my $strCipherPass = encodeToStr(ENCODE_TYPE_BASE64, cryptoRandomBytes($iKeySizeInBytes));\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strCipherPass', value => $strCipherPass, redact => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(cipherPassGen);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Exception.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Exception;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess longmess);\n"
"\n"
"use Scalar::Util qw(blessed);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::ExceptionAuto;\n"
"\n\n\n\n"
"push(@EXPORT, @pgBackRest::Common::ExceptionAuto::EXPORT);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"my $strLevel = shift;\n"
"my $iCode = shift;\n"
"my $strMessage = shift;\n"
"my $strTrace = shift;\n"
"my $rExtra = shift;\n"
"my $bErrorC = shift;\n"
"\n"
"if ($iCode < ERROR_MINIMUM || $iCode > ERROR_MAXIMUM)\n"
"{\n"
"$iCode = ERROR_INVALID;\n"
"}\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"$self->{strLevel} = $strLevel;\n"
"$self->{iCode} = $iCode;\n"
"$self->{strMessage} = $strMessage;\n"
"$self->{strTrace} = $strTrace;\n"
"$self->{rExtra} = $rExtra;\n"
"$self->{bErrorC} = $bErrorC ? 1 : 0;\n"
"\n"
"return $self;\n"
"}\n"
"\n\n\n\n"
"sub level\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{strLevel};\n"
"}\n"
"\n\n\n\n"
"sub code\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{iCode};\n"
"}\n"
"\n\n\n\n"
"sub errorC\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{bErrorC};\n"
"}\n"
"\n\n\n\n"
"sub extra\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{rExtra};\n"
"}\n"
"\n\n\n\n"
"sub message\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{strMessage};\n"
"}\n"
"\n\n\n\n"
"sub trace\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{strTrace};\n"
"}\n"
"\n\n\n\n"
"sub isException\n"
"{\n"
"my $roException = shift;\n"
"\n\n"
"if (defined($roException) && defined($$roException))\n"
"{\n"
"\n"
"if (blessed($$roException))\n"
"{\n"
"return $$roException->isa('pgBackRest::Common::Exception') ? 1 : 0;\n"
"}\n"
"\n"
"elsif ($$roException =~ /^PGBRCLIB\\:[0-9]+\\:/)\n"
"{\n"
"\n"
"my @stryException = split(/\\:/, $$roException);\n"
"shift(@stryException);\n"
"\n\n"
"my $iCode = shift(@stryException) + 0;\n"
"my $strTrace = shift(@stryException) . qw{:} . shift(@stryException);\n"
"my $strMessage = join(':', @stryException);\n"
"\n\n"
"$$roException = new pgBackRest::Common::Exception(\"ERROR\", $iCode, $strMessage, $strTrace, undef, 1);\n"
"\n"
"return 1;\n"
"}\n"
"}\n"
"\n"
"return 0;\n"
"}\n"
"\n"
"push @EXPORT, qw(isException);\n"
"\n\n\n\n\n\n"
"sub exceptionCode\n"
"{\n"
"my $oException = shift;\n"
"\n"
"return isException(\\$oException) ? $oException->code() : ERROR_UNKNOWN;\n"
"}\n"
"\n"
"push @EXPORT, qw(exceptionCode);\n"
"\n\n\n\n\n\n"
"sub exceptionMessage\n"
"{\n"
"my $oException = shift;\n"
"\n"
"return isException(\\$oException) ? $oException->message() : $oException;\n"
"}\n"
"\n"
"push @EXPORT, qw(exceptionMessage);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/ExceptionAuto.pm",
.data =
"\n\n\n\n\n"
"package pgBackRest::Common::ExceptionAuto;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n\n\n\n"
"use constant ERROR_MINIMUM => 25;\n"
"push @EXPORT, qw(ERROR_MINIMUM);\n"
"use constant ERROR_MAXIMUM => 125;\n"
"push @EXPORT, qw(ERROR_MAXIMUM);\n"
"\n"
"use constant ERROR_ASSERT => 25;\n"
"push @EXPORT, qw(ERROR_ASSERT);\n"
"use constant ERROR_CHECKSUM => 26;\n"
"push @EXPORT, qw(ERROR_CHECKSUM);\n"
"use constant ERROR_CONFIG => 27;\n"
"push @EXPORT, qw(ERROR_CONFIG);\n"
"use constant ERROR_FILE_INVALID => 28;\n"
"push @EXPORT, qw(ERROR_FILE_INVALID);\n"
"use constant ERROR_FORMAT => 29;\n"
"push @EXPORT, qw(ERROR_FORMAT);\n"
"use constant ERROR_COMMAND_REQUIRED => 30;\n"
"push @EXPORT, qw(ERROR_COMMAND_REQUIRED);\n"
"use constant ERROR_OPTION_INVALID => 31;\n"
"push @EXPORT, qw(ERROR_OPTION_INVALID);\n"
"use constant ERROR_OPTION_INVALID_VALUE => 32;\n"
"push @EXPORT, qw(ERROR_OPTION_INVALID_VALUE);\n"
"use constant ERROR_OPTION_INVALID_RANGE => 33;\n"
"push @EXPORT, qw(ERROR_OPTION_INVALID_RANGE);\n"
"use constant ERROR_OPTION_INVALID_PAIR => 34;\n"
"push @EXPORT, qw(ERROR_OPTION_INVALID_PAIR);\n"
"use constant ERROR_OPTION_DUPLICATE_KEY => 35;\n"
"push @EXPORT, qw(ERROR_OPTION_DUPLICATE_KEY);\n"
"use constant ERROR_OPTION_NEGATE => 36;\n"
"push @EXPORT, qw(ERROR_OPTION_NEGATE);\n"
"use constant ERROR_OPTION_REQUIRED => 37;\n"
"push @EXPORT, qw(ERROR_OPTION_REQUIRED);\n"
"use constant ERROR_POSTMASTER_RUNNING => 38;\n"
"push @EXPORT, qw(ERROR_POSTMASTER_RUNNING);\n"
"use constant ERROR_PROTOCOL => 39;\n"
"push @EXPORT, qw(ERROR_PROTOCOL);\n"
"use constant ERROR_PATH_NOT_EMPTY => 40;\n"
"push @EXPORT, qw(ERROR_PATH_NOT_EMPTY);\n"
"use constant ERROR_FILE_OPEN => 41;\n"
"push @EXPORT, qw(ERROR_FILE_OPEN);\n"
"use constant ERROR_FILE_READ => 42;\n"
"push @EXPORT, qw(ERROR_FILE_READ);\n"
"use constant ERROR_PARAM_REQUIRED => 43;\n"
"push @EXPORT, qw(ERROR_PARAM_REQUIRED);\n"
"use constant ERROR_ARCHIVE_MISMATCH => 44;\n"
"push @EXPORT, qw(ERROR_ARCHIVE_MISMATCH);\n"
"use constant ERROR_ARCHIVE_DUPLICATE => 45;\n"
"push @EXPORT, qw(ERROR_ARCHIVE_DUPLICATE);\n"
"use constant ERROR_VERSION_NOT_SUPPORTED => 46;\n"
"push @EXPORT, qw(ERROR_VERSION_NOT_SUPPORTED);\n"
"use constant ERROR_PATH_CREATE => 47;\n"
"push @EXPORT, qw(ERROR_PATH_CREATE);\n"
"use constant ERROR_COMMAND_INVALID => 48;\n"
"push @EXPORT, qw(ERROR_COMMAND_INVALID);\n"
"use constant ERROR_HOST_CONNECT => 49;\n"
"push @EXPORT, qw(ERROR_HOST_CONNECT);\n"
"use constant ERROR_LOCK_ACQUIRE => 50;\n"
"push @EXPORT, qw(ERROR_LOCK_ACQUIRE);\n"
"use constant ERROR_BACKUP_MISMATCH => 51;\n"
"push @EXPORT, qw(ERROR_BACKUP_MISMATCH);\n"
"use constant ERROR_FILE_SYNC => 52;\n"
"push @EXPORT, qw(ERROR_FILE_SYNC);\n"
"use constant ERROR_PATH_OPEN => 53;\n"
"push @EXPORT, qw(ERROR_PATH_OPEN);\n"
"use constant ERROR_PATH_SYNC => 54;\n"
"push @EXPORT, qw(ERROR_PATH_SYNC);\n"
"use constant ERROR_FILE_MISSING => 55;\n"
"push @EXPORT, qw(ERROR_FILE_MISSING);\n"
"use constant ERROR_DB_CONNECT => 56;\n"
"push @EXPORT, qw(ERROR_DB_CONNECT);\n"
"use constant ERROR_DB_QUERY => 57;\n"
"push @EXPORT, qw(ERROR_DB_QUERY);\n"
"use constant ERROR_DB_MISMATCH => 58;\n"
"push @EXPORT, qw(ERROR_DB_MISMATCH);\n"
"use constant ERROR_DB_TIMEOUT => 59;\n"
"push @EXPORT, qw(ERROR_DB_TIMEOUT);\n"
"use constant ERROR_FILE_REMOVE => 60;\n"
"push @EXPORT, qw(ERROR_FILE_REMOVE);\n"
"use constant ERROR_PATH_REMOVE => 61;\n"
"push @EXPORT, qw(ERROR_PATH_REMOVE);\n"
"use constant ERROR_STOP => 62;\n"
"push @EXPORT, qw(ERROR_STOP);\n"
"use constant ERROR_TERM => 63;\n"
"push @EXPORT, qw(ERROR_TERM);\n"
"use constant ERROR_FILE_WRITE => 64;\n"
"push @EXPORT, qw(ERROR_FILE_WRITE);\n"
"use constant ERROR_PROTOCOL_TIMEOUT => 66;\n"
"push @EXPORT, qw(ERROR_PROTOCOL_TIMEOUT);\n"
"use constant ERROR_FEATURE_NOT_SUPPORTED => 67;\n"
"push @EXPORT, qw(ERROR_FEATURE_NOT_SUPPORTED);\n"
"use constant ERROR_ARCHIVE_COMMAND_INVALID => 68;\n"
"push @EXPORT, qw(ERROR_ARCHIVE_COMMAND_INVALID);\n"
"use constant ERROR_LINK_EXPECTED => 69;\n"
"push @EXPORT, qw(ERROR_LINK_EXPECTED);\n"
"use constant ERROR_LINK_DESTINATION => 70;\n"
"push @EXPORT, qw(ERROR_LINK_DESTINATION);\n"
"use constant ERROR_TABLESPACE_IN_PGDATA => 71;\n"
"push @EXPORT, qw(ERROR_TABLESPACE_IN_PGDATA);\n"
"use constant ERROR_HOST_INVALID => 72;\n"
"push @EXPORT, qw(ERROR_HOST_INVALID);\n"
"use constant ERROR_PATH_MISSING => 73;\n"
"push @EXPORT, qw(ERROR_PATH_MISSING);\n"
"use constant ERROR_FILE_MOVE => 74;\n"
"push @EXPORT, qw(ERROR_FILE_MOVE);\n"
"use constant ERROR_BACKUP_SET_INVALID => 75;\n"
"push @EXPORT, qw(ERROR_BACKUP_SET_INVALID);\n"
"use constant ERROR_TABLESPACE_MAP => 76;\n"
"push @EXPORT, qw(ERROR_TABLESPACE_MAP);\n"
"use constant ERROR_PATH_TYPE => 77;\n"
"push @EXPORT, qw(ERROR_PATH_TYPE);\n"
"use constant ERROR_LINK_MAP => 78;\n"
"push @EXPORT, qw(ERROR_LINK_MAP);\n"
"use constant ERROR_FILE_CLOSE => 79;\n"
"push @EXPORT, qw(ERROR_FILE_CLOSE);\n"
"use constant ERROR_DB_MISSING => 80;\n"
"push @EXPORT, qw(ERROR_DB_MISSING);\n"
"use constant ERROR_DB_INVALID => 81;\n"
"push @EXPORT, qw(ERROR_DB_INVALID);\n"
"use constant ERROR_ARCHIVE_TIMEOUT => 82;\n"
"push @EXPORT, qw(ERROR_ARCHIVE_TIMEOUT);\n"
"use constant ERROR_FILE_MODE => 83;\n"
"push @EXPORT, qw(ERROR_FILE_MODE);\n"
"use constant ERROR_OPTION_MULTIPLE_VALUE => 84;\n"
"push @EXPORT, qw(ERROR_OPTION_MULTIPLE_VALUE);\n"
"use constant ERROR_PROTOCOL_OUTPUT_REQUIRED => 85;\n"
"push @EXPORT, qw(ERROR_PROTOCOL_OUTPUT_REQUIRED);\n"
"use constant ERROR_LINK_OPEN => 86;\n"
"push @EXPORT, qw(ERROR_LINK_OPEN);\n"
"use constant ERROR_ARCHIVE_DISABLED => 87;\n"
"push @EXPORT, qw(ERROR_ARCHIVE_DISABLED);\n"
"use constant ERROR_FILE_OWNER => 88;\n"
"push @EXPORT, qw(ERROR_FILE_OWNER);\n"
"use constant ERROR_USER_MISSING => 89;\n"
"push @EXPORT, qw(ERROR_USER_MISSING);\n"
"use constant ERROR_OPTION_COMMAND => 90;\n"
"push @EXPORT, qw(ERROR_OPTION_COMMAND);\n"
"use constant ERROR_GROUP_MISSING => 91;\n"
"push @EXPORT, qw(ERROR_GROUP_MISSING);\n"
"use constant ERROR_PATH_EXISTS => 92;\n"
"push @EXPORT, qw(ERROR_PATH_EXISTS);\n"
"use constant ERROR_FILE_EXISTS => 93;\n"
"push @EXPORT, qw(ERROR_FILE_EXISTS);\n"
"use constant ERROR_MEMORY => 94;\n"
"push @EXPORT, qw(ERROR_MEMORY);\n"
"use constant ERROR_CRYPTO => 95;\n"
"push @EXPORT, qw(ERROR_CRYPTO);\n"
"use constant ERROR_PARAM_INVALID => 96;\n"
"push @EXPORT, qw(ERROR_PARAM_INVALID);\n"
"use constant ERROR_PATH_CLOSE => 97;\n"
"push @EXPORT, qw(ERROR_PATH_CLOSE);\n"
"use constant ERROR_FILE_INFO => 98;\n"
"push @EXPORT, qw(ERROR_FILE_INFO);\n"
"use constant ERROR_JSON_FORMAT => 99;\n"
"push @EXPORT, qw(ERROR_JSON_FORMAT);\n"
"use constant ERROR_KERNEL => 100;\n"
"push @EXPORT, qw(ERROR_KERNEL);\n"
"use constant ERROR_SERVICE => 101;\n"
"push @EXPORT, qw(ERROR_SERVICE);\n"
"use constant ERROR_EXECUTE => 102;\n"
"push @EXPORT, qw(ERROR_EXECUTE);\n"
"use constant ERROR_RUNTIME => 122;\n"
"push @EXPORT, qw(ERROR_RUNTIME);\n"
"use constant ERROR_INVALID => 123;\n"
"push @EXPORT, qw(ERROR_INVALID);\n"
"use constant ERROR_UNHANDLED => 124;\n"
"push @EXPORT, qw(ERROR_UNHANDLED);\n"
"use constant ERROR_UNKNOWN => 125;\n"
"push @EXPORT, qw(ERROR_UNKNOWN);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Http/Client.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Http::Client;\n"
"use parent 'pgBackRest::Common::Io::Buffered';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use IO::Socket::SSL;\n"
"use Socket qw(SOL_SOCKET SO_KEEPALIVE);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Buffered;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Common::Xml;\n"
"use pgBackRest::Common::Http::Common;\n"
"\n\n\n\n"
"use constant HTTP_VERB_GET => 'GET';\n"
"push @EXPORT, qw(HTTP_VERB_GET);\n"
"use constant HTTP_VERB_POST => 'POST';\n"
"push @EXPORT, qw(HTTP_VERB_POST);\n"
"use constant HTTP_VERB_PUT => 'PUT';\n"
"push @EXPORT, qw(HTTP_VERB_PUT);\n"
"\n"
"use constant HTTP_HEADER_CONTENT_LENGTH => 'content-length';\n"
"push @EXPORT, qw(HTTP_HEADER_CONTENT_LENGTH);\n"
"use constant HTTP_HEADER_TRANSFER_ENCODING => 'transfer-encoding';\n"
"push @EXPORT, qw(HTTP_HEADER_TRANSFER_ENCODING);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strHost,\n"
"$strVerb,\n"
"$iPort,\n"
"$strUri,\n"
"$hQuery,\n"
"$hRequestHeader,\n"
"$rstrRequestBody,\n"
"$bResponseBodyPrefetch,\n"
"$iProtocolTimeout,\n"
"$iTryTotal,\n"
"$lBufferMax,\n"
"$bVerifySsl,\n"
"$strCaPath,\n"
"$strCaFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strHost', trace => true},\n"
"{name => 'strVerb', trace => true},\n"
"{name => 'iPort', optional => true, default => 443, trace => true},\n"
"{name => 'strUri', optional => true, default => qw(/), trace => true},\n"
"{name => 'hQuery', optional => true, trace => true},\n"
"{name => 'hRequestHeader', optional => true, trace => true},\n"
"{name => 'rstrRequestBody', optional => true, trace => true},\n"
"{name => 'bResponseBodyPrefetch', optional => true, default => false, trace => true},\n"
"{name => 'iProtocolTimeout', optional => true, default => 300, trace => true},\n"
"{name => 'iTryTotal', optional => true, default => 3, trace => true},\n"
"{name => 'lBufferMax', optional => true, default => 32768, trace => true},\n"
"{name => 'bVerifySsl', optional => true, default => true, trace => true},\n"
"{name => 'strCaPath', optional => true, trace => true},\n"
"{name => 'strCaFile', optional => true, trace => true},\n"
");\n"
"\n\n"
"my $self;\n"
"my $iTry = 1;\n"
"my $bRetry;\n"
"\n"
"do\n"
"{\n"
"\n"
"logDisable() if $iTry < $iTryTotal;\n"
"$bRetry = false;\n"
"\n"
"eval\n"
"{\n"
"\n"
"my $oSocket;\n"
"\n"
"if (eval{require IO::Socket::IP})\n"
"{\n"
"$oSocket = IO::Socket::IP->new(PeerHost => $strHost, PeerPort => $iPort)\n"
"or confess &log(ERROR, \"unable to create socket: $@\", ERROR_HOST_CONNECT);\n"
"}\n"
"else\n"
"{\n"
"require IO::Socket::INET;\n"
"\n"
"$oSocket = IO::Socket::INET->new(PeerHost => $strHost, PeerPort => $iPort)\n"
"or confess &log(ERROR, \"unable to create socket: $@\", ERROR_HOST_CONNECT);\n"
"}\n"
"\n"
"setsockopt($oSocket, SOL_SOCKET,SO_KEEPALIVE, 1)\n"
"or confess &log(ERROR, \"unable to set socket keepalive: $@\", ERROR_HOST_CONNECT);\n"
"\n"
"eval\n"
"{\n"
"IO::Socket::SSL->start_SSL(\n"
"$oSocket, SSL_verify_mode => $bVerifySsl ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, SSL_ca_path => $strCaPath,\n"
"SSL_ca_file => $strCaFile);\n"
"}\n"
"or do\n"
"{\n"
"logErrorResult(\n"
"ERROR_HOST_CONNECT, coalesce(length($!) == 0 ? undef : $!, $SSL_ERROR), length($!) > 0 ? $SSL_ERROR : undef);\n"
"};\n"
"\n\n"
"$self = $class->SUPER::new(\n"
"new pgBackRest::Common::Io::Handle('httpClient', $oSocket, $oSocket), $iProtocolTimeout, $lBufferMax);\n"
"bless $self, $class;\n"
"\n\n"
"$self->{oSocket} = $oSocket;\n"
"\n\n"
"my $strQuery = httpQuery($hQuery);\n"
"\n\n"
"$self->{strRequestHeader} = \"${strVerb} \" . httpUriEncode($strUri, true) . \"?${strQuery} HTTP/1.1\" . \"\\r\\n\";\n"
"\n"
"foreach my $strHeader (sort(keys(%{$hRequestHeader})))\n"
"{\n"
"$self->{strRequestHeader} .= \"${strHeader}: $hRequestHeader->{$strHeader}\\r\\n\";\n"
"}\n"
"\n"
"$self->{strRequestHeader} .= \"\\r\\n\";\n"
"\n\n"
"$self->write(\\$self->{strRequestHeader});\n"
"\n\n"
"if (defined($rstrRequestBody))\n"
"{\n"
"my $iTotalSize = length($$rstrRequestBody);\n"
"my $iTotalSent = 0;\n"
"\n\n"
"do\n"
"{\n"
"my $strBufferWrite = substr($$rstrRequestBody, $iTotalSent, $lBufferMax);\n"
"$iTotalSent += $self->write(\\$strBufferWrite);\n"
"} while ($iTotalSent < $iTotalSize);\n"
"}\n"
"\n\n"
"($self->{strResponseProtocol}, $self->{iResponseCode}, $self->{strResponseMessage}) =\n"
"split(' ', trim($self->readLine()));\n"
"\n\n"
"$self->{iContentLength} = 0;\n"
"$self->{strResponseHeader} = '';\n"
"my $strHeader = trim($self->readLine());\n"
"\n"
"while ($strHeader ne '')\n"
"{\n"
"\n"
"$self->{strResponseHeader} .= \"${strHeader}\\n\";\n"
"\n"
"my $iColonPos = index($strHeader, ':');\n"
"\n"
"if ($iColonPos == -1)\n"
"{\n"
"confess &log(ERROR, \"http header '${strHeader}' requires colon separator\", ERROR_PROTOCOL);\n"
"}\n"
"\n\n"
"my $strHeaderKey = lc(substr($strHeader, 0, $iColonPos));\n"
"my $strHeaderValue = trim(substr($strHeader, $iColonPos + 1));\n"
"\n\n"
"$self->{hResponseHeader}{$strHeaderKey} = $strHeaderValue;\n"
"\n\n"
"if ($strHeaderKey eq HTTP_HEADER_CONTENT_LENGTH)\n"
"{\n"
"$self->{iContentLength} = $strHeaderValue + 0;\n"
"$self->{iContentRemaining} = $self->{iContentLength};\n"
"}\n"
"\n"
"elsif ($strHeaderKey eq HTTP_HEADER_TRANSFER_ENCODING)\n"
"{\n"
"if ($strHeaderValue eq 'chunked')\n"
"{\n"
"$self->{iContentLength} = -1;\n"
"}\n"
"else\n"
"{\n"
"confess &log(ERROR, \"invalid value '${strHeaderValue} for http header '${strHeaderKey}'\", ERROR_PROTOCOL);\n"
"}\n"
"}\n"
"\n\n"
"$strHeader = trim($self->readLine());\n"
"}\n"
"\n\n"
"if ($bResponseBodyPrefetch)\n"
"{\n"
"$self->{strResponseBody} = $self->responseBody();\n"
"}\n"
"\n\n"
"logEnable() if $iTry < $iTryTotal;\n"
"return 1;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"logEnable() if $iTry < $iTryTotal;\n"
"\n\n"
"if ($iTry == $iTryTotal)\n"
"{\n"
"confess $EVAL_ERROR;\n"
"}\n"
"\n\n"
"$iTry++;\n"
"$bRetry = true;\n"
"};\n"
"}\n"
"while ($bRetry);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub read\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"my $iRequestSize = shift;\n"
"\n\n"
"$iRequestSize = $iRequestSize < $self->{iContentRemaining} ? $iRequestSize : $self->{iContentRemaining};\n"
"$self->{iContentRemaining} -= $iRequestSize;\n"
"\n"
"my $iActualSize = $self->SUPER::read($rtBuffer, $iRequestSize, true);\n"
"\n\n"
"if ($self->{iContentRemaining} == 0)\n"
"{\n"
"$self->SUPER::eofSet(true);\n"
"}\n"
"\n"
"return $iActualSize;\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"if (defined($self->{oSocket}))\n"
"{\n"
"$self->{oSocket}->close();\n"
"undef($self->{oSocket});\n"
"}\n"
"}\n"
"\n"
"sub DESTROY {shift->close()}\n"
"\n\n\n\n"
"sub responseBody\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->responseBody'\n"
");\n"
"\n\n"
"return $self->{strResponseBody} if exists($self->{strResponseBody});\n"
"\n\n"
"my $strResponseBody = undef;\n"
"\n"
"if ($self->{iContentLength} != 0)\n"
"{\n"
"\n"
"if ($self->{iContentLength} == -1)\n"
"{\n"
"while (1)\n"
"{\n"
"\n"
"my $strChunkLength = trim($self->readLine());\n"
"my $iChunkLength = hex($strChunkLength);\n"
"\n\n"
"last if ($iChunkLength == 0);\n"
"\n\n"
"$self->SUPER::read(\\$strResponseBody, $iChunkLength, true);\n"
"$self->readLine();\n"
"};\n"
"}\n"
"\n"
"else\n"
"{\n"
"$self->SUPER::read(\\$strResponseBody, $self->{iContentLength}, true);\n"
"}\n"
"\n"
"$self->close();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'rstrResponseBody', value => \\$strResponseBody, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub contentLength {shift->{iContentLength}}\n"
"sub requestHeaderText {trim(shift->{strRequestHeader})}\n"
"sub responseCode {shift->{iResponseCode}}\n"
"sub responseHeader {shift->{hResponseHeader}}\n"
"sub responseHeaderText {trim(shift->{strResponseHeader})}\n"
"sub responseMessage {shift->{strResponseMessage}}\n"
"sub responseProtocol {shift->{strResponseProtocol}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Http/Common.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Http::Common;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"sub httpQuery\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$hQuery,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::httpQuery', \\@_,\n"
"{name => 'hQuery', required => false, trace => true},\n"
");\n"
"\n\n"
"my $strQuery = '';\n"
"\n\n"
"if (ref($hQuery))\n"
"{\n"
"foreach my $strParam (sort(keys(%{$hQuery})))\n"
"{\n"
"\n"
"if (defined($hQuery->{$strParam}))\n"
"{\n"
"$strQuery .= ($strQuery eq '' ? '' : '&') . $strParam . '=' . httpUriEncode($hQuery->{$strParam});\n"
"}\n"
"}\n"
"}\n"
"\n"
"elsif (defined($hQuery))\n"
"{\n"
"$strQuery = $hQuery;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strQuery', value => $strQuery, trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(httpQuery);\n"
"\n\n\n\n"
"sub httpUriEncode\n"
"{\n"
"my $strString = shift;\n"
"my $bPath = shift;\n"
"\n\n"
"my $strEncodedString;\n"
"\n"
"if (defined($strString))\n"
"{\n"
"\n"
"for (my $iIndex = 0; $iIndex < length($strString); $iIndex++)\n"
"{\n"
"my $cChar = substr($strString, $iIndex, 1);\n"
"\n\n"
"if (($cChar ge 'A' && $cChar le 'Z') || ($cChar ge 'a' && $cChar le 'z') || ($cChar ge '0' && $cChar le '9') ||\n"
"$cChar eq '_' || $cChar eq '-' || $cChar eq '~' || $cChar eq '.' || ($bPath && $cChar eq '/'))\n"
"{\n"
"$strEncodedString .= $cChar;\n"
"}\n"
"\n"
"elsif ($cChar eq '/')\n"
"{\n"
"$strEncodedString .= '%2F';\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strEncodedString .= sprintf('%%%02X', ord($cChar));\n"
"}\n"
"}\n"
"}\n"
"\n"
"return $strEncodedString;\n"
"}\n"
"\n"
"push @EXPORT, qw(httpUriEncode);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Ini.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Ini;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname);\n"
"use JSON::PP;\n"
"use Storable qw(dclone);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::LibC qw(:crypto);\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"use constant INI_TRUE => JSON::PP::true;\n"
"push @EXPORT, qw(INI_TRUE);\n"
"use constant INI_FALSE => JSON::PP::false;\n"
"push @EXPORT, qw(INI_FALSE);\n"
"\n\n\n\n"
"use constant INI_SECTION_BACKREST => 'backrest';\n"
"push @EXPORT, qw(INI_SECTION_BACKREST);\n"
"\n"
"use constant INI_KEY_CHECKSUM => 'backrest-checksum';\n"
"push @EXPORT, qw(INI_KEY_CHECKSUM);\n"
"use constant INI_KEY_FORMAT => 'backrest-format';\n"
"push @EXPORT, qw(INI_KEY_FORMAT);\n"
"use constant INI_KEY_VERSION => 'backrest-version';\n"
"push @EXPORT, qw(INI_KEY_VERSION);\n"
"\n"
"use constant INI_SECTION_CIPHER => 'cipher';\n"
"push @EXPORT, qw(INI_SECTION_CIPHER);\n"
"\n"
"use constant INI_KEY_CIPHER_PASS => 'cipher-pass';\n"
"push @EXPORT, qw(INI_KEY_CIPHER_PASS);\n"
"\n\n\n\n"
"use constant INI_COPY_EXT => '.copy';\n"
"push @EXPORT, qw(INI_COPY_EXT);\n"
"\n\n\n\n"
"use constant INI_SORT_FORWARD => 'forward';\n"
"push @EXPORT, qw(INI_SORT_FORWARD);\n"
"use constant INI_SORT_REVERSE => 'reverse';\n"
"push @EXPORT, qw(INI_SORT_REVERSE);\n"
"use constant INI_SORT_NONE => 'none';\n"
"push @EXPORT, qw(INI_SORT_NONE);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"require pgBackRest::Storage::Helper;\n"
"pgBackRest::Storage::Helper->import();\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{strFileName},\n"
"my $bLoad,\n"
"my $strContent,\n"
"$self->{oStorage},\n"
"$self->{iInitFormat},\n"
"$self->{strInitVersion},\n"
"my $bIgnoreMissing,\n"
"$self->{strCipherPass},\n"
"my $strCipherPassSub,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strFileName', trace => true},\n"
"{name => 'bLoad', optional => true, default => true, trace => true},\n"
"{name => 'strContent', optional => true, trace => true},\n"
"{name => 'oStorage', optional => true, default => storageLocal(), trace => true},\n"
"{name => 'iInitFormat', optional => true, default => REPOSITORY_FORMAT, trace => true},\n"
"{name => 'strInitVersion', optional => true, default => PROJECT_VERSION, trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
"{name => 'strCipherPass', optional => true, trace => true},\n"
"{name => 'strCipherPassSub', optional => true, trace => true},\n"
");\n"
"\n"
"if (defined($self->{oStorage}->cipherPassUser()) && !defined($self->{strCipherPass}))\n"
"{\n"
"confess &log(ERROR, 'passphrase is required when storage is encrypted', ERROR_CRYPTO);\n"
"}\n"
"\n\n"
"$self->{bModified} = false;\n"
"\n\n"
"$self->{bExists} = false;\n"
"\n\n"
"if ($bLoad)\n"
"{\n"
"$self->load($bIgnoreMissing);\n"
"}\n"
"\n"
"elsif (defined($strContent))\n"
"{\n"
"$self->{oContent} = iniParse($strContent);\n"
"$self->headerCheck();\n"
"}\n"
"\n\n"
"if (!$self->{bExists} && !defined($strContent))\n"
"{\n"
"$self->numericSet(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, $self->{iInitFormat});\n"
"$self->set(INI_SECTION_BACKREST, INI_KEY_VERSION, undef, $self->{strInitVersion});\n"
"\n\n"
"if (defined($self->{strCipherPass}) && defined($strCipherPassSub))\n"
"{\n"
"$self->set(INI_SECTION_CIPHER, INI_KEY_CIPHER_PASS, undef, $strCipherPassSub);\n"
"}\n"
"elsif ((defined($self->{strCipherPass}) && !defined($strCipherPassSub)) ||\n"
"(!defined($self->{strCipherPass}) && defined($strCipherPassSub)))\n"
"{\n"
"confess &log(ASSERT, 'a user passphrase and sub passphrase are both required when encrypting');\n"
"}\n"
"}\n"
"\n"
"return $self;\n"
"}\n"
"\n\n\n\n"
"sub loadVersion\n"
"{\n"
"my $self = shift;\n"
"my $bCopy = shift;\n"
"my $bIgnoreError = shift;\n"
"\n\n"
"if ($self->{oStorage}->encryptionValid($self->{oStorage}->encrypted($self->{strFileName} . ($bCopy ? INI_COPY_EXT : ''),\n"
"{bIgnoreMissing => $bIgnoreError})))\n"
"{\n"
"\n"
"my $rstrContent = $self->{oStorage}->get(\n"
"$self->{oStorage}->openRead($self->{strFileName} . ($bCopy ? INI_COPY_EXT : ''),\n"
"{bIgnoreMissing => $bIgnoreError, strCipherPass => $self->{strCipherPass}}));\n"
"\n\n"
"if (defined($rstrContent))\n"
"{\n"
"my $rhContent = iniParse($$rstrContent, {bIgnoreInvalid => $bIgnoreError});\n"
"\n\n"
"if (defined($rhContent))\n"
"{\n"
"$self->{oContent} = $rhContent;\n"
"\n\n"
"if (!$self->headerCheck({bIgnoreInvalid => $bIgnoreError}))\n"
"{\n"
"delete($self->{oContent});\n"
"}\n"
"}\n"
"}\n"
"}\n"
"else\n"
"{\n"
"confess &log(ERROR, \"unable to parse '$self->{strFileName}\" . ($bCopy ? INI_COPY_EXT : '') . \"'\" .\n"
"\"\\nHINT: Is or was the repo encrypted?\", ERROR_CRYPTO);\n"
"}\n"
"\n"
"return defined($self->{oContent});\n"
"}\n"
"\n\n\n\n"
"sub load\n"
"{\n"
"my $self = shift;\n"
"my $bIgnoreMissing = shift;\n"
"\n\n"
"if (!$self->loadVersion(false, true))\n"
"{\n"
"if (!$self->loadVersion(true, true))\n"
"{\n"
"return if $bIgnoreMissing;\n"
"\n"
"confess &log(ERROR, \"unable to open $self->{strFileName} or $self->{strFileName}\" . INI_COPY_EXT, ERROR_FILE_MISSING);\n"
"}\n"
"}\n"
"\n"
"$self->{bExists} = true;\n"
"}\n"
"\n\n\n\n"
"sub headerCheck\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bIgnoreInvalid,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->headerCheck', \\@_,\n"
"{name => 'bIgnoreInvalid', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my $bValid = true;\n"
"\n"
"eval\n"
"{\n"
"\n\n"
"my $strChecksum = $self->get(INI_SECTION_BACKREST, INI_KEY_CHECKSUM, undef, false);\n"
"my $strTestChecksum = $self->hash();\n"
"\n"
"if (!defined($strChecksum) || $strChecksum ne $strTestChecksum)\n"
"{\n"
"confess &log(ERROR,\n"
"\"invalid checksum in '$self->{strFileName}', expected '${strTestChecksum}' but found \" .\n"
"(defined($strChecksum) ? \"'${strChecksum}'\" : '[undef]'),\n"
"ERROR_CHECKSUM);\n"
"}\n"
"\n\n"
"my $iFormat = $self->get(INI_SECTION_BACKREST, INI_KEY_FORMAT, undef, false, 0);\n"
"\n"
"if ($iFormat != $self->{iInitFormat})\n"
"{\n"
"confess &log(ERROR,\n"
"\"invalid format in '$self->{strFileName}', expected $self->{iInitFormat} but found ${iFormat}\", ERROR_FORMAT);\n"
"}\n"
"\n\n"
"if (!$self->test(INI_SECTION_BACKREST, INI_KEY_VERSION, undef, $self->{strInitVersion}))\n"
"{\n"
"$self->set(INI_SECTION_BACKREST, INI_KEY_VERSION, undef, $self->{strInitVersion});\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"if (!$bIgnoreInvalid)\n"
"{\n"
"confess $EVAL_ERROR;\n"
"}\n"
"\n\n"
"$bValid = false;\n"
"};\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bValid', value => $bValid, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"push @EXPORT, qw(iniParse);\n"
"\n"
"sub iniParse\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strContent,\n"
"$bRelaxed,\n"
"$bIgnoreInvalid,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::iniParse', \\@_,\n"
"{name => 'strContent', required => false, trace => true},\n"
"{name => 'bRelaxed', optional => true, default => false, trace => true},\n"
"{name => 'bIgnoreInvalid', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my $oContent = undef;\n"
"my $strSection;\n"
"\n\n"
"my $oJSON = JSON::PP->new()->allow_nonref();\n"
"\n\n"
"eval\n"
"{\n"
"\n"
"foreach my $strLine (split(\"\\n\", defined($strContent) ? $strContent : ''))\n"
"{\n"
"$strLine = trim($strLine);\n"
"\n\n"
"if ($strLine ne '' && $strLine !~ '^[ ]*#.*')\n"
"{\n"
"\n"
"if (index($strLine, '[') == 0)\n"
"{\n"
"$strSection = substr($strLine, 1, length($strLine) - 2);\n"
"}\n"
"else\n"
"{\n"
"if (!defined($strSection))\n"
"{\n"
"confess &log(ERROR, \"key/value pair '${strLine}' found outside of a section\", ERROR_CONFIG);\n"
"}\n"
"\n\n"
"my $iIndex = index($strLine, '=');\n"
"\n"
"if ($iIndex == -1)\n"
"{\n"
"confess &log(ERROR, \"unable to find '=' in '${strLine}'\", ERROR_CONFIG);\n"
"}\n"
"\n"
"my $strKey = substr($strLine, 0, $iIndex);\n"
"my $strValue = substr($strLine, $iIndex + 1);\n"
"\n\n"
"if ($bRelaxed)\n"
"{\n"
"if (defined($oContent->{$strSection}{$strKey}))\n"
"{\n"
"if (ref($oContent->{$strSection}{$strKey}) ne 'ARRAY')\n"
"{\n"
"$oContent->{$strSection}{$strKey} = [$oContent->{$strSection}{$strKey}];\n"
"}\n"
"\n"
"push(@{$oContent->{$strSection}{$strKey}}, $strValue);\n"
"}\n"
"else\n"
"{\n"
"$oContent->{$strSection}{$strKey} = $strValue;\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"${$oContent}{$strSection}{$strKey} = $oJSON->decode($strValue);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (!($bRelaxed || defined($oContent)))\n"
"{\n"
"confess &log(ERROR, 'no key/value pairs found', ERROR_CONFIG);\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"if (!$bIgnoreInvalid)\n"
"{\n"
"confess $EVAL_ERROR;\n"
"}\n"
"\n\n"
"undef($oContent);\n"
"};\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oContent', value => $oContent, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub save\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"if ($self->{bModified})\n"
"{\n"
"\n"
"$self->hash();\n"
"\n\n"
"$self->{oStorage}->put($self->{strFileName}, iniRender($self->{oContent}), {strCipherPass => $self->{strCipherPass}});\n"
"$self->{oStorage}->pathSync(dirname($self->{strFileName}));\n"
"$self->{oStorage}->put($self->{strFileName} . INI_COPY_EXT, iniRender($self->{oContent}),\n"
"{strCipherPass => $self->{strCipherPass}});\n"
"$self->{oStorage}->pathSync(dirname($self->{strFileName}));\n"
"$self->{bModified} = false;\n"
"\n\n"
"$self->{bExists} = true;\n"
"\n\n"
"return true;\n"
"}\n"
"\n\n"
"return false;\n"
"}\n"
"\n\n\n\n"
"sub saveCopy\n"
"{\n"
"my $self = shift;\n"
"\n"
"if ($self->{oStorage}->exists($self->{strFileName}))\n"
"{\n"
"confess &log(ASSERT, \"cannot save copy only when '$self->{strFileName}' exists\");\n"
"}\n"
"\n"
"$self->hash();\n"
"$self->{oStorage}->put($self->{strFileName} . INI_COPY_EXT, iniRender($self->{oContent}),\n"
"{strCipherPass => $self->{strCipherPass}});\n"
"}\n"
"\n\n\n\n"
"push @EXPORT, qw(iniRender);\n"
"\n"
"sub iniRender\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oContent,\n"
"$bRelaxed,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::iniRender', \\@_,\n"
"{name => 'oContent', trace => true},\n"
"{name => 'bRelaxed', default => false, trace => true},\n"
");\n"
"\n\n"
"my $strContent = '';\n"
"my $bFirst = true;\n"
"\n\n"
"my $oJSON = JSON::PP->new()->canonical()->allow_nonref();\n"
"\n\n"
"foreach my $strSection (sort(keys(%$oContent)))\n"
"{\n"
"\n"
"if (!$bFirst)\n"
"{\n"
"$strContent .= \"\\n\";\n"
"}\n"
"\n\n"
"$strContent .= \"[${strSection}]\\n\";\n"
"\n\n"
"foreach my $strKey (sort(keys(%{$oContent->{$strSection}})))\n"
"{\n"
"\n"
"my $strValue = ${$oContent}{$strSection}{$strKey};\n"
"\n\n"
"if ($bRelaxed)\n"
"{\n"
"\n"
"if (ref($strValue) eq 'ARRAY')\n"
"{\n"
"foreach my $strArrayValue (@{$strValue})\n"
"{\n"
"$strContent .= \"${strKey}=${strArrayValue}\\n\";\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strContent .= \"${strKey}=${strValue}\\n\";\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strContent .= \"${strKey}=\" . $oJSON->encode($strValue) . \"\\n\";\n"
"}\n"
"}\n"
"\n"
"$bFirst = false;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strContent', value => $strContent, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub hash\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"delete($self->{oContent}{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM});\n"
"\n\n"
"$self->{oContent}{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} =\n"
"cryptoHashOne('sha1', JSON::PP->new()->canonical()->allow_nonref()->encode($self->{oContent}));\n"
"\n"
"return $self->{oContent}{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM};\n"
"}\n"
"\n\n\n\n"
"sub get\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strKey = shift;\n"
"my $strSubKey = shift;\n"
"my $bRequired = shift;\n"
"my $oDefault = shift;\n"
"\n\n"
"if (!defined($strSection))\n"
"{\n"
"confess &log(ASSERT, 'strSection is required');\n"
"}\n"
"\n"
"if (defined($strSubKey) && !defined($strKey))\n"
"{\n"
"confess &log(ASSERT, \"strKey is required when strSubKey '${strSubKey}' is requested\");\n"
"}\n"
"\n\n"
"my $oResult = $self->{oContent}->{$strSection};\n"
"\n"
"if (defined($strKey) && defined($oResult))\n"
"{\n"
"$oResult = $oResult->{$strKey};\n"
"\n"
"if (defined($strSubKey) && defined($oResult))\n"
"{\n"
"$oResult = $oResult->{$strSubKey};\n"
"}\n"
"}\n"
"\n\n"
"if (!defined($oResult))\n"
"{\n"
"\n"
"if (!defined($bRequired) || $bRequired)\n"
"{\n"
"confess &log(ASSERT, \"strSection '$strSection'\" . (defined($strKey) ? \", strKey '$strKey'\" : '') .\n"
"(defined($strSubKey) ? \", strSubKey '$strSubKey'\" : '') . ' is required but not defined');\n"
"}\n"
"\n\n"
"if (defined($oDefault))\n"
"{\n"
"return $oDefault;\n"
"}\n"
"}\n"
"\n"
"return $oResult\n"
"}\n"
"\n\n\n\n"
"sub boolGet\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strKey = shift;\n"
"my $strSubKey = shift;\n"
"my $bRequired = shift;\n"
"my $bDefault = shift;\n"
"\n"
"return $self->get(\n"
"$strSection, $strKey, $strSubKey, $bRequired,\n"
"defined($bDefault) ? ($bDefault ? INI_TRUE : INI_FALSE) : undef) ? true : false;\n"
"}\n"
"\n\n\n\n"
"sub numericGet\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strKey = shift;\n"
"my $strSubKey = shift;\n"
"my $bRequired = shift;\n"
"my $nDefault = shift;\n"
"\n"
"return $self->get($strSection, $strKey, $strSubKey, $bRequired, defined($nDefault) ? $nDefault + 0 : undef) + 0;\n"
"}\n"
"\n\n\n\n"
"sub set\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strKey = shift;\n"
"my $strSubKey = shift;\n"
"my $oValue = shift;\n"
"\n\n"
"if (!(defined($strSection) && defined($strKey)))\n"
"{\n"
"confess &log(ASSERT, 'strSection and strKey are required');\n"
"}\n"
"\n"
"my $oCurrentValue;\n"
"\n"
"if (defined($strSubKey))\n"
"{\n"
"$oCurrentValue = \\$self->{oContent}{$strSection}{$strKey}{$strSubKey};\n"
"}\n"
"else\n"
"{\n"
"$oCurrentValue = \\$self->{oContent}{$strSection}{$strKey};\n"
"}\n"
"\n"
"if (!defined($$oCurrentValue) ||\n"
"defined($oCurrentValue) != defined($oValue) ||\n"
"${dclone($oCurrentValue)} ne ${dclone(\\$oValue)})\n"
"{\n"
"$$oCurrentValue = $oValue;\n"
"\n"
"if (!$self->{bModified})\n"
"{\n"
"$self->{bModified} = true;\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n\n\n\n"
"sub boolSet\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strKey = shift;\n"
"my $strSubKey = shift;\n"
"my $bValue = shift;\n"
"\n"
"$self->set($strSection, $strKey, $strSubKey, $bValue ? INI_TRUE : INI_FALSE);\n"
"}\n"
"\n\n\n\n"
"sub numericSet\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strKey = shift;\n"
"my $strSubKey = shift;\n"
"my $nValue = shift;\n"
"\n"
"$self->set($strSection, $strKey, $strSubKey, defined($nValue) ? $nValue + 0 : undef);\n"
"}\n"
"\n\n\n\n"
"sub remove\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strKey = shift;\n"
"my $strSubKey = shift;\n"
"\n\n"
"if ($self->test($strSection, $strKey, $strSubKey))\n"
"{\n"
"\n"
"if (defined($strSubKey))\n"
"{\n"
"delete($self->{oContent}{$strSection}{$strKey}{$strSubKey});\n"
"}\n"
"\n\n"
"if (defined($strKey))\n"
"{\n"
"if (!defined($strSubKey))\n"
"{\n"
"delete($self->{oContent}{$strSection}{$strKey});\n"
"}\n"
"\n\n"
"if (keys(%{$self->{oContent}{$strSection}}) == 0)\n"
"{\n"
"delete($self->{oContent}{$strSection});\n"
"}\n"
"}\n"
"\n\n"
"if (!defined($strKey))\n"
"{\n"
"delete($self->{oContent}{$strSection});\n"
"}\n"
"\n\n"
"if (!$self->{bModified})\n"
"{\n"
"$self->{bModified} = true;\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n\n\n\n"
"sub keys\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strSortOrder = shift;\n"
"\n"
"if ($self->test($strSection))\n"
"{\n"
"if (!defined($strSortOrder) || $strSortOrder eq INI_SORT_FORWARD)\n"
"{\n"
"return (sort(keys(%{$self->get($strSection)})));\n"
"}\n"
"elsif ($strSortOrder eq INI_SORT_REVERSE)\n"
"{\n"
"return (sort {$b cmp $a} (keys(%{$self->get($strSection)})));\n"
"}\n"
"elsif ($strSortOrder eq INI_SORT_NONE)\n"
"{\n"
"return (keys(%{$self->get($strSection)}));\n"
"}\n"
"else\n"
"{\n"
"confess &log(ASSERT, \"invalid strSortOrder '${strSortOrder}'\");\n"
"}\n"
"}\n"
"\n"
"my @stryEmptyArray;\n"
"return @stryEmptyArray;\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub test\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strValue = shift;\n"
"my $strSubValue = shift;\n"
"my $strTest = shift;\n"
"\n\n"
"my $strResult = $self->get($strSection, $strValue, $strSubValue, false);\n"
"\n\n"
"if (defined($strResult))\n"
"{\n"
"\n"
"if (defined($strTest))\n"
"{\n"
"\n"
"return ($strResult . '') eq ($strTest . '') ? true : false;\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n\n\n\n"
"sub boolTest\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strValue = shift;\n"
"my $strSubValue = shift;\n"
"my $bTest = shift;\n"
"\n"
"return $self->test($strSection, $strValue, $strSubValue, defined($bTest) ? ($bTest ? INI_TRUE : INI_FALSE) : undef);\n"
"}\n"
"\n\n\n\n"
"sub cipherPassSub\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->get(INI_SECTION_CIPHER, INI_KEY_CIPHER_PASS, undef, false);\n"
"}\n"
"\n\n\n\n"
"sub modified {shift->{bModified}}\n"
"sub exists {shift->{bExists}}\n"
"sub cipherPass {shift->{strCipherPass}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Io/Base.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Io::Base;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Scalar::Util qw(blessed);\n"
"\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"use constant COMMON_IO_BASE => __PACKAGE__;\n"
"push @EXPORT, qw(COMMON_IO_BASE);\n"
"\n\n\n\n"
"use constant COMMON_IO_BUFFER_MAX => 4194304;\n"
"push @EXPORT, qw(COMMON_IO_BUFFER_MAX);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{strId},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strId', trace => true},\n"
");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub error\n"
"{\n"
"my $self = shift;\n"
"my $iCode = shift;\n"
"my $strMessage = shift;\n"
"my $strDetail = shift;\n"
"\n"
"logErrorResult($iCode, $strMessage, $strDetail);\n"
"}\n"
"\n\n\n\n"
"sub result\n"
"{\n"
"my $self = shift;\n"
"my $strModule = shift;\n"
"\n"
"if (!defined($strModule))\n"
"{\n"
"return $self->{rhResult};\n"
"}\n"
"\n"
"return $self->{rhResult}{$strModule};\n"
"}\n"
"\n\n\n\n"
"sub resultAll\n"
"{\n"
"shift->{rhResult};\n"
"}\n"
"\n\n\n\n"
"sub resultSet\n"
"{\n"
"my $self = shift;\n"
"my $strModule = shift;\n"
"my $xResult = shift;\n"
"\n"
"$self->{rhResult}{$strModule} = $xResult;\n"
"}\n"
"\n\n\n\n"
"sub className {blessed(shift)}\n"
"sub id {shift->{strId}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Io/Buffered.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Io::Buffered;\n"
"use parent 'pgBackRest::Common::Io::Filter';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use IO::Select;\n"
"use Time::HiRes qw(gettimeofday);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Base;\n"
"use pgBackRest::Common::Io::Handle;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Wait;\n"
"\n\n\n\n"
"use constant COMMON_IO_BUFFERED => __PACKAGE__;\n"
"push @EXPORT, qw(COMMON_IO_BUFFERED);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oParent,\n"
"$iTimeout,\n"
"$lBufferMax,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oParent', trace => true},\n"
"{name => 'iTimeout', default => 0, trace => true},\n"
"{name => 'lBufferMax', default => COMMON_IO_BUFFER_MAX, trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($oParent);\n"
"bless $self, $class;\n"
"\n\n"
"$self->handleReadSet($self->handleRead());\n"
"\n\n"
"$self->{iTimeout} = $iTimeout;\n"
"$self->{lBufferMax} = $lBufferMax;\n"
"\n\n"
"$self->{tBuffer} = '';\n"
"$self->{lBufferSize} = 0;\n"
"$self->{lBufferPos} = 0;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub read\n"
"{\n"
"my $self = shift;\n"
"my $tBufferRef = shift;\n"
"my $iRequestSize = shift;\n"
"my $bBlock = shift;\n"
"\n\n"
"my $iRemainingSize = $iRequestSize;\n"
"\n\n"
"my $lBufferRemaining = $self->{lBufferSize} - $self->{lBufferPos};\n"
"\n"
"if ($lBufferRemaining > 0)\n"
"{\n"
"my $iReadSize = $iRequestSize < $lBufferRemaining ? $iRequestSize : $lBufferRemaining;\n"
"\n"
"$$tBufferRef .= substr($self->{tBuffer}, $self->{lBufferPos}, $iReadSize);\n"
"$self->{lBufferPos} += $iReadSize;\n"
"\n"
"$iRemainingSize -= $iReadSize;\n"
"}\n"
"\n\n\n"
"my $fTimeStart = gettimeofday();\n"
"my $fRemaining = $self->timeout();\n"
"\n"
"while ($iRemainingSize > 0 && $fRemaining > 0)\n"
"{\n"
"\n"
"if ($self->pending() || $self->{oReadSelect}->can_read($fRemaining))\n"
"{\n"
"\n"
"my $iReadSize = $self->parent()->read($tBufferRef, $iRemainingSize);\n"
"\n\n"
"if ($iReadSize == 0)\n"
"{\n"
"if ($bBlock)\n"
"{\n"
"$self->error(ERROR_FILE_READ, \"unable to read ${iRequestSize} byte(s) due to EOF from \" . $self->id());\n"
"}\n"
"else\n"
"{\n"
"return $iRequestSize - $iRemainingSize;\n"
"}\n"
"}\n"
"\n\n"
"$iRemainingSize -= $iReadSize;\n"
"}\n"
"\n\n"
"$fRemaining = $self->timeout() - (gettimeofday() - $fTimeStart);\n"
"};\n"
"\n\n"
"if ($iRemainingSize != 0 && $bBlock)\n"
"{\n"
"$self->error(\n"
"ERROR_FILE_READ, \"unable to read ${iRequestSize} byte(s) after \" . $self->timeout() . ' second(s) from ' . $self->id());\n"
"}\n"
"\n"
"return $iRequestSize - $iRemainingSize;\n"
"}\n"
"\n\n\n\n"
"sub readLine\n"
"{\n"
"my $self = shift;\n"
"my $bIgnoreEOF = shift;\n"
"my $bError = shift;\n"
"\n\n"
"my $iLineFeedPos = index($self->{tBuffer}, \"\\n\", $self->{lBufferPos});\n"
"\n\n"
"if ($iLineFeedPos == -1)\n"
"{\n"
"my $fRemaining = $self->timeout();\n"
"my $fTimeStart = gettimeofday();\n"
"\n\n"
"do\n"
"{\n"
"\n"
"if ($self->{lBufferPos} != 0)\n"
"{\n"
"$self->{tBuffer} = substr($self->{tBuffer}, $self->{lBufferPos});\n"
"$self->{lBufferSize} = $self->{lBufferSize} - $self->{lBufferPos};\n"
"$self->{lBufferPos} = 0;\n"
"}\n"
"\n\n"
"my $iBufferRead = 0;\n"
"\n"
"if ($self->pending() || $self->{oReadSelect}->can_read($fRemaining))\n"
"{\n"
"$iBufferRead = $self->parent()->read(\n"
"\\$self->{tBuffer},\n"
"$self->{lBufferSize} >= $self->bufferMax() ? $self->bufferMax() : $self->bufferMax() - $self->{lBufferSize});\n"
"\n\n"
"if ($iBufferRead == 0)\n"
"{\n"
"\n"
"if (defined($bIgnoreEOF) && $bIgnoreEOF)\n"
"{\n"
"return;\n"
"}\n"
"\n\n"
"$self->error(ERROR_FILE_READ, 'unexpected EOF reading line from ' . $self->id());\n"
"}\n"
"}\n"
"\n\n"
"if ($iBufferRead > 0)\n"
"{\n"
"$self->{lBufferSize} += $iBufferRead;\n"
"\n"
"$iLineFeedPos = index($self->{tBuffer}, \"\\n\");\n"
"}\n"
"\n\n"
"if ($iLineFeedPos == -1)\n"
"{\n"
"$fRemaining = $self->timeout() - (gettimeofday() - $fTimeStart);\n"
"}\n"
"}\n"
"while ($iLineFeedPos == -1 && $fRemaining > 0);\n"
"\n\n"
"if ($iLineFeedPos == -1)\n"
"{\n"
"if (!defined($bError) || $bError)\n"
"{\n"
"$self->error(\n"
"ERROR_FILE_READ, 'unable to read line after ' . $self->timeout() . ' second(s) from ' . $self->id());\n"
"}\n"
"\n"
"return;\n"
"}\n"
"}\n"
"\n\n"
"my $strLine = substr($self->{tBuffer}, $self->{lBufferPos}, $iLineFeedPos - $self->{lBufferPos});\n"
"$self->{lBufferPos} = $iLineFeedPos + 1;\n"
"\n"
"return $strLine;\n"
"}\n"
"\n\n\n\n"
"sub writeLine\n"
"{\n"
"my $self = shift;\n"
"my $strBuffer = shift;\n"
"\n"
"$strBuffer .= \"\\n\";\n"
"return $self->parent()->write(\\$strBuffer);\n"
"}\n"
"\n\n\n\n"
"sub timeout {shift->{iTimeout}};\n"
"sub bufferMax {shift->{lBufferMax}};\n"
"\n\n\n\n"
"sub handleReadSet\n"
"{\n"
"my $self = shift;\n"
"my $fhRead = shift;\n"
"\n"
"$self->parent()->handleReadSet($fhRead);\n"
"\n\n"
"$self->{oReadSelect} = IO::Select->new();\n"
"$self->{oReadSelect}->add($self->handleRead());\n"
"\n\n"
"$self->{bPending} = defined($fhRead) && $fhRead->can('pending') ? true : false;\n"
"}\n"
"\n\n\n\n"
"sub pending\n"
"{\n"
"my $self = shift;\n"
"\n"
"return ($self->{bPending} && $self->handleRead()->pending() ? true : false);\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Io/Filter.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Io::Filter;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Scalar::Util qw(blessed);\n"
"\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{oParent},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oParent', trace => true},\n"
");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub bufferMax {shift->{oParent}->bufferMax()};\n"
"sub className {shift->{oParent}->className()};\n"
"sub close {shift->{oParent}->close()};\n"
"sub eof {shift->{oParent}->eof()};\n"
"sub eofSet {shift->{oParent}->eofSet(@_)};\n"
"sub error {shift->{oParent}->error(@_)};\n"
"sub id {shift->{oParent}->id()};\n"
"sub handleRead {shift->{oParent}->handleRead()};\n"
"sub handleReadSet {shift->{oParent}->handleReadSet(@_)};\n"
"sub handleWrite {shift->{oParent}->handleWrite()};\n"
"sub handleWriteSet {shift->{oParent}->handleWriteSet(@_)};\n"
"sub name {shift->{oParent}->name()};\n"
"sub read {shift->{oParent}->read(@_)};\n"
"sub readLine {shift->{oParent}->readLine(@_)};\n"
"sub result {shift->{oParent}->result(@_)};\n"
"sub resultAll {shift->{oParent}->resultAll()};\n"
"sub resultSet {shift->{oParent}->resultSet(@_)};\n"
"sub size {shift->{oParent}->size()};\n"
"sub timeout {shift->{oParent}->timeout()};\n"
"sub write {shift->{oParent}->write(@_)};\n"
"sub writeLine {shift->{oParent}->writeLine(@_)};\n"
"\n\n\n\n"
"sub parent {shift->{oParent}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Io/Handle.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Io::Handle;\n"
"use parent 'pgBackRest::Common::Io::Base';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"use constant COMMON_IO_HANDLE => __PACKAGE__;\n"
"push @EXPORT, qw(COMMON_IO_HANDLE);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strId,\n"
"$fhRead,\n"
"$fhWrite,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strId', trace => true},\n"
"{name => 'fhRead', required => false, trace => true},\n"
"{name => 'fhWrite', required => false, trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($strId);\n"
"bless $self, $class;\n"
"\n\n"
"$self->handleReadSet($fhRead) if defined($fhRead);\n"
"$self->handleWriteSet($fhWrite) if defined($fhWrite);\n"
"\n\n"
"$self->{lSize} = 0;\n"
"\n\n"
"$self->eofSet(false);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub eof\n"
"{\n"
"return shift->{bEOF};\n"
"}\n"
"\n\n\n\n"
"sub eofSet\n"
"{\n"
"my $self = shift;\n"
"my $bEOF = shift;\n"
"\n"
"$self->{bEOF} = $bEOF;\n"
"}\n"
"\n\n\n\n"
"sub read\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"my $iSize = shift;\n"
"\n\n"
"my $iActualSize;\n"
"\n"
"eval\n"
"{\n"
"$iActualSize = sysread($self->handleRead(), $$rtBuffer, $iSize, defined($$rtBuffer) ? length($$rtBuffer) : 0);\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"$self->error(ERROR_FILE_READ, 'unable to read from ' . $self->id(), $EVAL_ERROR);\n"
"};\n"
"\n\n\n"
"defined($iActualSize)\n"
"or $self->error(ERROR_FILE_READ, 'unable to read from ' . $self->id(), $OS_ERROR);\n"
"\n\n"
"$self->{lSize} += $iActualSize;\n"
"\n\n"
"$self->eofSet($iActualSize == 0 ? true : false);\n"
"\n"
"return $iActualSize;\n"
"}\n"
"\n\n\n\n"
"sub write\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"\n\n"
"my $iActualSize;\n"
"\n"
"eval\n"
"{\n"
"$iActualSize = syswrite($self->handleWrite(), $$rtBuffer);\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"$self->error(ERROR_FILE_WRITE, 'unable to write to ' . $self->id(), $EVAL_ERROR);\n"
"};\n"
"\n\n\n"
"defined($iActualSize)\n"
"or $self->error(ERROR_FILE_WRITE, 'unable to write to ' . $self->id(), $OS_ERROR);\n"
"\n\n"
"$self->{lSize} += $iActualSize;\n"
"\n"
"return $iActualSize;\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"if (defined($self->{lSize}))\n"
"{\n"
"$self->resultSet(COMMON_IO_HANDLE, $self->{lSize});\n"
"undef($self->{lSize});\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n\n\n\n"
"sub handleRead {return shift->{fhHandleRead}}\n"
"sub handleReadSet {my $self = shift; $self->{fhHandleRead} = shift}\n"
"sub handleWrite {return shift->{fhHandleWrite}}\n"
"sub handleWriteSet {my $self = shift; $self->{fhHandleWrite} = shift}\n"
"sub size {shift->{lSize}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Io/Process.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Io::Process;\n"
"use parent 'pgBackRest::Common::Io::Filter';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use IPC::Open3 qw(open3);\n"
"use POSIX qw(:sys_wait_h);\n"
"use Symbol 'gensym';\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Buffered;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Wait;\n"
"\n\n\n\n"
"use constant COMMON_IO_PROCESS => __PACKAGE__;\n"
"push @EXPORT, qw(COMMON_IO_PROCESS);\n"
"\n\n\n\n"
"use constant IO_ERROR_TIMEOUT => 5;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oParent,\n"
"$strCommand,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oParent', trace => true},\n"
"{name => 'strCommand', trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($oParent);\n"
"bless $self, $class;\n"
"\n\n"
"my ($iProcessId, $fhRead, $fhWrite, $fhReadError);\n"
"$fhReadError = gensym;\n"
"\n"
"$iProcessId = IPC::Open3::open3($fhWrite, $fhRead, $fhReadError, $strCommand);\n"
"\n\n"
"$self->handleReadSet($fhRead);\n"
"$self->handleWriteSet($fhWrite);\n"
"\n\n"
"$self->{iProcessId} = $iProcessId;\n"
"$self->{fhReadError} = $fhReadError;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub error\n"
"{\n"
"my $self = shift;\n"
"my $iCode = shift;\n"
"my $strMessage = shift;\n"
"my $strDetail = shift;\n"
"my $bClose = shift;\n"
"\n"
"if (defined($self->{iProcessId}))\n"
"{\n"
"my $oWait = waitInit(defined($iCode) ? IO_ERROR_TIMEOUT : 0);\n"
"\n"
"do\n"
"{\n"
"\n"
"my $iResult = waitpid($self->{iProcessId}, $bClose ? 0 : WNOHANG);\n"
"\n\n"
"if ($iResult != 0)\n"
"{\n"
"\n"
"my $iExitStatus = $iResult == -1 ? 255 : ${^CHILD_ERROR_NATIVE} >> 8;\n"
"\n\n"
"my $strError;\n"
"my $oIoError = new pgBackRest::Common::Io::Buffered(\n"
"new pgBackRest::Common::Io::Handle($self->id(), $self->{fhReadError}), 5, $self->bufferMax());\n"
"\n"
"while (defined(my $strLine = $oIoError->readLine(true, false)))\n"
"{\n"
"$strError .= (defined($strError) ? \"\\n\" : '') . $strLine;\n"
"}\n"
"\n"
"delete($self->{iProcessId});\n"
"\n"
"if (!$bClose || $iExitStatus != 0 || defined($strError))\n"
"{\n"
"my $iErrorCode =\n"
"$iExitStatus >= ERROR_MINIMUM && $iExitStatus <= ERROR_MAXIMUM ? $iExitStatus : ERROR_FILE_READ;\n"
"\n"
"logErrorResult(\n"
"$iErrorCode, $self->id() . ' terminated unexpectedly' .\n"
"($iExitStatus != 255 ? sprintf(' [%03d]', $iExitStatus) : ''),\n"
"$strError);\n"
"}\n"
"}\n"
"}\n"
"while (waitMore($oWait));\n"
"\n"
"if (defined($iCode))\n"
"{\n"
"$self->parent()->error($iCode, $strMessage, $strDetail);\n"
"}\n"
"}\n"
"else\n"
"{\n"
"confess &log(ASSERT, 'cannot call error() after process has been closed');\n"
"}\n"
"}\n"
"\n\n\n\n"
"sub processId\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{iProcessId};\n"
"}\n"
"\n\n\n\n"
"sub writeLine\n"
"{\n"
"my $self = shift;\n"
"my $strBuffer = shift;\n"
"\n\n\n"
"$self->error();\n"
"\n"
"return $self->parent()->writeLine($strBuffer);\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n"
"if (defined($self->{iProcessId}))\n"
"{\n"
"$self->error(undef, undef, undef, true);\n"
"\n\n"
"$self->parent()->close();\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Lock.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Lock;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Fcntl qw(:DEFAULT :flock);\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n\n\n"
"sub lockPathCreate\n"
"{\n"
"storageLocal()->pathCreate(cfgOption(CFGOPT_LOCK_PATH), {strMode => '770', bIgnoreExists => true, bCreateParent => true});\n"
"}\n"
"\n\n\n\n\n\n"
"sub lockStopFileName\n"
"{\n"
"my $strStanza = shift;\n"
"\n"
"return cfgOption(CFGOPT_LOCK_PATH) . (defined($strStanza) ? \"/${strStanza}\" : '/all') . '.stop';\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub lockStop\n"
"{\n"
"\n"
"lockPathCreate();\n"
"\n\n"
"my $strStopFile = lockStopFileName(cfgOption(CFGOPT_STANZA, false));\n"
"\n\n"
"if (-e $strStopFile)\n"
"{\n"
"&log(WARN, 'stop file already exists' .\n"
"(cfgOptionTest(CFGOPT_STANZA) ? ' for stanza ' . cfgOption(CFGOPT_STANZA) : ' for all stanzas'));\n"
"return false;\n"
"}\n"
"\n\n"
"sysopen(my $hStopHandle, $strStopFile, O_WRONLY | O_CREAT, oct(640))\n"
"or confess &log(ERROR, \"unable to open stop file ${strStopFile}\", ERROR_FILE_OPEN);\n"
"close($hStopHandle);\n"
"\n\n"
"if (cfgOption(CFGOPT_FORCE))\n"
"{\n"
"my $strLockPath = cfgOption(CFGOPT_LOCK_PATH);\n"
"\n"
"opendir(my $hPath, $strLockPath)\n"
"or confess &log(ERROR, \"unable to open lock path ${strLockPath}\", ERROR_PATH_OPEN);\n"
"\n"
"my @stryFileList = grep(!/^(\\.)|(\\.\\.)$/i, readdir($hPath));\n"
"\n\n"
"foreach my $strFile (sort(@stryFileList))\n"
"{\n"
"my $hLockHandle;\n"
"my $strLockFile = \"${strLockPath}/${strFile}\";\n"
"\n\n"
"next if ($strFile =~ /\\.stop$/);\n"
"\n\n"
"if (!sysopen($hLockHandle, $strLockFile, O_RDONLY))\n"
"{\n"
"&log(WARN, \"unable to open lock file ${strLockFile}\");\n"
"next;\n"
"}\n"
"\n\n\n"
"if (flock($hLockHandle, LOCK_EX | LOCK_NB))\n"
"{\n"
"unlink($strLockFile);\n"
"close($hLockHandle);\n"
"next;\n"
"}\n"
"\n\n"
"my $iProcessId = trim(readline($hLockHandle));\n"
"\n\n"
"if (defined($iProcessId))\n"
"{\n"
"if (!kill('TERM', $iProcessId))\n"
"{\n"
"&log(WARN, \"unable to send term signal to process ${iProcessId}\");\n"
"}\n"
"\n"
"&log(INFO, \"sent term signal to process ${iProcessId}\");\n"
"}\n"
"\n"
"{\n"
"unlink($strLockFile);\n"
"close($hLockHandle);\n"
"next;\n"
"}\n"
"}\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n"
"push @EXPORT, qw(lockStop);\n"
"\n\n\n\n\n\n"
"sub lockStopTest\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bStanzaStopRequired,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::lockStopTest', \\@_,\n"
"{name => 'bStanzaStopRequired', optional => true, default => false}\n"
");\n"
"\n"
"my $bStopExists = false;\n"
"\n\n"
"if (cfgOptionTest(CFGOPT_STANZA))\n"
"{\n"
"\n"
"my $strStopFile = lockStopFileName(cfgOption(CFGOPT_STANZA));\n"
"\n"
"if (-e $strStopFile)\n"
"{\n"
"\n"
"if ($bStanzaStopRequired)\n"
"{\n"
"$bStopExists = true;\n"
"}\n"
"else\n"
"{\n"
"confess &log(ERROR, 'stop file exists for stanza ' . cfgOption(CFGOPT_STANZA), ERROR_STOP);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (!$bStanzaStopRequired)\n"
"{\n"
"\n"
"my $strStopFile = lockStopFileName();\n"
"\n"
"if (-e $strStopFile)\n"
"{\n"
"confess &log(ERROR, 'stop file exists for all stanzas', ERROR_STOP);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bStopExists', value => $bStopExists}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(lockStopTest);\n"
"\n\n\n\n\n\n"
"sub lockStart\n"
"{\n"
"\n"
"my $strStopFile = lockStopFileName(cfgOption(CFGOPT_STANZA, false));\n"
"\n\n"
"if (!-e $strStopFile)\n"
"{\n"
"&log(WARN, 'stop file does not exist' . (cfgOptionTest(CFGOPT_STANZA) ? ' for stanza ' . cfgOption(CFGOPT_STANZA) : ''));\n"
"return false;\n"
"}\n"
"\n\n"
"unlink($strStopFile)\n"
"or confess &log(ERROR, \"unable to remove ${strStopFile}: $!\");\n"
"\n"
"return true;\n"
"}\n"
"\n"
"push @EXPORT, qw(lockStart);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Log.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Log;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess longmess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Fcntl qw(:DEFAULT :flock);\n"
"use File::Basename qw(dirname);\n"
"use Scalar::Util qw(blessed reftype);\n"
"use Time::HiRes qw(gettimeofday usleep);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::String;\n"
"\n\n\n\n"
"use constant true => 1;\n"
"push @EXPORT, qw(true);\n"
"use constant false => 0;\n"
"push @EXPORT, qw(false);\n"
"\n\n\n\n"
"use constant TRACE => 'TRACE';\n"
"push @EXPORT, qw(TRACE);\n"
"use constant DEBUG => 'DEBUG';\n"
"push @EXPORT, qw(DEBUG);\n"
"use constant DETAIL => 'DETAIL';\n"
"push @EXPORT, qw(DETAIL);\n"
"use constant INFO => 'INFO';\n"
"push @EXPORT, qw(INFO);\n"
"use constant WARN => 'WARN';\n"
"push @EXPORT, qw(WARN);\n"
"use constant PROTOCOL => 'PROTOCOL';\n"
"push @EXPORT, qw(PROTOCOL);\n"
"use constant ERROR => 'ERROR';\n"
"push @EXPORT, qw(ERROR);\n"
"use constant ASSERT => 'ASSERT';\n"
"push @EXPORT, qw(ASSERT);\n"
"use constant OFF => 'OFF';\n"
"push @EXPORT, qw(OFF);\n"
"\n\n\n\n"
"my %oLogLevelRank;\n"
"\n"
"$oLogLevelRank{TRACE}{rank} = 8;\n"
"$oLogLevelRank{DEBUG}{rank} = 7;\n"
"$oLogLevelRank{DETAIL}{rank} = 6;\n"
"$oLogLevelRank{INFO}{rank} = 5;\n"
"$oLogLevelRank{WARN}{rank} = 4;\n"
"$oLogLevelRank{PROTOCOL}{rank} = 3;\n"
"$oLogLevelRank{ERROR}{rank} = 2;\n"
"$oLogLevelRank{ASSERT}{rank} = 1;\n"
"$oLogLevelRank{OFF}{rank} = 0;\n"
"\n\n\n\n"
"my $hLogFile = undef;\n"
"my $strLogFileCache = undef;\n"
"\n"
"my $strLogLevelFile = OFF;\n"
"my $strLogLevelConsole = OFF;\n"
"my $strLogLevelStdErr = WARN;\n"
"my $bLogTimestamp = true;\n"
"\n\n"
"my $iLogProcessSize = 2;\n"
"\n\n"
"my $bLogFileExists;\n"
"my $bLogFileFirst;\n"
"\n\n"
"my $bLogDisable = 0;\n"
"\n\n"
"my $bLogWarnOnError = 0;\n"
"\n\n"
"my $oErrorLast;\n"
"\n\n"
"my $bTest = false;\n"
"my $fTestDelay;\n"
"my $oTestPoint;\n"
"\n\n\n\n"
"use constant TEST => 'TEST';\n"
"push @EXPORT, qw(TEST);\n"
"use constant TEST_ENCLOSE => 'PgBaCkReStTeSt';\n"
"push @EXPORT, qw(TEST_ENCLOSE);\n"
"\n"
"use constant TEST_MANIFEST_BUILD => 'MANIFEST-BUILD';\n"
"push @EXPORT, qw(TEST_MANIFEST_BUILD);\n"
"use constant TEST_BACKUP_RESUME => 'BACKUP-RESUME';\n"
"push @EXPORT, qw(TEST_BACKUP_RESUME);\n"
"use constant TEST_BACKUP_NORESUME => 'BACKUP-NORESUME';\n"
"push @EXPORT, qw(TEST_BACKUP_NORESUME);\n"
"use constant TEST_BACKUP_START => 'BACKUP-START';\n"
"push @EXPORT, qw(TEST_BACKUP_START);\n"
"use constant TEST_BACKUP_STOP => 'BACKUP-STOP';\n"
"push @EXPORT, qw(TEST_BACKUP_STOP);\n"
"use constant TEST_KEEP_ALIVE => 'KEEP_ALIVE';\n"
"push @EXPORT, qw(TEST_KEEP_ALIVE);\n"
"use constant TEST_ARCHIVE_PUSH_ASYNC_START => 'ARCHIVE-PUSH-ASYNC-START';\n"
"push @EXPORT, qw(TEST_ARCHIVE_PUSH_ASYNC_START);\n"
"\n\n\n\n"
"sub logFileSet\n"
"{\n"
"my $oStorage = shift;\n"
"my $strFile = shift;\n"
"my $bLogFileFirstParam = shift;\n"
"\n\n"
"if ($strLogLevelFile ne OFF)\n"
"{\n"
"$oStorage->pathCreate(dirname($strFile), {strMode => '0770', bIgnoreExists => true, bCreateParent => true});\n"
"\n"
"$strFile .= '.log';\n"
"$bLogFileExists = -e $strFile ? true : false;\n"
"$bLogFileFirst = defined($bLogFileFirstParam) ? $bLogFileFirstParam : false;\n"
"\n"
"if (!sysopen($hLogFile, $strFile, O_WRONLY | O_CREAT | O_APPEND, oct('0660')))\n"
"{\n"
"logErrorResult(ERROR_FILE_OPEN, \"unable to open log file '${strFile}'\", $OS_ERROR);\n"
"}\n"
"\n\n"
"if (defined($strLogFileCache))\n"
"{\n"
"logBanner();\n"
"syswrite($hLogFile, $strLogFileCache);\n"
"undef($strLogFileCache);\n"
"}\n"
"}\n"
"}\n"
"\n"
"push @EXPORT, qw(logFileSet);\n"
"\n\n\n\n\n\n"
"sub logBanner\n"
"{\n"
"if ($bLogFileFirst)\n"
"{\n"
"if ($bLogFileExists)\n"
"{\n"
"syswrite($hLogFile, \"\\n\");\n"
"}\n"
"\n"
"syswrite($hLogFile, \"-------------------PROCESS START-------------------\\n\");\n"
"}\n"
"\n"
"$bLogFileFirst = false;\n"
"}\n"
"\n\n\n\n"
"sub logLevelSet\n"
"{\n"
"my $strLevelFileParam = shift;\n"
"my $strLevelConsoleParam = shift;\n"
"my $strLevelStdErrParam = shift;\n"
"my $bLogTimestampParam = shift;\n"
"my $iLogProcessMax = shift;\n"
"\n"
"if (defined($strLevelFileParam))\n"
"{\n"
"if (!defined($oLogLevelRank{uc($strLevelFileParam)}{rank}))\n"
"{\n"
"confess &log(ERROR, \"file log level ${strLevelFileParam} does not exist\");\n"
"}\n"
"\n"
"$strLogLevelFile = uc($strLevelFileParam);\n"
"}\n"
"\n"
"if (defined($strLevelConsoleParam))\n"
"{\n"
"if (!defined($oLogLevelRank{uc($strLevelConsoleParam)}{rank}))\n"
"{\n"
"confess &log(ERROR, \"console log level ${strLevelConsoleParam} does not exist\");\n"
"}\n"
"\n"
"$strLogLevelConsole = uc($strLevelConsoleParam);\n"
"}\n"
"\n"
"if (defined($strLevelStdErrParam))\n"
"{\n"
"if (!defined($oLogLevelRank{uc($strLevelStdErrParam)}{rank}))\n"
"{\n"
"confess &log(ERROR, \"stdout log level ${strLevelStdErrParam} does not exist\");\n"
"}\n"
"\n"
"$strLogLevelStdErr = uc($strLevelStdErrParam);\n"
"}\n"
"\n"
"if (defined($bLogTimestampParam))\n"
"{\n"
"$bLogTimestamp = $bLogTimestampParam;\n"
"}\n"
"\n"
"if (defined($iLogProcessMax))\n"
"{\n"
"$iLogProcessSize = $iLogProcessMax > 99 ? 3 : 2;\n"
"}\n"
"}\n"
"\n"
"push @EXPORT, qw(logLevelSet);\n"
"\n\n\n\n"
"sub logDisable\n"
"{\n"
"$bLogDisable++;\n"
"}\n"
"\n"
"push @EXPORT, qw(logDisable);\n"
"\n\n\n\n"
"sub logEnable\n"
"{\n"
"$bLogDisable--;\n"
"}\n"
"\n"
"push @EXPORT, qw(logEnable);\n"
"\n\n\n\n"
"sub logWarnOnErrorDisable\n"
"{\n"
"$bLogWarnOnError--;\n"
"}\n"
"\n"
"push @EXPORT, qw(logWarnOnErrorDisable);\n"
"\n\n\n\n"
"sub logWarnOnErrorEnable\n"
"{\n"
"$bLogWarnOnError++;\n"
"}\n"
"\n"
"push @EXPORT, qw(logWarnOnErrorEnable);\n"
"\n\n\n\n\n\n"
"use constant DEBUG_PARAM => '()';\n"
"\n"
"sub logDebugParam\n"
"{\n"
"my $strFunction = shift;\n"
"my $oyParamRef = shift;\n"
"\n"
"return logDebugProcess($strFunction, DEBUG_PARAM, undef, $oyParamRef, @_);\n"
"}\n"
"\n"
"push @EXPORT, qw(logDebugParam);\n"
"\n\n\n\n\n\n"
"use constant DEBUG_RETURN => '=>';\n"
"\n"
"sub logDebugReturn\n"
"{\n"
"my $strFunction = shift;\n"
"\n"
"return logDebugProcess($strFunction, DEBUG_RETURN, undef, undef, @_);\n"
"}\n"
"\n"
"push @EXPORT, qw(logDebugReturn);\n"
"\n\n\n\n\n\n"
"use constant DEBUG_MISC => '';\n"
"\n"
"sub logDebugMisc\n"
"{\n"
"my $strFunction = shift;\n"
"my $strDetail = shift;\n"
"\n"
"return logDebugProcess($strFunction, DEBUG_MISC, $strDetail, undef, @_);\n"
"}\n"
"\n"
"push @EXPORT, qw(logDebugMisc);\n"
"\n\n\n\n"
"sub logDebugProcess\n"
"{\n"
"my $strFunction = shift;\n"
"my $strType = shift;\n"
"my $strDetail = shift;\n"
"my $oyParamRef = shift;\n"
"\n"
"my $iIndex = 0;\n"
"my $oParamHash = {};\n"
"my @oyResult;\n"
"my $bLogTrace = true;\n"
"\n"
"if ($strType eq DEBUG_PARAM)\n"
"{\n"
"push @oyResult, $strFunction;\n"
"}\n"
"\n\n"
"my $oParam = shift;\n"
"my $bOptionalBlock = false;\n"
"\n\n"
"$strFunction =~ s/^pgBackRest[^\\:]*\\:\\://;\n"
"\n"
"while (defined($oParam))\n"
"{\n"
"my $strParamName = $$oParam{name};\n"
"my $bParamOptional = defined($oParam->{optional}) && $oParam->{optional};\n"
"my $bParamRequired = !defined($oParam->{required}) || $oParam->{required};\n"
"my $oValue;\n"
"\n\n"
"$oParamHash->{$strParamName}{redact} = $oParam->{redact} ? true : false;\n"
"\n\n"
"if ($bParamOptional)\n"
"{\n"
"if (defined($oParam->{required}))\n"
"{\n"
"confess &log(ASSERT, \"cannot define 'required' for optional parameter '${strParamName}'\");\n"
"}\n"
"\n"
"$bParamRequired = false;\n"
"$bOptionalBlock = true;\n"
"}\n"
"\n\n"
"if ($bParamOptional != $bOptionalBlock)\n"
"{\n"
"confess &log(ASSERT, \"non-optional parameter '${strParamName}' invalid after optional parameters\");\n"
"}\n"
"\n\n"
"if ($strType eq DEBUG_PARAM)\n"
"{\n"
"if ($bParamOptional)\n"
"{\n"
"$oValue = $$oyParamRef[$iIndex]->{$strParamName};\n"
"}\n"
"else\n"
"{\n"
"$oValue = $$oyParamRef[$iIndex];\n"
"}\n"
"\n"
"if (defined($oValue))\n"
"{\n"
"push(@oyResult, $oValue);\n"
"}\n"
"else\n"
"{\n"
"push(@oyResult, $${oParam}{default});\n"
"$$oParamHash{$strParamName}{default} = true;\n"
"}\n"
"\n"
"$oValue = $oyResult[-1];\n"
"\n"
"if (!defined($oValue) && $bParamRequired)\n"
"{\n"
"confess &log(ASSERT, \"${strParamName} is required in ${strFunction}\");\n"
"}\n"
"}\n"
"else\n"
"{\n"
"if (ref($$oParam{value}) eq 'ARRAY')\n"
"{\n"
"if (defined($$oParam{ref}) && $$oParam{ref})\n"
"{\n"
"push(@oyResult, $$oParam{value});\n"
"}\n"
"else\n"
"{\n"
"push(@oyResult, @{$$oParam{value}});\n"
"}\n"
"}\n"
"else\n"
"{\n"
"push(@oyResult, $$oParam{value});\n"
"}\n"
"\n"
"$oValue = $$oParam{value};\n"
"}\n"
"\n"
"if (!defined($$oParam{log}) || $$oParam{log})\n"
"{\n"
"\n\n"
"if (ref($oValue) eq 'HASH' && !blessed($oValue))\n"
"{\n"
"$$oParamHash{$strParamName}{value} = '[hash]';\n"
"}\n"
"\n"
"else\n"
"{\n"
"$$oParamHash{$strParamName}{value} = $oValue;\n"
"}\n"
"\n\n"
"if (!($strParamName eq 'self') &&\n"
"(!defined($$oParam{trace}) || !$$oParam{trace}))\n"
"{\n"
"$bLogTrace = false;\n"
"}\n"
"}\n"
"\n\n"
"$oParam = shift;\n"
"\n"
"if (!$bParamOptional)\n"
"{\n"
"$iIndex++;\n"
"}\n"
"}\n"
"\n"
"if (defined($strDetail) && $iIndex == 0)\n"
"{\n"
"$bLogTrace = false;\n"
"}\n"
"\n"
"logDebugOut($strFunction, $strType, $strDetail, $oParamHash, $bLogTrace ? TRACE : DEBUG);\n"
"\n\n"
"if (@oyResult == 1)\n"
"{\n"
"return $oyResult[0];\n"
"}\n"
"\n\n"
"return @oyResult;\n"
"}\n"
"\n\n\n\n"
"sub logDebugBuild\n"
"{\n"
"my $strValue = shift;\n"
"\n"
"my $rResult;\n"
"\n\n"
"if (!defined($strValue))\n"
"{\n"
"$rResult = \\'[undef]';\n"
"}\n"
"\n"
"elsif (!ref($strValue))\n"
"{\n"
"$rResult = \\$strValue;\n"
"}\n"
"\n"
"elsif (ref($strValue) eq 'HASH')\n"
"{\n"
"my $strValueHash;\n"
"\n"
"for my $strSubValue (sort(keys(%{$strValue})))\n"
"{\n"
"$strValueHash .=\n"
"(defined($strValueHash) ? ', ' : '{') . \"${strSubValue} => \" . ${logDebugBuild($strValue->{$strSubValue})};\n"
"}\n"
"\n"
"$rResult = \\(defined($strValueHash) ? $strValueHash . '}' : '{}');\n"
"}\n"
"\n"
"elsif (ref($strValue) eq 'ARRAY')\n"
"{\n"
"my $strValueArray;\n"
"\n"
"for my $strSubValue (@{$strValue})\n"
"{\n"
"$strValueArray .= (defined($strValueArray) ? ', ' : '(') . ${logDebugBuild($strSubValue)};\n"
"}\n"
"\n"
"$rResult = \\(defined($strValueArray) ? $strValueArray . ')' : '()');\n"
"}\n"
"\n"
"else\n"
"{\n"
"$rResult = \\('[object]');\n"
"}\n"
"\n"
"return $rResult;\n"
"}\n"
"\n"
"push @EXPORT, qw(logDebugBuild);\n"
"\n\n\n\n"
"use constant DEBUG_STRING_MAX_LEN => 1024;\n"
"\n"
"sub logDebugOut\n"
"{\n"
"my $strFunction = shift;\n"
"my $strType = shift;\n"
"my $strMessage = shift;\n"
"my $oParamHash = shift;\n"
"my $strLevel = shift;\n"
"\n"
"$strLevel = defined($strLevel) ? $strLevel : DEBUG;\n"
"\n"
"if ($oLogLevelRank{$strLevel}{rank} <= $oLogLevelRank{$strLogLevelConsole}{rank} ||\n"
"$oLogLevelRank{$strLevel}{rank} <= $oLogLevelRank{$strLogLevelFile}{rank} ||\n"
"$oLogLevelRank{$strLevel}{rank} <= $oLogLevelRank{$strLogLevelStdErr}{rank})\n"
"{\n"
"if (defined($oParamHash))\n"
"{\n"
"my $strParamSet;\n"
"\n"
"foreach my $strParam (sort(keys(%$oParamHash)))\n"
"{\n"
"if (defined($strParamSet))\n"
"{\n"
"$strParamSet .= ', ';\n"
"}\n"
"\n"
"my $strValueRef = defined($oParamHash->{$strParam}{value}) ? logDebugBuild($oParamHash->{$strParam}{value}) : undef;\n"
"my $bDefault =\n"
"defined($$strValueRef) && defined($$oParamHash{$strParam}{default}) ? $$oParamHash{$strParam}{default} : false;\n"
"\n"
"$strParamSet .=\n"
"\"${strParam} = \" .\n"
"($oParamHash->{$strParam}{redact} && defined($$strValueRef) ? '<redacted>' :\n"
"($bDefault ? '<' : '') .\n"
"(defined($$strValueRef) ?\n"
"($strParam =~ /^(b|is)/ ? ($$strValueRef ? 'true' : 'false'):\n"
"(length($$strValueRef) > DEBUG_STRING_MAX_LEN ?\n"
"substr($$strValueRef, 0, DEBUG_STRING_MAX_LEN) . ' ... <truncated>':\n"
"$$strValueRef)) : '[undef]') .\n"
"($bDefault ? '>' : ''));\n"
"}\n"
"\n"
"if (defined($strMessage))\n"
"{\n"
"$strMessage = $strMessage . (defined($strParamSet) ? \": ${strParamSet}\" : '');\n"
"}\n"
"else\n"
"{\n"
"$strMessage = $strParamSet;\n"
"}\n"
"}\n"
"\n"
"&log($strLevel, \"${strFunction}${strType}\" . (defined($strMessage) ? \": $strMessage\" : ''));\n"
"}\n"
"}\n"
"\n\n\n\n"
"sub logException\n"
"{\n"
"my $oException = shift;\n"
"\n"
"return &log($oException->level(), $oException->message(), $oException->code(), undef, undef, undef, $oException->extra());\n"
"}\n"
"\n"
"push @EXPORT, qw(logException);\n"
"\n\n\n\n"
"sub logErrorResult\n"
"{\n"
"my $iCode = shift;\n"
"my $strMessage = shift;\n"
"my $strResult = shift;\n"
"\n"
"confess &log(ERROR, $strMessage . (defined($strResult) ? ': ' . trim($strResult) : ''), $iCode);\n"
"}\n"
"\n"
"push @EXPORT, qw(logErrorResult);\n"
"\n\n\n\n"
"sub log\n"
"{\n"
"my $strLevel = shift;\n"
"my $strMessage = shift;\n"
"my $iCode = shift;\n"
"my $bSuppressLog = shift;\n"
"my $iIndent = shift;\n"
"my $iProcessId = shift;\n"
"my $rExtra = shift;\n"
"\n\n"
"$bSuppressLog = defined($bSuppressLog) ? $bSuppressLog : false;\n"
"\n\n"
"if (!defined($rExtra))\n"
"{\n"
"$rExtra =\n"
"{\n"
"bLogFile => false,\n"
"bLogConsole => false,\n"
"};\n"
"}\n"
"\n\n"
"my $strMessageFormat = $strMessage;\n"
"my $iLogLevelRank = $oLogLevelRank{$strLevel}{rank};\n"
"\n\n"
"if ($strLevel eq TEST)\n"
"{\n"
"if (!defined($oTestPoint) || !defined($$oTestPoint{lc($strMessage)}))\n"
"{\n"
"return;\n"
"}\n"
"\n"
"$iLogLevelRank = $oLogLevelRank{TRACE}{rank} + 1;\n"
"$strMessageFormat = TEST_ENCLOSE . '-' . $strMessageFormat . '-' . TEST_ENCLOSE;\n"
"}\n"
"\n"
"elsif (!defined($iLogLevelRank))\n"
"{\n"
"confess &log(ASSERT, \"log level ${strLevel} does not exist\");\n"
"}\n"
"\n\n"
"if (!defined($strMessageFormat))\n"
"{\n"
"$strMessageFormat = '(undefined)';\n"
"}\n"
"\n\n"
"if ($strLevel eq ASSERT)\n"
"{\n"
"$iCode = ERROR_ASSERT;\n"
"}\n"
"elsif ($strLevel eq ERROR && !defined($iCode))\n"
"{\n"
"$iCode = ERROR_UNKNOWN;\n"
"}\n"
"\n"
"$strMessageFormat = (defined($iCode) ? sprintf('[%03d]: ', $iCode) : '') . $strMessageFormat;\n"
"\n\n"
"if (defined($iIndent))\n"
"{\n"
"my $strIndent = ' ' x $iIndent;\n"
"$strMessageFormat =~ s/\\n/\\n${strIndent}/g;\n"
"}\n"
"else\n"
"{\n"
"\n"
"$bLogTimestamp ?\n"
"$strMessageFormat =~ s/\\n/\\n /g :\n"
"$strMessageFormat =~ s/\\n/\\n /g\n"
"}\n"
"\n\n"
"if ($strLevel eq TRACE || $strLevel eq TEST)\n"
"{\n"
"$strMessageFormat =~ s/\\n/\\n /g;\n"
"$strMessageFormat = ' ' . $strMessageFormat;\n"
"}\n"
"elsif ($strLevel eq DEBUG)\n"
"{\n"
"$strMessageFormat =~ s/\\n/\\n /g;\n"
"$strMessageFormat = ' ' . $strMessageFormat;\n"
"}\n"
"\n\n"
"my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);\n"
"\n\n\n"
"my $strDisplayLevel = ($bLogWarnOnError && $strLevel eq ERROR ? WARN : $strLevel);\n"
"my $iLogDisplayLevelRank = ($bLogWarnOnError && $strLevel eq ERROR ? $oLogLevelRank{$strDisplayLevel}{rank} : $iLogLevelRank);\n"
"\n"
"$strMessageFormat =\n"
"($bLogTimestamp ? timestampFormat() . sprintf('.%03d ', (gettimeofday() - int(gettimeofday())) * 1000) : '') .\n"
"sprintf('P%0*d', $iLogProcessSize, defined($iProcessId) ? $iProcessId : 0) .\n"
"(' ' x (7 - length($strDisplayLevel))) . \"${strDisplayLevel}: ${strMessageFormat}\\n\";\n"
"\n\n"
"if (!$bLogDisable)\n"
"{\n"
"\n"
"if (!$rExtra->{bLogConsole} && $iLogDisplayLevelRank <= $oLogLevelRank{$strLogLevelStdErr}{rank})\n"
"{\n"
"if ($strLogLevelStdErr ne PROTOCOL)\n"
"{\n"
"syswrite(*STDERR, $strDisplayLevel . (defined($iCode) ? sprintf(' [%03d]: ', $iCode) : '') . ': ');\n"
"}\n"
"\n"
"syswrite(*STDERR, \"${strMessage}\\n\");\n"
"$rExtra->{bLogConsole} = true;\n"
"}\n"
"\n"
"elsif (!$rExtra->{bLogConsole} && $iLogDisplayLevelRank <= $oLogLevelRank{$strLogLevelConsole}{rank} ||\n"
"$bTest && $strLevel eq TEST)\n"
"{\n"
"if (!$bSuppressLog)\n"
"{\n"
"syswrite(*STDOUT, $strMessageFormat);\n"
"\n\n\n\n\n\n\n\n"
"}\n"
"\n\n"
"if ($bTest && $strLevel eq TEST && $fTestDelay > 0)\n"
"{\n"
"usleep($fTestDelay * 1000000);\n"
"}\n"
"\n"
"$rExtra->{bLogConsole} = true;\n"
"}\n"
"\n\n"
"if (!$rExtra->{bLogLogFile} && $iLogDisplayLevelRank <= $oLogLevelRank{$strLogLevelFile}{rank})\n"
"{\n"
"if (defined($hLogFile) || (defined($strLogLevelFile) && $strLogLevelFile ne OFF))\n"
"{\n"
"if (!$bSuppressLog)\n"
"{\n"
"if (defined($hLogFile))\n"
"{\n"
"logBanner();\n"
"syswrite($hLogFile, $strMessageFormat);\n"
"}\n"
"else\n"
"{\n"
"$strLogFileCache .= $strMessageFormat;\n"
"}\n"
"\n"
"if ($strDisplayLevel eq ASSERT ||\n"
"($strDisplayLevel eq ERROR && ($strLogLevelFile eq DEBUG || $strLogLevelFile eq TRACE)))\n"
"{\n"
"my $strStackTrace = longmess() . \"\\n\";\n"
"$strStackTrace =~ s/\\n/\\n /g;\n"
"\n"
"if (defined($hLogFile))\n"
"{\n"
"syswrite($hLogFile, $strStackTrace);\n"
"}\n"
"else\n"
"{\n"
"$strLogFileCache .= $strStackTrace;\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n"
"$rExtra->{bLogFile} = true;\n"
"}\n"
"}\n"
"\n\n"
"if (defined($iCode))\n"
"{\n"
"$oErrorLast = new pgBackRest::Common::Exception($strLevel, $iCode, $strMessage, longmess(), $rExtra);\n"
"return $oErrorLast;\n"
"}\n"
"\n\n"
"return $strMessage;\n"
"}\n"
"\n"
"push @EXPORT, qw(log);\n"
"\n\n\n\n"
"sub logErrorLast\n"
"{\n"
"return $oErrorLast;\n"
"}\n"
"\n"
"push @EXPORT, qw(logErrorLast);\n"
"\n\n\n\n\n\n"
"sub testSet\n"
"{\n"
"my $bTestParam = shift;\n"
"my $fTestDelayParam = shift;\n"
"my $oTestPointParam = shift;\n"
"\n\n"
"$bTest = defined($bTestParam) ? $bTestParam : false;\n"
"$fTestDelay = defined($bTestParam) ? $fTestDelayParam : $fTestDelay;\n"
"$oTestPoint = $oTestPointParam;\n"
"\n\n"
"if ($bTest && !defined($fTestDelay))\n"
"{\n"
"confess &log(ASSERT, 'iTestDelay must be provided when bTest is true');\n"
"}\n"
"\n\n"
"if (!($fTestDelay >= 0 && $fTestDelay <= 600))\n"
"{\n"
"confess &log(ERROR, 'test-delay must be between 1 and 600 seconds');\n"
"}\n"
"}\n"
"\n"
"push @EXPORT, qw(testSet);\n"
"\n\n\n\n"
"sub testCheck\n"
"{\n"
"my $strLog = shift;\n"
"my $strTest = shift;\n"
"\n"
"return index($strLog, TEST_ENCLOSE . '-' . $strTest . '-' . TEST_ENCLOSE) != -1;\n"
"}\n"
"\n"
"push @EXPORT, qw(testCheck);\n"
"\n\n\n\n"
"sub logLevel\n"
"{\n"
"return ($strLogLevelFile, $strLogLevelConsole, $strLogLevelStdErr, $bLogTimestamp);\n"
"}\n"
"\n"
"push @EXPORT, qw(logLevel);\n"
"\n\n\n\n"
"sub logFileCacheClear\n"
"{\n"
"undef($strLogFileCache);\n"
"}\n"
"\n"
"push @EXPORT, qw(logFileCacheClear);\n"
"\n\n\n\n"
"sub logFileCache\n"
"{\n"
"return $strLogFileCache;\n"
"}\n"
"\n"
"push @EXPORT, qw(logFileCache);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/String.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::String;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess longmess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname);\n"
"\n\n\n\n\n\n"
"sub trim\n"
"{\n"
"my $strBuffer = shift;\n"
"\n"
"if (!defined($strBuffer))\n"
"{\n"
"return;\n"
"}\n"
"\n"
"$strBuffer =~ s/^\\s+|\\s+$//g;\n"
"\n"
"return $strBuffer;\n"
"}\n"
"\n"
"push @EXPORT, qw(trim);\n"
"\n\n\n\n"
"sub coalesce\n"
"{\n"
"foreach my $strParam (@_)\n"
"{\n"
"if (defined($strParam))\n"
"{\n"
"return $strParam;\n"
"}\n"
"}\n"
"\n"
"return;\n"
"}\n"
"\n"
"push @EXPORT, qw(coalesce);\n"
"\n\n\n\n\n\n"
"sub commonPrefix\n"
"{\n"
"my $strString1 = shift;\n"
"my $strString2 = shift;\n"
"\n"
"my $iCommonLen = 0;\n"
"my $iCompareLen = length($strString1) < length($strString2) ? length($strString1) : length($strString2);\n"
"\n"
"for (my $iIndex = 0; $iIndex < $iCompareLen; $iIndex++)\n"
"{\n"
"if (substr($strString1, $iIndex, 1) ne substr($strString2, $iIndex, 1))\n"
"{\n"
"last;\n"
"}\n"
"\n"
"$iCommonLen++;\n"
"}\n"
"\n"
"return $iCommonLen;\n"
"}\n"
"\n"
"push @EXPORT, qw(commonPrefix);\n"
"\n\n\n\n\n\n"
"sub boolFormat\n"
"{\n"
"return shift() ? 'true' : 'false';\n"
"}\n"
"\n"
"push @EXPORT, qw(boolFormat);\n"
"\n\n\n\n\n\n"
"sub fileSizeFormat\n"
"{\n"
"my $lFileSize = shift;\n"
"\n"
"if ($lFileSize < 1024)\n"
"{\n"
"return $lFileSize . 'B';\n"
"}\n"
"\n"
"if ($lFileSize < (1024 * 1024))\n"
"{\n"
"return (int($lFileSize / 102.4) / 10) . 'KB';\n"
"}\n"
"\n"
"if ($lFileSize < (1024 * 1024 * 1024))\n"
"{\n"
"return (int($lFileSize / 1024 / 102.4) / 10) . 'MB';\n"
"}\n"
"\n"
"return (int($lFileSize / 1024 / 1024 / 102.4) / 10) . 'GB';\n"
"}\n"
"\n"
"push @EXPORT, qw(fileSizeFormat);\n"
"\n\n\n\n\n\n"
"sub timestampFormat\n"
"{\n"
"my $strFormat = shift;\n"
"my $lTime = shift;\n"
"\n"
"if (!defined($strFormat))\n"
"{\n"
"$strFormat = '%4d-%02d-%02d %02d:%02d:%02d';\n"
"}\n"
"\n"
"if (!defined($lTime))\n"
"{\n"
"$lTime = time();\n"
"}\n"
"\n"
"my ($iSecond, $iMinute, $iHour, $iMonthDay, $iMonth, $iYear, $iWeekDay, $iYearDay, $bIsDst) = localtime($lTime);\n"
"\n"
"if ($strFormat eq \"%4d\")\n"
"{\n"
"return sprintf($strFormat, $iYear + 1900)\n"
"}\n"
"else\n"
"{\n"
"return sprintf($strFormat, $iYear + 1900, $iMonth + 1, $iMonthDay, $iHour, $iMinute, $iSecond);\n"
"}\n"
"}\n"
"\n"
"push @EXPORT, qw(timestampFormat);\n"
"\n\n\n\n"
"sub timestampFileFormat\n"
"{\n"
"my $strFormat = shift;\n"
"my $lTime = shift;\n"
"\n"
"return timestampFormat(defined($strFormat) ? $strFormat : '%4d%02d%02d-%02d%02d%02d', $lTime);\n"
"}\n"
"\n"
"push @EXPORT, qw(timestampFileFormat);\n"
"\n\n\n\n"
"sub stringSplit\n"
"{\n"
"my $strString = shift;\n"
"my $strChar = shift;\n"
"my $iLength = shift;\n"
"\n"
"if (length($strString) <= $iLength)\n"
"{\n"
"return $strString, undef;\n"
"}\n"
"\n"
"my $iPos = index($strString, $strChar);\n"
"\n"
"if ($iPos == -1)\n"
"{\n"
"return $strString, undef;\n"
"}\n"
"\n"
"my $iNewPos = $iPos;\n"
"\n"
"while ($iNewPos != -1 && $iNewPos + 1 < $iLength)\n"
"{\n"
"$iPos = $iNewPos;\n"
"$iNewPos = index($strString, $strChar, $iPos + 1);\n"
"}\n"
"\n"
"return substr($strString, 0, $iPos + 1), substr($strString, $iPos + 1);\n"
"}\n"
"\n"
"push @EXPORT, qw(stringSplit);\n"
"\n\n\n\n\n\n"
"sub regexPrefix\n"
"{\n"
"my $strExpression = shift;\n"
"my $strPrefix;\n"
"\n\n"
"if (defined($strExpression) && $strExpression =~ /^\\^/)\n"
"{\n"
"($strPrefix) = substr($strExpression, 1) =~ /^[^\\.\\^\\$\\*\\+\\-\\?\\(\\)\\[\\]\\{\\}\\\\\\|\\ ]+/g;\n"
"}\n"
"\n"
"return $strPrefix;\n"
"}\n"
"\n"
"push @EXPORT, qw(regexPrefix);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Wait.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Wait;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname);\n"
"use POSIX qw(ceil);\n"
"use Time::HiRes qw(gettimeofday usleep);\n"
"\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"use constant WAIT_TIME_MINIMUM => .1;\n"
"push @EXPORT, qw(WAIT_TIME_MINIMUM);\n"
"\n\n\n\n"
"sub waitRemainder\n"
"{\n"
"my $bWait = shift;\n"
"\n"
"my $lTimeBegin = gettimeofday();\n"
"\n"
"if (!defined($bWait) || $bWait)\n"
"{\n"
"my $lSleepMs = ceil(((int($lTimeBegin) + 1.05) - $lTimeBegin) * 1000);\n"
"\n"
"usleep($lSleepMs * 1000);\n"
"\n"
"&log(TRACE, \"WAIT_REMAINDER: slept ${lSleepMs}ms: begin ${lTimeBegin}, end \" . gettimeofday());\n"
"}\n"
"\n"
"return int($lTimeBegin);\n"
"}\n"
"\n"
"push @EXPORT, qw(waitRemainder);\n"
"\n\n\n\n"
"sub waitHiRes\n"
"{\n"
"my $fSecond = shift;\n"
"\n"
"return usleep($fSecond * 1000000);\n"
"}\n"
"\n"
"push @EXPORT, qw(waitHiRes);\n"
"\n\n\n\n"
"sub waitInit\n"
"{\n"
"my $fWaitTime = shift;\n"
"my $fSleep = shift;\n"
"\n\n"
"my $oWait = {};\n"
"\n\n"
"if (!defined($fWaitTime) || $fWaitTime == 0)\n"
"{\n"
"return;\n"
"}\n"
"\n\n"
"if ($fWaitTime < .1)\n"
"{\n"
"confess &log(ASSERT, 'fWaitTime cannot be < .1');\n"
"}\n"
"\n\n"
"if (!defined($fSleep))\n"
"{\n"
"if ($fWaitTime >= 1)\n"
"{\n"
"$$oWait{sleep} = .1;\n"
"}\n"
"else\n"
"{\n"
"$$oWait{sleep} = $fWaitTime / 10;\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if ($fSleep >= $fWaitTime)\n"
"{\n"
"confess &log(ASSERT, 'fSleep > fWaitTime - this is useless');\n"
"}\n"
"}\n"
"\n\n"
"$$oWait{wait_time} = $fWaitTime;\n"
"$$oWait{time_begin} = gettimeofday();\n"
"$$oWait{time_end} = $$oWait{time_begin};\n"
"\n"
"return $oWait;\n"
"}\n"
"\n"
"push @EXPORT, qw(waitInit);\n"
"\n\n\n\n"
"sub waitMore\n"
"{\n"
"my $oWait = shift;\n"
"\n\n"
"if (!defined($oWait))\n"
"{\n"
"return false;\n"
"}\n"
"\n\n"
"waitHiRes($$oWait{sleep});\n"
"\n\n"
"$$oWait{time_end} = gettimeofday();\n"
"\n\n"
"if ((gettimeofday() - $$oWait{time_begin}) < $$oWait{wait_time})\n"
"{\n"
"return true;\n"
"}\n"
"\n\n"
"my $fSleepNext = $$oWait{sleep} + (defined($$oWait{sleep_prev}) ? $$oWait{sleep_prev} : 0);\n"
"\n"
"if ($fSleepNext > $$oWait{wait_time} - ($$oWait{time_end} - $$oWait{time_begin}))\n"
"{\n"
"$fSleepNext = ($$oWait{wait_time} - ($$oWait{time_end} - $$oWait{time_begin})) + .001\n"
"}\n"
"\n"
"$$oWait{sleep_prev} = $$oWait{sleep};\n"
"$$oWait{sleep} = $fSleepNext;\n"
"\n"
"return false;\n"
"}\n"
"\n"
"push @EXPORT, qw(waitMore);\n"
"\n\n\n\n"
"sub waitInterval\n"
"{\n"
"my $oWait = shift;\n"
"\n\n"
"if (!defined($oWait))\n"
"{\n"
"confess &log(ERROR, \"oWait is not defined\");\n"
"}\n"
"\n"
"return int(($$oWait{time_end} - $$oWait{time_begin}) * 1000) / 1000;\n"
"}\n"
"\n"
"push @EXPORT, qw(waitInterval);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Common/Xml.pm",
.data =
"\n\n\n"
"package pgBackRest::Common::Xml;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use XML::LibXML;\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"use constant XML_HEADER => '<?xml version=\"1.0\" encoding=\"UTF-8\"?>';\n"
"push @EXPORT, qw(XML_HEADER);\n"
"\n\n\n\n"
"sub xmlFromText\n"
"{\n"
"my $strText = shift;\n"
"\n"
"return XML::LibXML::Text->new($strText)->toString();\n"
"}\n"
"\n"
"push @EXPORT, qw(xmlFromText);\n"
"\n\n\n\n"
"sub xmlParse\n"
"{\n"
"my $rstrXml = shift;\n"
"\n"
"my $oXml = XML::LibXML->load_xml(string => $rstrXml)->documentElement();\n"
"\n"
"return $oXml;\n"
"}\n"
"\n"
"push @EXPORT, qw(xmlParse);\n"
"\n\n\n\n"
"sub xmlTagChildren\n"
"{\n"
"my $oXml = shift;\n"
"my $strTag = shift;\n"
"\n"
"return $oXml->getChildrenByTagName($strTag);\n"
"}\n"
"\n"
"push @EXPORT, qw(xmlTagChildren);\n"
"\n\n\n\n"
"sub xmlTagText\n"
"{\n"
"my $oXml = shift;\n"
"my $strTag = shift;\n"
"my $bRequired = shift;\n"
"\n\n\n"
"my @oyTag = $oXml->getElementsByTagName($strTag);\n"
"\n\n"
"if (@oyTag > 1)\n"
"{\n"
"confess &log(ERROR, @oyTag . \" '${strTag}' tag(s) exist, but only one was expected\", ERROR_FORMAT);\n"
"}\n"
"elsif (@oyTag == 0)\n"
"{\n"
"if (!defined($bRequired) || $bRequired)\n"
"{\n"
"confess &log(ERROR, \"tag '${strTag}' does not exist\", ERROR_FORMAT);\n"
"}\n"
"}\n"
"else\n"
"{\n"
"return $oyTag[0]->textContent();\n"
"}\n"
"\n"
"return;\n"
"}\n"
"\n"
"push @EXPORT, qw(xmlTagText);\n"
"\n\n\n\n"
"sub xmlTagBool\n"
"{\n"
"my $oXml = shift;\n"
"my $strTag = shift;\n"
"my $bRequired = shift;\n"
"\n\n\n"
"my $strContent = xmlTagText($oXml, $strTag, $bRequired);\n"
"\n"
"if (defined($strContent))\n"
"{\n"
"if ($strContent eq 'true')\n"
"{\n"
"return true;\n"
"}\n"
"elsif ($strContent eq 'false')\n"
"{\n"
"return false;\n"
"}\n"
"else\n"
"{\n"
"confess &log(ERROR, \"invalid boolean value '${strContent}' for tag '${strTag}'\", ERROR_FORMAT);\n"
"}\n"
"}\n"
"\n"
"return;\n"
"}\n"
"\n"
"push @EXPORT, qw(xmlTagBool);\n"
"\n\n\n\n"
"sub xmlTagInt\n"
"{\n"
"my $oXml = shift;\n"
"my $strTag = shift;\n"
"my $bRequired = shift;\n"
"\n\n\n"
"my $iContent = xmlTagText($oXml, $strTag, $bRequired);\n"
"\n"
"if (defined($iContent))\n"
"{\n"
"eval\n"
"{\n"
"$iContent = $iContent + 0;\n"
"return 1;\n"
"}\n"
"or do\n"
"{\n"
"confess &log(ERROR, \"invalid integer value '${iContent}' for tag '${strTag}'\", ERROR_FORMAT);\n"
"}\n"
"}\n"
"\n"
"return $iContent;\n"
"}\n"
"\n"
"push @EXPORT, qw(xmlTagInt);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Config/Config.pm",
.data =
"\n\n\n"
"package pgBackRest::Config::Config;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use JSON::PP;\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Io::Base;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::LibC qw(:config :configDefine);\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"push(@EXPORT, @{$pgBackRest::LibC::EXPORT_TAGS{config}});\n"
"push(@EXPORT, @{$pgBackRest::LibC::EXPORT_TAGS{configDefine}});\n"
"\n\n\n\n"
"use constant CFGDEF_SOURCE_CONFIG => 'config';\n"
"push @EXPORT, qw(CFGDEF_SOURCE_CONFIG);\n"
"use constant CFGDEF_SOURCE_PARAM => 'param';\n"
"push @EXPORT, qw(CFGDEF_SOURCE_PARAM);\n"
"use constant CFGDEF_SOURCE_DEFAULT => 'default';\n"
"push @EXPORT, qw(CFGDEF_SOURCE_DEFAULT);\n"
"\n\n\n\n"
"use constant CFGDEF_SECTION_GLOBAL => 'global';\n"
"push @EXPORT, qw(CFGDEF_SECTION_GLOBAL);\n"
"use constant CFGDEF_SECTION_STANZA => 'stanza';\n"
"push @EXPORT, qw(CFGDEF_SECTION_STANZA);\n"
"\n\n\n\n"
"my %oOption;\n"
"my $strCommand;\n"
"my $bInitLog = false;\n"
"\n\n\n\n"
"sub configLogging\n"
"{\n"
"my $bLogInitForce = shift;\n"
"\n"
"if ($bInitLog || (defined($bLogInitForce) && $bLogInitForce))\n"
"{\n"
"logLevelSet(\n"
"cfgOptionValid(CFGOPT_LOG_LEVEL_FILE) ? cfgOption(CFGOPT_LOG_LEVEL_FILE) : OFF,\n"
"cfgOptionValid(CFGOPT_LOG_LEVEL_CONSOLE) ? cfgOption(CFGOPT_LOG_LEVEL_CONSOLE) : OFF,\n"
"cfgOptionValid(CFGOPT_LOG_LEVEL_STDERR) ? cfgOption(CFGOPT_LOG_LEVEL_STDERR) : OFF,\n"
"cfgOptionValid(CFGOPT_LOG_TIMESTAMP) ? cfgOption(CFGOPT_LOG_TIMESTAMP) : undef,\n"
"cfgOptionValid(CFGOPT_PROCESS_MAX) ? cfgOption(CFGOPT_PROCESS_MAX) : undef);\n"
"\n"
"$bInitLog = true;\n"
"}\n"
"}\n"
"\n"
"push @EXPORT, qw(configLogging);\n"
"\n\n\n\n\n\n"
"sub configLoad\n"
"{\n"
"my $bInitLogging = shift;\n"
"my $strBackRestBin = shift;\n"
"my $strCommandName = shift;\n"
"my $rstrConfigJson = shift;\n"
"\n\n"
"projectBinSet($strBackRestBin);\n"
"\n\n"
"$strCommand = $strCommandName;\n"
"\n"
"eval\n"
"{\n"
"%oOption = %{(JSON::PP->new()->allow_nonref())->decode($$rstrConfigJson)};\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"confess &log(ASSERT, \"unable to parse config JSON\");\n"
"};\n"
"\n\n"
"for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)\n"
"{\n"
"my $strOptionName = cfgOptionName($iOptionId);\n"
"\n\n"
"if (defined($oOption{$strOptionName}))\n"
"{\n"
"\n"
"if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_BOOLEAN && defined($oOption{$strOptionName}{value}))\n"
"{\n"
"$oOption{$strOptionName}{value} = $oOption{$strOptionName}{value} eq INI_TRUE ? true : false;\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"$oOption{$strOptionName}{valid} = false;\n"
"}\n"
"}\n"
"\n\n\n\n"
"if (!defined($bInitLogging) || $bInitLogging)\n"
"{\n"
"configLogging(true);\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n"
"push @EXPORT, qw(configLoad);\n"
"\n\n\n\n"
"sub cfgOptionIdFromIndex\n"
"{\n"
"my $iOptionId = shift;\n"
"my $iIndex = shift;\n"
"\n\n"
"$iIndex = defined($iIndex) ? $iIndex : 1;\n"
"my $strPrefix = cfgDefOptionPrefix($iOptionId);\n"
"\n"
"if (!defined($strPrefix))\n"
"{\n"
"if ($iIndex > 1)\n"
"{\n"
"confess &log(ASSERT, \"'\" . cfgOptionName($iOptionId) . \"' option does not allow indexing\");\n"
"}\n"
"\n"
"return $iOptionId;\n"
"}\n"
"\n"
"return cfgOptionId(\"${strPrefix}${iIndex}\" . substr(cfgOptionName($iOptionId), index(cfgOptionName($iOptionId), '-')));\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgOptionIdFromIndex);\n"
"\n\n\n\n"
"sub cfgOptionSource\n"
"{\n"
"my $iOptionId = shift;\n"
"\n"
"cfgOptionValid($iOptionId, true);\n"
"\n"
"return $oOption{cfgOptionName($iOptionId)}{source};\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgOptionSource);\n"
"\n\n\n\n"
"sub cfgOptionValid\n"
"{\n"
"my $iOptionId = shift;\n"
"my $bError = shift;\n"
"\n\n"
"my $iCommandId;\n"
"\n"
"if (defined($strCommand))\n"
"{\n"
"$iCommandId = cfgCommandId($strCommand);\n"
"}\n"
"\n"
"if (defined($iCommandId) && cfgDefOptionValid($iCommandId, $iOptionId))\n"
"{\n"
"return true;\n"
"}\n"
"\n"
"if (defined($bError) && $bError)\n"
"{\n"
"my $strOption = cfgOptionName($iOptionId);\n"
"\n"
"if (!defined($oOption{$strOption}))\n"
"{\n"
"confess &log(ASSERT, \"option '${strOption}' does not exist\");\n"
"}\n"
"\n"
"confess &log(ASSERT, \"option '${strOption}' not valid for command '\" . cfgCommandName(cfgCommandGet()) . \"'\");\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgOptionValid);\n"
"\n\n\n\n"
"sub cfgOption\n"
"{\n"
"my $iOptionId = shift;\n"
"my $bRequired = shift;\n"
"\n"
"cfgOptionValid($iOptionId, true);\n"
"\n"
"my $strOption = cfgOptionName($iOptionId);\n"
"\n"
"if (!defined($oOption{$strOption}{value}) && (!defined($bRequired) || $bRequired))\n"
"{\n"
"confess &log(ASSERT, \"option ${strOption} is required\");\n"
"}\n"
"\n"
"return $oOption{$strOption}{value};\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgOption);\n"
"\n\n\n\n"
"sub cfgOptionDefault\n"
"{\n"
"my $iOptionId = shift;\n"
"\n"
"cfgOptionValid($iOptionId, true);\n"
"\n"
"return cfgDefOptionDefault(cfgCommandId($strCommand), $iOptionId);\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgOptionDefault);\n"
"\n\n\n\n"
"sub cfgOptionSet\n"
"{\n"
"my $iOptionId = shift;\n"
"my $oValue = shift;\n"
"my $bForce = shift;\n"
"\n"
"my $strOption = cfgOptionName($iOptionId);\n"
"\n"
"if (!cfgOptionValid($iOptionId, !defined($bForce) || !$bForce))\n"
"{\n"
"$oOption{$strOption}{valid} = true;\n"
"}\n"
"\n"
"$oOption{$strOption}{source} = CFGDEF_SOURCE_PARAM;\n"
"$oOption{$strOption}{value} = $oValue;\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgOptionSet);\n"
"\n\n\n\n"
"sub cfgOptionTest\n"
"{\n"
"my $iOptionId = shift;\n"
"my $strValue = shift;\n"
"\n"
"if (!cfgOptionValid($iOptionId))\n"
"{\n"
"return false;\n"
"}\n"
"\n"
"if (defined($strValue))\n"
"{\n"
"return cfgOption($iOptionId) eq $strValue ? true : false;\n"
"}\n"
"\n"
"return defined($oOption{cfgOptionName($iOptionId)}{value}) ? true : false;\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgOptionTest);\n"
"\n\n\n\n"
"sub cfgCommandGet\n"
"{\n"
"return cfgCommandId($strCommand);\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgCommandGet);\n"
"\n\n\n\n"
"sub cfgCommandTest\n"
"{\n"
"my $iCommandIdTest = shift;\n"
"\n"
"return cfgCommandName($iCommandIdTest) eq $strCommand;\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgCommandTest);\n"
"\n\n\n\n"
"sub cfgCommandSet\n"
"{\n"
"my $iCommandId = shift;\n"
"\n"
"$strCommand = cfgCommandName($iCommandId);\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgCommandSet);\n"
"\n\n\n\n\n\n"
"sub cfgCommandWrite\n"
"{\n"
"my $iNewCommandId = shift;\n"
"my $bIncludeConfig = shift;\n"
"my $strExeString = shift;\n"
"my $bIncludeCommand = shift;\n"
"my $oOptionOverride = shift;\n"
"my $bDisplayOnly = shift;\n"
"\n\n"
"$strExeString = defined($strExeString) ? $strExeString : projectBin();\n"
"$bIncludeConfig = defined($bIncludeConfig) ? $bIncludeConfig : false;\n"
"$bIncludeCommand = defined($bIncludeCommand) ? $bIncludeCommand : true;\n"
"\n\n"
"for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)\n"
"{\n"
"my $strOption = cfgOptionName($iOptionId);\n"
"my $bSecure = cfgDefOptionSecure($iOptionId);\n"
"\n\n"
"next if ($bSecure && !$bDisplayOnly);\n"
"\n\n"
"if (defined($oOptionOverride->{$iOptionId}))\n"
"{\n"
"if (defined($oOptionOverride->{$iOptionId}{value}))\n"
"{\n"
"$strExeString .= cfgCommandWriteOptionFormat(\n"
"$strOption, false, $bSecure, {value => $oOptionOverride->{$iOptionId}{value}});\n"
"}\n"
"}\n"
"\n"
"elsif (defined($oOptionOverride->{$strOption}))\n"
"{\n"
"if (defined($oOptionOverride->{$strOption}{value}))\n"
"{\n"
"$strExeString .= cfgCommandWriteOptionFormat(\n"
"$strOption, false, $bSecure, {value => $oOptionOverride->{$strOption}{value}});\n"
"}\n"
"}\n"
"\n"
"elsif (cfgDefOptionValid($iNewCommandId, $iOptionId) &&\n"
"defined($oOption{$strOption}{value}) &&\n"
"($bIncludeConfig ?\n"
"$oOption{$strOption}{source} ne CFGDEF_SOURCE_DEFAULT : $oOption{$strOption}{source} eq CFGDEF_SOURCE_PARAM))\n"
"{\n"
"my $oValue;\n"
"my $bMulti = false;\n"
"\n\n"
"if (ref($oOption{$strOption}{value}) eq 'HASH')\n"
"{\n"
"$oValue = $oOption{$strOption}{value};\n"
"$bMulti = true;\n"
"}\n"
"\n"
"else\n"
"{\n"
"$oValue = {value => $oOption{$strOption}{value}};\n"
"}\n"
"\n"
"$strExeString .= cfgCommandWriteOptionFormat($strOption, $bMulti, $bSecure, $oValue);\n"
"}\n"
"\n"
"elsif (cfgDefOptionValid($iNewCommandId, $iOptionId) && $oOption{$strOption}{reset})\n"
"{\n"
"$strExeString .= \" --reset-${strOption}\";\n"
"}\n"
"}\n"
"\n"
"if ($bIncludeCommand)\n"
"{\n"
"$strExeString .= ' ' . cfgCommandName($iNewCommandId);\n"
"}\n"
"\n"
"return $strExeString;\n"
"}\n"
"\n"
"push @EXPORT, qw(cfgCommandWrite);\n"
"\n\n"
"sub cfgCommandWriteOptionFormat\n"
"{\n"
"my $strOption = shift;\n"
"my $bMulti = shift;\n"
"my $bSecure = shift;\n"
"my $oValue = shift;\n"
"\n\n"
"my $strOptionFormat = '';\n"
"my $strParam;\n"
"\n"
"foreach my $strKey (sort(keys(%$oValue)))\n"
"{\n"
"\n"
"my $strValue = $bSecure ? '<redacted>' : ($bMulti ? \"${strKey}=\" : '') . $$oValue{$strKey};\n"
"\n\n"
"if (cfgDefOptionType(cfgOptionId($strOption)) eq CFGDEF_TYPE_BOOLEAN)\n"
"{\n"
"$strParam = '--' . ($strValue ? '' : 'no-') . $strOption;\n"
"}\n"
"else\n"
"{\n"
"$strParam = \"--${strOption}=${strValue}\";\n"
"}\n"
"\n\n"
"$strOptionFormat .= ' ' . (index($strValue, \" \") != -1 ? \"\\\"${strParam}\\\"\" : $strParam);\n"
"}\n"
"\n"
"return $strOptionFormat;\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Db.pm",
.data =
"\n\n\n"
"package pgBackRest::Db;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use DBD::Pg ':async';\n"
"use DBI;\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Fcntl qw(O_RDONLY);\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n\n\n"
"use constant PG_WAL_SIZE_83 => 16777216;\n"
"\n\n\n\n"
"use constant DB_BACKUP_ADVISORY_LOCK => '12340078987004321';\n"
"push @EXPORT, qw(DB_BACKUP_ADVISORY_LOCK);\n"
"\n\n\n\n\n\n\n\n"
"my $oPgControlVersionHash =\n"
"{\n"
"\n"
"833 => {200711281 => PG_VERSION_83},\n"
"843 => {200904091 => PG_VERSION_84},\n"
"903 =>\n"
"{\n"
"201008051 => PG_VERSION_90,\n"
"201105231 => PG_VERSION_91,\n"
"},\n"
"922 => {201204301 => PG_VERSION_92},\n"
"937 => {201306121 => PG_VERSION_93},\n"
"942 =>\n"
"{\n"
"201409291 => PG_VERSION_94,\n"
"201510051 => PG_VERSION_95,\n"
"},\n"
"960 =>\n"
"{\n"
"201608131 => PG_VERSION_96,\n"
"},\n"
"1002 =>\n"
"{\n"
"201707211 => PG_VERSION_10,\n"
"},\n"
"1100 =>\n"
"{\n"
"201809051 => PG_VERSION_11,\n"
"},\n"
"};\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{iRemoteIdx},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'iRemoteIdx', required => false},\n"
");\n"
"\n"
"if (defined($self->{iRemoteIdx}))\n"
"{\n"
"$self->{strDbPath} = cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $self->{iRemoteIdx}));\n"
"\n"
"if (!isDbLocal({iRemoteIdx => $self->{iRemoteIdx}}))\n"
"{\n"
"$self->{oProtocol} = protocolGet(CFGOPTVAL_REMOTE_TYPE_DB, $self->{iRemoteIdx});\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub DESTROY\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->DESTROY');\n"
"\n"
"if (defined($self->{hDb}))\n"
"{\n"
"$self->{hDb}->disconnect();\n"
"undef($self->{hDb});\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub connect\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bWarnOnError,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::connect', \\@_,\n"
"{name => 'bWarnOnError', default => false},\n"
");\n"
"\n\n"
"my $bResult = true;\n"
"\n\n"
"if (defined($self->{oProtocol}))\n"
"{\n"
"\n"
"$bResult = $self->{oProtocol}->cmdExecute(OP_DB_CONNECT, undef, false, $bWarnOnError) ? true : false;\n"
"}\n"
"\n"
"else\n"
"{\n"
"if (!defined($self->{hDb}))\n"
"{\n"
"\n"
"my $strDbName = 'postgres';\n"
"my $strDbUser = getpwuid($<);\n"
"my $strDbSocketPath = cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_SOCKET_PATH, $self->{iRemoteIdx}), false);\n"
"\n\n"
"if (defined($strDbSocketPath) && $strDbSocketPath !~ /^\\//)\n"
"{\n"
"confess &log(ERROR, \"'${strDbSocketPath}' is not valid for '\" . cfgOptionName(CFGOPT_PG_SOCKET_PATH) . \"' option:\" .\n"
"\" path must be absolute\", ERROR_OPTION_INVALID_VALUE);\n"
"}\n"
"\n\n"
"my $strDbUri =\n"
"\"dbi:Pg:dbname=${strDbName};port=\" . cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PORT, $self->{iRemoteIdx})) .\n"
"(defined($strDbSocketPath) ? \";host=${strDbSocketPath}\" : '');\n"
"\n"
"logDebugMisc\n"
"(\n"
"$strOperation, undef,\n"
"{name => 'strDbUri', value => $strDbUri},\n"
"{name => 'strDbUser', value => $strDbUser}\n"
");\n"
"\n"
"$self->{hDb} = DBI->connect($strDbUri, $strDbUser, undef,\n"
"{AutoCommit => 1, RaiseError => 0, PrintError => 0, Warn => 0});\n"
"\n\n"
"if (!$self->{hDb})\n"
"{\n"
"\n"
"if (!$bWarnOnError)\n"
"{\n"
"confess &log(ERROR, $DBI::errstr, ERROR_DB_CONNECT);\n"
"}\n"
"\n\n"
"&log(WARN, $DBI::errstr);\n"
"\n"
"$bResult = false;\n"
"undef($self->{hDb});\n"
"}\n"
"else\n"
"{\n"
"my ($fDbVersion) = $self->versionGet();\n"
"\n"
"if ($fDbVersion >= PG_VERSION_APPLICATION_NAME)\n"
"{\n"
"\n"
"$self->{hDb}->do(\n"
"\"set application_name = '\" . PROJECT_NAME . ' [' .\n"
"(cfgOptionValid(CFGOPT_COMMAND) ? cfgOption(CFGOPT_COMMAND) : cfgCommandName(cfgCommandGet())) . \"]'\")\n"
"or confess &log(ERROR, $self->{hDb}->errstr, ERROR_DB_QUERY);\n"
"\n\n"
"$self->{hDb}->do(\"set search_path = 'pg_catalog'\")\n"
"or confess &log(ERROR, $self->{hDb}->errstr, ERROR_DB_QUERY);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bResult', value => $bResult}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub executeSql\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strSql,\n"
"$bIgnoreError,\n"
"$bResult,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::executeSql', \\@_,\n"
"{name => 'strSql'},\n"
"{name => 'bIgnoreError', default => false},\n"
"{name => 'bResult', default => true},\n"
");\n"
"\n\n"
"my @stryResult;\n"
"\n\n"
"if (defined($self->{oProtocol}))\n"
"{\n"
"\n"
"@stryResult = @{$self->{oProtocol}->cmdExecute(OP_DB_EXECUTE_SQL, [$strSql, $bIgnoreError, $bResult], $bResult)};\n"
"}\n"
"\n"
"else\n"
"{\n"
"$self->connect();\n"
"\n\n"
"my $hStatement = $self->{hDb}->prepare($strSql, {pg_async => PG_ASYNC})\n"
"or confess &log(ERROR, $DBI::errstr . \":\\n${strSql}\", ERROR_DB_QUERY);\n"
"\n\n"
"$hStatement->execute()\n"
"or confess &log(ERROR, $DBI::errstr. \":\\n${strSql}\", ERROR_DB_QUERY);\n"
"\n\n"
"my $oWait = waitInit(cfgOption(CFGOPT_DB_TIMEOUT));\n"
"my $bTimeout = true;\n"
"\n"
"do\n"
"{\n"
"\n"
"if ($hStatement->pg_ready())\n"
"{\n"
"\n"
"if (!$bResult)\n"
"{\n"
"return \\@stryResult;\n"
"}\n"
"\n"
"if (!$hStatement->pg_result())\n"
"{\n"
"\n"
"if ($bIgnoreError)\n"
"{\n"
"return \\@stryResult;\n"
"}\n"
"\n\n"
"confess &log(ERROR, $DBI::errstr . \":\\n${strSql}\", ERROR_DB_QUERY);\n"
"}\n"
"\n\n"
"my @stryRow;\n"
"\n"
"do\n"
"{\n"
"\n"
"@stryRow = $hStatement->fetchrow_array;\n"
"\n\n"
"if (@stryRow)\n"
"{\n"
"push(@{$stryResult[@stryResult]}, @stryRow);\n"
"}\n"
"\n"
"elsif ($hStatement->err)\n"
"{\n"
"confess &log(ERROR, $DBI::errstr . \":\\n${strSql}\", ERROR_DB_QUERY);\n"
"}\n"
"}\n"
"while (@stryRow);\n"
"\n"
"$bTimeout = false;\n"
"}\n"
"} while ($bTimeout && waitMore($oWait));\n"
"\n\n"
"if ($bTimeout)\n"
"{\n"
"$hStatement->pg_cancel();\n"
"confess &log(ERROR, 'statement timed out after ' . waitInterval($oWait) .\n"
"\" second(s):\\n${strSql}\", ERROR_DB_TIMEOUT);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryResult', value => \\@stryResult, ref => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub executeSqlRow\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strSql\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->executeSqlRow', \\@_,\n"
"{name => 'strSql'}\n"
");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryResult', value => @{$self->executeSql($strSql)}[0]}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub executeSqlOne\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strSql\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->executeSqlOne', \\@_,\n"
"{name => 'strSql'}\n"
");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strResult', value => @{@{$self->executeSql($strSql)}[0]}[0]}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub tablespaceMapGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->tablespaceMapGet');\n"
"\n"
"my $hTablespaceMap = {};\n"
"\n"
"for my $strRow (@{$self->executeSql('select oid, spcname from pg_tablespace')})\n"
"{\n"
"$hTablespaceMap->{@{$strRow}[0]} = @{$strRow}[1];\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hTablespaceMap', value => $hTablespaceMap}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub databaseMapGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->databaseMapGet');\n"
"\n"
"my $hDatabaseMap = {};\n"
"\n"
"for my $strRow (@{$self->executeSql('select datname, oid, datlastsysoid from pg_database')})\n"
"{\n"
"$hDatabaseMap->{@{$strRow}[0]}{&MANIFEST_KEY_DB_ID} = @{$strRow}[1];\n"
"$hDatabaseMap->{@{$strRow}[0]}{&MANIFEST_KEY_DB_LAST_SYSTEM_ID} = @{$strRow}[2];\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hDatabaseMap', value => $hDatabaseMap}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub info\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDbPath\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->info', \\@_,\n"
"{name => 'strDbPath', default => $self->{strDbPath}}\n"
");\n"
"\n\n\n"
"if (!defined($self->{info}{$strDbPath}))\n"
"{\n"
"\n\n"
"if (defined($self->{oProtocol}))\n"
"{\n"
"\n"
"($self->{info}{$strDbPath}{strDbVersion}, $self->{info}{$strDbPath}{iDbControlVersion},\n"
"$self->{info}{$strDbPath}{iDbCatalogVersion}, $self->{info}{$strDbPath}{ullDbSysId}) =\n"
"$self->{oProtocol}->cmdExecute(OP_DB_INFO, [$strDbPath], true);\n"
"}\n"
"\n\n"
"else\n"
"{\n"
"\n\n"
"my $strControlFile = \"${strDbPath}/\" . DB_FILE_PGCONTROL;\n"
"my $hFile;\n"
"my $tBlock;\n"
"\n"
"sysopen($hFile, $strControlFile, O_RDONLY)\n"
"or confess &log(ERROR, \"unable to open ${strControlFile}\", ERROR_FILE_OPEN);\n"
"\n\n"
"sysread($hFile, $tBlock, 8) == 8\n"
"or confess &log(ERROR, \"unable to read database system identifier\");\n"
"\n"
"$self->{info}{$strDbPath}{ullDbSysId} = unpack('Q', $tBlock);\n"
"\n\n"
"sysread($hFile, $tBlock, 4) == 4\n"
"or confess &log(ERROR, \"unable to read control version\");\n"
"\n"
"$self->{info}{$strDbPath}{iDbControlVersion} = unpack('L', $tBlock);\n"
"\n\n"
"sysread($hFile, $tBlock, 4) == 4\n"
"or confess &log(ERROR, \"unable to read catalog version\");\n"
"\n"
"$self->{info}{$strDbPath}{iDbCatalogVersion} = unpack('L', $tBlock);\n"
"\n\n"
"close($hFile);\n"
"\n\n"
"$self->{info}{$strDbPath}{strDbVersion} =\n"
"$oPgControlVersionHash->{$self->{info}{$strDbPath}{iDbControlVersion}}\n"
"{$self->{info}{$strDbPath}{iDbCatalogVersion}};\n"
"\n"
"if (!defined($self->{info}{$strDbPath}{strDbVersion}))\n"
"{\n"
"confess &log(\n"
"ERROR,\n"
"'unexpected control version = ' . $self->{info}{$strDbPath}{iDbControlVersion} .\n"
"' and catalog version = ' . $self->{info}{$strDbPath}{iDbCatalogVersion} . \"\\n\" .\n"
"'HINT: is this version of PostgreSQL supported?',\n"
"ERROR_VERSION_NOT_SUPPORTED);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strDbVersion', value => $self->{info}{$strDbPath}{strDbVersion}},\n"
"{name => 'iDbControlVersion', value => $self->{info}{$strDbPath}{iDbControlVersion}},\n"
"{name => 'iDbCatalogVersion', value => $self->{info}{$strDbPath}{iDbCatalogVersion}},\n"
"{name => 'ullDbSysId', value => $self->{info}{$strDbPath}{ullDbSysId}}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub versionGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->versionGet');\n"
"\n\n"
"if (defined($self->{strDbVersion}) && defined($self->{strDbPath}))\n"
"{\n"
"return $self->{strDbVersion}, $self->{strDbPath};\n"
"}\n"
"\n\n"
"my ($strVersionNum, $strDbPath) =\n"
"$self->executeSqlRow(\n"
"\"select (select setting from pg_settings where name = 'server_version_num'), \" .\n"
"\" (select setting from pg_settings where name = 'data_directory')\");\n"
"\n\n"
"$self->{strDbVersion} = substr($strVersionNum, 0, length($strVersionNum) - 4);\n"
"\n\n"
"if ($self->{strDbVersion} < PG_VERSION_10)\n"
"{\n"
"$self->{strDbVersion} .= qw{.} . int(substr($strVersionNum, 1, 2));\n"
"}\n"
"\n\n"
"my @stryVersionSupport = versionSupport();\n"
"\n"
"if ($self->{strDbVersion} < $stryVersionSupport[0])\n"
"{\n"
"confess &log(ERROR, 'unsupported Postgres version' . $self->{strDbVersion}, ERROR_VERSION_NOT_SUPPORTED);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strDbVersion', value => $self->{strDbVersion}},\n"
"{name => 'strDbPath', value => $strDbPath}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub backupStart\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strLabel,\n"
"$bStartFast\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->backupStart', \\@_,\n"
"{name => 'strLabel'},\n"
"{name => 'bStartFast'}\n"
");\n"
"\n\n"
"$self->configValidate();\n"
"\n\n"
"if ($self->{strDbVersion} < PG_VERSION_84 && $bStartFast)\n"
"{\n"
"&log(WARN, cfgOptionName(CFGOPT_START_FAST) . ' option is only available in PostgreSQL >= ' . PG_VERSION_84);\n"
"$bStartFast = false;\n"
"}\n"
"\n\n"
"my $bChecksumPage =\n"
"$self->executeSqlOne(\"select count(*) = 1 from pg_settings where name = 'data_checksums' and setting = 'on'\");\n"
"\n\n"
"if (!cfgOptionTest(CFGOPT_CHECKSUM_PAGE))\n"
"{\n"
"cfgOptionSet(CFGOPT_CHECKSUM_PAGE, $bChecksumPage);\n"
"}\n"
"\n"
"elsif (cfgOption(CFGOPT_CHECKSUM_PAGE) && !$bChecksumPage)\n"
"{\n"
"&log(WARN, 'unable to enable page checksums since they are not enabled in the database');\n"
"cfgOptionSet(CFGOPT_CHECKSUM_PAGE, false);\n"
"}\n"
"\n\n\n"
"if (!$self->executeSqlOne('select pg_try_advisory_lock(' . DB_BACKUP_ADVISORY_LOCK . ')'))\n"
"{\n"
"confess &log(ERROR, 'unable to acquire ' . PROJECT_NAME . \" advisory lock\\n\" .\n"
"'HINT: is another ' . PROJECT_NAME . ' backup already running on this cluster?', ERROR_LOCK_ACQUIRE);\n"
"}\n"
"\n\n\n"
"if (cfgOption(CFGOPT_STOP_AUTO) && $self->{strDbVersion} < PG_VERSION_96)\n"
"{\n"
"\n"
"if ($self->{strDbVersion} >= PG_VERSION_93)\n"
"{\n"
"\n"
"if ($self->executeSqlOne('select pg_is_in_backup()'))\n"
"{\n"
"&log(WARN, 'the cluster is already in backup mode but no ' . PROJECT_NAME . ' backup process is running.' .\n"
"' pg_stop_backup() will be called so a new backup can be started.');\n"
"$self->backupStop();\n"
"}\n"
"}\n"
"\n\n"
"else\n"
"{\n"
"&log(WARN, cfgOptionName(CFGOPT_STOP_AUTO) . ' option is only available in PostgreSQL >= ' . PG_VERSION_93);\n"
"}\n"
"}\n"
"\n\n"
"&log(INFO, 'execute ' . ($self->{strDbVersion} >= PG_VERSION_96 ? 'non-' : '') .\n"
"\"exclusive pg_start_backup() with label \\\"${strLabel}\\\": backup begins after \" .\n"
"($bStartFast ? \"the requested immediate checkpoint\" : \"the next regular checkpoint\") . \" completes\");\n"
"\n"
"my ($strTimestampDbStart, $strArchiveStart, $strLsnStart, $iWalSegmentSize) = $self->executeSqlRow(\n"
"\"select to_char(current_timestamp, 'YYYY-MM-DD HH24:MI:SS.US TZ'), pg_\" . $self->walId() . \"file_name(lsn), lsn::text,\" .\n"
"($self->{strDbVersion} < PG_VERSION_84 ? PG_WAL_SIZE_83 :\n"
"\" (select setting::int8 from pg_settings where name = 'wal_segment_size')\" .\n"
"\n"
"($self->{strDbVersion} < PG_VERSION_11 ?\n"
"\" * (select setting::int8 from pg_settings where name = 'wal_block_size')\" : '')) .\n"
"\" from pg_start_backup('${strLabel}'\" .\n"
"($bStartFast ? ', true' : $self->{strDbVersion} >= PG_VERSION_84 ? ', false' : '') .\n"
"($self->{strDbVersion} >= PG_VERSION_96 ? ', false' : '') . ') as lsn');\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strArchiveStart', value => $strArchiveStart},\n"
"{name => 'strLsnStart', value => $strLsnStart},\n"
"{name => 'iWalSegmentSize', value => $iWalSegmentSize},\n"
"{name => 'strTimestampDbStart', value => $strTimestampDbStart}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub backupStop\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->backupStop');\n"
"\n\n"
"&log(INFO, 'execute ' . ($self->{strDbVersion} >= PG_VERSION_96 ? 'non-' : '') .\n"
"'exclusive pg_stop_backup() and wait for all WAL segments to archive');\n"
"\n"
"my ($strTimestampDbStop, $strArchiveStop, $strLsnStop, $strLabel, $strTablespaceMap) =\n"
"$self->executeSqlRow(\n"
"\"select to_char(clock_timestamp(), 'YYYY-MM-DD HH24:MI:SS.US TZ'), pg_\" .\n"
"$self->walId() . \"file_name(lsn), lsn::text, \" .\n"
"($self->{strDbVersion} >= PG_VERSION_96 ?\n"
"'labelfile, ' .\n"
"'case when length(trim(both \\'\\t\\n \\' from spcmapfile)) = 0 then null else spcmapfile end as spcmapfile' :\n"
"'null as labelfile, null as spcmapfile') .\n"
"' from pg_stop_backup(' .\n"
"\n"
"($self->{strDbVersion} >= PG_VERSION_96 ? 'false' : '') .\n"
"\n"
"($self->{strDbVersion} >= PG_VERSION_10 ? ', false' : '') . ') as lsn');\n"
"\n\n"
"my $oFileHash =\n"
"{\n"
"&MANIFEST_FILE_BACKUPLABEL => $strLabel,\n"
"&MANIFEST_FILE_TABLESPACEMAP => $strTablespaceMap\n"
"};\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strArchiveStop', value => $strArchiveStop},\n"
"{name => 'strLsnStop', value => $strLsnStop},\n"
"{name => 'strTimestampDbStop', value => $strTimestampDbStop},\n"
"{name => 'oFileHash', value => $oFileHash}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub configValidate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->configValidate', \\@_,\n"
");\n"
"\n\n"
"my ($strDbVersion) = $self->info();\n"
"\n\n"
"my ($fCompareDbVersion, $strCompareDbPath) = $self->versionGet();\n"
"\n\n"
"if (!($strDbVersion == $fCompareDbVersion && $self->{strDbPath} eq $strCompareDbPath))\n"
"{\n"
"confess &log(ERROR,\n"
"\"version '${fCompareDbVersion}' and path '${strCompareDbPath}' queried from cluster do not match version\" .\n"
"\" '${strDbVersion}' and \" . cfgOptionName(CFGOPT_PG_PATH) . \" '$self->{strDbPath}' read from\" .\n"
"\" '$self->{strDbPath}/\" . DB_FILE_PGCONTROL . \"'\\n\" .\n"
"\"HINT: the \" . cfgOptionName(CFGOPT_PG_PATH) . \" and \" . cfgOptionName(CFGOPT_PG_PORT) .\n"
"\" settings likely reference different clusters\",\n"
"ERROR_DB_MISMATCH);\n"
"}\n"
"\n\n"
"if (!$self->isStandby() && cfgOptionValid(CFGOPT_ARCHIVE_CHECK) && cfgOption(CFGOPT_ARCHIVE_CHECK))\n"
"{\n"
"my $strArchiveMode = $self->executeSqlOne('show archive_mode');\n"
"\n\n"
"if ($strArchiveMode eq 'off')\n"
"{\n"
"confess &log(ERROR, 'archive_mode must be enabled', ERROR_ARCHIVE_DISABLED);\n"
"}\n"
"\n\n"
"if ($strArchiveMode eq 'always')\n"
"{\n"
"confess &log(ERROR, \"archive_mode=always not supported\", ERROR_FEATURE_NOT_SUPPORTED);\n"
"}\n"
"\n\n"
"my $strArchiveCommand = $self->executeSqlOne('show archive_command');\n"
"\n"
"if (index($strArchiveCommand, PROJECT_EXE) == -1)\n"
"{\n"
"confess &log(ERROR,\n"
"'archive_command ' . (defined($strArchiveCommand) ? \"'${strArchiveCommand}'\" : '[null]') . ' must contain \\'' .\n"
"PROJECT_EXE . '\\'', ERROR_ARCHIVE_COMMAND_INVALID);\n"
"}\n"
"}\n"
"\n"
"return logDebugReturn\n"
"(\n"
"$strOperation\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub walId\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{strDbVersion} >= PG_VERSION_10 ? 'wal' : 'xlog';\n"
"}\n"
"\n\n\n\n\n\n"
"sub lsnId\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->{strDbVersion} >= PG_VERSION_10 ? 'lsn' : 'location';\n"
"}\n"
"\n\n\n\n\n\n"
"sub walSwitch\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my $strOperation = logDebugParam(__PACKAGE__ . '->walSwitch');\n"
"\n\n\n"
"if ($self->{strDbVersion} >= PG_VERSION_91)\n"
"{\n"
"$self->executeSql(\"select pg_create_restore_point('\" . PROJECT_NAME . \" Archive Check');\");\n"
"}\n"
"\n"
"my $strWalFileName = $self->executeSqlOne(\n"
"'select pg_' . $self->walId() . 'file_name from pg_' . $self->walId() . 'file_name(pg_switch_' . $self->walId() . '());');\n"
"\n"
"&log(INFO, \"switch WAL ${strWalFileName}\");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strWalFileName', value => $strWalFileName}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub isStandby\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->isStandby');\n"
"\n"
"if (!defined($self->{bStandby}))\n"
"{\n"
"my ($strDbVersion) = $self->versionGet();\n"
"\n"
"if ($strDbVersion <= PG_VERSION_90)\n"
"{\n"
"$self->{bStandby} = false;\n"
"}\n"
"else\n"
"{\n"
"$self->{bStandby} = $self->executeSqlOne('select pg_is_in_recovery()') ? true : false;\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bStandby', value => $self->{bStandby}}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub replayWait\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strTargetLSN,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->replayWait', \\@_,\n"
"{name => 'strTargetLSN'}\n"
");\n"
"\n\n"
"require pgBackRest::Archive::Common;\n"
"pgBackRest::Archive::Common->import();\n"
"\n\n"
"my $oWait = waitInit(cfgOption(CFGOPT_ARCHIVE_TIMEOUT));\n"
"my $bTimeout = true;\n"
"my $strReplayedLSN = undef;\n"
"\n\n"
"do\n"
"{\n"
"my $strLastWalReplayLsnFunction =\n"
"'pg_last_' . $self->walId() . '_replay_' . $self->lsnId() . '()';\n"
"\n\n"
"my $strLastReplayedLSN = $self->executeSqlOne(\n"
"\"select coalesce(${strLastWalReplayLsnFunction}::text, '<NONE>')\");\n"
"\n\n"
"if ($strLastReplayedLSN eq '<NONE>')\n"
"{\n"
"confess &log(\n"
"ERROR,\n"
"\"unable to query replay lsn on the standby using ${strLastWalReplayLsnFunction}\\n\" .\n"
"\"Hint: Is this a standby?\",\n"
"ERROR_ARCHIVE_TIMEOUT);\n"
"}\n"
"\n\n\n"
"if (lsnNormalize($strLastReplayedLSN) ge lsnNormalize($strTargetLSN))\n"
"{\n"
"$bTimeout = false;\n"
"}\n"
"else\n"
"{\n"
"\n"
"if (defined($strReplayedLSN) &&\n"
"lsnNormalize($strLastReplayedLSN) gt lsnNormalize($strReplayedLSN) &&\n"
"!waitMore($oWait))\n"
"{\n"
"$oWait = waitInit(cfgOption(CFGOPT_ARCHIVE_TIMEOUT));\n"
"}\n"
"}\n"
"\n\n"
"$strReplayedLSN = $strLastReplayedLSN;\n"
"\n"
"} while ($bTimeout && waitMore($oWait));\n"
"\n\n"
"if ($bTimeout == true)\n"
"{\n"
"confess &log(\n"
"ERROR, \"timeout before standby replayed ${strTargetLSN} - only reached ${strReplayedLSN}\", ERROR_ARCHIVE_TIMEOUT);\n"
"}\n"
"\n\n"
"$self->executeSql('checkpoint', undef, false);\n"
"\n\n\n\n\n\n"
"my $strCheckpointLSN = undef;\n"
"\n"
"if ($self->{strDbVersion} >= PG_VERSION_96)\n"
"{\n"
"$strCheckpointLSN = $self->executeSqlOne('select checkpoint_' . $self->lsnId() .' from pg_control_checkpoint()');\n"
"\n"
"if (lsnNormalize($strCheckpointLSN) le lsnNormalize($strTargetLSN))\n"
"{\n"
"confess &log(\n"
"ERROR,\n"
"\"the checkpoint location ${strCheckpointLSN} is less than the target location ${strTargetLSN} even though the\" .\n"
"\" replay location is ${strReplayedLSN}\\n\" .\n"
"\"Hint: This should not be possible and may indicate a bug in PostgreSQL.\",\n"
"ERROR_ARCHIVE_TIMEOUT);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strReplayedLSN', value => $strReplayedLSN},\n"
"{name => 'strCheckpointLSN', value => $strCheckpointLSN},\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n\n"
"sub dbObjectGet\n"
"{\n"
"\n"
"my (\n"
"$strOperation,\n"
"$bMasterOnly,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::dbObjectGet', \\@_,\n"
"{name => 'bMasterOnly', optional => true, default => false},\n"
");\n"
"\n"
"my $iStandbyIdx = undef;\n"
"my $iMasterRemoteIdx = 1;\n"
"my $oDbMaster = undef;\n"
"my $oDbStandby = undef;\n"
"\n\n\n"
"if (!$bMasterOnly && cfgOptionTest(CFGOPT_ONLINE) && cfgOption(CFGOPT_ONLINE) && multipleDb())\n"
"{\n"
"for (my $iRemoteIdx = 1; $iRemoteIdx <= cfgOptionIndexTotal(CFGOPT_PG_HOST); $iRemoteIdx++)\n"
"{\n"
"\n"
"if (cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)) ||\n"
"cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iRemoteIdx)))\n"
"{\n"
"\n"
"my $oDb;\n"
"\n"
"logWarnOnErrorEnable();\n"
"eval\n"
"{\n"
"$oDb = new pgBackRest::Db($iRemoteIdx);\n"
"return true;\n"
"}\n"
"or do {};\n"
"\n"
"logWarnOnErrorDisable();\n"
"my $bAssigned = false;\n"
"\n"
"if (defined($oDb))\n"
"{\n"
"\n\n"
"if ($oDb->connect(true))\n"
"{\n"
"\n"
"if ($oDb->isStandby())\n"
"{\n"
"\n"
"if (cfgOption(CFGOPT_BACKUP_STANDBY) && !defined($oDbStandby))\n"
"{\n"
"$oDbStandby = $oDb;\n"
"$iStandbyIdx = $iRemoteIdx;\n"
"$bAssigned = true;\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if (defined($oDbMaster))\n"
"{\n"
"confess &log(ERROR, 'more than one master database found');\n"
"}\n"
"\n"
"$oDbMaster = $oDb;\n"
"$iMasterRemoteIdx = $iRemoteIdx;\n"
"$bAssigned = true;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (!$bAssigned)\n"
"{\n"
"protocolDestroy(CFGOPTVAL_REMOTE_TYPE_DB, $iRemoteIdx, true);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (cfgOption(CFGOPT_BACKUP_STANDBY) && !defined($oDbStandby))\n"
"{\n"
"\n"
"confess &log(ERROR, 'unable to find standby database - cannot proceed', ERROR_HOST_CONNECT);\n"
"}\n"
"\n\n"
"if (!defined($oDbMaster))\n"
"{\n"
"\n"
"confess &log(ERROR, 'unable to find master database - cannot proceed', ERROR_DB_CONNECT);\n"
"}\n"
"}\n"
"\n\n"
"if (!defined($oDbMaster))\n"
"{\n"
"$oDbMaster = new pgBackRest::Db($iMasterRemoteIdx);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oDbMaster', value => $oDbMaster},\n"
"{name => 'iDbMasterIdx', value => $iMasterRemoteIdx},\n"
"{name => 'oDbStandby', value => $oDbStandby},\n"
"{name => 'iDbStandbyIdx', value => $iStandbyIdx},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(dbObjectGet);\n"
"\n\n\n\n\n\n\n"
"sub dbMasterGet\n"
"{\n"
"\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '::dbMasterGet');\n"
"\n"
"my ($oDbMaster) = dbObjectGet({bMasterOnly => true});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oDbMaster', value => $oDbMaster, trace => true},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(dbMasterGet);\n"
"\n\n\n\n\n\n"
"sub multipleDb\n"
"{\n"
"for (my $iDbPathIdx = 2; $iDbPathIdx <= cfgOptionIndexTotal(CFGOPT_PG_PATH); $iDbPathIdx++)\n"
"{\n"
"\n"
"if (cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iDbPathIdx)))\n"
"{\n"
"return true;\n"
"}\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/DbVersion.pm",
.data =
"\n\n\n"
"package pgBackRest::DbVersion;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"use constant PG_PAGE_SIZE => 8192;\n"
"push @EXPORT, qw(PG_PAGE_SIZE);\n"
"\n\n\n\n"
"use constant PG_VERSION_83 => '8.3';\n"
"push @EXPORT, qw(PG_VERSION_83);\n"
"use constant PG_VERSION_84 => '8.4';\n"
"push @EXPORT, qw(PG_VERSION_84);\n"
"use constant PG_VERSION_90 => '9.0';\n"
"push @EXPORT, qw(PG_VERSION_90);\n"
"use constant PG_VERSION_91 => '9.1';\n"
"push @EXPORT, qw(PG_VERSION_91);\n"
"use constant PG_VERSION_92 => '9.2';\n"
"push @EXPORT, qw(PG_VERSION_92);\n"
"use constant PG_VERSION_93 => '9.3';\n"
"push @EXPORT, qw(PG_VERSION_93);\n"
"use constant PG_VERSION_94 => '9.4';\n"
"push @EXPORT, qw(PG_VERSION_94);\n"
"use constant PG_VERSION_95 => '9.5';\n"
"push @EXPORT, qw(PG_VERSION_95);\n"
"use constant PG_VERSION_96 => '9.6';\n"
"push @EXPORT, qw(PG_VERSION_96);\n"
"use constant PG_VERSION_10 => '10';\n"
"push @EXPORT, qw(PG_VERSION_10);\n"
"use constant PG_VERSION_11 => '11';\n"
"push @EXPORT, qw(PG_VERSION_11);\n"
"\n"
"use constant PG_VERSION_APPLICATION_NAME => PG_VERSION_90;\n"
"push @EXPORT, qw(PG_VERSION_APPLICATION_NAME);\n"
"use constant PG_VERSION_HOT_STANDBY => PG_VERSION_91;\n"
"push @EXPORT, qw(PG_VERSION_HOT_STANDBY);\n"
"use constant PG_VERSION_BACKUP_STANDBY => PG_VERSION_92;\n"
"push @EXPORT, qw(PG_VERSION_BACKUP_STANDBY);\n"
"\n\n\n\n\n\n"
"sub versionSupport\n"
"{\n"
"\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->versionSupport');\n"
"\n"
"my @strySupportVersion = (PG_VERSION_83, PG_VERSION_84, PG_VERSION_90, PG_VERSION_91, PG_VERSION_92, PG_VERSION_93,\n"
"PG_VERSION_94, PG_VERSION_95, PG_VERSION_96, PG_VERSION_10, PG_VERSION_11);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strySupportVersion', value => \\@strySupportVersion}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(versionSupport);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Expire.pm",
.data =
"\n\n\n"
"package pgBackRest::Expire;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"use File::Basename qw(dirname);\n"
"use Scalar::Util qw(looks_like_number);\n"
"\n"
"use pgBackRest::Archive::Common;\n"
"use pgBackRest::Archive::Info;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Backup::Common;\n"
"use pgBackRest::Backup::Info;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::InfoCommon;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');\n"
"\n\n"
"$self->{iArchiveExpireTotal} = 0;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub logExpire\n"
"{\n"
"my $self = shift;\n"
"my $strArchiveId = shift;\n"
"my $strArchiveFile = shift;\n"
"\n"
"if (defined($strArchiveFile))\n"
"{\n"
"if (!defined($self->{strArchiveExpireStart}))\n"
"{\n"
"$self->{strArchiveExpireStart} = $strArchiveFile;\n"
"$self->{strArchiveExpireStop} = $strArchiveFile;\n"
"}\n"
"else\n"
"{\n"
"$self->{strArchiveExpireStop} = $strArchiveFile;\n"
"}\n"
"\n"
"$self->{iArchiveExpireTotal}++;\n"
"}\n"
"else\n"
"{\n"
"if (defined($self->{strArchiveExpireStart}))\n"
"{\n"
"&log(DETAIL, \"remove archive: archiveId = ${strArchiveId}, start = \" . substr($self->{strArchiveExpireStart}, 0, 24) .\n"
"\", stop = \" . substr($self->{strArchiveExpireStop}, 0, 24));\n"
"}\n"
"\n"
"undef($self->{strArchiveExpireStart});\n"
"}\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');\n"
"\n"
"my @stryPath;\n"
"\n"
"my $oStorageRepo = storageRepo();\n"
"my $strBackupClusterPath = $oStorageRepo->pathGet(STORAGE_REPO_BACKUP);\n"
"my $iFullRetention = cfgOption(CFGOPT_REPO_RETENTION_FULL, false);\n"
"my $iDifferentialRetention = cfgOption(CFGOPT_REPO_RETENTION_DIFF, false);\n"
"my $strArchiveRetentionType = cfgOption(CFGOPT_REPO_RETENTION_ARCHIVE_TYPE, false);\n"
"my $iArchiveRetention = cfgOption(CFGOPT_REPO_RETENTION_ARCHIVE, false);\n"
"\n\n"
"my $oBackupInfo = new pgBackRest::Backup::Info($oStorageRepo->pathGet(STORAGE_REPO_BACKUP));\n"
"\n\n"
"if (defined($iFullRetention))\n"
"{\n"
"\n"
"if (!looks_like_number($iFullRetention) || $iFullRetention < 1)\n"
"{\n"
"confess &log(ERROR, cfgOptionName(CFGOPT_REPO_RETENTION_FULL) . ' must be a number >= 1');\n"
"}\n"
"\n"
"@stryPath = $oBackupInfo->list(backupRegExpGet(true));\n"
"\n"
"if (@stryPath > $iFullRetention)\n"
"{\n"
"\n"
"for (my $iFullIdx = 0; $iFullIdx < @stryPath - $iFullRetention; $iFullIdx++)\n"
"{\n"
"my @stryRemoveList;\n"
"\n"
"foreach my $strPath ($oBackupInfo->list('^' . $stryPath[$iFullIdx] . '.*'))\n"
"{\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strPath}/\" . FILE_MANIFEST . INI_COPY_EXT);\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strPath}/\" . FILE_MANIFEST);\n"
"$oBackupInfo->delete($strPath);\n"
"\n"
"if ($strPath ne $stryPath[$iFullIdx])\n"
"{\n"
"push(@stryRemoveList, $strPath);\n"
"}\n"
"}\n"
"\n"
"&log(INFO, 'expire full backup ' . (@stryRemoveList > 0 ? 'set: ' : '') . $stryPath[$iFullIdx] .\n"
"(@stryRemoveList > 0 ? ', ' . join(', ', @stryRemoveList) : ''));\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (defined($iDifferentialRetention))\n"
"{\n"
"\n"
"if (!looks_like_number($iDifferentialRetention) || $iDifferentialRetention < 1)\n"
"{\n"
"confess &log(ERROR, cfgOptionName(CFGOPT_REPO_RETENTION_DIFF) . ' must be a number >= 1');\n"
"}\n"
"\n\n\n"
"@stryPath = $oBackupInfo->list(backupRegExpGet(true, true));\n"
"\n"
"if (@stryPath > $iDifferentialRetention)\n"
"{\n"
"for (my $iDiffIdx = 0; $iDiffIdx < @stryPath - $iDifferentialRetention; $iDiffIdx++)\n"
"{\n"
"\n\n"
"next if ($stryPath[$iDiffIdx] =~ backupRegExpGet(true));\n"
"\n\n"
"my @stryRemoveList;\n"
"\n"
"foreach my $strPath ($oBackupInfo->list(backupRegExpGet(false, true, true)))\n"
"{\n"
"logDebugMisc($strOperation, \"checking ${strPath} for differential expiration\");\n"
"\n\n"
"if ($strPath lt $stryPath[$iDiffIdx + 1])\n"
"{\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strPath}\" . FILE_MANIFEST);\n"
"$oBackupInfo->delete($strPath);\n"
"\n"
"if ($strPath ne $stryPath[$iDiffIdx])\n"
"{\n"
"push(@stryRemoveList, $strPath);\n"
"}\n"
"}\n"
"}\n"
"\n"
"&log(INFO, 'expire diff backup ' . (@stryRemoveList > 0 ? 'set: ' : '') . $stryPath[$iDiffIdx] .\n"
"(@stryRemoveList > 0 ? ', ' . join(', ', @stryRemoveList) : ''));\n"
"}\n"
"}\n"
"}\n"
"\n"
"$oBackupInfo->save();\n"
"\n\n"
"foreach my $strBackup ($oStorageRepo->list(\n"
"STORAGE_REPO_BACKUP, {strExpression => backupRegExpGet(true, true, true), strSortOrder => 'reverse'}))\n"
"{\n"
"if (!$oBackupInfo->current($strBackup))\n"
"{\n"
"&log(INFO, \"remove expired backup ${strBackup}\");\n"
"\n"
"$oStorageRepo->remove(\"${strBackupClusterPath}/${strBackup}\", {bRecurse => true});\n"
"}\n"
"}\n"
"\n\n"
"if (!defined($iArchiveRetention))\n"
"{\n"
"&log(INFO, \"option '\" . cfgOptionName(CFGOPT_REPO_RETENTION_ARCHIVE) . \"' is not set - archive logs will not be expired\");\n"
"}\n"
"else\n"
"{\n"
"my @stryGlobalBackupRetention;\n"
"\n\n\n"
"if ($strArchiveRetentionType eq CFGOPTVAL_BACKUP_TYPE_FULL)\n"
"{\n"
"@stryGlobalBackupRetention = $oBackupInfo->list(backupRegExpGet(true), 'reverse');\n"
"}\n"
"elsif ($strArchiveRetentionType eq CFGOPTVAL_BACKUP_TYPE_DIFF)\n"
"{\n"
"@stryGlobalBackupRetention = $oBackupInfo->list(backupRegExpGet(true, true), 'reverse');\n"
"}\n"
"elsif ($strArchiveRetentionType eq CFGOPTVAL_BACKUP_TYPE_INCR)\n"
"{\n"
"@stryGlobalBackupRetention = $oBackupInfo->list(backupRegExpGet(true, true, true), 'reverse');\n"
"}\n"
"\n\n"
"my $iBackupTotal = scalar @stryGlobalBackupRetention;\n"
"\n"
"if ($iBackupTotal > 0)\n"
"{\n"
"my $oArchiveInfo = new pgBackRest::Archive::Info($oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE), true);\n"
"my @stryListArchiveDisk = sort {((split('-', $a))[1] + 0) cmp ((split('-', $b))[1] + 0)} $oStorageRepo->list(\n"
"STORAGE_REPO_ARCHIVE, {strExpression => REGEX_ARCHIVE_DIR_DB_VERSION, bIgnoreMissing => true});\n"
"\n\n"
"if (!($oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef,\n"
"($oBackupInfo->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION)))) ||\n"
"!($oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID, undef,\n"
"($oBackupInfo->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID)))))\n"
"{\n"
"confess &log(ERROR, \"archive and backup database versions do not match\\n\" .\n"
"\"HINT: has a stanza-upgrade been performed?\", ERROR_FILE_INVALID);\n"
"}\n"
"\n\n"
"my @stryTmp = @stryGlobalBackupRetention;\n"
"my @stryGlobalBackupArchiveRetention = splice(@stryTmp, 0, $iArchiveRetention);\n"
"\n\n"
"foreach my $strArchiveId (@stryListArchiveDisk)\n"
"{\n"
"\n\n"
"my @stryLocalBackupRetention = $oBackupInfo->listByArchiveId($strArchiveId,\n"
"$oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE), \\@stryGlobalBackupRetention, 'reverse');\n"
"\n\n"
"if (!@stryLocalBackupRetention)\n"
"{\n"
"\n"
"my $iDbHistoryId = $oBackupInfo->backupArchiveDbHistoryId(\n"
"$strArchiveId, $oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE));\n"
"\n\n\n"
"if (!defined($iDbHistoryId) || !$oBackupInfo->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID, undef,\n"
"$iDbHistoryId))\n"
"{\n"
"my $strFullPath = $oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE . \"/${strArchiveId}\");\n"
"\n"
"$oStorageRepo->remove($strFullPath, {bRecurse => true});\n"
"\n"
"&log(INFO, \"remove archive path: ${strFullPath}\");\n"
"}\n"
"\n\n"
"next;\n"
"}\n"
"\n"
"my @stryLocalBackupArchiveRentention;\n"
"\n\n"
"if (@stryGlobalBackupArchiveRetention && $iArchiveRetention <= scalar @stryGlobalBackupRetention)\n"
"{\n"
"\n"
"foreach my $strGlobalBackupArchiveRetention (@stryGlobalBackupArchiveRetention)\n"
"{\n"
"foreach my $strLocalBackupRetention (@stryLocalBackupRetention)\n"
"{\n"
"if ($strLocalBackupRetention eq $strGlobalBackupArchiveRetention)\n"
"{\n"
"unshift(@stryLocalBackupArchiveRentention, $strLocalBackupRetention);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n\n"
"else\n"
"{\n"
"if ($strArchiveRetentionType eq CFGOPTVAL_BACKUP_TYPE_FULL && scalar @stryLocalBackupRetention > 0)\n"
"{\n"
"&log(INFO, \"full backup total < ${iArchiveRetention} - using oldest full backup for ${strArchiveId} \" .\n"
"\"archive retention\");\n"
"$stryLocalBackupArchiveRentention[0] = $stryLocalBackupRetention[0];\n"
"}\n"
"}\n"
"\n\n\n"
"if (!@stryLocalBackupArchiveRentention)\n"
"{\n"
"$stryLocalBackupArchiveRentention[0] = $stryLocalBackupRetention[-1];\n"
"}\n"
"\n"
"my $strArchiveRetentionBackup = $stryLocalBackupArchiveRentention[0];\n"
"\n\n"
"if (defined($strArchiveRetentionBackup))\n"
"{\n"
"my $bRemove;\n"
"\n\n\n"
"if ($oBackupInfo->test(INFO_BACKUP_SECTION_BACKUP_CURRENT,\n"
"$strArchiveRetentionBackup, INFO_BACKUP_KEY_ARCHIVE_START))\n"
"{\n"
"\n\n\n"
"my $strArchiveExpireMax;\n"
"my @oyArchiveRange;\n"
"my @stryBackupList = $oBackupInfo->list();\n"
"\n\n"
"foreach my $strBackup (\n"
"$oBackupInfo->listByArchiveId(\n"
"$strArchiveId, $oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE), \\@stryBackupList))\n"
"{\n"
"if ($strBackup le $strArchiveRetentionBackup &&\n"
"$oBackupInfo->test(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_ARCHIVE_START))\n"
"{\n"
"my $oArchiveRange = {};\n"
"\n"
"$$oArchiveRange{start} = $oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT,\n"
"$strBackup, INFO_BACKUP_KEY_ARCHIVE_START);\n"
"\n"
"if ($strBackup ne $strArchiveRetentionBackup)\n"
"{\n"
"$$oArchiveRange{stop} = $oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT,\n"
"$strBackup, INFO_BACKUP_KEY_ARCHIVE_STOP);\n"
"}\n"
"else\n"
"{\n"
"$strArchiveExpireMax = $$oArchiveRange{start};\n"
"}\n"
"\n"
"&log(DETAIL, \"archive retention on backup ${strBackup}, archiveId = ${strArchiveId}, \" .\n"
"\"start = $$oArchiveRange{start}\" .\n"
"(defined($$oArchiveRange{stop}) ? \", stop = $$oArchiveRange{stop}\" : ''));\n"
"\n"
"push(@oyArchiveRange, $oArchiveRange);\n"
"}\n"
"}\n"
"\n\n"
"foreach my $strPath ($oStorageRepo->list(\n"
"STORAGE_REPO_ARCHIVE . \"/${strArchiveId}\", {strExpression => REGEX_ARCHIVE_DIR_WAL}))\n"
"{\n"
"logDebugMisc($strOperation, \"found major WAL path: ${strPath}\");\n"
"$bRemove = true;\n"
"\n\n"
"foreach my $oArchiveRange (@oyArchiveRange)\n"
"{\n"
"if ($strPath ge substr($$oArchiveRange{start}, 0, 16) &&\n"
"(!defined($$oArchiveRange{stop}) || $strPath le substr($$oArchiveRange{stop}, 0, 16)))\n"
"{\n"
"$bRemove = false;\n"
"last;\n"
"}\n"
"}\n"
"\n\n"
"if ($bRemove)\n"
"{\n"
"my $strFullPath = $oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE . \"/${strArchiveId}\") . \"/${strPath}\";\n"
"\n"
"$oStorageRepo->remove($strFullPath, {bRecurse => true});\n"
"\n\n"
"logDebugMisc($strOperation, \"remove major WAL path: ${strFullPath}\");\n"
"$self->logExpire($strArchiveId, $strPath);\n"
"}\n"
"\n\n\n"
"elsif ($strPath le substr($strArchiveExpireMax, 0, 16))\n"
"{\n"
"\n"
"foreach my $strSubPath ($oStorageRepo->list(\n"
"STORAGE_REPO_ARCHIVE . \"/${strArchiveId}/${strPath}\", {strExpression => \"^[0-F]{24}.*\\$\"}))\n"
"{\n"
"$bRemove = true;\n"
"\n\n"
"foreach my $oArchiveRange (@oyArchiveRange)\n"
"{\n"
"if (substr($strSubPath, 0, 24) ge $$oArchiveRange{start} &&\n"
"(!defined($$oArchiveRange{stop}) || substr($strSubPath, 0, 24) le $$oArchiveRange{stop}))\n"
"{\n"
"$bRemove = false;\n"
"last;\n"
"}\n"
"}\n"
"\n\n"
"if ($bRemove)\n"
"{\n"
"$oStorageRepo->remove(STORAGE_REPO_ARCHIVE . \"/${strArchiveId}/${strSubPath}\");\n"
"\n"
"logDebugMisc($strOperation, \"remove WAL segment: ${strArchiveId}/${strSubPath}\");\n"
"\n\n"
"$self->logExpire($strArchiveId, substr($strSubPath, 0, 24));\n"
"}\n"
"else\n"
"{\n"
"\n"
"$self->logExpire($strArchiveId);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if ($self->{iArchiveExpireTotal} == 0)\n"
"{\n"
"&log(DETAIL, \"no archive to remove, archiveId = ${strArchiveId}\");\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/InfoCommon.pm",
.data =
"\n\n\n\n"
"package pgBackRest::InfoCommon;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n\n\n\n"
"use constant INFO_BACKUP_SECTION_DB => 'db';\n"
"push @EXPORT, qw(INFO_BACKUP_SECTION_DB);\n"
"use constant INFO_BACKUP_SECTION_DB_HISTORY => INFO_BACKUP_SECTION_DB . ':history';\n"
"push @EXPORT, qw(INFO_BACKUP_SECTION_DB_HISTORY);\n"
"\n\n\n\n"
"use constant INFO_HISTORY_ID => 'id';\n"
"push @EXPORT, qw(INFO_HISTORY_ID);\n"
"use constant INFO_DB_VERSION => 'version';\n"
"push @EXPORT, qw(INFO_DB_VERSION);\n"
"use constant INFO_SYSTEM_ID => 'system-id';\n"
"push @EXPORT, qw(INFO_SYSTEM_ID);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/LibC.pm",
.data =
"\n\n\n"
"package pgBackRest::LibC;\n"
"use base 'Exporter';\n"
"\n"
"use 5.010001;\n"
"use strict;\n"
"use warnings;\n"
"use Carp;\n"
"\n"
"use pgBackRest::LibCAuto;\n"
"\n\n"
"my $rhConstant = pgBackRest::LibCAuto::libcAutoConstant();\n"
"\n"
"foreach my $strConstant (keys(%{$rhConstant}))\n"
"{\n"
"eval\n"
"\"use constant ${strConstant} => '\" . $rhConstant->{$strConstant} . \"'\";\n"
"}\n"
"\n\n"
"our %EXPORT_TAGS = %{pgBackRest::LibCAuto::libcAutoExportTag()};\n"
"our @EXPORT_OK;\n"
"\n"
"foreach my $strSection (keys(%EXPORT_TAGS))\n"
"{\n"
"\n\n"
"my $strPrefixLast = 'XXXXXXXX';\n"
"my $iConstantIdx = 0;\n"
"\n"
"foreach my $strConstant (@{$EXPORT_TAGS{$strSection}})\n"
"{\n"
"my $strPrefix = ($strConstant =~ m/^[A-Z0-9]+/g)[0];\n"
"\n"
"if (defined($strPrefix))\n"
"{\n"
"if ($strPrefix ne $strPrefixLast)\n"
"{\n"
"$iConstantIdx = 0;\n"
"}\n"
"else\n"
"{\n"
"$iConstantIdx++;\n"
"}\n"
"\n"
"if ($strPrefix eq 'CFGCMD' || $strPrefix eq 'CFGOPT')\n"
"{\n"
"eval\n"
"\"use constant ${strConstant} => ${iConstantIdx}\";\n"
"}\n"
"\n"
"$strPrefixLast = $strPrefix;\n"
"}\n"
"}\n"
"\n\n"
"push(@EXPORT_OK, @{$EXPORT_TAGS{$strSection}});\n"
"}\n"
"\n\n"
"our @EXPORT = ();\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/LibCAuto.pm",
.data =
"\n\n\n"
"package pgBackRest::LibCAuto;\n"
"\n"
"use strict;\n"
"use warnings;\n"
"\n\n"
"sub libcAutoConstant\n"
"{\n"
"return\n"
"{\n"
"CFGOPTVAL_INFO_OUTPUT_TEXT => 'text',\n"
"CFGOPTVAL_INFO_OUTPUT_JSON => 'json',\n"
"\n"
"CFGOPTVAL_REPO_CIPHER_TYPE_NONE => 'none',\n"
"CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC => 'aes-256-cbc',\n"
"\n"
"CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_FULL => 'full',\n"
"CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_DIFF => 'diff',\n"
"CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_INCR => 'incr',\n"
"\n"
"CFGOPTVAL_REPO_TYPE_CIFS => 'cifs',\n"
"CFGOPTVAL_REPO_TYPE_POSIX => 'posix',\n"
"CFGOPTVAL_REPO_TYPE_S3 => 's3',\n"
"\n"
"CFGOPTVAL_RESTORE_TARGET_ACTION_PAUSE => 'pause',\n"
"CFGOPTVAL_RESTORE_TARGET_ACTION_PROMOTE => 'promote',\n"
"CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN => 'shutdown',\n"
"\n"
"CFGOPTVAL_BACKUP_TYPE_FULL => 'full',\n"
"CFGOPTVAL_BACKUP_TYPE_DIFF => 'diff',\n"
"CFGOPTVAL_BACKUP_TYPE_INCR => 'incr',\n"
"\n"
"CFGOPTVAL_LOCAL_TYPE_DB => 'db',\n"
"CFGOPTVAL_LOCAL_TYPE_BACKUP => 'backup',\n"
"\n"
"CFGOPTVAL_REMOTE_TYPE_DB => 'db',\n"
"CFGOPTVAL_REMOTE_TYPE_BACKUP => 'backup',\n"
"\n"
"CFGOPTVAL_RESTORE_TYPE_NAME => 'name',\n"
"CFGOPTVAL_RESTORE_TYPE_TIME => 'time',\n"
"CFGOPTVAL_RESTORE_TYPE_XID => 'xid',\n"
"CFGOPTVAL_RESTORE_TYPE_PRESERVE => 'preserve',\n"
"CFGOPTVAL_RESTORE_TYPE_NONE => 'none',\n"
"CFGOPTVAL_RESTORE_TYPE_IMMEDIATE => 'immediate',\n"
"CFGOPTVAL_RESTORE_TYPE_DEFAULT => 'default',\n"
"\n"
"CFGDEF_TYPE_BOOLEAN => 0,\n"
"CFGDEF_TYPE_FLOAT => 1,\n"
"CFGDEF_TYPE_HASH => 2,\n"
"CFGDEF_TYPE_INTEGER => 3,\n"
"CFGDEF_TYPE_LIST => 4,\n"
"CFGDEF_TYPE_PATH => 5,\n"
"CFGDEF_TYPE_SIZE => 6,\n"
"CFGDEF_TYPE_STRING => 7,\n"
"\n"
"ENCODE_TYPE_BASE64 => 0,\n"
"\n"
"CIPHER_MODE_ENCRYPT => 0,\n"
"CIPHER_MODE_DECRYPT => 1,\n"
"}\n"
"}\n"
"\n\n"
"sub libcAutoExportTag\n"
"{\n"
"return\n"
"{\n"
"checksum =>\n"
"[\n"
"'pageChecksum',\n"
"'pageChecksumBufferTest',\n"
"'pageChecksumTest',\n"
"],\n"
"\n"
"config =>\n"
"[\n"
"'CFGOPTVAL_INFO_OUTPUT_TEXT',\n"
"'CFGOPTVAL_INFO_OUTPUT_JSON',\n"
"'CFGOPTVAL_REPO_CIPHER_TYPE_NONE',\n"
"'CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC',\n"
"'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_FULL',\n"
"'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_DIFF',\n"
"'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_INCR',\n"
"'CFGOPTVAL_REPO_TYPE_CIFS',\n"
"'CFGOPTVAL_REPO_TYPE_POSIX',\n"
"'CFGOPTVAL_REPO_TYPE_S3',\n"
"'CFGOPTVAL_RESTORE_TARGET_ACTION_PAUSE',\n"
"'CFGOPTVAL_RESTORE_TARGET_ACTION_PROMOTE',\n"
"'CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN',\n"
"'CFGOPTVAL_BACKUP_TYPE_FULL',\n"
"'CFGOPTVAL_BACKUP_TYPE_DIFF',\n"
"'CFGOPTVAL_BACKUP_TYPE_INCR',\n"
"'CFGOPTVAL_LOCAL_TYPE_DB',\n"
"'CFGOPTVAL_LOCAL_TYPE_BACKUP',\n"
"'CFGOPTVAL_REMOTE_TYPE_DB',\n"
"'CFGOPTVAL_REMOTE_TYPE_BACKUP',\n"
"'CFGOPTVAL_RESTORE_TYPE_NAME',\n"
"'CFGOPTVAL_RESTORE_TYPE_TIME',\n"
"'CFGOPTVAL_RESTORE_TYPE_XID',\n"
"'CFGOPTVAL_RESTORE_TYPE_PRESERVE',\n"
"'CFGOPTVAL_RESTORE_TYPE_NONE',\n"
"'CFGOPTVAL_RESTORE_TYPE_IMMEDIATE',\n"
"'CFGOPTVAL_RESTORE_TYPE_DEFAULT',\n"
"'CFGCMD_ARCHIVE_GET',\n"
"'CFGCMD_ARCHIVE_GET_ASYNC',\n"
"'CFGCMD_ARCHIVE_PUSH',\n"
"'CFGCMD_ARCHIVE_PUSH_ASYNC',\n"
"'CFGCMD_BACKUP',\n"
"'CFGCMD_CHECK',\n"
"'CFGCMD_EXPIRE',\n"
"'CFGCMD_HELP',\n"
"'CFGCMD_INFO',\n"
"'CFGCMD_LOCAL',\n"
"'CFGCMD_REMOTE',\n"
"'CFGCMD_RESTORE',\n"
"'CFGCMD_STANZA_CREATE',\n"
"'CFGCMD_STANZA_DELETE',\n"
"'CFGCMD_STANZA_UPGRADE',\n"
"'CFGCMD_START',\n"
"'CFGCMD_STOP',\n"
"'CFGCMD_VERSION',\n"
"'CFGOPT_ARCHIVE_ASYNC',\n"
"'CFGOPT_ARCHIVE_CHECK',\n"
"'CFGOPT_ARCHIVE_COPY',\n"
"'CFGOPT_ARCHIVE_GET_QUEUE_MAX',\n"
"'CFGOPT_ARCHIVE_PUSH_QUEUE_MAX',\n"
"'CFGOPT_ARCHIVE_TIMEOUT',\n"
"'CFGOPT_BACKUP_STANDBY',\n"
"'CFGOPT_BUFFER_SIZE',\n"
"'CFGOPT_C',\n"
"'CFGOPT_CHECKSUM_PAGE',\n"
"'CFGOPT_CMD_SSH',\n"
"'CFGOPT_COMMAND',\n"
"'CFGOPT_COMPRESS',\n"
"'CFGOPT_COMPRESS_LEVEL',\n"
"'CFGOPT_COMPRESS_LEVEL_NETWORK',\n"
"'CFGOPT_CONFIG',\n"
"'CFGOPT_CONFIG_INCLUDE_PATH',\n"
"'CFGOPT_CONFIG_PATH',\n"
"'CFGOPT_DB_INCLUDE',\n"
"'CFGOPT_DB_TIMEOUT',\n"
"'CFGOPT_DELTA',\n"
"'CFGOPT_EXCLUDE',\n"
"'CFGOPT_FORCE',\n"
"'CFGOPT_HOST_ID',\n"
"'CFGOPT_LINK_ALL',\n"
"'CFGOPT_LINK_MAP',\n"
"'CFGOPT_LOCK_PATH',\n"
"'CFGOPT_LOG_LEVEL_CONSOLE',\n"
"'CFGOPT_LOG_LEVEL_FILE',\n"
"'CFGOPT_LOG_LEVEL_STDERR',\n"
"'CFGOPT_LOG_PATH',\n"
"'CFGOPT_LOG_SUBPROCESS',\n"
"'CFGOPT_LOG_TIMESTAMP',\n"
"'CFGOPT_MANIFEST_SAVE_THRESHOLD',\n"
"'CFGOPT_NEUTRAL_UMASK',\n"
"'CFGOPT_ONLINE',\n"
"'CFGOPT_OUTPUT',\n"
"'CFGOPT_PERL_OPTION',\n"
"'CFGOPT_PG_HOST',\n"
"'CFGOPT_PG_HOST2',\n"
"'CFGOPT_PG_HOST3',\n"
"'CFGOPT_PG_HOST4',\n"
"'CFGOPT_PG_HOST5',\n"
"'CFGOPT_PG_HOST6',\n"
"'CFGOPT_PG_HOST7',\n"
"'CFGOPT_PG_HOST8',\n"
"'CFGOPT_PG_HOST_CMD',\n"
"'CFGOPT_PG_HOST_CMD2',\n"
"'CFGOPT_PG_HOST_CMD3',\n"
"'CFGOPT_PG_HOST_CMD4',\n"
"'CFGOPT_PG_HOST_CMD5',\n"
"'CFGOPT_PG_HOST_CMD6',\n"
"'CFGOPT_PG_HOST_CMD7',\n"
"'CFGOPT_PG_HOST_CMD8',\n"
"'CFGOPT_PG_HOST_CONFIG',\n"
"'CFGOPT_PG_HOST_CONFIG2',\n"
"'CFGOPT_PG_HOST_CONFIG3',\n"
"'CFGOPT_PG_HOST_CONFIG4',\n"
"'CFGOPT_PG_HOST_CONFIG5',\n"
"'CFGOPT_PG_HOST_CONFIG6',\n"
"'CFGOPT_PG_HOST_CONFIG7',\n"
"'CFGOPT_PG_HOST_CONFIG8',\n"
"'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH',\n"
"'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH2',\n"
"'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH3',\n"
"'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH4',\n"
"'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH5',\n"
"'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH6',\n"
"'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH7',\n"
"'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH8',\n"
"'CFGOPT_PG_HOST_CONFIG_PATH',\n"
"'CFGOPT_PG_HOST_CONFIG_PATH2',\n"
"'CFGOPT_PG_HOST_CONFIG_PATH3',\n"
"'CFGOPT_PG_HOST_CONFIG_PATH4',\n"
"'CFGOPT_PG_HOST_CONFIG_PATH5',\n"
"'CFGOPT_PG_HOST_CONFIG_PATH6',\n"
"'CFGOPT_PG_HOST_CONFIG_PATH7',\n"
"'CFGOPT_PG_HOST_CONFIG_PATH8',\n"
"'CFGOPT_PG_HOST_PORT',\n"
"'CFGOPT_PG_HOST_PORT2',\n"
"'CFGOPT_PG_HOST_PORT3',\n"
"'CFGOPT_PG_HOST_PORT4',\n"
"'CFGOPT_PG_HOST_PORT5',\n"
"'CFGOPT_PG_HOST_PORT6',\n"
"'CFGOPT_PG_HOST_PORT7',\n"
"'CFGOPT_PG_HOST_PORT8',\n"
"'CFGOPT_PG_HOST_USER',\n"
"'CFGOPT_PG_HOST_USER2',\n"
"'CFGOPT_PG_HOST_USER3',\n"
"'CFGOPT_PG_HOST_USER4',\n"
"'CFGOPT_PG_HOST_USER5',\n"
"'CFGOPT_PG_HOST_USER6',\n"
"'CFGOPT_PG_HOST_USER7',\n"
"'CFGOPT_PG_HOST_USER8',\n"
"'CFGOPT_PG_PATH',\n"
"'CFGOPT_PG_PATH2',\n"
"'CFGOPT_PG_PATH3',\n"
"'CFGOPT_PG_PATH4',\n"
"'CFGOPT_PG_PATH5',\n"
"'CFGOPT_PG_PATH6',\n"
"'CFGOPT_PG_PATH7',\n"
"'CFGOPT_PG_PATH8',\n"
"'CFGOPT_PG_PORT',\n"
"'CFGOPT_PG_PORT2',\n"
"'CFGOPT_PG_PORT3',\n"
"'CFGOPT_PG_PORT4',\n"
"'CFGOPT_PG_PORT5',\n"
"'CFGOPT_PG_PORT6',\n"
"'CFGOPT_PG_PORT7',\n"
"'CFGOPT_PG_PORT8',\n"
"'CFGOPT_PG_SOCKET_PATH',\n"
"'CFGOPT_PG_SOCKET_PATH2',\n"
"'CFGOPT_PG_SOCKET_PATH3',\n"
"'CFGOPT_PG_SOCKET_PATH4',\n"
"'CFGOPT_PG_SOCKET_PATH5',\n"
"'CFGOPT_PG_SOCKET_PATH6',\n"
"'CFGOPT_PG_SOCKET_PATH7',\n"
"'CFGOPT_PG_SOCKET_PATH8',\n"
"'CFGOPT_PROCESS',\n"
"'CFGOPT_PROCESS_MAX',\n"
"'CFGOPT_PROTOCOL_TIMEOUT',\n"
"'CFGOPT_RECOVERY_OPTION',\n"
"'CFGOPT_REPO_CIPHER_PASS',\n"
"'CFGOPT_REPO_CIPHER_TYPE',\n"
"'CFGOPT_REPO_HARDLINK',\n"
"'CFGOPT_REPO_HOST',\n"
"'CFGOPT_REPO_HOST_CMD',\n"
"'CFGOPT_REPO_HOST_CONFIG',\n"
"'CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH',\n"
"'CFGOPT_REPO_HOST_CONFIG_PATH',\n"
"'CFGOPT_REPO_HOST_PORT',\n"
"'CFGOPT_REPO_HOST_USER',\n"
"'CFGOPT_REPO_PATH',\n"
"'CFGOPT_REPO_RETENTION_ARCHIVE',\n"
"'CFGOPT_REPO_RETENTION_ARCHIVE_TYPE',\n"
"'CFGOPT_REPO_RETENTION_DIFF',\n"
"'CFGOPT_REPO_RETENTION_FULL',\n"
"'CFGOPT_REPO_S3_BUCKET',\n"
"'CFGOPT_REPO_S3_CA_FILE',\n"
"'CFGOPT_REPO_S3_CA_PATH',\n"
"'CFGOPT_REPO_S3_ENDPOINT',\n"
"'CFGOPT_REPO_S3_HOST',\n"
"'CFGOPT_REPO_S3_KEY',\n"
"'CFGOPT_REPO_S3_KEY_SECRET',\n"
"'CFGOPT_REPO_S3_REGION',\n"
"'CFGOPT_REPO_S3_TOKEN',\n"
"'CFGOPT_REPO_S3_VERIFY_TLS',\n"
"'CFGOPT_REPO_TYPE',\n"
"'CFGOPT_RESUME',\n"
"'CFGOPT_SET',\n"
"'CFGOPT_SPOOL_PATH',\n"
"'CFGOPT_STANZA',\n"
"'CFGOPT_START_FAST',\n"
"'CFGOPT_STOP_AUTO',\n"
"'CFGOPT_TABLESPACE_MAP',\n"
"'CFGOPT_TABLESPACE_MAP_ALL',\n"
"'CFGOPT_TARGET',\n"
"'CFGOPT_TARGET_ACTION',\n"
"'CFGOPT_TARGET_EXCLUSIVE',\n"
"'CFGOPT_TARGET_TIMELINE',\n"
"'CFGOPT_TEST',\n"
"'CFGOPT_TEST_DELAY',\n"
"'CFGOPT_TEST_POINT',\n"
"'CFGOPT_TYPE',\n"
"'cfgCommandName',\n"
"'cfgOptionIndex',\n"
"'cfgOptionIndexTotal',\n"
"'cfgOptionName',\n"
"],\n"
"\n"
"configDefine =>\n"
"[\n"
"'CFGDEF_TYPE_BOOLEAN',\n"
"'CFGDEF_TYPE_FLOAT',\n"
"'CFGDEF_TYPE_HASH',\n"
"'CFGDEF_TYPE_INTEGER',\n"
"'CFGDEF_TYPE_LIST',\n"
"'CFGDEF_TYPE_PATH',\n"
"'CFGDEF_TYPE_SIZE',\n"
"'CFGDEF_TYPE_STRING',\n"
"'cfgCommandId',\n"
"'cfgDefOptionDefault',\n"
"'cfgDefOptionPrefix',\n"
"'cfgDefOptionSecure',\n"
"'cfgDefOptionType',\n"
"'cfgDefOptionValid',\n"
"'cfgOptionId',\n"
"'cfgOptionTotal',\n"
"],\n"
"\n"
"crypto =>\n"
"[\n"
"'CIPHER_MODE_ENCRYPT',\n"
"'CIPHER_MODE_DECRYPT',\n"
"'cryptoHashOne',\n"
"],\n"
"\n"
"debug =>\n"
"[\n"
"'libcUvSize',\n"
"],\n"
"\n"
"encode =>\n"
"[\n"
"'ENCODE_TYPE_BASE64',\n"
"'decodeToBin',\n"
"'encodeToStr',\n"
"],\n"
"\n"
"lock =>\n"
"[\n"
"'lockAcquire',\n"
"'lockRelease',\n"
"],\n"
"\n"
"random =>\n"
"[\n"
"'cryptoRandomBytes',\n"
"],\n"
"\n"
"storage =>\n"
"[\n"
"'storagePosixPathRemove',\n"
"],\n"
"\n"
"test =>\n"
"[\n"
"'cfgParseTest',\n"
"],\n"
"}\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Main.pm",
.data =
"\n\n\n"
"package pgBackRest::Main;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n\n"
"$SIG{__DIE__} = sub {Carp::confess @_};\n"
"\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Lock;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Storage::Helper;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"my $strConfigJson;\n"
"my $strConfigBin;\n"
"my $bConfigLoaded = false;\n"
"\n"
"sub mainConfigSet\n"
"{\n"
"$strConfigBin = shift;\n"
"$strConfigJson = shift;\n"
"}\n"
"\n\n\n\n"
"sub main\n"
"{\n"
"my $strCommand = shift;\n"
"my @stryCommandArg = @_;\n"
"\n\n\n"
"my $iResult = 0;\n"
"my $bErrorC = false;\n"
"my $strMessage = '';\n"
"\n"
"eval\n"
"{\n"
"\n\n"
"if (!$bConfigLoaded)\n"
"{\n"
"configLoad(undef, $strConfigBin, $strCommand, \\$strConfigJson);\n"
"\n\n"
"if (cfgOptionTest(CFGOPT_TEST) && cfgOption(CFGOPT_TEST))\n"
"{\n"
"testSet(cfgOption(CFGOPT_TEST), cfgOption(CFGOPT_TEST_DELAY), cfgOption(CFGOPT_TEST_POINT, false));\n"
"}\n"
"\n"
"$bConfigLoaded = true;\n"
"}\n"
"else\n"
"{\n"
"cfgCommandSet(cfgCommandId($strCommand));\n"
"}\n"
"\n\n\n"
"if (cfgCommandTest(CFGCMD_REMOTE))\n"
"{\n"
"\n"
"cfgOptionSet(CFGOPT_LOG_LEVEL_STDERR, PROTOCOL, true);\n"
"logLevelSet(cfgOption(CFGOPT_LOG_LEVEL_FILE), OFF, cfgOption(CFGOPT_LOG_LEVEL_STDERR));\n"
"\n"
"logFileSet(\n"
"storageLocal(),\n"
"cfgOption(CFGOPT_LOG_PATH) . '/' . (cfgOptionTest(CFGOPT_STANZA) ? cfgOption(CFGOPT_STANZA) : 'all') . '-' .\n"
"lc(cfgOption(CFGOPT_COMMAND)) . '-' . lc(cfgCommandName(cfgCommandGet())) . '-' .\n"
"sprintf(\"%03d\", cfgOption(CFGOPT_PROCESS)));\n"
"\n"
"if (cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) &&\n"
"!cfgOptionTest(CFGOPT_REPO_TYPE, CFGOPTVAL_REPO_TYPE_S3) &&\n"
"!-e cfgOption(CFGOPT_REPO_PATH))\n"
"{\n"
"confess &log(ERROR,\n"
"cfgOptionName(CFGOPT_REPO_PATH) . ' \\'' . cfgOption(CFGOPT_REPO_PATH) . '\\' does not exist',\n"
"ERROR_PATH_MISSING);\n"
"}\n"
"\n\n"
"require pgBackRest::Protocol::Remote::Minion;\n"
"pgBackRest::Protocol::Remote::Minion->import();\n"
"\n\n"
"my $oRemote = new pgBackRest::Protocol::Remote::Minion(\n"
"cfgOption(CFGOPT_BUFFER_SIZE), cfgOption(CFGOPT_PROTOCOL_TIMEOUT));\n"
"\n\n"
"$oRemote->process(\n"
"cfgOption(CFGOPT_LOCK_PATH), cfgOption(CFGOPT_COMMAND), cfgOption(CFGOPT_STANZA, false), cfgOption(CFGOPT_PROCESS));\n"
"}\n"
"\n\n\n"
"elsif (cfgCommandTest(CFGCMD_LOCAL))\n"
"{\n"
"\n"
"cfgOptionSet(CFGOPT_LOG_LEVEL_STDERR, PROTOCOL, true);\n"
"logLevelSet(cfgOption(CFGOPT_LOG_LEVEL_FILE), OFF, cfgOption(CFGOPT_LOG_LEVEL_STDERR));\n"
"\n"
"logFileSet(\n"
"storageLocal(),\n"
"cfgOption(CFGOPT_LOG_PATH) . '/' . cfgOption(CFGOPT_STANZA) . '-' . lc(cfgOption(CFGOPT_COMMAND)) . '-' .\n"
"lc(cfgCommandName(cfgCommandGet())) . '-' . sprintf(\"%03d\", cfgOption(CFGOPT_PROCESS)));\n"
"\n\n"
"require pgBackRest::Protocol::Local::Minion;\n"
"pgBackRest::Protocol::Local::Minion->import();\n"
"\n\n"
"my $oLocal = new pgBackRest::Protocol::Local::Minion();\n"
"\n\n"
"$oLocal->process();\n"
"}\n"
"\n\n\n"
"elsif (cfgCommandTest(CFGCMD_CHECK))\n"
"{\n"
"\n"
"require pgBackRest::Check::Check;\n"
"pgBackRest::Check::Check->import();\n"
"\n"
"$iResult = new pgBackRest::Check::Check()->process();\n"
"}\n"
"\n\n\n"
"elsif (cfgCommandTest(CFGCMD_START))\n"
"{\n"
"lockStart();\n"
"}\n"
"elsif (cfgCommandTest(CFGCMD_STOP))\n"
"{\n"
"lockStop();\n"
"}\n"
"else\n"
"{\n"
"\n"
"require pgBackRest::Protocol::Storage::Helper;\n"
"pgBackRest::Protocol::Storage::Helper->import();\n"
"\n"
"if (isRepoLocal() && !cfgOptionTest(CFGOPT_REPO_TYPE, CFGOPTVAL_REPO_TYPE_S3) && !storageRepo()->pathExists(''))\n"
"{\n"
"confess &log(ERROR,\n"
"cfgOptionName(CFGOPT_REPO_PATH) . ' \\'' . cfgOption(CFGOPT_REPO_PATH) . '\\' does not exist',\n"
"ERROR_PATH_MISSING);\n"
"}\n"
"\n\n\n"
"if (cfgCommandTest(CFGCMD_INFO))\n"
"{\n"
"\n"
"require pgBackRest::Info;\n"
"pgBackRest::Info->import();\n"
"\n"
"new pgBackRest::Info()->process();\n"
"}\n"
"else\n"
"{\n"
"logFileSet(\n"
"storageLocal(),\n"
"cfgOption(CFGOPT_LOG_PATH) . '/' . cfgOption(CFGOPT_STANZA) . '-' . lc(cfgCommandName(cfgCommandGet())));\n"
"\n\n\n"
"if (cfgCommandTest(CFGCMD_STANZA_DELETE))\n"
"{\n"
"\n"
"require pgBackRest::Stanza;\n"
"pgBackRest::Stanza->import();\n"
"\n"
"new pgBackRest::Stanza()->process();\n"
"}\n"
"\n\n"
"elsif (cfgCommandTest(CFGCMD_RESTORE))\n"
"{\n"
"\n"
"if (!isDbLocal())\n"
"{\n"
"confess &log(ERROR,\n"
"cfgCommandName(cfgCommandGet()) . ' command must be run on the PostgreSQL host', ERROR_HOST_INVALID);\n"
"}\n"
"\n\n"
"require pgBackRest::Restore;\n"
"pgBackRest::Restore->import();\n"
"\n\n"
"new pgBackRest::Restore()->process();\n"
"}\n"
"else\n"
"{\n"
"\n"
"lockStopTest();\n"
"\n\n"
"if (!isRepoLocal())\n"
"{\n"
"confess &log(ERROR,\n"
"cfgCommandName(cfgCommandGet()) . ' command must be run on the repository host', ERROR_HOST_INVALID);\n"
"}\n"
"\n\n\n"
"if (cfgCommandTest(CFGCMD_STANZA_CREATE) || cfgCommandTest(CFGCMD_STANZA_UPGRADE))\n"
"{\n"
"\n"
"require pgBackRest::Stanza;\n"
"pgBackRest::Stanza->import();\n"
"\n"
"$iResult = new pgBackRest::Stanza()->process();\n"
"}\n"
"\n\n\n"
"elsif (cfgCommandTest(CFGCMD_BACKUP))\n"
"{\n"
"\n"
"require pgBackRest::Backup::Backup;\n"
"pgBackRest::Backup::Backup->import();\n"
"\n"
"new pgBackRest::Backup::Backup()->process();\n"
"}\n"
"\n\n\n"
"elsif (cfgCommandTest(CFGCMD_EXPIRE))\n"
"{\n"
"\n"
"require pgBackRest::Expire;\n"
"pgBackRest::Expire->import();\n"
"\n"
"new pgBackRest::Expire()->process();\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n"
"return 1;\n"
"}\n"
"\n\n\n"
"or do\n"
"{\n"
"\n\n\n"
"my $oException = defined($EVAL_ERROR) && length($EVAL_ERROR) > 0 ? $EVAL_ERROR : logErrorLast();\n"
"\n\n"
"if (isException(\\$oException))\n"
"{\n"
"$iResult = $oException->code();\n"
"$bErrorC = $oException->errorC();\n"
"\n\n"
"if (!$bConfigLoaded && cfgOption(CFGOPT_ARCHIVE_ASYNC))\n"
"{\n"
"$strMessage = $oException->message();\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"$iResult = ERROR_UNHANDLED;\n"
"$strMessage =\n"
"'process terminated due to an unhandled exception' .\n"
"(defined($oException) ? \":\\n${oException}\" : ': [exception not defined]');\n"
"}\n"
"};\n"
"\n\n"
"return $iResult, $bErrorC, $strMessage;\n"
"}\n"
"\n\n\n\n"
"sub mainCleanup\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iExitCode,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::mainCleanup', \\@_,\n"
"{name => 'iExitCode', required => false},\n"
");\n"
"\n\n"
"eval\n"
"{\n"
"protocolDestroy(undef, undef, defined($iExitCode) && ($iExitCode == 0 || $iExitCode == 1));\n"
"return true;\n"
"}\n"
"\n"
"or do {};\n"
"\n\n"
"eval\n"
"{\n"
"lockRelease(false);\n"
"return true;\n"
"}\n"
"\n"
"or do {};\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Manifest.pm",
.data =
"\n\n\n"
"package pgBackRest::Manifest;\n"
"use parent 'pgBackRest::Common::Ini';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname basename);\n"
"use Time::Local qw(timelocal);\n"
"\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n"
"use constant PATH_BACKUP_HISTORY => 'backup.history';\n"
"push @EXPORT, qw(PATH_BACKUP_HISTORY);\n"
"use constant FILE_MANIFEST => 'backup.manifest';\n"
"push @EXPORT, qw(FILE_MANIFEST);\n"
"use constant FILE_MANIFEST_COPY => FILE_MANIFEST . INI_COPY_EXT;\n"
"push @EXPORT, qw(FILE_MANIFEST_COPY);\n"
"\n\n\n\n"
"use constant MANIFEST_DEFAULT_MATCH_FACTOR => 0.1;\n"
"push @EXPORT, qw(MANIFEST_DEFAULT_MATCH_FACTOR);\n"
"\n\n\n\n"
"use constant MANIFEST_TARGET_PGDATA => 'pg_data';\n"
"push @EXPORT, qw(MANIFEST_TARGET_PGDATA);\n"
"use constant MANIFEST_TARGET_PGTBLSPC => 'pg_tblspc';\n"
"push @EXPORT, qw(MANIFEST_TARGET_PGTBLSPC);\n"
"\n"
"use constant MANIFEST_VALUE_PATH => 'path';\n"
"push @EXPORT, qw(MANIFEST_VALUE_PATH);\n"
"use constant MANIFEST_VALUE_LINK => 'link';\n"
"push @EXPORT, qw(MANIFEST_VALUE_LINK);\n"
"\n\n"
"use constant MANIFEST_SECTION_BACKUP => 'backup';\n"
"push @EXPORT, qw(MANIFEST_SECTION_BACKUP);\n"
"use constant MANIFEST_SECTION_BACKUP_DB => 'backup:db';\n"
"push @EXPORT, qw(MANIFEST_SECTION_BACKUP_DB);\n"
"use constant MANIFEST_SECTION_BACKUP_INFO => 'backup:info';\n"
"push @EXPORT, qw(MANIFEST_SECTION_BACKUP_INFO);\n"
"use constant MANIFEST_SECTION_BACKUP_OPTION => 'backup:option';\n"
"push @EXPORT, qw(MANIFEST_SECTION_BACKUP_OPTION);\n"
"use constant MANIFEST_SECTION_BACKUP_TARGET => 'backup:target';\n"
"push @EXPORT, qw(MANIFEST_SECTION_BACKUP_TARGET);\n"
"use constant MANIFEST_SECTION_DB => 'db';\n"
"push @EXPORT, qw(MANIFEST_SECTION_DB);\n"
"use constant MANIFEST_SECTION_TARGET_PATH => 'target:path';\n"
"push @EXPORT, qw(MANIFEST_SECTION_TARGET_PATH);\n"
"use constant MANIFEST_SECTION_TARGET_FILE => 'target:file';\n"
"push @EXPORT, qw(MANIFEST_SECTION_TARGET_FILE);\n"
"use constant MANIFEST_SECTION_TARGET_LINK => 'target:link';\n"
"push @EXPORT, qw(MANIFEST_SECTION_TARGET_LINK);\n"
"\n\n"
"use constant MANIFEST_KEY_ARCHIVE_START => 'backup-archive-start';\n"
"push @EXPORT, qw(MANIFEST_KEY_ARCHIVE_START);\n"
"use constant MANIFEST_KEY_ARCHIVE_STOP => 'backup-archive-stop';\n"
"push @EXPORT, qw(MANIFEST_KEY_ARCHIVE_STOP);\n"
"use constant MANIFEST_KEY_LABEL => 'backup-label';\n"
"push @EXPORT, qw(MANIFEST_KEY_LABEL);\n"
"use constant MANIFEST_KEY_LSN_START => 'backup-lsn-start';\n"
"push @EXPORT, qw(MANIFEST_KEY_LSN_START);\n"
"use constant MANIFEST_KEY_LSN_STOP => 'backup-lsn-stop';\n"
"push @EXPORT, qw(MANIFEST_KEY_LSN_STOP);\n"
"use constant MANIFEST_KEY_PRIOR => 'backup-prior';\n"
"push @EXPORT, qw(MANIFEST_KEY_PRIOR);\n"
"use constant MANIFEST_KEY_TIMESTAMP_COPY_START => 'backup-timestamp-copy-start';\n"
"push @EXPORT, qw(MANIFEST_KEY_TIMESTAMP_COPY_START);\n"
"use constant MANIFEST_KEY_TIMESTAMP_START => 'backup-timestamp-start';\n"
"push @EXPORT, qw(MANIFEST_KEY_TIMESTAMP_START);\n"
"use constant MANIFEST_KEY_TIMESTAMP_STOP => 'backup-timestamp-stop';\n"
"push @EXPORT, qw(MANIFEST_KEY_TIMESTAMP_STOP);\n"
"use constant MANIFEST_KEY_TYPE => 'backup-type';\n"
"push @EXPORT, qw(MANIFEST_KEY_TYPE);\n"
"\n\n"
"use constant MANIFEST_KEY_BACKUP_STANDBY => 'option-' . cfgOptionName(CFGOPT_BACKUP_STANDBY);\n"
"push @EXPORT, qw(MANIFEST_KEY_BACKUP_STANDBY);\n"
"use constant MANIFEST_KEY_HARDLINK => 'option-hardlink';\n"
"push @EXPORT, qw(MANIFEST_KEY_HARDLINK);\n"
"use constant MANIFEST_KEY_ARCHIVE_CHECK => 'option-' . cfgOptionName(CFGOPT_ARCHIVE_CHECK);\n"
"push @EXPORT, qw(MANIFEST_KEY_ARCHIVE_CHECK);\n"
"use constant MANIFEST_KEY_ARCHIVE_COPY => 'option-' .cfgOptionName(CFGOPT_ARCHIVE_COPY);\n"
"push @EXPORT, qw(MANIFEST_KEY_ARCHIVE_COPY);\n"
"use constant MANIFEST_KEY_BUFFER_SIZE => 'option-' . cfgOptionName(CFGOPT_BUFFER_SIZE);\n"
"push @EXPORT, qw(MANIFEST_KEY_BUFFER_SIZE);\n"
"use constant MANIFEST_KEY_CHECKSUM_PAGE => 'option-' . cfgOptionName(CFGOPT_CHECKSUM_PAGE);\n"
"push @EXPORT, qw(MANIFEST_KEY_CHECKSUM_PAGE);\n"
"use constant MANIFEST_KEY_COMPRESS => 'option-' . cfgOptionName(CFGOPT_COMPRESS);\n"
"push @EXPORT, qw(MANIFEST_KEY_COMPRESS);\n"
"use constant MANIFEST_KEY_COMPRESS_LEVEL => 'option-' . cfgOptionName(CFGOPT_COMPRESS_LEVEL);\n"
"push @EXPORT, qw(MANIFEST_KEY_COMPRESS_LEVEL);\n"
"use constant MANIFEST_KEY_COMPRESS_LEVEL_NETWORK => 'option-' . cfgOptionName(CFGOPT_COMPRESS_LEVEL_NETWORK);\n"
"push @EXPORT, qw(MANIFEST_KEY_COMPRESS_LEVEL_NETWORK);\n"
"use constant MANIFEST_KEY_ONLINE => 'option-' . cfgOptionName(CFGOPT_ONLINE);\n"
"push @EXPORT, qw(MANIFEST_KEY_ONLINE);\n"
"use constant MANIFEST_KEY_DELTA => 'option-' . cfgOptionName(CFGOPT_DELTA);\n"
"push @EXPORT, qw(MANIFEST_KEY_DELTA);\n"
"use constant MANIFEST_KEY_PROCESS_MAX => 'option-' . cfgOptionName(CFGOPT_PROCESS_MAX);\n"
"push @EXPORT, qw(MANIFEST_KEY_PROCESS_MAX);\n"
"\n\n"
"use constant MANIFEST_KEY_DB_ID => 'db-id';\n"
"push @EXPORT, qw(MANIFEST_KEY_DB_ID);\n"
"use constant MANIFEST_KEY_SYSTEM_ID => 'db-system-id';\n"
"push @EXPORT, qw(MANIFEST_KEY_SYSTEM_ID);\n"
"use constant MANIFEST_KEY_CATALOG => 'db-catalog-version';\n"
"push @EXPORT, qw(MANIFEST_KEY_CATALOG);\n"
"use constant MANIFEST_KEY_CONTROL => 'db-control-version';\n"
"push @EXPORT, qw(MANIFEST_KEY_CONTROL);\n"
"use constant MANIFEST_KEY_DB_LAST_SYSTEM_ID => 'db-last-system-id';\n"
"push @EXPORT, qw(MANIFEST_KEY_DB_LAST_SYSTEM_ID);\n"
"use constant MANIFEST_KEY_DB_VERSION => 'db-version';\n"
"push @EXPORT, qw(MANIFEST_KEY_DB_VERSION);\n"
"\n\n"
"use constant MANIFEST_SUBKEY_CHECKSUM => 'checksum';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_CHECKSUM);\n"
"use constant MANIFEST_SUBKEY_CHECKSUM_PAGE => 'checksum-page';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_CHECKSUM_PAGE);\n"
"use constant MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR => 'checksum-page-error';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR);\n"
"use constant MANIFEST_SUBKEY_DESTINATION => 'destination';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_DESTINATION);\n"
"use constant MANIFEST_SUBKEY_FILE => 'file';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_FILE);\n"
"use constant MANIFEST_SUBKEY_FUTURE => 'future';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_FUTURE);\n"
"use constant MANIFEST_SUBKEY_GROUP => 'group';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_GROUP);\n"
"use constant MANIFEST_SUBKEY_MASTER => 'master';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_MASTER);\n"
"use constant MANIFEST_SUBKEY_MODE => 'mode';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_MODE);\n"
"use constant MANIFEST_SUBKEY_TIMESTAMP => 'timestamp';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_TIMESTAMP);\n"
"use constant MANIFEST_SUBKEY_TYPE => 'type';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_TYPE);\n"
"use constant MANIFEST_SUBKEY_PATH => 'path';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_PATH);\n"
"use constant MANIFEST_SUBKEY_REFERENCE => 'reference';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_REFERENCE);\n"
"use constant MANIFEST_SUBKEY_REPO_SIZE => 'repo-size';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_REPO_SIZE);\n"
"use constant MANIFEST_SUBKEY_SIZE => 'size';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_SIZE);\n"
"use constant MANIFEST_SUBKEY_TABLESPACE_ID => 'tablespace-id';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_TABLESPACE_ID);\n"
"use constant MANIFEST_SUBKEY_TABLESPACE_NAME => 'tablespace-name';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_TABLESPACE_NAME);\n"
"use constant MANIFEST_SUBKEY_USER => 'user';\n"
"push @EXPORT, qw(MANIFEST_SUBKEY_USER);\n"
"\n\n\n\n"
"use constant DB_PATH_ARCHIVESTATUS => 'archive_status';\n"
"push @EXPORT, qw(DB_PATH_ARCHIVESTATUS);\n"
"use constant DB_PATH_BASE => 'base';\n"
"push @EXPORT, qw(DB_PATH_BASE);\n"
"use constant DB_PATH_GLOBAL => 'global';\n"
"push @EXPORT, qw(DB_PATH_GLOBAL);\n"
"use constant DB_PATH_PGDYNSHMEM => 'pg_dynshmem';\n"
"push @EXPORT, qw(DB_PATH_PGDYNSHMEM);\n"
"use constant DB_PATH_PGMULTIXACT => 'pg_multixact';\n"
"push @EXPORT, qw(DB_PATH_PGMULTIXACT);\n"
"use constant DB_PATH_PGNOTIFY => 'pg_notify';\n"
"push @EXPORT, qw(DB_PATH_PGNOTIFY);\n"
"use constant DB_PATH_PGREPLSLOT => 'pg_replslot';\n"
"push @EXPORT, qw(DB_PATH_PGREPLSLOT);\n"
"use constant DB_PATH_PGSERIAL => 'pg_serial';\n"
"push @EXPORT, qw(DB_PATH_PGSERIAL);\n"
"use constant DB_PATH_PGSNAPSHOTS => 'pg_snapshots';\n"
"push @EXPORT, qw(DB_PATH_PGSNAPSHOTS);\n"
"use constant DB_PATH_PGSTATTMP => 'pg_stat_tmp';\n"
"push @EXPORT, qw(DB_PATH_PGSTATTMP);\n"
"use constant DB_PATH_PGSUBTRANS => 'pg_subtrans';\n"
"push @EXPORT, qw(DB_PATH_PGSUBTRANS);\n"
"use constant DB_PATH_PGTBLSPC => 'pg_tblspc';\n"
"push @EXPORT, qw(DB_PATH_PGTBLSPC);\n"
"\n"
"use constant DB_FILE_BACKUPLABEL => 'backup_label';\n"
"push @EXPORT, qw(DB_FILE_BACKUPLABEL);\n"
"use constant DB_FILE_BACKUPLABELOLD => DB_FILE_BACKUPLABEL . '.old';\n"
"push @EXPORT, qw(DB_FILE_BACKUPLABELOLD);\n"
"use constant DB_FILE_PGCONTROL => DB_PATH_GLOBAL . '/pg_control';\n"
"push @EXPORT, qw(DB_FILE_PGCONTROL);\n"
"use constant DB_FILE_PGFILENODEMAP => 'pg_filenode.map';\n"
"push @EXPORT, qw(DB_FILE_PGFILENODEMAP);\n"
"use constant DB_FILE_PGINTERNALINIT => 'pg_internal.init';\n"
"push @EXPORT, qw(DB_FILE_PGINTERNALINIT);\n"
"use constant DB_FILE_PGVERSION => 'PG_VERSION';\n"
"push @EXPORT, qw(DB_FILE_PGVERSION);\n"
"use constant DB_FILE_POSTGRESQLAUTOCONFTMP => 'postgresql.auto.conf.tmp';\n"
"push @EXPORT, qw(DB_FILE_POSTGRESQLAUTOCONFTMP);\n"
"use constant DB_FILE_POSTMASTEROPTS => 'postmaster.opts';\n"
"push @EXPORT, qw(DB_FILE_POSTMASTEROPTS);\n"
"use constant DB_FILE_POSTMASTERPID => 'postmaster.pid';\n"
"push @EXPORT, qw(DB_FILE_POSTMASTERPID);\n"
"use constant DB_FILE_RECOVERYCONF => 'recovery.conf';\n"
"push @EXPORT, qw(DB_FILE_RECOVERYCONF);\n"
"use constant DB_FILE_RECOVERYDONE => 'recovery.done';\n"
"push @EXPORT, qw(DB_FILE_RECOVERYDONE);\n"
"use constant DB_FILE_TABLESPACEMAP => 'tablespace_map';\n"
"push @EXPORT, qw(DB_FILE_TABLESPACEMAP);\n"
"\n"
"use constant DB_FILE_PREFIX_TMP => 'pgsql_tmp';\n"
"push @EXPORT, qw(DB_FILE_PREFIX_TMP);\n"
"\n\n\n\n"
"use constant MANIFEST_PATH_BASE => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_BASE;\n"
"push @EXPORT, qw(MANIFEST_PATH_BASE);\n"
"use constant MANIFEST_PATH_GLOBAL => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_GLOBAL;\n"
"push @EXPORT, qw(MANIFEST_PATH_GLOBAL);\n"
"use constant MANIFEST_PATH_PGDYNSHMEM => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGDYNSHMEM;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGDYNSHMEM);\n"
"use constant MANIFEST_PATH_PGMULTIXACT => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGMULTIXACT;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGMULTIXACT);\n"
"use constant MANIFEST_PATH_PGNOTIFY => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGNOTIFY;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGNOTIFY);\n"
"use constant MANIFEST_PATH_PGREPLSLOT => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGREPLSLOT;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGREPLSLOT);\n"
"use constant MANIFEST_PATH_PGSERIAL => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGSERIAL;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGSERIAL);\n"
"use constant MANIFEST_PATH_PGSNAPSHOTS => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGSNAPSHOTS;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGSNAPSHOTS);\n"
"use constant MANIFEST_PATH_PGSTATTMP => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGSTATTMP;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGSTATTMP);\n"
"use constant MANIFEST_PATH_PGSUBTRANS => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGSUBTRANS;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGSUBTRANS);\n"
"use constant MANIFEST_PATH_PGTBLSPC => MANIFEST_TARGET_PGDATA . '/' . DB_PATH_PGTBLSPC;\n"
"push @EXPORT, qw(MANIFEST_PATH_PGTBLSPC);\n"
"\n"
"use constant MANIFEST_FILE_BACKUPLABEL => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_BACKUPLABEL;\n"
"push @EXPORT, qw(MANIFEST_FILE_BACKUPLABEL);\n"
"use constant MANIFEST_FILE_BACKUPLABELOLD => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_BACKUPLABELOLD;\n"
"push @EXPORT, qw(MANIFEST_FILE_BACKUPLABELOLD);\n"
"use constant MANIFEST_FILE_PGCONTROL => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_PGCONTROL;\n"
"push @EXPORT, qw(MANIFEST_FILE_PGCONTROL);\n"
"use constant MANIFEST_FILE_POSTGRESQLAUTOCONFTMP => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_POSTGRESQLAUTOCONFTMP;\n"
"push @EXPORT, qw(MANIFEST_FILE_PGCONTROL);\n"
"use constant MANIFEST_FILE_POSTMASTEROPTS => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_POSTMASTEROPTS;\n"
"push @EXPORT, qw(MANIFEST_FILE_POSTMASTEROPTS);\n"
"use constant MANIFEST_FILE_POSTMASTERPID => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_POSTMASTERPID;\n"
"push @EXPORT, qw(MANIFEST_FILE_POSTMASTERPID);\n"
"use constant MANIFEST_FILE_RECOVERYCONF => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_RECOVERYCONF;\n"
"push @EXPORT, qw(MANIFEST_FILE_RECOVERYCONF);\n"
"use constant MANIFEST_FILE_RECOVERYDONE => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_RECOVERYDONE;\n"
"push @EXPORT, qw(MANIFEST_FILE_RECOVERYDONE);\n"
"use constant MANIFEST_FILE_TABLESPACEMAP => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_TABLESPACEMAP;\n"
"push @EXPORT, qw(MANIFEST_FILE_TABLESPACEMAP);\n"
"\n\n\n\n"
"use constant DB_USER_OBJECT_MINIMUM_ID => 16384;\n"
"push @EXPORT, qw(DB_USER_OBJECT_MINIMUM_ID);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFileName,\n"
"$bLoad,\n"
"$oStorage,\n"
"$strDbVersion,\n"
"$iDbCatalogVersion,\n"
"$strCipherPass,\n"
"$strCipherPassSub,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strFileName', trace => true},\n"
"{name => 'bLoad', optional => true, default => true, trace => true},\n"
"{name => 'oStorage', optional => true, default => storageRepo(), trace => true},\n"
"{name => 'strDbVersion', optional => true, trace => true},\n"
"{name => 'iDbCatalogVersion', optional => true, trace => true},\n"
"{name => 'strCipherPass', optional => true, redact => true},\n"
"{name => 'strCipherPassSub', optional => true, redact => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($strFileName, {bLoad => $bLoad, oStorage => $oStorage, strCipherPass => $strCipherPass,\n"
"strCipherPassSub => $strCipherPassSub});\n"
"\n\n"
"if (!$bLoad)\n"
"{\n"
"if (!(defined($strDbVersion) && defined($iDbCatalogVersion)))\n"
"{\n"
"confess &log(ASSERT, 'strDbVersion and iDbCatalogVersion must be provided with bLoad = false');\n"
"}\n"
"\n"
"$self->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, $strDbVersion);\n"
"$self->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $iDbCatalogVersion);\n"
"}\n"
"\n\n"
"$self->{bBuilt} = $bLoad;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub save\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->save');\n"
"\n\n"
"$self->SUPER::save();\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub get\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strKey = shift;\n"
"my $strSubKey = shift;\n"
"my $bRequired = shift;\n"
"my $oDefault = shift;\n"
"\n"
"my $oValue = $self->SUPER::get($strSection, $strKey, $strSubKey, false);\n"
"\n"
"if (!defined($oValue) && defined($strKey) && defined($strSubKey) &&\n"
"($strSection eq MANIFEST_SECTION_TARGET_FILE || $strSection eq MANIFEST_SECTION_TARGET_PATH ||\n"
"$strSection eq MANIFEST_SECTION_TARGET_LINK) &&\n"
"($strSubKey eq MANIFEST_SUBKEY_USER || $strSubKey eq MANIFEST_SUBKEY_GROUP ||\n"
"$strSubKey eq MANIFEST_SUBKEY_MODE || $strSubKey eq MANIFEST_SUBKEY_MASTER) &&\n"
"$self->test($strSection, $strKey))\n"
"{\n"
"$oValue = $self->SUPER::get(\"${strSection}:default\", $strSubKey, undef, $bRequired, $oDefault);\n"
"}\n"
"else\n"
"{\n"
"$oValue = $self->SUPER::get($strSection, $strKey, $strSubKey, $bRequired, $oDefault);\n"
"}\n"
"\n"
"return $oValue;\n"
"}\n"
"\n\n\n\n\n\n"
"sub boolGet\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strValue = shift;\n"
"my $strSubValue = shift;\n"
"my $bRequired = shift;\n"
"my $bDefault = shift;\n"
"\n"
"return $self->get($strSection, $strValue, $strSubValue, $bRequired,\n"
"defined($bDefault) ? ($bDefault ? INI_TRUE : INI_FALSE) : undef) ? true : false;\n"
"}\n"
"\n\n\n\n\n\n"
"sub numericGet\n"
"{\n"
"my $self = shift;\n"
"my $strSection = shift;\n"
"my $strValue = shift;\n"
"my $strSubValue = shift;\n"
"my $bRequired = shift;\n"
"my $nDefault = shift;\n"
"\n"
"return $self->get($strSection, $strValue, $strSubValue, $bRequired,\n"
"defined($nDefault) ? $nDefault + 0 : undef) + 0;\n"
"}\n"
"\n\n\n\n\n\n"
"sub tablespacePathGet\n"
"{\n"
"my $self = shift;\n"
"\n"
"return('PG_' . $self->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION) .\n"
"'_' . $self->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG));\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbPathGet\n"
"{\n"
"my $self = shift;\n"
"my $strDbPath = shift;\n"
"my $strFile = shift;\n"
"\n"
"my $strDbFile = defined($strDbPath) ? \"${strDbPath}/\" : '';\n"
"\n"
"if (index($strFile, MANIFEST_TARGET_PGDATA . '/') == 0)\n"
"{\n"
"$strDbFile .= substr($strFile, length(MANIFEST_TARGET_PGDATA) + 1);\n"
"}\n"
"else\n"
"{\n"
"$strDbFile .= $strFile;\n"
"}\n"
"\n"
"return $strDbFile;\n"
"}\n"
"\n\n\n\n\n\n"
"sub repoPathGet\n"
"{\n"
"my $self = shift;\n"
"my $strTarget = shift;\n"
"my $strFile = shift;\n"
"\n"
"my $strRepoFile = $strTarget;\n"
"\n"
"if ($self->isTargetTablespace($strTarget) &&\n"
"($self->dbVersion() >= PG_VERSION_90))\n"
"{\n"
"$strRepoFile .= '/' . $self->tablespacePathGet();\n"
"}\n"
"\n"
"if (defined($strFile))\n"
"{\n"
"$strRepoFile .= \"/${strFile}\";\n"
"}\n"
"\n"
"return $strRepoFile;\n"
"}\n"
"\n\n\n\n\n\n"
"sub isTargetValid\n"
"{\n"
"my $self = shift;\n"
"my $strTarget = shift;\n"
"my $bError = shift;\n"
"\n"
"if (!defined($strTarget))\n"
"{\n"
"confess &log(ASSERT, 'target is not defined');\n"
"}\n"
"\n"
"if (!$self->test(MANIFEST_SECTION_BACKUP_TARGET, $strTarget))\n"
"{\n"
"if (defined($bError) && $bError)\n"
"{\n"
"confess &log(ASSERT, \"${strTarget} is not a valid target\");\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n\n\n\n\n\n"
"sub isTargetLink\n"
"{\n"
"my $self = shift;\n"
"my $strTarget = shift;\n"
"\n"
"$self->isTargetValid($strTarget, true);\n"
"\n"
"return $self->test(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_TYPE, MANIFEST_VALUE_LINK);\n"
"}\n"
"\n\n\n\n\n\n"
"sub isTargetFile\n"
"{\n"
"my $self = shift;\n"
"my $strTarget = shift;\n"
"\n"
"$self->isTargetValid($strTarget, true);\n"
"\n"
"return $self->test(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_FILE);\n"
"}\n"
"\n\n\n\n\n\n"
"sub isTargetTablespace\n"
"{\n"
"my $self = shift;\n"
"my $strTarget = shift;\n"
"\n"
"$self->isTargetValid($strTarget, true);\n"
"\n"
"return $self->test(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_TABLESPACE_ID);\n"
"}\n"
"\n\n\n\n\n\n"
"sub checkDelta\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strLastBackupSource,\n"
"$bOnlineSame,\n"
"$strTimelineCurrent,\n"
"$strTimelineLast,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->checkDelta', \\@_,\n"
"{name => 'strLastBackupSource'},\n"
"{name => 'bOnlineSame'},\n"
"{name => 'strTimelineCurrent', required => false},\n"
"{name => 'strTimelineLast', required => false},\n"
");\n"
"\n"
"my $bDelta = false;\n"
"\n\n"
"if (defined($strTimelineLast) && defined($strTimelineCurrent))\n"
"{\n"
"\n"
"if ($strTimelineLast ne $strTimelineCurrent)\n"
"{\n"
"&log(WARN, \"a timeline switch has occurred since the ${strLastBackupSource} backup, enabling delta checksum\");\n"
"$bDelta = true;\n"
"}\n"
"}\n"
"\n\n"
"if (!$bDelta && !$bOnlineSame)\n"
"{\n"
"&log(WARN, \"the online option has changed since the ${strLastBackupSource} backup, enabling delta checksum\");\n"
"$bDelta = true;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bDelta', value => $bDelta, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub checkDeltaFile\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$stryFileList,\n"
"$oPriorManifest,\n"
"$lTimeBegin,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->checkDeltaFile', \\@_,\n"
"{name => 'stryFileList'},\n"
"{name => 'oPriorManifest', required => false},\n"
"{name => 'lTimeBegin', required => false},\n"
");\n"
"\n"
"my $bDelta = false;\n"
"\n\n"
"foreach my $strName (@{$stryFileList})\n"
"{\n"
"\n\n"
"if (defined($lTimeBegin) &&\n"
"($self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP) > $lTimeBegin ||\n"
"(defined($oPriorManifest) &&\n"
"$oPriorManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_FUTURE, 'y'))))\n"
"{\n"
"&log(WARN, \"file $strName has timestamp in the future, enabling delta checksum\");\n"
"$bDelta = true;\n"
"last;\n"
"}\n"
"\n\n\n"
"if (defined($oPriorManifest) && $oPriorManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName) &&\n"
"($self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP) <\n"
"$oPriorManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP) ||\n"
"($self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_SIZE) !=\n"
"$oPriorManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_SIZE) &&\n"
"$self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP) ==\n"
"$oPriorManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP))))\n"
"{\n"
"&log(WARN, \"file $strName timestamp in the past or size changed but timestamp did not, enabling delta checksum\");\n"
"$bDelta = true;\n"
"last;\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bDelta', value => $bDelta, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub build\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oStorageDbMaster,\n"
"$strPath,\n"
"$oLastManifest,\n"
"$bOnline,\n"
"$bDelta,\n"
"$hTablespaceMap,\n"
"$hDatabaseMap,\n"
"$rhExclude,\n"
"$strTimelineCurrent,\n"
"$strTimelineLast,\n"
"$strLevel,\n"
"$bTablespace,\n"
"$strParentPath,\n"
"$strFilter,\n"
"$iLevel,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->build', \\@_,\n"
"{name => 'oStorageDbMaster'},\n"
"{name => 'strPath'},\n"
"{name => 'oLastManifest', required => false},\n"
"{name => 'bOnline'},\n"
"{name => 'bDelta'},\n"
"{name => 'hTablespaceMap', required => false},\n"
"{name => 'hDatabaseMap', required => false},\n"
"{name => 'rhExclude', required => false},\n"
"{name => 'strTimelineCurrent', required => false},\n"
"{name => 'strTimelineLast', required => false},\n"
"{name => 'strLevel', required => false},\n"
"{name => 'bTablespace', required => false},\n"
"{name => 'strParentPath', required => false},\n"
"{name => 'strFilter', required => false},\n"
"{name => 'iLevel', required => false, default => 0},\n"
");\n"
"\n\n"
"if ($iLevel >= 16)\n"
"{\n"
"confess &log(\n"
"ERROR,\n"
"\"recursion in manifest build exceeds depth of ${iLevel}: ${strLevel}\\n\" .\n"
"'HINT: is there a link loop in $PGDATA?',\n"
"ERROR_FORMAT);\n"
"}\n"
"\n"
"if (!defined($strLevel))\n"
"{\n"
"\n"
"if ($self->{bBuilt})\n"
"{\n"
"confess &log(ASSERT, \"manifest has already been built\");\n"
"}\n"
"\n"
"$self->{bBuilt} = true;\n"
"\n\n"
"$strLevel = MANIFEST_TARGET_PGDATA;\n"
"\n\n"
"if (!$bOnline && !defined($hTablespaceMap))\n"
"{\n"
"my $hTablespaceManifest = $oStorageDbMaster->manifest($strPath . '/' . DB_PATH_PGTBLSPC);\n"
"$hTablespaceMap = {};\n"
"\n"
"foreach my $strOid (sort(CORE::keys(%{$hTablespaceManifest})))\n"
"{\n"
"if ($strOid eq '.' or $strOid eq '..')\n"
"{\n"
"next;\n"
"}\n"
"\n"
"logDebugMisc($strOperation, \"found tablespace ${strOid} in offline mode\");\n"
"\n"
"$hTablespaceMap->{$strOid} = \"ts${strOid}\";\n"
"}\n"
"}\n"
"\n\n"
"if (defined($oLastManifest) && !$bDelta)\n"
"{\n"
"$bDelta = $self->checkDelta(\n"
"'last', $oLastManifest->boolTest(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE, undef, $bOnline),\n"
"$strTimelineCurrent, $strTimelineLast);\n"
"}\n"
"}\n"
"\n"
"$self->set(MANIFEST_SECTION_BACKUP_TARGET, $strLevel, MANIFEST_SUBKEY_PATH, $strPath);\n"
"$self->set(MANIFEST_SECTION_BACKUP_TARGET, $strLevel, MANIFEST_SUBKEY_TYPE,\n"
"$strLevel eq MANIFEST_TARGET_PGDATA ? MANIFEST_VALUE_PATH : MANIFEST_VALUE_LINK);\n"
"\n"
"if ($bTablespace)\n"
"{\n"
"my $iTablespaceId = (split('\\/', $strLevel))[1];\n"
"\n"
"if (!defined($hTablespaceMap->{$iTablespaceId}))\n"
"{\n"
"confess &log(ASSERT, \"tablespace with oid ${iTablespaceId} not found in tablespace map\\n\" .\n"
"\"HINT: was a tablespace created or dropped during the backup?\");\n"
"}\n"
"\n"
"$self->set(MANIFEST_SECTION_BACKUP_TARGET, $strLevel, MANIFEST_SUBKEY_TABLESPACE_ID, $iTablespaceId);\n"
"$self->set(MANIFEST_SECTION_BACKUP_TARGET, $strLevel, MANIFEST_SUBKEY_TABLESPACE_NAME,\n"
"$hTablespaceMap->{$iTablespaceId});\n"
"}\n"
"\n"
"if (index($strPath, '/') != 0)\n"
"{\n"
"if (!defined($strParentPath))\n"
"{\n"
"confess &log(ASSERT, \"cannot get manifest for '${strPath}' when no parent path is specified\");\n"
"}\n"
"\n"
"$strPath = $oStorageDbMaster->pathAbsolute($strParentPath, $strPath);\n"
"}\n"
"\n\n"
"my $hManifest = $oStorageDbMaster->manifest($strPath, {strFilter => $strFilter});\n"
"my $strManifestType = MANIFEST_VALUE_LINK;\n"
"\n\n"
"foreach my $strName (sort(CORE::keys(%{$hManifest})))\n"
"{\n"
"my $strFile = $strLevel;\n"
"\n"
"if ($strName ne '.')\n"
"{\n"
"if ($strManifestType eq MANIFEST_VALUE_LINK && $hManifest->{$strName}{type} eq 'l')\n"
"{\n"
"confess &log(ERROR, 'link \\'' .\n"
"$self->dbPathGet(\n"
"$self->get(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH), $strLevel) .\n"
"'\\' -> \\'' . $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strLevel, MANIFEST_SUBKEY_PATH) .\n"
"'\\' cannot reference another link', ERROR_LINK_DESTINATION);\n"
"}\n"
"\n"
"if ($strManifestType eq MANIFEST_VALUE_LINK)\n"
"{\n"
"$strFile = dirname($strFile);\n"
"$self->set(MANIFEST_SECTION_BACKUP_TARGET, $strLevel, MANIFEST_SUBKEY_PATH,\n"
"dirname($self->get(MANIFEST_SECTION_BACKUP_TARGET, $strLevel, MANIFEST_SUBKEY_PATH)));\n"
"$self->set(MANIFEST_SECTION_BACKUP_TARGET, $strLevel, MANIFEST_SUBKEY_FILE, $strName);\n"
"}\n"
"\n"
"$strFile .= \"/${strName}\";\n"
"}\n"
"else\n"
"{\n"
"$strManifestType = MANIFEST_VALUE_PATH;\n"
"}\n"
"\n\n\n"
"next if ($bOnline && $strFile =~ (qw{^} . MANIFEST_TARGET_PGDATA . qw{/} . $self->walPath() . '\\/') &&\n"
"$strFile !~ ('^' . MANIFEST_TARGET_PGDATA . qw{/} . $self->walPath() . qw{/} . DB_PATH_ARCHIVESTATUS . '$'));\n"
"\n\n\n"
"next if $strName =~ ('(^|\\/)' . DB_FILE_PREFIX_TMP);\n"
"\n\n"
"next if $strFile =~ ('^' . MANIFEST_PATH_PGDYNSHMEM . '\\/') && $self->dbVersion() >= PG_VERSION_94;\n"
"\n\n"
"next if $strFile =~ ('^' . MANIFEST_PATH_PGNOTIFY . '\\/') && $self->dbVersion() >= PG_VERSION_90;\n"
"\n\n"
"next if $strFile =~ ('^' . MANIFEST_PATH_PGREPLSLOT . '\\/') && $self->dbVersion() >= PG_VERSION_94;\n"
"\n\n"
"next if $strFile =~ ('^' . MANIFEST_PATH_PGSERIAL . '\\/') && $self->dbVersion() >= PG_VERSION_91;\n"
"\n\n"
"next if $strFile =~ ('^' . MANIFEST_PATH_PGSNAPSHOTS . '\\/') && $self->dbVersion() >= PG_VERSION_92;\n"
"\n\n\n"
"next if $strFile =~ ('^' . MANIFEST_PATH_PGSTATTMP . '\\/') && $self->dbVersion() >= PG_VERSION_84;\n"
"\n\n"
"next if $strFile =~ ('^' . MANIFEST_PATH_PGSUBTRANS . '\\/');\n"
"\n\n"
"next if $strFile =~ (DB_FILE_PGINTERNALINIT . '$');\n"
"\n\n"
"if ($strFile eq MANIFEST_FILE_POSTGRESQLAUTOCONFTMP ||\n"
"$strFile eq MANIFEST_FILE_BACKUPLABELOLD ||\n"
"$strFile eq MANIFEST_FILE_POSTMASTEROPTS ||\n"
"$strFile eq MANIFEST_FILE_POSTMASTERPID ||\n"
"$strFile eq MANIFEST_FILE_RECOVERYCONF || # recovery.conf - doesn't make sense to backup this file\n"
"$strFile eq MANIFEST_FILE_RECOVERYDONE) # recovery.done - doesn't make sense to backup this file\n"
"{\n"
"next;\n"
"}\n"
"\n\n"
"if ($self->dbVersion() >= PG_VERSION_90 && $hManifest->{$strName}{type} eq 'f')\n"
"{\n"
"\n"
"my $strDir = dirname($strName);\n"
"\n\n"
"if ($strDir =~ '^base\\/[0-9]+$' ||\n"
"$strDir =~ ('^' . $self->tablespacePathGet() . '\\/[0-9]+$'))\n"
"{\n"
"\n"
"my $strBaseName = basename($strName);\n"
"\n\n\n"
"if ($strBaseName =~ '^t[0-9]+\\_[0-9]+(|\\_(fsm|vm)){0,1}(\\.[0-9]+){0,1}$')\n"
"{\n"
"next;\n"
"}\n"
"\n\n"
"if ($self->dbVersion() >= PG_VERSION_91)\n"
"{\n"
"\n"
"if ($strBaseName =~ '^[0-9]+(|\\_(fsm|vm)){0,1}(\\.[0-9]+){0,1}$')\n"
"{\n"
"\n"
"my ($strFileNode) = $strBaseName =~ '^(\\d+)';\n"
"\n\n"
"$strFileNode = $strDir. \"/\" . $strFileNode . \"_init\";\n"
"\n\n"
"if (exists($hManifest->{$strFileNode}) && $hManifest->{$strFileNode}{type} eq 'f')\n"
"{\n"
"next;\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n"
"my $cType = $hManifest->{$strName}{type};\n"
"my $strSection = MANIFEST_SECTION_TARGET_PATH;\n"
"\n"
"if ($cType eq 'f')\n"
"{\n"
"$strSection = MANIFEST_SECTION_TARGET_FILE;\n"
"}\n"
"elsif ($cType eq 'l')\n"
"{\n"
"$strSection = MANIFEST_SECTION_TARGET_LINK;\n"
"}\n"
"elsif ($cType ne 'd')\n"
"{\n"
"confess &log(ASSERT, \"unrecognized file type $cType for file $strName\");\n"
"}\n"
"\n\n"
"my $bTablespace = false;\n"
"\n"
"if (index($strName, DB_PATH_PGTBLSPC . '/') == 0 && $strLevel eq MANIFEST_TARGET_PGDATA)\n"
"{\n"
"$bTablespace = true;\n"
"$strFile = MANIFEST_TARGET_PGDATA . '/' . $strName;\n"
"\n\n"
"if ($hManifest->{$strName}{type} ne 'l')\n"
"{\n"
"confess &log(ERROR, \"${strName} is not a symlink - \" . DB_PATH_PGTBLSPC . ' should contain only symlinks',\n"
"ERROR_LINK_EXPECTED);\n"
"}\n"
"\n\n"
"if (index($hManifest->{$strName}{link_destination}, \"${strPath}/\") == 0 ||\n"
"(index($hManifest->{$strName}{link_destination}, '/') != 0 &&\n"
"index($oStorageDbMaster->pathAbsolute($strPath . '/' . DB_PATH_PGTBLSPC,\n"
"$hManifest->{$strName}{link_destination}) . '/', \"${strPath}/\") == 0))\n"
"{\n"
"confess &log(ERROR, 'tablespace symlink ' . $hManifest->{$strName}{link_destination} .\n"
"' destination must not be in $PGDATA', ERROR_TABLESPACE_IN_PGDATA);\n"
"}\n"
"}\n"
"\n\n"
"if (defined($rhExclude))\n"
"{\n"
"\n"
"my $strPgFile = $self->dbPathGet(undef, $strFile);\n"
"my $bExclude = false;\n"
"\n\n"
"foreach my $strExclude (sort(keys(%{$rhExclude})))\n"
"{\n"
"\n"
"if ($strExclude =~ /\\/$/)\n"
"{\n"
"if (index($strPgFile, $strExclude) == 0)\n"
"{\n"
"$bExclude = true;\n"
"}\n"
"}\n"
"\n"
"elsif ($strPgFile eq $strExclude || index($strPgFile, \"${strExclude}/\") == 0)\n"
"{\n"
"$bExclude = true;\n"
"}\n"
"\n\n"
"if ($bExclude)\n"
"{\n"
"&log(INFO, \"exclude ${strPgFile} from backup using '${strExclude}' exclusion\");\n"
"last;\n"
"}\n"
"}\n"
"\n\n"
"next if $bExclude;\n"
"}\n"
"\n\n"
"if (defined($hManifest->{$strName}{user}))\n"
"{\n"
"$self->set($strSection, $strFile, MANIFEST_SUBKEY_USER, $hManifest->{$strName}{user});\n"
"}\n"
"else\n"
"{\n"
"$self->boolSet($strSection, $strFile, MANIFEST_SUBKEY_USER, false);\n"
"}\n"
"\n"
"if (defined($hManifest->{$strName}{group}))\n"
"{\n"
"$self->set($strSection, $strFile, MANIFEST_SUBKEY_GROUP, $hManifest->{$strName}{group});\n"
"}\n"
"else\n"
"{\n"
"$self->boolSet($strSection, $strFile, MANIFEST_SUBKEY_GROUP, false);\n"
"}\n"
"\n\n"
"if ($cType eq 'f' || $cType eq 'd')\n"
"{\n"
"$self->set($strSection, $strFile, MANIFEST_SUBKEY_MODE, $hManifest->{$strName}{mode});\n"
"}\n"
"\n\n"
"if ($cType eq 'f')\n"
"{\n"
"$self->set($strSection, $strFile, MANIFEST_SUBKEY_TIMESTAMP,\n"
"$hManifest->{$strName}{modification_time} + 0);\n"
"$self->set($strSection, $strFile, MANIFEST_SUBKEY_SIZE, $hManifest->{$strName}{size} + 0);\n"
"$self->boolSet($strSection, $strFile, MANIFEST_SUBKEY_MASTER,\n"
"($strFile eq MANIFEST_FILE_PGCONTROL || $self->isMasterFile($strFile)));\n"
"}\n"
"\n\n"
"if ($cType eq 'l')\n"
"{\n"
"my $strLinkDestination = $hManifest->{$strName}{link_destination};\n"
"$self->set($strSection, $strFile, MANIFEST_SUBKEY_DESTINATION, $strLinkDestination);\n"
"\n\n"
"my $strFilter;\n"
"\n"
"if ($bTablespace)\n"
"{\n"
"\n\n"
"if ($self->dbVersion() >= PG_VERSION_90)\n"
"{\n"
"$strFilter = $self->tablespacePathGet();\n"
"}\n"
"\n"
"$self->set(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGTBLSPC, undef,\n"
"$self->get(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA));\n"
"\n\n"
"$strFile = substr($strFile, length(MANIFEST_TARGET_PGDATA) + 1);\n"
"}\n"
"\n"
"$bDelta = $self->build(\n"
"$oStorageDbMaster, $strLinkDestination, undef, $bOnline, $bDelta, $hTablespaceMap, $hDatabaseMap, $rhExclude, undef,\n"
"undef, $strFile, $bTablespace, dirname(\"${strPath}/${strName}\"), $strFilter, $iLevel + 1);\n"
"}\n"
"}\n"
"\n\n"
"if ($strLevel eq MANIFEST_TARGET_PGDATA)\n"
"{\n"
"my $bTimeInFuture = false;\n"
"\n\n\n\n\n\n"
"my $lTimeBegin =\n"
"$oStorageDbMaster->can('protocol') ?\n"
"$oStorageDbMaster->protocol()->cmdExecute(OP_WAIT, [$bOnline]) : waitRemainder($bOnline);\n"
"\n\n"
"$self->linkCheck();\n"
"\n"
"if (defined($oLastManifest))\n"
"{\n"
"$self->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_PRIOR, undef,\n"
"$oLastManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL));\n"
"}\n"
"\n\n"
"foreach my $strDbName (sort(keys(%{$hDatabaseMap})))\n"
"{\n"
"$self->numericSet(MANIFEST_SECTION_DB, $strDbName, MANIFEST_KEY_DB_ID,\n"
"$hDatabaseMap->{$strDbName}{&MANIFEST_KEY_DB_ID});\n"
"$self->numericSet(MANIFEST_SECTION_DB, $strDbName, MANIFEST_KEY_DB_LAST_SYSTEM_ID,\n"
"$hDatabaseMap->{$strDbName}{&MANIFEST_KEY_DB_LAST_SYSTEM_ID});\n"
"}\n"
"\n\n"
"if (!$bDelta)\n"
"{\n"
"my @stryFileList = $self->keys(MANIFEST_SECTION_TARGET_FILE);\n"
"\n"
"if (@stryFileList)\n"
"{\n"
"$bDelta = $self->checkDeltaFile(\\@stryFileList, $oLastManifest, $lTimeBegin);\n"
"}\n"
"}\n"
"\n\n"
"foreach my $strName ($self->keys(MANIFEST_SECTION_TARGET_FILE))\n"
"{\n"
"\n\n"
"if ($self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP) > $lTimeBegin ||\n"
"(defined($oLastManifest) &&\n"
"$oLastManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_FUTURE, 'y')))\n"
"{\n"
"$bTimeInFuture = true;\n"
"\n\n"
"if ($self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP) > $lTimeBegin)\n"
"{\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_FUTURE, 'y');\n"
"}\n"
"}\n"
"\n\n\n\n\n"
"elsif (defined($oLastManifest) && $oLastManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName) &&\n"
"$self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_SIZE) ==\n"
"$oLastManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_SIZE) &&\n"
"($bDelta || ($self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_SIZE) == 0 ||\n"
"$self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP) ==\n"
"$oLastManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP))))\n"
"{\n"
"\n"
"if ($oLastManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_REFERENCE))\n"
"{\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_REFERENCE,\n"
"$oLastManifest->get(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_REFERENCE));\n"
"}\n"
"\n"
"else\n"
"{\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_REFERENCE,\n"
"$oLastManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL));\n"
"}\n"
"\n\n"
"if ($oLastManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_CHECKSUM))\n"
"{\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_CHECKSUM,\n"
"$oLastManifest->get(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_CHECKSUM));\n"
"}\n"
"\n\n"
"if ($oLastManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_REPO_SIZE))\n"
"{\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_REPO_SIZE,\n"
"$oLastManifest->get(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_REPO_SIZE));\n"
"}\n"
"\n\n"
"if ($oLastManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_MASTER))\n"
"{\n"
"$self->set(\n"
"MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_MASTER,\n"
"$oLastManifest->get(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_MASTER));\n"
"}\n"
"\n\n"
"my $bChecksumPage = $oLastManifest->get(\n"
"MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_CHECKSUM_PAGE, false);\n"
"\n"
"if (defined($bChecksumPage))\n"
"{\n"
"$self->boolSet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_CHECKSUM_PAGE, $bChecksumPage);\n"
"\n"
"if (!$bChecksumPage &&\n"
"$oLastManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR))\n"
"{\n"
"$self->set(\n"
"MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR,\n"
"$oLastManifest->get(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_CHECKSUM_PAGE_ERROR));\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if ($bTimeInFuture)\n"
"{\n"
"&log(WARN, \"some files have timestamps in the future - they will be copied to prevent possible race conditions\");\n"
"}\n"
"\n\n"
"$self->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_COPY_START, undef, $lTimeBegin + ($bOnline ? 1 : 0));\n"
"\n\n"
"$self->buildDefault();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bDelta', value => $bDelta, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub linkCheck\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->linkCheck');\n"
"\n\n"
"my $strBasePath = $self->get(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH);\n"
"\n"
"foreach my $strTargetParent ($self->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"if ($self->isTargetLink($strTargetParent))\n"
"{\n"
"my $strParentPath = $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strTargetParent, MANIFEST_SUBKEY_PATH);\n"
"my $strParentFile = $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strTargetParent, MANIFEST_SUBKEY_FILE, false);\n"
"\n"
"foreach my $strTargetChild ($self->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"if ($self->isTargetLink($strTargetChild) && $strTargetParent ne $strTargetChild)\n"
"{\n"
"my $strChildPath = $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strTargetChild, MANIFEST_SUBKEY_PATH);\n"
"my $strChildFile = $self->get(MANIFEST_SECTION_BACKUP_TARGET, $strTargetParent, MANIFEST_SUBKEY_FILE, false);\n"
"\n"
"if (!(defined($strParentFile) && defined($strChildFile)) &&\n"
"index(\n"
"storageLocal()->pathAbsolute($strBasePath, $strChildPath) . '/',\n"
"storageLocal()->pathAbsolute($strBasePath, $strParentPath) . '/') == 0)\n"
"{\n"
"confess &log(ERROR, 'link ' . $self->dbPathGet($strBasePath, $strTargetChild) .\n"
"\" (${strChildPath}) references a subdirectory of or\" .\n"
"\" the same directory as link \" . $self->dbPathGet($strBasePath, $strTargetParent) .\n"
"\" (${strParentPath})\", ERROR_LINK_DESTINATION);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub fileAdd\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strManifestFile,\n"
"$lModificationTime,\n"
"$lSize,\n"
"$strChecksum,\n"
"$bMaster,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->fileAdd', \\@_,\n"
"{name => 'strManifestFile'},\n"
"{name => 'lModificationTime'},\n"
"{name => 'lSize'},\n"
"{name => 'lChecksum'},\n"
"{name => 'bMaster'},\n"
");\n"
"\n\n"
"if (!$self->test(MANIFEST_SECTION_TARGET_FILE . ':default', MANIFEST_SUBKEY_USER) ||\n"
"!$self->test(MANIFEST_SECTION_TARGET_FILE . ':default', MANIFEST_SUBKEY_USER, undef,\n"
"$self->get(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_USER)))\n"
"{\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strManifestFile, MANIFEST_SUBKEY_USER,\n"
"$self->get(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_USER));\n"
"}\n"
"\n"
"if (!$self->test(MANIFEST_SECTION_TARGET_FILE . ':default', MANIFEST_SUBKEY_GROUP) ||\n"
"!$self->test(MANIFEST_SECTION_TARGET_FILE . ':default', MANIFEST_SUBKEY_GROUP, undef,\n"
"$self->get(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_GROUP)))\n"
"{\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strManifestFile, MANIFEST_SUBKEY_GROUP,\n"
"$self->get(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_GROUP));\n"
"}\n"
"\n"
"if (!$self->test(MANIFEST_SECTION_TARGET_FILE . ':default', MANIFEST_SUBKEY_MODE) ||\n"
"!$self->test(MANIFEST_SECTION_TARGET_FILE . ':default', MANIFEST_SUBKEY_MODE, undef, '0600'))\n"
"{\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strManifestFile, MANIFEST_SUBKEY_MODE, '0600');\n"
"}\n"
"\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strManifestFile, MANIFEST_SUBKEY_TIMESTAMP, $lModificationTime);\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strManifestFile, MANIFEST_SUBKEY_SIZE, $lSize);\n"
"$self->set(MANIFEST_SECTION_TARGET_FILE, $strManifestFile, MANIFEST_SUBKEY_CHECKSUM, $strChecksum);\n"
"$self->boolSet(MANIFEST_SECTION_TARGET_FILE, $strManifestFile, MANIFEST_SUBKEY_MASTER, $bMaster);\n"
"}\n"
"\n\n\n\n\n\n"
"sub buildDefault\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->buildDefault');\n"
"\n\n"
"foreach my $strSection (&MANIFEST_SECTION_TARGET_FILE, &MANIFEST_SECTION_TARGET_PATH, &MANIFEST_SECTION_TARGET_LINK)\n"
"{\n"
"foreach my $strSubKey (&MANIFEST_SUBKEY_USER, &MANIFEST_SUBKEY_GROUP, &MANIFEST_SUBKEY_MODE, &MANIFEST_SUBKEY_MASTER)\n"
"{\n"
"\n"
"next if ($strSection eq MANIFEST_SECTION_TARGET_LINK && $strSubKey eq &MANIFEST_SUBKEY_MODE);\n"
"\n\n"
"next if ($strSection ne MANIFEST_SECTION_TARGET_FILE && $strSubKey eq &MANIFEST_SUBKEY_MASTER);\n"
"\n"
"my %oDefault;\n"
"my $iSectionTotal = 0;\n"
"\n"
"foreach my $strFile ($self->keys($strSection))\n"
"{\n"
"\n"
"next if (($strSubKey eq MANIFEST_SUBKEY_USER || $strSubKey eq MANIFEST_SUBKEY_GROUP) &&\n"
"$self->boolTest($strSection, $strFile, $strSubKey, false));\n"
"\n"
"my $strValue = $self->get($strSection, $strFile, $strSubKey);\n"
"\n"
"if (defined($oDefault{$strValue}))\n"
"{\n"
"$oDefault{$strValue}++;\n"
"}\n"
"else\n"
"{\n"
"$oDefault{$strValue} = 1;\n"
"}\n"
"\n"
"$iSectionTotal++;\n"
"}\n"
"\n"
"my $strMaxValue;\n"
"my $iMaxValueTotal = 0;\n"
"\n"
"foreach my $strValue (sort(keys(%oDefault)))\n"
"{\n"
"if ($oDefault{$strValue} > $iMaxValueTotal)\n"
"{\n"
"$iMaxValueTotal = $oDefault{$strValue};\n"
"$strMaxValue = $strValue;\n"
"}\n"
"}\n"
"\n"
"if (defined($strMaxValue) > 0 && $iMaxValueTotal > $iSectionTotal * MANIFEST_DEFAULT_MATCH_FACTOR)\n"
"{\n"
"if ($strSubKey eq MANIFEST_SUBKEY_MASTER)\n"
"{\n"
"$self->boolSet(\"${strSection}:default\", $strSubKey, undef, $strMaxValue);\n"
"}\n"
"else\n"
"{\n"
"$self->set(\"${strSection}:default\", $strSubKey, undef, $strMaxValue);\n"
"}\n"
"\n"
"foreach my $strFile ($self->keys($strSection))\n"
"{\n"
"if ($self->test($strSection, $strFile, $strSubKey, $strMaxValue))\n"
"{\n"
"$self->remove($strSection, $strFile, $strSubKey);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub validate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . 'validate');\n"
"\n\n\n"
"foreach my $strFile ($self->keys(MANIFEST_SECTION_TARGET_FILE))\n"
"{\n"
"\n"
"if (!$self->test(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_SIZE))\n"
"{\n"
"confess &log(ASSERT, \"manifest subvalue 'size' not set for file '${strFile}'\");\n"
"}\n"
"\n\n"
"if ($self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_SIZE) > 0 &&\n"
"!$self->test(MANIFEST_SECTION_TARGET_FILE, $strFile, MANIFEST_SUBKEY_CHECKSUM))\n"
"{\n"
"confess &log(ASSERT, \"manifest subvalue 'checksum' not set for file '${strFile}'\");\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub dbVersion\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION);\n"
"}\n"
"\n\n\n\n"
"sub xactPath\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->dbVersion() >= PG_VERSION_10 ? 'pg_xact' : 'pg_clog';\n"
"}\n"
"\n\n\n\n"
"sub walPath\n"
"{\n"
"my $self = shift;\n"
"\n"
"return $self->dbVersion() >= PG_VERSION_10 ? 'pg_wal' : 'pg_xlog';\n"
"}\n"
"\n\n\n\n\n\n"
"sub isMasterFile\n"
"{\n"
"my $self = shift;\n"
"my $strFile = shift;\n"
"\n"
"return\n"
"$strFile !~ ('^(' . MANIFEST_TARGET_PGDATA . '\\/' . '(' . DB_PATH_BASE . '|' . DB_PATH_GLOBAL . '|' .\n"
"$self->xactPath() . '|' . DB_PATH_PGMULTIXACT . ')|' . DB_PATH_PGTBLSPC . ')\\/');\n"
"}\n"
"\n\n\n\n\n\n"
"sub isChecksumPage\n"
"{\n"
"my $strFile = shift;\n"
"\n"
"if (($strFile =~ ('^' . MANIFEST_TARGET_PGDATA . '\\/' . DB_PATH_BASE . '|^' . MANIFEST_TARGET_PGTBLSPC . '\\/') &&\n"
"$strFile !~ ('(' . DB_FILE_PGFILENODEMAP . '|' . DB_FILE_PGINTERNALINIT . '|' . DB_FILE_PGVERSION . ')$')) ||\n"
"($strFile =~ ('^' . MANIFEST_TARGET_PGDATA . '\\/' . DB_PATH_GLOBAL) &&\n"
"$strFile !~ ('(' . DB_FILE_PGFILENODEMAP . '|' . DB_FILE_PGINTERNALINIT . '|' . DB_FILE_PGVERSION . '|' .\n"
"DB_FILE_PGCONTROL . ')$')))\n"
"{\n"
"return true;\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n"
"push @EXPORT, qw(isChecksumPage);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Base/Master.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Base::Master;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Time::HiRes qw(gettimeofday);\n"
"use JSON::PP;\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"use constant OP_NOOP => 'noop';\n"
"push @EXPORT, qw(OP_NOOP);\n"
"use constant OP_EXIT => 'exit';\n"
"push @EXPORT, qw(OP_EXIT);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{strName},\n"
"$self->{strId},\n"
"$self->{oIo},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strName', trace => true},\n"
"{name => 'strId', trace => true},\n"
"{name => 'oIo', trace => true},\n"
");\n"
"\n\n"
"$self->{oJSON} = JSON::PP->new()->allow_nonref();\n"
"\n\n"
"$self->{fKeepAliveTimeout} = $self->io()->timeout() / 2 > 120 ? 120 : $self->io()->timeout() / 2;\n"
"$self->{fKeepAliveTime} = gettimeofday();\n"
"\n\n"
"$self->{strErrorPrefix} = 'raised from ' . $self->{strId};\n"
"\n\n"
"$self->greetingRead();\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub DESTROY\n"
"{\n"
"my $self = shift;\n"
"\n"
"$self->close();\n"
"}\n"
"\n\n\n\n\n\n"
"sub greetingRead\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my $strGreeting = $self->io()->readLine(true);\n"
"\n\n"
"my $hGreeting;\n"
"\n"
"eval\n"
"{\n"
"$hGreeting = $self->{oJSON}->decode($strGreeting);\n"
"\n"
"return true;\n"
"}\n"
"\n"
"or do\n"
"{\n"
"$self->io()->error(ERROR_PROTOCOL, 'invalid protocol greeting', $strGreeting);\n"
"};\n"
"\n\n"
"for my $hParam ({strName => 'name', strExpected => PROJECT_NAME},\n"
"{strName => 'version', strExpected => PROJECT_VERSION},\n"
"{strName => 'service', strExpected => $self->{strName}})\n"
"{\n"
"if (!defined($hGreeting->{$hParam->{strName}}) || $hGreeting->{$hParam->{strName}} ne $hParam->{strExpected})\n"
"{\n"
"confess &log(ERROR,\n"
"'found name \\'' . (defined($hGreeting->{$hParam->{strName}}) ? $hGreeting->{$hParam->{strName}} : '[undef]') .\n"
"\"' in protocol greeting instead of expected '$hParam->{strExpected}'\", ERROR_HOST_CONNECT);\n"
"}\n"
"}\n"
"\n\n"
"$self->noOp();\n"
"}\n"
"\n\n\n\n\n\n"
"sub outputRead\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bOutputRequired,\n"
"$bSuppressLog,\n"
"$bWarnOnError,\n"
"$bRef,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->outputRead', \\@_,\n"
"{name => 'bOutputRequired', default => false, trace => true},\n"
"{name => 'bSuppressLog', required => false, trace => true},\n"
"{name => 'bWarnOnError', default => false, trace => true},\n"
"{name => 'bRef', default => false, trace => true},\n"
");\n"
"\n"
"my $strProtocolResult = $self->io()->readLine();\n"
"\n"
"logDebugMisc\n"
"(\n"
"$strOperation, undef,\n"
"{name => 'strProtocolResult', value => $strProtocolResult, trace => true}\n"
");\n"
"\n"
"my $hResult = $self->{oJSON}->decode($strProtocolResult);\n"
"\n\n"
"if (defined($hResult->{err}))\n"
"{\n"
"my $strError = $self->{strErrorPrefix} . (defined($hResult->{out}) ? \": $hResult->{out}\" : '');\n"
"\n\n"
"if (!$bWarnOnError)\n"
"{\n"
"confess &log(\n"
"ERROR, $strError . (defined($hResult->{errStack}) ? \"\\n$hResult->{errStack}\" : ''), $hResult->{err}, $bSuppressLog);\n"
"}\n"
"\n"
"&log(WARN, $strError, $hResult->{err});\n"
"undef($hResult->{out});\n"
"}\n"
"\n\n"
"$self->{fKeepAliveTime} = gettimeofday();\n"
"\n\n"
"if ($bOutputRequired && !defined($hResult->{out}))\n"
"{\n"
"confess &log(ERROR, \"$self->{strErrorPrefix}: output is not defined\", ERROR_PROTOCOL_OUTPUT_REQUIRED);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hOutput', value => $hResult->{out}, ref => $bRef, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub cmdWrite\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strCommand,\n"
"$hParam,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->cmdWrite', \\@_,\n"
"{name => 'strCommand', trace => true},\n"
"{name => 'hParam', required => false, trace => true},\n"
");\n"
"\n"
"my $strProtocolCommand = $self->{oJSON}->encode({cmd => $strCommand, param => $hParam});\n"
"\n"
"logDebugMisc\n"
"(\n"
"$strOperation, undef,\n"
"{name => 'strProtocolCommand', value => $strProtocolCommand, trace => true}\n"
");\n"
"\n\n"
"$self->io()->writeLine($strProtocolCommand);\n"
"\n\n"
"$self->{fKeepAliveTime} = gettimeofday();\n"
"\n\n"
"logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub cmdExecute\n"
"{\n"
"my $self = shift;\n"
"my $strCommand = shift;\n"
"my $oParamRef = shift;\n"
"my $bOutputRequired = shift;\n"
"my $bWarnOnError = shift;\n"
"\n"
"$self->cmdWrite($strCommand, $oParamRef);\n"
"\n"
"return $self->outputRead($bOutputRequired, undef, $bWarnOnError);\n"
"}\n"
"\n\n\n\n\n\n"
"sub keepAlive\n"
"{\n"
"my $self = shift;\n"
"\n"
"if (gettimeofday() - $self->{fKeepAliveTimeout} > $self->{fKeepAliveTime})\n"
"{\n"
"$self->noOp();\n"
"\n\n"
"&log(TEST, TEST_KEEP_ALIVE);\n"
"}\n"
"}\n"
"\n\n\n\n\n\n"
"sub noOp\n"
"{\n"
"my $self = shift;\n"
"\n"
"$self->cmdExecute(OP_NOOP, undef, false);\n"
"$self->{fKeepAliveTime} = gettimeofday();\n"
"}\n"
"\n\n\n\n"
"sub io {shift->{oIo}}\n"
"sub master {true}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Base/Minion.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Base::Minion;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use JSON::PP;\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Lock;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::LibC qw(:lock);\n"
"use pgBackRest::Protocol::Base::Master;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"use constant OP_POST => 'post';\n"
"push @EXPORT, qw(OP_POST);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{strName},\n"
"$self->{oIo},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strName', trace => true},\n"
"{name => 'oIo', trace => true},\n"
");\n"
"\n\n"
"$self->{oJSON} = JSON::PP->new()->allow_nonref();\n"
"\n\n"
"$self->greetingWrite();\n"
"\n\n"
"$self->{hCommandMap} = $self->can('init') ? $self->init() : undef;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub greetingWrite\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"$self->io()->writeLine((JSON::PP->new()->canonical()->allow_nonref())->encode(\n"
"{name => PROJECT_NAME, service => $self->{strName}, version => PROJECT_VERSION}));\n"
"}\n"
"\n\n\n\n\n\n"
"sub errorWrite\n"
"{\n"
"my $self = shift;\n"
"my $oException = shift;\n"
"\n\n"
"if (!isException(\\$oException))\n"
"{\n"
"confess &log(ERROR, 'unknown error: ' . $oException, ERROR_UNKNOWN);\n"
"}\n"
"\n\n"
"$self->io()->writeLine($self->{oJSON}->encode({err => $oException->code(), out => $oException->message()}));\n"
"}\n"
"\n\n\n\n\n\n"
"sub outputWrite\n"
"{\n"
"my $self = shift;\n"
"\n"
"$self->io()->writeLine($self->{oJSON}->encode({out => \\@_}));\n"
"}\n"
"\n\n\n\n\n\n"
"sub cmdRead\n"
"{\n"
"my $self = shift;\n"
"\n"
"my $hCommand = $self->{oJSON}->decode($self->io()->readLine());\n"
"\n"
"return $hCommand->{cmd}, $hCommand->{param};\n"
"}\n"
"\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"my $strLockPath = shift;\n"
"my $strLockCommand = shift;\n"
"my $strLockStanza = shift;\n"
"my $iProcessId = shift;\n"
"\n\n"
"logLevelSet(undef, undef, OFF);\n"
"\n\n\n"
"my $oPermanentError;\n"
"\n\n"
"eval\n"
"{\n"
"\n\n"
"if (defined($strLockPath) && defined($strLockStanza) && $iProcessId == 0)\n"
"{\n"
"eval\n"
"{\n"
"if (lockAcquire($strLockPath, $strLockCommand, $strLockStanza, 30, true))\n"
"{\n"
"\n"
"lockStopTest();\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"$oPermanentError = $EVAL_ERROR;\n"
"};\n"
"}\n"
"\n"
"while (true)\n"
"{\n"
"my ($strCommand, $rParam) = $self->cmdRead();\n"
"\n"
"last if ($strCommand eq OP_EXIT);\n"
"\n\n"
"if (defined($oPermanentError))\n"
"{\n"
"$self->errorWrite($oPermanentError);\n"
"}\n"
"\n"
"else\n"
"{\n"
"eval\n"
"{\n"
"\n"
"if (defined($self->{hCommandMap}{$strCommand}))\n"
"{\n"
"$self->outputWrite($self->{hCommandMap}{$strCommand}->($rParam));\n"
"}\n"
"\n"
"elsif ($strCommand eq OP_NOOP)\n"
"{\n"
"protocolKeepAlive();\n"
"$self->outputWrite();\n"
"}\n"
"else\n"
"{\n"
"confess \"invalid command: ${strCommand}\";\n"
"}\n"
"\n\n"
"if (defined($self->{hCommandMap}{&OP_POST}))\n"
"{\n"
"$self->{hCommandMap}{&OP_POST}->();\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n"
"or do\n"
"{\n"
"$self->errorWrite($EVAL_ERROR);\n"
"};\n"
"}\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"my $oException = $EVAL_ERROR;\n"
"\n\n"
"logLevelSet(undef, undef, PROTOCOL);\n"
"\n\n"
"if (isException(\\$oException))\n"
"{\n"
"confess &log($oException->level(), $oException->message(), $oException->code());\n"
"}\n"
"\n\n"
"confess &log(ERROR, 'unknown error: ' . $oException, ERROR_UNKNOWN);\n"
"};\n"
"}\n"
"\n\n\n\n"
"sub io {shift->{oIo}}\n"
"sub master {false}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Command/Master.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Command::Master;\n"
"use parent 'pgBackRest::Protocol::Base::Master';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use File::Basename qw(dirname);\n"
"use Time::HiRes qw(gettimeofday);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Io::Process;\n"
"use pgBackRest::Protocol::Base::Master;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strName,\n"
"$strId,\n"
"$strCommand,\n"
"$iBufferMax,\n"
"$iCompressLevel,\n"
"$iCompressLevelNetwork,\n"
"$iProtocolTimeout,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strName'},\n"
"{name => 'strId'},\n"
"{name => 'strCommand'},\n"
"{name => 'iBufferMax'},\n"
"{name => 'iCompressLevel'},\n"
"{name => 'iCompressLevelNetwork'},\n"
"{name => 'iProtocolTimeout'},\n"
");\n"
"\n\n"
"if (!defined($strCommand))\n"
"{\n"
"confess &log(ASSERT, 'strCommand must be set');\n"
"}\n"
"\n\n"
"my $oIo = new pgBackRest::Common::Io::Process(\n"
"new pgBackRest::Common::Io::Buffered(\n"
"new pgBackRest::Common::Io::Handle($strId), $iProtocolTimeout, $iBufferMax), $strCommand);\n"
"\n\n"
"my $self = $class->SUPER::new($strName, $strId, $oIo);\n"
"bless $self, $class;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bComplete,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->close', \\@_,\n"
"{name => 'bComplete', default => false, trace => true},\n"
");\n"
"\n\n"
"my $iExitStatus = 0;\n"
"my $bClosed = false;\n"
"\n\n"
"if (defined($self->io()) && defined($self->io()->processId()))\n"
"{\n"
"&log(TRACE, \"sending exit command to process\");\n"
"\n"
"eval\n"
"{\n"
"$self->cmdWrite(OP_EXIT);\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"my $oException = $EVAL_ERROR;\n"
"my $strError = 'unable to shutdown protocol';\n"
"my $strHint = 'HINT: the process completed all operations successfully but protocol-timeout may need to be increased.';\n"
"\n"
"if (isException(\\$oException))\n"
"{\n"
"$iExitStatus = $oException->code();\n"
"}\n"
"else\n"
"{\n"
"if (!defined($oException))\n"
"{\n"
"$oException = 'unknown error';\n"
"}\n"
"\n"
"$iExitStatus = ERROR_UNKNOWN;\n"
"}\n"
"\n"
"&log(WARN,\n"
"$strError . ($iExitStatus == ERROR_UNKNOWN ? '' : sprintf(' [%03d]', $oException->code())) . ': ' .\n"
"($iExitStatus == ERROR_UNKNOWN ? $oException : $oException->message()) .\n"
"($bComplete ? \"\\n${strHint}\" : ''));\n"
"};\n"
"\n"
"$self->{oIo}->close();\n"
"undef($self->{oIo});\n"
"$bClosed = true;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iExitStatus', value => $iExitStatus, trace => !$bClosed}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Command/Minion.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Command::Minion;\n"
"use parent 'pgBackRest::Protocol::Base::Minion';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use JSON::PP;\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Protocol::Base::Minion;\n"
"use pgBackRest::Common::Io::Buffered;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strName,\n"
"$iBufferMax,\n"
"$iProtocolTimeout,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strName'},\n"
"{name => 'iBufferMax'},\n"
"{name => 'iProtocolTimeout'},\n"
");\n"
"\n\n"
"my $oIo =\n"
"new pgBackRest::Common::Io::Buffered(\n"
"new pgBackRest::Common::Io::Handle('stdio', *STDIN, *STDOUT), $iProtocolTimeout, $iBufferMax);\n"
"\n\n"
"my $self = $class->SUPER::new($strName, $oIo);\n"
"bless $self, $class;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Helper.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Helper;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Remote::Master;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n\n"
"use constant OP_BACKUP_FILE => 'backupFile';\n"
"push @EXPORT, qw(OP_BACKUP_FILE);\n"
"\n\n"
"use constant OP_ARCHIVE_GET_CHECK => 'archiveCheck';\n"
"push @EXPORT, qw(OP_ARCHIVE_GET_CHECK);\n"
"\n\n"
"use constant OP_CHECK_BACKUP_INFO_CHECK => 'backupInfoCheck';\n"
"push @EXPORT, qw(OP_CHECK_BACKUP_INFO_CHECK);\n"
"\n\n"
"use constant OP_DB_CONNECT => 'dbConnect';\n"
"push @EXPORT, qw(OP_DB_CONNECT);\n"
"use constant OP_DB_EXECUTE_SQL => 'dbExecSql';\n"
"push @EXPORT, qw(OP_DB_EXECUTE_SQL);\n"
"use constant OP_DB_INFO => 'dbInfo';\n"
"push @EXPORT, qw(OP_DB_INFO);\n"
"\n\n"
"use constant OP_STORAGE_OPEN_READ => 'storageOpenRead';\n"
"push @EXPORT, qw(OP_STORAGE_OPEN_READ);\n"
"use constant OP_STORAGE_OPEN_WRITE => 'storageOpenWrite';\n"
"push @EXPORT, qw(OP_STORAGE_OPEN_WRITE);\n"
"use constant OP_STORAGE_CIPHER_PASS_USER => 'storageCipherPassUser';\n"
"push @EXPORT, qw(OP_STORAGE_CIPHER_PASS_USER);\n"
"use constant OP_STORAGE_EXISTS => 'storageExists';\n"
"push @EXPORT, qw(OP_STORAGE_EXISTS);\n"
"use constant OP_STORAGE_HASH_SIZE => 'storageHashSize';\n"
"push @EXPORT, qw(OP_STORAGE_HASH_SIZE);\n"
"use constant OP_STORAGE_LIST => 'storageList';\n"
"push @EXPORT, qw(OP_STORAGE_LIST);\n"
"use constant OP_STORAGE_MANIFEST => 'storageManifest';\n"
"push @EXPORT, qw(OP_STORAGE_MANIFEST);\n"
"use constant OP_STORAGE_MOVE => 'storageMove';\n"
"push @EXPORT, qw(OP_STORAGE_MOVE);\n"
"use constant OP_STORAGE_PATH_GET => 'storagePathGet';\n"
"push @EXPORT, qw(OP_STORAGE_PATH_GET);\n"
"\n\n"
"use constant OP_RESTORE_FILE => 'restoreFile';\n"
"push @EXPORT, qw(OP_RESTORE_FILE);\n"
"\n\n"
"use constant OP_WAIT => 'wait';\n"
"push @EXPORT, qw(OP_WAIT);\n"
"\n\n\n\n"
"my $hProtocol = {};\n"
"\n\n\n\n\n\n"
"sub isRepoLocal\n"
"{\n"
"\n"
"if (cfgCommandTest(CFGCMD_REMOTE) && !cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP))\n"
"{\n"
"confess &log(ASSERT, 'isRepoLocal() not valid on ' . cfgOption(CFGOPT_TYPE) . ' remote');\n"
"}\n"
"\n"
"return cfgOptionTest(CFGOPT_REPO_HOST) ? false : true;\n"
"}\n"
"\n"
"push @EXPORT, qw(isRepoLocal);\n"
"\n\n\n\n"
"sub isDbLocal\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iRemoteIdx,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::isDbLocal', \\@_,\n"
"{name => 'iRemoteIdx', optional => true, default => cfgOptionValid(CFGOPT_HOST_ID) ? cfgOption(CFGOPT_HOST_ID) : 1,\n"
"trace => true},\n"
");\n"
"\n\n"
"if (cfgCommandTest(CFGCMD_REMOTE) && !cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB))\n"
"{\n"
"confess &log(ASSERT, 'isDbLocal() not valid on ' . cfgOption(CFGOPT_TYPE) . ' remote');\n"
"}\n"
"\n"
"my $bLocal = cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iRemoteIdx)) ? false : true;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bLocal', value => $bLocal, trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(isDbLocal);\n"
"\n\n\n\n"
"sub protocolParam\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strCommand,\n"
"$strRemoteType,\n"
"$iRemoteIdx,\n"
"$strBackRestBin,\n"
"$iProcessIdx,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::protocolParam', \\@_,\n"
"{name => 'strCommand'},\n"
"{name => 'strRemoteType'},\n"
"{name => 'iRemoteIdx', default => cfgOptionValid(CFGOPT_HOST_ID) ? cfgOption(CFGOPT_HOST_ID) : 1},\n"
"{name => 'strBackRestBin', optional => true},\n"
"{name => 'iProcessIdx', optional => true,\n"
"default => cfgOptionValid(CFGOPT_PROCESS) ? cfgOption(CFGOPT_PROCESS, false) : undef},\n"
");\n"
"\n\n"
"my $iOptionIdCmd = CFGOPT_REPO_HOST_CMD;\n"
"my $iOptionIdConfig = CFGOPT_REPO_HOST_CONFIG;\n"
"my $iOptionIdConfigIncludePath = CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH;\n"
"my $iOptionIdConfigPath = CFGOPT_REPO_HOST_CONFIG_PATH;\n"
"my $iOptionIdHost = CFGOPT_REPO_HOST;\n"
"my $iOptionIdUser = CFGOPT_REPO_HOST_USER;\n"
"my $strOptionDbPath = undef;\n"
"my $strOptionDbPort = undef;\n"
"my $strOptionDbSocketPath = undef;\n"
"my $strOptionSshPort = CFGOPT_REPO_HOST_PORT;\n"
"\n"
"if ($strRemoteType eq CFGOPTVAL_REMOTE_TYPE_DB)\n"
"{\n"
"$iOptionIdCmd = cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, $iRemoteIdx);\n"
"$iOptionIdConfig = cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG, $iRemoteIdx);\n"
"$iOptionIdConfigIncludePath = cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH, $iRemoteIdx);\n"
"$iOptionIdConfigPath = cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG_PATH, $iRemoteIdx);\n"
"$iOptionIdHost = cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iRemoteIdx);\n"
"$iOptionIdUser = cfgOptionIdFromIndex(CFGOPT_PG_HOST_USER, $iRemoteIdx);\n"
"$strOptionSshPort = cfgOptionIdFromIndex(CFGOPT_PG_HOST_PORT, $iRemoteIdx);\n"
"}\n"
"\n\n"
"if (cfgOptionValid(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)))\n"
"{\n"
"$strOptionDbPath =\n"
"cfgOptionSource(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)) eq CFGDEF_SOURCE_DEFAULT ?\n"
"undef : cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx));\n"
"}\n"
"\n\n"
"if (cfgOptionValid(cfgOptionIdFromIndex(CFGOPT_PG_PORT, $iRemoteIdx)))\n"
"{\n"
"$strOptionDbPort =\n"
"cfgOptionSource(cfgOptionIdFromIndex(CFGOPT_PG_PORT, $iRemoteIdx)) eq CFGDEF_SOURCE_DEFAULT ?\n"
"undef : cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PORT, $iRemoteIdx));\n"
"}\n"
"\n\n"
"if (cfgOptionValid(cfgOptionIdFromIndex(CFGOPT_PG_SOCKET_PATH, $iRemoteIdx)))\n"
"{\n"
"$strOptionDbSocketPath =\n"
"cfgOptionSource(cfgOptionIdFromIndex(CFGOPT_PG_SOCKET_PATH, $iRemoteIdx)) eq CFGDEF_SOURCE_DEFAULT ?\n"
"undef : cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_SOCKET_PATH, $iRemoteIdx));\n"
"}\n"
"\n\n"
"my $rhCommandOption =\n"
"{\n"
"&CFGOPT_COMMAND => {value => $strCommand},\n"
"&CFGOPT_PROCESS => {value => defined($iProcessIdx) ? $iProcessIdx : 0},\n"
"&CFGOPT_CONFIG =>\n"
"{value => cfgOptionValid($iOptionIdConfig) && cfgOptionSource($iOptionIdConfig) eq CFGDEF_SOURCE_DEFAULT ?\n"
"undef : cfgOption($iOptionIdConfig)},\n"
"&CFGOPT_CONFIG_INCLUDE_PATH =>\n"
"{value => cfgOptionValid($iOptionIdConfigIncludePath) &&\n"
"cfgOptionSource($iOptionIdConfigIncludePath) eq CFGDEF_SOURCE_DEFAULT ?\n"
"undef : cfgOption($iOptionIdConfigIncludePath)},\n"
"&CFGOPT_CONFIG_PATH =>\n"
"{value => cfgOptionValid($iOptionIdConfigPath) && cfgOptionSource($iOptionIdConfigPath) eq CFGDEF_SOURCE_DEFAULT ?\n"
"undef : cfgOption($iOptionIdConfigPath)},\n"
"&CFGOPT_TYPE => {value => $strRemoteType},\n"
"&CFGOPT_LOG_PATH => {},\n"
"&CFGOPT_LOCK_PATH => {},\n"
"\n\n"
"&CFGOPT_LOG_LEVEL_FILE => {value => cfgOption(CFGOPT_LOG_SUBPROCESS) ? cfgOption(CFGOPT_LOG_LEVEL_FILE) : lc(OFF)},\n"
"\n\n\n"
"&CFGOPT_LOG_LEVEL_STDERR => {},\n"
"\n"
"cfgOptionIdFromIndex(CFGOPT_PG_PATH, 1) => {value => $strOptionDbPath},\n"
"cfgOptionIdFromIndex(CFGOPT_PG_PORT, 1) => {value => $strOptionDbPort},\n"
"cfgOptionIdFromIndex(CFGOPT_PG_SOCKET_PATH, 1) => {value => $strOptionDbSocketPath},\n"
"\n\n"
"&CFGOPT_BUFFER_SIZE => {value => cfgOption(CFGOPT_BUFFER_SIZE)},\n"
"&CFGOPT_COMPRESS_LEVEL => {value => cfgOption(CFGOPT_COMPRESS_LEVEL)},\n"
"&CFGOPT_COMPRESS_LEVEL_NETWORK => {value => cfgOption(CFGOPT_COMPRESS_LEVEL_NETWORK)},\n"
"&CFGOPT_PROTOCOL_TIMEOUT => {value => cfgOption(CFGOPT_PROTOCOL_TIMEOUT)}\n"
"};\n"
"\n\n\n"
"for (my $iOptionIdx = 1; $iOptionIdx <= cfgOptionIndexTotal(CFGOPT_PG_HOST); $iOptionIdx++)\n"
"{\n"
"if ($iOptionIdx != 1)\n"
"{\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG, $iOptionIdx)} = {};\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH, $iOptionIdx)} = {};\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_HOST_CONFIG_PATH, $iOptionIdx)} = {};\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iOptionIdx)} = {};\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iOptionIdx)} = {};\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_PORT, $iOptionIdx)} = {};\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_SOCKET_PATH, $iOptionIdx)} = {};\n"
"}\n"
"\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_HOST_CMD, $iOptionIdx)} = {};\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_HOST_USER, $iOptionIdx)} = {};\n"
"$rhCommandOption->{cfgOptionIdFromIndex(CFGOPT_PG_HOST_PORT, $iOptionIdx)} = {};\n"
"}\n"
"\n\n"
"my $strRemoteCommand = cfgCommandWrite(\n"
"CFGCMD_REMOTE, true, defined($strBackRestBin) ? $strBackRestBin : cfgOption($iOptionIdCmd), undef, $rhCommandOption);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strRemoteHost', value => cfgOption($iOptionIdHost)},\n"
"{name => 'strRemoteHostUser', value => cfgOption($iOptionIdUser)},\n"
"{name => 'strRemoteHostSshPort', value => cfgOption($strOptionSshPort, false)},\n"
"{name => 'strRemoteCommand', value => $strRemoteCommand},\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub protocolGet\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strRemoteType,\n"
"$iRemoteIdx,\n"
"$bCache,\n"
"$strBackRestBin,\n"
"$iProcessIdx,\n"
"$strCommand,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::protocolGet', \\@_,\n"
"{name => 'strRemoteType'},\n"
"{name => 'iRemoteIdx', default => cfgOptionValid(CFGOPT_HOST_ID) ? cfgOption(CFGOPT_HOST_ID) : 1},\n"
"{name => 'bCache', optional => true, default => true},\n"
"{name => 'strBackRestBin', optional => true},\n"
"{name => 'iProcessIdx', optional => true},\n"
"{name => 'strCommand', optional => true,\n"
"default => cfgOptionValid(CFGOPT_COMMAND) ? cfgOption(CFGOPT_COMMAND) : cfgCommandName(cfgCommandGet())},\n"
");\n"
"\n\n"
"my $oProtocol;\n"
"\n\n"
"if (!cfgOptionTest(\n"
"cfgOptionIdFromIndex($strRemoteType eq CFGOPTVAL_REMOTE_TYPE_DB ? CFGOPT_PG_HOST : CFGOPT_REPO_HOST, $iRemoteIdx)))\n"
"{\n"
"confess &log(ASSERT, 'protocol cannot be created when remote host is not specified');\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"$oProtocol =\n"
"$bCache && defined($$hProtocol{$strRemoteType}{$iRemoteIdx}) ? $$hProtocol{$strRemoteType}{$iRemoteIdx} : undef;\n"
"\n"
"if ($bCache && $$hProtocol{$strRemoteType}{$iRemoteIdx})\n"
"{\n"
"$oProtocol = $$hProtocol{$strRemoteType}{$iRemoteIdx};\n"
"logDebugMisc($strOperation, 'found cached protocol');\n"
"\n\n\n"
"$oProtocol->noOp();\n"
"}\n"
"\n\n"
"if (!defined($oProtocol))\n"
"{\n"
"logDebugMisc($strOperation, 'create (' . ($bCache ? '' : 'un') . 'cached) remote protocol');\n"
"\n"
"my ($strRemoteHost, $strRemoteHostUser, $strRemoteHostSshPort, $strRemoteCommand) = protocolParam(\n"
"$strCommand, $strRemoteType, $iRemoteIdx, {strBackRestBin => $strBackRestBin, iProcessIdx => $iProcessIdx});\n"
"\n"
"$oProtocol = new pgBackRest::Protocol::Remote::Master\n"
"(\n"
"cfgOption(CFGOPT_CMD_SSH),\n"
"$strRemoteCommand,\n"
"cfgOption(CFGOPT_BUFFER_SIZE),\n"
"cfgOption(CFGOPT_COMPRESS_LEVEL),\n"
"cfgOption(CFGOPT_COMPRESS_LEVEL_NETWORK),\n"
"$strRemoteHost,\n"
"$strRemoteHostUser,\n"
"$strRemoteHostSshPort,\n"
"cfgOption(CFGOPT_PROTOCOL_TIMEOUT)\n"
");\n"
"\n\n"
"if ($bCache)\n"
"{\n"
"$$hProtocol{$strRemoteType}{$iRemoteIdx} = $oProtocol;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oProtocol', value => $oProtocol, trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(protocolGet);\n"
"\n\n\n\n"
"sub protocolList\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strRemoteType,\n"
"$iRemoteIdx,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::protocolList', \\@_,\n"
"{name => 'strRemoteType', required => false, trace => true},\n"
"{name => 'iRemoteIdx', required => false, trace => true},\n"
");\n"
"\n"
"my @oyProtocol;\n"
"\n"
"if (!defined($strRemoteType))\n"
"{\n"
"foreach my $strRemoteType (sort(keys(%{$hProtocol})))\n"
"{\n"
"push(@oyProtocol, protocolList($strRemoteType));\n"
"}\n"
"}\n"
"elsif (!defined($iRemoteIdx))\n"
"{\n"
"foreach my $iRemoteIdx (sort(keys(%{$hProtocol->{$strRemoteType}})))\n"
"{\n"
"push(@oyProtocol, protocolList($strRemoteType, $iRemoteIdx));\n"
"}\n"
"}\n"
"elsif (defined($hProtocol->{$strRemoteType}{$iRemoteIdx}))\n"
"{\n"
"push(@oyProtocol, {strRemoteType => $strRemoteType, iRemoteIdx => $iRemoteIdx});\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oyProtocol', value => \\@oyProtocol, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub protocolDestroy\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strRemoteType,\n"
"$iRemoteIdx,\n"
"$bComplete,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::protocolDestroy', \\@_,\n"
"{name => 'strRemoteType', required => false},\n"
"{name => 'iRemoteIdx', required => false},\n"
"{name => 'bComplete', default => false},\n"
");\n"
"\n"
"my $iExitStatus = 0;\n"
"\n"
"foreach my $rhProtocol (protocolList($strRemoteType, $iRemoteIdx))\n"
"{\n"
"logDebugMisc(\n"
"$strOperation, 'found cached protocol',\n"
"{name => 'strRemoteType', value => $rhProtocol->{strRemoteType}},\n"
"{name => 'iRemoteIdx', value => $rhProtocol->{iRemoteIdx}});\n"
"\n"
"$iExitStatus = $hProtocol->{$rhProtocol->{strRemoteType}}{$rhProtocol->{iRemoteIdx}}->close($bComplete);\n"
"delete($hProtocol->{$rhProtocol->{strRemoteType}}{$rhProtocol->{iRemoteIdx}});\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iExitStatus', value => $iExitStatus}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(protocolDestroy);\n"
"\n\n\n\n"
"sub protocolKeepAlive\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strRemoteType,\n"
"$iRemoteIdx,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::protocolDestroy', \\@_,\n"
"{name => 'strRemoteType', required => false, trace => true},\n"
"{name => 'iRemoteIdx', required => false, trace => true},\n"
");\n"
"\n"
"foreach my $rhProtocol (protocolList($strRemoteType, $iRemoteIdx))\n"
"{\n"
"$hProtocol->{$rhProtocol->{strRemoteType}}{$rhProtocol->{iRemoteIdx}}->keepAlive();\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n"
"push @EXPORT, qw(protocolKeepAlive);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Local/Master.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Local::Master;\n"
"use parent 'pgBackRest::Protocol::Command::Master';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use pgBackRest::Backup::File;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Command::Master;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strCommand,\n"
"$iProcessIdx,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strCommand'},\n"
"{name => 'iProcessIdx', default => 1},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new(\n"
"'local', \"local-${iProcessIdx} process\", $strCommand, cfgOption(CFGOPT_BUFFER_SIZE),\n"
"cfgOption(CFGOPT_COMPRESS_LEVEL), cfgOption(CFGOPT_COMPRESS_LEVEL_NETWORK), cfgOption(CFGOPT_PROTOCOL_TIMEOUT));\n"
"\n"
"bless $self, $class;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Local/Minion.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Local::Minion;\n"
"use parent 'pgBackRest::Protocol::Command::Minion';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use pgBackRest::Backup::File;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Storage::Local;\n"
"use pgBackRest::Protocol::Base::Master;\n"
"use pgBackRest::Protocol::Base::Minion;\n"
"use pgBackRest::Protocol::Command::Minion;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::RestoreFile;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');\n"
"\n\n"
"my $self = $class->SUPER::new(cfgCommandName(CFGCMD_LOCAL), cfgOption(CFGOPT_BUFFER_SIZE), cfgOption(CFGOPT_PROTOCOL_TIMEOUT));\n"
"bless $self, $class;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub init\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->init');\n"
"\n\n"
"my $hCommandMap =\n"
"{\n"
"&OP_BACKUP_FILE => sub {backupFile(@{shift()})},\n"
"\n\n"
"&OP_POST => sub {protocolKeepAlive()},\n"
"};\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hCommandMap', value => $hCommandMap}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Local/Process.pm",
.data =
"\n\n\n\n\n"
"package pgBackRest::Protocol::Local::Process;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use IO::Select;\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Local::Master;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{strHostType},\n"
"$self->{iSelectTimeout},\n"
"$self->{strBackRestBin},\n"
"$self->{bConfessError},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strHostType'},\n"
"{name => 'iSelectTimeout', default => int(cfgOption(CFGOPT_PROTOCOL_TIMEOUT) / 2)},\n"
"{name => 'strBackRestBin', default => projectBin()},\n"
"{name => 'bConfessError', default => true},\n"
");\n"
"\n\n"
"$self->{hHostMap} = {};\n"
"$self->{hyHost} = undef;\n"
"\n\n"
"$self->reset();\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub reset\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->reset');\n"
"\n\n"
"$self->{oSelect} = undef;\n"
"\n\n"
"$self->{hyLocalMap} = undef;\n"
"$self->{hyLocal} = undef;\n"
"\n\n"
"$self->{bProcessing} = false;\n"
"\n\n"
"$self->{iQueued} = 0;\n"
"\n\n"
"$self->{iRunning} = 0;\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub hostAdd\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iHostConfigIdx,\n"
"$iProcessMax,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->hostAdd', \\@_,\n"
"{name => 'iHostConfigIdx'},\n"
"{name => 'iProcessMax'},\n"
");\n"
"\n"
"my $iHostIdx = $self->{hHostMap}{$iHostConfigIdx};\n"
"\n"
"if (!defined($iHostIdx))\n"
"{\n"
"$iHostIdx = defined($self->{hyHost}) ? @{$self->{hyHost}} : 0;\n"
"$self->{hHostMap}{$iHostConfigIdx} = $iHostIdx;\n"
"}\n"
"\n"
"my $hHost =\n"
"{\n"
"iHostConfigIdx => $iHostConfigIdx,\n"
"iProcessMax => $iProcessMax,\n"
"};\n"
"\n"
"push(@{$self->{hyHost}}, $hHost);\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub hostConnect\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->hostConnect');\n"
"\n\n"
"$self->{oSelect} = IO::Select->new();\n"
"\n\n"
"my $iHostIdx = 0;\n"
"\n"
"foreach my $hHost (@{$self->{hyHost}})\n"
"{\n"
"\n"
"if (!defined($hHost->{hyQueue}))\n"
"{\n"
"logDebugMisc(\n"
"$strOperation, \"no jobs for host\",\n"
"{name => 'strHostType', value => $self->{strHostType}},\n"
"{name => 'iHostConfigIdx', value => $hHost->{iHostConfigIdx}});\n"
"next;\n"
"}\n"
"\n"
"for (my $iHostProcessIdx = 0; $iHostProcessIdx < $hHost->{iProcessMax}; $iHostProcessIdx++)\n"
"{\n"
"my $iLocalIdx = defined($self->{hyLocal}) ? @{$self->{hyLocal}} : 0;\n"
"my $iProcessId = $iLocalIdx + 1;\n"
"\n"
"logDebugMisc(\n"
"$strOperation, 'start local process',\n"
"{name => 'strHostType', value => $self->{strHostType}},\n"
"{name => 'iHostProcessIdx', value => $iHostProcessIdx},\n"
"{name => 'iHostConfigIdx', value => $hHost->{iHostConfigIdx}},\n"
"{name => 'iHostIdx', value => $iHostIdx},\n"
"{name => 'iProcessId', value => $iProcessId});\n"
"\n"
"my $oLocal = new pgBackRest::Protocol::Local::Master\n"
"(\n"
"cfgCommandWrite(\n"
"CFGCMD_LOCAL, true, $self->{strBackRestBin}, undef,\n"
"{\n"
"&CFGOPT_COMMAND => {value => cfgCommandName(cfgCommandGet())},\n"
"&CFGOPT_PROCESS => {value => $iProcessId},\n"
"&CFGOPT_TYPE => {value => $self->{strHostType}},\n"
"&CFGOPT_HOST_ID => {value => $hHost->{iHostConfigIdx}},\n"
"\n\n"
"&CFGOPT_LOG_LEVEL_FILE =>\n"
"{value => cfgOption(CFGOPT_LOG_SUBPROCESS) ? cfgOption(CFGOPT_LOG_LEVEL_FILE) : lc(OFF)},\n"
"&CFGOPT_LOG_LEVEL_STDERR => {},\n"
"}),\n"
"$iLocalIdx + 1\n"
");\n"
"\n"
"my $hLocal =\n"
"{\n"
"iHostIdx => $iHostIdx,\n"
"iProcessId => $iProcessId,\n"
"iHostProcessIdx => $iHostProcessIdx,\n"
"oLocal => $oLocal,\n"
"hndIn => fileno($oLocal->io()->handleRead()),\n"
"};\n"
"\n"
"push(@{$self->{hyLocal}}, $hLocal);\n"
"\n"
"$self->{hLocalMap}{$hLocal->{hndIn}} = $hLocal;\n"
"$self->{oSelect}->add($hLocal->{hndIn});\n"
"}\n"
"\n"
"$iHostIdx++;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bResult', value => $iHostIdx > 0 ? true : false}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub init\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->init');\n"
"\n"
"if ($self->hostConnect())\n"
"{\n"
"foreach my $hLocal (@{$self->{hyLocal}})\n"
"{\n"
"my $hHost = $self->{hyHost}[$hLocal->{iHostIdx}];\n"
"my $hyQueue = $hHost->{hyQueue};\n"
"\n\n"
"$hLocal->{iDirection} = $hLocal->{iHostProcessIdx} % 2 == 0 ? 1 : -1;\n"
"$hLocal->{iQueueIdx} = int((@{$hyQueue} / $hHost->{iProcessMax}) * $hLocal->{iHostProcessIdx});\n"
"\n\n"
"$hLocal->{iQueueLastIdx} = $hLocal->{iQueueIdx} + ($hLocal->{iDirection} * -1);\n"
"\n"
"if ($hLocal->{iQueueLastIdx} < 0)\n"
"{\n"
"$hLocal->{iQueueLastIdx} = @{$hyQueue} - 1;\n"
"}\n"
"elsif ($hLocal->{iQueueLastIdx} >= @{$hyQueue})\n"
"{\n"
"$hLocal->{iQueueLastIdx} = 0;\n"
"}\n"
"\n"
"logDebugMisc(\n"
"$strOperation, 'init local process',\n"
"{name => 'iHostIdx', value => $hLocal->{iHostIdx}},\n"
"{name => 'iProcessId', value => $hLocal->{iProcessId}},\n"
"{name => 'iDirection', value => $hLocal->{iDirection}},\n"
"{name => 'iQueueIdx', value => $hLocal->{iQueueIdx}},\n"
"{name => 'iQueueLastIdx', value => $hLocal->{iQueueLastIdx}});\n"
"}\n"
"\n"
"$self->{bProcessing} = true;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bResult', value => $self->processing()}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');\n"
"\n\n"
"if (!$self->processing())\n"
"{\n"
"if (!$self->init())\n"
"{\n"
"logDebugMisc($strOperation, 'no jobs to run');\n"
"$self->reset();\n"
"return;\n"
"}\n"
"}\n"
"\n\n"
"my @hyResult = ();\n"
"my $iCompleted = 0;\n"
"\n"
"if ($self->{iRunning} > 0)\n"
"{\n"
"&logDebugMisc(\n"
"$strOperation, 'check running jobs',\n"
"{name => 'iRunning', value => $self->{iRunning}, trace => true});\n"
"\n\n"
"my @hndyIn = $self->{oSelect}->can_read($self->{iSelectTimeout});\n"
"\n\n"
"foreach my $hndIn (@hndyIn)\n"
"{\n"
"\n"
"my $hLocal = $self->{hLocalMap}{$hndIn};\n"
"\n"
"if (!defined($hLocal))\n"
"{\n"
"confess &log(ASSERT, \"unable to map from fileno ${hndIn} to local\");\n"
"}\n"
"\n\n"
"my $hJob = $hLocal->{hJob};\n"
"\n"
"eval\n"
"{\n"
"$hJob->{rResult} = $hLocal->{oLocal}->outputRead(true, undef, undef, true);\n"
"\n\n\n"
"if (ref($hJob->{rResult}) ne 'ARRAY')\n"
"{\n"
"my @resultArray = (${$hJob->{rResult}});\n"
"$hJob->{rResult} = \\@resultArray;\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"my $oException = $EVAL_ERROR;\n"
"\n\n"
"confess $oException if (!isException(\\$oException));\n"
"\n\n"
"if (!defined($hLocal->{oLocal}->io()->processId()))\n"
"{\n"
"confess logException($oException);\n"
"}\n"
"\n\n"
"if ($self->{bConfessError})\n"
"{\n"
"confess logException($oException);\n"
"}\n"
"\n"
"else\n"
"{\n"
"$hJob->{oException} = $oException;\n"
"}\n"
"};\n"
"\n"
"$hJob->{iProcessId} = $hLocal->{iProcessId};\n"
"push(@hyResult, $hJob);\n"
"\n"
"logDebugMisc(\n"
"$strOperation, 'job complete',\n"
"{name => 'iProcessId', value => $hJob->{iProcessId}},\n"
"{name => 'strKey', value => $hJob->{strKey}},\n"
"{name => 'rResult', value => $hJob->{rResult}});\n"
"\n\n"
"$hLocal->{hJob} = undef;\n"
"$self->{iRunning}--;\n"
"$iCompleted++;\n"
"}\n"
"}\n"
"\n\n"
"if ($self->{iRunning} == 0 || $iCompleted > 0)\n"
"{\n"
"&logDebugMisc(\n"
"$strOperation, 'get new jobs',\n"
"{name => 'iRunning', value => $self->{iRunning}, trace => true},\n"
"{name => 'iCompleted', value => $iCompleted, trace => true});\n"
"\n"
"my $bFound = false;\n"
"my $iLocalIdx = -1;\n"
"\n\n"
"foreach my $hLocal (@{$self->{hyLocal}})\n"
"{\n"
"\n"
"$iLocalIdx++;\n"
"next if (!defined($hLocal));\n"
"\n"
"my $hHost = $self->{hyHost}[$hLocal->{iHostIdx}];\n"
"my $hyQueue = $hHost->{hyQueue};\n"
"\n\n"
"if (!defined($hLocal->{hJob}))\n"
"{\n"
"\n"
"my $iQueueIdx = $hLocal->{iQueueIdx};\n"
"my $hJob = shift(@{$$hyQueue[$iQueueIdx]});\n"
"\n"
"while (!defined($hJob) && $iQueueIdx != $hLocal->{iQueueLastIdx})\n"
"{\n"
"$iQueueIdx += $hLocal->{iDirection};\n"
"\n"
"if ($iQueueIdx < 0)\n"
"{\n"
"$iQueueIdx = @{$hyQueue} - 1;\n"
"}\n"
"elsif ($iQueueIdx >= @{$hyQueue})\n"
"{\n"
"$iQueueIdx = 0;\n"
"}\n"
"\n"
"$hJob = shift(@{$$hyQueue[$iQueueIdx]});\n"
"}\n"
"\n\n"
"if (!defined($hJob))\n"
"{\n"
"logDebugMisc(\n"
"$strOperation, 'no jobs found, stop local',\n"
"{name => 'strHostType', value => $hLocal->{strHostType}},\n"
"{name => 'iHostConfigIdx', value => $hLocal->{iHostConfigIdx}},\n"
"{name => 'iHostIdx', value => $hLocal->{iHostIdx}},\n"
"{name => 'iProcessId', value => $hLocal->{iProcessId}});\n"
"\n\n"
"my $iHandleTotal = $self->{oSelect}->count();\n"
"\n"
"$self->{oSelect}->remove($hLocal->{hndIn});\n"
"\n"
"if ($iHandleTotal - $self->{oSelect}->count() != 1)\n"
"{\n"
"confess &log(ASSERT,\n"
"\"iProcessId $hLocal->{iProcessId}, handle $hLocal->{hndIn} was not removed from select object\");\n"
"}\n"
"\n\n"
"delete($self->{hLocalMap}{$hLocal->{hndIn}});\n"
"\n\n"
"$hLocal->{oLocal}->close(true);\n"
"\n\n"
"undef(${$self->{hyLocal}}[$iLocalIdx]);\n"
"\n\n"
"next;\n"
"}\n"
"\n\n"
"$hLocal->{hJob} = $hJob;\n"
"$bFound = true;\n"
"$self->{iRunning}++;\n"
"$self->{iQueued}--;\n"
"\n"
"logDebugMisc(\n"
"$strOperation, 'get job from queue',\n"
"{name => 'iHostIdx', value => $hLocal->{iHostIdx}},\n"
"{name => 'iProcessId', value => $hLocal->{iProcessId}},\n"
"{name => 'strQueueIdx', value => $iQueueIdx},\n"
"{name => 'strKey', value => $hLocal->{hJob}{strKey}});\n"
"\n\n"
"$hLocal->{oLocal}->cmdWrite($hLocal->{hJob}{strOp}, $hLocal->{hJob}->{rParam});\n"
"}\n"
"}\n"
"\n\n"
"if (!$bFound && !$self->{iRunning} && @hyResult == 0)\n"
"{\n"
"logDebugMisc($strOperation, 'all jobs complete');\n"
"$self->reset();\n"
"return;\n"
"}\n"
"}\n"
"\n\n"
"return \\@hyResult;\n"
"}\n"
"\n\n\n\n\n\n"
"sub queueJob\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iHostConfigIdx,\n"
"$strQueue,\n"
"$strKey,\n"
"$strOp,\n"
"$rParam,\n"
"$rParamSecure,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->queueJob', \\@_,\n"
"{name => 'iHostConfigIdx'},\n"
"{name => 'strQueue'},\n"
"{name => 'strKey'},\n"
"{name => 'strOp'},\n"
"{name => 'rParam'},\n"
"{name => 'rParamSecure', optional => true, redact => true},\n"
");\n"
"\n\n"
"if ($self->processing())\n"
"{\n"
"confess &log(ASSERT, 'new jobs cannot be added until processing is complete');\n"
"}\n"
"\n\n"
"if (defined($rParamSecure))\n"
"{\n"
"push(@{$rParam}, @{$rParamSecure});\n"
"}\n"
"\n\n"
"my $hJob =\n"
"{\n"
"iHostConfigIdx => $iHostConfigIdx,\n"
"strQueue => $strQueue,\n"
"strKey => $strKey,\n"
"strOp => $strOp,\n"
"rParam => $rParam,\n"
"};\n"
"\n\n"
"my $iHostIdx = $self->{hHostMap}{$iHostConfigIdx};\n"
"\n"
"if (!defined($iHostIdx))\n"
"{\n"
"confess &log(ASSERT, \"iHostConfigIdx = $iHostConfigIdx does not exist\");\n"
"}\n"
"\n"
"my $hHost = $self->{hyHost}[$iHostIdx];\n"
"\n\n"
"my $iQueueIdx = $hHost->{hQueueMap}{$strQueue};\n"
"\n"
"if (!defined($iQueueIdx))\n"
"{\n"
"$iQueueIdx = defined($hHost->{hyQueue}) ? @{$hHost->{hyQueue}} : 0;\n"
"$hHost->{hQueueMap}{$strQueue} = $iQueueIdx;\n"
"}\n"
"\n"
"push(@{$hHost->{hyQueue}[$iQueueIdx]}, $hJob);\n"
"$self->{iQueued}++;\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub dequeueJobs\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iHostConfigIdx,\n"
"$strQueue,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->dequeueJobs', \\@_,\n"
"{name => 'iHostConfigIdx'},\n"
"{name => 'strQueue'},\n"
");\n"
"\n\n"
"if (!$self->processing())\n"
"{\n"
"confess &log(ASSERT, 'unable to dequeue a job when not processing');\n"
"}\n"
"\n\n"
"my $iHostIdx = $self->{hHostMap}{$iHostConfigIdx};\n"
"\n"
"if (!defined($iHostIdx))\n"
"{\n"
"confess &log(ASSERT, \"iHostConfigIdx = $iHostConfigIdx does not exist\");\n"
"}\n"
"\n"
"my $hHost = $self->{hyHost}[$iHostIdx];\n"
"\n\n"
"my $iQueueIdx = $hHost->{hQueueMap}{$strQueue};\n"
"\n"
"if (!defined($iQueueIdx))\n"
"{\n"
"confess &log(ASSERT, \"unable to find queue '${strQueue}'\");\n"
"}\n"
"\n"
"$hHost->{hyQueue}[$iQueueIdx] = [];\n"
"$self->{iQueued} = 0;\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub jobTotal\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->jobTotal');\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iJobTotal', value => $self->{iQueued} + $self->{iRunning}}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub processing\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->processing');\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bProcessing', value => $self->{bProcessing}, trace => true}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Remote/Master.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Remote::Master;\n"
"use parent 'pgBackRest::Protocol::Command::Master';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Command::Master;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strCommandSSH,\n"
"$strCommand,\n"
"$iBufferMax,\n"
"$iCompressLevel,\n"
"$iCompressLevelNetwork,\n"
"$strHost,\n"
"$strUser,\n"
"$iSshPort,\n"
"$iProtocolTimeout,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strCommandSSH'},\n"
"{name => 'strCommand'},\n"
"{name => 'iBufferMax'},\n"
"{name => 'iCompressLevel'},\n"
"{name => 'iCompressLevelNetwork'},\n"
"{name => 'strHost'},\n"
"{name => 'strUser'},\n"
"{name => 'iSshPort', required => false},\n"
"{name => 'iProtocolTimeout'},\n"
");\n"
"\n"
"my $strCommandSshPort = defined($iSshPort) ? '-p ' . $iSshPort . ' ' : '';\n"
"\n\n"
"$strCommand =\n"
"\"${strCommandSSH} -o LogLevel=error -o Compression=no -o PasswordAuthentication=no $strCommandSshPort\" .\n"
"\"${strUser}\\@${strHost} '${strCommand}'\";\n"
"\n\n"
"my $self = $class->SUPER::new(\n"
"'remote', \"remote process on '$strHost'\", $strCommand, $iBufferMax, $iCompressLevel, $iCompressLevelNetwork,\n"
"$iProtocolTimeout);\n"
"bless $self, $class;\n"
"\n\n"
"$self->{strHost} = $strHost;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Remote/Minion.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Remote::Minion;\n"
"use parent 'pgBackRest::Protocol::Command::Minion';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Backup::File;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Io::Buffered;\n"
"use pgBackRest::Common::Wait;\n"
"use pgBackRest::Archive::Get::File;\n"
"use pgBackRest::Check::Check;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Db;\n"
"use pgBackRest::Protocol::Command::Minion;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iBufferMax,\n"
"$iProtocolTimeout\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'iBufferMax'},\n"
"{name => 'iProtocolTimeout'}\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new(cfgCommandName(CFGCMD_REMOTE), $iBufferMax, $iProtocolTimeout);\n"
"bless $self, $class;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub init\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->init');\n"
"\n\n"
"my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();\n"
"\n"
"my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef;\n"
"my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;\n"
"\n\n"
"my $hCommandMap =\n"
"{\n"
"\n"
"&OP_ARCHIVE_GET_CHECK => sub {archiveGetCheck(@{shift()})},\n"
"\n\n"
"&OP_CHECK_BACKUP_INFO_CHECK => sub {$oCheck->backupInfoCheck(@{shift()})},\n"
"\n\n"
"&OP_DB_CONNECT => sub {$oDb->connect()},\n"
"&OP_DB_EXECUTE_SQL => sub {$oDb->executeSql(@{shift()})},\n"
"&OP_DB_INFO => sub {$oDb->info(@{shift()})},\n"
"\n\n"
"&OP_STORAGE_OPEN_READ => sub\n"
"{\n"
"my $oSourceFileIo = $oStorage->openRead(@{shift()});\n"
"\n\n"
"if (defined($oSourceFileIo))\n"
"{\n"
"$self->outputWrite(true);\n"
"\n"
"$oStorage->copy($oSourceFileIo, new pgBackRest::Protocol::Storage::File($self, $oSourceFileIo));\n"
"\n"
"return true;\n"
"}\n"
"\n"
"return false;\n"
"},\n"
"&OP_STORAGE_OPEN_WRITE => sub\n"
"{\n"
"my $oDestinationFileIo = $oStorage->openWrite(@{shift()});\n"
"$oStorage->copy(new pgBackRest::Protocol::Storage::File($self, $oDestinationFileIo), $oDestinationFileIo);\n"
"},\n"
"\n"
"&OP_STORAGE_CIPHER_PASS_USER => sub {$oStorage->cipherPassUser()},\n"
"&OP_STORAGE_EXISTS => sub {$oStorage->exists(@{shift()})},\n"
"&OP_STORAGE_LIST => sub {$oStorage->list(@{shift()})},\n"
"&OP_STORAGE_MANIFEST => sub {$oStorage->manifest(@{shift()})},\n"
"&OP_STORAGE_MOVE => sub {$oStorage->move(@{shift()})},\n"
"&OP_STORAGE_PATH_GET => sub {$oStorage->pathGet(@{shift()})},\n"
"&OP_STORAGE_HASH_SIZE => sub {$oStorage->hashSize(@{shift()})},\n"
"\n\n"
"&OP_WAIT => sub {waitRemainder(@{shift()})},\n"
"};\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hCommandMap', value => $hCommandMap}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Storage/File.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Storage::File;\n"
"use parent 'pgBackRest::Common::Io::Base';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oProtocol,\n"
"$oFileIo,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oProtocol', trace => true},\n"
"{name => 'oFileIo', required => false, trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($oProtocol->io()->id() . ' file');\n"
"bless $self, $class;\n"
"\n\n"
"$self->{oProtocol} = $oProtocol;\n"
"$self->{oFileIo} = $oFileIo;\n"
"\n\n"
"$self->{bWrite} = false;\n"
"\n\n"
"$self->eofSet(false);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub eof\n"
"{\n"
"return shift->{bEOF};\n"
"}\n"
"\n\n\n\n"
"sub eofSet\n"
"{\n"
"my $self = shift;\n"
"my $bEOF = shift;\n"
"\n"
"$self->{bEOF} = $bEOF;\n"
"}\n"
"\n\n\n\n"
"sub read\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"\n\n"
"return 0 if $self->eof();\n"
"\n"
"my $lBlockSize;\n"
"\n\n"
"my $strBlockHeader = $self->{oProtocol}->io()->readLine();\n"
"\n"
"if ($strBlockHeader !~ /^BRBLOCK[0-9]+$/)\n"
"{\n"
"confess &log(ERROR, \"invalid block header '${strBlockHeader}'\", ERROR_FILE_READ);\n"
"}\n"
"\n\n"
"$lBlockSize = substr($strBlockHeader, 7);\n"
"\n\n"
"if ($lBlockSize > 0)\n"
"{\n"
"$self->{oProtocol}->io()->read($rtBuffer, $lBlockSize, true);\n"
"}\n"
"else\n"
"{\n"
"$self->eofSet(true);\n"
"}\n"
"\n\n"
"return $lBlockSize;\n"
"}\n"
"\n\n\n\n"
"sub write\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"\n\n"
"$self->{bWrite} = true;\n"
"\n\n"
"my $lBlockSize = defined($rtBuffer) ? length($$rtBuffer) : 0;\n"
"\n\n"
"if ($lBlockSize > 0)\n"
"{\n"
"\n"
"$self->{oProtocol}->io()->writeLine(\"BRBLOCK${lBlockSize}\");\n"
"\n\n"
"$self->{oProtocol}->io()->write($rtBuffer);\n"
"}\n"
"\n"
"return length($$rtBuffer);\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"if (defined($self->{oProtocol}))\n"
"{\n"
"\n"
"if ($self->{bWrite})\n"
"{\n"
"$self->{oProtocol}->io()->writeLine(\"BRBLOCK0\");\n"
"}\n"
"\n\n"
"if ($self->{oProtocol}->master())\n"
"{\n"
"($self->{rhResult}) = $self->{oProtocol}->outputRead();\n"
"\n\n"
"$self->{oProtocol}->outputRead();\n"
"}\n"
"\n"
"else\n"
"{\n"
"$self->{oProtocol}->outputWrite($self->{oFileIo}->resultAll());\n"
"}\n"
"\n\n"
"delete($self->{oProtocol});\n"
"}\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Storage/Helper.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Storage::Helper;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(basename);\n"
"\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Remote;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Helper;\n"
"use pgBackRest::Storage::Local;\n"
"\n\n\n\n"
"use constant STORAGE_DB => '<DB>';\n"
"push @EXPORT, qw(STORAGE_DB);\n"
"\n"
"use constant STORAGE_REPO => '<REPO>';\n"
"push @EXPORT, qw(STORAGE_REPO);\n"
"use constant STORAGE_REPO_ARCHIVE => '<REPO:ARCHIVE>';\n"
"push @EXPORT, qw(STORAGE_REPO_ARCHIVE);\n"
"use constant STORAGE_REPO_BACKUP => '<REPO:BACKUP>';\n"
"push @EXPORT, qw(STORAGE_REPO_BACKUP);\n"
"\n\n\n\n"
"my $hStorage;\n"
"\n\n\n\n"
"sub storageDb\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iRemoteIdx,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::storageDb', \\@_,\n"
"{name => 'iRemoteIdx', optional => true, default => cfgOptionValid(CFGOPT_HOST_ID) ? cfgOption(CFGOPT_HOST_ID) : 1,\n"
"trace => true},\n"
");\n"
"\n\n"
"if (!defined($hStorage->{&STORAGE_DB}{$iRemoteIdx}))\n"
"{\n"
"if (isDbLocal({iRemoteIdx => $iRemoteIdx}))\n"
"{\n"
"$hStorage->{&STORAGE_DB}{$iRemoteIdx} = new pgBackRest::Storage::Local(\n"
"cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)), new pgBackRest::Storage::Posix::Driver(),\n"
"{strTempExtension => STORAGE_TEMP_EXT, lBufferMax => cfgOption(CFGOPT_BUFFER_SIZE)});\n"
"}\n"
"else\n"
"{\n"
"$hStorage->{&STORAGE_DB}{$iRemoteIdx} = new pgBackRest::Protocol::Storage::Remote(\n"
"protocolGet(CFGOPTVAL_REMOTE_TYPE_DB, $iRemoteIdx));\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oStorageDb', value => $hStorage->{&STORAGE_DB}{$iRemoteIdx}, trace => true},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(storageDb);\n"
"\n\n\n\n"
"sub storageRepoRule\n"
"{\n"
"my $strRule = shift;\n"
"my $strFile = shift;\n"
"my $strStanza = shift;\n"
"\n\n"
"my $strResultFile;\n"
"\n\n"
"if ($strRule eq STORAGE_REPO_ARCHIVE)\n"
"{\n"
"$strResultFile = \"archive\" . (defined($strStanza) ? \"/${strStanza}\" : '');\n"
"\n\n"
"if (defined($strFile))\n"
"{\n"
"my ($strArchiveId, $strWalFile) = split('/', $strFile);\n"
"\n\n"
"if (defined($strWalFile) && $strWalFile =~ /^[0-F]{24}/)\n"
"{\n"
"$strResultFile .= \"/${strArchiveId}/\" . substr($strWalFile, 0, 16) . \"/${strWalFile}\";\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strResultFile .= \"/${strFile}\";\n"
"}\n"
"}\n"
"}\n"
"\n"
"elsif ($strRule eq STORAGE_REPO_BACKUP)\n"
"{\n"
"$strResultFile = \"backup\" . (defined($strStanza) ? \"/${strStanza}\" : '') . (defined($strFile) ? \"/${strFile}\" : '');\n"
"}\n"
"\n"
"else\n"
"{\n"
"confess &log(ASSERT, \"invalid \" . STORAGE_REPO . \" storage rule ${strRule}\");\n"
"}\n"
"\n"
"return $strResultFile;\n"
"}\n"
"\n\n\n\n"
"sub storageRepo\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strStanza,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::storageRepo', \\@_,\n"
"{name => 'strStanza', optional => true, trace => true},\n"
");\n"
"\n"
"if (!defined($strStanza))\n"
"{\n"
"if (cfgOptionValid(CFGOPT_STANZA) && cfgOptionTest(CFGOPT_STANZA))\n"
"{\n"
"$strStanza = cfgOption(CFGOPT_STANZA);\n"
"}\n"
"else\n"
"{\n"
"$strStanza = STORAGE_REPO;\n"
"}\n"
"}\n"
"\n\n"
"if (!defined($hStorage->{&STORAGE_REPO}{$strStanza}))\n"
"{\n"
"if (isRepoLocal())\n"
"{\n"
"\n"
"my $hRule =\n"
"{\n"
"&STORAGE_REPO_ARCHIVE =>\n"
"{\n"
"fnRule => \\&storageRepoRule,\n"
"xData => $strStanza eq STORAGE_REPO ? undef : $strStanza,\n"
"},\n"
"&STORAGE_REPO_BACKUP =>\n"
"{\n"
"fnRule => \\&storageRepoRule,\n"
"xData => $strStanza eq STORAGE_REPO ? undef : $strStanza,\n"
"},\n"
"};\n"
"\n\n"
"my $oDriver;\n"
"\n"
"if (cfgOptionTest(CFGOPT_REPO_TYPE, CFGOPTVAL_REPO_TYPE_S3))\n"
"{\n"
"require pgBackRest::Storage::S3::Driver;\n"
"\n"
"$oDriver = new pgBackRest::Storage::S3::Driver(\n"
"cfgOption(CFGOPT_REPO_S3_BUCKET), cfgOption(CFGOPT_REPO_S3_ENDPOINT), cfgOption(CFGOPT_REPO_S3_REGION),\n"
"cfgOption(CFGOPT_REPO_S3_KEY), cfgOption(CFGOPT_REPO_S3_KEY_SECRET),\n"
"{strHost => cfgOption(CFGOPT_REPO_S3_HOST, false), bVerifySsl => cfgOption(CFGOPT_REPO_S3_VERIFY_TLS, false),\n"
"strCaPath => cfgOption(CFGOPT_REPO_S3_CA_PATH, false),\n"
"strCaFile => cfgOption(CFGOPT_REPO_S3_CA_FILE, false), lBufferMax => cfgOption(CFGOPT_BUFFER_SIZE),\n"
"strSecurityToken => cfgOption(CFGOPT_REPO_S3_TOKEN, false)});\n"
"}\n"
"elsif (cfgOptionTest(CFGOPT_REPO_TYPE, CFGOPTVAL_REPO_TYPE_CIFS))\n"
"{\n"
"require pgBackRest::Storage::Cifs::Driver;\n"
"\n"
"$oDriver = new pgBackRest::Storage::Cifs::Driver();\n"
"}\n"
"else\n"
"{\n"
"$oDriver = new pgBackRest::Storage::Posix::Driver();\n"
"}\n"
"\n\n"
"my $strCipherType;\n"
"my $strCipherPass;\n"
"\n\n"
"if (cfgOption(CFGOPT_REPO_CIPHER_TYPE) ne CFGOPTVAL_REPO_CIPHER_TYPE_NONE)\n"
"{\n"
"$strCipherType = cfgOption(CFGOPT_REPO_CIPHER_TYPE);\n"
"$strCipherPass = cfgOption(CFGOPT_REPO_CIPHER_PASS);\n"
"}\n"
"\n\n"
"$hStorage->{&STORAGE_REPO}{$strStanza} = new pgBackRest::Storage::Local(\n"
"cfgOption(CFGOPT_REPO_PATH), $oDriver,\n"
"{strTempExtension => STORAGE_TEMP_EXT, hRule => $hRule, lBufferMax => cfgOption(CFGOPT_BUFFER_SIZE),\n"
"strCipherType => $strCipherType, strCipherPassUser => $strCipherPass});\n"
"}\n"
"else\n"
"{\n"
"\n"
"$hStorage->{&STORAGE_REPO}{$strStanza} = new pgBackRest::Protocol::Storage::Remote(\n"
"protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP));\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oStorageRepo', value => $hStorage->{&STORAGE_REPO}{$strStanza}, trace => true},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(storageRepo);\n"
"\n\n\n\n"
"sub storageRepoCacheClear\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strStanza,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::storageRepoCacheClear', \\@_,\n"
"{name => 'strStanza'},\n"
");\n"
"\n"
"if (defined($hStorage->{&STORAGE_REPO}{$strStanza}))\n"
"{\n"
"delete($hStorage->{&STORAGE_REPO}{$strStanza});\n"
"}\n"
"\n"
"return;\n"
"}\n"
"\n"
"push @EXPORT, qw(storageRepoCacheClear);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Protocol/Storage/Remote.pm",
.data =
"\n\n\n"
"package pgBackRest::Protocol::Storage::Remote;\n"
"use parent 'pgBackRest::Storage::Base';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::File;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Filter::Gzip;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oProtocol,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oProtocol'},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new({lBufferMax => $oProtocol->io()->bufferMax()});\n"
"bless $self, $class;\n"
"\n\n"
"$self->{oProtocol} = $oProtocol;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub exists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->exists', \\@_,\n"
"{name => 'strPathExp'},\n"
");\n"
"\n"
"my $bExists = $self->{oProtocol}->cmdExecute(OP_STORAGE_EXISTS, [$strPathExp]);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bExists', value => $bExists}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub hashSize\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
"$rhParam,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->hashSize', \\@_,\n"
"{name => 'strPathExp'},\n"
"{name => 'rhParam', required => false},\n"
");\n"
"\n"
"my ($strHash, $lSize) = $self->{oProtocol}->cmdExecute(OP_STORAGE_HASH_SIZE, [$strPathExp, $rhParam]);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strHash', value => $strHash},\n"
"{name => 'lSize', value => $lSize}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub list\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
"$rhParam,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->list', \\@_,\n"
"{name => 'strPathExp'},\n"
"{name => 'rhParam', required => false},\n"
");\n"
"\n"
"my @stryFileList = $self->{oProtocol}->cmdExecute(OP_STORAGE_LIST, [$strPathExp, $rhParam]);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryFileList', value => \\@stryFileList}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub manifest\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
"$rhParam,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->manifest', \\@_,\n"
"{name => 'strPathExp'},\n"
"{name => 'rhParam', required => false},\n"
");\n"
"\n"
"my $hManifest = $self->{oProtocol}->cmdExecute(OP_STORAGE_MANIFEST, [$strPathExp, $rhParam]);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hManifest', value => $hManifest, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub openRead\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFileExp,\n"
"$rhParam,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->openRead', \\@_,\n"
"{name => 'strFileExp'},\n"
"{name => 'rhParam', required => false},\n"
");\n"
"\n\n"
"my $bProtocolCompress = protocolCompress($rhParam);\n"
"\n\n"
"if ($bProtocolCompress)\n"
"{\n"
"push(\n"
"@{$rhParam->{rhyFilter}},\n"
"{strClass => STORAGE_FILTER_GZIP,\n"
"rxyParam => [{iLevel => cfgOption(CFGOPT_COMPRESS_LEVEL_NETWORK), bWantGzip => false}]});\n"
"}\n"
"\n"
"my $oSourceFileIo =\n"
"$self->{oProtocol}->cmdExecute(OP_STORAGE_OPEN_READ, [$strFileExp, $rhParam]) ?\n"
"new pgBackRest::Protocol::Storage::File($self->{oProtocol}) : undef;\n"
"\n\n"
"if ($bProtocolCompress)\n"
"{\n"
"$oSourceFileIo = new pgBackRest::Storage::Filter::Gzip(\n"
"$oSourceFileIo, {strCompressType => STORAGE_DECOMPRESS, bWantGzip => false});\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oFileIo', value => $oSourceFileIo, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub openWrite\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFileExp,\n"
"$rhParam,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->openWrite', \\@_,\n"
"{name => 'strFileExp'},\n"
"{name => 'rhParam', required => false},\n"
");\n"
"\n\n"
"my $bProtocolCompress = protocolCompress($rhParam);\n"
"\n\n"
"if ($bProtocolCompress)\n"
"{\n"
"push(\n"
"@{$rhParam->{rhyFilter}},\n"
"{strClass => STORAGE_FILTER_GZIP, rxyParam => [{strCompressType => STORAGE_DECOMPRESS, bWantGzip => false}]});\n"
"}\n"
"\n\n"
"$self->{oProtocol}->cmdWrite(OP_STORAGE_OPEN_WRITE, [$strFileExp, $rhParam]);\n"
"my $oDestinationFileIo = new pgBackRest::Protocol::Storage::File($self->{oProtocol});\n"
"\n\n"
"if ($bProtocolCompress)\n"
"{\n"
"$oDestinationFileIo = new pgBackRest::Storage::Filter::Gzip(\n"
"$oDestinationFileIo, {iLevel => cfgOption(CFGOPT_COMPRESS_LEVEL_NETWORK), bWantGzip => false});\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oFileIo', value => $oDestinationFileIo, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
"$rhParam,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathGet', \\@_,\n"
"{name => 'strPathExp', required => false},\n"
"{name => 'rhParam', required => false},\n"
");\n"
"\n"
"my $strPath = $self->{oProtocol}->cmdExecute(OP_STORAGE_PATH_GET, [$strPathExp, $rhParam]);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strPath', value => $strPath}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub move\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strSourcePathExp,\n"
"$strDestinationPathExp,\n"
"$rhParam,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->move', \\@_,\n"
"{name => 'strSourcePathExp'},\n"
"{name => 'strDestinationPathExp'},\n"
"{name => 'rhParam', required => false},\n"
");\n"
"\n"
"$self->{oProtocol}->cmdExecute(OP_STORAGE_MOVE, [$strSourcePathExp, $strDestinationPathExp, $rhParam], false);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation\n"
");\n"
"}\n"
"\n\n\n\n"
"sub cipherPassUser\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->cipherPassUser', \\@_,\n"
");\n"
"\n"
"my $strCipherPassUser = $self->{oProtocol}->cmdExecute(OP_STORAGE_CIPHER_PASS_USER);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strCipherPassUser', value => $strCipherPassUser, redact => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub protocolCompress\n"
"{\n"
"my $rhParam = shift;\n"
"\n"
"my $bProtocolCompress = false;\n"
"\n"
"if (defined($rhParam->{bProtocolCompress}))\n"
"{\n"
"$bProtocolCompress = $rhParam->{bProtocolCompress} && cfgOption(CFGOPT_COMPRESS_LEVEL_NETWORK) > 0 ? true : false;\n"
"delete($rhParam->{bProtocolCompress});\n"
"}\n"
"\n"
"return $bProtocolCompress;\n"
"}\n"
"\n\n\n\n"
"sub protocol {shift->{oProtocol}};\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Restore.pm",
.data =
"\n\n\n"
"package pgBackRest::Restore;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Cwd qw(abs_path);\n"
"use File::Basename qw(basename dirname);\n"
"use File::stat qw(lstat);\n"
"\n"
"use pgBackRest::Backup::Info;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::RestoreFile;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Local::Process;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Helper;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');\n"
"\n\n"
"$self->{oProtocol} = !isRepoLocal() ? protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP) : undef;\n"
"\n\n"
"$self->{strDbClusterPath} = cfgOption(CFGOPT_PG_PATH);\n"
"$self->{strBackupSet} = cfgOption(CFGOPT_SET);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub manifestOwnershipCheck\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oManifest\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->manifestOwnershipCheck', \\@_,\n"
"{name => 'oManifest'}\n"
");\n"
"\n\n"
"my %oOwnerHash = ();\n"
"\n\n"
"my %oFileTypeHash =\n"
"(\n"
"&MANIFEST_SECTION_TARGET_PATH => true,\n"
"&MANIFEST_SECTION_TARGET_LINK => true,\n"
"&MANIFEST_SECTION_TARGET_FILE => true\n"
");\n"
"\n\n\n\n"
"my %oOwnerTypeHash;\n"
"\n"
"if ($oManifest->test(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_USER) &&\n"
"!$oManifest->boolTest(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_USER, false))\n"
"{\n"
"$oOwnerTypeHash{&MANIFEST_SUBKEY_USER} =\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_USER);\n"
"}\n"
"else\n"
"{\n"
"$oOwnerTypeHash{&MANIFEST_SUBKEY_USER} = getpwuid($<);\n"
"\n"
"if (!defined($oOwnerTypeHash{&MANIFEST_SUBKEY_USER}))\n"
"{\n"
"confess &log(ERROR_USER_MISSING, 'current user uid does not map to a name');\n"
"}\n"
"}\n"
"\n"
"if ($oManifest->test(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_GROUP) &&\n"
"!$oManifest->boolTest(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_GROUP, false))\n"
"{\n"
"$oOwnerTypeHash{&MANIFEST_SUBKEY_GROUP} =\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_PATH, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_GROUP);\n"
"}\n"
"else\n"
"{\n"
"$oOwnerTypeHash{&MANIFEST_SUBKEY_GROUP} = getgrgid($();\n"
"\n"
"if (!defined($oOwnerTypeHash{&MANIFEST_SUBKEY_GROUP}))\n"
"{\n"
"confess &log(ERROR_GROUP_MISSING, 'current user gid does not map to a name');\n"
"}\n"
"}\n"
"\n\n"
"foreach my $strOwnerType (sort (keys %oOwnerTypeHash))\n"
"{\n"
"\n"
"foreach my $strSection (sort (keys %oFileTypeHash))\n"
"{\n"
"foreach my $strName ($oManifest->keys($strSection))\n"
"{\n"
"my $strOwner = $oManifest->get($strSection, $strName, $strOwnerType);\n"
"\n\n"
"if ($oManifest->boolTest($strSection, $strName, $strOwnerType, false))\n"
"{\n"
"$strOwner = $oOwnerTypeHash{$strOwnerType};\n"
"\n"
"&log(WARN, \"backup ${strOwnerType} for ${strName} was not mapped to a name, set to ${strOwner}\");\n"
"$oManifest->set($strSection, $strName, $strOwnerType, $strOwner);\n"
"}\n"
"\n\n"
"if ($< == 0)\n"
"{\n"
"\n"
"if (!defined($oOwnerHash{$strOwnerType}{$strOwner}))\n"
"{\n"
"my $strOwnerId;\n"
"\n"
"if ($strOwnerType eq 'user')\n"
"{\n"
"$strOwnerId = getpwnam($strOwner);\n"
"}\n"
"else\n"
"{\n"
"$strOwnerId = getgrnam($strOwner);\n"
"}\n"
"\n"
"$oOwnerHash{$strOwnerType}{$strOwner} = defined($strOwnerId) ? true : false;\n"
"}\n"
"\n"
"if (!$oOwnerHash{$strOwnerType}{$strOwner})\n"
"{\n"
"$oManifest->set($strSection, $strName, $strOwnerType, $oOwnerTypeHash{$strOwnerType});\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"if ($strOwner ne $oOwnerTypeHash{$strOwnerType})\n"
"{\n"
"$oOwnerHash{$strOwnerType}{$strOwner} = false;\n"
"$oManifest->set($strSection, $strName, $strOwnerType, $oOwnerTypeHash{$strOwnerType});\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (defined($oOwnerHash{$strOwnerType}))\n"
"{\n"
"foreach my $strOwner (sort (keys(%{$oOwnerHash{$strOwnerType}})))\n"
"{\n"
"if (!$oOwnerHash{$strOwnerType}{$strOwner})\n"
"{\n"
"&log(WARN, \"${strOwnerType} ${strOwner} in manifest \" . ($< == 0 ? 'does not exist locally ' : '') .\n"
"\"cannot be used for restore, set to $oOwnerTypeHash{$strOwnerType}\");\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub manifestLoad\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strCipherPass,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->manifestLoad', \\@_,\n"
"{name => 'strCipherPass', required => false, redact => true},\n"
");\n"
"\n\n"
"if (!storageRepo()->exists(STORAGE_REPO_BACKUP . \"/$self->{strBackupSet}/\" . FILE_MANIFEST))\n"
"{\n"
"confess &log(ERROR, \"backup '$self->{strBackupSet}' does not exist\");\n"
"}\n"
"\n\n"
"storageDb()->copy(\n"
"storageRepo()->openRead(STORAGE_REPO_BACKUP . \"/$self->{strBackupSet}/\" . FILE_MANIFEST, {bProtocolCompress => true,\n"
"strCipherPass => $strCipherPass}),\n"
"$self->{strDbClusterPath} . '/' . FILE_MANIFEST);\n"
"\n\n"
"my $oManifest = new pgBackRest::Manifest(\n"
"storageDb()->pathGet($self->{strDbClusterPath} . '/' . FILE_MANIFEST), {oStorage => storageDb()});\n"
"\n\n"
"my $strBackupLabel = $oManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL);\n"
"\n"
"if ($self->{strBackupSet} eq cfgOptionDefault(CFGOPT_SET))\n"
"{\n"
"$self->{strBackupSet} = $strBackupLabel;\n"
"}\n"
"elsif ($self->{strBackupSet} ne $strBackupLabel)\n"
"{\n"
"confess &log(ASSERT, \"request backup $self->{strBackupSet} and label ${strBackupLabel} do not match \" .\n"
"' - this indicates some sort of corruption (at the very least paths have been renamed)');\n"
"}\n"
"\n"
"if ($self->{strDbClusterPath} ne $oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH))\n"
"{\n"
"&log(INFO, 'remap $PGDATA directory to ' . $self->{strDbClusterPath});\n"
"\n"
"$oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH, $self->{strDbClusterPath});\n"
"}\n"
"\n\n"
"my $oTablespaceRemap;\n"
"\n"
"if (cfgOptionTest(CFGOPT_TABLESPACE_MAP))\n"
"{\n"
"my $oTablespaceRemapRequest = cfgOption(CFGOPT_TABLESPACE_MAP);\n"
"\n"
"for my $strKey (sort(keys(%{$oTablespaceRemapRequest})))\n"
"{\n"
"my $bFound = false;\n"
"\n"
"for my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"if ($oManifest->test(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_TABLESPACE_ID, $strKey) ||\n"
"$oManifest->test(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_TABLESPACE_NAME, $strKey))\n"
"{\n"
"if (defined(${$oTablespaceRemap}{$strTarget}))\n"
"{\n"
"confess &log(ERROR, \"tablespace ${strKey} has already been remapped to ${$oTablespaceRemap}{$strTarget}\",\n"
"ERROR_TABLESPACE_MAP);\n"
"}\n"
"\n"
"${$oTablespaceRemap}{$strTarget} = ${$oTablespaceRemapRequest}{$strKey};\n"
"$bFound = true;\n"
"}\n"
"}\n"
"\n\n"
"if (!$bFound)\n"
"{\n"
"confess &log(ERROR, \"cannot remap invalid tablespace ${strKey} to ${$oTablespaceRemapRequest}{$strKey}\",\n"
"ERROR_TABLESPACE_MAP);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (cfgOptionTest(CFGOPT_TABLESPACE_MAP_ALL))\n"
"{\n"
"for my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"if ($oManifest->isTargetTablespace($strTarget))\n"
"{\n"
"if (!defined(${$oTablespaceRemap}{$strTarget}))\n"
"{\n"
"${$oTablespaceRemap}{$strTarget} = cfgOption(CFGOPT_TABLESPACE_MAP_ALL) . '/' .\n"
"$oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_TABLESPACE_NAME);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if ($oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION) < PG_VERSION_92 &&\n"
"(cfgOptionTest(CFGOPT_TABLESPACE_MAP) || cfgOptionTest(CFGOPT_TABLESPACE_MAP_ALL)))\n"
"{\n"
"&log(WARN, \"update pg_tablespace.spclocation with new tablespace location in PostgreSQL < \" . PG_VERSION_92);\n"
"}\n"
"\n\n"
"if (defined($oTablespaceRemap))\n"
"{\n"
"foreach my $strTarget (sort(keys(%{$oTablespaceRemap})))\n"
"{\n"
"my $strRemapPath = ${$oTablespaceRemap}{$strTarget};\n"
"\n\n"
"&log(INFO, \"remap tablespace ${strTarget} directory to ${strRemapPath}\");\n"
"\n"
"$oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_PATH, $strRemapPath);\n"
"$oManifest->set(MANIFEST_SECTION_TARGET_LINK, MANIFEST_TARGET_PGDATA . \"/${strTarget}\", MANIFEST_SUBKEY_DESTINATION,\n"
"$strRemapPath);\n"
"}\n"
"}\n"
"\n"
"$self->manifestOwnershipCheck($oManifest);\n"
"\n\n"
"my $oLinkRemap;\n"
"\n"
"if (cfgOptionTest(CFGOPT_LINK_MAP))\n"
"{\n"
"my $oLinkRemapRequest = cfgOption(CFGOPT_LINK_MAP);\n"
"\n"
"for my $strKey (sort(keys(%{$oLinkRemapRequest})))\n"
"{\n"
"my $strTarget = MANIFEST_TARGET_PGDATA . \"/${strKey}\";\n"
"\n\n"
"if ($oManifest->isTargetValid($strTarget, false) &&\n"
"$oManifest->isTargetLink($strTarget) && !$oManifest->isTargetTablespace($strTarget))\n"
"{\n"
"if (defined(${$oTablespaceRemap}{$strTarget}))\n"
"{\n"
"confess &log(ERROR, \"tablespace ${strKey} has already been remapped to ${$oLinkRemap}{$strTarget}\",\n"
"ERROR_LINK_MAP);\n"
"}\n"
"\n"
"${$oLinkRemap}{$strTarget} = ${$oLinkRemapRequest}{$strKey};\n"
"\n"
"&log(INFO, \"remap link ${strTarget} destination to ${$oLinkRemap}{$strTarget}\");\n"
"}\n"
"\n"
"else\n"
"{\n"
"confess &log(ERROR, \"cannot remap invalid link ${strKey} to ${$oLinkRemapRequest}{$strKey}\",\n"
"ERROR_LINK_MAP);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (cfgOption(CFGOPT_LINK_ALL))\n"
"{\n"
"for my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"\n"
"if ($oManifest->isTargetLink($strTarget) && !$oManifest->isTargetTablespace($strTarget) &&\n"
"!defined(${$oLinkRemap}{$strTarget}))\n"
"{\n"
"${$oLinkRemap}{$strTarget} =\n"
"$oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_PATH);\n"
"\n"
"if ($oManifest->isTargetFile($strTarget))\n"
"{\n"
"${$oLinkRemap}{$strTarget} .= '/' .\n"
"$oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_FILE);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"for my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"if ($oManifest->isTargetLink($strTarget) && !$oManifest->isTargetTablespace($strTarget))\n"
"{\n"
"\n"
"if (defined(${$oLinkRemap}{$strTarget}))\n"
"{\n"
"my $strTargetPath = ${$oLinkRemap}{$strTarget};\n"
"\n\n"
"if ($oManifest->isTargetFile($strTarget))\n"
"{\n"
"$strTargetPath = dirname($strTargetPath);\n"
"\n\n"
"if (!defined($strTargetPath))\n"
"{\n"
"confess &log(ERROR, \"${$oLinkRemap}{$strTarget} is not long enough to be target for ${strTarget}\");\n"
"}\n"
"\n\n"
"$oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_FILE,\n"
"substr(${$oLinkRemap}{$strTarget}, length($strTargetPath) + 1));\n"
"\n\n"
"$oManifest->set(\n"
"MANIFEST_SECTION_TARGET_LINK, $strTarget, MANIFEST_SUBKEY_DESTINATION, ${$oLinkRemap}{$strTarget});\n"
"}\n"
"else\n"
"{\n"
"\n"
"$oManifest->set(MANIFEST_SECTION_TARGET_LINK, $strTarget, MANIFEST_SUBKEY_DESTINATION, $strTargetPath);\n"
"\n\n"
"$oManifest->remove(MANIFEST_SECTION_TARGET_PATH, $strTarget);\n"
"}\n"
"\n\n"
"$oManifest->set(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_PATH, $strTargetPath);\n"
"}\n"
"\n"
"else\n"
"{\n"
"if ($oManifest->test(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_FILE))\n"
"{\n"
"&log(WARN, 'file link ' . $oManifest->dbPathGet(undef, $strTarget) .\n"
"' will be restored as a file at the same location');\n"
"}\n"
"else\n"
"{\n"
"&log(WARN, 'contents of directory link ' . $oManifest->dbPathGet(undef, $strTarget) .\n"
"' will be restored in a directory at the same location');\n"
"}\n"
"\n"
"$oManifest->remove(MANIFEST_SECTION_BACKUP_TARGET, $strTarget);\n"
"$oManifest->remove(MANIFEST_SECTION_TARGET_LINK, $strTarget);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"$oManifest->linkCheck();\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oManifest', value => $oManifest, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub clean\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oManifest\n"
"\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->clean', \\@_,\n"
"{name => 'oManifest'}\n"
");\n"
"\n\n"
"my $oStorageDb = storageDb();\n"
"\n\n"
"my %oRemoveHash =\n"
"(\n"
"&MANIFEST_SECTION_TARGET_FILE => 0,\n"
"&MANIFEST_SECTION_TARGET_PATH => 0,\n"
"&MANIFEST_SECTION_TARGET_LINK => 0\n"
");\n"
"\n\n"
"my %oTargetFound;\n"
"my $bDelta = cfgOption(CFGOPT_FORCE) || cfgOption(CFGOPT_DELTA);\n"
"\n"
"for my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"${$self->{oTargetPath}}{$strTarget} = $oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_PATH);\n"
"$oTargetFound{$strTarget} = false;\n"
"\n"
"my $strCheckPath = ${$self->{oTargetPath}}{$strTarget};\n"
"\n"
"if ($oManifest->isTargetLink($strTarget) && index($strCheckPath, '/') != 0)\n"
"{\n"
"my $strBasePath = $oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH);\n"
"my $strTargetPath = dirname($oManifest->dbPathGet(undef, $strTarget));\n"
"\n"
"if ($strTargetPath ne '.')\n"
"{\n"
"$strBasePath .= \"/${strTargetPath}\";\n"
"}\n"
"\n"
"${$self->{oTargetPath}}{$strTarget} = $oStorageDb->pathAbsolute($strBasePath, $strCheckPath);\n"
"\n"
"$strCheckPath = ${$self->{oTargetPath}}{$strTarget};\n"
"\n"
"if ($oManifest->isTargetTablespace($strTarget))\n"
"{\n"
"$strCheckPath = dirname(${$self->{oTargetPath}}{$strTarget});\n"
"}\n"
"}\n"
"\n"
"&log(DETAIL, \"check ${strCheckPath} exists\");\n"
"\n\n"
"if (!$oStorageDb->pathExists($strCheckPath))\n"
"{\n"
"confess &log(ERROR, \"cannot restore to missing path ${strCheckPath}\", ERROR_PATH_MISSING);\n"
"}\n"
"\n\n"
"if ($oManifest->isTargetFile($strTarget))\n"
"{\n"
"\n"
"my $strCheckFile = \"${strCheckPath}/\" .\n"
"$oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_SUBKEY_FILE);\n"
"\n\n"
"if ($oStorageDb->exists($strCheckFile))\n"
"{\n"
"\n"
"if (!$bDelta)\n"
"{\n"
"confess &log(ERROR, \"cannot restore file '${strCheckFile}' that already exists - \" .\n"
"'try using --delta if this is what you intended', ERROR_PATH_NOT_EMPTY);\n"
"}\n"
"\n\n"
"$oTargetFound{$strTarget} = true;\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if ($oManifest->isTargetTablespace($strTarget))\n"
"{\n"
"\n"
"${$self->{oTargetPath}}{$strTarget} = \"${$self->{oTargetPath}}{$strTarget}\" .\n"
"(($oManifest->dbVersion() >= PG_VERSION_90) ? \"/\" . $oManifest->tablespacePathGet() : \"\");\n"
"\n\n"
"if (!$oStorageDb->pathExists(${$self->{oTargetPath}}{$strTarget}))\n"
"{\n"
"next;\n"
"}\n"
"}\n"
"\n\n"
"my $hTargetManifest = $oStorageDb->manifest(${$self->{oTargetPath}}{$strTarget});\n"
"\n"
"for my $strName (keys(%{$hTargetManifest}))\n"
"{\n"
"\n"
"if ($strName eq '.' ||\n"
"(($strName eq FILE_MANIFEST || $strName eq DB_FILE_RECOVERYCONF) && $strTarget eq MANIFEST_TARGET_PGDATA))\n"
"{\n"
"next;\n"
"}\n"
"\n\n"
"if (!$bDelta)\n"
"{\n"
"confess &log(ERROR, \"cannot restore to path '${$self->{oTargetPath}}{$strTarget}' that contains files - \" .\n"
"'try using --delta if this is what you intended', ERROR_PATH_NOT_EMPTY);\n"
"}\n"
"\n\n"
"$oTargetFound{$strTarget} = true;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"my %oFileChecked;\n"
"\n"
"for my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET, INI_SORT_REVERSE))\n"
"{\n"
"if ($oTargetFound{$strTarget})\n"
"{\n"
"&log(INFO, \"remove invalid files/paths/links from ${$self->{oTargetPath}}{$strTarget}\");\n"
"\n\n"
"if (!$oStorageDb->pathExists(${$self->{oTargetPath}}{$strTarget}) &&\n"
"$oManifest->isTargetTablespace($strTarget))\n"
"{\n"
"next;\n"
"}\n"
"\n\n"
"my $hTargetManifest = $oStorageDb->manifest(${$self->{oTargetPath}}{$strTarget});\n"
"\n\n"
"if ($oManifest->isTargetFile($strTarget))\n"
"{\n"
"next;\n"
"}\n"
"\n"
"foreach my $strName (sort {$b cmp $a} (keys(%{$hTargetManifest})))\n"
"{\n"
"\n"
"if ($strName eq '.' || ($strName eq FILE_MANIFEST && $strTarget eq MANIFEST_TARGET_PGDATA))\n"
"{\n"
"next;\n"
"}\n"
"\n"
"my $strOsFile = \"${$self->{oTargetPath}}{$strTarget}/${strName}\";\n"
"my $strManifestFile = $oManifest->repoPathGet($strTarget, $strName);\n"
"\n\n"
"my $strSection = MANIFEST_SECTION_TARGET_FILE;\n"
"\n"
"if ($hTargetManifest->{$strName}{type} eq 'd')\n"
"{\n"
"$strSection = MANIFEST_SECTION_TARGET_PATH;\n"
"}\n"
"elsif ($hTargetManifest->{$strName}{type} eq 'l')\n"
"{\n"
"$strSection = MANIFEST_SECTION_TARGET_LINK;\n"
"}\n"
"\n\n"
"if ($oManifest->test($strSection, $strManifestFile) &&\n"
"!defined($oFileChecked{$strSection}{$strManifestFile}))\n"
"{\n"
"my $strUser = $oManifest->get($strSection, $strManifestFile, MANIFEST_SUBKEY_USER);\n"
"my $strGroup = $oManifest->get($strSection, $strManifestFile, MANIFEST_SUBKEY_GROUP);\n"
"\n\n"
"if (!defined($hTargetManifest->{$strName}{user}) ||\n"
"$strUser ne $hTargetManifest->{$strName}{user} ||\n"
"!defined($hTargetManifest->{$strName}{group}) ||\n"
"$strGroup ne $hTargetManifest->{$strName}{group})\n"
"{\n"
"&log(DETAIL, \"set ownership ${strUser}:${strGroup} on ${strOsFile}\");\n"
"\n"
"$oStorageDb->owner($strOsFile, $strUser, $strGroup);\n"
"}\n"
"\n\n"
"if ($strSection eq MANIFEST_SECTION_TARGET_LINK)\n"
"{\n"
"if ($oManifest->get($strSection, $strManifestFile, MANIFEST_SUBKEY_DESTINATION) ne\n"
"$hTargetManifest->{$strName}{link_destination})\n"
"{\n"
"&log(DETAIL, \"remove link ${strOsFile} - destination changed\");\n"
"$oStorageDb->remove($strOsFile);\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"my $strMode = $oManifest->get($strSection, $strManifestFile, MANIFEST_SUBKEY_MODE);\n"
"\n"
"if ($strMode ne $hTargetManifest->{$strName}{mode})\n"
"{\n"
"&log(DETAIL, \"set mode ${strMode} on ${strOsFile}\");\n"
"\n"
"chmod(oct($strMode), $strOsFile)\n"
"or confess 'unable to set mode ${strMode} on ${strOsFile}';\n"
"}\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if ($strSection eq MANIFEST_SECTION_TARGET_PATH)\n"
"{\n"
"&log(DETAIL, \"remove path ${strOsFile}\");\n"
"rmdir($strOsFile) or confess &log(ERROR, \"unable to delete path ${strOsFile}, is it empty?\");\n"
"\n"
"$oRemoveHash{$strSection} += 1;\n"
"}\n"
"\n"
"else\n"
"{\n"
"my $strType = (split('\\:', $strSection))[1];\n"
"\n\n\n"
"if ($oManifest->dbPathGet(undef, $strManifestFile) eq DB_FILE_RECOVERYCONF)\n"
"{\n"
"&log(DETAIL, \"preserve ${strType} ${strOsFile}\");\n"
"}\n"
"else\n"
"{\n"
"&log(DETAIL, \"remove ${strType} ${strOsFile}\");\n"
"$oStorageDb->remove($strOsFile);\n"
"\n\n"
"protocolKeepAlive();\n"
"\n"
"$oRemoveHash{$strSection} += 1;\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n\n"
"foreach my $strSection (sort (keys %oRemoveHash))\n"
"{\n"
"for my $strManifestFile ($oManifest->keys($strSection))\n"
"{\n"
"\n\n"
"if ($strSection ne MANIFEST_SECTION_TARGET_LINK || $strManifestFile ne $strTarget)\n"
"{\n"
"\n"
"if (index($strManifestFile, \"${strTarget}/\") == 0)\n"
"{\n"
"\n"
"$oFileChecked{$strSection}{$strManifestFile} = true;\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"my @stryMessage;\n"
"\n"
"foreach my $strFileType (sort (keys %oRemoveHash))\n"
"{\n"
"if ($oRemoveHash{$strFileType} > 0)\n"
"{\n"
"push(@stryMessage, \"$oRemoveHash{$strFileType} \" . (split('\\:', $strFileType))[1] .\n"
"($oRemoveHash{$strFileType} > 1 ? 's' : ''));\n"
"}\n"
"}\n"
"\n"
"if (@stryMessage)\n"
"{\n"
"&log(INFO, 'cleanup removed ' . join(', ', @stryMessage));\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub build\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oManifest\n"
"\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->build', \\@_,\n"
"{name => 'oManifest'}\n"
");\n"
"\n\n"
"my $oStorageDb = storageDb();\n"
"\n\n"
"foreach my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"if ($strTarget ne MANIFEST_TARGET_PGDATA)\n"
"{\n"
"my $strPath = ${$self->{oTargetPath}}{$strTarget};\n"
"\n"
"if ($oManifest->isTargetTablespace($strTarget))\n"
"{\n"
"\n"
"$strPath = dirname($strPath);\n"
"}\n"
"\n\n"
"if (!$oStorageDb->pathExists($strPath))\n"
"{\n"
"$oStorageDb->pathCreate(\n"
"$strPath, {strMode => $oManifest->get(MANIFEST_SECTION_TARGET_PATH, $strTarget, MANIFEST_SUBKEY_MODE)});\n"
"\n\n"
"my $strUser = $oManifest->get(MANIFEST_SECTION_TARGET_PATH, $strTarget, MANIFEST_SUBKEY_USER);\n"
"my $strGroup = $oManifest->get(MANIFEST_SECTION_TARGET_PATH, $strTarget, MANIFEST_SUBKEY_GROUP);\n"
"\n"
"if ($strUser ne getpwuid($<) || $strGroup ne getgrgid($())\n"
"{\n"
"$oStorageDb->owner($strPath, $strUser, $strGroup);\n"
"}\n"
"}\n"
"}\n"
"\n"
"$oManifest->remove(MANIFEST_SECTION_TARGET_PATH, $strTarget);\n"
"}\n"
"\n\n\n"
"my $iLevel = 1;\n"
"my $iFound;\n"
"\n"
"do\n"
"{\n"
"$iFound = 0;\n"
"\n"
"&log(DEBUG, \"build level ${iLevel} paths/links\");\n"
"\n\n"
"foreach my $strSection (&MANIFEST_SECTION_TARGET_PATH, &MANIFEST_SECTION_TARGET_LINK)\n"
"{\n"
"\n"
"foreach my $strName ($oManifest->keys($strSection))\n"
"{\n"
"\n"
"if ($strName eq '.')\n"
"{\n"
"next;\n"
"}\n"
"\n\n"
"my @stryName = split('\\/', $oManifest->dbPathGet(undef, $strName));\n"
"\n\n"
"if (@stryName == $iLevel)\n"
"{\n"
"my $strDbPath = $oManifest->dbPathGet($self->{strDbClusterPath}, $strName);\n"
"\n\n\n"
"if (!$oStorageDb->pathExists($strDbPath) && !$oStorageDb->exists($strDbPath))\n"
"{\n"
"\n"
"if ($strSection eq &MANIFEST_SECTION_TARGET_PATH)\n"
"{\n"
"$oStorageDb->pathCreate(\n"
"$strDbPath, {strMode => $oManifest->get($strSection, $strName, MANIFEST_SUBKEY_MODE)});\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"my $strDestination = $oManifest->get($strSection, $strName, MANIFEST_SUBKEY_DESTINATION);\n"
"\n\n\n\n"
"$oStorageDb->linkCreate(\n"
"$oStorageDb->pathAbsolute(\n"
"dirname($strDbPath), $strDestination), $strDbPath,\n"
"{bRelative => (index($strDestination, '/') != 0, bIgnoreExists => true)});\n"
"}\n"
"\n\n"
"my $strUser = $oManifest->get($strSection, $strName, MANIFEST_SUBKEY_USER);\n"
"my $strGroup = $oManifest->get($strSection, $strName, MANIFEST_SUBKEY_GROUP);\n"
"\n"
"if ($strUser ne getpwuid($<) || $strGroup ne getgrgid($())\n"
"{\n"
"$oStorageDb->owner($strDbPath, $strUser, $strGroup);\n"
"}\n"
"}\n"
"\n\n"
"$iFound++;\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"$iLevel++;\n"
"}\n"
"while ($iFound > 0);\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub recovery\n"
"{\n"
"my $self = shift;\n"
"my $strDbVersion = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam (__PACKAGE__ . '->recovery');\n"
"\n\n"
"my $strRecoveryConf = $self->{strDbClusterPath} . '/' . DB_FILE_RECOVERYCONF;\n"
"\n\n"
"my $bRecoveryConfExists = storageDb()->exists($strRecoveryConf);\n"
"\n\n"
"if (cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_RESTORE_TYPE_PRESERVE))\n"
"{\n"
"if (!$bRecoveryConfExists)\n"
"{\n"
"&log(WARN, \"recovery type is \" . cfgOption(CFGOPT_TYPE) . \" but recovery file does not exist at ${strRecoveryConf}\");\n"
"}\n"
"}\n"
"else\n"
"{\n"
"\n"
"if ($bRecoveryConfExists)\n"
"{\n"
"storageDb()->remove($strRecoveryConf);\n"
"}\n"
"\n\n"
"if (!cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_RESTORE_TYPE_NONE))\n"
"{\n"
"\n"
"my $strRecovery = '';\n"
"my $bRestoreCommandOverride = false;\n"
"\n"
"if (cfgOptionTest(CFGOPT_RECOVERY_OPTION))\n"
"{\n"
"my $oRecoveryRef = cfgOption(CFGOPT_RECOVERY_OPTION);\n"
"\n"
"foreach my $strKey (sort(keys(%$oRecoveryRef)))\n"
"{\n"
"my $strPgKey = $strKey;\n"
"$strPgKey =~ s/\\-/\\_/g;\n"
"\n"
"if ($strPgKey eq 'restore_command')\n"
"{\n"
"$bRestoreCommandOverride = true;\n"
"}\n"
"\n"
"$strRecovery .= \"${strPgKey} = '$$oRecoveryRef{$strKey}'\\n\";\n"
"}\n"
"}\n"
"\n\n"
"if (!$bRestoreCommandOverride)\n"
"{\n"
"$strRecovery .= \"restore_command = '\" . cfgCommandWrite(CFGCMD_ARCHIVE_GET) . \" %f \\\"%p\\\"'\\n\";\n"
"}\n"
"\n\n"
"if (cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_RESTORE_TYPE_IMMEDIATE))\n"
"{\n"
"$strRecovery .= \"recovery_target = '\" . CFGOPTVAL_RESTORE_TYPE_IMMEDIATE . \"'\\n\";\n"
"}\n"
"\n"
"elsif (!cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_RESTORE_TYPE_DEFAULT))\n"
"{\n"
"\n"
"$strRecovery .= \"recovery_target_\" . cfgOption(CFGOPT_TYPE) . \" = '\" . cfgOption(CFGOPT_TARGET) . \"'\\n\";\n"
"\n\n"
"if (cfgOption(CFGOPT_TARGET_EXCLUSIVE, false))\n"
"{\n"
"$strRecovery .= \"recovery_target_inclusive = 'false'\\n\";\n"
"}\n"
"}\n"
"\n\n"
"if (cfgOptionTest(CFGOPT_TARGET_ACTION))\n"
"{\n"
"my $strTargetAction = cfgOption(CFGOPT_TARGET_ACTION);\n"
"\n"
"if ($strTargetAction ne cfgOptionDefault(CFGOPT_TARGET_ACTION))\n"
"{\n"
"if ($strDbVersion >= PG_VERSION_95)\n"
"{\n"
"$strRecovery .= \"recovery_target_action = '${strTargetAction}'\\n\";\n"
"}\n"
"elsif ($strDbVersion >= PG_VERSION_91)\n"
"{\n"
"if ($strTargetAction eq CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN)\n"
"{\n"
"confess &log(ERROR,\n"
"cfgOptionName(CFGOPT_TARGET_ACTION) . '=' . CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN .\n"
"' is only available in PostgreSQL >= ' . PG_VERSION_95)\n"
"}\n"
"\n"
"$strRecovery .= \"pause_at_recovery_target = 'false'\\n\";\n"
"}\n"
"else\n"
"{\n"
"confess &log(ERROR,\n"
"cfgOptionName(CFGOPT_TARGET_ACTION) . ' option is only available in PostgreSQL >= ' . PG_VERSION_91)\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if (cfgOptionTest(CFGOPT_TARGET_TIMELINE))\n"
"{\n"
"$strRecovery .= \"recovery_target_timeline = '\" . cfgOption(CFGOPT_TARGET_TIMELINE) . \"'\\n\";\n"
"}\n"
"\n\n"
"my $hFile;\n"
"\n"
"open($hFile, '>', $strRecoveryConf)\n"
"or confess &log(ERROR, \"unable to open ${strRecoveryConf}: $!\");\n"
"\n"
"syswrite($hFile, $strRecovery)\n"
"or confess \"unable to write section ${strRecoveryConf}: $!\";\n"
"\n"
"close($hFile)\n"
"or confess \"unable to close ${strRecoveryConf}: $!\";\n"
"\n"
"&log(INFO, \"write $strRecoveryConf\");\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam (__PACKAGE__ . '->process');\n"
"\n\n"
"my $oStorageDb = storageDb();\n"
"\n"
"if (!$oStorageDb->pathExists($self->{strDbClusterPath}))\n"
"{\n"
"confess &log(ERROR, \"\\$PGDATA directory $self->{strDbClusterPath} does not exist\");\n"
"}\n"
"\n\n"
"if ($oStorageDb->exists($self->{strDbClusterPath} . '/' . DB_FILE_POSTMASTERPID))\n"
"{\n"
"confess &log(ERROR,\n"
"\"unable to restore while PostgreSQL is running\\n\" .\n"
"\"HINT: presence of '\" . DB_FILE_POSTMASTERPID . \"' in '$self->{strDbClusterPath}' indicates PostgreSQL is running.\\n\" .\n"
"\"HINT: remove '\" . DB_FILE_POSTMASTERPID . \"' only if PostgreSQL is not running.\",\n"
"ERROR_POSTMASTER_RUNNING);\n"
"}\n"
"\n\n"
"if ((cfgOption(CFGOPT_DELTA) || cfgOption(CFGOPT_FORCE)) &&\n"
"!($oStorageDb->exists($self->{strDbClusterPath} . '/' . DB_FILE_PGVERSION) ||\n"
"$oStorageDb->exists($self->{strDbClusterPath} . '/' . FILE_MANIFEST)))\n"
"{\n"
"&log(WARN, '--delta or --force specified but unable to find \\'' . DB_FILE_PGVERSION . '\\' or \\'' . FILE_MANIFEST .\n"
"'\\' in \\'' . $self->{strDbClusterPath} . '\\' to confirm that this is a valid $PGDATA directory.' .\n"
"' --delta and --force have been disabled and if any files exist in the destination directories the restore' .\n"
"' will be aborted.');\n"
"\n"
"cfgOptionSet(CFGOPT_DELTA, false);\n"
"cfgOptionSet(CFGOPT_FORCE, false);\n"
"}\n"
"\n\n"
"$oStorageDb->copy(\n"
"storageRepo()->openRead(STORAGE_REPO_BACKUP . qw(/) . FILE_BACKUP_INFO, {bProtocolCompress => true}),\n"
"$self->{strDbClusterPath} . '/' . FILE_BACKUP_INFO);\n"
"\n"
"my $oBackupInfo = new pgBackRest::Backup::Info($self->{strDbClusterPath}, false, undef, {oStorage => storageDb()});\n"
"\n"
"$oStorageDb->remove($self->{strDbClusterPath} . '/' . FILE_BACKUP_INFO);\n"
"\n\n"
"if ($self->{strBackupSet} eq cfgOptionDefault(CFGOPT_SET))\n"
"{\n"
"$self->{strBackupSet} = $oBackupInfo->last(CFGOPTVAL_BACKUP_TYPE_INCR);\n"
"\n"
"if (!defined($self->{strBackupSet}))\n"
"{\n"
"confess &log(ERROR, \"no backup sets to restore\", ERROR_BACKUP_SET_INVALID);\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"if (!$oBackupInfo->current($self->{strBackupSet}))\n"
"{\n"
"confess &log(ERROR, \"backup set $self->{strBackupSet} is not valid\", ERROR_BACKUP_SET_INVALID);\n"
"}\n"
"}\n"
"\n\n"
"&log(INFO, \"restore backup set \" . $self->{strBackupSet});\n"
"\n\n"
"my $oManifest = $self->manifestLoad($oBackupInfo->cipherPassSub());\n"
"\n\n\n"
"$oStorageDb->remove(\n"
"$oManifest->dbPathGet(\n"
"$oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, MANIFEST_TARGET_PGDATA, MANIFEST_SUBKEY_PATH),\n"
"MANIFEST_FILE_PGCONTROL));\n"
"\n\n"
"$self->clean($oManifest);\n"
"\n\n"
"$self->build($oManifest);\n"
"\n\n"
"my $strCurrentUser = getpwuid($<);\n"
"my $strCurrentGroup = getgrgid($();\n"
"\n\n"
"my $strDbFilter;\n"
"\n"
"if (cfgOptionTest(CFGOPT_DB_INCLUDE))\n"
"{\n"
"\n"
"my %oDbList;\n"
"\n"
"foreach my $strFile ($oManifest->keys(MANIFEST_SECTION_TARGET_FILE))\n"
"{\n"
"my $strTblspcRegEx;\n"
"if ($oManifest->dbVersion() < PG_VERSION_90)\n"
"{\n"
"$strTblspcRegEx = '^' . MANIFEST_TARGET_PGTBLSPC . '\\/[0-9]+\\/[0-9]+\\/PG\\_VERSION';\n"
"}\n"
"else\n"
"{\n"
"$strTblspcRegEx = '^' . MANIFEST_TARGET_PGTBLSPC .\n"
"'\\/[0-9]+\\/'.$oManifest->tablespacePathGet().'\\/[0-9]+\\/PG\\_VERSION';\n"
"}\n"
"\n\n"
"if ($strFile =~ ('^' . MANIFEST_TARGET_PGDATA . '\\/base\\/[0-9]+\\/PG\\_VERSION') ||\n"
"$strFile =~ ($strTblspcRegEx))\n"
"{\n"
"my $lDbId = basename(dirname($strFile));\n"
"\n"
"$oDbList{$lDbId} = true;\n"
"}\n"
"}\n"
"\n\n"
"if (keys(%oDbList) == 0)\n"
"{\n"
"confess &log(ASSERT, 'no databases for include/exclude -- does not look like a valid cluster');\n"
"}\n"
"\n\n"
"&log(DETAIL, 'databases for include/exclude (' . join(', ', sort(keys(%oDbList))) . ')');\n"
"\n\n"
"my $oDbInclude = cfgOption(CFGOPT_DB_INCLUDE);\n"
"\n"
"for my $strDbKey (sort(keys(%{$oDbInclude})))\n"
"{\n"
"\n"
"if (!defined($oDbList{$strDbKey}))\n"
"{\n"
"\n"
"my $lDbId = $oManifest->get(MANIFEST_SECTION_DB, $strDbKey, MANIFEST_KEY_DB_ID, false);\n"
"\n"
"if (!defined($lDbId) || !defined($oDbList{$lDbId}))\n"
"{\n"
"confess &log(ERROR, \"database to include '${strDbKey}' does not exist\", ERROR_DB_MISSING);\n"
"}\n"
"\n\n"
"$strDbKey = $lDbId;\n"
"}\n"
"\n\n"
"if ($strDbKey < DB_USER_OBJECT_MINIMUM_ID)\n"
"{\n"
"confess &log(ERROR, \"system databases (template0, postgres, etc.) are included by default\", ERROR_DB_INVALID);\n"
"}\n"
"\n\n"
"delete($oDbList{$strDbKey});\n"
"}\n"
"\n\n"
"for my $strDbKey (sort(keys(%oDbList)))\n"
"{\n"
"\n"
"if ($strDbKey >= DB_USER_OBJECT_MINIMUM_ID)\n"
"{\n"
"\n"
"$strDbFilter .= (defined($strDbFilter) ? '|' : '') .\n"
"'(^' . MANIFEST_TARGET_PGDATA . '\\/base\\/' . $strDbKey . '\\/)';\n"
"\n\n"
"for my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"if ($oManifest->isTargetTablespace($strTarget))\n"
"{\n"
"if ($oManifest->dbVersion() < PG_VERSION_90)\n"
"{\n"
"$strDbFilter .= '|(^' . $strTarget . '\\/' . $strDbKey . '\\/)';\n"
"}\n"
"else\n"
"{\n"
"$strDbFilter .=\n"
"'|(^' . $strTarget . '\\/' . $oManifest->tablespacePathGet() . '\\/' . $strDbKey . '\\/)';\n"
"}\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"&log(DETAIL, \"database filter: \" . (defined($strDbFilter) ? \"${strDbFilter}\" : ''));\n"
"}\n"
"\n\n"
"my $oRestoreProcess = new pgBackRest::Protocol::Local::Process(CFGOPTVAL_LOCAL_TYPE_BACKUP);\n"
"$oRestoreProcess->hostAdd(1, cfgOption(CFGOPT_PROCESS_MAX));\n"
"\n\n"
"my $lSizeTotal = 0;\n"
"my $lSizeCurrent = 0;\n"
"\n"
"foreach my $strRepoFile (\n"
"sort {sprintf(\"%016d-%s\", $oManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $b, MANIFEST_SUBKEY_SIZE), $b) cmp\n"
"sprintf(\"%016d-%s\", $oManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $a, MANIFEST_SUBKEY_SIZE), $a)}\n"
"($oManifest->keys(MANIFEST_SECTION_TARGET_FILE, INI_SORT_NONE)))\n"
"{\n"
"\n\n"
"if ($strRepoFile eq MANIFEST_FILE_TABLESPACEMAP &&\n"
"$oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION) >= PG_VERSION_95)\n"
"{\n"
"next;\n"
"}\n"
"\n\n"
"my $strQueueKey = MANIFEST_TARGET_PGDATA;\n"
"\n\n"
"if (index($strRepoFile, DB_PATH_PGTBLSPC . '/') == 0)\n"
"{\n"
"$strQueueKey = DB_PATH_PGTBLSPC . '/' . (split('\\/', $strRepoFile))[1];\n"
"}\n"
"\n\n"
"my $strDbFile = $oManifest->dbPathGet($self->{strDbClusterPath}, $strRepoFile);\n"
"my $lSize = $oManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_SIZE);\n"
"\n\n"
"if ($strRepoFile eq MANIFEST_TARGET_PGDATA . '/' . DB_FILE_PGCONTROL)\n"
"{\n"
"$strDbFile .= '.' . STORAGE_TEMP_EXT;\n"
"}\n"
"\n\n"
"$lSizeTotal += $lSize;\n"
"\n\n"
"$oRestoreProcess->queueJob(\n"
"1, $strQueueKey, $strRepoFile, OP_RESTORE_FILE,\n"
"[$strDbFile, $lSize,\n"
"$oManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_TIMESTAMP),\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_CHECKSUM, $lSize > 0),\n"
"defined($strDbFilter) && $strRepoFile =~ $strDbFilter && $strRepoFile !~ /\\/PG\\_VERSION$/ ? true : false,\n"
"cfgOption(CFGOPT_FORCE), $strRepoFile,\n"
"$oManifest->boolTest(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK, undef, true) ? undef :\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_REFERENCE, false),\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_MODE),\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_USER),\n"
"$oManifest->get(MANIFEST_SECTION_TARGET_FILE, $strRepoFile, MANIFEST_SUBKEY_GROUP),\n"
"$oManifest->numericGet(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_COPY_START), cfgOption(CFGOPT_DELTA),\n"
"$self->{strBackupSet}, $oManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS)],\n"
"{rParamSecure => $oManifest->cipherPassSub() ? [$oManifest->cipherPassSub()] : undef});\n"
"}\n"
"\n\n"
"while (my $hyJob = $oRestoreProcess->process())\n"
"{\n"
"foreach my $hJob (@{$hyJob})\n"
"{\n"
"($lSizeCurrent) = restoreLog(\n"
"$hJob->{iProcessId}, @{$hJob->{rParam}}[0..5], @{$hJob->{rResult}}, $lSizeTotal, $lSizeCurrent);\n"
"}\n"
"\n\n\n"
"protocolKeepAlive();\n"
"}\n"
"\n\n"
"$self->recovery($oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION));\n"
"\n\n"
"foreach my $strPath ($oManifest->keys(MANIFEST_SECTION_TARGET_PATH))\n"
"{\n"
"\n"
"next if $strPath eq MANIFEST_TARGET_PGTBLSPC;\n"
"\n"
"$oStorageDb->pathSync($oManifest->dbPathGet($self->{strDbClusterPath}, $strPath));\n"
"}\n"
"\n\n"
"foreach my $strTarget ($oManifest->keys(MANIFEST_SECTION_BACKUP_TARGET))\n"
"{\n"
"\n"
"next if $strTarget eq MANIFEST_TARGET_PGDATA;\n"
"\n"
"$oStorageDb->pathSync(\n"
"$oStorageDb->pathAbsolute(\n"
"$self->{strDbClusterPath} . ($strTarget =~ ('^' . MANIFEST_TARGET_PGTBLSPC) ? '/' . MANIFEST_TARGET_PGTBLSPC : ''),\n"
"$oManifest->get(MANIFEST_SECTION_BACKUP_TARGET, $strTarget, MANIFEST_VALUE_PATH)));\n"
"}\n"
"\n\n"
"&log(INFO,\n"
"'restore ' . $oManifest->dbPathGet(undef, MANIFEST_FILE_PGCONTROL) .\n"
"' (performed last to ensure aborted restores cannot be started)');\n"
"\n"
"$oStorageDb->move(\n"
"$self->{strDbClusterPath} . '/' . DB_FILE_PGCONTROL . '.' . STORAGE_TEMP_EXT,\n"
"$self->{strDbClusterPath} . '/' . DB_FILE_PGCONTROL);\n"
"\n\n"
"$oStorageDb->pathSync($self->{strDbClusterPath});\n"
"\n\n"
"$oStorageDb->remove($self->{strDbClusterPath} . '/' . FILE_MANIFEST);\n"
"\n\n"
"$oStorageDb->pathSync($self->{strDbClusterPath});\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/RestoreFile.pm",
.data =
"\n\n\n"
"package pgBackRest::RestoreFile;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Fcntl qw(:mode);\n"
"use File::Basename qw(dirname);\n"
"use File::stat qw(lstat);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Handle;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Filter::Gzip;\n"
"use pgBackRest::Storage::Filter::Sha;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n\n\n"
"sub restoreLog\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$iLocalId,\n"
"$strDbFile,\n"
"$lSize,\n"
"$lModificationTime,\n"
"$strChecksum,\n"
"$bZero,\n"
"$bForce,\n"
"$bCopy,\n"
"$lSizeTotal,\n"
"$lSizeCurrent,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::restoreLog', \\@_,\n"
"{name => 'iLocalId', required => false},\n"
"{name => 'strDbFile'},\n"
"{name => 'lSize'},\n"
"{name => 'lModificationTime'},\n"
"{name => 'strChecksum', required => false},\n"
"{name => 'bZero', required => false, default => false},\n"
"{name => 'bForce'},\n"
"{name => 'bCopy'},\n"
"{name => 'lSizeTotal'},\n"
"{name => 'lSizeCurrent'},\n"
");\n"
"\n\n"
"my $strLog;\n"
"\n"
"if (!$bCopy && !$bZero)\n"
"{\n"
"if ($bForce)\n"
"{\n"
"$strLog = 'exists and matches size ' . $lSize . ' and modification time ' . $lModificationTime;\n"
"}\n"
"else\n"
"{\n"
"$strLog = 'exists and ' . ($lSize == 0 ? 'is zero size' : 'matches backup');\n"
"}\n"
"}\n"
"\n\n"
"$lSizeCurrent += $lSize;\n"
"\n"
"&log($bCopy ? INFO : DETAIL,\n"
"'restore' . ($bZero ? ' zeroed' : '') .\n"
"\" file ${strDbFile}\" . (defined($strLog) ? \" - ${strLog}\" : '') .\n"
"' (' . fileSizeFormat($lSize) .\n"
"($lSizeTotal > 0 ? ', ' . int($lSizeCurrent * 100 / $lSizeTotal) . '%' : '') . ')' .\n"
"($lSize != 0 && !$bZero ? \" checksum ${strChecksum}\" : ''), undef, undef, undef, $iLocalId);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'lSizeCurrent', value => $lSizeCurrent, trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(restoreLog);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Stanza.pm",
.data =
"\n\n\n\n\n"
"package pgBackRest::Stanza;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Backup::Common;\n"
"use pgBackRest::Common::Cipher;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Lock;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Archive::Info;\n"
"use pgBackRest::Backup::Info;\n"
"use pgBackRest::Db;\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::InfoCommon;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"\n\n\n\n"
"my $strHintForce = \"\\nHINT: use stanza-create --force to force the stanza data to be recreated.\";\n"
"my $strInfoMissing = \" information missing\";\n"
"my $strStanzaCreateErrorMsg = \"not empty\";\n"
"my $strRepoEncryptedMsg = \" and repo is encrypted and info file(s) are missing, --force cannot be used\";\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"my $strOperation = logDebugParam(__PACKAGE__ . '->new');\n"
"\n\n"
"if (!cfgCommandTest(CFGCMD_STANZA_DELETE))\n"
"{\n"
"($self->{oDb}) = dbObjectGet();\n"
"$self->dbInfoGet();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');\n"
"\n"
"my $iResult = 0;\n"
"\n\n"
"if (cfgCommandTest(CFGCMD_STANZA_CREATE))\n"
"{\n"
"$iResult = $self->stanzaCreate();\n"
"}\n"
"\n"
"elsif (cfgCommandTest(CFGCMD_STANZA_UPGRADE))\n"
"{\n"
"$self->stanzaUpgrade();\n"
"}\n"
"\n"
"else\n"
"{\n"
"$self->stanzaDelete();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iResult', value => $iResult, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub stanzaCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaCreate');\n"
"\n"
"my $bContinue = true;\n"
"\n\n"
"my $strParentPathArchive = $self->parentPathGet(STORAGE_REPO_ARCHIVE);\n"
"my $strParentPathBackup = $self->parentPathGet(STORAGE_REPO_BACKUP);\n"
"\n\n"
"my @stryFileListArchive = storageRepo()->list($strParentPathArchive, {bIgnoreMissing => true});\n"
"my @stryFileListBackup = storageRepo()->list($strParentPathBackup, {bIgnoreMissing => true});\n"
"\n\n\n\n"
"if (@stryFileListArchive || @stryFileListBackup)\n"
"{\n"
"my $strBackupInfoFile = &FILE_BACKUP_INFO;\n"
"my $strArchiveInfoFile = &ARCHIVE_INFO_FILE;\n"
"\n\n"
"my $bBackupInfoFileExists = grep(/^$strBackupInfoFile$/i, @stryFileListBackup);\n"
"my $bArchiveInfoFileExists = grep(/^$strArchiveInfoFile$/i, @stryFileListArchive);\n"
"\n\n"
"if (!$bBackupInfoFileExists)\n"
"{\n"
"$strBackupInfoFile .= &INI_COPY_EXT;\n"
"$bBackupInfoFileExists = grep(/^$strBackupInfoFile$/i, @stryFileListBackup);\n"
"}\n"
"\n"
"if (!$bArchiveInfoFileExists)\n"
"{\n"
"$strArchiveInfoFile .= &INI_COPY_EXT;\n"
"$bArchiveInfoFileExists = grep(/^$strArchiveInfoFile$/i, @stryFileListArchive);\n"
"}\n"
"\n\n"
"my $strExistingFile = $self->existingFileName(STORAGE_REPO_BACKUP, $strParentPathBackup, &FILE_BACKUP_INFO);\n"
"if (!defined($strExistingFile))\n"
"{\n"
"$strExistingFile = $self->existingFileName(STORAGE_REPO_ARCHIVE, $strParentPathArchive, &ARCHIVE_INFO_FILE);\n"
"}\n"
"\n\n\n"
"if (defined($strExistingFile) && (!storageRepo()->encryptionValid(storageRepo()->encrypted($strExistingFile))))\n"
"{\n"
"confess &log(ERROR, 'files exist - the encryption type or passphrase cannot be changed', ERROR_PATH_NOT_EMPTY);\n"
"}\n"
"\n\n\n\n\n"
"if (!$bArchiveInfoFileExists && $bBackupInfoFileExists)\n"
"{\n"
"$self->errorForce('archive' . $strInfoMissing, ERROR_FILE_MISSING, $strExistingFile, $bArchiveInfoFileExists,\n"
"$strParentPathArchive, $strParentPathBackup);\n"
"}\n"
"elsif (!$bBackupInfoFileExists && $bArchiveInfoFileExists)\n"
"{\n"
"$self->errorForce('backup' . $strInfoMissing, ERROR_FILE_MISSING, $strExistingFile, $bBackupInfoFileExists,\n"
"$strParentPathArchive, $strParentPathBackup);\n"
"}\n"
"\n\n\n\n"
"else\n"
"{\n"
"$self->errorForce(\n"
"(@stryFileListBackup ? 'backup directory ' : '') .\n"
"((@stryFileListBackup && @stryFileListArchive) ? 'and/or ' : '') .\n"
"(@stryFileListArchive ? 'archive directory ' : '') .\n"
"$strStanzaCreateErrorMsg, ERROR_PATH_NOT_EMPTY,\n"
"$strExistingFile, $bArchiveInfoFileExists, $strParentPathArchive, $strParentPathBackup);\n"
"\n\n"
"if (!cfgOption(CFGOPT_FORCE))\n"
"{\n"
"$bContinue = false;\n"
"}\n"
"}\n"
"}\n"
"\n"
"my $iResult = 0;\n"
"\n"
"if ($bContinue)\n"
"{\n"
"\n"
"my $oArchiveInfo =\n"
"$self->infoObject(STORAGE_REPO_ARCHIVE, $strParentPathArchive, {bRequired => false, bIgnoreMissing => true});\n"
"my $oBackupInfo =\n"
"$self->infoObject(STORAGE_REPO_BACKUP, $strParentPathBackup, {bRequired => false, bIgnoreMissing => true});\n"
"\n\n"
"($iResult, my $strResultMessage) = $self->infoFileCreate($oArchiveInfo);\n"
"\n"
"if ($iResult == 0)\n"
"{\n"
"\n"
"($iResult, $strResultMessage) = $self->infoFileCreate($oBackupInfo);\n"
"}\n"
"\n"
"if ($iResult != 0)\n"
"{\n"
"&log(WARN, \"unable to create stanza '\" . cfgOption(CFGOPT_STANZA) . \"'\");\n"
"confess &log(ERROR, $strResultMessage, $iResult);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iResult', value => $iResult, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub stanzaUpgrade\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaUpgrade');\n"
"\n\n"
"my $oArchiveInfo = $self->infoObject(STORAGE_REPO_ARCHIVE, storageRepo()->pathGet(STORAGE_REPO_ARCHIVE));\n"
"my $oBackupInfo = $self->infoObject(STORAGE_REPO_BACKUP, storageRepo()->pathGet(STORAGE_REPO_BACKUP));\n"
"my $bBackupUpgraded = false;\n"
"my $bArchiveUpgraded = false;\n"
"\n\n"
"if ($self->upgradeCheck($oBackupInfo, STORAGE_REPO_BACKUP, ERROR_BACKUP_MISMATCH))\n"
"{\n"
"\n"
"my ($bReconstruct, $strWarningMsgArchive) = $oBackupInfo->reconstruct(false, false, $self->{oDb}{strDbVersion},\n"
"$self->{oDb}{ullDbSysId}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion});\n"
"$oBackupInfo->save();\n"
"$bBackupUpgraded = true;\n"
"}\n"
"\n"
"if ($self->upgradeCheck($oArchiveInfo, STORAGE_REPO_ARCHIVE, ERROR_ARCHIVE_MISMATCH))\n"
"{\n"
"\n"
"my ($bReconstruct, $strWarningMsgArchive) = $oArchiveInfo->reconstruct($self->{oDb}{strDbVersion},\n"
"$self->{oDb}{ullDbSysId});\n"
"$oArchiveInfo->save();\n"
"$bArchiveUpgraded = true;\n"
"}\n"
"\n\n"
"if (!($bBackupUpgraded || $bArchiveUpgraded))\n"
"{\n"
"&log(INFO, \"the stanza data is already up to date\");\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub stanzaDelete\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaDelete');\n"
"\n"
"my $strStanza = cfgOption(CFGOPT_STANZA);\n"
"my $oStorageRepo = storageRepo({strStanza => $strStanza});\n"
"\n\n"
"if ($oStorageRepo->pathExists(STORAGE_REPO_ARCHIVE) || $oStorageRepo->pathExists(STORAGE_REPO_BACKUP))\n"
"{\n"
"\n"
"if (!lockStopTest({bStanzaStopRequired => true}))\n"
"{\n"
"confess &log(ERROR, \"stop file does not exist for stanza '${strStanza}'\" .\n"
"\"\\nHINT: has the pgbackrest stop command been run on this server?\", ERROR_FILE_MISSING);\n"
"}\n"
"\n\n"
"if (!cfgOption(CFGOPT_FORCE))\n"
"{\n"
"\n"
"my ($oDbMaster, $iMasterRemoteIdx) = dbObjectGet({bMasterOnly => true});\n"
"\n\n"
"my $oStorageDbMaster = storageDb({iRemoteIdx => $iMasterRemoteIdx});\n"
"\n\n"
"if ($oStorageDbMaster->exists(DB_FILE_POSTMASTERPID))\n"
"{\n"
"confess &log(ERROR, DB_FILE_POSTMASTERPID . \" exists - looks like the postmaster is running. \" .\n"
"\"To delete stanza '${strStanza}', shutdown the postmaster for stanza '${strStanza}' and try again, \" .\n"
"\"or use --force.\", ERROR_POSTMASTER_RUNNING);\n"
"}\n"
"}\n"
"\n\n"
"$oStorageRepo->remove(STORAGE_REPO_ARCHIVE . '/' . ARCHIVE_INFO_FILE, {bIgnoreMissing => true});\n"
"$oStorageRepo->remove(STORAGE_REPO_ARCHIVE . '/' . ARCHIVE_INFO_FILE . INI_COPY_EXT, {bIgnoreMissing => true});\n"
"\n\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . '/' . FILE_BACKUP_INFO, {bIgnoreMissing => true});\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . '/' . FILE_BACKUP_INFO . INI_COPY_EXT, {bIgnoreMissing => true});\n"
"\n\n"
"foreach my $strBackup ($oStorageRepo->list(\n"
"STORAGE_REPO_BACKUP, {strExpression => backupRegExpGet(true, true, true), strSortOrder => 'reverse',\n"
"bIgnoreMissing => true}))\n"
"{\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strBackup}/\" . FILE_MANIFEST, {bIgnoreMissing => true});\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strBackup}/\" . FILE_MANIFEST_COPY, {bIgnoreMissing => true});\n"
"}\n"
"\n\n"
"$oStorageRepo->remove(STORAGE_REPO_ARCHIVE, {bRecurse => true, bIgnoreMissing => true});\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP, {bRecurse => true, bIgnoreMissing => true});\n"
"\n\n"
"lockStart();\n"
"}\n"
"else\n"
"{\n"
"&log(INFO, \"stanza ${strStanza} already deleted\");\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub parentPathGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathType,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->parentPathGet', \\@_,\n"
"{name => 'strPathType', trace => true},\n"
");\n"
"\n"
"my $strParentPath = storageRepo()->pathGet($strPathType);\n"
"\n\n"
"if (!storageRepo()->pathExists($strParentPath))\n"
"{\n"
"\n"
"storageRepo()->pathCreate($strPathType, {bIgnoreExists => true, bCreateParent => true});\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strParentPath', value => $strParentPath},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub existingFileName\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathType,\n"
"$strParentPath,\n"
"$strExcludeFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->existingFileName', \\@_,\n"
"{name => 'strPathType'},\n"
"{name => 'strParentPath'},\n"
"{name => 'strExcludeFile'},\n"
");\n"
"\n"
"my $hFullList = storageRepo()->manifest(storageRepo()->pathGet($strPathType), {bIgnoreMissing => true});\n"
"my $strExistingFile = undef;\n"
"\n"
"foreach my $strName (keys(%{$hFullList}))\n"
"{\n"
"if (($hFullList->{$strName}{type} eq 'f') &&\n"
"(substr($strName, 0, length($strExcludeFile)) ne $strExcludeFile))\n"
"{\n"
"$strExistingFile = $strParentPath . \"/\" . $strName;\n"
"last;\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strExistingFile', value => $strExistingFile},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub errorForce\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strMessage,\n"
"$iErrorCode,\n"
"$strFileName,\n"
"$bInfoFileExists,\n"
"$strParentPathArchive,\n"
"$strParentPathBackup,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->errorForce', \\@_,\n"
"{name => 'strMessage', trace => true},\n"
"{name => 'iErrorCode', trace => true},\n"
"{name => 'strFileName', required => false, trace => true},\n"
"{name => 'bInfoFileExists', trace => true},\n"
"{name => 'strParentPathArchive', trace => true},\n"
"{name => 'strParentPathBackup', trace => true},\n"
");\n"
"\n"
"my $bRepoEncrypted = false;\n"
"\n\n"
"if (defined($strFileName))\n"
"{\n"
"$bRepoEncrypted = storageRepo()->encrypted($strFileName);\n"
"}\n"
"elsif (defined(storageRepo()->cipherType()))\n"
"{\n"
"$bRepoEncrypted = true;\n"
"}\n"
"\n\n\n"
"if ($bRepoEncrypted && defined($strFileName) && !$bInfoFileExists)\n"
"{\n"
"confess &log(ERROR, $strMessage . $strRepoEncryptedMsg, $iErrorCode);\n"
"}\n"
"elsif (!cfgOption(CFGOPT_FORCE))\n"
"{\n"
"\n"
"if ($bInfoFileExists && $iErrorCode == ERROR_PATH_NOT_EMPTY)\n"
"{\n"
"if ($self->upgradeCheck(new pgBackRest::Backup::Info($strParentPathBackup), STORAGE_REPO_BACKUP,\n"
"ERROR_BACKUP_MISMATCH) ||\n"
"$self->upgradeCheck(new pgBackRest::Archive::Info($strParentPathArchive), STORAGE_REPO_ARCHIVE,\n"
"ERROR_ARCHIVE_MISMATCH))\n"
"{\n"
"confess &log(ERROR, \"backup info file or archive info file invalid\\n\" .\n"
"'HINT: use stanza-upgrade if the database has been upgraded or use --force', ERROR_FILE_INVALID);\n"
"}\n"
"else\n"
"{\n"
"&log(INFO, \"stanza-create was already performed\");\n"
"}\n"
"}\n"
"else\n"
"{\n"
"\n"
"confess &log(ERROR, $strMessage . $strHintForce, $iErrorCode);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub infoObject\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathType,\n"
"$strParentPath,\n"
"$bRequired,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->infoObject', \\@_,\n"
"{name => 'strPathType'},\n"
"{name => 'strParentPath'},\n"
"{name => 'bRequired', optional => true, default => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
");\n"
"\n"
"my $iResult = 0;\n"
"my $strResultMessage;\n"
"my $oInfo;\n"
"\n\n"
"logDisable();\n"
"\n\n\n"
"eval\n"
"{\n"
"\n\n\n\n"
"my $oParamRef =\n"
"{bIgnoreMissing => $bIgnoreMissing, strCipherPassSub => defined(storageRepo()->cipherType()) ? cipherPassGen() : undef};\n"
"\n"
"$oInfo = ($strPathType eq STORAGE_REPO_BACKUP ?\n"
"new pgBackRest::Backup::Info($strParentPath, false, $bRequired, $oParamRef) :\n"
"new pgBackRest::Archive::Info($strParentPath, $bRequired, $oParamRef));\n"
"\n\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"logEnable();\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n"
"if ($iResult != 0)\n"
"{\n"
"\n\n\n"
"if ((cfgOptionValid(CFGOPT_FORCE) && !cfgOption(CFGOPT_FORCE)) ||\n"
"(!cfgOptionValid(CFGOPT_FORCE)))\n"
"{\n"
"if ($iResult == ERROR_FILE_MISSING)\n"
"{\n"
"confess &log(ERROR, cfgOptionValid(CFGOPT_FORCE) ? $strResultMessage . $strHintForce : $strResultMessage, $iResult);\n"
"}\n"
"else\n"
"{\n"
"confess &log(ERROR, $strResultMessage, $iResult);\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if (($iResult != ERROR_FILE_MISSING) && ($iResult != ERROR_CRYPTO))\n"
"{\n"
"confess &log(ERROR, $strResultMessage, $iResult);\n"
"}\n"
"\n"
"my $oParamRef =\n"
"{bLoad => false, strCipherPassSub => defined(storageRepo()->cipherType()) ? cipherPassGen() : undef};\n"
"\n"
"$oInfo = ($strPathType eq STORAGE_REPO_BACKUP ?\n"
"new pgBackRest::Backup::Info($strParentPath, false, false, $oParamRef) :\n"
"new pgBackRest::Archive::Info($strParentPath, false, $oParamRef));\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oInfo', value => $oInfo},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub infoFileCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oInfo,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->infoFileCreate', \\@_,\n"
"{name => 'oInfo', trace => true},\n"
");\n"
"\n"
"my $iResult = 0;\n"
"my $strResultMessage = undef;\n"
"my $strWarningMsgArchive = undef;\n"
"\n\n"
"logDisable();\n"
"\n"
"eval\n"
"{\n"
"\n"
"if (defined($oInfo->{strBackupClusterPath}))\n"
"{\n"
"$oInfo->reconstruct(false, false, $self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId}, $self->{oDb}{iControlVersion},\n"
"$self->{oDb}{iCatalogVersion});\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strWarningMsgArchive = $oInfo->reconstruct($self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId});\n"
"}\n"
"\n\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"logEnable();\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n\n"
"if ($iResult == 0)\n"
"{\n"
"$oInfo->save();\n"
"\n\n"
"storageRepo()->pathSync(\n"
"defined($oInfo->{strArchiveClusterPath}) ? $oInfo->{strArchiveClusterPath} : $oInfo->{strBackupClusterPath});\n"
"}\n"
"\n\n"
"if (defined($strWarningMsgArchive))\n"
"{\n"
"&log(WARN, $strWarningMsgArchive);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iResult', value => $iResult},\n"
"{name => 'strResultMessage', value => $strResultMessage},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbInfoGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->dbInfoGet');\n"
"\n\n\n\n"
"if (cfgOption(CFGOPT_ONLINE))\n"
"{\n"
"\n"
"$self->{oDb}->configValidate();\n"
"}\n"
"\n"
"($self->{oDb}{strDbVersion}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion}, $self->{oDb}{ullDbSysId})\n"
"= $self->{oDb}->info();\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub upgradeCheck\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oInfo,\n"
"$strPathType,\n"
"$iExpectedError,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->upgradeCheck', \\@_,\n"
"{name => 'oInfo'},\n"
"{name => 'strPathType'},\n"
"{name => 'iExpectedError'},\n"
");\n"
"\n"
"my $iResult = 0;\n"
"my $strResultMessage = undef;\n"
"\n\n"
"logDisable();\n"
"\n"
"eval\n"
"{\n"
"($strPathType eq STORAGE_REPO_BACKUP)\n"
"? $oInfo->check($self->{oDb}{strDbVersion}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion},\n"
"$self->{oDb}{ullDbSysId}, true)\n"
": $oInfo->check($self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId}, true);\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"logEnable();\n"
"\n\n"
"confess $EVAL_ERROR if (exceptionCode($EVAL_ERROR) != $iExpectedError);\n"
"\n\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bResult', value => ($iResult == $iExpectedError ? true : false)},\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Base.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::Base;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Base;\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"use constant STORAGE_COMPRESS => 'compress';\n"
"push @EXPORT, qw(STORAGE_COMPRESS);\n"
"use constant STORAGE_DECOMPRESS => 'decompress';\n"
"push @EXPORT, qw(STORAGE_DECOMPRESS);\n"
"\n\n\n\n"
"use constant STORAGE_ENCRYPT => 'encrypt';\n"
"push @EXPORT, qw(STORAGE_ENCRYPT);\n"
"use constant STORAGE_DECRYPT => 'decrypt';\n"
"push @EXPORT, qw(STORAGE_DECRYPT);\n"
"use constant CIPHER_MAGIC => 'Salted__';\n"
"push @EXPORT, qw(CIPHER_MAGIC);\n"
"\n\n\n\n\n\n\n"
"use constant STORAGE_CAPABILITY_SIZE_DIFF => 'size-diff';\n"
"push @EXPORT, qw(STORAGE_CAPABILITY_SIZE_DIFF);\n"
"\n"
"use constant STORAGE_CAPABILITY_LINK => 'link';\n"
"push @EXPORT, qw(STORAGE_CAPABILITY_LINK);\n"
"use constant STORAGE_CAPABILITY_PATH_SYNC => 'path-sync';\n"
"push @EXPORT, qw(STORAGE_CAPABILITY_PATH_SYNC);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{lBufferMax},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'lBufferMax', optional => true, default => COMMON_IO_BUFFER_MAX, trace => true},\n"
");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n\n"
"sub copy\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$xSourceFile,\n"
"$xDestinationFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->copy', \\@_,\n"
"{name => 'xSourceFile', required => false},\n"
"{name => 'xDestinationFile', required => false},\n"
");\n"
"\n\n"
"my $bResult = false;\n"
"\n\n"
"my $oSourceFileIo =\n"
"defined($xSourceFile) ?\n"
"(ref($xSourceFile) ? $xSourceFile : $self->openRead($self->pathGet($xSourceFile))) : undef;\n"
"\n\n"
"if (defined($oSourceFileIo))\n"
"{\n"
"\n"
"my $oDestinationFileIo = ref($xDestinationFile) ? $xDestinationFile : $self->openWrite($self->pathGet($xDestinationFile));\n"
"\n\n"
"my $lSizeRead;\n"
"\n"
"do\n"
"{\n"
"\n"
"my $tBuffer = '';\n"
"\n"
"$lSizeRead = $oSourceFileIo->read(\\$tBuffer, $self->{lBufferMax});\n"
"$oDestinationFileIo->write(\\$tBuffer);\n"
"}\n"
"while ($lSizeRead != 0);\n"
"\n\n"
"$oSourceFileIo->close();\n"
"$oDestinationFileIo->close();\n"
"\n\n"
"$bResult = true;\n"
"}\n"
"\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bResult', value => $bResult, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub get\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$xFile,\n"
"$strCipherPass,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->get', \\@_,\n"
"{name => 'xFile', required => false, trace => true},\n"
"{name => 'strCipherPass', optional => true, redact => true},\n"
");\n"
"\n\n\n"
"my $oFileIo = defined($xFile) ? (ref($xFile) ? $xFile : $self->openRead(\n"
"$xFile, {strCipherPass => defined($strCipherPass) ? $strCipherPass : $self->cipherPassUser()})) : undef;\n"
"\n\n"
"my $tContent;\n"
"my $lSize = 0;\n"
"\n"
"if (defined($oFileIo))\n"
"{\n"
"my $lSizeRead;\n"
"\n"
"do\n"
"{\n"
"$lSizeRead = $oFileIo->read(\\$tContent, $self->{lBufferMax});\n"
"$lSize += $lSizeRead;\n"
"}\n"
"while ($lSizeRead != 0);\n"
"\n\n"
"$oFileIo->close();\n"
"\n\n"
"if ($lSize == 0)\n"
"{\n"
"$tContent = undef;\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'rtContent', value => defined($oFileIo) ? \\$tContent : undef, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathAbsolute\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strBasePath,\n"
"$strPath\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::pathAbsolute', \\@_,\n"
"{name => 'strBasePath', trace => true},\n"
"{name => 'strPath', trace => true}\n"
");\n"
"\n\n"
"my $strAbsolutePath;\n"
"\n\n"
"if (index($strPath, '/') == 0)\n"
"{\n"
"$strAbsolutePath = $strPath;\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if (index($strBasePath, '/') != 0 || index($strBasePath, '/..') != -1)\n"
"{\n"
"confess &log(ERROR, \"${strBasePath} is not an absolute path\", ERROR_PATH_TYPE);\n"
"}\n"
"\n"
"while (index($strPath, '..') == 0)\n"
"{\n"
"$strBasePath = dirname($strBasePath);\n"
"$strPath = substr($strPath, 2);\n"
"\n"
"if (index($strPath, '/') == 0)\n"
"{\n"
"$strPath = substr($strPath, 1);\n"
"}\n"
"}\n"
"\n"
"$strAbsolutePath = \"${strBasePath}/${strPath}\";\n"
"}\n"
"\n\n"
"if (index($strAbsolutePath, '/') != 0 || index($strAbsolutePath, '/..') != -1)\n"
"{\n"
"confess &log(ERROR, \"result ${strAbsolutePath} was not an absolute path\", ERROR_PATH_TYPE);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strAbsolutePath', value => $strAbsolutePath, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub put\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$xFile,\n"
"$xContent,\n"
"$strCipherPass,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->put', \\@_,\n"
"{name => 'xFile', trace => true},\n"
"{name => 'xContent', required => false, trace => true},\n"
"{name => 'strCipherPass', optional => true, trace => true, redact => true},\n"
");\n"
"\n\n\n"
"my $oFileIo = ref($xFile) ? $xFile : $self->openWrite(\n"
"$xFile, {strCipherPass => defined($strCipherPass) ? $strCipherPass : $self->cipherPassUser()});\n"
"\n\n"
"my $lSize = defined($xContent) ? length(ref($xContent) ? $$xContent : $xContent) : 0;\n"
"\n\n"
"if ($lSize > 0)\n"
"{\n"
"$oFileIo->write(ref($xContent) ? $xContent : \\$xContent);\n"
"}\n"
"\n"
"else\n"
"{\n"
"$oFileIo->open();\n"
"}\n"
"\n\n"
"$oFileIo->close();\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'lSize', value => $lSize, trace => true},\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Cifs/Driver.pm",
.data =
"\n\n\n\n\n"
"package pgBackRest::Storage::Cifs::Driver;\n"
"use parent 'pgBackRest::Storage::Posix::Driver';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Storage::Base;\n"
"\n\n\n\n"
"use constant STORAGE_CIFS_DRIVER => __PACKAGE__;\n"
"push @EXPORT, qw(STORAGE_CIFS_DRIVER);\n"
"\n\n\n\n"
"sub pathSync\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathSync', \\@_,\n"
"{name => 'strPath', trace => true},\n"
");\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub capability {shift eq STORAGE_CAPABILITY_SIZE_DIFF ? true : false}\n"
"sub className {STORAGE_CIFS_DRIVER}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Filter/CipherBlock.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::Filter::CipherBlock;\n"
"use parent 'pgBackRest::Common::Io::Filter';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Base;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::LibC qw(:crypto);\n"
"use pgBackRest::Storage::Base;\n"
"\n\n\n\n"
"use constant STORAGE_FILTER_CIPHER_BLOCK => __PACKAGE__;\n"
"push @EXPORT, qw(STORAGE_FILTER_CIPHER_BLOCK);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oParent,\n"
"$strCipherType,\n"
"$tCipherPass,\n"
"$strMode,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oParent', trace => true},\n"
"{name => 'strCipherType', trace => true},\n"
"{name => 'tCipherPass', trace => true},\n"
"{name => 'strMode', optional => true, default => STORAGE_ENCRYPT, trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($oParent);\n"
"bless $self, $class;\n"
"\n\n"
"$self->{strMode} = $strMode;\n"
"\n"
"if (!($self->{strMode} eq STORAGE_ENCRYPT || $self->{strMode} eq STORAGE_DECRYPT))\n"
"{\n"
"confess &log(ASSERT, \"unknown cipher mode: $self->{strMode}\");\n"
"}\n"
"\n\n"
"$self->{bWrite} = false;\n"
"\n\n"
"$self->{oCipher} = new pgBackRest::LibC::Cipher::Block(\n"
"$self->{strMode} eq STORAGE_ENCRYPT ? CIPHER_MODE_ENCRYPT : CIPHER_MODE_DECRYPT, $strCipherType, $tCipherPass,\n"
"length($tCipherPass));\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub read\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"my $iSize = shift;\n"
"\n\n"
"return 0 if $self->eof();\n"
"\n\n"
"my $tBufferRead = '';\n"
"my $iBufferReadSize = 0;\n"
"\n"
"do\n"
"{\n"
"\n"
"my $tCipherBuffer;\n"
"my $iActualSize = $self->SUPER::read(\\$tCipherBuffer, $iSize);\n"
"\n\n"
"if ($iActualSize > 0)\n"
"{\n"
"$tBufferRead .= $self->{oCipher}->process($tCipherBuffer);\n"
"}\n"
"\n\n"
"if ($self->eof())\n"
"{\n"
"$tBufferRead .= $self->{oCipher}->flush();\n"
"}\n"
"\n\n"
"$iBufferReadSize = length($tBufferRead);\n"
"}\n"
"while ($iBufferReadSize < $iSize && !$self->eof());\n"
"\n\n"
"$$rtBuffer .= $tBufferRead;\n"
"\n\n"
"return $iBufferReadSize;\n"
"}\n"
"\n\n\n\n"
"sub write\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"\n\n"
"$self->{bWrite} = true;\n"
"\n\n"
"my $tCipherBuffer;\n"
"\n"
"if (defined($$rtBuffer))\n"
"{\n"
"$tCipherBuffer = $self->{oCipher}->process($$rtBuffer);\n"
"}\n"
"\n\n"
"$self->SUPER::write(\\$tCipherBuffer);\n"
"\n"
"return length($$rtBuffer);\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"if ($self->{oCipher})\n"
"{\n"
"\n"
"if ($self->{bWrite})\n"
"{\n"
"my $tCipherBuffer = $self->{oCipher}->flush();\n"
"$self->SUPER::write(\\$tCipherBuffer);\n"
"}\n"
"\n"
"undef($self->{oCipher});\n"
"\n\n"
"return $self->SUPER::close();\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Filter/Gzip.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::Filter::Gzip;\n"
"use parent 'pgBackRest::Common::Io::Filter';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Compress::Raw::Zlib qw(WANT_GZIP MAX_WBITS Z_OK Z_BUF_ERROR Z_DATA_ERROR Z_STREAM_END);\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Base;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Storage::Base;\n"
"\n\n\n\n"
"use constant STORAGE_FILTER_GZIP => __PACKAGE__;\n"
"push @EXPORT, qw(STORAGE_FILTER_GZIP);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oParent,\n"
"$bWantGzip,\n"
"$strCompressType,\n"
"$iLevel,\n"
"$lCompressBufferMax,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oParent', trace => true},\n"
"{name => 'bWantGzip', optional => true, default => true, trace => true},\n"
"{name => 'strCompressType', optional => true, default => STORAGE_COMPRESS, trace => true},\n"
"{name => 'iLevel', optional => true, default => 6, trace => true},\n"
"{name => 'lCompressBufferMax', optional => true, default => COMMON_IO_BUFFER_MAX, trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($oParent);\n"
"bless $self, $class;\n"
"\n\n"
"$self->{bWantGzip} = $bWantGzip;\n"
"$self->{iLevel} = $iLevel;\n"
"$self->{lCompressBufferMax} = $lCompressBufferMax;\n"
"$self->{strCompressType} = $strCompressType;\n"
"\n\n"
"$self->{bWrite} = false;\n"
"\n\n"
"my $iZLibStatus;\n"
"\n"
"if ($self->{strCompressType} eq STORAGE_COMPRESS)\n"
"{\n"
"($self->{oZLib}, $iZLibStatus) = new Compress::Raw::Zlib::Deflate(\n"
"WindowBits => $self->{bWantGzip} ? WANT_GZIP : MAX_WBITS, Level => $self->{iLevel},\n"
"Bufsize => $self->{lCompressBufferMax}, AppendOutput => 1);\n"
"\n"
"$self->{tCompressedBuffer} = undef;\n"
"}\n"
"else\n"
"{\n"
"($self->{oZLib}, $iZLibStatus) = new Compress::Raw::Zlib::Inflate(\n"
"WindowBits => $self->{bWantGzip} ? WANT_GZIP : MAX_WBITS, Bufsize => $self->{lCompressBufferMax},\n"
"LimitOutput => 1, AppendOutput => 1);\n"
"\n"
"$self->{tUncompressedBuffer} = undef;\n"
"$self->{lUncompressedBufferSize} = 0;\n"
"}\n"
"\n"
"$self->errorCheck($iZLibStatus);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub errorCheck\n"
"{\n"
"my $self = shift;\n"
"my $iZLibStatus = shift;\n"
"\n"
"if (!($iZLibStatus == Z_OK || $iZLibStatus == Z_BUF_ERROR))\n"
"{\n"
"logErrorResult(\n"
"$self->{bWrite} ? ERROR_FILE_WRITE : ERROR_FILE_READ,\n"
"'unable to ' . ($self->{strCompressType} eq STORAGE_COMPRESS ? 'deflate' : 'inflate') . \" '\" .\n"
"$self->parent()->name() . \"'\",\n"
"$self->{oZLib}->msg());\n"
"}\n"
"\n"
"return Z_OK;\n"
"}\n"
"\n\n\n\n"
"sub read\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"my $iSize = shift;\n"
"\n"
"if ($self->{strCompressType} eq STORAGE_COMPRESS)\n"
"{\n"
"return 0 if $self->eof();\n"
"\n"
"my $lSizeBegin = defined($$rtBuffer) ? length($$rtBuffer) : 0;\n"
"my $lUncompressedSize;\n"
"my $lCompressedSize;\n"
"\n"
"do\n"
"{\n"
"my $tUncompressedBuffer;\n"
"$lUncompressedSize = $self->parent()->read(\\$tUncompressedBuffer, $iSize);\n"
"\n"
"if ($lUncompressedSize > 0)\n"
"{\n"
"$self->errorCheck($self->{oZLib}->deflate($tUncompressedBuffer, $$rtBuffer));\n"
"}\n"
"else\n"
"{\n"
"$self->errorCheck($self->{oZLib}->flush($$rtBuffer));\n"
"}\n"
"\n"
"$lCompressedSize = length($$rtBuffer) - $lSizeBegin;\n"
"}\n"
"while ($lUncompressedSize > 0 && $lCompressedSize < $iSize);\n"
"\n\n"
"return $lCompressedSize;\n"
"}\n"
"else\n"
"{\n"
"\n"
"while ($self->{lUncompressedBufferSize} < $iSize && !$self->parent()->eof())\n"
"{\n"
"if (!defined($self->{tCompressedBuffer}) || length($self->{tCompressedBuffer}) == 0)\n"
"{\n"
"$self->parent()->read(\\$self->{tCompressedBuffer}, $self->{lCompressBufferMax});\n"
"}\n"
"\n"
"my $iZLibStatus = $self->{oZLib}->inflate($self->{tCompressedBuffer}, $self->{tUncompressedBuffer});\n"
"$self->{lUncompressedBufferSize} = length($self->{tUncompressedBuffer});\n"
"\n"
"last if $iZLibStatus == Z_STREAM_END;\n"
"\n"
"$self->errorCheck($iZLibStatus);\n"
"}\n"
"\n\n\n"
"my $iActualSize = $self->{lUncompressedBufferSize} < $iSize ? $self->{lUncompressedBufferSize} : $iSize;\n"
"\n\n"
"$$rtBuffer .= substr($self->{tUncompressedBuffer}, 0, $iActualSize);\n"
"\n\n"
"$self->{tUncompressedBuffer} = substr($self->{tUncompressedBuffer}, $iActualSize);\n"
"$self->{lUncompressedBufferSize} -= $iActualSize;\n"
"\n\n"
"return $iActualSize;\n"
"}\n"
"}\n"
"\n\n\n\n"
"sub write\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"\n"
"$self->{bWrite} = true;\n"
"\n"
"if ($self->{strCompressType} eq STORAGE_COMPRESS)\n"
"{\n"
"\n"
"$self->errorCheck($self->{oZLib}->deflate($$rtBuffer, $self->{tCompressedBuffer}));\n"
"\n\n"
"if (length($self->{tCompressedBuffer}) > $self->{lCompressBufferMax})\n"
"{\n"
"$self->parent()->write(\\$self->{tCompressedBuffer});\n"
"$self->{tCompressedBuffer} = undef;\n"
"}\n"
"}\n"
"else\n"
"{\n"
"my $tCompressedBuffer = $$rtBuffer;\n"
"\n"
"while (length($tCompressedBuffer) > 0)\n"
"{\n"
"my $tUncompressedBuffer;\n"
"\n"
"my $iZLibStatus = $self->{oZLib}->inflate($tCompressedBuffer, $tUncompressedBuffer);\n"
"$self->parent()->write(\\$tUncompressedBuffer);\n"
"\n"
"last if $iZLibStatus == Z_STREAM_END;\n"
"\n"
"$self->errorCheck($iZLibStatus);\n"
"}\n"
"}\n"
"\n\n"
"return length($$rtBuffer);\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n"
"if (defined($self->{oZLib}))\n"
"{\n"
"\n"
"if ($self->{bWrite})\n"
"{\n"
"if ($self->{strCompressType} eq STORAGE_COMPRESS)\n"
"{\n"
"\n"
"$self->errorCheck($self->{oZLib}->flush($self->{tCompressedBuffer}));\n"
"\n\n"
"$self->parent()->write(\\$self->{tCompressedBuffer});\n"
"}\n"
"}\n"
"\n"
"undef($self->{oZLib});\n"
"\n\n"
"return $self->parent()->close();\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Filter/Sha.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::Filter::Sha;\n"
"use parent 'pgBackRest::Common::Io::Filter';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"use constant STORAGE_FILTER_SHA => __PACKAGE__;\n"
"push @EXPORT, qw(STORAGE_FILTER_SHA);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oParent,\n"
"$strAlgorithm,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oParent', trace => true},\n"
"{name => 'strAlgorithm', optional => true, default => 'sha1', trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new($oParent);\n"
"bless $self, $class;\n"
"\n\n"
"$self->{strAlgorithm} = $strAlgorithm;\n"
"\n\n"
"$self->{oSha} = new pgBackRest::LibC::Crypto::Hash($self->{strAlgorithm});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub read\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"my $iSize = shift;\n"
"\n\n"
"my $tShaBuffer;\n"
"my $iActualSize = $self->parent()->read(\\$tShaBuffer, $iSize);\n"
"\n\n"
"if ($iActualSize > 0)\n"
"{\n"
"$self->{oSha}->process($tShaBuffer);\n"
"$$rtBuffer .= $tShaBuffer;\n"
"}\n"
"\n\n"
"return $iActualSize;\n"
"}\n"
"\n\n\n\n"
"sub write\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"\n\n"
"$self->{oSha}->process($$rtBuffer);\n"
"\n\n"
"return $self->parent()->write($rtBuffer);\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n"
"if (defined($self->{oSha}))\n"
"{\n"
"\n"
"$self->resultSet(STORAGE_FILTER_SHA, $self->{oSha}->result());\n"
"\n\n"
"delete($self->{oSha});\n"
"\n\n"
"return $self->parent->close();\n"
"}\n"
"\n"
"return false;\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Helper.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::Helper;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(basename);\n"
"\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Storage::Posix::Driver;\n"
"use pgBackRest::Storage::Local;\n"
"use pgBackRest::Version;\n"
"\n\n\n\n"
"use constant STORAGE_LOCAL => '<LOCAL>';\n"
"push @EXPORT, qw(STORAGE_LOCAL);\n"
"\n\n\n\n"
"use constant COMPRESS_EXT => 'gz';\n"
"push @EXPORT, qw(COMPRESS_EXT);\n"
"\n\n\n\n"
"use constant STORAGE_TEMP_EXT => PROJECT_EXE . '.tmp';\n"
"push @EXPORT, qw(STORAGE_TEMP_EXT);\n"
"\n\n\n\n"
"my $hStorage;\n"
"\n\n\n\n\n\n\n"
"sub storageLocal\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::storageLocal', \\@_,\n"
"{name => 'strPath', default => '/', trace => true},\n"
");\n"
"\n\n"
"if (!defined($hStorage->{&STORAGE_LOCAL}{$strPath}))\n"
"{\n"
"\n"
"$hStorage->{&STORAGE_LOCAL}{$strPath} = new pgBackRest::Storage::Local(\n"
"$strPath, new pgBackRest::Storage::Posix::Driver(),\n"
"{strTempExtension => STORAGE_TEMP_EXT,\n"
"lBufferMax => cfgOptionValid(CFGOPT_BUFFER_SIZE, false) ? cfgOption(CFGOPT_BUFFER_SIZE, false) : undef});\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oStorageLocal', value => $hStorage->{&STORAGE_LOCAL}{$strPath}, trace => true},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(storageLocal);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Local.pm",
.data =
"\n\n\n\n\n"
"package pgBackRest::Storage::Local;\n"
"use parent 'pgBackRest::Storage::Base';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Filter::Sha;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathBase,\n"
"$oDriver,\n"
"$hRule,\n"
"$bAllowTemp,\n"
"$strTempExtension,\n"
"$strDefaultPathMode,\n"
"$strDefaultFileMode,\n"
"$lBufferMax,\n"
"$strCipherType,\n"
"$strCipherPassUser,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strPathBase'},\n"
"{name => 'oDriver'},\n"
"{name => 'hRule', optional => true},\n"
"{name => 'bAllowTemp', optional => true, default => true},\n"
"{name => 'strTempExtension', optional => true, default => 'tmp'},\n"
"{name => 'strDefaultPathMode', optional => true, default => '0750'},\n"
"{name => 'strDefaultFileMode', optional => true, default => '0640'},\n"
"{name => 'lBufferMax', optional => true},\n"
"{name => 'strCipherType', optional => true},\n"
"{name => 'strCipherPassUser', optional => true, redact => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new({lBufferMax => $lBufferMax});\n"
"bless $self, $class;\n"
"\n"
"$self->{strPathBase} = $strPathBase;\n"
"$self->{oDriver} = $oDriver;\n"
"$self->{hRule} = $hRule;\n"
"$self->{bAllowTemp} = $bAllowTemp;\n"
"$self->{strTempExtension} = $strTempExtension;\n"
"$self->{strDefaultPathMode} = $strDefaultPathMode;\n"
"$self->{strDefaultFileMode} = $strDefaultFileMode;\n"
"$self->{strCipherType} = $strCipherType;\n"
"$self->{strCipherPassUser} = $strCipherPassUser;\n"
"\n"
"if (defined($self->{strCipherType}))\n"
"{\n"
"require pgBackRest::Storage::Filter::CipherBlock;\n"
"pgBackRest::Storage::Filter::CipherBlock->import();\n"
"}\n"
"\n\n"
"$self->driver()->tempExtensionSet($self->{strTempExtension}) if $self->driver()->can('tempExtensionSet');\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub exists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFileExp,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->exists', \\@_,\n"
"{name => 'strFileExp'},\n"
");\n"
"\n\n"
"my $bExists = $self->driver()->exists($self->pathGet($strFileExp));\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bExists', value => $bExists}\n"
");\n"
"}\n"
"\n\n\n\n\n"
"sub hashSize\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$xFileExp,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->hashSize', \\@_,\n"
"{name => 'xFileExp'},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
");\n"
"\n\n"
"my $strHash;\n"
"my $lSize;\n"
"\n\n"
"my $oFileIo =\n"
"defined($xFileExp) ? (ref($xFileExp) ? $xFileExp :\n"
"$self->openRead($self->pathGet($xFileExp), {bIgnoreMissing => $bIgnoreMissing})) : undef;\n"
"\n"
"if (defined($oFileIo))\n"
"{\n"
"$lSize = 0;\n"
"my $oShaIo = new pgBackRest::Storage::Filter::Sha($oFileIo);\n"
"my $lSizeRead;\n"
"\n"
"do\n"
"{\n"
"my $tContent;\n"
"$lSizeRead = $oShaIo->read(\\$tContent, $self->{lBufferMax});\n"
"$lSize += $lSizeRead;\n"
"}\n"
"while ($lSizeRead != 0);\n"
"\n\n"
"$oShaIo->close();\n"
"\n\n"
"$strHash = $oShaIo->result(STORAGE_FILTER_SHA);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strHash', value => $strHash},\n"
"{name => 'lSize', value => $lSize}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub info\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathFileExp,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::fileStat', \\@_,\n"
"{name => 'strPathFileExp'},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
");\n"
"\n\n"
"my $oInfo = $self->driver()->info($self->pathGet($strPathFileExp), {bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oInfo', value => $oInfo, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub linkCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strSourcePathFileExp,\n"
"$strDestinationLinkExp,\n"
"$bHard,\n"
"$bRelative,\n"
"$bPathCreate,\n"
"$bIgnoreExists,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->linkCreate', \\@_,\n"
"{name => 'strSourcePathFileExp'},\n"
"{name => 'strDestinationLinkExp'},\n"
"{name => 'bHard', optional=> true, default => false},\n"
"{name => 'bRelative', optional=> true, default => false},\n"
"{name => 'bPathCreate', optional=> true, default => true},\n"
"{name => 'bIgnoreExists', optional => true, default => false},\n"
");\n"
"\n\n"
"my $strSourcePathFile = $self->pathGet($strSourcePathFileExp);\n"
"my $strDestinationLink = $self->pathGet($strDestinationLinkExp);\n"
"\n\n"
"if ($bRelative)\n"
"{\n"
"\n"
"my @strySource = split('/', $strSourcePathFile);\n"
"my @stryDestination = split('/', $strDestinationLink);\n"
"\n"
"while (defined($strySource[0]) && defined($stryDestination[0]) && $strySource[0] eq $stryDestination[0])\n"
"{\n"
"shift(@strySource);\n"
"shift(@stryDestination);\n"
"}\n"
"\n\n"
"$strSourcePathFile = '';\n"
"\n"
"for (my $iIndex = 0; $iIndex < @stryDestination - 1; $iIndex++)\n"
"{\n"
"$strSourcePathFile .= '../';\n"
"}\n"
"\n\n"
"$strSourcePathFile .= join('/', @strySource);\n"
"\n"
"logDebugMisc\n"
"(\n"
"$strOperation, 'apply relative path',\n"
"{name => 'strSourcePathFile', value => $strSourcePathFile, trace => true}\n"
");\n"
"}\n"
"\n\n"
"$self->driver()->linkCreate(\n"
"$strSourcePathFile, $strDestinationLink, {bHard => $bHard, bPathCreate => $bPathCreate, bIgnoreExists => $bIgnoreExists});\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub list\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
"$strExpression,\n"
"$strSortOrder,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->list', \\@_,\n"
"{name => 'strPathExp', required => false},\n"
"{name => 'strExpression', optional => true},\n"
"{name => 'strSortOrder', optional => true, default => 'forward'},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
");\n"
"\n\n"
"my $rstryFileList = $self->driver()->list(\n"
"$self->pathGet($strPathExp), {strExpression => $strExpression, bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n"
"if (defined($strExpression))\n"
"{\n"
"@{$rstryFileList} = grep(/$strExpression/i, @{$rstryFileList});\n"
"}\n"
"\n\n"
"if ($strSortOrder eq 'reverse')\n"
"{\n"
"@{$rstryFileList} = sort {$b cmp $a} @{$rstryFileList};\n"
"}\n"
"\n"
"else\n"
"{\n"
"@{$rstryFileList} = sort @{$rstryFileList};\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryFileList', value => $rstryFileList}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub manifest\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
"$strFilter,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->manifest', \\@_,\n"
"{name => 'strPathExp'},\n"
"{name => 'strFilter', optional => true, trace => true},\n"
");\n"
"\n"
"my $hManifest = $self->driver()->manifest($self->pathGet($strPathExp), {strFilter => $strFilter});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hManifest', value => $hManifest, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub move\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strSourcePathFileExp,\n"
"$strDestinationPathFileExp,\n"
"$bPathCreate,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->move', \\@_,\n"
"{name => 'strSourcePathExp'},\n"
"{name => 'strDestinationPathExp'},\n"
"{name => 'bPathCreate', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"$self->driver()->move(\n"
"$self->pathGet($strSourcePathFileExp), $self->pathGet($strDestinationPathFileExp), {bPathCreate => $bPathCreate});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation\n"
");\n"
"}\n"
"\n\n\n\n"
"sub openRead\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$xFileExp,\n"
"$bIgnoreMissing,\n"
"$rhyFilter,\n"
"$strCipherPass,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->openRead', \\@_,\n"
"{name => 'xFileExp'},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
"{name => 'rhyFilter', optional => true},\n"
"{name => 'strCipherPass', optional => true, redact => true},\n"
");\n"
"\n\n"
"my $oFileIo = $self->driver()->openRead($self->pathGet($xFileExp), {bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n"
"if (defined($oFileIo))\n"
"{\n"
"\n\n"
"if (defined($self->cipherType()))\n"
"{\n"
"$oFileIo = &STORAGE_FILTER_CIPHER_BLOCK->new(\n"
"$oFileIo, $self->cipherType(), defined($strCipherPass) ? $strCipherPass : $self->cipherPassUser(),\n"
"{strMode => STORAGE_DECRYPT});\n"
"}\n"
"\n\n"
"if (defined($rhyFilter))\n"
"{\n"
"foreach my $rhFilter (@{$rhyFilter})\n"
"{\n"
"$oFileIo = $rhFilter->{strClass}->new($oFileIo, @{$rhFilter->{rxyParam}});\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oFileIo', value => $oFileIo, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub openWrite\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$xFileExp,\n"
"$strMode,\n"
"$strUser,\n"
"$strGroup,\n"
"$lTimestamp,\n"
"$bAtomic,\n"
"$bPathCreate,\n"
"$rhyFilter,\n"
"$strCipherPass,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->openWrite', \\@_,\n"
"{name => 'xFileExp'},\n"
"{name => 'strMode', optional => true, default => $self->{strDefaultFileMode}},\n"
"{name => 'strUser', optional => true},\n"
"{name => 'strGroup', optional => true},\n"
"{name => 'lTimestamp', optional => true},\n"
"{name => 'bAtomic', optional => true, default => false},\n"
"{name => 'bPathCreate', optional => true, default => false},\n"
"{name => 'rhyFilter', optional => true},\n"
"{name => 'strCipherPass', optional => true, redact => true},\n"
");\n"
"\n\n"
"my $oFileIo = $self->driver()->openWrite($self->pathGet($xFileExp),\n"
"{strMode => $strMode, strUser => $strUser, strGroup => $strGroup, lTimestamp => $lTimestamp, bPathCreate => $bPathCreate,\n"
"bAtomic => $bAtomic});\n"
"\n\n"
"if (defined($self->cipherType()))\n"
"{\n"
"$oFileIo = &STORAGE_FILTER_CIPHER_BLOCK->new(\n"
"$oFileIo, $self->cipherType(), defined($strCipherPass) ? $strCipherPass : $self->cipherPassUser());\n"
"}\n"
"\n\n"
"if (defined($rhyFilter))\n"
"{\n"
"foreach my $rhFilter (reverse(@{$rhyFilter}))\n"
"{\n"
"$oFileIo = $rhFilter->{strClass}->new($oFileIo, @{$rhFilter->{rxyParam}});\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oFileIo', value => $oFileIo, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub owner\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathFileExp,\n"
"$strUser,\n"
"$strGroup\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->owner', \\@_,\n"
"{name => 'strPathFileExp'},\n"
"{name => 'strUser', required => false},\n"
"{name => 'strGroup', required => false}\n"
");\n"
"\n\n"
"$self->driver()->owner($self->pathGet($strPathFileExp), {strUser => $strUser, strGroup => $strGroup});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
"$strMode,\n"
"$bIgnoreExists,\n"
"$bCreateParent,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathCreate', \\@_,\n"
"{name => 'strPathExp'},\n"
"{name => 'strMode', optional => true, default => $self->{strDefaultPathMode}},\n"
"{name => 'bIgnoreExists', optional => true, default => false},\n"
"{name => 'bCreateParent', optional => true, default => false},\n"
");\n"
"\n\n"
"$self->driver()->pathCreate(\n"
"$self->pathGet($strPathExp), {strMode => $strMode, bIgnoreExists => $bIgnoreExists, bCreateParent => $bCreateParent});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathExists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathExists', \\@_,\n"
"{name => 'strPathExp'},\n"
");\n"
"\n\n"
"my $bExists = $self->driver()->pathExists($self->pathGet($strPathExp));\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bExists', value => $bExists}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
"$bTemp,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathGet', \\@_,\n"
"{name => 'strPathExp', required => false, trace => true},\n"
"{name => 'bTemp', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my $strPath;\n"
"my $strFile;\n"
"\n\n"
"my $bAbsolute = false;\n"
"\n"
"if (defined($strPathExp) && index($strPathExp, qw(/)) == 0)\n"
"{\n"
"$bAbsolute = true;\n"
"$strPath = $strPathExp;\n"
"}\n"
"else\n"
"{\n"
"\n"
"if (defined($strPathExp) && index($strPathExp, qw(<)) == 0)\n"
"{\n"
"\n"
"my $iPos = index($strPathExp, qw(>));\n"
"\n"
"if ($iPos == -1)\n"
"{\n"
"confess &log(ASSERT, \"found < but not > in '${strPathExp}'\");\n"
"}\n"
"\n"
"my $strType = substr($strPathExp, 0, $iPos + 1);\n"
"\n\n"
"if ($iPos < length($strPathExp) - 1)\n"
"{\n"
"$strFile = substr($strPathExp, $iPos + 2);\n"
"}\n"
"\n\n"
"if (!defined($self->{hRule}->{$strType}))\n"
"{\n"
"confess &log(ASSERT, \"storage rule '${strType}' does not exist\");\n"
"}\n"
"\n\n"
"if (ref($self->{hRule}->{$strType}))\n"
"{\n"
"$strPath = $self->pathBase();\n"
"$strFile = $self->{hRule}{$strType}{fnRule}->($strType, $strFile, $self->{hRule}{$strType}{xData});\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strPath = $self->pathBase() . ($self->pathBase() =~ /\\/$/ ? '' : qw{/}) . $self->{hRule}->{$strType};\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strPath = $self->pathBase();\n"
"$strFile = $strPathExp;\n"
"}\n"
"}\n"
"\n\n"
"if ($bTemp)\n"
"{\n"
"\n"
"if (!$self->{bAllowTemp})\n"
"{\n"
"confess &log(ASSERT, \"temp file not supported for storage '\" . $self->pathBase() . \"'\");\n"
"}\n"
"\n\n"
"if (!$bAbsolute)\n"
"{\n"
"if (!defined($strFile))\n"
"{\n"
"confess &log(ASSERT, 'file part must be defined when temp file specified');\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"$strPath .= defined($strFile) ? ($strPath =~ /\\/$/ ? '' : qw{/}) . \"${strFile}\" : '';\n"
"\n\n"
"$strPath .= $bTemp ? \".$self->{strTempExtension}\" : '';\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strPath', value => $strPath, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathSync\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathExp,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathSync', \\@_,\n"
"{name => 'strPathExp'},\n"
");\n"
"\n"
"$self->driver()->pathSync($self->pathGet($strPathExp));\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub remove\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$xstryPathFileExp,\n"
"$bIgnoreMissing,\n"
"$bRecurse,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->remove', \\@_,\n"
"{name => 'xstryPathFileExp'},\n"
"{name => 'bIgnoreMissing', optional => true, default => true},\n"
"{name => 'bRecurse', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my @stryPathFileExp;\n"
"\n"
"if (ref($xstryPathFileExp))\n"
"{\n"
"foreach my $strPathFileExp (@{$xstryPathFileExp})\n"
"{\n"
"push(@stryPathFileExp, $self->pathGet($strPathFileExp));\n"
"}\n"
"}\n"
"\n\n"
"my $bRemoved = $self->driver()->remove(\n"
"ref($xstryPathFileExp) ? \\@stryPathFileExp : $self->pathGet($xstryPathFileExp),\n"
"{bIgnoreMissing => $bIgnoreMissing, bRecurse => $bRecurse});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bRemoved', value => $bRemoved}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub encrypted\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFileName,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->encrypted', \\@_,\n"
"{name => 'strFileName'},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
");\n"
"\n"
"my $tMagicSignature;\n"
"my $bEncrypted = false;\n"
"\n\n"
"my $oFile = $self->driver()->openRead($self->pathGet($strFileName), {bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n\n"
"if (!defined($oFile))\n"
"{\n"
"if (defined($self->{strCipherType}))\n"
"{\n"
"$bEncrypted = true;\n"
"}\n"
"}\n"
"else\n"
"{\n"
"\n"
"my $lSizeRead = $oFile->read(\\$tMagicSignature, length(CIPHER_MAGIC));\n"
"\n\n"
"$oFile->close();\n"
"\n\n\n"
"if (($lSizeRead > 0) && substr($tMagicSignature, 0, length(CIPHER_MAGIC)) eq CIPHER_MAGIC)\n"
"{\n"
"$bEncrypted = true;\n"
"}\n"
"\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bEncrypted', value => $bEncrypted}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub encryptionValid\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$bEncrypted,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->encryptionValid', \\@_,\n"
"{name => 'bEncrypted'},\n"
");\n"
"\n"
"my $bValid = true;\n"
"\n\n"
"if ($bEncrypted)\n"
"{\n"
"if (!defined($self->{strCipherType}))\n"
"{\n"
"$bValid = false;\n"
"}\n"
"}\n"
"else\n"
"{\n"
"if (defined($self->{strCipherType}))\n"
"{\n"
"$bValid = false;\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bValid', value => $bValid}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathBase {shift->{strPathBase}}\n"
"sub driver {shift->{oDriver}}\n"
"sub cipherType {shift->{strCipherType}}\n"
"sub cipherPassUser {shift->{strCipherPassUser}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Posix/Driver.pm",
.data =
"\n\n\n\n\n"
"package pgBackRest::Storage::Posix::Driver;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use File::Basename qw(basename dirname);\n"
"use Fcntl qw(:mode);\n"
"use File::stat qw{lstat};\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::Posix::FileRead;\n"
"use pgBackRest::Storage::Posix::FileWrite;\n"
"\n\n\n\n"
"use constant STORAGE_POSIX_DRIVER => __PACKAGE__;\n"
"push @EXPORT, qw(STORAGE_POSIX_DRIVER);\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{bFileSync},\n"
"$self->{bPathSync},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'bFileSync', optional => true, default => true},\n"
"{name => 'bPathSync', optional => true, default => true},\n"
");\n"
"\n\n"
"$self->{strTempExtension} = 'tmp';\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub exists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->exists', \\@_,\n"
"{name => 'strFile', trace => true},\n"
");\n"
"\n\n"
"my $bExists = true;\n"
"my $oStat = lstat($strFile);\n"
"\n\n"
"if (defined($oStat))\n"
"{\n"
"\n"
"$bExists = !S_ISDIR($oStat->mode) ? true : false;\n"
"}\n"
"else\n"
"{\n"
"\n"
"if (!$OS_ERROR{ENOENT})\n"
"{\n"
"logErrorResult(ERROR_FILE_EXISTS, \"unable to test if file '${strFile}' exists\", $OS_ERROR);\n"
"}\n"
"\n"
"$bExists = false;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bExists', value => $bExists, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub info\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathFile,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->info', \\@_,\n"
"{name => 'strFile', trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my $oInfo = lstat($strPathFile);\n"
"\n\n"
"if (!defined($oInfo))\n"
"{\n"
"if (!($OS_ERROR{ENOENT} && $bIgnoreMissing))\n"
"{\n"
"logErrorResult($OS_ERROR{ENOENT} ? ERROR_FILE_MISSING : ERROR_FILE_OPEN, \"unable to stat '${strPathFile}'\", $OS_ERROR);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oInfo', value => $oInfo, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub linkCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strSourcePathFile,\n"
"$strDestinationLink,\n"
"$bHard,\n"
"$bPathCreate,\n"
"$bIgnoreExists,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->linkCreate', \\@_,\n"
"{name => 'strSourcePathFile', trace => true},\n"
"{name => 'strDestinationLink', trace => true},\n"
"{name => 'bHard', optional=> true, default => false, trace => true},\n"
"{name => 'bPathCreate', optional=> true, default => true, trace => true},\n"
"{name => 'bIgnoreExists', optional => true, default => false, trace => true},\n"
");\n"
"\n"
"if (!($bHard ? link($strSourcePathFile, $strDestinationLink) : symlink($strSourcePathFile, $strDestinationLink)))\n"
"{\n"
"my $strMessage = \"unable to create link '${strDestinationLink}'\";\n"
"\n\n"
"if ($OS_ERROR{ENOENT})\n"
"{\n"
"\n"
"if (!$self->exists($strSourcePathFile))\n"
"{\n"
"confess &log(ERROR, \"${strMessage} because source '${strSourcePathFile}' does not exist\", ERROR_FILE_MISSING);\n"
"}\n"
"\n"
"if (!$bPathCreate)\n"
"{\n"
"confess &log(ERROR, \"${strMessage} because parent does not exist\", ERROR_PATH_MISSING);\n"
"}\n"
"\n\n"
"$self->pathCreate(dirname($strDestinationLink), {bIgnoreExists => true, bCreateParent => true});\n"
"\n\n"
"$self->linkCreate($strSourcePathFile, $strDestinationLink, {bHard => $bHard});\n"
"}\n"
"\n"
"elsif ($OS_ERROR{EEXIST})\n"
"{\n"
"if (!$bIgnoreExists)\n"
"{\n"
"confess &log(ERROR, \"${strMessage} because it already exists\", ERROR_PATH_EXISTS);\n"
"}\n"
"}\n"
"else\n"
"{\n"
"logErrorResult(ERROR_PATH_CREATE, ${strMessage}, $OS_ERROR);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub linkDestination\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strLink,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->linkDestination', \\@_,\n"
"{name => 'strLink', trace => true},\n"
");\n"
"\n\n"
"my $strLinkDestination = readlink($strLink);\n"
"\n\n"
"if (!defined($strLinkDestination))\n"
"{\n"
"logErrorResult(\n"
"$OS_ERROR{ENOENT} ? ERROR_FILE_MISSING : ERROR_FILE_OPEN, \"unable to get destination for link ${strLink}\", $OS_ERROR);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strLinkDestination', value => $strLinkDestination, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub list\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->list', \\@_,\n"
"{name => 'strPath', trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my @stryFileList;\n"
"my $hPath;\n"
"\n\n"
"if (opendir($hPath, $strPath))\n"
"{\n"
"@stryFileList = grep(!/^(\\.)|(\\.\\.)$/i, readdir($hPath));\n"
"close($hPath);\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if (!($OS_ERROR{ENOENT} && $bIgnoreMissing))\n"
"{\n"
"logErrorResult($OS_ERROR{ENOENT} ? ERROR_FILE_MISSING : ERROR_FILE_OPEN, \"unable to read path '${strPath}'\", $OS_ERROR);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryFileList', value => \\@stryFileList, ref => true, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub manifest\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
"$bIgnoreMissing,\n"
"$strFilter,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->manifest', \\@_,\n"
"{name => 'strPath', trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
"{name => 'strFilter', optional => true, trace => true},\n"
");\n"
"\n\n"
"my $hManifest = {};\n"
"$self->manifestRecurse($strPath, undef, 0, $hManifest, $bIgnoreMissing, $strFilter);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hManifest', value => $hManifest, trace => true}\n"
");\n"
"}\n"
"\n"
"sub manifestRecurse\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
"$strSubPath,\n"
"$iDepth,\n"
"$hManifest,\n"
"$bIgnoreMissing,\n"
"$strFilter,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::manifestRecurse', \\@_,\n"
"{name => 'strPath', trace => true},\n"
"{name => 'strSubPath', required => false, trace => true},\n"
"{name => 'iDepth', default => 0, trace => true},\n"
"{name => 'hManifest', required => false, trace => true},\n"
"{name => 'bIgnoreMissing', required => false, default => false, trace => true},\n"
"{name => 'strFilter', required => false, trace => true},\n"
");\n"
"\n\n"
"my $strPathRead = $strPath . (defined($strSubPath) ? \"/${strSubPath}\" : '');\n"
"my $hPath;\n"
"\n\n"
"my $oPathInfo = $self->info($strPathRead, {bIgnoreMissing => $bIgnoreMissing});\n"
"\n"
"if (defined($oPathInfo))\n"
"{\n"
"\n"
"if ($iDepth == 0 && !S_ISDIR($oPathInfo->mode()))\n"
"{\n"
"$hManifest->{basename($strPathRead)} = $self->manifestStat($strPathRead);\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"my @stryFileList = @{$self->list($strPathRead, {bIgnoreMissing => $iDepth != 0})};\n"
"unshift(@stryFileList, '.');\n"
"my $hFileStat = $self->manifestList($strPathRead, \\@stryFileList, $strFilter);\n"
"\n\n"
"foreach my $strFile (keys(%{$hFileStat}))\n"
"{\n"
"my $strManifestFile = $iDepth == 0 ? $strFile : ($strSubPath . ($strFile eq qw(.) ? '' : \"/${strFile}\"));\n"
"$hManifest->{$strManifestFile} = $hFileStat->{$strFile};\n"
"\n\n"
"if ($hManifest->{$strManifestFile}{type} eq 'd' && $strFile ne qw(.))\n"
"{\n"
"$self->manifestRecurse($strPath, $strManifestFile, $iDepth + 1, $hManifest);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n"
"sub manifestList\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
"$stryFile,\n"
"$strFilter,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->manifestList', \\@_,\n"
"{name => 'strPath', trace => true},\n"
"{name => 'stryFile', trace => true},\n"
"{name => 'strFilter', required => false, trace => true},\n"
");\n"
"\n"
"my $hFileStat = {};\n"
"\n"
"foreach my $strFile (@{$stryFile})\n"
"{\n"
"if ($strFile ne '.' && defined($strFilter) && $strFilter ne $strFile)\n"
"{\n"
"next;\n"
"}\n"
"\n"
"$hFileStat->{$strFile} = $self->manifestStat(\"${strPath}\" . ($strFile eq qw(.) ? '' : \"/${strFile}\"));\n"
"\n"
"if (!defined($hFileStat->{$strFile}))\n"
"{\n"
"delete($hFileStat->{$strFile});\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hFileStat', value => $hFileStat, trace => true}\n"
");\n"
"}\n"
"\n"
"sub manifestStat\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->manifestStat', \\@_,\n"
"{name => 'strFile', trace => true},\n"
");\n"
"\n\n"
"my $oStat = $self->info($strFile, {bIgnoreMissing => true});\n"
"\n\n"
"my $hFile;\n"
"\n"
"if (defined($oStat))\n"
"{\n"
"\n"
"if (S_ISREG($oStat->mode))\n"
"{\n"
"$hFile->{type} = 'f';\n"
"\n\n"
"$hFile->{size} = $oStat->size;\n"
"\n\n"
"$hFile->{modification_time} = $oStat->mtime;\n"
"}\n"
"\n"
"elsif (S_ISDIR($oStat->mode))\n"
"{\n"
"$hFile->{type} = 'd';\n"
"}\n"
"\n"
"elsif (S_ISLNK($oStat->mode))\n"
"{\n"
"$hFile->{type} = 'l';\n"
"$hFile->{link_destination} = $self->linkDestination($strFile);\n"
"}\n"
"\n"
"else\n"
"{\n"
"confess &log(ERROR, \"${strFile} is not of type directory, file, or link\", ERROR_FILE_INVALID);\n"
"}\n"
"\n\n"
"$hFile->{user} = getpwuid($oStat->uid);\n"
"\n\n"
"$hFile->{group} = getgrgid($oStat->gid);\n"
"\n\n"
"if ($hFile->{type} ne 'l')\n"
"{\n"
"$hFile->{mode} = sprintf('%04o', S_IMODE($oStat->mode));\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hFile', value => $hFile, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub move\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strSourceFile,\n"
"$strDestinationFile,\n"
"$bPathCreate,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->move', \\@_,\n"
"{name => 'strSourceFile', trace => true},\n"
"{name => 'strDestinationFile', trace => true},\n"
"{name => 'bPathCreate', default => false, trace => true},\n"
");\n"
"\n\n"
"my $strSourcePathFile = dirname($strSourceFile);\n"
"my $strDestinationPathFile = dirname($strDestinationFile);\n"
"\n\n"
"if (!rename($strSourceFile, $strDestinationFile))\n"
"{\n"
"my $strMessage = \"unable to move '${strSourceFile}'\";\n"
"\n\n"
"if ($OS_ERROR{ENOENT})\n"
"{\n"
"if (!$self->exists($strSourceFile))\n"
"{\n"
"logErrorResult(ERROR_FILE_MISSING, \"${strMessage} because it is missing\");\n"
"}\n"
"\n"
"if ($bPathCreate)\n"
"{\n"
"\n"
"$self->pathCreate($strDestinationPathFile, {bCreateParent => true, bIgnoreExists => true});\n"
"\n\n"
"$self->move($strSourceFile, $strDestinationFile);\n"
"}\n"
"else\n"
"{\n"
"logErrorResult(ERROR_PATH_MISSING, \"${strMessage} to missing path '${strDestinationPathFile}'\");\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"logErrorResult(ERROR_FILE_MOVE, \"${strMessage} to '${strDestinationFile}'\", $OS_ERROR);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub openRead\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFile,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->openRead', \\@_,\n"
"{name => 'strFile', trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
");\n"
"\n"
"my $oFileIO = new pgBackRest::Storage::Posix::FileRead($self, $strFile, {bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oFileIO', value => $oFileIO, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub openWrite\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFile,\n"
"$strMode,\n"
"$strUser,\n"
"$strGroup,\n"
"$lTimestamp,\n"
"$bPathCreate,\n"
"$bAtomic,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->openWrite', \\@_,\n"
"{name => 'strFile', trace => true},\n"
"{name => 'strMode', optional => true, trace => true},\n"
"{name => 'strUser', optional => true, trace => true},\n"
"{name => 'strGroup', optional => true, trace => true},\n"
"{name => 'lTimestamp', optional => true, trace => true},\n"
"{name => 'bPathCreate', optional => true, trace => true},\n"
"{name => 'bAtomic', optional => true, trace => true},\n"
");\n"
"\n"
"my $oFileIO = new pgBackRest::Storage::Posix::FileWrite(\n"
"$self, $strFile,\n"
"{strMode => $strMode, strUser => $strUser, strGroup => $strGroup, lTimestamp => $lTimestamp, bPathCreate => $bPathCreate,\n"
"bAtomic => $bAtomic, bSync => $self->{bFileSync}});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oFileIO', value => $oFileIO, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub owner\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFilePath,\n"
"$strUser,\n"
"$strGroup,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->owner', \\@_,\n"
"{name => 'strFilePath', trace => true},\n"
"{name => 'strUser', optional => true, trace => true},\n"
"{name => 'strGroup', optional => true, trace => true},\n"
");\n"
"\n\n"
"if (defined($strUser) || defined($strGroup))\n"
"{\n"
"my $strMessage = \"unable to set ownership for '${strFilePath}'\";\n"
"my $iUserId;\n"
"my $iGroupId;\n"
"\n\n\n"
"my $oStat = $self->info($strFilePath);\n"
"\n"
"if (!defined($strUser))\n"
"{\n"
"$iUserId = $oStat->uid;\n"
"}\n"
"\n"
"if (!defined($strGroup))\n"
"{\n"
"$iGroupId = $oStat->gid;\n"
"}\n"
"\n\n"
"if (defined($strUser))\n"
"{\n"
"$iUserId = getpwnam($strUser);\n"
"\n"
"if (!defined($iUserId))\n"
"{\n"
"logErrorResult(ERROR_FILE_OWNER, \"${strMessage} because user '${strUser}' does not exist\");\n"
"}\n"
"}\n"
"\n\n"
"if (defined($strGroup))\n"
"{\n"
"$iGroupId = getgrnam($strGroup);\n"
"\n"
"if (!defined($iGroupId))\n"
"{\n"
"logErrorResult(ERROR_FILE_OWNER, \"${strMessage} because group '${strGroup}' does not exist\");\n"
"}\n"
"}\n"
"\n\n"
"if ($iUserId != $oStat->uid || $iGroupId != $oStat->gid)\n"
"{\n"
"if (!chown($iUserId, $iGroupId, $strFilePath))\n"
"{\n"
"logErrorResult(ERROR_FILE_OWNER, \"${strMessage}\", $OS_ERROR);\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub pathCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
"$strMode,\n"
"$bIgnoreExists,\n"
"$bCreateParent,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathCreate', \\@_,\n"
"{name => 'strPath', trace => true},\n"
"{name => 'strMode', optional => true, default => '0750', trace => true},\n"
"{name => 'bIgnoreExists', optional => true, default => false, trace => true},\n"
"{name => 'bCreateParent', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"if (!mkdir($strPath, oct($strMode)))\n"
"{\n"
"my $strMessage = \"unable to create path '${strPath}'\";\n"
"\n\n"
"if ($OS_ERROR{ENOENT})\n"
"{\n"
"if (!$bCreateParent)\n"
"{\n"
"confess &log(ERROR, \"${strMessage} because parent does not exist\", ERROR_PATH_MISSING);\n"
"}\n"
"\n\n"
"$self->pathCreate(dirname($strPath), {strMode => $strMode, bIgnoreExists => true, bCreateParent => $bCreateParent});\n"
"\n\n"
"$self->pathCreate($strPath, {strMode => $strMode, bIgnoreExists => true});\n"
"}\n"
"\n"
"elsif ($OS_ERROR{EEXIST})\n"
"{\n"
"if (!$bIgnoreExists)\n"
"{\n"
"confess &log(ERROR, \"${strMessage} because it already exists\", ERROR_PATH_EXISTS);\n"
"}\n"
"}\n"
"else\n"
"{\n"
"logErrorResult(ERROR_PATH_CREATE, ${strMessage}, $OS_ERROR);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub pathExists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathExists', \\@_,\n"
"{name => 'strPath', trace => true},\n"
");\n"
"\n\n"
"my $bExists = true;\n"
"my $oStat = lstat($strPath);\n"
"\n\n"
"if (defined($oStat))\n"
"{\n"
"\n"
"$bExists = S_ISDIR($oStat->mode) ? true : false;\n"
"}\n"
"else\n"
"{\n"
"\n"
"if (!$OS_ERROR{ENOENT})\n"
"{\n"
"logErrorResult(ERROR_FILE_EXISTS, \"unable to test if path '${strPath}' exists\", $OS_ERROR);\n"
"}\n"
"\n"
"$bExists = false;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bExists', value => $bExists, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathSync\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathSync', \\@_,\n"
"{name => 'strPath', trace => true},\n"
");\n"
"\n"
"open(my $hPath, \"<\", $strPath)\n"
"or confess &log(ERROR, \"unable to open '${strPath}' for sync\", ERROR_PATH_OPEN);\n"
"open(my $hPathDup, \">&\", $hPath)\n"
"or confess &log(ERROR, \"unable to duplicate '${strPath}' handle for sync\", ERROR_PATH_OPEN);\n"
"\n"
"$hPathDup->sync()\n"
"or confess &log(ERROR, \"unable to sync path '${strPath}'\", ERROR_PATH_SYNC);\n"
"\n"
"close($hPathDup);\n"
"close($hPath);\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub remove\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathFile,\n"
"$bIgnoreMissing,\n"
"$bRecurse,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->remove', \\@_,\n"
"{name => 'strPathFile', trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
"{name => 'bRecurse', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my $bRemoved = true;\n"
"\n\n"
"if ($bRecurse)\n"
"{\n"
"\n"
"require pgBackRest::LibC;\n"
"pgBackRest::LibC->import(qw(:storage));\n"
"\n"
"storagePosixPathRemove($strPathFile, !$bIgnoreMissing, $bRecurse)\n"
"}\n"
"\n"
"else\n"
"{\n"
"foreach my $strFile (ref($strPathFile) ? @{$strPathFile} : ($strPathFile))\n"
"{\n"
"if (unlink($strFile) != 1)\n"
"{\n"
"$bRemoved = false;\n"
"\n\n"
"if (!($OS_ERROR{ENOENT} && $bIgnoreMissing))\n"
"{\n"
"logErrorResult(\n"
"$OS_ERROR{ENOENT} ? ERROR_FILE_MISSING : ERROR_FILE_OPEN, \"unable to remove file '${strFile}'\", $OS_ERROR);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bRemoved', value => $bRemoved, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub capability {true}\n"
"sub className {STORAGE_POSIX_DRIVER}\n"
"sub tempExtension {shift->{strTempExtension}}\n"
"sub tempExtensionSet {my $self = shift; $self->{strTempExtension} = shift}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Posix/FileRead.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::Posix::FileRead;\n"
"use parent 'pgBackRest::Common::Io::Handle';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Fcntl qw(O_RDONLY);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oDriver,\n"
"$strName,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oDriver', trace => true},\n"
"{name => 'strName', trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my $fhFile;\n"
"\n"
"if (!sysopen($fhFile, $strName, O_RDONLY))\n"
"{\n"
"if (!($OS_ERROR{ENOENT} && $bIgnoreMissing))\n"
"{\n"
"logErrorResult($OS_ERROR{ENOENT} ? ERROR_FILE_MISSING : ERROR_FILE_OPEN, \"unable to open '${strName}'\", $OS_ERROR);\n"
"}\n"
"\n"
"undef($fhFile);\n"
"}\n"
"\n\n"
"my $self;\n"
"\n"
"if (defined($fhFile))\n"
"{\n"
"\n"
"binmode($fhFile);\n"
"\n\n"
"$self = $class->SUPER::new(\"'${strName}'\", $fhFile);\n"
"bless $self, $class;\n"
"\n\n"
"$self->{oDriver} = $oDriver;\n"
"$self->{strName} = $strName;\n"
"$self->{fhFile} = $fhFile;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n"
"if (defined($self->handle()))\n"
"{\n"
"\n"
"close($self->handle());\n"
"undef($self->{fhFile});\n"
"\n\n"
"$self->SUPER::close();\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n\n\n\n"
"sub handle {shift->{fhFile}}\n"
"sub name {shift->{strName}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Posix/FileWrite.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::Posix::FileWrite;\n"
"use parent 'pgBackRest::Common::Io::Handle';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Fcntl qw(O_RDONLY O_WRONLY O_CREAT O_TRUNC);\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"\n"
"use pgBackRest::Common::Io::Handle;\n"
"use pgBackRest::Storage::Base;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oDriver,\n"
"$strName,\n"
"$strMode,\n"
"$strUser,\n"
"$strGroup,\n"
"$lTimestamp,\n"
"$bPathCreate,\n"
"$bAtomic,\n"
"$bSync,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oDriver', trace => true},\n"
"{name => 'strName', trace => true},\n"
"{name => 'strMode', optional => true, trace => true},\n"
"{name => 'strUser', optional => true, trace => true},\n"
"{name => 'strGroup', optional => true, trace => true},\n"
"{name => 'lTimestamp', optional => true, trace => true},\n"
"{name => 'bPathCreate', optional => true, default => false, trace => true},\n"
"{name => 'bAtomic', optional => true, default => false, trace => true},\n"
"{name => 'bSync', optional => true, default => true, trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new(\"'${strName}'\");\n"
"bless $self, $class;\n"
"\n\n"
"$self->{oDriver} = $oDriver;\n"
"$self->{strName} = $strName;\n"
"$self->{strMode} = $strMode;\n"
"$self->{strUser} = $strUser;\n"
"$self->{strGroup} = $strGroup;\n"
"$self->{lTimestamp} = $lTimestamp;\n"
"$self->{bPathCreate} = $bPathCreate;\n"
"$self->{bAtomic} = $bAtomic;\n"
"$self->{bSync} = $bSync;\n"
"\n\n"
"if ($self->{bAtomic})\n"
"{\n"
"\n"
"$self->{strNameTmp} = \"$self->{strName}.\" . $self->{oDriver}->tempExtension();\n"
"}\n"
"\n\n"
"$self->{bOpened} = false;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub open\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my $strFile = $self->{bAtomic} ? $self->{strNameTmp} : $self->{strName};\n"
"\n\n"
"if (!sysopen(\n"
"$self->{fhFile}, $strFile, O_WRONLY | O_CREAT | O_TRUNC, oct(defined($self->{strMode}) ? $self->{strMode} : '0666')))\n"
"{\n"
"\n"
"if ($OS_ERROR{ENOENT} && $self->{bPathCreate})\n"
"{\n"
"$self->{oDriver}->pathCreate(dirname($strFile), {bIgnoreExists => true, bCreateParent => true});\n"
"$self->{bPathCreate} = false;\n"
"return $self->open();\n"
"}\n"
"\n"
"logErrorResult($OS_ERROR{ENOENT} ? ERROR_PATH_MISSING : ERROR_FILE_OPEN, \"unable to open '${strFile}'\", $OS_ERROR);\n"
"}\n"
"\n\n"
"binmode($self->{fhFile});\n"
"\n\n"
"$self->{oDriver}->owner($strFile, {strUser => $self->{strUser}, strGroup => $self->{strGroup}});\n"
"\n\n"
"$self->handleWriteSet($self->{fhFile});\n"
"\n\n"
"$self->{bOpened} = true;\n"
"\n"
"return true;\n"
"}\n"
"\n\n\n\n"
"sub write\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"\n\n"
"$self->open() if !$self->opened();\n"
"\n"
"return $self->SUPER::write($rtBuffer);\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n"
"if (defined($self->handle()))\n"
"{\n"
"\n"
"if ($self->{bSync})\n"
"{\n"
"$self->handle()->sync();\n"
"}\n"
"\n\n"
"close($self->handle());\n"
"undef($self->{fhFile});\n"
"\n\n"
"my $strCurrentName = $self->{bAtomic} ? $self->{strNameTmp} : $self->{strName};\n"
"\n\n"
"if (defined($self->{lTimestamp}))\n"
"{\n"
"utime(time(), $self->{lTimestamp}, $strCurrentName)\n"
"or logErrorResult(ERROR_FILE_WRITE, \"unable to set time for '${strCurrentName}'\", $OS_ERROR);\n"
"}\n"
"\n\n"
"if ($self->{bAtomic})\n"
"{\n"
"$self->{oDriver}->move($strCurrentName, $self->{strName});\n"
"}\n"
"\n\n"
"$self->resultSet(COMMON_IO_HANDLE, $self->{lSize});\n"
"\n\n"
"$self->SUPER::close();\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n\n\n\n"
"sub DESTROY\n"
"{\n"
"my $self = shift;\n"
"\n"
"if (defined($self->handle()))\n"
"{\n"
"CORE::close($self->handle());\n"
"undef($self->{fhFile});\n"
"}\n"
"}\n"
"\n\n\n\n"
"sub handle {shift->{fhFile}}\n"
"sub opened {shift->{bOpened}}\n"
"sub name {shift->{strName}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/S3/Auth.pm",
.data =
"\n\n\n\n\n\n"
"package pgBackRest::Storage::S3::Auth;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Digest::SHA qw(hmac_sha256 hmac_sha256_hex);\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use POSIX qw(strftime);\n"
"\n"
"use pgBackRest::Common::Http::Common;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::LibC qw(:crypto);\n"
"\n\n\n\n"
"use constant S3 => 's3';\n"
"use constant AWS4 => 'AWS4';\n"
"use constant AWS4_REQUEST => 'aws4_request';\n"
"use constant AWS4_HMAC_SHA256 => 'AWS4-HMAC-SHA256';\n"
"\n"
"use constant S3_HEADER_AUTHORIZATION => 'authorization';\n"
"push @EXPORT, qw(S3_HEADER_AUTHORIZATION);\n"
"use constant S3_HEADER_DATE => 'x-amz-date';\n"
"push @EXPORT, qw(S3_HEADER_DATE);\n"
"use constant S3_HEADER_CONTENT_SHA256 => 'x-amz-content-sha256';\n"
"push @EXPORT, qw(S3_HEADER_CONTENT_SHA256);\n"
"use constant S3_HEADER_HOST => 'host';\n"
"push @EXPORT, qw(S3_HEADER_HOST);\n"
"use constant S3_HEADER_TOKEN => 'x-amz-security-token';\n"
"push @EXPORT, qw(S3_HEADER_TOKEN);\n"
"\n"
"use constant PAYLOAD_DEFAULT_HASH => cryptoHashOne('sha256', '');\n"
"push @EXPORT, qw(PAYLOAD_DEFAULT_HASH);\n"
"\n\n\n\n"
"sub s3DateTime\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$lTime,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::s3DateTime', \\@_,\n"
"{name => 'lTime', default => time(), trace => true},\n"
");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strDateTime', value => strftime(\"%Y%m%dT%H%M%SZ\", gmtime($lTime)), trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(s3DateTime);\n"
"\n\n\n\n"
"sub s3CanonicalRequest\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strVerb,\n"
"$strUri,\n"
"$strQuery,\n"
"$hHeader,\n"
"$strPayloadHash,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::s3CanonicalRequest', \\@_,\n"
"{name => 'strVerb', trace => true},\n"
"{name => 'strUri', trace => true},\n"
"{name => 'strQuery', trace => true},\n"
"{name => 'hHeader', trace => true},\n"
"{name => 'strPayloadHash', trace => true},\n"
");\n"
"\n\n"
"my $strCanonicalRequest =\n"
"\"${strVerb}\\n${strUri}\\n${strQuery}\\n\";\n"
"my $strSignedHeaders;\n"
"\n"
"foreach my $strHeader (sort(keys(%{$hHeader})))\n"
"{\n"
"if (lc($strHeader) ne $strHeader)\n"
"{\n"
"confess &log(ASSERT, \"header '${strHeader}' must be lower case\");\n"
"}\n"
"\n"
"$strCanonicalRequest .= $strHeader . \":$hHeader->{$strHeader}\\n\";\n"
"$strSignedHeaders .= (defined($strSignedHeaders) ? qw(;) : '') . lc($strHeader);\n"
"}\n"
"\n"
"$strCanonicalRequest .= \"\\n${strSignedHeaders}\\n${strPayloadHash}\";\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strCanonicalRequest', value => $strCanonicalRequest, trace => true},\n"
"{name => 'strSignedHeaders', value => $strSignedHeaders, trace => true},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(s3CanonicalRequest);\n"
"\n\n\n\n"
"my $hSigningKeyCache;\n"
"\n"
"sub s3SigningKey\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDate,\n"
"$strRegion,\n"
"$strSecretAccessKey,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::s3SigningKey', \\@_,\n"
"{name => 'strDate', trace => true},\n"
"{name => 'strRegion', trace => true},\n"
"{name => 'strSecretAccessKey', redact => true, trace => true},\n"
");\n"
"\n\n"
"my $strSigningKey = $hSigningKeyCache->{$strDate}{$strRegion}{$strSecretAccessKey};\n"
"\n\n"
"if (!defined($strSigningKey))\n"
"{\n"
"my $strDateKey = hmac_sha256($strDate, AWS4 . $strSecretAccessKey);\n"
"my $strRegionKey = hmac_sha256($strRegion, $strDateKey);\n"
"my $strServiceKey = hmac_sha256(S3, $strRegionKey);\n"
"$strSigningKey = hmac_sha256(AWS4_REQUEST, $strServiceKey);\n"
"\n\n"
"$hSigningKeyCache->{$strDate}{$strRegion}{$strSecretAccessKey} = $strSigningKey;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strSigningKey', value => $strSigningKey, redact => true, trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(s3SigningKey);\n"
"\n\n\n\n"
"sub s3StringToSign\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strDateTime,\n"
"$strRegion,\n"
"$strCanonicalRequestHash,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::s3StringToSign', \\@_,\n"
"{name => 'strDateTime', trace => true},\n"
"{name => 'strRegion', trace => true},\n"
"{name => 'strCanonicalRequestHash', trace => true},\n"
");\n"
"\n"
"my $strStringToSign =\n"
"AWS4_HMAC_SHA256 . \"\\n${strDateTime}\\n\" . substr($strDateTime, 0, 8) . \"/${strRegion}/\" . S3 . '/' . AWS4_REQUEST . \"\\n\" .\n"
"$strCanonicalRequestHash;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strStringToSign', value => $strStringToSign, trace => true}\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(s3StringToSign);\n"
"\n\n\n\n"
"sub s3AuthorizationHeader\n"
"{\n"
"\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strRegion,\n"
"$strHost,\n"
"$strVerb,\n"
"$strUri,\n"
"$strQuery,\n"
"$strDateTime,\n"
"$hHeader,\n"
"$strAccessKeyId,\n"
"$strSecretAccessKey,\n"
"$strSecurityToken,\n"
"$strPayloadHash,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '::s3AuthorizationHeader', \\@_,\n"
"{name => 'strRegion', trace => true},\n"
"{name => 'strHost', trace => true},\n"
"{name => 'strVerb', trace => true},\n"
"{name => 'strUri', trace => true},\n"
"{name => 'strQuery', trace => true},\n"
"{name => 'strDateTime', trace => true},\n"
"{name => 'hHeader', required => false, trace => true},\n"
"{name => 'strAccessKeyId', redact => true, trace => true},\n"
"{name => 'strSecretAccessKey', redact => true, trace => true},\n"
"{name => 'strSecurityToken', required => false, redact => true, trace => true},\n"
"{name => 'strPayloadHash', trace => true},\n"
");\n"
"\n\n"
"delete($hHeader->{&S3_HEADER_AUTHORIZATION});\n"
"\n\n"
"$hHeader->{&S3_HEADER_HOST} = $strHost;\n"
"$hHeader->{&S3_HEADER_CONTENT_SHA256} = $strPayloadHash;\n"
"$hHeader->{&S3_HEADER_DATE} = $strDateTime;\n"
"\n\n"
"if (defined($strSecurityToken))\n"
"{\n"
"$hHeader->{&S3_HEADER_TOKEN} = $strSecurityToken;\n"
"}\n"
"\n\n"
"my ($strCanonicalRequest, $strSignedHeaders) = s3CanonicalRequest(\n"
"$strVerb, httpUriEncode($strUri, true), $strQuery, $hHeader, $strPayloadHash);\n"
"my $strStringToSign = s3StringToSign($strDateTime, $strRegion, cryptoHashOne('sha256', $strCanonicalRequest));\n"
"\n"
"$hHeader->{&S3_HEADER_AUTHORIZATION} =\n"
"AWS4_HMAC_SHA256 . \" Credential=${strAccessKeyId}/\" . substr($strDateTime, 0, 8) . \"/${strRegion}/\" . S3 . qw(/) .\n"
"AWS4_REQUEST . \",SignedHeaders=${strSignedHeaders},Signature=\" . hmac_sha256_hex($strStringToSign,\n"
"s3SigningKey(substr($strDateTime, 0, 8), $strRegion, $strSecretAccessKey));\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hHeader', value => $hHeader, trace => true},\n"
"{name => 'strCanonicalRequest', value => $strCanonicalRequest, trace => true},\n"
"{name => 'strSignedHeaders', value => $strSignedHeaders, trace => true},\n"
"{name => 'strStringToSign', value => $strStringToSign, trace => true},\n"
");\n"
"}\n"
"\n"
"push @EXPORT, qw(s3AuthorizationHeader);\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/S3/Driver.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::S3::Driver;\n"
"use parent 'pgBackRest::Storage::S3::Request';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use Digest::MD5 qw(md5_base64);\n"
"use File::Basename qw(basename dirname);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Common::Xml;\n"
"use pgBackRest::Storage::S3::FileRead;\n"
"use pgBackRest::Storage::S3::FileWrite;\n"
"use pgBackRest::Storage::S3::Request;\n"
"use pgBackRest::Storage::S3::Info;\n"
"\n\n\n\n"
"use constant STORAGE_S3_DRIVER => __PACKAGE__;\n"
"push @EXPORT, qw(STORAGE_S3_DRIVER);\n"
"\n\n\n\n"
"use constant S3_QUERY_CONTINUATION_TOKEN => 'continuation-token';\n"
"use constant S3_QUERY_DELIMITER => 'delimiter';\n"
"use constant S3_QUERY_LIST_TYPE => 'list-type';\n"
"use constant S3_QUERY_PREFIX => 'prefix';\n"
"\n\n\n\n"
"use constant S3_BATCH_MAX => 1000;\n"
"\n\n\n\n"
"sub openWrite\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->openWrite', \\@_,\n"
"{name => 'strFile', trace => true},\n"
");\n"
"\n"
"my $oFileIO = new pgBackRest::Storage::S3::FileWrite($self, $strFile);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oFileIO', value => $oFileIO, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub openRead\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFile,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->openRead', \\@_,\n"
"{name => 'strFile', trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
");\n"
"\n"
"my $oFileIO = new pgBackRest::Storage::S3::FileRead($self, $strFile, {bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oFileIO', value => $oFileIO, trace => true},\n"
");\n"
"}\n"
"\n\n\n\n"
"sub manifest\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
"$bRecurse,\n"
"$bPath,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->manifest', \\@_,\n"
"{name => 'strPath', trace => true},\n"
"\n"
"{name => 'bRecurse', optional => true, default => true, trace => true},\n"
"{name => 'bPath', optional => true, default => true, trace => true},\n"
");\n"
"\n\n"
"my $strPrefix = $strPath eq qw{/} ? undef : substr($strPath, 1) . ($bPath ? qw{/} : '');\n"
"\n\n"
"my $strDelimiter = $bRecurse ? undef : '/';\n"
"\n\n"
"my $hManifest = {};\n"
"\n\n"
"my $strContinuationToken;\n"
"\n"
"do\n"
"{\n"
"\n"
"my $oResponse = $self->request(\n"
"HTTP_VERB_GET, {hQuery =>\n"
"{&S3_QUERY_LIST_TYPE => 2, &S3_QUERY_PREFIX => $strPrefix, &S3_QUERY_DELIMITER => $strDelimiter,\n"
"&S3_QUERY_CONTINUATION_TOKEN => $strContinuationToken}, strResponseType => S3_RESPONSE_TYPE_XML});\n"
"\n\n"
"if (defined($strPrefix) && !$bPath)\n"
"{\n"
"\n"
"if (index($strPrefix, qw{/}) == -1)\n"
"{\n"
"undef($strPrefix);\n"
"}\n"
"else\n"
"{\n"
"$strPrefix = dirname($strPrefix) . qw{/};\n"
"}\n"
"}\n"
"\n\n"
"foreach my $oFile (xmlTagChildren($oResponse, \"Contents\"))\n"
"{\n"
"my $strName = xmlTagText($oFile, \"Key\");\n"
"\n\n"
"if (defined($strPrefix))\n"
"{\n"
"$strName = substr($strName, length($strPrefix));\n"
"}\n"
"\n"
"$hManifest->{$strName}->{type} = 'f';\n"
"$hManifest->{$strName}->{size} = xmlTagText($oFile, 'Size') + 0;\n"
"\n\n"
"if ($bRecurse)\n"
"{\n"
"my @stryName = split(qw{/}, $strName);\n"
"\n"
"if (@stryName > 1)\n"
"{\n"
"$strName = undef;\n"
"\n"
"for (my $iIndex = 0; $iIndex < @stryName - 1; $iIndex++)\n"
"{\n"
"$strName .= (defined($strName) ? qw{/} : '') . $stryName[$iIndex];\n"
"$hManifest->{$strName}->{type} = 'd';\n"
"}\n"
"}\n"
"}\n"
"}\n"
"\n\n"
"if ($bPath && !$bRecurse)\n"
"{\n"
"foreach my $oPath (xmlTagChildren($oResponse, \"CommonPrefixes\"))\n"
"{\n"
"my $strName = xmlTagText($oPath, \"Prefix\");\n"
"\n\n"
"if (defined($strPrefix))\n"
"{\n"
"$strName = substr($strName, length($strPrefix));\n"
"}\n"
"\n\n"
"$strName = substr($strName, 0, length($strName) - 1);\n"
"\n"
"$hManifest->{$strName}->{type} = 'd';\n"
"}\n"
"}\n"
"\n"
"$strContinuationToken = xmlTagText($oResponse, \"NextContinuationToken\", false);\n"
"}\n"
"while (defined($strContinuationToken));\n"
"\n\n"
"if ($bPath)\n"
"{\n"
"$hManifest->{qw{.}}->{type} = 'd';\n"
"}\n"
"\n\n\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'hManifest', value => $hManifest, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub list\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
"$strExpression\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->list', \\@_,\n"
"{name => 'strPath', trace => true},\n"
"{name => 'strExpression', optional => true, trace => true},\n"
");\n"
"\n\n"
"my $strPrefix = regexPrefix($strExpression);\n"
"\n\n"
"my @stryFileList = grep(\n"
"!/^\\.$/i, keys(%{$self->manifest(\n"
"$strPath . (defined($strPrefix) ? \"/${strPrefix}\" : ''), {bRecurse => false, bPath => !defined($strPrefix)})}));\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'stryFileList', value => \\@stryFileList, ref => true, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathCreate', \\@_,\n"
"{name => 'strPath', trace => true},\n"
");\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub pathSync\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathSync', \\@_,\n"
"{name => 'strPath', trace => true},\n"
");\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n"
"sub exists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->exists', \\@_,\n"
"{name => 'strFile', trace => true},\n"
");\n"
"\n\n"
"my $bExists = defined($self->manifest($strFile, {bRecurse => false, bPath => false})->{basename($strFile)}) ? true : false;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bExists', value => $bExists, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub pathExists\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPath,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->pathExists', \\@_,\n"
"{name => 'strPath', trace => true},\n"
");\n"
"\n"
"my $bExists = true;\n"
"\n\n"
"if ($strPath ne qw{/})\n"
"{\n"
"\n"
"my $rhInfo = $self->manifest(dirname($strPath), {bRecurse => false, bPath => true})->{basename($strPath)};\n"
"$bExists = defined($rhInfo) && $rhInfo->{type} eq 'd' ? true : false;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bExists', value => $bExists, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub info\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->info', \\@_,\n"
"{name => 'strFile', trace => true},\n"
");\n"
"\n\n"
"my $rhFile = $self->manifest($strFile, {bRecurse => false, bPath => false})->{basename($strFile)};\n"
"\n"
"if (!defined($rhFile))\n"
"{\n"
"confess &log(ERROR, \"unable to get info for missing file ${strFile}\", ERROR_FILE_MISSING);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oInfo', value => new pgBackRest::Storage::S3::Info($rhFile->{size}), trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub remove\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$rstryFile,\n"
"$bRecurse,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->remove', \\@_,\n"
"{name => 'rstryFile', trace => true},\n"
"{name => 'bRecurse', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"if ($bRecurse)\n"
"{\n"
"my $rhManifest = $self->manifest($rstryFile);\n"
"my @stryRemoveFile;\n"
"\n\n"
"foreach my $strFile (sort({$b cmp $a} keys(%{$rhManifest})))\n"
"{\n"
"next if $rhManifest->{$strFile}->{type} eq 'd';\n"
"push(@stryRemoveFile, \"${rstryFile}/${strFile}\");\n"
"}\n"
"\n\n"
"if (@stryRemoveFile > 0)\n"
"{\n"
"$self->remove(\\@stryRemoveFile);\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"my $rstryFileAll = ref($rstryFile) ? $rstryFile : [$rstryFile];\n"
"\n"
"do\n"
"{\n"
"my $strFile = shift(@{$rstryFileAll});\n"
"my $iTotal = 0;\n"
"my $strXml = XML_HEADER . '<Delete><Quiet>true</Quiet>';\n"
"\n"
"while (defined($strFile))\n"
"{\n"
"$iTotal++;\n"
"$strXml .= '<Object><Key>' . xmlFromText(substr($strFile, 1)) . '</Key></Object>';\n"
"\n"
"$strFile = $iTotal < S3_BATCH_MAX ? shift(@{$rstryFileAll}) : undef;\n"
"}\n"
"\n"
"$strXml .= '</Delete>';\n"
"\n"
"my $hHeader = {'content-md5' => md5_base64($strXml) . '=='};\n"
"\n\n"
"my $oResponse = $self->request(\n"
"HTTP_VERB_POST,\n"
"{hQuery => 'delete=', rstrBody => \\$strXml, hHeader => $hHeader, strResponseType => S3_RESPONSE_TYPE_XML});\n"
"}\n"
"while (@{$rstryFileAll} > 0);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bResult', value => true, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n"
"sub capability {false}\n"
"sub className {STORAGE_S3_DRIVER}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/S3/FileRead.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::S3::FileRead;\n"
"use parent 'pgBackRest::Common::Http::Client';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Digest::MD5 qw(md5_base64);\n"
"use Fcntl qw(O_RDONLY O_WRONLY O_CREAT O_TRUNC);\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Xml;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::S3::Request;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oDriver,\n"
"$strName,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oDriver', trace => true},\n"
"{name => 'strName', trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my $self = $oDriver->request(\n"
"HTTP_VERB_GET, {strUri => $strName, strResponseType => S3_RESPONSE_TYPE_IO, bIgnoreMissing => $bIgnoreMissing});\n"
"\n\n"
"if (defined($self))\n"
"{\n"
"bless $self, $class;\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub name {shift->{strName}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/S3/FileWrite.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::S3::FileWrite;\n"
"use parent 'pgBackRest::Common::Io::Base';\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Digest::MD5 qw(md5_base64);\n"
"use Fcntl qw(O_RDONLY O_WRONLY O_CREAT O_TRUNC);\n"
"use File::Basename qw(dirname);\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Io::Handle;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::Xml;\n"
"use pgBackRest::Storage::Base;\n"
"use pgBackRest::Storage::S3::Request;\n"
"\n\n\n\n"
"use constant S3_BUFFER_MAX => 16777216;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oDriver,\n"
"$strName,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'oDriver', trace => true},\n"
"{name => 'strName', trace => true},\n"
");\n"
"\n\n"
"my $self = $class->SUPER::new(\"'${strName}'\");\n"
"bless $self, $class;\n"
"\n\n"
"$self->{oDriver} = $oDriver;\n"
"$self->{strName} = $strName;\n"
"\n\n"
"$self->{rtBuffer} = '';\n"
"\n\n"
"$self->{bWritten} = false;\n"
"\n\n"
"$self->{lSize} = 0;\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub open\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my $oResponse = $self->{oDriver}->request(\n"
"HTTP_VERB_POST, {strUri => $self->{strName}, hQuery => 'uploads=', strResponseType => S3_RESPONSE_TYPE_XML});\n"
"\n"
"$self->{strUploadId} = xmlTagText($oResponse, 'UploadId');\n"
"\n\n"
"$self->{rstryMultiPart} = [];\n"
"}\n"
"\n\n\n\n"
"sub write\n"
"{\n"
"my $self = shift;\n"
"my $rtBuffer = shift;\n"
"\n\n"
"$self->{bWritten} = true;\n"
"\n"
"if (defined($rtBuffer))\n"
"{\n"
"$self->{rtBuffer} .= $$rtBuffer;\n"
"$self->{lSize} += length($$rtBuffer);\n"
"\n\n"
"if (length($self->{rtBuffer}) >= S3_BUFFER_MAX)\n"
"{\n"
"$self->flush();\n"
"}\n"
"\n"
"return length($$rtBuffer);\n"
"}\n"
"\n"
"return 0;\n"
"}\n"
"\n\n\n\n"
"sub flush\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"$self->open() if !$self->opened();\n"
"\n\n"
"$self->{oDriver}->request(\n"
"HTTP_VERB_PUT,\n"
"{strUri => $self->{strName},\n"
"hQuery => {'partNumber' => @{$self->{rstryMultiPart}} + 1, 'uploadId' => $self->{strUploadId}},\n"
"rstrBody => \\$self->{rtBuffer}, hHeader => {'content-md5' => md5_base64($self->{rtBuffer}) . '=='}});\n"
"\n\n"
"push(@{$self->{rstryMultiPart}}, $self->{oDriver}->{hResponseHeader}{&S3_HEADER_ETAG});\n"
"\n\n"
"$self->{rtBuffer} = '';\n"
"}\n"
"\n\n\n\n"
"sub close\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"if ($self->{bWritten})\n"
"{\n"
"\n"
"$self->{bWritten} = false;\n"
"\n\n"
"if ($self->opened())\n"
"{\n"
"\n"
"$self->flush();\n"
"\n"
"my $strXml = XML_HEADER . '<CompleteMultipartUpload>';\n"
"my $iPartNo = 0;\n"
"\n"
"foreach my $strETag (@{$self->{rstryMultiPart}})\n"
"{\n"
"$iPartNo++;\n"
"\n"
"$strXml .= \"<Part><PartNumber>${iPartNo}</PartNumber><ETag>${strETag}</ETag></Part>\";\n"
"}\n"
"\n"
"$strXml .= '</CompleteMultipartUpload>';\n"
"\n\n"
"my $oResponse = $self->{oDriver}->request(\n"
"HTTP_VERB_POST,\n"
"{strUri => $self->{strName}, hQuery => {'uploadId' => $self->{strUploadId}},\n"
"rstrBody => \\$strXml, hHeader => {'content-md5' => md5_base64($strXml) . '=='},\n"
"strResponseType => S3_RESPONSE_TYPE_XML});\n"
"}\n"
"\n"
"else\n"
"{\n"
"$self->{oDriver}->request(\n"
"HTTP_VERB_PUT,\n"
"{strUri => $self->{strName}, rstrBody => \\$self->{rtBuffer},\n"
"hHeader => {'content-md5' => md5_base64($self->{rtBuffer}) . '=='}});\n"
"}\n"
"}\n"
"\n\n\n\n"
"$self->resultSet(COMMON_IO_HANDLE, $self->{lSize});\n"
"\n"
"return true;\n"
"}\n"
"\n\n\n\n"
"sub opened {defined(shift->{strUploadId})}\n"
"sub name {shift->{strName}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/S3/Info.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::S3::Info;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use pgBackRest::Common::Log;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{lSize},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'lSize'},\n"
");\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub size {shift->{lSize}}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/S3/Request.pm",
.data =
"\n\n\n"
"package pgBackRest::Storage::S3::Request;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"use IO::Socket::SSL;\n"
"\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Http::Client;\n"
"use pgBackRest::Common::Http::Common;\n"
"use pgBackRest::Common::Io::Base;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Common::String;\n"
"use pgBackRest::Common::Xml;\n"
"use pgBackRest::LibC qw(:crypto);\n"
"use pgBackRest::Storage::S3::Auth;\n"
"\n\n\n\n"
"use constant HTTP_VERB_GET => 'GET';\n"
"push @EXPORT, qw(HTTP_VERB_GET);\n"
"use constant HTTP_VERB_POST => 'POST';\n"
"push @EXPORT, qw(HTTP_VERB_POST);\n"
"use constant HTTP_VERB_PUT => 'PUT';\n"
"push @EXPORT, qw(HTTP_VERB_PUT);\n"
"\n"
"use constant S3_HEADER_CONTENT_LENGTH => 'content-length';\n"
"push @EXPORT, qw(S3_HEADER_CONTENT_LENGTH);\n"
"use constant S3_HEADER_TRANSFER_ENCODING => 'transfer-encoding';\n"
"push @EXPORT, qw(S3_HEADER_TRANSFER_ENCODING);\n"
"use constant S3_HEADER_ETAG => 'etag';\n"
"push @EXPORT, qw(S3_HEADER_ETAG);\n"
"\n"
"use constant S3_RESPONSE_TYPE_IO => 'io';\n"
"push @EXPORT, qw(S3_RESPONSE_TYPE_IO);\n"
"use constant S3_RESPONSE_TYPE_NONE => 'none';\n"
"push @EXPORT, qw(S3_RESPONSE_TYPE_NONE);\n"
"use constant S3_RESPONSE_TYPE_XML => 'xml';\n"
"push @EXPORT, qw(S3_RESPONSE_TYPE_XML);\n"
"\n"
"use constant S3_RESPONSE_CODE_SUCCESS => 200;\n"
"use constant S3_RESPONSE_CODE_ERROR_AUTH => 403;\n"
"use constant S3_RESPONSE_CODE_ERROR_NOT_FOUND => 404;\n"
"use constant S3_RESPONSE_CODE_ERROR_RETRY_CLASS => 5;\n"
"\n"
"use constant S3_RETRY_MAX => 4;\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"(\n"
"my $strOperation,\n"
"$self->{strBucket},\n"
"$self->{strEndPoint},\n"
"$self->{strRegion},\n"
"$self->{strAccessKeyId},\n"
"$self->{strSecretAccessKey},\n"
"$self->{strSecurityToken},\n"
"$self->{strHost},\n"
"$self->{iPort},\n"
"$self->{bVerifySsl},\n"
"$self->{strCaPath},\n"
"$self->{strCaFile},\n"
"$self->{lBufferMax},\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->new', \\@_,\n"
"{name => 'strBucket'},\n"
"{name => 'strEndPoint'},\n"
"{name => 'strRegion'},\n"
"{name => 'strAccessKeyId', redact => true},\n"
"{name => 'strSecretAccessKey', redact => true},\n"
"{name => 'strSecurityToken', optional => true, redact => true},\n"
"{name => 'strHost', optional => true},\n"
"{name => 'iPort', optional => true},\n"
"{name => 'bVerifySsl', optional => true, default => true},\n"
"{name => 'strCaPath', optional => true},\n"
"{name => 'strCaFile', optional => true},\n"
"{name => 'lBufferMax', optional => true, default => COMMON_IO_BUFFER_MAX},\n"
");\n"
"\n\n"
"$self->{strHost} = defined($self->{strHost}) ? $self->{strHost} : \"$self->{strBucket}.$self->{strEndPoint}\";\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub request\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strVerb,\n"
"$strUri,\n"
"$hQuery,\n"
"$hHeader,\n"
"$rstrBody,\n"
"$strResponseType,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->request', \\@_,\n"
"{name => 'strVerb', trace => true},\n"
"{name => 'strUri', optional => true, default => '/', trace => true},\n"
"{name => 'hQuery', optional => true, trace => true},\n"
"{name => 'hHeader', optional => true, trace => true},\n"
"{name => 'rstrBody', optional => true, trace => true},\n"
"{name => 'strResponseType', optional => true, default => S3_RESPONSE_TYPE_NONE, trace => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n"
");\n"
"\n\n"
"my $oResponse;\n"
"\n\n"
"my $bRetry;\n"
"my $iRetryTotal = 0;\n"
"\n"
"do\n"
"{\n"
"\n"
"$bRetry = false;\n"
"\n\n"
"$hHeader->{&S3_HEADER_CONTENT_SHA256} = defined($rstrBody) ? cryptoHashOne('sha256', $$rstrBody) : PAYLOAD_DEFAULT_HASH;\n"
"$hHeader->{&S3_HEADER_CONTENT_LENGTH} = defined($rstrBody) ? length($$rstrBody) : 0;\n"
"\n\n"
"($hHeader, my $strCanonicalRequest, my $strSignedHeaders, my $strStringToSign) = s3AuthorizationHeader(\n"
"$self->{strRegion}, \"$self->{strBucket}.$self->{strEndPoint}\", $strVerb, $strUri, httpQuery($hQuery), s3DateTime(),\n"
"$hHeader, $self->{strAccessKeyId}, $self->{strSecretAccessKey}, $self->{strSecurityToken},\n"
"$hHeader->{&S3_HEADER_CONTENT_SHA256});\n"
"\n\n"
"my $oHttpClient = new pgBackRest::Common::Http::Client(\n"
"$self->{strHost}, $strVerb,\n"
"{iPort => $self->{iPort}, strUri => $strUri, hQuery => $hQuery, hRequestHeader => $hHeader,\n"
"rstrRequestBody => $rstrBody, bVerifySsl => $self->{bVerifySsl}, strCaPath => $self->{strCaPath},\n"
"strCaFile => $self->{strCaFile}, bResponseBodyPrefetch => $strResponseType eq S3_RESPONSE_TYPE_XML,\n"
"lBufferMax => $self->{lBufferMax}});\n"
"\n\n"
"my $iResponseCode = $oHttpClient->responseCode();\n"
"\n"
"if ($iResponseCode == S3_RESPONSE_CODE_SUCCESS)\n"
"{\n"
"\n"
"$self->{hResponseHeader} = $oHttpClient->responseHeader();\n"
"\n\n"
"if ($strResponseType eq S3_RESPONSE_TYPE_XML)\n"
"{\n"
"my $rtResponseBody = $oHttpClient->responseBody();\n"
"\n"
"if ($oHttpClient->contentLength() == 0 || !defined($$rtResponseBody))\n"
"{\n"
"confess &log(ERROR,\n"
"\"response type '${strResponseType}' was requested but content length is zero or content is missing\",\n"
"ERROR_PROTOCOL);\n"
"}\n"
"\n"
"$oResponse = xmlParse($$rtResponseBody);\n"
"}\n"
"\n"
"elsif ($strResponseType eq S3_RESPONSE_TYPE_IO)\n"
"{\n"
"$oResponse = $oHttpClient;\n"
"}\n"
"}\n"
"else\n"
"{\n"
"\n"
"if ($iResponseCode == S3_RESPONSE_CODE_ERROR_NOT_FOUND)\n"
"{\n"
"\n"
"if (!$bIgnoreMissing)\n"
"{\n"
"confess &log(ERROR, \"unable to open '${strUri}': No such file or directory\", ERROR_FILE_MISSING);\n"
"}\n"
"\n"
"$bRetry = false;\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if (int($iResponseCode / 100) == S3_RESPONSE_CODE_ERROR_RETRY_CLASS)\n"
"{\n"
"\n"
"$iRetryTotal++;\n"
"$bRetry = $iRetryTotal <= S3_RETRY_MAX;\n"
"\n\n"
"if ($iRetryTotal > 1)\n"
"{\n"
"sleep(5);\n"
"}\n"
"}\n"
"\n\n"
"if (!$bRetry)\n"
"{\n"
"my $rstrResponseBody = $oHttpClient->responseBody();\n"
"\n\n"
"my $strRequestHeader = $oHttpClient->requestHeaderText();\n"
"$strRequestHeader =~ s/^${\\S3_HEADER_AUTHORIZATION}:.*$/${\\S3_HEADER_AUTHORIZATION}: <redacted>/mg;\n"
"\n"
"confess &log(ERROR,\n"
"'S3 request error' . ($iRetryTotal > 0 ? \" after \" . (S3_RETRY_MAX + 1) . \" tries\" : '') .\n"
"\" [$iResponseCode] \" . $oHttpClient->responseMessage() .\n"
"\"\\n*** request header ***\\n${strRequestHeader}\" .\n"
"($iResponseCode == S3_RESPONSE_CODE_ERROR_AUTH ?\n"
"\"\\n*** canonical request ***\\n\" . $strCanonicalRequest .\n"
"\"\\n*** signed headers ***\\n\" . $strSignedHeaders .\n"
"\"\\n*** string to sign ***\\n\" . $strStringToSign : '') .\n"
"\"\\n*** response header ***\\n\" . $oHttpClient->responseHeaderText() .\n"
"(defined($$rstrResponseBody) ? \"\\n*** response body ***\\n${$rstrResponseBody}\" : ''),\n"
"ERROR_PROTOCOL);\n"
"}\n"
"}\n"
"}\n"
"}\n"
"while ($bRetry);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oResponse', value => $oResponse, trace => true, ref => true}\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Version.pm",
.data =
"\n\n\n\n\n"
"package pgBackRest::Version;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"\n"
"use Cwd qw(abs_path);\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n\n\n\n\n"
"use constant PROJECT_NAME => 'pgBackRest';\n"
"push @EXPORT, qw(PROJECT_NAME);\n"
"use constant PROJECT_EXE => lc(PROJECT_NAME);\n"
"push @EXPORT, qw(PROJECT_EXE);\n"
"use constant PROJECT_CONF => PROJECT_EXE . '.conf';\n"
"push @EXPORT, qw(PROJECT_CONF);\n"
"\n\n\n\n\n"
"my $strProjectBin;\n"
"\n"
"sub projectBin {return $strProjectBin};\n"
"sub projectBinSet {$strProjectBin = shift}\n"
"\n"
"push @EXPORT, qw(projectBin projectBinSet);\n"
"\n\n\n\n\n\n"
"use constant PROJECT_VERSION => '2.15dev';\n"
"push @EXPORT, qw(PROJECT_VERSION);\n"
"\n\n\n\n\n\n"
"use constant REPOSITORY_FORMAT => 5;\n"
"push @EXPORT, qw(REPOSITORY_FORMAT);\n"
"\n"
"1;\n"
},
};