diff --git a/.travis.yml b/.travis.yml index d657af7f0..319ac68df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,8 @@ services: - docker env: - - PGB_CI="--vm=co6 test" - PGB_CI="--vm=u16 test" + - PGB_CI="--vm=co6 test" - PGB_CI="--vm=co7 test" - PGB_CI="--vm=u12 test" - PGB_CI="doc" diff --git a/build/lib/pgBackRestBuild/Build/Common.pm b/build/lib/pgBackRestBuild/Build/Common.pm index d55299db5..9691938e6 100644 --- a/build/lib/pgBackRestBuild/Build/Common.pm +++ b/build/lib/pgBackRestBuild/Build/Common.pm @@ -33,8 +33,6 @@ use constant BLD_HEADER => 'h'; use constant BLD_CONSTANT => 'constant'; push @EXPORT, qw(BLD_CONSTANT); -use constant BLD_CONSTANT_EXPORT => 'constantExport'; - push @EXPORT, qw(BLD_CONSTANT_EXPORT); use constant BLD_CONSTANT_GROUP => 'constantGroup'; push @EXPORT, qw(BLD_CONSTANT_GROUP); use constant BLD_CONSTANT_VALUE => 'constantValue'; diff --git a/build/lib/pgBackRestBuild/Embed/Build.pm b/build/lib/pgBackRestBuild/Embed/Build.pm new file mode 100644 index 000000000..7e479d6f9 --- /dev/null +++ b/build/lib/pgBackRestBuild/Embed/Build.pm @@ -0,0 +1,115 @@ +#################################################################################################################################### +# Auto-Generate Embedded Perl Modules +#################################################################################################################################### +package pgBackRestBuild::Embed::Build; + +use strict; +use warnings FATAL => qw(all); +use Carp qw(confess); +use English '-no_match_vars'; + +use Exporter qw(import); + our @EXPORT = qw(); + +use pgBackRestBuild::Build::Common; + +use pgBackRest::Common::Log; +use pgBackRest::Common::String; + +#################################################################################################################################### +# Constants +#################################################################################################################################### +use constant BLDLCL_FILE_DEFINE => 'embed'; + +use constant BLDLCL_DATA_EMBED => '01-dataEmbed'; + +#################################################################################################################################### +# Definitions for constants and data to build +#################################################################################################################################### +my $strSummary = 'Embed Perl modules'; + +my $rhBuild = +{ + &BLD_FILE => + { + &BLDLCL_FILE_DEFINE => + { + &BLD_SUMMARY => $strSummary, + + &BLD_DATA => + { + &BLDLCL_DATA_EMBED => + { + &BLD_SUMMARY => 'Embedded Perl modules', + }, + }, + }, + }, +}; + +#################################################################################################################################### +# Embed Perl modules +#################################################################################################################################### +sub buildEmbed +{ + my $oStorage = shift; + + # Output embedded modules array + my $strBuildSource = + "static const EmbeddedModule embeddedModule[] =\n" . + "{\n"; + + foreach my $strModule (sort(keys(%{$oStorage->manifest('lib')}))) + { + # Ignore non-Perl modules + if ($strModule =~ /\.pm$/) + { + # Load data + my $strData = trim(${$oStorage->get("lib/${strModule}")}); + + # Escape \ and quotes + $strData =~ s/\\/\\\\/g; + $strData =~ s/\"/\\\"/g; + + $strBuildSource .= + " {\n" . + " .name = \"${strModule}\",\n" . + " .data =\n"; + + # Process each line + foreach my $strLine (split("\n", $strData)) + { + # Remove comments + $strLine =~ s/^\s*\#.*$//; + $strLine =~ s/\#[^\'\"]*$//; + + # Remove spacing in constant declarations + if ($strLine =~ /use constant [A-Z0-9_]+/) + { + $strLine =~ s/\s{2,}\=\> / \=\> /g; + } + + # Remove leading/trailing spaces + $strLine = trim($strLine); + + # Output line + $strBuildSource .= + " \"$strLine\\n\"\n"; + } + + $strBuildSource .= + " },\n"; + } + } + + $strBuildSource .= + "};"; + + $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_EMBED}{&BLD_SOURCE} = $strBuildSource; + + return $rhBuild; +} + +push @EXPORT, qw(buildEmbed); + +1; diff --git a/doc/xml/release.xml b/doc/xml/release.xml index 45522ef7f..96c33b935 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -33,6 +33,10 @@ + +

Embed exported C functions and Perl modules directly into the executable.

+
+ diff --git a/doc/xml/user-guide.xml b/doc/xml/user-guide.xml index 204783fbb..d27c826bf 100644 --- a/doc/xml/user-guide.xml +++ b/doc/xml/user-guide.xml @@ -205,33 +205,6 @@ -

is written in Perl which is included with {[user-guide-os]} by default. Some additional modules must also be installed but they are available as standard packages.

- - - Install required Perl packages - - - apt-get update - - - - apt-get install libdbd-pg-perl libio-socket-ssl-perl libxml-libxml-perl - -y 2>&1 - - - -

is written in Perl which is not included with {[user-guide-os]} by default, however all required modules are available as standard packages.

- - - Install required Perl packages - - - yum install perl perl-Time-HiRes perl-parent perl-JSON - perl-Digest-SHA perl-DBD-Pg perl-XML-LibXML perl-IO-Socket-SSL - -y 2>&1 - - -

{[user-guide-os]} packages for are available at apt.postgresql.org. If they are not provided for your distribution/version it is easy to download the source and install manually.

{[user-guide-os]} packages for are available from Crunchy Data or yum.postgresql.org, but it is also easy to download the source and install manually.

@@ -250,12 +223,6 @@ mkdir /root/pgbackrest-release-{[version]} - - cp -r /backrest/build /root/pgbackrest-release-{[version]} - - - cp -r /backrest/lib /root/pgbackrest-release-{[version]} - cp -r /backrest/libc /root/pgbackrest-release-{[version]} @@ -264,62 +231,8 @@ - - Install <backrest/> - - - cp -r /root/pgbackrest-release-{[version]}/lib/pgBackRest - {[perl-lib-path]} - - - find {[perl-lib-path]}/pgBackRest -type f -exec chmod 644 {} + - - - find {[perl-lib-path]}/pgBackRest -type d -exec chmod 755 {} + - - - mkdir -m 770 /var/log/pgbackrest - - - chown {[br-install-user]}:{[br-install-group]} /var/log/pgbackrest - - - mkdir {[backrest-config-path]} - - - mkdir {[backrest-config-include-path]} - - - touch {[backrest-config-demo]} - - - chmod 640 {[backrest-config-demo]} - - - chown {[br-install-user]}:{[br-install-group]} {[backrest-config-demo]} - - - - -

requires a companion C library that enhances performance and enables the `checksum-page` option and encryption. Pre-built packages are generally a better option than building the C library manually but the steps required are given below for completeness. Depending on the distribution a number of packages may be required which will not be enumerated here.

- - - Build and Install C Library - - - sh -c 'cd /root/pgbackrest-release-{[version]}/libc && - perl Makefile.PL INSTALLMAN1DIR=none INSTALLMAN3DIR=none' - - - make -C /root/pgbackrest-release-{[version]}/libc test - - - make -C /root/pgbackrest-release-{[version]}/libc install - - - -

Although most of is written in Perl, the main executable is written in C. This allows certain time-critical commands (like async archive-push) to run more quickly.

+

The executable is written in C. This allows certain time-critical commands (like async archive-push/archive-get) to run more quickly.

Build and Install Binary @@ -331,6 +244,62 @@ make -C /root/pgbackrest-release-{[version]}/src install + + +

contains embedded Perl which requires some additional modules.

+ + + Install required Perl packages + + + apt-get update + + + + apt-get install libdbd-pg-perl libio-socket-ssl-perl libxml-libxml-perl + -y 2>&1 + + + +

contains embedded Perl. All required Perl modules are available as standard packages.

+ + + Install required Perl packages + + + yum install perl perl-Time-HiRes perl-parent perl-JSON + perl-Digest-SHA perl-DBD-Pg perl-XML-LibXML perl-IO-Socket-SSL + -y 2>&1 + + + +

Finally, requires log and configuration directories and a configuration file.

+ + + Create <backrest/> configuration file and directories + + + mkdir -p -m 770 /var/log/pgbackrest + + + chown {[br-install-user]}:{[br-install-group]} /var/log/pgbackrest + + + mkdir -p {[backrest-config-path]} + + + mkdir -p {[backrest-config-include-path]} + + + touch {[backrest-config-demo]} + + + chmod 640 {[backrest-config-demo]} + + + chown {[br-install-user]}:{[br-install-group]} {[backrest-config-demo]} + +
@@ -458,31 +427,6 @@ -

If has been installed before it's best to be sure that no prior copies of it are still installed. Depending on how old the version of pgBackRest is it may have been installed in a few different locations. The following commands will remove all prior versions of pgBackRest.

- - - Remove prior <backrest/> installations - - - rm -f /usr/bin/pgbackrest - - - rm -f /usr/bin/pg_backrest - - - rm -rf /usr/lib/perl5/BackRest - - - rm -rf {[perl-lib-path]}/BackRest - - - rm -rf /usr/lib/perl5/pgBackRest - - - rm -rf {[perl-lib-path]}/pgBackRest - - - {[host-pg1]} postgres @@ -2473,7 +2417,7 @@ Create the spool directory - mkdir -m 750 {[spool-path]} + mkdir -p -m 750 {[spool-path]} chown postgres:postgres {[spool-path]} @@ -2484,7 +2428,7 @@ Create the spool directory - mkdir -m 750 {[spool-path]} + mkdir -p -m 750 {[spool-path]} chown postgres:postgres {[spool-path]} diff --git a/lib/pgBackRest/LibC.pm b/lib/pgBackRest/LibC.pm new file mode 100644 index 000000000..cef20077c --- /dev/null +++ b/lib/pgBackRest/LibC.pm @@ -0,0 +1,35 @@ +#################################################################################################################################### +# C to Perl Interface +#################################################################################################################################### +package pgBackRest::LibC; +use base 'Exporter'; + +use 5.010001; +use strict; +use warnings; +use Carp; + +use pgBackRest::LibCAuto; + +# Dynamically create constants +my $rhConstant = pgBackRest::LibCAuto::libcAutoConstant(); + +foreach my $strConstant (keys(%{$rhConstant})) +{ + eval ## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval) + "use constant ${strConstant} => '" . $rhConstant->{$strConstant} . "'"; +} + +# Export functions and constants +our %EXPORT_TAGS = %{pgBackRest::LibCAuto::libcAutoExportTag()}; +our @EXPORT_OK; + +foreach my $strSection (keys(%EXPORT_TAGS)) +{ + push(@EXPORT_OK, @{$EXPORT_TAGS{$strSection}}); +} + +# Nothing is exported by default +our @EXPORT = (); + +1; diff --git a/lib/pgBackRest/LibCAuto.pm b/lib/pgBackRest/LibCAuto.pm new file mode 100644 index 000000000..e5f76c686 --- /dev/null +++ b/lib/pgBackRest/LibCAuto.pm @@ -0,0 +1,388 @@ +#################################################################################################################################### +# Automatically generated by Build.pm -- do not modify directly. +#################################################################################################################################### +package pgBackRest::LibCAuto; + +use strict; +use warnings; + +# Configuration option value constants +sub libcAutoConstant +{ + return + { + CFGOPTVAL_INFO_OUTPUT_TEXT => 'text', + CFGOPTVAL_INFO_OUTPUT_JSON => 'json', + + CFGOPTVAL_REPO_CIPHER_TYPE_NONE => 'none', + CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC => 'aes-256-cbc', + + CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_FULL => 'full', + CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_DIFF => 'diff', + CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_INCR => 'incr', + + CFGOPTVAL_REPO_TYPE_CIFS => 'cifs', + CFGOPTVAL_REPO_TYPE_POSIX => 'posix', + CFGOPTVAL_REPO_TYPE_S3 => 's3', + + CFGOPTVAL_RESTORE_TARGET_ACTION_PAUSE => 'pause', + CFGOPTVAL_RESTORE_TARGET_ACTION_PROMOTE => 'promote', + CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN => 'shutdown', + + CFGOPTVAL_BACKUP_TYPE_FULL => 'full', + CFGOPTVAL_BACKUP_TYPE_DIFF => 'diff', + CFGOPTVAL_BACKUP_TYPE_INCR => 'incr', + + CFGOPTVAL_LOCAL_TYPE_DB => 'db', + CFGOPTVAL_LOCAL_TYPE_BACKUP => 'backup', + + CFGOPTVAL_REMOTE_TYPE_DB => 'db', + CFGOPTVAL_REMOTE_TYPE_BACKUP => 'backup', + + CFGOPTVAL_RESTORE_TYPE_NAME => 'name', + CFGOPTVAL_RESTORE_TYPE_TIME => 'time', + CFGOPTVAL_RESTORE_TYPE_XID => 'xid', + CFGOPTVAL_RESTORE_TYPE_PRESERVE => 'preserve', + CFGOPTVAL_RESTORE_TYPE_NONE => 'none', + CFGOPTVAL_RESTORE_TYPE_IMMEDIATE => 'immediate', + CFGOPTVAL_RESTORE_TYPE_DEFAULT => 'default', + + CFGCMD_ARCHIVE_GET => 0, + CFGCMD_ARCHIVE_PUSH => 1, + CFGCMD_BACKUP => 2, + CFGCMD_CHECK => 3, + CFGCMD_EXPIRE => 4, + CFGCMD_HELP => 5, + CFGCMD_INFO => 6, + CFGCMD_LOCAL => 7, + CFGCMD_REMOTE => 8, + CFGCMD_RESTORE => 9, + CFGCMD_STANZA_CREATE => 10, + CFGCMD_STANZA_DELETE => 11, + CFGCMD_STANZA_UPGRADE => 12, + CFGCMD_START => 13, + CFGCMD_STOP => 14, + CFGCMD_VERSION => 15, + + CFGOPT_ARCHIVE_ASYNC => 0, + CFGOPT_ARCHIVE_CHECK => 1, + CFGOPT_ARCHIVE_COPY => 2, + CFGOPT_ARCHIVE_GET_QUEUE_MAX => 3, + CFGOPT_ARCHIVE_PUSH_QUEUE_MAX => 4, + CFGOPT_ARCHIVE_TIMEOUT => 5, + CFGOPT_BACKUP_STANDBY => 6, + CFGOPT_BUFFER_SIZE => 7, + CFGOPT_CHECKSUM_PAGE => 8, + CFGOPT_CMD_SSH => 9, + CFGOPT_COMMAND => 10, + CFGOPT_COMPRESS => 11, + CFGOPT_COMPRESS_LEVEL => 12, + CFGOPT_COMPRESS_LEVEL_NETWORK => 13, + CFGOPT_CONFIG => 14, + CFGOPT_CONFIG_INCLUDE_PATH => 15, + CFGOPT_CONFIG_PATH => 16, + CFGOPT_DB_INCLUDE => 17, + CFGOPT_DB_TIMEOUT => 18, + CFGOPT_DELTA => 19, + CFGOPT_FORCE => 20, + CFGOPT_HOST_ID => 21, + CFGOPT_LINK_ALL => 22, + CFGOPT_LINK_MAP => 23, + CFGOPT_LOCK_PATH => 24, + CFGOPT_LOG_LEVEL_CONSOLE => 25, + CFGOPT_LOG_LEVEL_FILE => 26, + CFGOPT_LOG_LEVEL_STDERR => 27, + CFGOPT_LOG_PATH => 28, + CFGOPT_LOG_TIMESTAMP => 29, + CFGOPT_MANIFEST_SAVE_THRESHOLD => 30, + CFGOPT_NEUTRAL_UMASK => 31, + CFGOPT_ONLINE => 32, + CFGOPT_OUTPUT => 33, + CFGOPT_PERL_OPTION => 34, + CFGOPT_PG_HOST => 35, + CFGOPT_PG_HOST_CMD => 43, + CFGOPT_PG_HOST_CONFIG => 51, + CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH => 59, + CFGOPT_PG_HOST_CONFIG_PATH => 67, + CFGOPT_PG_HOST_PORT => 75, + CFGOPT_PG_HOST_USER => 83, + CFGOPT_PG_PATH => 91, + CFGOPT_PG_PORT => 99, + CFGOPT_PG_SOCKET_PATH => 107, + CFGOPT_PROCESS => 115, + CFGOPT_PROCESS_MAX => 116, + CFGOPT_PROTOCOL_TIMEOUT => 117, + CFGOPT_RECOVERY_OPTION => 118, + CFGOPT_REPO_CIPHER_PASS => 119, + CFGOPT_REPO_CIPHER_TYPE => 120, + CFGOPT_REPO_HARDLINK => 121, + CFGOPT_REPO_HOST => 122, + CFGOPT_REPO_HOST_CMD => 123, + CFGOPT_REPO_HOST_CONFIG => 124, + CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH => 125, + CFGOPT_REPO_HOST_CONFIG_PATH => 126, + CFGOPT_REPO_HOST_PORT => 127, + CFGOPT_REPO_HOST_USER => 128, + CFGOPT_REPO_PATH => 129, + CFGOPT_REPO_RETENTION_ARCHIVE => 130, + CFGOPT_REPO_RETENTION_ARCHIVE_TYPE => 131, + CFGOPT_REPO_RETENTION_DIFF => 132, + CFGOPT_REPO_RETENTION_FULL => 133, + CFGOPT_REPO_S3_BUCKET => 134, + CFGOPT_REPO_S3_CA_FILE => 135, + CFGOPT_REPO_S3_CA_PATH => 136, + CFGOPT_REPO_S3_ENDPOINT => 137, + CFGOPT_REPO_S3_HOST => 138, + CFGOPT_REPO_S3_KEY => 139, + CFGOPT_REPO_S3_KEY_SECRET => 140, + CFGOPT_REPO_S3_REGION => 141, + CFGOPT_REPO_S3_TOKEN => 142, + CFGOPT_REPO_S3_VERIFY_SSL => 143, + CFGOPT_REPO_TYPE => 144, + CFGOPT_RESUME => 145, + CFGOPT_SET => 146, + CFGOPT_SPOOL_PATH => 147, + CFGOPT_STANZA => 148, + CFGOPT_START_FAST => 149, + CFGOPT_STOP_AUTO => 150, + CFGOPT_TABLESPACE_MAP => 151, + CFGOPT_TABLESPACE_MAP_ALL => 152, + CFGOPT_TARGET => 153, + CFGOPT_TARGET_ACTION => 154, + CFGOPT_TARGET_EXCLUSIVE => 155, + CFGOPT_TARGET_TIMELINE => 156, + CFGOPT_TEST => 157, + CFGOPT_TEST_DELAY => 158, + CFGOPT_TEST_POINT => 159, + CFGOPT_TYPE => 160, + + CFGDEF_TYPE_BOOLEAN => 0, + CFGDEF_TYPE_FLOAT => 1, + CFGDEF_TYPE_HASH => 2, + CFGDEF_TYPE_INTEGER => 3, + CFGDEF_TYPE_LIST => 4, + CFGDEF_TYPE_SIZE => 5, + CFGDEF_TYPE_STRING => 6, + + ENCODE_TYPE_BASE64 => 0, + + CIPHER_MODE_ENCRYPT => 0, + CIPHER_MODE_DECRYPT => 1, + } +} + +# Export function and constants +sub libcAutoExportTag +{ + return + { + checksum => + [ + 'pageChecksum', + 'pageChecksumBufferTest', + 'pageChecksumTest', + ], + + cipher => + [ + 'CIPHER_MODE_ENCRYPT', + 'CIPHER_MODE_DECRYPT', + ], + + config => + [ + 'CFGOPTVAL_INFO_OUTPUT_TEXT', + 'CFGOPTVAL_INFO_OUTPUT_JSON', + 'CFGOPTVAL_REPO_CIPHER_TYPE_NONE', + 'CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC', + 'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_FULL', + 'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_DIFF', + 'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_INCR', + 'CFGOPTVAL_REPO_TYPE_CIFS', + 'CFGOPTVAL_REPO_TYPE_POSIX', + 'CFGOPTVAL_REPO_TYPE_S3', + 'CFGOPTVAL_RESTORE_TARGET_ACTION_PAUSE', + 'CFGOPTVAL_RESTORE_TARGET_ACTION_PROMOTE', + 'CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN', + 'CFGOPTVAL_BACKUP_TYPE_FULL', + 'CFGOPTVAL_BACKUP_TYPE_DIFF', + 'CFGOPTVAL_BACKUP_TYPE_INCR', + 'CFGOPTVAL_LOCAL_TYPE_DB', + 'CFGOPTVAL_LOCAL_TYPE_BACKUP', + 'CFGOPTVAL_REMOTE_TYPE_DB', + 'CFGOPTVAL_REMOTE_TYPE_BACKUP', + 'CFGOPTVAL_RESTORE_TYPE_NAME', + 'CFGOPTVAL_RESTORE_TYPE_TIME', + 'CFGOPTVAL_RESTORE_TYPE_XID', + 'CFGOPTVAL_RESTORE_TYPE_PRESERVE', + 'CFGOPTVAL_RESTORE_TYPE_NONE', + 'CFGOPTVAL_RESTORE_TYPE_IMMEDIATE', + 'CFGOPTVAL_RESTORE_TYPE_DEFAULT', + 'CFGCMD_ARCHIVE_GET', + 'CFGCMD_ARCHIVE_PUSH', + 'CFGCMD_BACKUP', + 'CFGCMD_CHECK', + 'CFGCMD_EXPIRE', + 'CFGCMD_HELP', + 'CFGCMD_INFO', + 'CFGCMD_LOCAL', + 'CFGCMD_REMOTE', + 'CFGCMD_RESTORE', + 'CFGCMD_STANZA_CREATE', + 'CFGCMD_STANZA_DELETE', + 'CFGCMD_STANZA_UPGRADE', + 'CFGCMD_START', + 'CFGCMD_STOP', + 'CFGCMD_VERSION', + 'CFGOPT_ARCHIVE_ASYNC', + 'CFGOPT_ARCHIVE_CHECK', + 'CFGOPT_ARCHIVE_COPY', + 'CFGOPT_ARCHIVE_GET_QUEUE_MAX', + 'CFGOPT_ARCHIVE_PUSH_QUEUE_MAX', + 'CFGOPT_ARCHIVE_TIMEOUT', + 'CFGOPT_BACKUP_STANDBY', + 'CFGOPT_BUFFER_SIZE', + 'CFGOPT_CHECKSUM_PAGE', + 'CFGOPT_CMD_SSH', + 'CFGOPT_COMMAND', + 'CFGOPT_COMPRESS', + 'CFGOPT_COMPRESS_LEVEL', + 'CFGOPT_COMPRESS_LEVEL_NETWORK', + 'CFGOPT_CONFIG', + 'CFGOPT_CONFIG_INCLUDE_PATH', + 'CFGOPT_CONFIG_PATH', + 'CFGOPT_DB_INCLUDE', + 'CFGOPT_DB_TIMEOUT', + 'CFGOPT_DELTA', + 'CFGOPT_FORCE', + 'CFGOPT_HOST_ID', + 'CFGOPT_LINK_ALL', + 'CFGOPT_LINK_MAP', + 'CFGOPT_LOCK_PATH', + 'CFGOPT_LOG_LEVEL_CONSOLE', + 'CFGOPT_LOG_LEVEL_FILE', + 'CFGOPT_LOG_LEVEL_STDERR', + 'CFGOPT_LOG_PATH', + 'CFGOPT_LOG_TIMESTAMP', + 'CFGOPT_MANIFEST_SAVE_THRESHOLD', + 'CFGOPT_NEUTRAL_UMASK', + 'CFGOPT_ONLINE', + 'CFGOPT_OUTPUT', + 'CFGOPT_PERL_OPTION', + 'CFGOPT_PG_HOST', + 'CFGOPT_PG_HOST_CMD', + 'CFGOPT_PG_HOST_CONFIG', + 'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH', + 'CFGOPT_PG_HOST_CONFIG_PATH', + 'CFGOPT_PG_HOST_PORT', + 'CFGOPT_PG_HOST_USER', + 'CFGOPT_PG_PATH', + 'CFGOPT_PG_PORT', + 'CFGOPT_PG_SOCKET_PATH', + 'CFGOPT_PROCESS', + 'CFGOPT_PROCESS_MAX', + 'CFGOPT_PROTOCOL_TIMEOUT', + 'CFGOPT_RECOVERY_OPTION', + 'CFGOPT_REPO_CIPHER_PASS', + 'CFGOPT_REPO_CIPHER_TYPE', + 'CFGOPT_REPO_HARDLINK', + 'CFGOPT_REPO_HOST', + 'CFGOPT_REPO_HOST_CMD', + 'CFGOPT_REPO_HOST_CONFIG', + 'CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH', + 'CFGOPT_REPO_HOST_CONFIG_PATH', + 'CFGOPT_REPO_HOST_PORT', + 'CFGOPT_REPO_HOST_USER', + 'CFGOPT_REPO_PATH', + 'CFGOPT_REPO_RETENTION_ARCHIVE', + 'CFGOPT_REPO_RETENTION_ARCHIVE_TYPE', + 'CFGOPT_REPO_RETENTION_DIFF', + 'CFGOPT_REPO_RETENTION_FULL', + 'CFGOPT_REPO_S3_BUCKET', + 'CFGOPT_REPO_S3_CA_FILE', + 'CFGOPT_REPO_S3_CA_PATH', + 'CFGOPT_REPO_S3_ENDPOINT', + 'CFGOPT_REPO_S3_HOST', + 'CFGOPT_REPO_S3_KEY', + 'CFGOPT_REPO_S3_KEY_SECRET', + 'CFGOPT_REPO_S3_REGION', + 'CFGOPT_REPO_S3_TOKEN', + 'CFGOPT_REPO_S3_VERIFY_SSL', + 'CFGOPT_REPO_TYPE', + 'CFGOPT_RESUME', + 'CFGOPT_SET', + 'CFGOPT_SPOOL_PATH', + 'CFGOPT_STANZA', + 'CFGOPT_START_FAST', + 'CFGOPT_STOP_AUTO', + 'CFGOPT_TABLESPACE_MAP', + 'CFGOPT_TABLESPACE_MAP_ALL', + 'CFGOPT_TARGET', + 'CFGOPT_TARGET_ACTION', + 'CFGOPT_TARGET_EXCLUSIVE', + 'CFGOPT_TARGET_TIMELINE', + 'CFGOPT_TEST', + 'CFGOPT_TEST_DELAY', + 'CFGOPT_TEST_POINT', + 'CFGOPT_TYPE', + 'cfgCommandName', + 'cfgOptionIndex', + 'cfgOptionIndexTotal', + 'cfgOptionName', + ], + + configDefine => + [ + 'CFGDEF_TYPE_BOOLEAN', + 'CFGDEF_TYPE_FLOAT', + 'CFGDEF_TYPE_HASH', + 'CFGDEF_TYPE_INTEGER', + 'CFGDEF_TYPE_LIST', + 'CFGDEF_TYPE_SIZE', + 'CFGDEF_TYPE_STRING', + 'cfgCommandId', + 'cfgDefOptionDefault', + 'cfgDefOptionPrefix', + 'cfgDefOptionSecure', + 'cfgDefOptionType', + 'cfgDefOptionValid', + 'cfgOptionId', + 'cfgOptionTotal', + ], + + debug => + [ + 'libcUvSize', + ], + + encode => + [ + 'ENCODE_TYPE_BASE64', + 'decodeToBin', + 'encodeToStr', + ], + + lock => + [ + 'lockAcquire', + 'lockRelease', + ], + + random => + [ + 'randomBytes', + ], + + storage => + [ + 'storageDriverPosixPathRemove', + ], + + test => + [ + 'cfgParseTest', + ], + } +} + +1; diff --git a/libc/LibC.xs b/libc/LibC.xs index 5e0a05751..2f6543737 100644 --- a/libc/LibC.xs +++ b/libc/LibC.xs @@ -28,12 +28,17 @@ Order is critical here so don't change it. #pragma GCC diagnostic ignored "-Wuninitialized" #endif +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wconversion" + #include #include #include -#if WARNING_MAYBE_INITIALIZED || WARNING_INITIALIZED - #pragma GCC diagnostic pop +#if WARNING_MAYBE_INITIALIZED + #pragma GCC diagnostic warning "-Wmaybe-uninitialized" +#elif WARNING_INITIALIZED + #pragma GCC diagnostic warning "-Wuninitialized" #endif /*********************************************************************************************************************************** @@ -64,19 +69,6 @@ These includes define data structures that are required for the C to Perl interf ***********************************************************************************************************************************/ #include "xs/cipher/block.xsh" #include "xs/common/encode.xsh" -#include "xs/config/config.auto.xsh" -#include "xs/config/define.auto.xsh" - -/*********************************************************************************************************************************** -Constant include - -Auto generated code that handles exporting C constants to Perl. -***********************************************************************************************************************************/ -#pragma GCC diagnostic ignored "-Wunused-parameter" - -#include "const-c.inc" - -#pragma GCC diagnostic warning "-Wunused-parameter" /*********************************************************************************************************************************** Module definition @@ -84,15 +76,14 @@ Module definition MODULE = pgBackRest::LibC PACKAGE = pgBackRest::LibC PROTOTYPES: DISABLE -# Exported constants -# -# The XS portion of the code that handles exporting C constants to Perl. +# Return UVSIZE to ensure that this Perl supports 64-bit integers # ---------------------------------------------------------------------------------------------------------------------------------- -#pragma GCC diagnostic ignored "-Wuninitialized" - -INCLUDE: const-xs.inc - -#pragma GCC diagnostic warning "-Wuninitialized" +I32 +libcUvSize() +CODE: + RETVAL = UVSIZE; +OUTPUT: + RETVAL # Exported functions and modules # diff --git a/libc/Makefile.PL b/libc/Makefile.PL index a6a0e3b60..3c6a36219 100644 --- a/libc/Makefile.PL +++ b/libc/Makefile.PL @@ -17,9 +17,6 @@ use File::Basename qw(dirname); use lib dirname($0) . '/lib'; use lib dirname($0) . '/build/lib'; -use pgBackRest::LibCAuto; -use pgBackRestLibC::BuildParam; - #################################################################################################################################### # Storage object to use for all file operations #################################################################################################################################### @@ -27,45 +24,6 @@ use constant BACKREST_NAME => 'pgBackRe use constant LIB_NAME => 'LibC'; use constant LIB_AUTO_NAME => LIB_NAME . 'Auto'; -#################################################################################################################################### -# Build list of constants to export from C and add them to the constant array -#################################################################################################################################### -{ - # Build constants - my $rhExport = pgBackRest::LibCAuto::libcAutoExportTag(); - my @stryConstant; - - foreach my $strSection (sort(keys(%{$rhExport}))) - { - # Search exports for constants - foreach my $strExport (@{$rhExport->{$strSection}}) - { - # Constants will be upper-case - if (uc($strExport) eq $strExport) - { - push(@stryConstant, $strExport); - } - } - } - - # Build constant C code - if (eval {require ExtUtils::Constant; 1}) - { - ExtUtils::Constant::WriteConstants - ( - NAME => BACKREST_NAME . '::' . LIB_NAME, - NAMES => \@stryConstant, - DEFAULT_TYPE => 'IV', - C_FILE => 'const-c.inc', - XS_FILE => 'const-xs.inc', - ); - } - else - { - die "ExtUtils::Constant is required to build constants!"; - } -} - #################################################################################################################################### # Create C Makefile #################################################################################################################################### @@ -145,22 +103,21 @@ for (my $iFileIdx = 1; $iFileIdx < @stryCFile; $iFileIdx++) WriteMakefile ( NAME => BACKREST_NAME . '::LibC', - VERSION_FROM => 'lib/' . BACKREST_NAME . '/LibC.pm', + VERSION => '999', AUTHOR => 'David Steele ', - CCFLAGS => join(' ', buildParamCCAll()), + CCFLAGS => join(' ', qw) + -Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered -Wno-missing-field-initializers + -o $@ + -std=c99 + -D_FILE_OFFSET_BITS=64 + )), INC => join(' ', qw( -I. -I../src )), - PM => - { - ('lib/' . BACKREST_NAME . '/' . LIB_NAME . '.pm') => ('$(INST_LIB)/' . BACKREST_NAME . '/' . LIB_NAME . '.pm'), - ('lib/' . BACKREST_NAME . '/' . LIB_AUTO_NAME . '.pm') => ('$(INST_LIB)/' . BACKREST_NAME . '/' . LIB_AUTO_NAME . '.pm'), - }, - C => \@stryCFile, LIBS => [-lcrypto], diff --git a/libc/build/lib/pgBackRestLibC/Build.pm b/libc/build/lib/pgBackRestLibC/Build.pm index 7596e8636..6458da2bc 100644 --- a/libc/build/lib/pgBackRestLibC/Build.pm +++ b/libc/build/lib/pgBackRestLibC/Build.pm @@ -28,9 +28,6 @@ use pgBackRestBuild::Build; use pgBackRestBuild::Build::Common; use pgBackRestBuild::Error::Data; -use pgBackRestLibC::Config::Build; -use pgBackRestLibC::Config::BuildDefine; - #################################################################################################################################### # Perl function and constant exports #################################################################################################################################### @@ -87,12 +84,8 @@ my $rhExport = 'debug' => { - &BLD_EXPORTTYPE_CONSTANT => [qw( - UVSIZE - )], - &BLD_EXPORTTYPE_SUB => [qw( - libcVersion + libcUvSize )], }, @@ -145,37 +138,10 @@ sub buildXsAll { my $strBuildPath = shift; - my $rhBuild = - { - 'config' => - { - &BLD_DATA => buildXsConfig(), - &BLD_PATH => 'xs/config', - }, - - 'configDefine' => - { - &BLD_DATA => buildXsConfigDefine(), - &BLD_PATH => 'xs/config', - }, - }; - - buildAll($strBuildPath, $rhBuild, 'xs'); - # Storage my $oStorage = new pgBackRest::Storage::Local( $strBuildPath, new pgBackRest::Storage::Posix::Driver({bFileSync => false, bPathSync => false})); - # Get current version - my $strVersion = BACKREST_VERSION; - my $bDev = false; - - if ($strVersion =~ /dev$/) - { - $strVersion = substr($strVersion, 0, length($strVersion) - 3) . '.999'; - $bDev = true; - } - # Build interface file my $strContent = ('#' x 132) . "\n" . @@ -183,11 +149,8 @@ sub buildXsAll ('#' x 132) . "\n" . "package pgBackRest::LibCAuto;\n" . "\n" . - "# Library version (.999 indicates development version)\n" . - "sub libcAutoVersion\n" . - "{\n" . - " return '${strVersion}';\n" . - "}\n"; + "use strict;\n" . + "use warnings;\n"; # Generate constants for options that have a list of strings as allowed values my $rhConfigDefine = cfgDefine(); @@ -234,6 +197,73 @@ sub buildXsAll } } + # Generate command constants + $strConstantBlock .= defined($strConstantBlock) ? "\n" : ''; + my $iIndex = 0; + + foreach my $strCommand (cfgDefineCommandList()) + { + my $strConstant = "CFGCMD_" . uc($strCommand); + $strConstant =~ s/\-/\_/g; + + $strConstantBlock .= + " ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> $iIndex,\n"; + push(@{$rhExport->{'config'}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant); + + $iIndex++; + } + + # Generate option constants + $strConstantBlock .= defined($strConstantBlock) ? "\n" : ''; + $iIndex = 0; + + foreach my $strOption (sort(keys(%{$rhConfigDefine}))) + { + # Build Perl constant + my $strConstant = "CFGOPT_" . uc($strOption); + $strConstant =~ s/\-/\_/g; + + $strConstantBlock .= + " ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> $iIndex,\n"; + push(@{$rhExport->{'config'}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant); + + $iIndex += $rhConfigDefine->{$strOption}{&CFGDEF_INDEX_TOTAL}; + } + + # Generate option type constants + $strConstantBlock .= defined($strConstantBlock) ? "\n" : ''; + $iIndex = 0; + + foreach my $strOptionType (cfgDefineOptionTypeList()) + { + # Build Perl constant + my $strConstant = "CFGDEF_TYPE_" . uc($strOptionType); + $strConstant =~ s/\-/\_/g; + + $strConstantBlock .= + " ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> $iIndex,\n"; + push(@{$rhExport->{'configDefine'}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant); + + $iIndex++; + }; + + # Generate encode type constants + $strConstantBlock .= defined($strConstantBlock) ? "\n" : ''; + + my $strConstant = "ENCODE_TYPE_BASE64"; + $strConstantBlock .= + " ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> 0,\n"; + + # Generate cipher type constants + $strConstantBlock .= defined($strConstantBlock) ? "\n" : ''; + + $strConstant = "CIPHER_MODE_ENCRYPT"; + $strConstantBlock .= + " ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> 0,\n"; + $strConstant = "CIPHER_MODE_DECRYPT"; + $strConstantBlock .= + " ${strConstant}" . (' ' x (69 - length($strConstant) - 4)) . "=> 1,\n"; + $strContent .= "\n" . "# Configuration option value constants\n" . @@ -245,29 +275,6 @@ sub buildXsAll " }\n" . "}\n"; - foreach my $strBuild (sort(keys(%{$rhBuild}))) - { - foreach my $strFile (sort(keys(%{$rhBuild->{$strBuild}{&BLD_DATA}{&BLD_FILE}}))) - { - my $rhFileConstant = $rhBuild->{$strBuild}{&BLD_DATA}{&BLD_FILE}{$strFile}{&BLD_CONSTANT_GROUP}; - - foreach my $strConstantGroup (sort(keys(%{$rhFileConstant}))) - { - my $rhConstantGroup = $rhFileConstant->{$strConstantGroup}; - - foreach my $strConstant (sort(keys(%{$rhConstantGroup->{&BLD_CONSTANT}}))) - { - my $rhConstant = $rhConstantGroup->{&BLD_CONSTANT}{$strConstant}; - - if ($rhConstant->{&BLD_CONSTANT_EXPORT}) - { - push(@{$rhExport->{$strBuild}{&BLD_EXPORTTYPE_CONSTANT}}, $strConstant); - } - } - } - } - } - # Generate export tags my $strExportTags; @@ -313,7 +320,7 @@ sub buildXsAll "1;\n"; # Save the file - $oStorage->put('lib/' . BACKREST_NAME . '/' . LIB_AUTO_NAME . '.pm', $strContent); + $oStorage->put('../lib/' . BACKREST_NAME . '/' . LIB_AUTO_NAME . '.pm', $strContent); # Build error file #------------------------------------------------------------------------------------------------------------------------------- diff --git a/libc/build/lib/pgBackRestLibC/BuildParam.pm b/libc/build/lib/pgBackRestLibC/BuildParam.pm deleted file mode 100644 index d591fb943..000000000 --- a/libc/build/lib/pgBackRestLibC/BuildParam.pm +++ /dev/null @@ -1,46 +0,0 @@ -#################################################################################################################################### -# Parameters used by LibC builds -#################################################################################################################################### -package pgBackRestLibC::BuildParam; - -use strict; -use warnings FATAL => qw(all); -use Carp qw(confess); -use English '-no_match_vars'; - -use Exporter qw(import); - our @EXPORT = qw(); - -#################################################################################################################################### -# All CC params used for a debug build -#################################################################################################################################### -sub buildParamCCDebug -{ - return qw( - -Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered -Wno-missing-field-initializers - -o $@ - -std=c99 - -D_FILE_OFFSET_BITS=64 - $(CFLAGS)); -} - -push @EXPORT, qw(buildParamCCDebug); - -#################################################################################################################################### -# All CC params used for a production build -#################################################################################################################################### -sub buildParamCCAll -{ - my @stryParams = buildParamCCDebug; - - push(@stryParams, qw( - -DNDEBUG - -funroll-loops - -ftree-vectorize)); - - return @stryParams; -} - -push @EXPORT, qw(buildParamCCAll); - -1; diff --git a/libc/build/lib/pgBackRestLibC/Config/Build.pm b/libc/build/lib/pgBackRestLibC/Config/Build.pm deleted file mode 100644 index 62a8dfe6b..000000000 --- a/libc/build/lib/pgBackRestLibC/Config/Build.pm +++ /dev/null @@ -1,105 +0,0 @@ -#################################################################################################################################### -# Auto-Generate Command and Option Configuration Constants for Export to Perl -#################################################################################################################################### -package pgBackRestLibC::Config::Build; - -use strict; -use warnings FATAL => qw(all); -use Carp qw(confess); -use English '-no_match_vars'; - -use Cwd qw(abs_path); -use Exporter qw(import); - our @EXPORT = qw(); -use File::Basename qw(dirname); -use Storable qw(dclone); - -use pgBackRest::Common::Log; -use pgBackRest::Common::String; -use pgBackRestBuild::Config::Data; -use pgBackRest::Version; - -use pgBackRestBuild::Build::Common; -use pgBackRestBuild::Config::Build; - -#################################################################################################################################### -# Constants -#################################################################################################################################### -use constant BLDLCL_FILE_CONFIG => 'config'; - -use constant BLDLCL_CONSTANT_COMMAND => '01-command'; -use constant BLDLCL_CONSTANT_OPTION => '02-option'; - -#################################################################################################################################### -# Definitions for constants and data to build -#################################################################################################################################### -my $rhBuild = -{ - &BLD_FILE => - { - #--------------------------------------------------------------------------------------------------------------------------- - &BLDLCL_FILE_CONFIG => - { - &BLD_SUMMARY => 'Command and Option Configuration', - - &BLD_CONSTANT_GROUP => - { - &BLDLCL_CONSTANT_COMMAND => - { - &BLD_SUMMARY => 'Command', - &BLD_CONSTANT => {}, - }, - - &BLDLCL_CONSTANT_OPTION => - { - &BLD_SUMMARY => 'Option', - &BLD_CONSTANT => {}, - }, - }, - }, - }, -}; - -#################################################################################################################################### -# Build constants and data -#################################################################################################################################### -sub buildXsConfig -{ - # Build command constants and data - #------------------------------------------------------------------------------------------------------------------------------- - my $rhConstant = $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_CONSTANT_GROUP}{&BLDLCL_CONSTANT_COMMAND}{&BLD_CONSTANT}; - - foreach my $strCommand (cfgDefineCommandList()) - { - # Build Perl constant - my $strCommandEnum = buildConfigCommandEnum($strCommand); - my $strCommandConstant = "CFGCMD_" . uc($strCommand); - $strCommandConstant =~ s/\-/\_/g; - - $rhConstant->{$strCommandConstant}{&BLD_CONSTANT_VALUE} = $strCommandEnum; - $rhConstant->{$strCommandConstant}{&BLD_CONSTANT_EXPORT} = true; - } - - - # Build option constants and data - #------------------------------------------------------------------------------------------------------------------------------- - my $rhConfigDefine = cfgDefine(); - $rhConstant = $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_CONSTANT_GROUP}{&BLDLCL_CONSTANT_OPTION}{&BLD_CONSTANT}; - - foreach my $strOption (sort(keys(%{$rhConfigDefine}))) - { - # Build Perl constant - my $strOptionEnum = buildConfigOptionEnum($strOption); - my $strOptionConstant = "CFGOPT_" . uc($strOption); - $strOptionConstant =~ s/\-/\_/g; - - $rhConstant->{$strOptionConstant}{&BLD_CONSTANT_VALUE} = $strOptionEnum; - $rhConstant->{$strOptionConstant}{&BLD_CONSTANT_EXPORT} = true; - } - - return $rhBuild; -} - -push @EXPORT, qw(buildXsConfig); - -1; diff --git a/libc/build/lib/pgBackRestLibC/Config/BuildDefine.pm b/libc/build/lib/pgBackRestLibC/Config/BuildDefine.pm deleted file mode 100644 index 39bed9839..000000000 --- a/libc/build/lib/pgBackRestLibC/Config/BuildDefine.pm +++ /dev/null @@ -1,81 +0,0 @@ -#################################################################################################################################### -# Auto-Generate Command and Option Configuration Definition Constants for Export to Perl -#################################################################################################################################### -package pgBackRestLibC::Config::BuildDefine; - -use strict; -use warnings FATAL => qw(all); -use Carp qw(confess); -use English '-no_match_vars'; - -use Cwd qw(abs_path); -use Exporter qw(import); - our @EXPORT = qw(); -use File::Basename qw(dirname); -use Storable qw(dclone); - -use pgBackRest::Common::Log; -use pgBackRest::Common::String; -use pgBackRestBuild::Config::Data; -use pgBackRest::Version; - -use pgBackRestBuild::Build::Common; -use pgBackRestBuild::Config::BuildDefine; - -#################################################################################################################################### -# Constants -#################################################################################################################################### -use constant BLDLCL_FILE_DEFINE => 'define'; - -use constant BLDLCL_CONSTANT_OPTION_TYPE => '01-constantOptionType'; - -#################################################################################################################################### -# Definitions for constants and data to build -#################################################################################################################################### -my $strSummary = 'Command and Option Definitions'; - -my $rhBuild = -{ - &BLD_FILE => - { - &BLDLCL_FILE_DEFINE => - { - &BLD_SUMMARY => $strSummary, - - &BLD_CONSTANT_GROUP => - { - &BLDLCL_CONSTANT_OPTION_TYPE => - { - &BLD_SUMMARY => 'Option type', - &BLD_CONSTANT => {}, - }, - }, - }, - }, -}; - -#################################################################################################################################### -# Build configuration constants and data -#################################################################################################################################### -sub buildXsConfigDefine -{ - # Build option type constants - #------------------------------------------------------------------------------------------------------------------------------- - my $rhConstant = $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_CONSTANT_GROUP}{&BLDLCL_CONSTANT_OPTION_TYPE}{&BLD_CONSTANT}; - - foreach my $strOptionType (cfgDefineOptionTypeList()) - { - # Build Perl constant - my $strOptionTypeConstant = "CFGDEF_TYPE_" . uc($strOptionType); - $strOptionTypeConstant =~ s/\-/\_/g; - - $rhConstant->{$strOptionTypeConstant}{&BLD_CONSTANT_VALUE} = buildConfigDefineOptionTypeEnum($strOptionType); - $rhConstant->{$strOptionTypeConstant}{&BLD_CONSTANT_EXPORT} = true; - }; - - return $rhBuild; -} - -push @EXPORT, qw(buildXsConfigDefine); - -1; diff --git a/libc/lib/pgBackRest/LibC.pm b/libc/lib/pgBackRest/LibC.pm deleted file mode 100644 index 4c55480dd..000000000 --- a/libc/lib/pgBackRest/LibC.pm +++ /dev/null @@ -1,70 +0,0 @@ -#################################################################################################################################### -# C to Perl Interface -#################################################################################################################################### -package pgBackRest::LibC; - -use 5.010001; -use strict; -use warnings; -use Carp; - -require Exporter; -use AutoLoader; -our @ISA = qw(Exporter); - -use pgBackRest::LibCAuto; - -# Library version -our $VERSION = pgBackRest::LibCAuto::libcAutoVersion(); - -sub libcVersion -{ - return $VERSION; -} - -# Dynamically create constants -my $rhConstant = pgBackRest::LibCAuto::libcAutoConstant(); - -foreach my $strConstant (keys(%{$rhConstant})) -{ - eval "use constant ${strConstant} => '" . $rhConstant->{$strConstant} . "'"; -} - -# Export function and constants -our %EXPORT_TAGS = %{pgBackRest::LibCAuto::libcAutoExportTag()}; -our @EXPORT_OK; - -foreach my $strSection (keys(%EXPORT_TAGS)) -{ - push(@EXPORT_OK, @{$EXPORT_TAGS{$strSection}}); -} - -# Nothing is exported by default -our @EXPORT = (); - -# Autoload constants from the constant() XS function -sub AUTOLOAD -{ - my $strConstantFunctionName; - our $AUTOLOAD; - - ($strConstantFunctionName = $AUTOLOAD) =~ s/.*:://; - - croak "&pgBackRest::LibC::constant not defined" - if $strConstantFunctionName eq 'constant'; - my ($error, $val) = constant($strConstantFunctionName); - if ($error) {croak $error;} - - { - no strict 'refs'; - *$AUTOLOAD = sub {$val}; - } - - goto &$AUTOLOAD; -} - -require XSLoader; -XSLoader::load('pgBackRest::LibC', $VERSION); - -1; -__END__ diff --git a/libc/lib/pgBackRest/LibCAuto.pm b/libc/lib/pgBackRest/LibCAuto.pm deleted file mode 100644 index b0349ba52..000000000 --- a/libc/lib/pgBackRest/LibCAuto.pm +++ /dev/null @@ -1,270 +0,0 @@ -#################################################################################################################################### -# Automatically generated by Build.pm -- do not modify directly. -#################################################################################################################################### -package pgBackRest::LibCAuto; - -# Library version (.999 indicates development version) -sub libcAutoVersion -{ - return '2.03.999'; -} - -# Configuration option value constants -sub libcAutoConstant -{ - return - { - CFGOPTVAL_INFO_OUTPUT_TEXT => 'text', - CFGOPTVAL_INFO_OUTPUT_JSON => 'json', - - CFGOPTVAL_REPO_CIPHER_TYPE_NONE => 'none', - CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC => 'aes-256-cbc', - - CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_FULL => 'full', - CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_DIFF => 'diff', - CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_INCR => 'incr', - - CFGOPTVAL_REPO_TYPE_CIFS => 'cifs', - CFGOPTVAL_REPO_TYPE_POSIX => 'posix', - CFGOPTVAL_REPO_TYPE_S3 => 's3', - - CFGOPTVAL_RESTORE_TARGET_ACTION_PAUSE => 'pause', - CFGOPTVAL_RESTORE_TARGET_ACTION_PROMOTE => 'promote', - CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN => 'shutdown', - - CFGOPTVAL_BACKUP_TYPE_FULL => 'full', - CFGOPTVAL_BACKUP_TYPE_DIFF => 'diff', - CFGOPTVAL_BACKUP_TYPE_INCR => 'incr', - - CFGOPTVAL_LOCAL_TYPE_DB => 'db', - CFGOPTVAL_LOCAL_TYPE_BACKUP => 'backup', - - CFGOPTVAL_REMOTE_TYPE_DB => 'db', - CFGOPTVAL_REMOTE_TYPE_BACKUP => 'backup', - - CFGOPTVAL_RESTORE_TYPE_NAME => 'name', - CFGOPTVAL_RESTORE_TYPE_TIME => 'time', - CFGOPTVAL_RESTORE_TYPE_XID => 'xid', - CFGOPTVAL_RESTORE_TYPE_PRESERVE => 'preserve', - CFGOPTVAL_RESTORE_TYPE_NONE => 'none', - CFGOPTVAL_RESTORE_TYPE_IMMEDIATE => 'immediate', - CFGOPTVAL_RESTORE_TYPE_DEFAULT => 'default', - } -} - -# Export function and constants -sub libcAutoExportTag -{ - return - { - checksum => - [ - 'pageChecksum', - 'pageChecksumBufferTest', - 'pageChecksumTest', - ], - - cipher => - [ - 'CIPHER_MODE_ENCRYPT', - 'CIPHER_MODE_DECRYPT', - ], - - config => - [ - 'CFGOPTVAL_INFO_OUTPUT_TEXT', - 'CFGOPTVAL_INFO_OUTPUT_JSON', - 'CFGOPTVAL_REPO_CIPHER_TYPE_NONE', - 'CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC', - 'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_FULL', - 'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_DIFF', - 'CFGOPTVAL_REPO_RETENTION_ARCHIVE_TYPE_INCR', - 'CFGOPTVAL_REPO_TYPE_CIFS', - 'CFGOPTVAL_REPO_TYPE_POSIX', - 'CFGOPTVAL_REPO_TYPE_S3', - 'CFGOPTVAL_RESTORE_TARGET_ACTION_PAUSE', - 'CFGOPTVAL_RESTORE_TARGET_ACTION_PROMOTE', - 'CFGOPTVAL_RESTORE_TARGET_ACTION_SHUTDOWN', - 'CFGOPTVAL_BACKUP_TYPE_FULL', - 'CFGOPTVAL_BACKUP_TYPE_DIFF', - 'CFGOPTVAL_BACKUP_TYPE_INCR', - 'CFGOPTVAL_LOCAL_TYPE_DB', - 'CFGOPTVAL_LOCAL_TYPE_BACKUP', - 'CFGOPTVAL_REMOTE_TYPE_DB', - 'CFGOPTVAL_REMOTE_TYPE_BACKUP', - 'CFGOPTVAL_RESTORE_TYPE_NAME', - 'CFGOPTVAL_RESTORE_TYPE_TIME', - 'CFGOPTVAL_RESTORE_TYPE_XID', - 'CFGOPTVAL_RESTORE_TYPE_PRESERVE', - 'CFGOPTVAL_RESTORE_TYPE_NONE', - 'CFGOPTVAL_RESTORE_TYPE_IMMEDIATE', - 'CFGOPTVAL_RESTORE_TYPE_DEFAULT', - 'CFGCMD_ARCHIVE_GET', - 'CFGCMD_ARCHIVE_PUSH', - 'CFGCMD_BACKUP', - 'CFGCMD_CHECK', - 'CFGCMD_EXPIRE', - 'CFGCMD_HELP', - 'CFGCMD_INFO', - 'CFGCMD_LOCAL', - 'CFGCMD_REMOTE', - 'CFGCMD_RESTORE', - 'CFGCMD_STANZA_CREATE', - 'CFGCMD_STANZA_DELETE', - 'CFGCMD_STANZA_UPGRADE', - 'CFGCMD_START', - 'CFGCMD_STOP', - 'CFGCMD_VERSION', - 'CFGOPT_ARCHIVE_ASYNC', - 'CFGOPT_ARCHIVE_CHECK', - 'CFGOPT_ARCHIVE_COPY', - 'CFGOPT_ARCHIVE_GET_QUEUE_MAX', - 'CFGOPT_ARCHIVE_PUSH_QUEUE_MAX', - 'CFGOPT_ARCHIVE_TIMEOUT', - 'CFGOPT_BACKUP_STANDBY', - 'CFGOPT_BUFFER_SIZE', - 'CFGOPT_CHECKSUM_PAGE', - 'CFGOPT_CMD_SSH', - 'CFGOPT_COMMAND', - 'CFGOPT_COMPRESS', - 'CFGOPT_COMPRESS_LEVEL', - 'CFGOPT_COMPRESS_LEVEL_NETWORK', - 'CFGOPT_CONFIG', - 'CFGOPT_CONFIG_INCLUDE_PATH', - 'CFGOPT_CONFIG_PATH', - 'CFGOPT_DB_INCLUDE', - 'CFGOPT_DB_TIMEOUT', - 'CFGOPT_DELTA', - 'CFGOPT_FORCE', - 'CFGOPT_HOST_ID', - 'CFGOPT_LINK_ALL', - 'CFGOPT_LINK_MAP', - 'CFGOPT_LOCK_PATH', - 'CFGOPT_LOG_LEVEL_CONSOLE', - 'CFGOPT_LOG_LEVEL_FILE', - 'CFGOPT_LOG_LEVEL_STDERR', - 'CFGOPT_LOG_PATH', - 'CFGOPT_LOG_TIMESTAMP', - 'CFGOPT_MANIFEST_SAVE_THRESHOLD', - 'CFGOPT_NEUTRAL_UMASK', - 'CFGOPT_ONLINE', - 'CFGOPT_OUTPUT', - 'CFGOPT_PERL_OPTION', - 'CFGOPT_PG_HOST', - 'CFGOPT_PG_HOST_CMD', - 'CFGOPT_PG_HOST_CONFIG', - 'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH', - 'CFGOPT_PG_HOST_CONFIG_PATH', - 'CFGOPT_PG_HOST_PORT', - 'CFGOPT_PG_HOST_USER', - 'CFGOPT_PG_PATH', - 'CFGOPT_PG_PORT', - 'CFGOPT_PG_SOCKET_PATH', - 'CFGOPT_PROCESS', - 'CFGOPT_PROCESS_MAX', - 'CFGOPT_PROTOCOL_TIMEOUT', - 'CFGOPT_RECOVERY_OPTION', - 'CFGOPT_REPO_CIPHER_PASS', - 'CFGOPT_REPO_CIPHER_TYPE', - 'CFGOPT_REPO_HARDLINK', - 'CFGOPT_REPO_HOST', - 'CFGOPT_REPO_HOST_CMD', - 'CFGOPT_REPO_HOST_CONFIG', - 'CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH', - 'CFGOPT_REPO_HOST_CONFIG_PATH', - 'CFGOPT_REPO_HOST_PORT', - 'CFGOPT_REPO_HOST_USER', - 'CFGOPT_REPO_PATH', - 'CFGOPT_REPO_RETENTION_ARCHIVE', - 'CFGOPT_REPO_RETENTION_ARCHIVE_TYPE', - 'CFGOPT_REPO_RETENTION_DIFF', - 'CFGOPT_REPO_RETENTION_FULL', - 'CFGOPT_REPO_S3_BUCKET', - 'CFGOPT_REPO_S3_CA_FILE', - 'CFGOPT_REPO_S3_CA_PATH', - 'CFGOPT_REPO_S3_ENDPOINT', - 'CFGOPT_REPO_S3_HOST', - 'CFGOPT_REPO_S3_KEY', - 'CFGOPT_REPO_S3_KEY_SECRET', - 'CFGOPT_REPO_S3_REGION', - 'CFGOPT_REPO_S3_TOKEN', - 'CFGOPT_REPO_S3_VERIFY_SSL', - 'CFGOPT_REPO_TYPE', - 'CFGOPT_RESUME', - 'CFGOPT_SET', - 'CFGOPT_SPOOL_PATH', - 'CFGOPT_STANZA', - 'CFGOPT_START_FAST', - 'CFGOPT_STOP_AUTO', - 'CFGOPT_TABLESPACE_MAP', - 'CFGOPT_TABLESPACE_MAP_ALL', - 'CFGOPT_TARGET', - 'CFGOPT_TARGET_ACTION', - 'CFGOPT_TARGET_EXCLUSIVE', - 'CFGOPT_TARGET_TIMELINE', - 'CFGOPT_TEST', - 'CFGOPT_TEST_DELAY', - 'CFGOPT_TEST_POINT', - 'CFGOPT_TYPE', - 'cfgCommandName', - 'cfgOptionIndex', - 'cfgOptionIndexTotal', - 'cfgOptionName', - ], - - configDefine => - [ - 'CFGDEF_TYPE_BOOLEAN', - 'CFGDEF_TYPE_FLOAT', - 'CFGDEF_TYPE_HASH', - 'CFGDEF_TYPE_INTEGER', - 'CFGDEF_TYPE_LIST', - 'CFGDEF_TYPE_SIZE', - 'CFGDEF_TYPE_STRING', - 'cfgCommandId', - 'cfgDefOptionDefault', - 'cfgDefOptionPrefix', - 'cfgDefOptionSecure', - 'cfgDefOptionType', - 'cfgDefOptionValid', - 'cfgOptionId', - 'cfgOptionTotal', - ], - - debug => - [ - 'UVSIZE', - 'libcVersion', - ], - - encode => - [ - 'ENCODE_TYPE_BASE64', - 'decodeToBin', - 'encodeToStr', - ], - - lock => - [ - 'lockAcquire', - 'lockRelease', - ], - - random => - [ - 'randomBytes', - ], - - storage => - [ - 'storageDriverPosixPathRemove', - ], - - test => - [ - 'cfgParseTest', - ], - } -} - -1; diff --git a/libc/t/sanity.t b/libc/t/sanity.t index 986a5d28f..4d37ef937 100644 --- a/libc/t/sanity.t +++ b/libc/t/sanity.t @@ -8,17 +8,28 @@ use warnings; use Carp; use English '-no_match_vars'; +use Cwd qw(abs_path); +use File::Basename qw(dirname); + # Set number of tests -use Test::More tests => 4; +use Test::More tests => 5; + +use lib abs_path(dirname($0) . '/../../lib'); # Make sure the module loads without errors BEGIN {use_ok('pgBackRest::LibC', qw(:debug :config :configDefine))}; +require XSLoader; +XSLoader::load('pgBackRest::LibC', '999'); + # UVSIZE determines the pointer and long long int size. This needs to be 8 to indicate 64-bit types are available. -ok (&UVSIZE == 8, 'UVSIZE == 8'); +ok (libcUvSize() == 8, 'UVSIZE == 8'); # Check constant that is created dynamically ok (CFGOPTVAL_BACKUP_TYPE_FULL eq 'full', 'auto constant valid'); # Check constant that is exported from C ok (CFGDEF_TYPE_HASH >= 0, 'auto constant valid'); + +# Check a function +ok (cfgOptionName(CFGOPT_DELTA) eq 'delta', 'auto constant valid'); diff --git a/libc/xs/cipher/block.xsh b/libc/xs/cipher/block.xsh index 9464e7b07..7f4a0d26a 100644 --- a/libc/xs/cipher/block.xsh +++ b/libc/xs/cipher/block.xsh @@ -1,8 +1,8 @@ /*********************************************************************************************************************************** Block Cipher XS Header ***********************************************************************************************************************************/ -#include "../src/common/memContext.h" -#include "../src/cipher/block.h" +#include "common/memContext.h" +#include "cipher/block.h" // Encrypt/decrypt modes #define CIPHER_MODE_ENCRYPT ((int)cipherModeEncrypt) diff --git a/libc/xs/common/encode.xsh b/libc/xs/common/encode.xsh index 65f60aabc..452c8133f 100644 --- a/libc/xs/common/encode.xsh +++ b/libc/xs/common/encode.xsh @@ -1,7 +1,7 @@ /*********************************************************************************************************************************** Binary to String Encode/Decode XS Header ***********************************************************************************************************************************/ -#include "../src/common/encode.h" +#include "common/encode.h" // Encode types #define ENCODE_TYPE_BASE64 ((int)encodeBase64) diff --git a/libc/xs/config/config.auto.xsh b/libc/xs/config/config.auto.xsh deleted file mode 100644 index 79be698fa..000000000 --- a/libc/xs/config/config.auto.xsh +++ /dev/null @@ -1,124 +0,0 @@ -/*********************************************************************************************************************************** -Command and Option Configuration - -Automatically generated by Build.pm -- do not modify directly. -***********************************************************************************************************************************/ -#ifndef XS_CONFIG_CONFIG_AUTO_H -#define XS_CONFIG_CONFIG_AUTO_H - -/*********************************************************************************************************************************** -Command constants -***********************************************************************************************************************************/ -#define CFGCMD_ARCHIVE_GET cfgCmdArchiveGet -#define CFGCMD_ARCHIVE_PUSH cfgCmdArchivePush -#define CFGCMD_BACKUP cfgCmdBackup -#define CFGCMD_CHECK cfgCmdCheck -#define CFGCMD_EXPIRE cfgCmdExpire -#define CFGCMD_HELP cfgCmdHelp -#define CFGCMD_INFO cfgCmdInfo -#define CFGCMD_LOCAL cfgCmdLocal -#define CFGCMD_REMOTE cfgCmdRemote -#define CFGCMD_RESTORE cfgCmdRestore -#define CFGCMD_STANZA_CREATE cfgCmdStanzaCreate -#define CFGCMD_STANZA_DELETE cfgCmdStanzaDelete -#define CFGCMD_STANZA_UPGRADE cfgCmdStanzaUpgrade -#define CFGCMD_START cfgCmdStart -#define CFGCMD_STOP cfgCmdStop -#define CFGCMD_VERSION cfgCmdVersion - -/*********************************************************************************************************************************** -Option constants -***********************************************************************************************************************************/ -#define CFGOPT_ARCHIVE_ASYNC cfgOptArchiveAsync -#define CFGOPT_ARCHIVE_CHECK cfgOptArchiveCheck -#define CFGOPT_ARCHIVE_COPY cfgOptArchiveCopy -#define CFGOPT_ARCHIVE_GET_QUEUE_MAX cfgOptArchiveGetQueueMax -#define CFGOPT_ARCHIVE_PUSH_QUEUE_MAX cfgOptArchivePushQueueMax -#define CFGOPT_ARCHIVE_TIMEOUT cfgOptArchiveTimeout -#define CFGOPT_BACKUP_STANDBY cfgOptBackupStandby -#define CFGOPT_BUFFER_SIZE cfgOptBufferSize -#define CFGOPT_CHECKSUM_PAGE cfgOptChecksumPage -#define CFGOPT_CMD_SSH cfgOptCmdSsh -#define CFGOPT_COMMAND cfgOptCommand -#define CFGOPT_COMPRESS cfgOptCompress -#define CFGOPT_COMPRESS_LEVEL cfgOptCompressLevel -#define CFGOPT_COMPRESS_LEVEL_NETWORK cfgOptCompressLevelNetwork -#define CFGOPT_CONFIG cfgOptConfig -#define CFGOPT_CONFIG_INCLUDE_PATH cfgOptConfigIncludePath -#define CFGOPT_CONFIG_PATH cfgOptConfigPath -#define CFGOPT_DB_INCLUDE cfgOptDbInclude -#define CFGOPT_DB_TIMEOUT cfgOptDbTimeout -#define CFGOPT_DELTA cfgOptDelta -#define CFGOPT_FORCE cfgOptForce -#define CFGOPT_HOST_ID cfgOptHostId -#define CFGOPT_LINK_ALL cfgOptLinkAll -#define CFGOPT_LINK_MAP cfgOptLinkMap -#define CFGOPT_LOCK_PATH cfgOptLockPath -#define CFGOPT_LOG_LEVEL_CONSOLE cfgOptLogLevelConsole -#define CFGOPT_LOG_LEVEL_FILE cfgOptLogLevelFile -#define CFGOPT_LOG_LEVEL_STDERR cfgOptLogLevelStderr -#define CFGOPT_LOG_PATH cfgOptLogPath -#define CFGOPT_LOG_TIMESTAMP cfgOptLogTimestamp -#define CFGOPT_MANIFEST_SAVE_THRESHOLD cfgOptManifestSaveThreshold -#define CFGOPT_NEUTRAL_UMASK cfgOptNeutralUmask -#define CFGOPT_ONLINE cfgOptOnline -#define CFGOPT_OUTPUT cfgOptOutput -#define CFGOPT_PERL_OPTION cfgOptPerlOption -#define CFGOPT_PG_HOST cfgOptPgHost -#define CFGOPT_PG_HOST_CMD cfgOptPgHostCmd -#define CFGOPT_PG_HOST_CONFIG cfgOptPgHostConfig -#define CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH cfgOptPgHostConfigIncludePath -#define CFGOPT_PG_HOST_CONFIG_PATH cfgOptPgHostConfigPath -#define CFGOPT_PG_HOST_PORT cfgOptPgHostPort -#define CFGOPT_PG_HOST_USER cfgOptPgHostUser -#define CFGOPT_PG_PATH cfgOptPgPath -#define CFGOPT_PG_PORT cfgOptPgPort -#define CFGOPT_PG_SOCKET_PATH cfgOptPgSocketPath -#define CFGOPT_PROCESS cfgOptProcess -#define CFGOPT_PROCESS_MAX cfgOptProcessMax -#define CFGOPT_PROTOCOL_TIMEOUT cfgOptProtocolTimeout -#define CFGOPT_RECOVERY_OPTION cfgOptRecoveryOption -#define CFGOPT_REPO_CIPHER_PASS cfgOptRepoCipherPass -#define CFGOPT_REPO_CIPHER_TYPE cfgOptRepoCipherType -#define CFGOPT_REPO_HARDLINK cfgOptRepoHardlink -#define CFGOPT_REPO_HOST cfgOptRepoHost -#define CFGOPT_REPO_HOST_CMD cfgOptRepoHostCmd -#define CFGOPT_REPO_HOST_CONFIG cfgOptRepoHostConfig -#define CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH cfgOptRepoHostConfigIncludePath -#define CFGOPT_REPO_HOST_CONFIG_PATH cfgOptRepoHostConfigPath -#define CFGOPT_REPO_HOST_PORT cfgOptRepoHostPort -#define CFGOPT_REPO_HOST_USER cfgOptRepoHostUser -#define CFGOPT_REPO_PATH cfgOptRepoPath -#define CFGOPT_REPO_RETENTION_ARCHIVE cfgOptRepoRetentionArchive -#define CFGOPT_REPO_RETENTION_ARCHIVE_TYPE cfgOptRepoRetentionArchiveType -#define CFGOPT_REPO_RETENTION_DIFF cfgOptRepoRetentionDiff -#define CFGOPT_REPO_RETENTION_FULL cfgOptRepoRetentionFull -#define CFGOPT_REPO_S3_BUCKET cfgOptRepoS3Bucket -#define CFGOPT_REPO_S3_CA_FILE cfgOptRepoS3CaFile -#define CFGOPT_REPO_S3_CA_PATH cfgOptRepoS3CaPath -#define CFGOPT_REPO_S3_ENDPOINT cfgOptRepoS3Endpoint -#define CFGOPT_REPO_S3_HOST cfgOptRepoS3Host -#define CFGOPT_REPO_S3_KEY cfgOptRepoS3Key -#define CFGOPT_REPO_S3_KEY_SECRET cfgOptRepoS3KeySecret -#define CFGOPT_REPO_S3_REGION cfgOptRepoS3Region -#define CFGOPT_REPO_S3_TOKEN cfgOptRepoS3Token -#define CFGOPT_REPO_S3_VERIFY_SSL cfgOptRepoS3VerifySsl -#define CFGOPT_REPO_TYPE cfgOptRepoType -#define CFGOPT_RESUME cfgOptResume -#define CFGOPT_SET cfgOptSet -#define CFGOPT_SPOOL_PATH cfgOptSpoolPath -#define CFGOPT_STANZA cfgOptStanza -#define CFGOPT_START_FAST cfgOptStartFast -#define CFGOPT_STOP_AUTO cfgOptStopAuto -#define CFGOPT_TABLESPACE_MAP cfgOptTablespaceMap -#define CFGOPT_TABLESPACE_MAP_ALL cfgOptTablespaceMapAll -#define CFGOPT_TARGET cfgOptTarget -#define CFGOPT_TARGET_ACTION cfgOptTargetAction -#define CFGOPT_TARGET_EXCLUSIVE cfgOptTargetExclusive -#define CFGOPT_TARGET_TIMELINE cfgOptTargetTimeline -#define CFGOPT_TEST cfgOptTest -#define CFGOPT_TEST_DELAY cfgOptTestDelay -#define CFGOPT_TEST_POINT cfgOptTestPoint -#define CFGOPT_TYPE cfgOptType - -#endif diff --git a/libc/xs/config/define.auto.xsh b/libc/xs/config/define.auto.xsh deleted file mode 100644 index 52b2f3913..000000000 --- a/libc/xs/config/define.auto.xsh +++ /dev/null @@ -1,20 +0,0 @@ -/*********************************************************************************************************************************** -Command and Option Definitions - -Automatically generated by Build.pm -- do not modify directly. -***********************************************************************************************************************************/ -#ifndef XS_CONFIG_DEFINE_AUTO_H -#define XS_CONFIG_DEFINE_AUTO_H - -/*********************************************************************************************************************************** -Option type constants -***********************************************************************************************************************************/ -#define CFGDEF_TYPE_BOOLEAN cfgDefOptTypeBoolean -#define CFGDEF_TYPE_FLOAT cfgDefOptTypeFloat -#define CFGDEF_TYPE_HASH cfgDefOptTypeHash -#define CFGDEF_TYPE_INTEGER cfgDefOptTypeInteger -#define CFGDEF_TYPE_LIST cfgDefOptTypeList -#define CFGDEF_TYPE_SIZE cfgDefOptTypeSize -#define CFGDEF_TYPE_STRING cfgDefOptTypeString - -#endif diff --git a/src/Makefile b/src/Makefile index b59a20bfb..6ec5484c3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -14,7 +14,7 @@ CSTD = -std=c99 COPT = -O2 # Locations of header files -CINCLUDE = -I. +CINCLUDE = -I. -I../libc # Compile warnings CWARN = -Wfatal-errors -Wall -Wextra -Wwrite-strings -Wswitch-enum -Wconversion -Wformat=2 -Wformat-nonliteral \ @@ -42,7 +42,7 @@ LDPERL = `perl -MExtUtils::Embed -e ldopts` LDEXTRA = # Concatenate options for easy usage -LDFLAGS = $(LDPERL) $(LDEXTRA) +LDFLAGS = -lcrypto $(LDPERL) $(LDEXTRA) #################################################################################################################################### # Install options @@ -54,12 +54,17 @@ DESTDIR = # List of required source files. main.c should always be listed last and the rest in alpha order. #################################################################################################################################### SRCS = \ + cipher/block.c \ + cipher/cipher.c \ + cipher/random.c \ command/archive/common.c \ command/archive/get/get.c \ command/archive/push/push.c \ command/help/help.c \ command/command.c \ common/debug.c \ + common/encode.c \ + common/encode/base64.c \ common/error.c \ common/exit.c \ common/fork.c \ @@ -87,6 +92,7 @@ SRCS = \ perl/config.c \ perl/exec.c \ postgres/info.c \ + postgres/pageChecksum.c \ storage/driver/posix/driver.c \ storage/driver/posix/driverFile.c \ storage/driver/posix/driverRead.c \ @@ -106,6 +112,9 @@ OBJS=$(SRCS:.c=.o) pgbackrest: $(OBJS) $(CC) -o pgbackrest $(OBJS) $(LDFLAGS) +postgres/pageChecksum.o: + $(CC) $(CFLAGS) -funroll-loops -ftree-vectorize -c postgres/pageChecksum.c -o postgres/pageChecksum.o + .c.o: $(CC) $(CFLAGS) -c $< -o $@ diff --git a/src/perl/embed.auto.c b/src/perl/embed.auto.c new file mode 100644 index 000000000..efadb5d86 --- /dev/null +++ b/src/perl/embed.auto.c @@ -0,0 +1,25113 @@ +/*********************************************************************************************************************************** +Embed Perl modules + +Automatically generated by Build.pm -- do not modify directly. +***********************************************************************************************************************************/ + +/*********************************************************************************************************************************** +Embedded Perl modules +***********************************************************************************************************************************/ +static const EmbeddedModule embeddedModule[] = +{ + { + .name = "pgBackRest/Archive/Base.pm", + .data = + "\n" + "\n" + "\n" + "package pgBackRest::Archive::Base;\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" + "\n" + "use pgBackRest::Archive::Info;\n" + "use pgBackRest::Archive::Common;\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::Helper;\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" + "(\n" + "my $strOperation,\n" + "$self->{strBackRestBin},\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->new', \\@_,\n" + "{name => 'strBackRestBin', default => backrestBin(), trace => true},\n" + ");\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'self', value => $self}\n" + ");\n" + "}\n" + "\n" + "1;\n" + }, + { + .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" + "use constant WAL_STATUS_ERROR => 'error';\n" + "push @EXPORT, qw(WAL_STATUS_ERROR);\n" + "use constant WAL_STATUS_OK => 'ok';\n" + "push @EXPORT, qw(WAL_STATUS_OK);\n" + "\n" + "\n" + "\n" + "\n" + "my $oWalMagicHash =\n" + "{\n" + "hex('0xD062') => PG_VERSION_83,\n" + "hex('0xD063') => PG_VERSION_84,\n" + "hex('0xD064') => PG_VERSION_90,\n" + "hex('0xD066') => PG_VERSION_91,\n" + "hex('0xD071') => PG_VERSION_92,\n" + "hex('0xD075') => PG_VERSION_93,\n" + "hex('0xD07E') => PG_VERSION_94,\n" + "hex('0xD087') => PG_VERSION_95,\n" + "hex('0xD093') => PG_VERSION_96,\n" + "hex('0xD097') => PG_VERSION_10,\n" + "};\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" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::lsnFileRange', \\@_,\n" + "{name => 'strLsnStart'},\n" + "{name => 'strLsnStop'},\n" + "{name => '$strDbVersion'},\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 = hex(substr(sprintf(\"%08s\", $stryArchiveSplit[1]), 0, 2));\n" + "\n" + "@stryArchiveSplit = split('/', $strLsnStop);\n" + "my $iStopMajor = hex($stryArchiveSplit[0]);\n" + "my $iStopMinor = hex(substr(sprintf(\"%08s\", $stryArchiveSplit[1]), 0, 2));\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 == 256)\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" + "sub walInfo\n" + "{\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strWalFile,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::walInfo', \\@_,\n" + "{name => 'strWalFile'}\n" + ");\n" + "\n" + "\n" + "\n" + "my $hFile;\n" + "my $tBlock;\n" + "\n" + "sysopen($hFile, $strWalFile, O_RDONLY)\n" + "or confess &log(ERROR, \"unable to open ${strWalFile}\", ERROR_FILE_OPEN);\n" + "\n" + "\n" + "sysread($hFile, $tBlock, 2) == 2\n" + "or confess &log(ERROR, \"unable to read wal magic\");\n" + "\n" + "my $iMagic = unpack('S', $tBlock);\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "my $strDbVersion = $$oWalMagicHash{$iMagic};\n" + "\n" + "if (!defined($strDbVersion))\n" + "{\n" + "confess &log(ERROR, \"unexpected WAL magic 0x\" . sprintf(\"%X\", $iMagic) . \"\\n\" .\n" + "'HINT: is this version of PostgreSQL supported?',\n" + "ERROR_VERSION_NOT_SUPPORTED);\n" + "}\n" + "\n" + "\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" + "\n" + "sysread($hFile, $tBlock, 2) == 2\n" + "or confess &log(ERROR, \"unable to read wal info\");\n" + "\n" + "my $iFlag = unpack('S', $tBlock);\n" + "\n" + "\n" + "$iFlag & 2\n" + "or confess &log(ERROR, \"expected long header in flags \" . sprintf(\"%x\", $iFlag));\n" + "\n" + "\n" + "\n" + "sysseek($hFile, $iSysIdOffset, SEEK_CUR)\n" + "or confess &log(ERROR, \"unable to read padding\");\n" + "\n" + "sysread($hFile, $tBlock, 8) == 8\n" + "or confess &log(ERROR, \"unable to read database system identifier\");\n" + "\n" + "length($tBlock) == 8\n" + "or confess &log(ERROR, \"block is incorrect length\");\n" + "\n" + "close($hFile);\n" + "\n" + "my $ullDbSysId = unpack('Q', $tBlock);\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'strDbVersion', value => $strDbVersion},\n" + "{name => 'ullDbSysId', value => $ullDbSysId}\n" + ");\n" + "}\n" + "\n" + "push @EXPORT, qw(walInfo);\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(ERROR, \"could not find WAL segment ${strWalSegment} after ${iWaitSeconds} second(s)\", 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 walPath\n" + "{\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strWalFile,\n" + "$strDbPath,\n" + "$strCommand,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::walPath', \\@_,\n" + "{name => 'strWalFile', trace => true},\n" + "{name => 'strDbPath', trace => true, required => false},\n" + "{name => 'strCommand', trace => true},\n" + ");\n" + "\n" + "if (index($strWalFile, '/') != 0)\n" + "{\n" + "if (!defined($strDbPath))\n" + "{\n" + "confess &log(ERROR,\n" + "\"option '\" . cfgOptionName(CFGOPT_PG_PATH) . \"' must be specified when relative wal paths are used\\n\" .\n" + "\"HINT: Is \\%f passed to ${strCommand} instead of \\%p?\\n\" .\n" + "\"HINT: PostgreSQL may pass relative paths even with \\%p depending on the environment.\",\n" + "ERROR_OPTION_REQUIRED);\n" + "}\n" + "\n" + "$strWalFile = \"${strDbPath}/${strWalFile}\";\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'strWalFile', value => $strWalFile, trace => true}\n" + ");\n" + "\n" + "}\n" + "\n" + "push @EXPORT, qw(walPath);\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" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub archiveAsyncStatusWrite\n" + "{\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strType,\n" + "$strSpoolPath,\n" + "$strWalFile,\n" + "$iCode,\n" + "$strMessage,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::archiveAsyncStatusWrite', \\@_,\n" + "{name => 'strType'},\n" + "{name => 'strSpoolPath'},\n" + "{name => 'strWalFile'},\n" + "{name => 'iCode', required => false},\n" + "{name => 'strMessage', required => false},\n" + ");\n" + "\n" + "\n" + "if ($strType ne WAL_STATUS_ERROR)\n" + "{\n" + "\n" + "storageLocal()->remove(\"${strSpoolPath}/${strWalFile}.error\", {bIgnoreMissing => true});\n" + "}\n" + "\n" + "\n" + "my $strStatus;\n" + "\n" + "if (defined($iCode))\n" + "{\n" + "if (!defined($strMessage))\n" + "{\n" + "confess &log(ASSERT, 'strMessage must be set when iCode is set');\n" + "}\n" + "\n" + "$strStatus = \"${iCode}\\n${strMessage}\";\n" + "}\n" + "elsif ($strType eq WAL_STATUS_ERROR)\n" + "{\n" + "confess &log(ASSERT, 'error status must have iCode and strMessage set');\n" + "}\n" + "\n" + "storageLocal()->put(\n" + "storageLocal()->openWrite(\"${strSpoolPath}/${strWalFile}.${strType}\", {bAtomic => true}), $strStatus);\n" + "}\n" + "\n" + "push @EXPORT, qw(archiveAsyncStatusWrite);\n" + "\n" + "1;\n" + }, + { + .name = "pgBackRest/Archive/Get/Async.pm", + .data = + "\n" + "\n" + "\n" + "package pgBackRest::Archive::Get::Async;\n" + "use parent 'pgBackRest::Archive::Get::Get';\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::Lock;\n" + "use pgBackRest::Common::Log;\n" + "use pgBackRest::Archive::Common;\n" + "use pgBackRest::Archive::Info;\n" + "use pgBackRest::Common::String;\n" + "use pgBackRest::Common::Wait;\n" + "use pgBackRest::Config::Config;\n" + "use pgBackRest::Db;\n" + "use pgBackRest::DbVersion;\n" + "use pgBackRest::LibC qw(:lock);\n" + "use pgBackRest::Protocol::Local::Process;\n" + "use pgBackRest::Protocol::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 = $class->SUPER::new();\n" + "bless $self, $class;\n" + "\n" + "\n" + "(\n" + "my $strOperation,\n" + "$self->{strSpoolPath},\n" + "$self->{strBackRestBin},\n" + "$self->{rstryWal},\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->new', \\@_,\n" + "{name => 'strSpoolPath'},\n" + "{name => 'strBackRestBin', default => backrestBin()},\n" + "{name => 'rstryWal'},\n" + ");\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'self', value => $self}\n" + ");\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "sub initServer\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my ($strOperation) = logDebugParam(__PACKAGE__ . '->initServer');\n" + "\n" + "\n" + "$self->{oArchiveProcess} = new pgBackRest::Protocol::Local::Process(\n" + "CFGOPTVAL_LOCAL_TYPE_BACKUP, cfgOption(CFGOPT_PROTOCOL_TIMEOUT) < 60 ? cfgOption(CFGOPT_PROTOCOL_TIMEOUT) / 2 : 30,\n" + "$self->{strBackRestBin}, false);\n" + "$self->{oArchiveProcess}->hostAdd(1, cfgOption(CFGOPT_PROCESS_MAX));\n" + "\n" + "\n" + "return logDebugReturn($strOperation);\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "sub process\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');\n" + "\n" + "\n" + "logFileSet(storageLocal(), cfgOption(CFGOPT_LOG_PATH) . '/' . cfgOption(CFGOPT_STANZA) . '-archive-get-async');\n" + "\n" + "\n" + "\n" + "$self->initServer();\n" + "$self->processQueue();\n" + "\n" + "\n" + "return logDebugReturn($strOperation);\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "sub processQueue\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my ($strOperation) = logDebugParam(__PACKAGE__ . '->processQueue');\n" + "\n" + "\n" + "foreach my $strWalFile (@{$self->{rstryWal}})\n" + "{\n" + "$self->{oArchiveProcess}->queueJob(\n" + "1, 'default', $strWalFile, OP_ARCHIVE_GET_FILE, [$strWalFile, \"$self->{strSpoolPath}/${strWalFile}\", true]);\n" + "}\n" + "\n" + "\n" + "my $iFoundTotal = 0;\n" + "my $iMissingTotal = 0;\n" + "my $iErrorTotal = 0;\n" + "\n" + "&log(INFO,\n" + "'get ' . @{$self->{rstryWal}} . ' WAL file(s) from archive: ' .\n" + "${$self->{rstryWal}}[0] . (@{$self->{rstryWal}} > 1 ? \"...${$self->{rstryWal}}[-1]\" : ''));\n" + "\n" + "eval\n" + "{\n" + "\n" + "lockStopTest();\n" + "\n" + "while (my $hyJob = $self->{oArchiveProcess}->process())\n" + "{\n" + "foreach my $hJob (@{$hyJob})\n" + "{\n" + "my $strWalFile = @{$hJob->{rParam}}[0];\n" + "my $iResult = @{$hJob->{rResult}}[0];\n" + "\n" + "\n" + "if (defined($hJob->{oException}))\n" + "{\n" + "archiveAsyncStatusWrite(\n" + "WAL_STATUS_ERROR, $self->{strSpoolPath}, $strWalFile, $hJob->{oException}->code(),\n" + "$hJob->{oException}->message());\n" + "\n" + "$iErrorTotal++;\n" + "\n" + "&log(WARN,\n" + "\"could not get WAL file ${strWalFile} from archive (will be retried): [\" .\n" + "$hJob->{oException}->code() . \"] \" . $hJob->{oException}->message());\n" + "}\n" + "\n" + "elsif ($iResult == 1)\n" + "{\n" + "archiveAsyncStatusWrite(WAL_STATUS_OK, $self->{strSpoolPath}, $strWalFile);\n" + "\n" + "$iMissingTotal++;\n" + "\n" + "&log(DETAIL, \"WAL file ${strWalFile} not found in archive\", undef, undef, undef, $hJob->{iProcessId});\n" + "}\n" + "\n" + "else\n" + "{\n" + "$iFoundTotal++;\n" + "\n" + "&log(DETAIL, \"got WAL file ${strWalFile} from archive\", undef, undef, undef, $hJob->{iProcessId});\n" + "}\n" + "}\n" + "}\n" + "\n" + "return 1;\n" + "}\n" + "or do\n" + "{\n" + "\n" + "my $iCode = exceptionCode($EVAL_ERROR);\n" + "my $strMessage = exceptionMessage($EVAL_ERROR);\n" + "\n" + "\n" + "foreach my $strWalFile (@{$self->{rstryWal}})\n" + "{\n" + "archiveAsyncStatusWrite(WAL_STATUS_ERROR, $self->{strSpoolPath}, $strWalFile, $iCode, $strMessage);\n" + "}\n" + "};\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'iNewTotal', value => scalar(@{$self->{rstryWal}})},\n" + "{name => 'iFoundTotal', value => $iFoundTotal},\n" + "{name => 'iMissingTotal', value => $iMissingTotal},\n" + "{name => 'iErrorTotal', value => $iErrorTotal}\n" + ");\n" + "}\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" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub archiveGetFile\n" + "{\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strSourceArchive,\n" + "$strDestinationFile,\n" + "$bAtomic,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::archiveGetFile', \\@_,\n" + "{name => 'strSourceArchive'},\n" + "{name => 'strDestinationFile'},\n" + "{name => 'bAtomic'},\n" + ");\n" + "\n" + "lockStopTest();\n" + "\n" + "\n" + "my $oStorageRepo = storageRepo();\n" + "\n" + "\n" + "$strDestinationFile = walPath($strDestinationFile, cfgOption(CFGOPT_PG_PATH, false), cfgCommandName(cfgCommandGet()));\n" + "\n" + "\n" + "my ($strArchiveId, $strArchiveFile, $strCipherPass) = archiveGetCheck(undef, undef, $strSourceArchive, false);\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "my $iResult = 0;\n" + "\n" + "if (!defined($strArchiveFile))\n" + "{\n" + "&log(INFO, \"unable to find ${strSourceArchive} in the archive\");\n" + "\n" + "$iResult = 1;\n" + "}\n" + "else\n" + "{\n" + "\n" + "my $bSourceCompressed = $strArchiveFile =~ ('^.*\\.' . COMPRESS_EXT . '$') ? true : false;\n" + "\n" + "\n" + "\n" + "$oStorageRepo->copy(\n" + "$oStorageRepo->openRead(\n" + "STORAGE_REPO_ARCHIVE . \"/${strArchiveId}/${strArchiveFile}\", {bProtocolCompress => !$bSourceCompressed,\n" + "strCipherPass => defined($strCipherPass) ? $strCipherPass : undef}),\n" + "storageDb()->openWrite(\n" + "$strDestinationFile,\n" + "{bAtomic => $bAtomic, rhyFilter => $bSourceCompressed ?\n" + "[{strClass => STORAGE_FILTER_GZIP, rxyParam => [{strCompressType => STORAGE_DECOMPRESS}]}] : undef}));\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'iResult', value => $iResult}\n" + ");\n" + "}\n" + "\n" + "push @EXPORT, qw(archiveGetFile);\n" + "\n" + "1;\n" + }, + { + .name = "pgBackRest/Archive/Get/Get.pm", + .data = + "\n" + "\n" + "\n" + "package pgBackRest::Archive::Get::Get;\n" + "use parent 'pgBackRest::Archive::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 Fcntl qw(SEEK_CUR O_RDONLY O_WRONLY O_CREAT);\n" + "use File::Basename qw(dirname basename);\n" + "use Scalar::Util qw(blessed);\n" + "\n" + "use pgBackRest::Common::Exception;\n" + "use pgBackRest::Common::Lock;\n" + "use pgBackRest::Common::Log;\n" + "use pgBackRest::Archive::Common;\n" + "use pgBackRest::Archive::Get::File;\n" + "use pgBackRest::Archive::Info;\n" + "use pgBackRest::Common::String;\n" + "use pgBackRest::Common::Wait;\n" + "use pgBackRest::Config::Config;\n" + "use pgBackRest::Db;\n" + "use pgBackRest::DbVersion;\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::Helper;\n" + "\n" + "\n" + "\n" + "\n" + "sub process\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$rstryCommandArg,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->process', \\@_,\n" + "{name => 'rstryCommandArg'},\n" + ");\n" + "\n" + "my $iResult = 0;\n" + "\n" + "\n" + "if (!isDbLocal())\n" + "{\n" + "confess &log(ERROR, cfgCommandName(CFGCMD_ARCHIVE_GET) . ' operation must run on db host', ERROR_HOST_INVALID);\n" + "}\n" + "\n" + "\n" + "if (cfgOption(CFGOPT_ARCHIVE_ASYNC))\n" + "{\n" + "\n" + "require pgBackRest::Archive::Get::Async;\n" + "(new pgBackRest::Archive::Get::Async(\n" + "storageSpool()->pathGet(STORAGE_SPOOL_ARCHIVE_IN), $self->{strBackRestBin}, $rstryCommandArg))->process();\n" + "}\n" + "\n" + "else\n" + "{\n" + "\n" + "my $strSourceArchive = ${$rstryCommandArg}[0];\n" + "\n" + "if (!defined($strSourceArchive))\n" + "{\n" + "confess &log(ERROR, 'WAL segment not provided', ERROR_PARAM_REQUIRED);\n" + "}\n" + "\n" + "\n" + "my $strDestinationFile = ${$rstryCommandArg}[1];\n" + "\n" + "if (!defined($strDestinationFile))\n" + "{\n" + "confess &log(ERROR, 'WAL segment destination not provided', ERROR_PARAM_REQUIRED);\n" + "}\n" + "\n" + "$iResult = archiveGetFile($strSourceArchive, $strDestinationFile, false);\n" + "\n" + "\n" + "&log(INFO, 'got WAL segment ' . $strSourceArchive);\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'iResult', value => $iResult, trace => true},\n" + ");\n" + "}\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_CIPHER && $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(ERROR, \"unable to retrieve the archive id for database version '$strDbVersion' and system-id '$ullDbSysId'\");\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_CIPHER);\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/Archive/Push/Async.pm", + .data = + "\n" + "\n" + "\n" + "package pgBackRest::Archive::Push::Async;\n" + "use parent 'pgBackRest::Archive::Push::Push';\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::Lock;\n" + "use pgBackRest::Common::Log;\n" + "use pgBackRest::Archive::Common;\n" + "use pgBackRest::Archive::Info;\n" + "use pgBackRest::Archive::Push::Push;\n" + "use pgBackRest::Common::String;\n" + "use pgBackRest::Common::Wait;\n" + "use pgBackRest::Config::Config;\n" + "use pgBackRest::Db;\n" + "use pgBackRest::DbVersion;\n" + "use pgBackRest::LibC qw(:lock);\n" + "use pgBackRest::Protocol::Local::Process;\n" + "use pgBackRest::Protocol::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 = $class->SUPER::new();\n" + "bless $self, $class;\n" + "\n" + "\n" + "(\n" + "my $strOperation,\n" + "$self->{strWalPath},\n" + "$self->{strSpoolPath},\n" + "$self->{strBackRestBin},\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->new', \\@_,\n" + "{name => 'strWalPath'},\n" + "{name => 'strSpoolPath'},\n" + "{name => 'strBackRestBin', default => backrestBin()},\n" + ");\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'self', value => $self}\n" + ");\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub initServer\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my ($strOperation) = logDebugParam(__PACKAGE__ . '->initServer');\n" + "\n" + "\n" + "storageSpool()->pathCreate($self->{strSpoolPath}, {bIgnoreExists => true, bCreateParent => true});\n" + "\n" + "\n" + "$self->{oArchiveProcess} = new pgBackRest::Protocol::Local::Process(\n" + "CFGOPTVAL_LOCAL_TYPE_BACKUP, cfgOption(CFGOPT_PROTOCOL_TIMEOUT) < 60 ? cfgOption(CFGOPT_PROTOCOL_TIMEOUT) / 2 : 30,\n" + "$self->{strBackRestBin}, false);\n" + "$self->{oArchiveProcess}->hostAdd(1, cfgOption(CFGOPT_PROCESS_MAX));\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" + "logFileSet(storageLocal(), cfgOption(CFGOPT_LOG_PATH) . '/' . cfgOption(CFGOPT_STANZA) . '-archive-push-async');\n" + "\n" + "\n" + "\n" + "$self->initServer();\n" + "$self->processQueue();\n" + "\n" + "\n" + "return logDebugReturn($strOperation);\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub processQueue\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my ($strOperation) = logDebugParam(__PACKAGE__ . '->processQueue');\n" + "\n" + "\n" + "my $stryWalFile = $self->readyList();\n" + "\n" + "\n" + "foreach my $strWalFile (@{$stryWalFile})\n" + "{\n" + "$self->{oArchiveProcess}->queueJob(\n" + "1, 'default', $strWalFile, OP_ARCHIVE_PUSH_FILE,\n" + "[$self->{strWalPath}, $strWalFile, cfgOption(CFGOPT_COMPRESS), cfgOption(CFGOPT_COMPRESS_LEVEL)]);\n" + "}\n" + "\n" + "\n" + "my $iOkTotal = 0;\n" + "my $iErrorTotal = 0;\n" + "my $iDropTotal = 0;\n" + "\n" + "if ($self->{oArchiveProcess}->jobTotal() > 0)\n" + "{\n" + "&log(INFO,\n" + "'push ' . @{$stryWalFile} . ' WAL file(s) to archive: ' .\n" + "${$stryWalFile}[0] . (@{$stryWalFile} > 1 ? \"...${$stryWalFile}[-1]\" : ''));\n" + "\n" + "eval\n" + "{\n" + "\n" + "lockStopTest();\n" + "\n" + "\n" + "!isRepoLocal() && protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP);\n" + "\n" + "while (my $hyJob = $self->{oArchiveProcess}->process())\n" + "{\n" + "\n" + "protocolKeepAlive();\n" + "\n" + "foreach my $hJob (@{$hyJob})\n" + "{\n" + "my $strWalFile = @{$hJob->{rParam}}[1];\n" + "my $strWarning = @{$hJob->{rResult}}[0];\n" + "\n" + "\n" + "if (defined($hJob->{oException}))\n" + "{\n" + "archiveAsyncStatusWrite(\n" + "WAL_STATUS_ERROR, $self->{strSpoolPath}, $strWalFile, $hJob->{oException}->code(),\n" + "$hJob->{oException}->message());\n" + "\n" + "$iErrorTotal++;\n" + "\n" + "&log(WARN,\n" + "\"could not push WAL file ${strWalFile} to archive (will be retried): [\" .\n" + "$hJob->{oException}->code() . \"] \" . $hJob->{oException}->message());\n" + "}\n" + "\n" + "else\n" + "{\n" + "archiveAsyncStatusWrite(\n" + "WAL_STATUS_OK, $self->{strSpoolPath}, $strWalFile, defined($strWarning) ? 0 : undef,\n" + "defined($strWarning) ? $strWarning : undef);\n" + "\n" + "$iOkTotal++;\n" + "\n" + "&log(DETAIL, \"pushed WAL file ${strWalFile} to archive\", undef, undef, undef, $hJob->{iProcessId});\n" + "}\n" + "}\n" + "\n" + "\n" + "if (cfgOptionTest(CFGOPT_ARCHIVE_PUSH_QUEUE_MAX))\n" + "{\n" + "my $stryDropList = $self->dropList($self->readyList());\n" + "\n" + "if (@{$stryDropList} > 0)\n" + "{\n" + "foreach my $strDropFile (@{$stryDropList})\n" + "{\n" + "archiveAsyncStatusWrite(\n" + "WAL_STATUS_OK, $self->{strSpoolPath}, $strDropFile, 0,\n" + "\"dropped WAL file ${strDropFile} because archive queue exceeded \" .\n" + "cfgOption(CFGOPT_ARCHIVE_PUSH_QUEUE_MAX) . ' bytes');\n" + "\n" + "$iDropTotal++;\n" + "}\n" + "\n" + "$self->{oArchiveProcess}->dequeueJobs(1, 'default');\n" + "}\n" + "}\n" + "}\n" + "\n" + "return 1;\n" + "}\n" + "or do\n" + "{\n" + "\n" + "my $iCode = exceptionCode($EVAL_ERROR);\n" + "my $strMessage = exceptionMessage($EVAL_ERROR);\n" + "\n" + "\n" + "foreach my $strWalFile (@{$stryWalFile})\n" + "{\n" + "archiveAsyncStatusWrite(\n" + "WAL_STATUS_ERROR, $self->{strSpoolPath}, $strWalFile, $iCode, $strMessage);\n" + "}\n" + "}\n" + "}\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'iNewTotal', value => scalar(@{$stryWalFile})},\n" + "{name => 'iDropTotal', value => $iDropTotal},\n" + "{name => 'iOkTotal', value => $iOkTotal},\n" + "{name => 'iErrorTotal', value => $iErrorTotal}\n" + ");\n" + "}\n" + "\n" + "1;\n" + }, + { + .name = "pgBackRest/Archive/Push/File.pm", + .data = + "\n" + "\n" + "\n" + "package pgBackRest::Archive::Push::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::Common::Exception;\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::Filter::Gzip;\n" + "use pgBackRest::Storage::Filter::Sha;\n" + "use pgBackRest::Storage::Helper;\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub archivePushCheck\n" + "{\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strArchiveFile,\n" + "$strDbVersion,\n" + "$ullDbSysId,\n" + "$strWalFile,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::archivePushCheck', \\@_,\n" + "{name => 'strArchiveFile'},\n" + "{name => 'strDbVersion', required => false},\n" + "{name => 'ullDbSysId', required => false},\n" + "{name => 'strWalFile', required => false},\n" + ");\n" + "\n" + "\n" + "my $oStorageRepo = storageRepo();\n" + "my $strArchiveId;\n" + "my $strChecksum;\n" + "my $strCipherPass = undef;\n" + "\n" + "\n" + "my $bWalSegment = walIsSegment($strArchiveFile);\n" + "\n" + "if (!isRepoLocal())\n" + "{\n" + "\n" + "($strArchiveId, $strChecksum, $strCipherPass) = protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(\n" + "OP_ARCHIVE_PUSH_CHECK, [$strArchiveFile, $strDbVersion, $ullDbSysId], true);\n" + "}\n" + "else\n" + "{\n" + "my $oArchiveInfo = new pgBackRest::Archive::Info($oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE));\n" + "\n" + "\n" + "if ($bWalSegment)\n" + "{\n" + "\n" + "$strArchiveId = $oArchiveInfo->check($strDbVersion, $ullDbSysId);\n" + "\n" + "\n" + "my $strFoundFile = walSegmentFind($oStorageRepo, $strArchiveId, $strArchiveFile);\n" + "\n" + "if (defined($strFoundFile))\n" + "{\n" + "$strChecksum = substr($strFoundFile, length($strArchiveFile) + 1, 40);\n" + "}\n" + "}\n" + "\n" + "else\n" + "{\n" + "$strArchiveId = $oArchiveInfo->archiveId();\n" + "}\n" + "\n" + "\n" + "$strCipherPass = $oArchiveInfo->cipherPassSub();\n" + "}\n" + "\n" + "my $strWarning;\n" + "\n" + "if (defined($strChecksum) && !cfgCommandTest(CFGCMD_REMOTE))\n" + "{\n" + "my ($strChecksumNew) = storageDb()->hashSize($strWalFile);\n" + "\n" + "if ($strChecksumNew ne $strChecksum)\n" + "{\n" + "confess &log(ERROR, \"WAL segment \" . basename($strWalFile) . \" already exists in the archive\", ERROR_ARCHIVE_DUPLICATE);\n" + "}\n" + "\n" + "$strWarning =\n" + "\"WAL segment \" . basename($strWalFile) . \" already exists in the archive with the same checksum\\n\" .\n" + "\"HINT: this is valid in some recovery scenarios but may also indicate a problem.\";\n" + "\n" + "&log(WARN, $strWarning);\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'strArchiveId', value => $strArchiveId},\n" + "{name => 'strChecksum', value => $strChecksum},\n" + "{name => 'strCipherPass', value => $strCipherPass, redact => true},\n" + "{name => 'strWarning', value => $strWarning},\n" + ");\n" + "}\n" + "\n" + "push @EXPORT, qw(archivePushCheck);\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub archivePushFile\n" + "{\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strWalPath,\n" + "$strWalFile,\n" + "$bCompress,\n" + "$iCompressLevel,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::archivePushFile', \\@_,\n" + "{name => 'strWalPath'},\n" + "{name => 'strWalFile'},\n" + "{name => 'bCompress'},\n" + "{name => 'iCompressLevel'},\n" + ");\n" + "\n" + "\n" + "my $oStorageRepo = storageRepo();\n" + "my $strDbVersion;\n" + "my $ullDbSysId;\n" + "\n" + "if (walIsSegment($strWalFile))\n" + "{\n" + "($strDbVersion, $ullDbSysId) = walInfo(\"${strWalPath}/${strWalFile}\");\n" + "}\n" + "\n" + "\n" + "my ($strArchiveId, $strChecksum, $strCipherPass, $strWarning) = archivePushCheck(\n" + "$strWalFile, $strDbVersion, $ullDbSysId, walIsSegment($strWalFile) ? \"${strWalPath}/${strWalFile}\" : undef);\n" + "\n" + "\n" + "\n" + "if (!defined($strChecksum))\n" + "{\n" + "my $strArchiveFile = \"${strArchiveId}/${strWalFile}\";\n" + "\n" + "\n" + "if (walIsSegment($strWalFile))\n" + "{\n" + "\n" + "my ($strSourceHash) = storageDb()->hashSize(\"${strWalPath}/${strWalFile}\");\n" + "\n" + "$strArchiveFile .= \"-${strSourceHash}\";\n" + "\n" + "\n" + "if ($bCompress)\n" + "{\n" + "$strArchiveFile .= qw{.} . COMPRESS_EXT;\n" + "}\n" + "}\n" + "\n" + "\n" + "my $rhyFilter;\n" + "\n" + "if (walIsSegment($strWalFile) && $bCompress)\n" + "{\n" + "push(@{$rhyFilter}, {strClass => STORAGE_FILTER_GZIP, rxyParam => [{iLevel => $iCompressLevel}]});\n" + "}\n" + "\n" + "\n" + "$oStorageRepo->copy(\n" + "storageDb()->openRead(\"${strWalPath}/${strWalFile}\", {rhyFilter => $rhyFilter}),\n" + "$oStorageRepo->openWrite(\n" + "STORAGE_REPO_ARCHIVE . \"/${strArchiveFile}\",\n" + "{bPathCreate => true, bAtomic => true, bProtocolCompress => !walIsSegment($strWalFile) || !$bCompress,\n" + "strCipherPass => $strCipherPass}));\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'strWarning', value => $strWarning}\n" + ");\n" + "}\n" + "\n" + "push @EXPORT, qw(archivePushFile);\n" + "\n" + "1;\n" + }, + { + .name = "pgBackRest/Archive/Push/Push.pm", + .data = + "\n" + "\n" + "\n" + "package pgBackRest::Archive::Push::Push;\n" + "use parent 'pgBackRest::Archive::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(basename dirname);\n" + "\n" + "use pgBackRest::Archive::Common;\n" + "use pgBackRest::DbVersion;\n" + "use pgBackRest::Common::Exception;\n" + "use pgBackRest::Common::Lock;\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" + "\n" + "\n" + "sub process\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strWalPathFile,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->process', \\@_,\n" + "{name => 'strWalPathFile', required => false},\n" + ");\n" + "\n" + "\n" + "if (!isDbLocal())\n" + "{\n" + "confess &log(ERROR, cfgCommandName(CFGCMD_ARCHIVE_PUSH) . ' operation must run on db host', ERROR_HOST_INVALID);\n" + "}\n" + "\n" + "if (!defined($strWalPathFile))\n" + "{\n" + "confess &log(ERROR, 'WAL file to push required', ERROR_PARAM_REQUIRED);\n" + "}\n" + "\n" + "\n" + "my $strWalPath = dirname(walPath($strWalPathFile, cfgOption(CFGOPT_PG_PATH, false), cfgCommandName(cfgCommandGet())));\n" + "my $strWalFile = basename($strWalPathFile);\n" + "\n" + "\n" + "if (cfgOption(CFGOPT_ARCHIVE_ASYNC))\n" + "{\n" + "\n" + "require pgBackRest::Archive::Push::Async;\n" + "(new pgBackRest::Archive::Push::Async(\n" + "$strWalPath, storageSpool()->pathGet(STORAGE_SPOOL_ARCHIVE_OUT), $self->{strBackRestBin}))->process();\n" + "}\n" + "\n" + "else\n" + "{\n" + "\n" + "lockStopTest();\n" + "\n" + "\n" + "require pgBackRest::Archive::Push::File;\n" + "pgBackRest::Archive::Push::File->import();\n" + "\n" + "\n" + "$self->{strWalPath} = $strWalPath;\n" + "\n" + "if (cfgOptionTest(CFGOPT_ARCHIVE_PUSH_QUEUE_MAX) && @{$self->dropList($self->readyList())} > 0)\n" + "{\n" + "&log(WARN,\n" + "\"dropped WAL file ${strWalFile} because archive queue exceeded \" . cfgOption(CFGOPT_ARCHIVE_PUSH_QUEUE_MAX) . ' bytes');\n" + "}\n" + "\n" + "else\n" + "{\n" + "archivePushFile($strWalPath, $strWalFile, cfgOption(CFGOPT_COMPRESS), cfgOption(CFGOPT_COMPRESS_LEVEL));\n" + "&log(INFO, \"pushed WAL segment ${strWalFile}\");\n" + "}\n" + "}\n" + "\n" + "\n" + "return logDebugReturn($strOperation);\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub readyList\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my ($strOperation) = logDebugParam(__PACKAGE__ . '->readyList');\n" + "\n" + "\n" + "my $hOkFile = {};\n" + "\n" + "if (defined($self->{strSpoolPath}))\n" + "{\n" + "foreach my $strOkFile (storageSpool()->list($self->{strSpoolPath}, {strExpression => '\\.ok$', bIgnoreMissing => true}))\n" + "{\n" + "$strOkFile = substr($strOkFile, 0, length($strOkFile) - length('.ok'));\n" + "$hOkFile->{$strOkFile} = true;\n" + "}\n" + "}\n" + "\n" + "\n" + "my $strWalStatusPath = \"$self->{strWalPath}/archive_status\";\n" + "my @stryReadyFile = storageDb()->list($strWalStatusPath, {strExpression => '\\.ready$'});\n" + "\n" + "\n" + "my @stryNewReadyFile;\n" + "my $hReadyFile = {};\n" + "\n" + "foreach my $strReadyFile (@stryReadyFile)\n" + "{\n" + "\n" + "$strReadyFile = substr($strReadyFile, 0, length($strReadyFile) - length('.ready'));\n" + "\n" + "\n" + "if (!defined($hOkFile->{$strReadyFile}))\n" + "{\n" + "\n" + "push(@stryNewReadyFile, $strReadyFile);\n" + "}\n" + "\n" + "\n" + "$hReadyFile->{$strReadyFile} = true;\n" + "}\n" + "\n" + "\n" + "foreach my $strOkFile (sort(keys(%{$hOkFile})))\n" + "{\n" + "if (!defined($hReadyFile->{$strOkFile}))\n" + "{\n" + "storageSpool()->remove(\"$self->{strSpoolPath}/${strOkFile}.ok\");\n" + "}\n" + "}\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'stryWalFile', value => \\@stryNewReadyFile, ref => true}\n" + ");\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub dropList\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$stryReadyFile,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->dropList', \\@_,\n" + "{name => 'stryReadyList'},\n" + ");\n" + "\n" + "my $stryDropFile = [];\n" + "\n" + "\n" + "if (@{$stryReadyFile} > int(cfgOption(CFGOPT_ARCHIVE_PUSH_QUEUE_MAX) / PG_WAL_SIZE))\n" + "{\n" + "$stryDropFile = $stryReadyFile;\n" + "}\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'stryDropFile', value => $stryDropFile, ref => true}\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::Archive::Get::Get;\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" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->resumeClean', \\@_,\n" + "{name => 'oStorageRepo'},\n" + "{name => 'strBackupLabel'},\n" + "{name => 'oManifest'},\n" + "{name => 'oAbortedManifest'}\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" + "\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" + "if (defined($strChecksum))\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($strOperation);\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-${b}\", $oBackupManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $b, MANIFEST_SUBKEY_SIZE)) cmp\n" + "sprintf(\"%016d-${a}\", $oBackupManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $a, MANIFEST_SUBKEY_SIZE))}\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" + "if ($bHardLink)\n" + "{\n" + "&log(DETAIL, \"hardlink ${strRepoFile} to ${strReference}\");\n" + "\n" + "storageRepo()->linkCreate(\n" + "STORAGE_REPO_BACKUP . \"/${strReference}/${strRepoFile}\" . ($bCompress ? qw{.} . COMPRESS_EXT : ''),\n" + "STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strRepoFile}\" . ($bCompress ? qw{.} . COMPRESS_EXT : ''),\n" + "{bHard => true});\n" + "}\n" + "\n" + "else\n" + "{\n" + "logDebugMisc($strOperation, \"reference ${strRepoFile} to ${strReference}\");\n" + "}\n" + "\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 $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" + "{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" + "\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" + "\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" + "&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" + "\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 BACKREST_VERSION)\n" + "{\n" + "$strKey = INI_KEY_VERSION;\n" + "$strValueNew = BACKREST_VERSION;\n" + "$strValueAborted = $oAbortedManifest->get(INI_SECTION_BACKREST, INI_KEY_VERSION);\n" + "}\n" + "\n" + "elsif ($oAbortedManifest->get(INI_SECTION_BACKREST, INI_KEY_FORMAT) ne BACKREST_FORMAT)\n" + "{\n" + "$strKey = INI_KEY_FORMAT;\n" + "$strValueNew = BACKREST_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, '') ne\n" + "(defined($strBackupLastPath) ? $strBackupLastPath : ''))\n" + "{\n" + "$strKey = MANIFEST_KEY_PRIOR;\n" + "$strValueNew = defined($strBackupLastPath) ? $strBackupLastPath : '';\n" + "$strValueAborted =\n" + "$oAbortedManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_PRIOR, undef, false, '');\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" + "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,\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->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef, $bCompress);\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" + "\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_CATALOG, undef, $iCatalogVersion);\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 $hTablespaceMap = undef;\n" + "my $hDatabaseMap = 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) =\n" + "$oDbMaster->backupStart(\n" + "BACKREST_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" + "$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" + "$oBackupManifest->build($oStorageDbMaster, $strDbMasterPath, $oLastManifest, cfgOption(CFGOPT_ONLINE),\n" + "$hTablespaceMap, $hDatabaseMap);\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" + "$self->resumeClean($oStorageRepo, $strBackupLabel, $oBackupManifest, $oAbortedManifest);\n" + "}\n" + "\n" + "else\n" + "{\n" + "logDebugMisc($strOperation, \"create backup path ${strBackupPath}\");\n" + "$oStorageRepo->pathCreate(STORAGE_REPO_BACKUP . \"/${strBackupLabel}\");\n" + "}\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);\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" + "\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" + "$strCipherPass,\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 => '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" + "\n" + "my $bCopy = true;\n" + "\n" + "if (defined($strChecksum))\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" + "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 => true});\n" + "\n" + "\n" + "if (defined($oSourceFileIo))\n" + "{\n" + "\n" + "$oStorageRepo->copy(\n" + "$oSourceFileIo,\n" + "$oStorageRepo->openWrite(\n" + "STORAGE_REPO_BACKUP . \"/${strBackupLabel}/${strFileOp}\",\n" + "{bPathCreate => true, bProtocolCompress => !$bCompress, strCipherPass => $strCipherPass}));\n" + "\n" + "\n" + "$strCopyChecksum = $oSourceFileIo->result(STORAGE_FILTER_SHA);\n" + "$lCopySize = $oSourceFileIo->result(COMMON_IO_HANDLE);\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" + "if ($iCopyResult == BACKUP_FILE_COPY || $iCopyResult == BACKUP_FILE_RECOPY || $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_RECOPY)\n" + "{\n" + "&log(\n" + "WARN,\n" + "\"resumed backup file ${strRepoFile} should have checksum ${strChecksum} but actually has checksum ${strChecksumCopy}.\" .\n" + "\" The file will be recopied and backup will continue but this may be an issue unless the backup temp path is known to\" .\n" + "\" be corrupted.\");\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 ($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" + "$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_CIPHER && $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,\n" + "strCipherPass => 'x',\n" + "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_CATALOG, undef, $iCatalogVersion);\n" + "$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef, $ullDbSysId);\n" + "\n" + "$oBackupManifest->build(storageDb({iRemoteIdx => $iRemoteIdx}),\n" + "cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)), undef, cfgOption(CFGOPT_ONLINE),\n" + "$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, randomBytes($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" + "\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" + "\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 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);\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_CIPHER => 95;\n" + "push @EXPORT, qw(ERROR_CIPHER);\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_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" + "\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" + "eval\n" + "{\n" + "$oSocket = IO::Socket::SSL->new(\n" + "PeerHost => $strHost, PeerPort => $iPort, SSL_verify_mode => $bVerifySsl ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,\n" + "SSL_ca_path => $strCaPath, SSL_ca_file => $strCaFile);\n" + "\n" + "return 1;\n" + "}\n" + "or do\n" + "{\n" + "logErrorResult(ERROR_HOST_CONNECT, $EVAL_ERROR);\n" + "};\n" + "\n" + "\n" + "if (!defined($oSocket))\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} ${strUri}?${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} = undef;\n" + "\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 ($self->{iResponseCode} == 200)\n" + "{\n" + "\n" + "if (!defined($self->{iContentLength}))\n" + "{\n" + "confess &log(ERROR,\n" + "HTTP_HEADER_CONTENT_LENGTH . ' or ' . HTTP_HEADER_TRANSFER_ENCODING . ' must be defined', ERROR_PROTOCOL);\n" + "}\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" + "\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 '.')\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 Digest::SHA;\n" + "use Exporter qw(import);\n" + "our @EXPORT = qw();\n" + "use Fcntl qw(:mode O_WRONLY O_CREAT O_TRUNC);\n" + "use File::Basename qw(dirname basename);\n" + "use IO::Handle;\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::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 => BACKREST_FORMAT, trace => true},\n" + "{name => 'strInitVersion', optional => true, default => BACKREST_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_CIPHER);\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_CIPHER);\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" + "my $oSHA = Digest::SHA->new('sha1');\n" + "my $oJSON = JSON::PP->new()->canonical()->allow_nonref();\n" + "$oSHA->add($oJSON->encode($self->{oContent}));\n" + "\n" + "\n" + "$self->{oContent}{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = $oSHA->hexdigest();\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" + "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 DESTROY {shift->close()}\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 $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" + "\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" + "\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) ? '' :\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) . ' ... ':\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%02d', 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 => '';\n" + "push @EXPORT, qw(XML_HEADER);\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" + "\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" + "backrestBinSet($strBackRestBin);\n" + "\n" + "\n" + "$strCommand = $strCommandName;\n" + "\n" + "eval\n" + "{\n" + "\n" + "$$rstrConfigJson =~ s/\\\\/\\\\\\\\/g;\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 : backrestBin();\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 ? '' : ($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" + "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" + "};\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" + "$self->{hDb}->do(\n" + "\"set application_name = '\" . BACKREST_NAME . ' [' .\n" + "(cfgOptionValid(CFGOPT_COMMAND) ? cfgOption(CFGOPT_COMMAND) : cfgCommandName(cfgCommandGet())) . \"]'\")\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, $self->{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 => $self->{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 ' . BACKREST_NAME . \" advisory lock\\n\" .\n" + "'HINT: is another ' . BACKREST_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 ' . BACKREST_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) = $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" + "\" 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 => '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, BACKREST_EXE) == -1)\n" + "{\n" + "confess &log(ERROR,\n" + "'archive_command ' . (defined($strArchiveCommand) ? \"'${strArchiveCommand}'\" : '[null]') . ' must contain \\'' .\n" + "BACKREST_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('\" . BACKREST_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, '')\");\n" + "\n" + "\n" + "if ($strLastReplayedLSN eq '')\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" + "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_WAL_SIZE => 16777216;\n" + "push @EXPORT, qw(PG_WAL_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" + "\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);\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::Get::Get;\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/Info.pm", + .data = + "\n" + "\n" + "\n" + "package pgBackRest::Info;\n" + "\n" + "use strict;\n" + "use warnings FATAL => qw(all);\n" + "use Carp qw(confess);\n" + "\n" + "use English '-no_match_vars';\n" + "use Exporter qw(import);\n" + "our @EXPORT = qw();\n" + "use File::Basename qw(dirname);\n" + "\n" + "use pgBackRest::Backup::Common;\n" + "use pgBackRest::Backup::Info;\n" + "use pgBackRest::Common::Exception;\n" + "use pgBackRest::Common::Log;\n" + "use pgBackRest::Common::Ini;\n" + "use pgBackRest::Common::String;\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" + "use pgBackRest::Storage::Helper;\n" + "\n" + "\n" + "\n" + "\n" + "use constant INFO_SECTION_BACKREST => 'backrest';\n" + "use constant INFO_SECTION_ARCHIVE => 'archive';\n" + "use constant INFO_SECTION_DB => 'database';\n" + "use constant INFO_SECTION_INFO => 'info';\n" + "use constant INFO_SECTION_REPO => 'repository';\n" + "use constant INFO_SECTION_TIMESTAMP => 'timestamp';\n" + "use constant INFO_SECTION_STATUS => 'status';\n" + "\n" + "use constant INFO_STANZA_NAME => 'name';\n" + "\n" + "use constant INFO_STANZA_STATUS_OK => 'ok';\n" + "use constant INFO_STANZA_STATUS_ERROR => 'error';\n" + "\n" + "use constant INFO_STANZA_STATUS_OK_CODE => 0;\n" + "use constant INFO_STANZA_STATUS_OK_MESSAGE => INFO_STANZA_STATUS_OK;\n" + "use constant INFO_STANZA_STATUS_MISSING_STANZA_CODE => 1;\n" + "use constant INFO_STANZA_STATUS_MISSING_STANZA_MESSAGE => 'missing stanza path';\n" + "use constant INFO_STANZA_STATUS_NO_BACKUP_CODE => 2;\n" + "use constant INFO_STANZA_STATUS_NO_BACKUP_MESSAGE => 'no valid backups';\n" + "use constant INFO_STANZA_STATUS_MISSING_STANZA_DATA_CODE => 3;\n" + "use constant INFO_STANZA_STATUS_MISSING_STANZA_DATA_MESSAGE => 'missing stanza data';\n" + "\n" + "use constant INFO_KEY_CODE => 'code';\n" + "use constant INFO_KEY_DELTA => 'delta';\n" + "use constant INFO_KEY_FORMAT => 'format';\n" + "use constant INFO_KEY_ID => INFO_HISTORY_ID;\n" + "use constant INFO_KEY_LABEL => 'label';\n" + "use constant INFO_KEY_MAX => 'max';\n" + "use constant INFO_KEY_MIN => 'min';\n" + "use constant INFO_KEY_MESSAGE => 'message';\n" + "use constant INFO_KEY_PRIOR => 'prior';\n" + "use constant INFO_KEY_REFERENCE => 'reference';\n" + "use constant INFO_KEY_SIZE => 'size';\n" + "use constant INFO_KEY_START => 'start';\n" + "use constant INFO_KEY_STOP => 'stop';\n" + "use constant INFO_KEY_SYSTEM_ID => INFO_SYSTEM_ID;\n" + "use constant INFO_KEY_TYPE => 'type';\n" + "use constant INFO_KEY_VERSION => INFO_DB_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 process\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');\n" + "\n" + "\n" + "my $strStanza = cfgOptionTest(CFGOPT_STANZA) ? cfgOption(CFGOPT_STANZA) : undef;\n" + "\n" + "\n" + "my $oyStanzaList = $self->stanzaList($strStanza);\n" + "\n" + "if (cfgOptionTest(CFGOPT_OUTPUT, CFGOPTVAL_INFO_OUTPUT_TEXT))\n" + "{\n" + "my $strOutput = $self->formatText($oyStanzaList);\n" + "\n" + "if (defined($strOutput))\n" + "{\n" + "syswrite(*STDOUT, $strOutput);\n" + "}\n" + "else\n" + "{\n" + "syswrite(*STDOUT, 'No stanzas exist in ' . storageRepo()->pathGet() . \".\\n\");\n" + "}\n" + "}\n" + "elsif (cfgOptionTest(CFGOPT_OUTPUT, CFGOPTVAL_INFO_OUTPUT_JSON))\n" + "{\n" + "my $oJSON = JSON::PP->new()->canonical()->pretty()->indent_length(4);\n" + "$self->outputJSON($oJSON->encode($oyStanzaList));\n" + "}\n" + "else\n" + "{\n" + "confess &log(ASSERT, \"invalid info output option '\" . cfgOption(CFGOPT_OUTPUT) . \"'\");\n" + "}\n" + "\n" + "\n" + "return logDebugReturn($strOperation);\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "sub outputJSON\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strJSON,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->outputJSON', \\@_,\n" + "{name => 'strJSON'},\n" + ");\n" + "\n" + "syswrite(*STDOUT, $strJSON);\n" + "\n" + "\n" + "\n" + "if ($strJSON !~ /\\n$/)\n" + "{\n" + "syswrite(*STDOUT, \"\\n\");\n" + "}\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub formatText\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$oyStanzaList,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->formatText', \\@_,\n" + "{name => 'oyStanzaList', trace => true},\n" + ");\n" + "\n" + "my $strOutput;\n" + "\n" + "foreach my $oStanzaInfo (@{$oyStanzaList})\n" + "{\n" + "\n" + "$strOutput .= (defined($strOutput) ? \"\\n\" : '') . $self->formatTextStanza($oStanzaInfo) . \"\\n\";\n" + "\n" + "\n" + "my $bDbCurrent = true;\n" + "\n" + "\n" + "foreach my $hDbInfo (reverse @{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}})\n" + "{\n" + "if ($bDbCurrent)\n" + "{\n" + "$strOutput .= \"\\n db (current)\";\n" + "}\n" + "\n" + "\n" + "my $strOutputArchive;\n" + "foreach my $hDbArchive (@{$oStanzaInfo->{&INFO_SECTION_ARCHIVE}})\n" + "{\n" + "if ($hDbArchive->{&INFO_SECTION_DB}{&INFO_HISTORY_ID} == $hDbInfo->{&INFO_HISTORY_ID})\n" + "{\n" + "\n" + "$strOutputArchive .= \"\\n wal archive min/max (\" . $hDbArchive->{&INFO_KEY_ID} . \"): \";\n" + "\n" + "if (defined($hDbArchive->{&INFO_KEY_MIN}))\n" + "{\n" + "$strOutputArchive .= $hDbArchive->{&INFO_KEY_MIN} . ' / ' . $hDbArchive->{&INFO_KEY_MAX};\n" + "}\n" + "else\n" + "{\n" + "$strOutputArchive .= 'none present';\n" + "}\n" + "\n" + "$strOutputArchive .= \"\\n\";\n" + "}\n" + "}\n" + "\n" + "\n" + "my $strOutputBackup;\n" + "foreach my $oBackupInfo (@{$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}})\n" + "{\n" + "if ($oBackupInfo->{&INFO_SECTION_DB}{&INFO_KEY_ID} == $hDbInfo->{&INFO_HISTORY_ID})\n" + "{\n" + "$strOutputBackup .= \"\\n\" . $self->formatTextBackup($oBackupInfo) . \"\\n\";\n" + "}\n" + "}\n" + "\n" + "if (defined($strOutputArchive) || defined($strOutputBackup))\n" + "{\n" + "if (!$bDbCurrent)\n" + "{\n" + "$strOutput .= \"\\n db (prior)\";\n" + "}\n" + "\n" + "if (defined($strOutputArchive))\n" + "{\n" + "$strOutput .= $strOutputArchive;\n" + "}\n" + "\n" + "if (defined($strOutputBackup))\n" + "{\n" + "$strOutput .= $strOutputBackup;\n" + "}\n" + "}\n" + "\n" + "$bDbCurrent = false;\n" + "}\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'strOutput', value => $strOutput, trace => true}\n" + ");\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub formatTextStanza\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$oStanzaInfo,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->formatTextStanza', \\@_,\n" + "{name => 'oStanzaInfo', trace => true},\n" + ");\n" + "\n" + "\n" + "my $strOutput =\n" + "'stanza: ' . $oStanzaInfo->{&INFO_STANZA_NAME} . \"\\n\" .\n" + "\" status: \" . ($oStanzaInfo->{&INFO_SECTION_STATUS}{&INFO_KEY_CODE} == 0 ? INFO_STANZA_STATUS_OK :\n" + "INFO_STANZA_STATUS_ERROR . ' (' . $oStanzaInfo->{&INFO_SECTION_STATUS}{&INFO_KEY_MESSAGE} . ')');\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'strOutput', value => $strOutput, trace => true}\n" + ");\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "sub formatTextBackup\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$oBackupInfo,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->formatTextBackup', \\@_,\n" + "{name => 'oBackupInfo', trace => true},\n" + ");\n" + "\n" + "my $strOutput =\n" + "' ' . $$oBackupInfo{&INFO_KEY_TYPE} . ' backup: ' . $$oBackupInfo{&INFO_KEY_LABEL} . \"\\n\" .\n" + "\n" + "' timestamp start/stop: ' .\n" + "timestampFormat(undef, $$oBackupInfo{&INFO_SECTION_TIMESTAMP}{&INFO_KEY_START}) .\n" + "' / ' .\n" + "timestampFormat(undef, $$oBackupInfo{&INFO_SECTION_TIMESTAMP}{&INFO_KEY_STOP}) . \"\\n\" .\n" + "\n" + "\" wal start/stop: \";\n" + "\n" + "if (defined($oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_START}) &&\n" + "defined($oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_STOP}))\n" + "{\n" + "$strOutput .=\n" + "$oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_START} . ' / ' . $oBackupInfo->{&INFO_SECTION_ARCHIVE}{&INFO_KEY_STOP};\n" + "}\n" + "else\n" + "{\n" + "$strOutput .= 'n/a';\n" + "}\n" + "\n" + "$strOutput .=\n" + "\"\\n database size: \" .\n" + "(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_SIZE}) ?\n" + "fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_SIZE}) : '') .\n" + "', backup size: ' .\n" + "(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_DELTA}) ?\n" + "fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_KEY_DELTA}) : '') . \"\\n\" .\n" + "\n" + "' repository size: ' .\n" + "(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_SIZE}) ?\n" + "fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_SIZE}) : '') .\n" + "', repository backup size: ' .\n" + "(defined($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_DELTA}) ?\n" + "fileSizeFormat($$oBackupInfo{&INFO_SECTION_INFO}{&INFO_SECTION_REPO}{&INFO_KEY_DELTA}) : '');\n" + "\n" + "\n" + "if (defined($oBackupInfo->{&INFO_KEY_REFERENCE}) && @{$oBackupInfo->{&INFO_KEY_REFERENCE}} > 0)\n" + "{\n" + "$strOutput .= \"\\n backup reference list: \" . (join(', ', @{$$oBackupInfo{&INFO_KEY_REFERENCE}}));\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'strOutput', value => $strOutput, trace => true}\n" + ");\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "sub stanzaList\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strStanza\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->stanzaList', \\@_,\n" + "{name => 'strStanza', required => false}\n" + ");\n" + "\n" + "my @oyStanzaList;\n" + "\n" + "\n" + "if (!isRepoLocal())\n" + "{\n" + "@oyStanzaList = @{protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(OP_INFO_STANZA_LIST, [$strStanza], true)};\n" + "}\n" + "\n" + "else\n" + "{\n" + "my @stryStanza = storageRepo()->list(cfgCommandName(CFGCMD_BACKUP), {bIgnoreMissing => true});\n" + "\n" + "foreach my $strStanzaFound (@stryStanza)\n" + "{\n" + "if (defined($strStanza) && $strStanza ne $strStanzaFound)\n" + "{\n" + "next;\n" + "}\n" + "\n" + "my $oStanzaInfo = {};\n" + "$$oStanzaInfo{&INFO_STANZA_NAME} = $strStanzaFound;\n" + "($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}, $$oStanzaInfo{&INFO_BACKUP_SECTION_DB}) =\n" + "$self->backupList($strStanzaFound);\n" + "\n" + "\n" + "if (defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}) && @{$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}} == 0)\n" + "{\n" + "$$oStanzaInfo{&INFO_SECTION_STATUS} =\n" + "{\n" + "&INFO_KEY_CODE => INFO_STANZA_STATUS_NO_BACKUP_CODE,\n" + "&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_NO_BACKUP_MESSAGE\n" + "};\n" + "}\n" + "\n" + "elsif (defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}))\n" + "{\n" + "$$oStanzaInfo{&INFO_SECTION_STATUS} =\n" + "{\n" + "&INFO_KEY_CODE => INFO_STANZA_STATUS_OK_CODE,\n" + "&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_OK_MESSAGE\n" + "};\n" + "}\n" + "\n" + "\n" + "my @oyDbArchiveList = ();\n" + "\n" + "if (!defined($$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP}))\n" + "{\n" + "$$oStanzaInfo{&INFO_SECTION_STATUS} =\n" + "{\n" + "&INFO_KEY_CODE => INFO_STANZA_STATUS_MISSING_STANZA_DATA_CODE,\n" + "&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_MISSING_STANZA_DATA_MESSAGE\n" + "};\n" + "\n" + "$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP} = [];\n" + "$$oStanzaInfo{&INFO_BACKUP_SECTION_DB} = [];\n" + "}\n" + "else\n" + "{\n" + "\n" + "my $hDbCurrent = @{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}}[-1];\n" + "my $strDbCurrentVersion = $hDbCurrent->{&INFO_KEY_VERSION};\n" + "my $ullDbCurrentSystemId = $hDbCurrent->{&INFO_KEY_SYSTEM_ID};\n" + "\n" + "\n" + "foreach my $hDbInfo (@{$oStanzaInfo->{&INFO_BACKUP_SECTION_DB}})\n" + "{\n" + "my $strArchiveStanzaPath = \"archive/\" . $strStanzaFound;\n" + "my $strDbVersion = $hDbInfo->{&INFO_KEY_VERSION};\n" + "my $ullDbSysId = $hDbInfo->{&INFO_KEY_SYSTEM_ID};\n" + "\n" + "\n" + "\n" + "my $oArchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet($strArchiveStanzaPath));\n" + "my $strArchiveId = $oArchiveInfo->archiveId({strDbVersion => $hDbInfo->{&INFO_KEY_VERSION},\n" + "ullDbSysId => $hDbInfo->{&INFO_KEY_SYSTEM_ID}});\n" + "my $strArchivePath = \"archive/${strStanzaFound}/${strArchiveId}\";\n" + "\n" + "\n" + "my $hDbArchive = $self->dbArchiveSection($hDbInfo, $strArchiveId, $strArchivePath, $strDbCurrentVersion,\n" + "$ullDbCurrentSystemId);\n" + "\n" + "if (defined($hDbArchive))\n" + "{\n" + "push(@oyDbArchiveList, $hDbArchive);\n" + "}\n" + "}\n" + "}\n" + "\n" + "\n" + "$oStanzaInfo->{&INFO_SECTION_ARCHIVE} = \\@oyDbArchiveList;\n" + "\n" + "push @oyStanzaList, $oStanzaInfo;\n" + "}\n" + "\n" + "if (defined($strStanza) && @oyStanzaList == 0)\n" + "{\n" + "my $oStanzaInfo = {};\n" + "\n" + "$$oStanzaInfo{&INFO_STANZA_NAME} = $strStanza;\n" + "\n" + "$$oStanzaInfo{&INFO_SECTION_STATUS} =\n" + "{\n" + "&INFO_KEY_CODE => INFO_STANZA_STATUS_MISSING_STANZA_CODE,\n" + "&INFO_KEY_MESSAGE => INFO_STANZA_STATUS_MISSING_STANZA_MESSAGE\n" + "};\n" + "\n" + "$$oStanzaInfo{&INFO_BACKUP_SECTION_BACKUP} = [];\n" + "$$oStanzaInfo{&INFO_BACKUP_SECTION_DB} = [];\n" + "\n" + "push @oyStanzaList, $oStanzaInfo;\n" + "}\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'oyStanzaList', value => \\@oyStanzaList, log => false, ref => true}\n" + ");\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "sub backupList\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strStanza\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->backupList', \\@_,\n" + "{name => 'strStanza'}\n" + ");\n" + "\n" + "\n" + "my $oBackupInfo = undef;\n" + "\n" + "\n" + "logDisable();\n" + "\n" + "eval\n" + "{\n" + "$oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet(cfgCommandName(CFGCMD_BACKUP) . \"/${strStanza}\"), false);\n" + "logEnable();\n" + "return true;\n" + "}\n" + "or do\n" + "{\n" + "logEnable();\n" + "\n" + "if (exceptionCode($EVAL_ERROR) == ERROR_FILE_MISSING)\n" + "{\n" + "return;\n" + "}\n" + "elsif (exceptionCode($EVAL_ERROR) == ERROR_CIPHER)\n" + "{\n" + "\n" + "confess &log(ERROR, exceptionMessage($EVAL_ERROR) .\n" + "\"\\nHINT: use option --stanza if encryption settings are different for the stanza than the global settings\",\n" + "ERROR_CIPHER);\n" + "}\n" + "else\n" + "{\n" + "\n" + "confess $EVAL_ERROR;\n" + "}\n" + "};\n" + "\n" + "\n" + "my @oyDbList;\n" + "\n" + "foreach my $iHistoryId ($oBackupInfo->keys(INFO_BACKUP_SECTION_DB_HISTORY))\n" + "{\n" + "my $oDbHash =\n" + "{\n" + "&INFO_HISTORY_ID => $iHistoryId + 0,\n" + "&INFO_DB_VERSION =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_DB_VERSION),\n" + "&INFO_SYSTEM_ID =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_SYSTEM_ID)\n" + "};\n" + "\n" + "push(@oyDbList, $oDbHash);\n" + "}\n" + "\n" + "\n" + "my @oyBackupList;\n" + "\n" + "foreach my $strBackup ($oBackupInfo->keys(INFO_BACKUP_SECTION_BACKUP_CURRENT))\n" + "{\n" + "my $oBackupHash =\n" + "{\n" + "&INFO_SECTION_ARCHIVE =>\n" + "{\n" + "&INFO_KEY_START =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_ARCHIVE_START, false),\n" + "&INFO_KEY_STOP =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_ARCHIVE_STOP, false),\n" + "},\n" + "&INFO_SECTION_BACKREST =>\n" + "{\n" + "&INFO_KEY_FORMAT =>\n" + "$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INI_KEY_FORMAT),\n" + "&INFO_KEY_VERSION =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INI_KEY_VERSION)\n" + "},\n" + "&INFO_SECTION_DB =>\n" + "{\n" + "&INFO_KEY_ID =>\n" + "$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_HISTORY_ID)\n" + "},\n" + "&INFO_SECTION_INFO =>\n" + "{\n" + "&INFO_SECTION_REPO =>\n" + "{\n" + "\n" + "&INFO_KEY_SIZE =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_REPO_SIZE),\n" + "\n" + "&INFO_KEY_DELTA =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA),\n" + "},\n" + "\n" + "&INFO_KEY_SIZE =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_SIZE),\n" + "\n" + "&INFO_KEY_DELTA =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_BACKUP_SIZE_DELTA),\n" + "},\n" + "&INFO_SECTION_TIMESTAMP =>\n" + "{\n" + "&INFO_KEY_START =>\n" + "$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TIMESTAMP_START),\n" + "&INFO_KEY_STOP =>\n" + "$oBackupInfo->numericGet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TIMESTAMP_STOP),\n" + "},\n" + "&INFO_KEY_LABEL => $strBackup,\n" + "&INFO_KEY_PRIOR =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_PRIOR, false),\n" + "&INFO_KEY_REFERENCE =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_REFERENCE, false),\n" + "&INFO_KEY_TYPE =>\n" + "$oBackupInfo->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_TYPE)\n" + "};\n" + "\n" + "push(@oyBackupList, $oBackupHash);\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'oyBackupList', value => \\@oyBackupList, log => false, ref => true},\n" + "{name => 'oyDbList', value => \\@oyDbList, log => false, ref => true}\n" + ");\n" + "}\n" + "\n" + "\n" + "\n" + "\n" + "sub dbArchiveSection\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$hDbInfo,\n" + "$strArchiveId,\n" + "$strArchivePath,\n" + "$strDbCurrentVersion,\n" + "$ullDbCurrentSystemId,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->dbArchiveSection', \\@_,\n" + "{name => 'hDbInfo'},\n" + "{name => 'strArchiveId'},\n" + "{name => 'strArchivePath'},\n" + "{name => 'strDbCurrentVersion'},\n" + "{name => 'ullDbCurrentSystemId'},\n" + ");\n" + "\n" + "my $hDbArchive = undef;\n" + "my $strArchiveStart = undef;\n" + "my $strArchiveStop = undef;\n" + "\n" + "if (storageRepo()->pathExists($strArchivePath))\n" + "{\n" + "my @stryWalMajor = storageRepo()->list($strArchivePath, {strExpression => '^[0-F]{16}$'});\n" + "\n" + "\n" + "foreach my $strWalMajor (@stryWalMajor)\n" + "{\n" + "my @stryWalFile = storageRepo()->list(\n" + "\"${strArchivePath}/${strWalMajor}\",\n" + "{strExpression => \"^[0-F]{24}-[0-f]{40}(\\\\.\" . COMPRESS_EXT . \"){0,1}\\$\"});\n" + "\n" + "if (@stryWalFile > 0)\n" + "{\n" + "$strArchiveStart = substr($stryWalFile[0], 0, 24);\n" + "last;\n" + "}\n" + "}\n" + "\n" + "\n" + "foreach my $strWalMajor (sort({$b cmp $a} @stryWalMajor))\n" + "{\n" + "my @stryWalFile = storageRepo()->list(\n" + "\"${strArchivePath}/${strWalMajor}\",\n" + "{strExpression => \"^[0-F]{24}-[0-f]{40}(\\\\.\" . COMPRESS_EXT . \"){0,1}\\$\", strSortOrder => 'reverse'});\n" + "\n" + "if (@stryWalFile > 0)\n" + "{\n" + "$strArchiveStop = substr($stryWalFile[0], 0, 24);\n" + "last;\n" + "}\n" + "}\n" + "}\n" + "\n" + "\n" + "if (($strDbCurrentVersion eq $hDbInfo->{&INFO_KEY_VERSION} &&\n" + "$ullDbCurrentSystemId == $hDbInfo->{&INFO_KEY_SYSTEM_ID}) ||\n" + "defined($strArchiveStart) )\n" + "{\n" + "$hDbArchive =\n" + "{\n" + "&INFO_KEY_ID => $strArchiveId,\n" + "&INFO_KEY_MIN => $strArchiveStart,\n" + "&INFO_KEY_MAX => $strArchiveStop,\n" + "&INFO_SECTION_DB =>\n" + "{\n" + "&INFO_HISTORY_ID => $hDbInfo->{&INFO_HISTORY_ID} + 0,\n" + "},\n" + "};\n" + "}\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'hDbArchive', value => $hDbArchive, trace => true},\n" + ");\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" + "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" + "CFGCMD_ARCHIVE_GET => 0,\n" + "CFGCMD_ARCHIVE_PUSH => 1,\n" + "CFGCMD_BACKUP => 2,\n" + "CFGCMD_CHECK => 3,\n" + "CFGCMD_EXPIRE => 4,\n" + "CFGCMD_HELP => 5,\n" + "CFGCMD_INFO => 6,\n" + "CFGCMD_LOCAL => 7,\n" + "CFGCMD_REMOTE => 8,\n" + "CFGCMD_RESTORE => 9,\n" + "CFGCMD_STANZA_CREATE => 10,\n" + "CFGCMD_STANZA_DELETE => 11,\n" + "CFGCMD_STANZA_UPGRADE => 12,\n" + "CFGCMD_START => 13,\n" + "CFGCMD_STOP => 14,\n" + "CFGCMD_VERSION => 15,\n" + "\n" + "CFGOPT_ARCHIVE_ASYNC => 0,\n" + "CFGOPT_ARCHIVE_CHECK => 1,\n" + "CFGOPT_ARCHIVE_COPY => 2,\n" + "CFGOPT_ARCHIVE_GET_QUEUE_MAX => 3,\n" + "CFGOPT_ARCHIVE_PUSH_QUEUE_MAX => 4,\n" + "CFGOPT_ARCHIVE_TIMEOUT => 5,\n" + "CFGOPT_BACKUP_STANDBY => 6,\n" + "CFGOPT_BUFFER_SIZE => 7,\n" + "CFGOPT_CHECKSUM_PAGE => 8,\n" + "CFGOPT_CMD_SSH => 9,\n" + "CFGOPT_COMMAND => 10,\n" + "CFGOPT_COMPRESS => 11,\n" + "CFGOPT_COMPRESS_LEVEL => 12,\n" + "CFGOPT_COMPRESS_LEVEL_NETWORK => 13,\n" + "CFGOPT_CONFIG => 14,\n" + "CFGOPT_CONFIG_INCLUDE_PATH => 15,\n" + "CFGOPT_CONFIG_PATH => 16,\n" + "CFGOPT_DB_INCLUDE => 17,\n" + "CFGOPT_DB_TIMEOUT => 18,\n" + "CFGOPT_DELTA => 19,\n" + "CFGOPT_FORCE => 20,\n" + "CFGOPT_HOST_ID => 21,\n" + "CFGOPT_LINK_ALL => 22,\n" + "CFGOPT_LINK_MAP => 23,\n" + "CFGOPT_LOCK_PATH => 24,\n" + "CFGOPT_LOG_LEVEL_CONSOLE => 25,\n" + "CFGOPT_LOG_LEVEL_FILE => 26,\n" + "CFGOPT_LOG_LEVEL_STDERR => 27,\n" + "CFGOPT_LOG_PATH => 28,\n" + "CFGOPT_LOG_TIMESTAMP => 29,\n" + "CFGOPT_MANIFEST_SAVE_THRESHOLD => 30,\n" + "CFGOPT_NEUTRAL_UMASK => 31,\n" + "CFGOPT_ONLINE => 32,\n" + "CFGOPT_OUTPUT => 33,\n" + "CFGOPT_PERL_OPTION => 34,\n" + "CFGOPT_PG_HOST => 35,\n" + "CFGOPT_PG_HOST_CMD => 43,\n" + "CFGOPT_PG_HOST_CONFIG => 51,\n" + "CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH => 59,\n" + "CFGOPT_PG_HOST_CONFIG_PATH => 67,\n" + "CFGOPT_PG_HOST_PORT => 75,\n" + "CFGOPT_PG_HOST_USER => 83,\n" + "CFGOPT_PG_PATH => 91,\n" + "CFGOPT_PG_PORT => 99,\n" + "CFGOPT_PG_SOCKET_PATH => 107,\n" + "CFGOPT_PROCESS => 115,\n" + "CFGOPT_PROCESS_MAX => 116,\n" + "CFGOPT_PROTOCOL_TIMEOUT => 117,\n" + "CFGOPT_RECOVERY_OPTION => 118,\n" + "CFGOPT_REPO_CIPHER_PASS => 119,\n" + "CFGOPT_REPO_CIPHER_TYPE => 120,\n" + "CFGOPT_REPO_HARDLINK => 121,\n" + "CFGOPT_REPO_HOST => 122,\n" + "CFGOPT_REPO_HOST_CMD => 123,\n" + "CFGOPT_REPO_HOST_CONFIG => 124,\n" + "CFGOPT_REPO_HOST_CONFIG_INCLUDE_PATH => 125,\n" + "CFGOPT_REPO_HOST_CONFIG_PATH => 126,\n" + "CFGOPT_REPO_HOST_PORT => 127,\n" + "CFGOPT_REPO_HOST_USER => 128,\n" + "CFGOPT_REPO_PATH => 129,\n" + "CFGOPT_REPO_RETENTION_ARCHIVE => 130,\n" + "CFGOPT_REPO_RETENTION_ARCHIVE_TYPE => 131,\n" + "CFGOPT_REPO_RETENTION_DIFF => 132,\n" + "CFGOPT_REPO_RETENTION_FULL => 133,\n" + "CFGOPT_REPO_S3_BUCKET => 134,\n" + "CFGOPT_REPO_S3_CA_FILE => 135,\n" + "CFGOPT_REPO_S3_CA_PATH => 136,\n" + "CFGOPT_REPO_S3_ENDPOINT => 137,\n" + "CFGOPT_REPO_S3_HOST => 138,\n" + "CFGOPT_REPO_S3_KEY => 139,\n" + "CFGOPT_REPO_S3_KEY_SECRET => 140,\n" + "CFGOPT_REPO_S3_REGION => 141,\n" + "CFGOPT_REPO_S3_TOKEN => 142,\n" + "CFGOPT_REPO_S3_VERIFY_SSL => 143,\n" + "CFGOPT_REPO_TYPE => 144,\n" + "CFGOPT_RESUME => 145,\n" + "CFGOPT_SET => 146,\n" + "CFGOPT_SPOOL_PATH => 147,\n" + "CFGOPT_STANZA => 148,\n" + "CFGOPT_START_FAST => 149,\n" + "CFGOPT_STOP_AUTO => 150,\n" + "CFGOPT_TABLESPACE_MAP => 151,\n" + "CFGOPT_TABLESPACE_MAP_ALL => 152,\n" + "CFGOPT_TARGET => 153,\n" + "CFGOPT_TARGET_ACTION => 154,\n" + "CFGOPT_TARGET_EXCLUSIVE => 155,\n" + "CFGOPT_TARGET_TIMELINE => 156,\n" + "CFGOPT_TEST => 157,\n" + "CFGOPT_TEST_DELAY => 158,\n" + "CFGOPT_TEST_POINT => 159,\n" + "CFGOPT_TYPE => 160,\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_SIZE => 5,\n" + "CFGDEF_TYPE_STRING => 6,\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" + "cipher =>\n" + "[\n" + "'CIPHER_MODE_ENCRYPT',\n" + "'CIPHER_MODE_DECRYPT',\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_PUSH',\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_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_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_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_HOST_CMD',\n" + "'CFGOPT_PG_HOST_CONFIG',\n" + "'CFGOPT_PG_HOST_CONFIG_INCLUDE_PATH',\n" + "'CFGOPT_PG_HOST_CONFIG_PATH',\n" + "'CFGOPT_PG_HOST_PORT',\n" + "'CFGOPT_PG_HOST_USER',\n" + "'CFGOPT_PG_PATH',\n" + "'CFGOPT_PG_PORT',\n" + "'CFGOPT_PG_SOCKET_PATH',\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_SSL',\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_SIZE',\n" + "'CFGDEF_TYPE_STRING',\n" + "'cfgCommandId',\n" + "'cfgDefOptionDefault',\n" + "'cfgDefOptionPrefix',\n" + "'cfgDefOptionSecure',\n" + "'cfgDefOptionType',\n" + "'cfgDefOptionValid',\n" + "'cfgOptionId',\n" + "'cfgOptionTotal',\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" + "'randomBytes',\n" + "],\n" + "\n" + "storage =>\n" + "[\n" + "'storageDriverPosixPathRemove',\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::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 $result = 0;\n" + "my $message = '';\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_ARCHIVE_PUSH))\n" + "{\n" + "\n" + "require pgBackRest::Archive::Push::Push;\n" + "pgBackRest::Archive::Push::Push->import();\n" + "\n" + "new pgBackRest::Archive::Push::Push()->process($stryCommandArg[0]);\n" + "}\n" + "\n" + "\n" + "\n" + "elsif (cfgCommandTest(CFGCMD_ARCHIVE_GET))\n" + "{\n" + "\n" + "require pgBackRest::Archive::Get::Get;\n" + "pgBackRest::Archive::Get::Get->import();\n" + "\n" + "$result = new pgBackRest::Archive::Get::Get()->process(\\@stryCommandArg);\n" + "}\n" + "\n" + "\n" + "\n" + "elsif (cfgCommandTest(CFGCMD_REMOTE))\n" + "{\n" + "\n" + "cfgOptionSet(CFGOPT_LOG_LEVEL_STDERR, PROTOCOL, true);\n" + "logLevelSet(OFF, OFF, cfgOption(CFGOPT_LOG_LEVEL_STDERR));\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(cfgOption(CFGOPT_LOCK_PATH), cfgOption(CFGOPT_COMMAND), cfgOption(CFGOPT_STANZA, false));\n" + "}\n" + "\n" + "\n" + "\n" + "elsif (cfgCommandTest(CFGCMD_LOCAL))\n" + "{\n" + "\n" + "cfgOptionSet(CFGOPT_LOG_LEVEL_STDERR, PROTOCOL, true);\n" + "logLevelSet(OFF, OFF, cfgOption(CFGOPT_LOG_LEVEL_STDERR));\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" + "$result = 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" + "\n" + "require pgBackRest::Storage::Helper;\n" + "pgBackRest::Storage::Helper->import();\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" + "$result = 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" + "$result = $oException->code();\n" + "\n" + "\n" + "if (!$bConfigLoaded && cfgOption(CFGOPT_ARCHIVE_ASYNC))\n" + "{\n" + "$message = $oException->message();\n" + "}\n" + "}\n" + "\n" + "else\n" + "{\n" + "$result = ERROR_UNHANDLED;\n" + "$message =\n" + "'process terminated due to an unhandled exception' .\n" + "(defined($oException) ? \":\\n${oException}\" : ': [exception not defined]');\n" + "}\n" + "};\n" + "\n" + "\n" + "return $result, $message;\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 Digest::SHA;\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_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_ONLINE => 'option-' . cfgOptionName(CFGOPT_ONLINE);\n" + "push @EXPORT, qw(MANIFEST_KEY_ONLINE);\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" + "$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 => '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))\n" + "{\n" + "confess &log(ASSERT, 'strDbVersion must be provided with bLoad = false');\n" + "}\n" + "\n" + "$self->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, $strDbVersion);\n" + "}\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 build\n" + "{\n" + "my $self = shift;\n" + "\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$oStorageDbMaster,\n" + "$strPath,\n" + "$oLastManifest,\n" + "$bOnline,\n" + "$hTablespaceMap,\n" + "$hDatabaseMap,\n" + "$strLevel,\n" + "$bTablespace,\n" + "$strParentPath,\n" + "$strFilter\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->build', \\@_,\n" + "{name => 'oStorageDbMaster'},\n" + "{name => 'strPath'},\n" + "{name => 'oLastManifest', required => false},\n" + "{name => 'bOnline'},\n" + "{name => 'hTablespaceMap', required => false},\n" + "{name => 'hDatabaseMap', required => false},\n" + "{name => 'strLevel', required => false},\n" + "{name => 'bTablespace', required => false},\n" + "{name => 'strParentPath', required => false},\n" + "{name => 'strFilter', required => false}\n" + ");\n" + "\n" + "if (!defined($strLevel))\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" + "$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);\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" + "\n" + "if (defined($strFilter) && $strName ne $strFilter && index($strName, \"${strFilter}/\") != 0)\n" + "{\n" + "next;\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" + "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($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" + "$strPath = dirname(\"${strPath}/${strName}\");\n" + "\n" + "$self->build(\n" + "$oStorageDbMaster, $strLinkDestination, undef, $bOnline, $hTablespaceMap, $hDatabaseMap, $strFile, $bTablespace,\n" + "$strPath, $strFilter, $strLinkDestination);\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" + "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" + "elsif (defined($oLastManifest) && $oLastManifest->test(MANIFEST_SECTION_TARGET_FILE, $strName) &&\n" + "$self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_SIZE) ==\n" + "$oLastManifest->get(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_SIZE) &&\n" + "$self->numericGet(MANIFEST_SECTION_TARGET_FILE, $strName, MANIFEST_SUBKEY_TIMESTAMP) ==\n" + "$oLastManifest->get(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($strOperation);\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 => BACKREST_NAME},\n" + "{strName => 'version', strExpected => BACKREST_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(ERROR, $strError, $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 => BACKREST_NAME, service => $self->{strName}, version => BACKREST_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" + "\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))\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" + "use constant OP_ARCHIVE_PUSH_CHECK => 'archivePushCheck';\n" + "push @EXPORT, qw(OP_ARCHIVE_PUSH_CHECK);\n" + "\n" + "\n" + "use constant OP_ARCHIVE_GET_FILE => 'archiveGetFile';\n" + "push @EXPORT, qw(OP_ARCHIVE_GET_FILE);\n" + "use constant OP_ARCHIVE_PUSH_FILE => 'archivePushFile';\n" + "push @EXPORT, qw(OP_ARCHIVE_PUSH_FILE);\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_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_INFO_STANZA_LIST => 'infoStanzList';\n" + "push @EXPORT, qw(OP_INFO_STANZA_LIST);\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" + ");\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 => $iProcessIdx},\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" + "\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, default => 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::Archive::Get::File;\n" + "use pgBackRest::Archive::Push::File;\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_ARCHIVE_GET_FILE => sub {archiveGetFile(@{shift()})},\n" + "&OP_ARCHIVE_PUSH_FILE => sub {archivePushFile(@{shift()})},\n" + "&OP_BACKUP_FILE => sub {backupFile(@{shift()})},\n" + "&OP_RESTORE_FILE => sub {restoreFile(@{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 => backrestBin()},\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" + "&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" + "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::Archive::Push::File;\n" + "use pgBackRest::Check::Check;\n" + "use pgBackRest::Config::Config;\n" + "use pgBackRest::Db;\n" + "use pgBackRest::Info;\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 $oInfo = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Info() : 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_ARCHIVE_PUSH_CHECK => sub {archivePushCheck(@{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" + "\n" + "\n" + "&OP_INFO_STANZA_LIST => sub {$oInfo->stanzaList(@{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 => '';\n" + "push @EXPORT, qw(STORAGE_DB);\n" + "\n" + "use constant STORAGE_REPO => '';\n" + "push @EXPORT, qw(STORAGE_REPO);\n" + "use constant STORAGE_REPO_ARCHIVE => '';\n" + "push @EXPORT, qw(STORAGE_REPO_ARCHIVE);\n" + "use constant STORAGE_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/${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/${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" + "if ($strStanza ne STORAGE_REPO)\n" + "{\n" + "$hRule =\n" + "{\n" + "&STORAGE_REPO_ARCHIVE =>\n" + "{\n" + "fnRule => \\&storageRepoRule,\n" + "xData => $strStanza,\n" + "},\n" + "&STORAGE_REPO_BACKUP =>\n" + "{\n" + "fnRule => \\&storageRepoRule,\n" + "xData => $strStanza,\n" + "},\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_SSL, 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 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" + "\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" + "\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" + "$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: $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-${b}\", $oManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $b, MANIFEST_SUBKEY_SIZE)) cmp\n" + "sprintf(\"%016d-${a}\", $oManifest->numericGet(MANIFEST_SECTION_TARGET_FILE, $a, MANIFEST_SUBKEY_SIZE))}\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 restoreFile\n" + "{\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strDbFile,\n" + "$lSize,\n" + "$lModificationTime,\n" + "$strChecksum,\n" + "$bZero,\n" + "$bForce,\n" + "$strRepoFile,\n" + "$strReference,\n" + "$strMode,\n" + "$strUser,\n" + "$strGroup,\n" + "$lCopyTimeStart,\n" + "$bDelta,\n" + "$strBackupPath,\n" + "$bSourceCompressed,\n" + "$strCipherPass,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::restoreFile', \\@_,\n" + "{name => 'strDbFile', trace => true},\n" + "{name => 'lSize', trace => true},\n" + "{name => 'lModificationTime', trace => true},\n" + "{name => 'strChecksum', required => false, trace => true},\n" + "{name => 'bZero', required => false, default => false, trace => true},\n" + "{name => 'bForce', trace => true},\n" + "{name => 'strRepoFile', trace => true},\n" + "{name => 'strReference', required => false, trace => true},\n" + "{name => 'strMode', trace => true},\n" + "{name => 'strUser', trace => true},\n" + "{name => 'strGroup', trace => true},\n" + "{name => 'lCopyTimeStart', trace => true},\n" + "{name => 'bDelta', trace => true},\n" + "{name => 'strBackupPath', trace => true},\n" + "{name => 'bSourceCompressed', trace => true},\n" + "{name => 'strCipherPass', required => false, trace => true},\n" + ");\n" + "\n" + "\n" + "my $oStorageDb = storageDb();\n" + "my $bCopy = true;\n" + "\n" + "\n" + "if ($bZero)\n" + "{\n" + "$bCopy = false;\n" + "\n" + "my $oDestinationFileIo = $oStorageDb->openWrite(\n" + "$strDbFile, {strMode => $strMode, strUser => $strUser, strGroup => $strGroup, lTimestamp => $lModificationTime});\n" + "$oDestinationFileIo->open();\n" + "\n" + "\n" + "truncate($oDestinationFileIo->handle(), $lSize);\n" + "\n" + "$oDestinationFileIo->close();\n" + "}\n" + "\n" + "elsif ($bDelta)\n" + "{\n" + "my $oStat = $oStorageDb->info($strDbFile, {bIgnoreMissing => true});\n" + "\n" + "\n" + "if (defined($oStat) &&\n" + "(!S_ISLNK($oStat->mode) ||\n" + "$oStorageDb->exists(\n" + "$oStorageDb->pathAbsolute(dirname($strDbFile), $oStorageDb->{oDriver}->linkDestination($strDbFile)))))\n" + "{\n" + "\n" + "if ($bForce)\n" + "{\n" + "\n" + "if (defined($oStat) && $oStat->size == $lSize &&\n" + "$oStat->mtime == $lModificationTime && $oStat->mtime < $lCopyTimeStart)\n" + "{\n" + "$bCopy = false;\n" + "}\n" + "}\n" + "else\n" + "{\n" + "my ($strActualChecksum, $lActualSize) = $oStorageDb->hashSize($strDbFile);\n" + "\n" + "if ($lActualSize == $lSize && ($lSize == 0 || $strActualChecksum eq $strChecksum))\n" + "{\n" + "\n" + "\n" + "utime($lModificationTime, $lModificationTime, $strDbFile)\n" + "or confess &log(ERROR, \"unable to set time for ${strDbFile}\");\n" + "\n" + "$bCopy = false;\n" + "}\n" + "}\n" + "}\n" + "}\n" + "\n" + "\n" + "if ($bCopy)\n" + "{\n" + "\n" + "my $rhyFilter = [{strClass => STORAGE_FILTER_SHA}];\n" + "\n" + "\n" + "if ($bSourceCompressed)\n" + "{\n" + "unshift(@{$rhyFilter}, {strClass => STORAGE_FILTER_GZIP, rxyParam => [{strCompressType => STORAGE_DECOMPRESS}]});\n" + "}\n" + "\n" + "\n" + "my $oDestinationFileIo = $oStorageDb->openWrite(\n" + "$strDbFile,\n" + "{strMode => $strMode, strUser => $strUser, strGroup => $strGroup, lTimestamp => $lModificationTime,\n" + "rhyFilter => $rhyFilter});\n" + "\n" + "\n" + "storageRepo()->copy(\n" + "storageRepo()->openRead(\n" + "STORAGE_REPO_BACKUP . qw(/) . (defined($strReference) ? $strReference : $strBackupPath) .\n" + "\"/${strRepoFile}\" . ($bSourceCompressed ? qw{.} . COMPRESS_EXT : ''),\n" + "{bProtocolCompress => !$bSourceCompressed && $lSize != 0, strCipherPass => $strCipherPass}),\n" + "$oDestinationFileIo);\n" + "\n" + "\n" + "if ($oDestinationFileIo->result(COMMON_IO_HANDLE) != 0 && $oDestinationFileIo->result(STORAGE_FILTER_SHA) ne $strChecksum)\n" + "{\n" + "confess &log(ERROR,\n" + "\"error restoring ${strDbFile}: actual checksum '\" . $oDestinationFileIo->digest() .\n" + "\"' does not match expected checksum ${strChecksum}\", ERROR_CHECKSUM);\n" + "}\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'bCopy', value => $bCopy, trace => true}\n" + ");\n" + "}\n" + "\n" + "push @EXPORT, qw(restoreFile);\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" + "my $strHintStanzaCreate = \"\\nHINT: has a stanza-create been performed?\";\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" + "elsif (cfgCommandTest(CFGCMD_STANZA_DELETE))\n" + "{\n" + "$self->stanzaDelete();\n" + "}\n" + "\n" + "else\n" + "{\n" + "confess &log(ASSERT, \"stanza->process() called with invalid command: \" . cfgCommandName(cfgCommandGet()));\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" + "my ($oDbMaster, $iMasterRemoteIdx) = dbObjectGet({bMasterOnly => true});\n" + "\n" + "\n" + "my $oStorageDbMaster = storageDb({iRemoteIdx => $iMasterRemoteIdx});\n" + "\n" + "\n" + "if ($oStorageDbMaster->exists(DB_FILE_POSTMASTERPID) && !cfgOption(CFGOPT_FORCE))\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" + "$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 :\n" + "$strResultMessage . $strHintStanzaCreate, $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_CIPHER))\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" + "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" + "\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 {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(:cipher);\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} = Digest::SHA->new($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}->add($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}->add($$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}->hexdigest());\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 => '';\n" + "push @EXPORT, qw(STORAGE_LOCAL);\n" + "\n" + "use constant STORAGE_SPOOL => '';\n" + "push @EXPORT, qw(STORAGE_SPOOL);\n" + "use constant STORAGE_SPOOL_ARCHIVE_IN => '';\n" + "push @EXPORT, qw(STORAGE_SPOOL_ARCHIVE_IN);\n" + "use constant STORAGE_SPOOL_ARCHIVE_OUT => '';\n" + "push @EXPORT, qw(STORAGE_SPOOL_ARCHIVE_OUT);\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 => BACKREST_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" + "\n" + "\n" + "\n" + "sub storageSpool\n" + "{\n" + "\n" + "my\n" + "(\n" + "$strOperation,\n" + "$strStanza,\n" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '::storageSpool', \\@_,\n" + "{name => 'strStanza', default => cfgOption(CFGOPT_STANZA), trace => true},\n" + ");\n" + "\n" + "\n" + "if (!defined($hStorage->{&STORAGE_SPOOL}{$strStanza}))\n" + "{\n" + "\n" + "my $hRule =\n" + "{\n" + "&STORAGE_SPOOL_ARCHIVE_IN => \"archive/${strStanza}/in\",\n" + "&STORAGE_SPOOL_ARCHIVE_OUT => \"archive/${strStanza}/out\",\n" + "};\n" + "\n" + "\n" + "$hStorage->{&STORAGE_SPOOL}{$strStanza} = new pgBackRest::Storage::Local(\n" + "cfgOption(CFGOPT_SPOOL_PATH), new pgBackRest::Storage::Posix::Driver(),\n" + "{hRule => $hRule, strTempExtension => STORAGE_TEMP_EXT, lBufferMax => cfgOption(CFGOPT_BUFFER_SIZE)});\n" + "}\n" + "\n" + "\n" + "return logDebugReturn\n" + "(\n" + "$strOperation,\n" + "{name => 'oStorageSpool', value => $hStorage->{&STORAGE_SPOOL}{$strStanza}, trace => true},\n" + ");\n" + "}\n" + "\n" + "push @EXPORT, qw(storageSpool);\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" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->hashSize', \\@_,\n" + "{name => 'xFileExp'},\n" + ");\n" + "\n" + "\n" + "my $strHash;\n" + "my $lSize;\n" + "\n" + "\n" + "my $oFileIo = defined($xFileExp) ? (ref($xFileExp) ? $xFileExp : $self->openRead($self->pathGet($xFileExp))) : 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'},\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" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->manifest', \\@_,\n" + "{name => 'strPathExp'},\n" + ");\n" + "\n" + "my $hManifest = $self->driver()->manifest($self->pathGet($strPathExp));\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" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->manifest', \\@_,\n" + "{name => 'strPath', trace => true},\n" + "{name => 'bIgnoreMissing', optional => true, default => false, trace => true},\n" + ");\n" + "\n" + "\n" + "my $hManifest = {};\n" + "$self->manifestRecurse($strPath, undef, 0, $hManifest, $bIgnoreMissing);\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" + ") =\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" + ");\n" + "\n" + "\n" + "my $strPathRead = $strPath . (defined($strSubPath) ? \"/${strSubPath}\" : '');\n" + "my $hPath;\n" + "my $strFilter;\n" + "\n" + "\n" + "my $oPathInfo = $self->info($strPathRead, {bIgnoreMissing => $bIgnoreMissing});\n" + "\n" + "if (defined($oPathInfo))\n" + "{\n" + "if ($iDepth == 0 && !S_ISDIR($oPathInfo->mode()))\n" + "{\n" + "$strFilter = basename($strPathRead);\n" + "$strPathRead = dirname($strPathRead);\n" + "}\n" + "\n" + "\n" + "my @stryFileList = @{$self->list($strPathRead, {bIgnoreMissing => $iDepth != 0})};\n" + "unshift(@stryFileList, '.');\n" + "my $hFileStat = $self->manifestList($strPathRead, \\@stryFileList);\n" + "\n" + "\n" + "foreach my $strFile (keys(%{$hFileStat}))\n" + "{\n" + "\n" + "if (defined($strFilter) && $strFile ne $strFilter)\n" + "{\n" + "next;\n" + "}\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" + "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" + ") =\n" + "logDebugParam\n" + "(\n" + "__PACKAGE__ . '->manifestList', \\@_,\n" + "{name => 'strPath', trace => true},\n" + "{name => 'stryFile', trace => true},\n" + ");\n" + "\n" + "my $hFileStat = {};\n" + "\n" + "foreach my $strFile (@{$stryFile})\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" + "if (!(defined($strUser) && defined($strGroup)))\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" + "\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 (!chown($iUserId, $iGroupId, $strFilePath))\n" + "{\n" + "if ($OS_ERROR{ENOENT})\n" + "{\n" + "logErrorResult(ERROR_FILE_OWNER, \"${strMessage} because it is missing\");\n" + "}\n" + "\n" + "logErrorResult(ERROR_FILE_OWNER, \"${strMessage}\", $OS_ERROR);\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" + "storageDriverPosixPathRemove($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 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 sha256_hex);\n" + "use Exporter qw(import);\n" + "our @EXPORT = qw();\n" + "use POSIX qw(strftime);\n" + "\n" + "use pgBackRest::Common::Log;\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 => sha256_hex('');\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%k%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($strVerb, $strUri, $strQuery, $hHeader, $strPayloadHash);\n" + "my $strStringToSign = s3StringToSign($strDateTime, $strRegion, sha256_hex($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 . 'true';\n" + "\n" + "while (defined($strFile))\n" + "{\n" + "$iTotal++;\n" + "$strXml .= '' . substr($strFile, 1) . '';\n" + "\n" + "$strFile = $iTotal < S3_BATCH_MAX ? shift(@{$rstryFileAll}) : undef;\n" + "}\n" + "\n" + "$strXml .= '';\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::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" + "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" + "\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 . '';\n" + "my $iPartNo = 0;\n" + "\n" + "foreach my $strETag (@{$self->{rstryMultiPart}})\n" + "{\n" + "$iPartNo++;\n" + "\n" + "$strXml .= \"${iPartNo}${strETag}\";\n" + "}\n" + "\n" + "$strXml .= '';\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" + "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 Digest::SHA qw(hmac_sha256 hmac_sha256_hex sha256_hex);\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::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_INTERNAL => 500;\n" + "\n" + "use constant S3_RETRY_MAX => 2;\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) ? sha256_hex($$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 ($iResponseCode == S3_RESPONSE_CODE_ERROR_INTERNAL)\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" + "confess &log(ERROR,\n" + "'S3 request error' . ($iRetryTotal > 0 ? \" after retries\" : '') .\n" + "\" [$iResponseCode] \" . $oHttpClient->responseMessage() .\n" + "\"\\n*** request header ***\\n\" . $oHttpClient->requestHeaderText() .\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 BACKREST_NAME => 'pgBackRest';\n" + "push @EXPORT, qw(BACKREST_NAME);\n" + "use constant BACKREST_EXE => lc(BACKREST_NAME);\n" + "push @EXPORT, qw(BACKREST_EXE);\n" + "use constant BACKREST_CONF => BACKREST_EXE . '.conf';\n" + "push @EXPORT, qw(BACKREST_CONF);\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "my $strBackRestBin;\n" + "\n" + "sub backrestBin {return $strBackRestBin};\n" + "sub backrestBinSet {$strBackRestBin = shift}\n" + "\n" + "push @EXPORT, qw(backrestBin backrestBinSet);\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "use constant BACKREST_VERSION => '2.03dev';\n" + "push @EXPORT, qw(BACKREST_VERSION);\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "use constant BACKREST_FORMAT => 5;\n" + "push @EXPORT, qw(BACKREST_FORMAT);\n" + "\n" + "1;\n" + }, +}; diff --git a/src/perl/exec.c b/src/perl/exec.c index b385d6426..e1ca1fce0 100644 --- a/src/perl/exec.c +++ b/src/perl/exec.c @@ -15,34 +15,28 @@ Execute Perl for Legacy Functionality #include "perl/config.h" #include "perl/exec.h" -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - #define WARNING_PEDANTIC 1 -#endif - -#pragma GCC diagnostic ignored "-Wsign-conversion" - -#if WARNING_PEDANTIC - #pragma GCC diagnostic ignored "-Wpedantic" -#endif +/*********************************************************************************************************************************** +Include LibC code +This file is generated by the LibC xs build. Including it here allows the functions provided by the C library to be provided by the +pgBackRest binary instead which means the C library does not need to be deployed in production builds. +***********************************************************************************************************************************/ #ifndef HAS_BOOL # define HAS_BOOL 1 #endif -#include -#include - -#if WARNING_PEDANTIC - #pragma GCC diagnostic warning "-Wpedantic" -#endif - -#pragma GCC diagnostic warning "-Wsign-conversion" +#include "perl/libc.auto.c" /*********************************************************************************************************************************** -Constants used to build perl options +Include embedded Perl modules ***********************************************************************************************************************************/ -#define PGBACKREST_MODULE PGBACKREST_NAME "::Main" -#define PGBACKREST_MAIN PGBACKREST_MODULE "::main" +typedef struct EmbeddedModule +{ + const char *name; + const char *data; +} EmbeddedModule; + +#include "perl/embed.auto.c" /*********************************************************************************************************************************** Perl interpreter @@ -51,6 +45,12 @@ This is a silly name but Perl prefers it. ***********************************************************************************************************************************/ static PerlInterpreter *my_perl = NULL; +/*********************************************************************************************************************************** +Constants used to build perl options +***********************************************************************************************************************************/ +#define PGBACKREST_MODULE PGBACKREST_NAME "::Main" +#define PGBACKREST_MAIN PGBACKREST_MODULE "::main" + /*********************************************************************************************************************************** Build list of parameters to use for perl main ***********************************************************************************************************************************/ @@ -72,11 +72,64 @@ perlMain() FUNCTION_TEST_RESULT(STRING, mainCall); } +/*********************************************************************************************************************************** +Dynamic module loader +***********************************************************************************************************************************/ +XS_EUPXS(embeddedModuleGet); +XS_EUPXS(embeddedModuleGet) +{ + // Ensure all parameters were passed + dVAR; dXSARGS; + + if (items != 1) // {uncovered - no invalid calls} + croak_xs_usage(cv, "moduleName"); // {+uncovered} + + // Get module name + const char *moduleName = (const char *)SvPV_nolen(ST(0)); + dXSTARG; // {uncovered - internal Perl macro branch} + + // Find module + const char *result = NULL; + + for (unsigned int moduleIdx = 0; // {uncovered - no invalid modules in embedded Perl} + moduleIdx < sizeof(embeddedModule) / sizeof(EmbeddedModule); moduleIdx++) + { + if (strcmp(embeddedModule[moduleIdx].name, moduleName) == 0) + { + result = embeddedModule[moduleIdx].data; + break; + } + } + + // Error if the module was not found + if (result == NULL) // {uncovered - no invalid modules in embedded Perl} + croak("unable to load embedded module '%s'", moduleName); // {+uncovered} + + // Return module data + sv_setpv(TARG, result); + XSprePUSH; + PUSHTARG; // {uncovered - internal Perl macro branch} + + XSRETURN(1); +} + /*********************************************************************************************************************************** Init the dynaloader so other C modules can be loaded There are no FUNCTION_TEST* calls because this is a callback from Perl and it doesn't seem wise to mix our stack stuff up in it. ***********************************************************************************************************************************/ +#define LOADER_SUB \ + "sub\n" \ + "{\n" \ + " if ($_[1] =~ /^pgBackRest/)\n" \ + " {\n" \ + " my $data = pgBackRest::LibC::embeddedModuleGet($_[1]);\n" \ + "\n" \ + " open my $fh, '<', \\$data;\n" \ + " return $fh;\n" \ + " }\n" \ + "}" + EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); static void xs_init(pTHX) @@ -84,7 +137,14 @@ static void xs_init(pTHX) dXSUB_SYS; PERL_UNUSED_CONTEXT; - /* DynaLoader is a special case */ + // Register the LibC functions by registering the boot function and calling it + newXS("pgBackRest::LibC::boot", boot_pgBackRest__LibC, __FILE__); + eval_pv("pgBackRest::LibC::boot()", TRUE); + + // Register the embedded module getter + newXS("pgBackRest::LibC::embeddedModuleGet", embeddedModuleGet, __FILE__); + + // DynaLoader is a special case newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__); } @@ -120,7 +180,7 @@ perlInit() PERL_SYS_INIT3(&argc, (char ***)&argv, (char ***)&env); // Create the interpreter - const char *embedding[] = {"", "-M"PGBACKREST_MODULE, "-e", "0"}; + const char *embedding[] = {"", "-e", "0"}; my_perl = perl_alloc(); perl_construct(my_perl); @@ -132,6 +192,12 @@ perlInit() PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl); + // Use customer loader to get all embedded modules + eval_pv("splice(@INC, 0, 0, " LOADER_SUB ");", true); + + // Now that the custom loader is installed, load the main module; + eval_pv("use " PGBACKREST_MODULE ";", true); + // Set config data -- this is done separately to avoid it being included in stack traces perlEval(strNewFmt(PGBACKREST_MAIN "ConfigSet('%s', '%s')", strPtr(cfgExe()), strPtr(perlOptionJson()))); } diff --git a/src/perl/libc.auto.c b/src/perl/libc.auto.c new file mode 100644 index 000000000..a0979b210 --- /dev/null +++ b/src/perl/libc.auto.c @@ -0,0 +1,1080 @@ +/* + * This file was generated automatically by ExtUtils::ParseXS version 3.28 from the + * contents of LibC.xs. Do not edit this file, edit LibC.xs instead. + * + * ANY CHANGES MADE HERE WILL BE LOST! + * + */ + +/*********************************************************************************************************************************** +C to Perl Interface + +The following C types are mapped by the current typemap: + +'AV *', 'Boolean', 'CV *', 'FILE *', 'FileHandle', 'HV *', 'I16', 'I32', 'I8', 'IV', 'InOutStream', 'InputStream', 'NV', +'OutputStream', 'PerlIO *', 'Result', 'STRLEN', 'SV *', 'SVREF', 'SysRet', 'SysRetLong', 'Time_t *', 'U16', 'U32', 'U8', 'UV', +'bool', 'bool_t', 'caddr_t', 'char', 'char *', 'char **', 'const char *', 'double', 'float', 'int', 'long', 'short', 'size_t', +'ssize_t', 'time_t', 'unsigned', 'unsigned char', 'unsigned char *', 'unsigned int', 'unsigned long', 'unsigned long *', +'unsigned short', 'void *', 'wchar_t', 'wchar_t *' +***********************************************************************************************************************************/ +#define PERL_NO_GET_CONTEXT + +/*********************************************************************************************************************************** +Perl includes + +Order is critical here so don't change it. +***********************************************************************************************************************************/ +#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 8 || (__GNUC_MINOR__ == 8 && __GNUC_PATCHLEVEL__ >= 0))) + #define WARNING_MAYBE_INITIALIZED 1 +#elif __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ >= 0))) + #define WARNING_INITIALIZED 1 +#endif + +#if WARNING_MAYBE_INITIALIZED + #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#elif WARNING_INITIALIZED + #pragma GCC diagnostic ignored "-Wuninitialized" +#endif + +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wconversion" + +#include +#include +#include + +#if WARNING_MAYBE_INITIALIZED + #pragma GCC diagnostic warning "-Wmaybe-uninitialized" +#elif WARNING_INITIALIZED + #pragma GCC diagnostic warning "-Wuninitialized" +#endif + +/*********************************************************************************************************************************** +C includes + +These includes are from the src directory. There is no Perl-specific code in them. +***********************************************************************************************************************************/ +#include "cipher/random.h" +#include "common/error.h" +#include "common/lock.h" +#include "config/config.h" +#include "config/define.h" +#include "config/load.h" +#include "config/parse.h" +#include "perl/config.h" +#include "postgres/pageChecksum.h" +#include "storage/driver/posix/driver.h" + +/*********************************************************************************************************************************** +Helper macros +***********************************************************************************************************************************/ +#include "LibC.h" + +/*********************************************************************************************************************************** +XSH includes + +These includes define data structures that are required for the C to Perl interface but are not part of the regular C source. +***********************************************************************************************************************************/ +#include "xs/cipher/block.xsh" +#include "xs/common/encode.xsh" + +/*********************************************************************************************************************************** +Module definition +***********************************************************************************************************************************/ +#ifndef PERL_UNUSED_VAR +# define PERL_UNUSED_VAR(var) if (0) var = var +#endif + +#ifndef dVAR +# define dVAR dNOOP +#endif + + +/* This stuff is not part of the API! You have been warned. */ +#ifndef PERL_VERSION_DECIMAL +# define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s) +#endif +#ifndef PERL_DECIMAL_VERSION +# define PERL_DECIMAL_VERSION \ + PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION) +#endif +#ifndef PERL_VERSION_GE +# define PERL_VERSION_GE(r,v,s) \ + (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s)) +#endif +#ifndef PERL_VERSION_LE +# define PERL_VERSION_LE(r,v,s) \ + (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s)) +#endif + +/* XS_INTERNAL is the explicit static-linkage variant of the default + * XS macro. + * + * XS_EXTERNAL is the same as XS_INTERNAL except it does not include + * "STATIC", ie. it exports XSUB symbols. You probably don't want that + * for anything but the BOOT XSUB. + * + * See XSUB.h in core! + */ + + +/* TODO: This might be compatible further back than 5.10.0. */ +#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1) +# undef XS_EXTERNAL +# undef XS_INTERNAL +# if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING) +# define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name) +# define XS_INTERNAL(name) STATIC XSPROTO(name) +# endif +# if defined(__SYMBIAN32__) +# define XS_EXTERNAL(name) EXPORT_C XSPROTO(name) +# define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name) +# endif +# ifndef XS_EXTERNAL +# if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus) +# define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__) +# define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__) +# else +# ifdef __cplusplus +# define XS_EXTERNAL(name) extern "C" XSPROTO(name) +# define XS_INTERNAL(name) static XSPROTO(name) +# else +# define XS_EXTERNAL(name) XSPROTO(name) +# define XS_INTERNAL(name) STATIC XSPROTO(name) +# endif +# endif +# endif +#endif + +/* perl >= 5.10.0 && perl <= 5.15.1 */ + + +/* The XS_EXTERNAL macro is used for functions that must not be static + * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL + * macro defined, the best we can do is assume XS is the same. + * Dito for XS_INTERNAL. + */ +#ifndef XS_EXTERNAL +# define XS_EXTERNAL(name) XS(name) +#endif +#ifndef XS_INTERNAL +# define XS_INTERNAL(name) XS(name) +#endif + +/* Now, finally, after all this mess, we want an ExtUtils::ParseXS + * internal macro that we're free to redefine for varying linkage due + * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use + * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to! + */ + +#undef XS_EUPXS +#if defined(PERL_EUPXS_ALWAYS_EXPORT) +# define XS_EUPXS(name) XS_EXTERNAL(name) +#else + /* default to internal */ +# define XS_EUPXS(name) XS_INTERNAL(name) +#endif + +#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE +#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params) + +/* prototype to pass -Wmissing-prototypes */ +STATIC void +S_croak_xs_usage(const CV *const cv, const char *const params); + +STATIC void +S_croak_xs_usage(const CV *const cv, const char *const params) +{ + const GV *const gv = CvGV(cv); + + PERL_ARGS_ASSERT_CROAK_XS_USAGE; + + if (gv) { + const char *const gvname = GvNAME(gv); + const HV *const stash = GvSTASH(gv); + const char *const hvname = stash ? HvNAME(stash) : NULL; + + if (hvname) + Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params); + else + Perl_croak_nocontext("Usage: %s(%s)", gvname, params); + } else { + /* Pants. I don't think that it should be possible to get here. */ + Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params); + } +} +#undef PERL_ARGS_ASSERT_CROAK_XS_USAGE + +#define croak_xs_usage S_croak_xs_usage + +#endif + +/* NOTE: the prototype of newXSproto() is different in versions of perls, + * so we define a portable version of newXSproto() + */ +#ifdef newXS_flags +#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0) +#else +#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv) +#endif /* !defined(newXS_flags) */ + +#if PERL_VERSION_LE(5, 21, 5) +# define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file) +#else +# define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b) +#endif + + +XS_EUPXS(XS_pgBackRest__LibC_libcUvSize); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_libcUvSize) +{ + dVAR; dXSARGS; + if (items != 0) + croak_xs_usage(cv, ""); + { + I32 RETVAL; + dXSTARG; + RETVAL = UVSIZE; + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + + +/* INCLUDE: Including 'xs/cipher/block.xs' from 'LibC.xs' */ + + +/* INCLUDE: Including 'xs/cipher/random.xs' from 'xs/cipher/block.xs' */ + + +/* INCLUDE: Including 'xs/common/encode.xs' from 'xs/cipher/random.xs' */ + + +/* INCLUDE: Including 'xs/common/lock.xs' from 'xs/common/encode.xs' */ + + +/* INCLUDE: Including 'xs/config/config.xs' from 'xs/common/lock.xs' */ + + +/* INCLUDE: Including 'xs/config/configTest.xs' from 'xs/config/config.xs' */ + + +/* INCLUDE: Including 'xs/config/define.xs' from 'xs/config/configTest.xs' */ + + +/* INCLUDE: Including 'xs/postgres/pageChecksum.xs' from 'xs/config/define.xs' */ + + +/* INCLUDE: Including 'xs/storage/storage.xs' from 'xs/postgres/pageChecksum.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC_storageDriverPosixPathRemove); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_storageDriverPosixPathRemove) +{ + dVAR; dXSARGS; + if (items != 3) + croak_xs_usage(cv, "path, errorOnMissing, recurse"); + { + const char * path = (const char *)SvPV_nolen(ST(0)) +; + bool errorOnMissing = (bool)SvTRUE(ST(1)) +; + bool recurse = (bool)SvTRUE(ST(2)) +; + MEM_CONTEXT_XS_TEMP_BEGIN() + { + storageDriverPosixPathRemove(strNew(path), errorOnMissing, recurse); + } + MEM_CONTEXT_XS_TEMP_END(); + } + XSRETURN_EMPTY; +} + + +/* INCLUDE: Returning to 'xs/postgres/pageChecksum.xs' from 'xs/storage/storage.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC_pageChecksum); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_pageChecksum) +{ + dVAR; dXSARGS; + if (items != 3) + croak_xs_usage(cv, "page, blockNo, pageSize"); + { + const char * page = (const char *)SvPV_nolen(ST(0)) +; + U32 blockNo = (unsigned long)SvUV(ST(1)) +; + U32 pageSize = (unsigned long)SvUV(ST(2)) +; + U16 RETVAL; + dXSTARG; + RETVAL = 0; + + ERROR_XS_BEGIN() + { + RETVAL = pageChecksum( + (const unsigned char *)page, blockNo, pageSize); + } + ERROR_XS_END(); + XSprePUSH; PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_pageChecksumTest); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_pageChecksumTest) +{ + dVAR; dXSARGS; + if (items != 5) + croak_xs_usage(cv, "page, blockNo, pageSize, ignoreWalId, ignoreWalOffset"); + { + const char * page = (const char *)SvPV_nolen(ST(0)) +; + U32 blockNo = (unsigned long)SvUV(ST(1)) +; + U32 pageSize = (unsigned long)SvUV(ST(2)) +; + U32 ignoreWalId = (unsigned long)SvUV(ST(3)) +; + U32 ignoreWalOffset = (unsigned long)SvUV(ST(4)) +; + bool RETVAL; + RETVAL = false; + + ERROR_XS_BEGIN() + { + RETVAL = pageChecksumTest( + (const unsigned char *)page, blockNo, pageSize, ignoreWalId, ignoreWalOffset); + } + ERROR_XS_END(); + ST(0) = boolSV(RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_pageChecksumBufferTest); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_pageChecksumBufferTest) +{ + dVAR; dXSARGS; + if (items != 6) + croak_xs_usage(cv, "pageBuffer, pageBufferSize, blockNoBegin, pageSize, ignoreWalId, ignoreWalOffset"); + { + const char * pageBuffer = (const char *)SvPV_nolen(ST(0)) +; + U32 pageBufferSize = (unsigned long)SvUV(ST(1)) +; + U32 blockNoBegin = (unsigned long)SvUV(ST(2)) +; + U32 pageSize = (unsigned long)SvUV(ST(3)) +; + U32 ignoreWalId = (unsigned long)SvUV(ST(4)) +; + U32 ignoreWalOffset = (unsigned long)SvUV(ST(5)) +; + bool RETVAL; + RETVAL = false; + + ERROR_XS_BEGIN() + { + RETVAL = pageChecksumBufferTest( + (const unsigned char *)pageBuffer, pageBufferSize, blockNoBegin, pageSize, ignoreWalId, ignoreWalOffset); + } + ERROR_XS_END(); + ST(0) = boolSV(RETVAL); + } + XSRETURN(1); +} + + +/* INCLUDE: Returning to 'xs/config/define.xs' from 'xs/postgres/pageChecksum.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC_cfgCommandId); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgCommandId) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "commandName"); + { + const char * commandName = (const char *)SvPV_nolen(ST(0)) +; + I32 RETVAL; + dXSTARG; + RETVAL = 0; + + ERROR_XS_BEGIN() + { + RETVAL = cfgCommandId(commandName); + } + ERROR_XS_END(); + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionId); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionId) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "optionName"); + { + const char * optionName = (const char *)SvPV_nolen(ST(0)) +; + I32 RETVAL; + dXSTARG; + RETVAL = 0; + + ERROR_XS_BEGIN() + { + RETVAL = cfgOptionId(optionName); + } + ERROR_XS_END(); + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionDefault); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionDefault) +{ + dVAR; dXSARGS; + if (items != 2) + croak_xs_usage(cv, "commandId, optionId"); + { + U32 commandId = (unsigned long)SvUV(ST(0)) +; + U32 optionId = (unsigned long)SvUV(ST(1)) +; + const char * RETVAL; + dXSTARG; + RETVAL = NULL; + + ERROR_XS_BEGIN() + { + RETVAL = cfgDefOptionDefault(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId)); + } + ERROR_XS_END(); + sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionPrefix); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionPrefix) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "optionId"); + { + U32 optionId = (unsigned long)SvUV(ST(0)) +; + const char * RETVAL; + dXSTARG; + RETVAL = NULL; + + ERROR_XS_BEGIN() + { + RETVAL = cfgDefOptionPrefix(cfgOptionDefIdFromId(optionId)); + } + ERROR_XS_END(); + sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionSecure); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionSecure) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "optionId"); + { + U32 optionId = (unsigned long)SvUV(ST(0)) +; + bool RETVAL; + RETVAL = false; + + ERROR_XS_BEGIN() + { + RETVAL = cfgDefOptionSecure(cfgOptionDefIdFromId(optionId)); + } + ERROR_XS_END(); + ST(0) = boolSV(RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionType); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionType) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "optionId"); + { + U32 optionId = (unsigned long)SvUV(ST(0)) +; + I32 RETVAL; + dXSTARG; + RETVAL = 0; + + ERROR_XS_BEGIN() + { + RETVAL = cfgDefOptionType(cfgOptionDefIdFromId(optionId)); + } + ERROR_XS_END(); + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionValid); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgDefOptionValid) +{ + dVAR; dXSARGS; + if (items != 2) + croak_xs_usage(cv, "commandId, optionId"); + { + U32 commandId = (unsigned long)SvUV(ST(0)) +; + U32 optionId = (unsigned long)SvUV(ST(1)) +; + bool RETVAL; + RETVAL = false; + + ERROR_XS_BEGIN() + { + RETVAL = cfgDefOptionValid(cfgCommandDefIdFromId(commandId), cfgOptionDefIdFromId(optionId)); + } + ERROR_XS_END(); + ST(0) = boolSV(RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionTotal); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionTotal) +{ + dVAR; dXSARGS; + if (items != 0) + croak_xs_usage(cv, ""); + { + U32 RETVAL; + dXSTARG; + RETVAL = CFG_OPTION_TOTAL; + XSprePUSH; PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + + +/* INCLUDE: Returning to 'xs/config/configTest.xs' from 'xs/config/define.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC_cfgParseTest); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgParseTest) +{ + dVAR; dXSARGS; + if (items != 2) + croak_xs_usage(cv, "backrestBin, parseParam"); + { + const char * backrestBin = (const char *)SvPV_nolen(ST(0)) +; + const char * parseParam = (const char *)SvPV_nolen(ST(1)) +; + SV * RETVAL; + RETVAL = NULL; + + ERROR_XS_BEGIN() + { + // This should run in a temp context but for some reason getopt_long gets upset when if gets called again after the previous + // arg list being freed. So, this is a memory leak but it is only used for testing, not production. + StringList *paramList = strLstNewSplitZ(strCat(strNew("pgbackrest|"), parseParam), "|"); + + // Don't use cfgLoad() because it has a lot of side effects that we don't want + configParse(strLstSize(paramList), strLstPtr(paramList)); + cfgExeSet(strNew(backrestBin)); + cfgLoadUpdateOption(); + + String *result = perlOptionJson(); + + RETVAL = newSV(strSize(result)); + SvPOK_only(RETVAL); + + strcpy(SvPV_nolen(RETVAL), strPtr(result)); + SvCUR_set(RETVAL, strSize(result)); + } + ERROR_XS_END() + RETVAL = sv_2mortal(RETVAL); + ST(0) = RETVAL; + } + XSRETURN(1); +} + + +/* INCLUDE: Returning to 'xs/config/config.xs' from 'xs/config/configTest.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC_cfgCommandName); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgCommandName) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "commandId"); + { + U32 commandId = (unsigned long)SvUV(ST(0)) +; + const char * RETVAL; + dXSTARG; + + RETVAL = cfgCommandName(commandId); + sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionIndex); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionIndex) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "optionId"); + { + U32 optionId = (unsigned long)SvUV(ST(0)) +; + I32 RETVAL; + dXSTARG; + + RETVAL = cfgOptionIndex(optionId); + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionIndexTotal); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionIndexTotal) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "optionId"); + { + U32 optionId = (unsigned long)SvUV(ST(0)) +; + I32 RETVAL; + dXSTARG; + + RETVAL = cfgOptionIndexTotal(optionId); + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionName); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_cfgOptionName) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "optionId"); + { + U32 optionId = (unsigned long)SvUV(ST(0)) +; + const char * RETVAL; + dXSTARG; + + RETVAL = cfgOptionName(optionId); + sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; + } + XSRETURN(1); +} + + +/* INCLUDE: Returning to 'xs/common/lock.xs' from 'xs/config/config.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC_lockAcquire); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_lockAcquire) +{ + dVAR; dXSARGS; + if (items != 5) + croak_xs_usage(cv, "lockPath, command, stanza, lockTimeout, failOnNoLock"); + { + const char * lockPath = (const char *)SvPV_nolen(ST(0)) +; + const char * command = (const char *)SvPV_nolen(ST(1)) +; + const char * stanza = (const char *)SvPV_nolen(ST(2)) +; + double lockTimeout = (double)SvNV(ST(3)) +; + bool failOnNoLock = (bool)SvTRUE(ST(4)) +; + bool RETVAL; + RETVAL = false; + + MEM_CONTEXT_XS_TEMP_BEGIN() + { + // Set the command so we can get the correct lock type to use + cfgCommandSet(cfgCommandId(command)); + + // Attempt to acquire the lock + if (cfgLockRequired()) + RETVAL = lockAcquire(strNew(lockPath), strNew(stanza), cfgLockType(), lockTimeout, failOnNoLock); + } + MEM_CONTEXT_XS_TEMP_END(); + ST(0) = boolSV(RETVAL); + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_lockRelease); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_lockRelease) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "failOnNoLock"); + { + bool failOnNoLock = (bool)SvTRUE(ST(0)) +; + bool RETVAL; + RETVAL = false; + + MEM_CONTEXT_XS_TEMP_BEGIN() + { + RETVAL = lockRelease(failOnNoLock); + } + MEM_CONTEXT_XS_TEMP_END(); + ST(0) = boolSV(RETVAL); + } + XSRETURN(1); +} + + +/* INCLUDE: Returning to 'xs/common/encode.xs' from 'xs/common/lock.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC_encodeToStr); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_encodeToStr) +{ + dVAR; dXSARGS; + if (items != 2) + croak_xs_usage(cv, "encodeType, source"); + { + int encodeType = (int)SvIV(ST(0)) +; + SV * source = ST(1) +; + SV * RETVAL; + RETVAL = NULL; + + STRLEN sourceSize; + unsigned char *sourcePtr = (unsigned char *)SvPV(source, sourceSize); + + ERROR_XS_BEGIN() + { + RETVAL = newSV(encodeToStrSize(encodeType, sourceSize)); + SvPOK_only(RETVAL); + + encodeToStr(encodeType, sourcePtr, sourceSize, (char *)SvPV_nolen(RETVAL)); + SvCUR_set(RETVAL, encodeToStrSize(encodeType, sourceSize)); + } + ERROR_XS_END(); + RETVAL = sv_2mortal(RETVAL); + ST(0) = RETVAL; + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC_decodeToBin); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_decodeToBin) +{ + dVAR; dXSARGS; + if (items != 2) + croak_xs_usage(cv, "encodeType, source"); + { + int encodeType = (int)SvIV(ST(0)) +; + const char * source = (const char *)SvPV_nolen(ST(1)) +; + SV * RETVAL; + RETVAL = NULL; + + ERROR_XS_BEGIN() + { + RETVAL = newSV(decodeToBinSize(encodeType, source)); + SvPOK_only(RETVAL); + + decodeToBin(encodeType, source, (unsigned char *)SvPV_nolen(RETVAL)); + SvCUR_set(RETVAL, decodeToBinSize(encodeType, source)); + } + ERROR_XS_END(); + RETVAL = sv_2mortal(RETVAL); + ST(0) = RETVAL; + } + XSRETURN(1); +} + + +/* INCLUDE: Returning to 'xs/cipher/random.xs' from 'xs/common/encode.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC_randomBytes); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC_randomBytes) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "size"); + { + I32 size = (I32)SvIV(ST(0)) +; + SV * RETVAL; + RETVAL = newSV(size); + SvPOK_only(RETVAL); + + randomBytes((unsigned char *)SvPV_nolen(RETVAL), size); + + SvCUR_set(RETVAL, size); + RETVAL = sv_2mortal(RETVAL); + ST(0) = RETVAL; + } + XSRETURN(1); +} + + +/* INCLUDE: Returning to 'xs/cipher/block.xs' from 'xs/cipher/random.xs' */ + + +XS_EUPXS(XS_pgBackRest__LibC__Cipher__Block_new); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC__Cipher__Block_new) +{ + dVAR; dXSARGS; + if (items < 5 || items > 6) + croak_xs_usage(cv, "class, mode, type, key, keySize, digest = NULL"); + { + const char * class = (const char *)SvPV_nolen(ST(0)) +; + U32 mode = (unsigned long)SvUV(ST(1)) +; + const char * type = (const char *)SvPV_nolen(ST(2)) +; + unsigned char * key = (unsigned char *)SvPV_nolen(ST(3)) +; + I32 keySize = (I32)SvIV(ST(4)) +; + const char * digest; + pgBackRest__LibC__Cipher__Block RETVAL; + + if (items < 6) + digest = NULL; + else { + digest = (const char *)SvPV_nolen(ST(5)) +; + } + RETVAL = NULL; + + // Not much point to this but it keeps the var from being unused + if (strcmp(class, PACKAGE_NAME_LIBC "::Cipher::Block") != 0) + croak("unexpected class name '%s'", class); + + MEM_CONTEXT_XS_NEW_BEGIN("cipherBlockXs") + { + RETVAL = memNew(sizeof(CipherBlockXs)); + + RETVAL->memContext = MEM_COMTEXT_XS(); + + RETVAL->pxPayload = cipherBlockNew(mode, type, key, keySize, digest); + } + MEM_CONTEXT_XS_NEW_END(); + { + SV * RETVALSV; + RETVALSV = sv_newmortal(); + sv_setref_pv(RETVALSV, "pgBackRest::LibC::Cipher::Block", (void*)RETVAL); + ST(0) = RETVALSV; + } + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC__Cipher__Block_process); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC__Cipher__Block_process) +{ + dVAR; dXSARGS; + if (items != 2) + croak_xs_usage(cv, "self, source"); + { + pgBackRest__LibC__Cipher__Block self; + SV * source = ST(1) +; + SV * RETVAL; + + if (SvROK(ST(0)) && sv_derived_from(ST(0), "pgBackRest::LibC::Cipher::Block")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + self = INT2PTR(pgBackRest__LibC__Cipher__Block,tmp); + } + else + Perl_croak_nocontext("%s: %s is not of type %s", + "pgBackRest::LibC::Cipher::Block::process", + "self", "pgBackRest::LibC::Cipher::Block") +; + RETVAL = NULL; + + MEM_CONTEXT_XS_BEGIN(self->memContext) + { + STRLEN tSize; + const unsigned char *sourcePtr = (const unsigned char *)SvPV(source, tSize); + + RETVAL = NEWSV(0, cipherBlockProcessSize(self->pxPayload, tSize)); + SvPOK_only(RETVAL); + + SvCUR_set(RETVAL, cipherBlockProcess(self->pxPayload, sourcePtr, tSize, (unsigned char *)SvPV_nolen(RETVAL))); + } + MEM_CONTEXT_XS_END(); + RETVAL = sv_2mortal(RETVAL); + ST(0) = RETVAL; + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC__Cipher__Block_flush); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC__Cipher__Block_flush) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "self"); + { + pgBackRest__LibC__Cipher__Block self; + SV * RETVAL; + + if (SvROK(ST(0)) && sv_derived_from(ST(0), "pgBackRest::LibC::Cipher::Block")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + self = INT2PTR(pgBackRest__LibC__Cipher__Block,tmp); + } + else + Perl_croak_nocontext("%s: %s is not of type %s", + "pgBackRest::LibC::Cipher::Block::flush", + "self", "pgBackRest::LibC::Cipher::Block") +; + RETVAL = NULL; + + MEM_CONTEXT_XS_BEGIN(self->memContext) + { + RETVAL = NEWSV(0, cipherBlockProcessSize(self->pxPayload, 0)); + SvPOK_only(RETVAL); + + SvCUR_set(RETVAL, cipherBlockFlush(self->pxPayload, (unsigned char *)SvPV_nolen(RETVAL))); + } + MEM_CONTEXT_XS_END(); + RETVAL = sv_2mortal(RETVAL); + ST(0) = RETVAL; + } + XSRETURN(1); +} + + +XS_EUPXS(XS_pgBackRest__LibC__Cipher__Block_DESTROY); /* prototype to pass -Wmissing-prototypes */ +XS_EUPXS(XS_pgBackRest__LibC__Cipher__Block_DESTROY) +{ + dVAR; dXSARGS; + if (items != 1) + croak_xs_usage(cv, "self"); + { + pgBackRest__LibC__Cipher__Block self; + + if (SvROK(ST(0))) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + self = INT2PTR(pgBackRest__LibC__Cipher__Block,tmp); + } + else + Perl_croak_nocontext("%s: %s is not a reference", + "pgBackRest::LibC::Cipher::Block::DESTROY", + "self") +; + MEM_CONTEXT_XS_DESTROY(self->memContext); + } + XSRETURN_EMPTY; +} + + +/* INCLUDE: Returning to 'LibC.xs' from 'xs/cipher/block.xs' */ + +#ifdef __cplusplus +extern "C" +#endif +XS_EXTERNAL(boot_pgBackRest__LibC); /* prototype to pass -Wmissing-prototypes */ +XS_EXTERNAL(boot_pgBackRest__LibC) +{ +#if PERL_VERSION_LE(5, 21, 5) + dVAR; dXSARGS; +#else + dVAR; dXSBOOTARGSXSAPIVERCHK; +#endif +#if (PERL_REVISION == 5 && PERL_VERSION < 9) + char* file = __FILE__; +#else + const char* file = __FILE__; +#endif + + PERL_UNUSED_VAR(file); + + PERL_UNUSED_VAR(cv); /* -W */ + PERL_UNUSED_VAR(items); /* -W */ +#if PERL_VERSION_LE(5, 21, 5) + XS_VERSION_BOOTCHECK; +# ifdef XS_APIVERSION_BOOTCHECK + XS_APIVERSION_BOOTCHECK; +# endif +#endif + + newXS_deffile("pgBackRest::LibC::libcUvSize", XS_pgBackRest__LibC_libcUvSize); + newXS_deffile("pgBackRest::LibC::storageDriverPosixPathRemove", XS_pgBackRest__LibC_storageDriverPosixPathRemove); + newXS_deffile("pgBackRest::LibC::pageChecksum", XS_pgBackRest__LibC_pageChecksum); + newXS_deffile("pgBackRest::LibC::pageChecksumTest", XS_pgBackRest__LibC_pageChecksumTest); + newXS_deffile("pgBackRest::LibC::pageChecksumBufferTest", XS_pgBackRest__LibC_pageChecksumBufferTest); + newXS_deffile("pgBackRest::LibC::cfgCommandId", XS_pgBackRest__LibC_cfgCommandId); + newXS_deffile("pgBackRest::LibC::cfgOptionId", XS_pgBackRest__LibC_cfgOptionId); + newXS_deffile("pgBackRest::LibC::cfgDefOptionDefault", XS_pgBackRest__LibC_cfgDefOptionDefault); + newXS_deffile("pgBackRest::LibC::cfgDefOptionPrefix", XS_pgBackRest__LibC_cfgDefOptionPrefix); + newXS_deffile("pgBackRest::LibC::cfgDefOptionSecure", XS_pgBackRest__LibC_cfgDefOptionSecure); + newXS_deffile("pgBackRest::LibC::cfgDefOptionType", XS_pgBackRest__LibC_cfgDefOptionType); + newXS_deffile("pgBackRest::LibC::cfgDefOptionValid", XS_pgBackRest__LibC_cfgDefOptionValid); + newXS_deffile("pgBackRest::LibC::cfgOptionTotal", XS_pgBackRest__LibC_cfgOptionTotal); + newXS_deffile("pgBackRest::LibC::cfgParseTest", XS_pgBackRest__LibC_cfgParseTest); + newXS_deffile("pgBackRest::LibC::cfgCommandName", XS_pgBackRest__LibC_cfgCommandName); + newXS_deffile("pgBackRest::LibC::cfgOptionIndex", XS_pgBackRest__LibC_cfgOptionIndex); + newXS_deffile("pgBackRest::LibC::cfgOptionIndexTotal", XS_pgBackRest__LibC_cfgOptionIndexTotal); + newXS_deffile("pgBackRest::LibC::cfgOptionName", XS_pgBackRest__LibC_cfgOptionName); + newXS_deffile("pgBackRest::LibC::lockAcquire", XS_pgBackRest__LibC_lockAcquire); + newXS_deffile("pgBackRest::LibC::lockRelease", XS_pgBackRest__LibC_lockRelease); + newXS_deffile("pgBackRest::LibC::encodeToStr", XS_pgBackRest__LibC_encodeToStr); + newXS_deffile("pgBackRest::LibC::decodeToBin", XS_pgBackRest__LibC_decodeToBin); + newXS_deffile("pgBackRest::LibC::randomBytes", XS_pgBackRest__LibC_randomBytes); + newXS_deffile("pgBackRest::LibC::Cipher::Block::new", XS_pgBackRest__LibC__Cipher__Block_new); + newXS_deffile("pgBackRest::LibC::Cipher::Block::process", XS_pgBackRest__LibC__Cipher__Block_process); + newXS_deffile("pgBackRest::LibC::Cipher::Block::flush", XS_pgBackRest__LibC__Cipher__Block_flush); + newXS_deffile("pgBackRest::LibC::Cipher::Block::DESTROY", XS_pgBackRest__LibC__Cipher__Block_DESTROY); +#if PERL_VERSION_LE(5, 21, 5) +# if PERL_VERSION_GE(5, 9, 0) + if (PL_unitcheckav) + call_list(PL_scopestack_ix, PL_unitcheckav); +# endif + XSRETURN_YES; +#else + Perl_xs_boot_epilog(aTHX_ ax); +#endif +} diff --git a/test/lib/pgBackRestTest/Common/DefineTest.pm b/test/lib/pgBackRestTest/Common/DefineTest.pm index d377fdc1d..b97447203 100644 --- a/test/lib/pgBackRestTest/Common/DefineTest.pm +++ b/test/lib/pgBackRestTest/Common/DefineTest.pm @@ -134,6 +134,7 @@ sub testDefLoad # Set module type variables $hTestDefHash->{$strModule}{$strTest}{&TESTDEF_C} = $strModuleType eq TESTDEF_UNIT && $strTest !~ /\-perl$/ ? true : false; + $hTestDefHash->{$strModule}{$strTest}{&TESTDEF_INTEGRATION} = $strModuleType eq TESTDEF_INTEGRATION ? true : false; $hTestDefHash->{$strModule}{$strTest}{&TESTDEF_EXPECT} = $bExpect; $hTestDefHash->{$strModule}{$strTest}{&TESTDEF_CONTAINER} = $bContainer; $hTestDefHash->{$strModule}{$strTest}{&TESTDEF_INDIVIDUAL} = $bIndividual; diff --git a/test/lib/pgBackRestTest/Common/JobTest.pm b/test/lib/pgBackRestTest/Common/JobTest.pm index 1b46b92c9..0bf7514dc 100644 --- a/test/lib/pgBackRestTest/Common/JobTest.pm +++ b/test/lib/pgBackRestTest/Common/JobTest.pm @@ -200,6 +200,8 @@ sub run if (!$bGCovExists || $bFlagsChanged) { executeTest("rsync -rt --delete $self->{strBackRestBase}/src/ $self->{strGCovPath}"); + executeTest("rsync -t $self->{strBackRestBase}/libc/LibC.h $self->{strGCovPath}"); + executeTest("rsync -rt $self->{strBackRestBase}/libc/xs/ $self->{strGCovPath}/xs"); executeTest("rsync -rt $self->{strBackRestBase}/test/src/ $self->{strGCovPath}"); } @@ -209,7 +211,9 @@ sub run # If testing Perl code (or C code that calls Perl code) install bin and Perl C Library if (!$self->{oTest}->{&TEST_C} || $self->{oTest}->{&TEST_PERL_REQ}) { - jobInstallC($self->{strBackRestBase}, $self->{oTest}->{&TEST_VM}, $strImage); + jobInstallC( + $self->{strBackRestBase}, $self->{oTest}->{&TEST_VM}, $strImage, + !$self->{oTest}->{&TEST_C} && !$self->{oTest}->{&TEST_INTEGRATION}); } } } @@ -357,8 +361,9 @@ sub run # This warning appears to be broken on U12 even though the functionality is fine ($self->{oTest}->{&TEST_VM} eq VM_U12 || $self->{oTest}->{&TEST_VM} eq VM_CO6 ? " -Wno-missing-field-initializers \\\n" : '') . - ($self->{oTest}->{&TEST_VM} ne VM_CO6 && $self->{oTest}->{&TEST_VM} ne VM_U12 ? - " -Wpedantic \\\n" : '') . + # ($self->{oTest}->{&TEST_VM} ne VM_CO6 && $self->{oTest}->{&TEST_VM} ne VM_U12 && + # $self->{oTest}->{&TEST_MODULE} ne 'perl' && $self->{oTest}->{&TEST_NAME} ne 'exec' ? + # " -Wpedantic \\\n" : '') . " -Wformat=2 -Wformat-nonliteral \\\n" . " `perl -MExtUtils::Embed -e ccopts`\n" . "LDFLAGS=-lcrypto" . (vmCoverage($self->{oTest}->{&TEST_VM}) && $self->{bCoverageUnit} ? " -lgcov" : '') . @@ -616,6 +621,7 @@ sub jobInstallC my $strBasePath = shift; my $strVm = shift; my $strImage = shift; + my $bCopyLibC = shift; # Install Perl C Library my $oVm = vmGet(); @@ -623,20 +629,14 @@ sub jobInstallC my $strBuildLibCPath = "$strBuildPath/libc/${strVm}/libc"; my $strBuildBinPath = "$strBuildPath/bin/${strVm}/src"; my $strPerlAutoPath = $oVm->{$strVm}{&VMDEF_PERL_ARCH_PATH} . '/auto/pgBackRest/LibC'; - my $strPerlModulePath = $oVm->{$strVm}{&VMDEF_PERL_ARCH_PATH} . '/pgBackRest'; executeTest( "docker exec -i -u root ${strImage} bash -c '" . - "mkdir -p -m 755 ${strPerlAutoPath} && " . - # "cp ${strBuildLibCPath}/blib/arch/auto/pgBackRest/LibC/LibC.bs ${strPerlAutoPath} && " . - "cp ${strBuildLibCPath}/blib/arch/auto/pgBackRest/LibC/LibC.so ${strPerlAutoPath} && " . - "cp ${strBuildLibCPath}/blib/lib/auto/pgBackRest/LibC/autosplit.ix ${strPerlAutoPath} && " . - "mkdir -p -m 755 ${strPerlModulePath} && " . - "cp ${strBuildLibCPath}/blib/lib/pgBackRest/LibC.pm ${strPerlModulePath} && " . - "cp ${strBuildLibCPath}/blib/lib/pgBackRest/LibCAuto.pm ${strPerlModulePath} && " . + (defined($bCopyLibC) && $bCopyLibC ? + "mkdir -p -m 755 ${strPerlAutoPath} && " . + "cp ${strBuildLibCPath}/blib/arch/auto/pgBackRest/LibC/LibC.so ${strPerlAutoPath} && " : '') . "cp ${strBuildBinPath}/" . BACKREST_EXE . ' /usr/bin/' . BACKREST_EXE . ' && ' . - 'chmod 755 /usr/bin/' . BACKREST_EXE . ' && ' . - "ln -s ${strBasePath}/lib/pgBackRest /usr/share/perl5/pgBackRest'"); + 'chmod 755 /usr/bin/' . BACKREST_EXE . "'"); } push(@EXPORT, qw(jobInstallC)); diff --git a/test/lib/pgBackRestTest/Common/ListTest.pm b/test/lib/pgBackRestTest/Common/ListTest.pm index e340e54cd..6d8c7a9dc 100644 --- a/test/lib/pgBackRestTest/Common/ListTest.pm +++ b/test/lib/pgBackRestTest/Common/ListTest.pm @@ -42,6 +42,8 @@ use constant TEST_PERL_REQ => 'perl-req push @EXPORT, qw(TEST_PERL_REQ); use constant TEST_PGSQL_BIN => 'pgsql-bin'; push @EXPORT, qw(TEST_PGSQL_BIN); +use constant TEST_INTEGRATION => 'integration'; + push @EXPORT, qw(TEST_INTEGRATION); use constant TEST_RUN => 'run'; push @EXPORT, qw(TEST_RUN); use constant TEST_VM => 'os'; @@ -155,6 +157,7 @@ sub testListGet &TEST_PGSQL_BIN => $strPgSqlBin, &TEST_PERL_ARCH_PATH => $$oyVm{$strTestOS}{&VMDEF_PERL_ARCH_PATH}, &TEST_PERL_REQ => $hTest->{&TESTDEF_PERL_REQ}, + &TEST_INTEGRATION => $hTest->{&TESTDEF_INTEGRATION}, &TEST_MODULE => $strModule, &TEST_NAME => $strModuleTest, &TEST_RUN => diff --git a/test/lib/pgBackRestTest/Common/VmTest.pm b/test/lib/pgBackRestTest/Common/VmTest.pm index 5c9b796c1..edca6f229 100644 --- a/test/lib/pgBackRestTest/Common/VmTest.pm +++ b/test/lib/pgBackRestTest/Common/VmTest.pm @@ -105,7 +105,7 @@ use constant VM_HOST_DEFAULT => VM_U16; use constant VM_COVERAGE => VM_U16; # Lists valid VMs -use constant VM_LIST => (VM_CO6, VM_U16, VM_CO7, VM_U12); +use constant VM_LIST => (VM_U16, VM_CO6, VM_CO7, VM_U12); push @EXPORT, qw(VM_LIST); my $oyVm = diff --git a/test/patch/debian-package.patch b/test/patch/debian-package.patch new file mode 100644 index 000000000..53430cfd9 --- /dev/null +++ b/test/patch/debian-package.patch @@ -0,0 +1,30 @@ +--- pgbackrest.install +++++ pgbackrest.install +@@ -1,2 +1 @@ + debian/pgbackrest.conf etc/ +-lib/pgBackRest usr/share/perl5/ +--- rules ++++ rules +@@ -20,22 +20,16 @@ + -t pgbackrest \ + -s 1 \ + ${MANTEMPLATE} > ${CURDIR}/doc/output/man/pgbackrest.1 +- cd $(CURDIR)/libc; perl Makefile.PL INSTALLDIRS=vendor NO_PACKLIST=1 +- make -C $(CURDIR)/libc/ + make -C $(CURDIR)/src/ + dh_auto_build + + override_dh_auto_test: +- test "$(DEB_TARGET_ARCH_ENDIAN)" = "little" && \ +- cd $(CURDIR)/libc; make test + dh_auto_test + + override_dh_auto_clean: + rm -rf $(CURDIR)/doc/output +- test ! -f libc/Makefile || make -C libc distclean + dh_auto_clean + + override_dh_auto_install: +- make -C libc install DESTDIR=$(CURDIR)/debian/pgbackrest + make -C src install DESTDIR=$(CURDIR)/debian/pgbackrest + dh_auto_install diff --git a/test/patch/rhel-package.patch b/test/patch/rhel-package.patch new file mode 100644 index 000000000..098fd13cf --- /dev/null +++ b/test/patch/rhel-package.patch @@ -0,0 +1,37 @@ +--- pgbackrest.spec ++++ pgbackrest.spec +@@ -28,11 +28,6 @@ + %setup -q -n %{name}-release-%{version} + + %build +-pushd libc +-perl Makefile.PL +-%{__make} +-popd +- + pushd src + %{__make} + popd +@@ -44,12 +39,6 @@ + %{__install} -D -d -m 0700 %{buildroot}/var/spool/%{name} + %{__install} -D -d -m 0755 %{buildroot}%{_sysconfdir} + %{__install} %{SOURCE1} %{buildroot}/%{_sysconfdir}/%{name}.conf +-%{__cp} -a lib/* %{buildroot}%{perl_vendorlib}/ +-%{__mkdir} -p %{buildroot}%{perl_vendorarch}/auto/pgBackRest/LibC +-%{__cp} -a libc/blib/arch/auto/pgBackRest/LibC/* %{buildroot}%{perl_vendorarch}/auto/pgBackRest/LibC +-%{__cp} -a libc/blib/lib/auto/pgBackRest/LibC/* %{buildroot}%{perl_vendorarch}/auto/pgBackRest/LibC +-%{__mkdir} -p %{buildroot}%{perl_vendorarch}/pgBackRest +-%{__cp} -a libc/blib/lib/pgBackRest/* %{buildroot}%{perl_vendorarch}/pgBackRest + %{__cp} -a src/%{name} %{buildroot}%{_bindir}/%{name} + + %clean +@@ -64,9 +53,6 @@ + %endif + %{_bindir}/%{name} + %config(noreplace) %attr (644,root,root) %{_sysconfdir}/%{name}.conf +-%{perl_vendorlib}/pgBackRest/ +-%{perl_vendorarch}/pgBackRest/ +-%{perl_vendorarch}/auto/pgBackRest/LibC + %attr(-,postgres,postgres) /var/log/%{name} + %attr(-,postgres,postgres) %{_sharedstatedir}/%{name} + %attr(-,postgres,postgres) /var/spool/%{name} diff --git a/test/test.pl b/test/test.pl index 4222f8157..48e4618b3 100755 --- a/test/test.pl +++ b/test/test.pl @@ -42,6 +42,7 @@ use pgBackRestBuild::Build::Common; use pgBackRestBuild::Config::Build; use pgBackRestBuild::Config::BuildDefine; use pgBackRestBuild::Config::BuildParse; +use pgBackRestBuild::Embed::Build; use pgBackRestBuild::Error::Build; use pgBackRestBuild::Error::Data; @@ -78,10 +79,11 @@ test.pl [options] --pg-version version of postgres to test (all, defaults to minimal) --log-force force overwrite of current test log files --no-lint disable static source code analysis - --build-only compile the C library / packages and run tests only + --build-only compile the test library / packages and run tests only --coverage-only only run coverage tests (as a subset of selected tests) --c-only only run C tests --gen-only only run auto-generation + --no-gen do not run code generation --code-count generate code counts --smart perform libc/package builds only when source timestamps have changed --no-package do not build packages @@ -143,6 +145,7 @@ my $bCoverageOnly = false; my $bNoCoverage = false; my $bCOnly = false; my $bGenOnly = false; +my $bNoGen = false; my $bCodeCount = false; my $bSmart = false; my $bNoPackage = false; @@ -185,6 +188,7 @@ GetOptions ('q|quiet' => \$bQuiet, 'no-coverage' => \$bNoCoverage, 'c-only' => \$bCOnly, 'gen-only' => \$bGenOnly, + 'no-gen' => \$bNoGen, 'code-count' => \$bCodeCount, 'smart' => \$bSmart, 'dev' => \$bDev, @@ -360,87 +364,116 @@ eval exit 0; } - # Auto-generate C files + # Auto-generate files unless --no-gen specified #--------------------------------------------------------------------------------------------------------------------------- - &log(INFO, "check code autogenerate"); - - errorDefineLoad(${$oStorageBackRest->get("build/error.yaml")}); - - # Get last mod for build files and version file - my $lLastBuildMod = buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['build']); - my $lLastVersionMod = buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['lib'], 'Version\.pm$'); - - # If version mod is later than build mod, then make it the build mod - if ($lLastVersionMod > $lLastBuildMod) + if (!$bNoGen) { - $lLastBuildMod = $lLastVersionMod; - } + &log(INFO, "check code autogenerate"); - if (!$bSmart || $lLastBuildMod > buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['src'], '\.auto\.c$')) - { - &log(INFO, " autogenerate C code"); - - my $rhBuild = + # Auto-generate C files + #----------------------------------------------------------------------------------------------------------------------- + if (!$bSmart || buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['build']) > + buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['src'], '\.auto\.c$')) { - 'config' => - { - &BLD_DATA => buildConfig(), - &BLD_PATH => 'config', - }, + &log(INFO, " autogenerate C code"); - 'configDefine' => - { - &BLD_DATA => buildConfigDefine(), - &BLD_PATH => 'config', - }, + errorDefineLoad(${$oStorageBackRest->get("build/error.yaml")}); - 'configParse' => + my $rhBuild = { - &BLD_DATA => buildConfigParse(), - &BLD_PATH => 'config', - }, + 'config' => + { + &BLD_DATA => buildConfig(), + &BLD_PATH => 'config', + }, - 'error' => + 'configDefine' => + { + &BLD_DATA => buildConfigDefine(), + &BLD_PATH => 'config', + }, + + 'configParse' => + { + &BLD_DATA => buildConfigParse(), + &BLD_PATH => 'config', + }, + + 'error' => + { + &BLD_DATA => buildError(), + &BLD_PATH => 'common', + }, + }; + + buildAll("${strBackRestBase}/src", $rhBuild); + } + + # Auto-generate Perl code + #----------------------------------------------------------------------------------------------------------------------- + use lib dirname(dirname($0)) . '/libc/build/lib'; + use pgBackRestLibC::Build; ## no critic (Modules::ProhibitConditionalUseStatements) + + if (!$bSmart || buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['build', 'libc/build']) > + buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['lib'], 'Auto\.pm$')) + { + &log(INFO, " autogenerate Perl code"); + + errorDefineLoad(${$oStorageBackRest->get("build/error.yaml")}); + + buildXsAll("${strBackRestBase}/libc"); + } + + # Auto-generate C library code to embed in the binary + #----------------------------------------------------------------------------------------------------------------------- + if (!$bSmart || buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['libc']) > + buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['src/perl'], '^libc\.auto\.c$')) + { + &log(INFO, " autogenerate embedded C code"); + + my $strLibC = executeTest( + "cd ${strBackRestBase}/libc && " . + "perl /usr/share/perl/5.22/ExtUtils/xsubpp -typemap /usr/share/perl/5.22/ExtUtils/typemap" . + " -typemap typemap LibC.xs"); + + # Trim off any trailing LFs + $strLibC = trim($strLibC) . "\n"; + + # Strip out line numbers. These are useful for the LibC build but only cause churn in the binary + # build. + $strLibC =~ s/^\#line .*\n//mg; + + # Save into the bin src dir + $oStorageBackRest->put("${strBackRestBase}/src/perl/libc.auto.c", $strLibC); + } + + # Auto-generate embedded Perl code + #----------------------------------------------------------------------------------------------------------------------- + if (!$bSmart || buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['lib']) > + buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['src/perl'], 'embed\.auto\.c')) + { + &log(INFO, " autogenerate embedded Perl code"); + + my $rhBuild = { - &BLD_DATA => buildError(), - &BLD_PATH => 'common', - }, - }; + 'embed' => + { + &BLD_DATA => buildEmbed($oStorageBackRest), + &BLD_PATH => 'perl', + }, + }; - buildAll("${strBackRestBase}/src", $rhBuild); + buildAll("${strBackRestBase}/src", $rhBuild); + } + + if ($bGenOnly) + { + exit 0; + } } - # Auto-generate XS files - # - # Use statements are put here so this will be easy to get rid of someday. + # Build CI config #--------------------------------------------------------------------------------------------------------------------------- - use lib dirname(dirname($0)) . '/libc/build/lib'; - use pgBackRestLibC::Build; ## no critic (Modules::ProhibitConditionalUseStatements) - use pgBackRestLibC::BuildParam; ## no critic (Modules::ProhibitConditionalUseStatements) - - # Get last mod for Perl build files - my $lLastPerlBuildMod = buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['libc/build']); - - # If Perl build mod is later than build mod, then make it the build mod - if ($lLastPerlBuildMod > $lLastBuildMod) - { - $lLastBuildMod = $lLastPerlBuildMod; - } - - if (!$bSmart || - $lLastBuildMod > buildLastModTime($oStorageBackRest, "${strBackRestBase}", ['libc', 'lib'], '(\.auto\.xs|Auto\.pm)$')) - { - &log(INFO, " autogenerate Perl code"); - - buildXsAll("${strBackRestBase}/libc"); - } - - if ($bGenOnly) - { - exit 0; - } - - # Build CI configuration if (!$bNoCiConfig) { (new pgBackRestTest::Common::CiTest($oStorageBackRest))->process(); @@ -548,7 +581,9 @@ eval # Determine which tests to run #--------------------------------------------------------------------------------------------------------------------------- my $oyTestRun; - my $bBuildRequired = false; + my $bBinRequired = $bBuildOnly; + my $bLibCHostRequired = $bBuildOnly; + my $bLibCVmRequired = $bBuildOnly; # Only get the test list when they can run if (!$bBuildOnly) @@ -557,274 +592,312 @@ eval $oyTestRun = testListGet( $strVm, \@stryModule, \@stryModuleTest, \@iyModuleTestRun, $strPgVersion, $bCoverageOnly, $bCOnly); - # Search for any tests that are not C unit tests to determine if the C binary and lib need to be built for testing. If - # all the tests are C unit tests then no builds are required. This saves a lot ot time. + # Determine if the C binary and test library need to be built foreach my $hTest (@{$oyTestRun}) { + # Bin build required for all Perl tests or if a C unit test calls Perl if (!$hTest->{&TEST_C} || $hTest->{&TEST_PERL_REQ}) { - $bBuildRequired = true; - last; + $bBinRequired = true; + } + + # Host LibC required if a Perl test + if (!$hTest->{&TEST_C}) + { + $bLibCHostRequired = true; + } + + # VM LibC required if Perl and not an integration test + if (!$hTest->{&TEST_C} && !$hTest->{&TEST_INTEGRATION}) + { + $bLibCVmRequired = true; } } } + my $strBuildRequired; + + if ($bBinRequired || $bLibCHostRequired || $bLibCVmRequired) + { + if ($bBinRequired) + { + $strBuildRequired = "bin"; + } + + if ($bLibCHostRequired) + { + $strBuildRequired .= ", libc host"; + } + + if ($bLibCVmRequired) + { + $strBuildRequired .= ", libc vm"; + } + } + else + { + $strBuildRequired = "none"; + } + + &log(INFO, "builds required: ${strBuildRequired}"); + # Build the binary, library and packages #--------------------------------------------------------------------------------------------------------------------------- - if (!$bDryRun && $bBuildRequired) + if (!$bDryRun) { - &log(INFO, "check bin builds"); - my $oVm = vmGet(); my $strVagrantPath = "${strBackRestBase}/test/.vagrant"; - - # Build the binary - #--------------------------------------------------------------------------------------------------------------------------- - my $strBinPath = "${strVagrantPath}/bin"; - my $strBinSmart = "${strBinPath}/build.timestamp"; - my $bRebuild = !$bSmart; - my @stryBinSrcPath = ('src'); - - # Find the lastest modified time for dirs that affect the bin build - my $lTimestampLast = buildLastModTime($oStorageBackRest, $strBackRestBase, \@stryBinSrcPath); - - # Rebuild if the modification time of the smart file does equal the last changes in source paths - if ($bSmart) - { - if (!$oStorageBackRest->exists($strBinSmart) || $oStorageBackRest->info($strBinSmart)->mtime < $lTimestampLast) - { - &log(INFO, ' bin dependencies have changed, rebuilding...'); - - $bRebuild = true; - } - } - else - { - executeTest("sudo rm -rf ${strBinPath}"); - } - - # Loop through VMs to do the C bin builds - my $bLogDetail = $strLogLevel eq 'detail'; - my @stryBuildVm = $strVm eq VM_ALL ? VM_LIST : ($strVm); - - foreach my $strBuildVM (sort(@stryBuildVm)) - { - my $strBuildPath = "${strBinPath}/${strBuildVM}/src"; - - if ($bRebuild) - { - &log(INFO, " build bin for ${strBuildVM} (${strBuildPath})"); - - executeTest( - "docker run -itd -h test-build --name=test-build" . - " -v ${strBackRestBase}:${strBackRestBase} " . containerRepo() . ":${strBuildVM}-build", - {bSuppressStdErr => true}); - - foreach my $strBinSrcPath (@stryBinSrcPath) - { - $oStorageBackRest->pathCreate( - "${strBinPath}/${strBuildVM}/${strBinSrcPath}", {bIgnoreExists => true, bCreateParent => true}); - executeTest("rsync -rt ${strBackRestBase}/${strBinSrcPath}/* ${strBinPath}/${strBuildVM}/${strBinSrcPath}"); - } - - if (vmCoverage($strVm) && !$bNoLint) - { - &log(INFO, " clang static analyzer ${strBuildVM} (${strBuildPath})"); - } - - my $strCExtra = - "'-g" . (vmWithBackTrace($strBuildVM) && $bNoLint && $bBackTrace ? ' -DWITH_BACKTRACE' : '') . "'"; - my $strLdExtra = vmWithBackTrace($strBuildVM) && $bNoLint && $bBackTrace ? '-lbacktrace' : ''; - my $strCDebug = vmDebugIntegration($strBuildVM) ? 'CDEBUG=' : ''; - - executeTest( - 'docker exec -i test-build' . - (vmCoverage($strVm) && !$bNoLint ? ' scan-build-5.0' : '') . - " make --silent --directory ${strBuildPath} CEXTRA=${strCExtra} LDEXTRA=${strLdExtra} ${strCDebug}", - {bShowOutputAsync => $bLogDetail}); - - executeTest( - "docker exec -i test-build make --silent --directory ${strBuildPath} install", - {bShowOutputAsync => $bLogDetail}); - - executeTest("docker rm -f test-build"); - } - } - - # Write files to indicate the last time a build was successful - $oStorageBackRest->put($strBinSmart); - utime($lTimestampLast, $lTimestampLast, $strBinSmart) or - confess "unable to set time for ${strBinSmart}" . (defined($!) ? ":$!" : ''); + my $lTimestampLast; # Build the C Library - #--------------------------------------------------------------------------------------------------------------------------- - my $strLibCPath = "${strVagrantPath}/libc"; - my $strLibCSmart = "${strLibCPath}/build.timestamp"; - $bRebuild = !$bSmart; - my @stryLibCSrcPath = ('libc', 'src'); - - # Find the lastest modified time for dirs that affect the libc build - $lTimestampLast = buildLastModTime($oStorageBackRest, $strBackRestBase, \@stryLibCSrcPath); - - # Rebuild if the modification time of the smart file does equal the last changes in source paths - if ($bSmart) + #----------------------------------------------------------------------------------------------------------------------- + if ($bLibCHostRequired || $bLibCVmRequired) { - if (!$oStorageBackRest->exists($strLibCSmart) || $oStorageBackRest->info($strLibCSmart)->mtime < $lTimestampLast) + my $strLibCPath = "${strVagrantPath}/libc"; + my $strLibCSmart = "${strLibCPath}/build.timestamp"; + my $bRebuild = !$bSmart; + my @stryLibCSrcPath = $bLibCHostRequired || $bLibCVmRequired ? ('libc', 'src') : ('libc'); + + # Find the lastest modified time for dirs that affect the libc build + $lTimestampLast = buildLastModTime($oStorageBackRest, $strBackRestBase, \@stryLibCSrcPath); + + # Rebuild if the modification time of the smart file does equal the last changes in source paths + if ($bSmart) { - &log(INFO, ' libc dependencies have changed, rebuilding...'); + if (!$oStorageBackRest->exists($strLibCSmart) || + $oStorageBackRest->info($strLibCSmart)->mtime < $lTimestampLast) + { + &log(INFO, ' libc dependencies have changed, rebuilding...'); - $bRebuild = true; + $bRebuild = true; + } + } + else + { + executeTest("sudo rm -rf ${strLibCPath}"); } - } - else - { - executeTest("sudo rm -rf ${strLibCPath}"); - } - - # Delete old libc files from the host - if ($bRebuild) - { - executeTest('sudo rm -rf ' . $oVm->{$strVmHost}{&VMDEF_PERL_ARCH_PATH} . '/auto/pgBackRest/LibC'); - executeTest('sudo rm -rf ' . $oVm->{$strVmHost}{&VMDEF_PERL_ARCH_PATH} . '/pgBackRest'); - } - - # Loop through VMs to do the C Library builds - $bLogDetail = $strLogLevel eq 'detail'; - @stryBuildVm = $strVm eq VM_ALL ? VM_LIST : ($strVm eq $strVmHost ? ($strVm) : ($strVm, $strVmHost)); - - foreach my $strBuildVM (sort(@stryBuildVm)) - { - my $strBuildPath = "${strLibCPath}/${strBuildVM}/libc"; - my $bContainerExists = $strVm eq VM_ALL || $strBuildVM ne $strVmHost; + # Delete old libc files from the host if ($bRebuild) { - &log(INFO, " build C library for ${strBuildVM} (${strBuildPath})"); + executeTest('sudo rm -rf ' . $oVm->{$strVmHost}{&VMDEF_PERL_ARCH_PATH} . '/auto/pgBackRest/LibC'); + executeTest('sudo rm -rf ' . $oVm->{$strVmHost}{&VMDEF_PERL_ARCH_PATH} . '/pgBackRest'); + } - # It's very expensive to rebuild the Makefile so make sure it has actually changed - my $bMakeRebuild = - !$oStorageBackRest->exists("${strBuildPath}/Makefile") || - ($oStorageBackRest->info("${strBackRestBase}/libc/Makefile.PL")->mtime > - $oStorageBackRest->info("${strBuildPath}/Makefile.PL")->mtime); + # Loop through VMs to do the C Library builds + my $bLogDetail = $strLogLevel eq 'detail'; + my @stryBuildVm = (); - if ($bContainerExists) + if ($strVm eq VM_ALL) + { + @stryBuildVm = $bLibCVmRequired ? VM_LIST : ($strVmHost); + } + else + { + @stryBuildVm = $bLibCVmRequired ? ($strVmHost, $strVm) : ($strVmHost); + } + + foreach my $strBuildVM (@stryBuildVm) + { + my $strBuildPath = "${strLibCPath}/${strBuildVM}/libc"; + my $bContainerExists = $strBuildVM ne $strVmHost; + + if ($bRebuild) { + &log(INFO, " build test library for ${strBuildVM} (${strBuildPath})"); + + # It's very expensive to rebuild the Makefile so make sure it has actually changed + my $bMakeRebuild = + !$oStorageBackRest->exists("${strBuildPath}/Makefile") || + ($oStorageBackRest->info("${strBackRestBase}/libc/Makefile.PL")->mtime > + $oStorageBackRest->info("${strBuildPath}/Makefile.PL")->mtime); + + if ($bContainerExists) + { + executeTest( + "docker run -itd -h test-build --name=test-build" . + " -v ${strBackRestBase}:${strBackRestBase} " . containerRepo() . ":${strBuildVM}-build", + {bSuppressStdErr => true}); + } + + foreach my $strLibCSrcPath ('lib', 'libc', 'src') + { + $oStorageBackRest->pathCreate( + "${strLibCPath}/${strBuildVM}/${strLibCSrcPath}", {bIgnoreExists => true, bCreateParent => true}); + executeTest( + "rsync -rt ${strBackRestBase}/${strLibCSrcPath}/* ${strLibCPath}/${strBuildVM}/${strLibCSrcPath}"); + } + + if ($bMakeRebuild) + { + executeTest( + ($bContainerExists ? "docker exec -i test-build bash -c '" : '') . + "cd ${strBuildPath} && perl Makefile.PL INSTALLMAN1DIR=none INSTALLMAN3DIR=none" . + ($bContainerExists ? "'" : ''), + {bSuppressStdErr => true, bShowOutputAsync => $bLogDetail}); + } + + executeTest( + ($bContainerExists ? 'docker exec -i test-build ' : '') . + "make --silent --directory ${strBuildPath}", + {bShowOutputAsync => $bLogDetail}); + executeTest( + ($bContainerExists ? 'docker exec -i test-build ' : '') . + "make --silent --directory ${strBuildPath} test", + {bShowOutputAsync => $bLogDetail}); + executeTest( + ($bContainerExists ? 'docker exec -i test-build ' : 'sudo ') . + "make --silent --directory ${strBuildPath} install", + {bShowOutputAsync => $bLogDetail}); + + if ($bContainerExists) + { + executeTest("docker rm -f test-build"); + } + + if ($strBuildVM eq $strVmHost) + { + executeTest("sudo make -C ${strBuildPath} install", {bSuppressStdErr => true}); + + # Load the module dynamically + require pgBackRest::LibC; + pgBackRest::LibC->import(qw(:debug)); + + require XSLoader; + XSLoader::load('pgBackRest::LibC', '999'); + + # Do a basic test to make sure it installed correctly + if (libcUvSize() != 8) + { + confess &log(ERROR, 'UVSIZE in test library does not equal 8'); + } + } + } + } + + # Write files to indicate the last time a build was successful + $oStorageBackRest->put($strLibCSmart); + utime($lTimestampLast, $lTimestampLast, $strLibCSmart) or + confess "unable to set time for ${strLibCSmart}" . (defined($!) ? ":$!" : ''); + } + + # Build the binary + #----------------------------------------------------------------------------------------------------------------------- + if ($bBinRequired) + { + my $strBinPath = "${strVagrantPath}/bin"; + my $strBinSmart = "${strBinPath}/build.timestamp"; + my $bRebuild = !$bSmart; + my @stryBinSrcPath = ('src', 'libc'); + + # Find the lastest modified time for dirs that affect the bin build + $lTimestampLast = buildLastModTime($oStorageBackRest, $strBackRestBase, \@stryBinSrcPath); + + # Rebuild if the modification time of the smart file does equal the last changes in source paths + if ($bSmart) + { + if (!$oStorageBackRest->exists($strBinSmart) || $oStorageBackRest->info($strBinSmart)->mtime < $lTimestampLast) + { + &log(INFO, ' bin dependencies have changed, rebuilding...'); + + $bRebuild = true; + } + } + else + { + executeTest("sudo rm -rf ${strBinPath}"); + } + + # Loop through VMs to do the C bin builds + my $bLogDetail = $strLogLevel eq 'detail'; + my @stryBuildVm = $strVm eq VM_ALL ? VM_LIST : ($strVm); + + foreach my $strBuildVM (@stryBuildVm) + { + my $strBuildPath = "${strBinPath}/${strBuildVM}/src"; + + if ($bRebuild) + { + &log(INFO, " build bin for ${strBuildVM} (${strBuildPath})"); + executeTest( "docker run -itd -h test-build --name=test-build" . " -v ${strBackRestBase}:${strBackRestBase} " . containerRepo() . ":${strBuildVM}-build", {bSuppressStdErr => true}); - } - foreach my $strLibCSrcPath (@stryLibCSrcPath) - { - $oStorageBackRest->pathCreate( - "${strLibCPath}/${strBuildVM}/${strLibCSrcPath}", {bIgnoreExists => true, bCreateParent => true}); - executeTest( - "rsync -rt ${strBackRestBase}/${strLibCSrcPath}/* ${strLibCPath}/${strBuildVM}/${strLibCSrcPath}"); - } + foreach my $strBinSrcPath (@stryBinSrcPath) + { + $oStorageBackRest->pathCreate( + "${strBinPath}/${strBuildVM}/${strBinSrcPath}", {bIgnoreExists => true, bCreateParent => true}); + executeTest( + "rsync -rt ${strBackRestBase}/${strBinSrcPath}/* ${strBinPath}/${strBuildVM}/${strBinSrcPath}"); + } - if ($bMakeRebuild) - { - my $strCCFlags = vmDebugIntegration($strBuildVM) ? ' CCFLAGS="' . join(' ', buildParamCCDebug()) . '"' : ''; - $strCCFlags =~ s/\$/\\\$/; + if (vmCoverage($strVm) && !$bNoLint) + { + &log(INFO, " clang static analyzer ${strBuildVM} (${strBuildPath})"); + } + + my $strCExtra = + "'-g" . (vmWithBackTrace($strBuildVM) && $bNoLint && $bBackTrace ? ' -DWITH_BACKTRACE' : '') . "'"; + my $strLdExtra = vmWithBackTrace($strBuildVM) && $bNoLint && $bBackTrace ? '-lbacktrace' : ''; + my $strCDebug = vmDebugIntegration($strBuildVM) ? 'CDEBUG=' : ''; executeTest( - ($bContainerExists ? "docker exec -i test-build bash -c '" : '') . - "cd ${strBuildPath} && perl Makefile.PL${strCCFlags} INSTALLMAN1DIR=none INSTALLMAN3DIR=none" . - ($bContainerExists ? "'" : ''), - {bSuppressStdErr => true, bShowOutputAsync => $bLogDetail}); - } + 'docker exec -i test-build' . + (vmCoverage($strVm) && !$bNoLint ? ' scan-build-5.0' : '') . + " make --silent --directory ${strBuildPath} CEXTRA=${strCExtra} LDEXTRA=${strLdExtra} ${strCDebug}", + {bShowOutputAsync => $bLogDetail}); - executeTest( - ($bContainerExists ? 'docker exec -i test-build ' : '') . - "make --silent --directory ${strBuildPath}", - {bShowOutputAsync => $bLogDetail}); - executeTest( - ($bContainerExists ? 'docker exec -i test-build ' : '') . - "make --silent --directory ${strBuildPath} test", - {bShowOutputAsync => $bLogDetail}); - executeTest( - ($bContainerExists ? 'docker exec -i test-build ' : 'sudo ') . - "make --silent --directory ${strBuildPath} install", - {bShowOutputAsync => $bLogDetail}); - - if ($bContainerExists) - { executeTest("docker rm -f test-build"); } - - if ($strBuildVM eq $strVmHost) - { - executeTest("sudo make -C ${strBuildPath} install", {bSuppressStdErr => true}); - - # Load the module dynamically - require pgBackRest::LibC; - pgBackRest::LibC->import(qw(:debug)); - - # Do a basic test to make sure it installed correctly - if (&UVSIZE != 8) - { - confess &log(ERROR, 'UVSIZE in C library does not equal 8'); - } - - # Also check the version number - my $strLibCVersion = - BACKREST_VERSION =~ /dev$/ ? - substr(BACKREST_VERSION, 0, length(BACKREST_VERSION) - 3) . '.999' : BACKREST_VERSION; - - if (libcVersion() ne $strLibCVersion) - { - confess &log(ERROR, $strLibCVersion . ' was expected for LibC version but found ' . libcVersion()); - } - } } - } - # Write files to indicate the last time a build was successful - $oStorageBackRest->put($strLibCSmart); - utime($lTimestampLast, $lTimestampLast, $strLibCSmart) or - confess "unable to set time for ${strLibCSmart}" . (defined($!) ? ":$!" : ''); + # Write files to indicate the last time a build was successful + $oStorageBackRest->put($strBinSmart); + utime($lTimestampLast, $lTimestampLast, $strBinSmart) or + confess "unable to set time for ${strBinSmart}" . (defined($!) ? ":$!" : ''); + } # Build the package - #--------------------------------------------------------------------------------------------------------------------------- - my $strPackagePath = "${strVagrantPath}/package"; - my $strPackageSmart = "${strPackagePath}/build.timestamp"; - my @stryPackageSrcPath = ('lib'); - - # Find the lastest modified time for additional dirs that affect the package build - foreach my $strPackageSrcPath (@stryPackageSrcPath) - { - my $hManifest = $oStorageBackRest->manifest($strPackageSrcPath); - - foreach my $strFile (sort(keys(%{$hManifest}))) - { - if ($hManifest->{$strFile}{type} eq 'f' && $hManifest->{$strFile}{modification_time} > $lTimestampLast) - { - $lTimestampLast = $hManifest->{$strFile}{modification_time}; - } - } - } - - # Rebuild if the modification time of the smart file does equal the last changes in source paths - if (!$bNoPackage && - (!$bSmart || !$oStorageBackRest->exists($strPackageSmart) || - $oStorageBackRest->info($strPackageSmart)->mtime < $lTimestampLast)) - { - if ($bSmart) - { - &log(INFO, 'package dependencies have changed, rebuilding...'); - } - - executeTest("sudo rm -rf ${strPackagePath}"); - } - - # Loop through VMs to do the package builds + #----------------------------------------------------------------------------------------------------------------------- if (!$bNoPackage) { + my $strPackagePath = "${strVagrantPath}/package"; + my $strPackageSmart = "${strPackagePath}/build.timestamp"; + my @stryPackageSrcPath = ('lib'); + + # Find the lastest modified time for additional dirs that affect the package build + foreach my $strPackageSrcPath (@stryPackageSrcPath) + { + my $hManifest = $oStorageBackRest->manifest($strPackageSrcPath); + + foreach my $strFile (sort(keys(%{$hManifest}))) + { + if ($hManifest->{$strFile}{type} eq 'f' && $hManifest->{$strFile}{modification_time} > $lTimestampLast) + { + $lTimestampLast = $hManifest->{$strFile}{modification_time}; + } + } + } + + # Rebuild if the modification time of the smart file does not equal the last changes in source paths + if ((!$bSmart || !$oStorageBackRest->exists($strPackageSmart) || + $oStorageBackRest->info($strPackageSmart)->mtime < $lTimestampLast)) + { + if ($bSmart) + { + &log(INFO, 'package dependencies have changed, rebuilding...'); + } + + executeTest("sudo rm -rf ${strPackagePath}"); + } + + # Loop through VMs to do the package builds my @stryBuildVm = $strVm eq VM_ALL ? VM_LIST : ($strVm); $oStorageBackRest->pathCreate($strPackagePath, {bIgnoreExists => true, bCreateParent => true}); - foreach my $strBuildVM (sort(@stryBuildVm)) + foreach my $strBuildVM (@stryBuildVm) { my $strBuildPath = "${strPackagePath}/${strBuildVM}/src"; @@ -1325,6 +1398,14 @@ eval exit 0; } + # Load the module dynamically + require pgBackRest::LibCAuto; + require pgBackRest::LibC; + pgBackRest::LibC->import(qw(:debug)); + + require XSLoader; + XSLoader::load('pgBackRest::LibC', '999'); + ################################################################################################################################ # Runs tests ################################################################################################################################ diff --git a/test/travis.pl b/test/travis.pl index df7eb57d2..0327d8526 100755 --- a/test/travis.pl +++ b/test/travis.pl @@ -156,7 +156,8 @@ eval processBegin("${strVm} test" . (defined($strParam) ? ": ${strParam}" : '')); executeTest( - "${strTestExe} --vm-host=" . VM_U14 . " --vm-max=2 --vm=${strVm}" . (defined($strParam) ? " ${strParam}" : ''), + "${strTestExe} --no-gen --no-ci-config --vm-host=" . VM_U14 . " --vm-max=2 --vm=${strVm}" . + (defined($strParam) ? " ${strParam}" : ''), {bShowOutputAsync => true}); processEnd(); }