2017-06-09 23:51:41 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# Local Storage
|
|
|
|
#
|
|
|
|
# Implements storage functionality using drivers.
|
|
|
|
####################################################################################################################################
|
|
|
|
package pgBackRest::Storage::Local;
|
|
|
|
use parent 'pgBackRest::Storage::Base';
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
|
|
|
use English '-no_match_vars';
|
|
|
|
|
|
|
|
use File::Basename qw(dirname);
|
|
|
|
|
|
|
|
use pgBackRest::Common::Exception;
|
|
|
|
use pgBackRest::Common::Log;
|
|
|
|
use pgBackRest::Common::String;
|
2017-11-06 19:51:12 +02:00
|
|
|
use pgBackRest::Storage::Base;
|
2017-06-09 23:51:41 +02:00
|
|
|
use pgBackRest::Storage::Filter::Sha;
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# new
|
|
|
|
####################################################################################################################################
|
|
|
|
sub new
|
|
|
|
{
|
|
|
|
my $class = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathBase,
|
|
|
|
$oDriver,
|
|
|
|
$hRule,
|
|
|
|
$bAllowTemp,
|
|
|
|
$strTempExtension,
|
|
|
|
$strDefaultPathMode,
|
|
|
|
$strDefaultFileMode,
|
|
|
|
$lBufferMax,
|
2017-11-06 19:51:12 +02:00
|
|
|
$strCipherType,
|
|
|
|
$strCipherPassUser,
|
2017-06-09 23:51:41 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->new', \@_,
|
|
|
|
{name => 'strPathBase'},
|
|
|
|
{name => 'oDriver'},
|
|
|
|
{name => 'hRule', optional => true},
|
|
|
|
{name => 'bAllowTemp', optional => true, default => true},
|
|
|
|
{name => 'strTempExtension', optional => true, default => 'tmp'},
|
|
|
|
{name => 'strDefaultPathMode', optional => true, default => '0750'},
|
|
|
|
{name => 'strDefaultFileMode', optional => true, default => '0640'},
|
|
|
|
{name => 'lBufferMax', optional => true},
|
2017-11-06 19:51:12 +02:00
|
|
|
{name => 'strCipherType', optional => true},
|
|
|
|
{name => 'strCipherPassUser', optional => true, redact => true},
|
2017-06-09 23:51:41 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
# Create class
|
|
|
|
my $self = $class->SUPER::new({lBufferMax => $lBufferMax});
|
|
|
|
bless $self, $class;
|
|
|
|
|
|
|
|
$self->{strPathBase} = $strPathBase;
|
|
|
|
$self->{oDriver} = $oDriver;
|
|
|
|
$self->{hRule} = $hRule;
|
|
|
|
$self->{bAllowTemp} = $bAllowTemp;
|
|
|
|
$self->{strTempExtension} = $strTempExtension;
|
|
|
|
$self->{strDefaultPathMode} = $strDefaultPathMode;
|
|
|
|
$self->{strDefaultFileMode} = $strDefaultFileMode;
|
2017-11-06 19:51:12 +02:00
|
|
|
$self->{strCipherType} = $strCipherType;
|
|
|
|
$self->{strCipherPassUser} = $strCipherPassUser;
|
|
|
|
|
|
|
|
if (defined($self->{strCipherType}))
|
|
|
|
{
|
|
|
|
require pgBackRest::Storage::Filter::CipherBlock;
|
|
|
|
pgBackRest::Storage::Filter::CipherBlock->import();
|
|
|
|
}
|
2017-06-09 23:51:41 +02:00
|
|
|
|
|
|
|
# Set temp extension in driver
|
|
|
|
$self->driver()->tempExtensionSet($self->{strTempExtension}) if $self->driver()->can('tempExtensionSet');
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'self', value => $self}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# exists - check if file exists
|
|
|
|
####################################################################################################################################
|
|
|
|
sub exists
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strFileExp,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->exists', \@_,
|
|
|
|
{name => 'strFileExp'},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Check exists
|
|
|
|
my $bExists = $self->driver()->exists($self->pathGet($strFileExp));
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'bExists', value => $bExists}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
2017-11-06 19:51:12 +02:00
|
|
|
# hashSize - calculate sha1 hash and size of file. If special encryption settings are required, then the file objects from
|
|
|
|
# openRead/openWrite must be passed instead of file names.
|
2017-06-09 23:51:41 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
sub hashSize
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$xFileExp,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->hashSize', \@_,
|
|
|
|
{name => 'xFileExp'},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Set operation variables
|
|
|
|
my $strHash;
|
|
|
|
my $lSize;
|
|
|
|
|
|
|
|
# Is this an IO object or a file expression?
|
|
|
|
my $oFileIo = defined($xFileExp) ? (ref($xFileExp) ? $xFileExp : $self->openRead($self->pathGet($xFileExp))) : undef;
|
|
|
|
|
|
|
|
if (defined($oFileIo))
|
|
|
|
{
|
|
|
|
$lSize = 0;
|
|
|
|
my $oShaIo = new pgBackRest::Storage::Filter::Sha($oFileIo);
|
|
|
|
my $lSizeRead;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
my $tContent;
|
|
|
|
$lSizeRead = $oShaIo->read(\$tContent, $self->{lBufferMax});
|
|
|
|
$lSize += $lSizeRead;
|
|
|
|
}
|
|
|
|
while ($lSizeRead != 0);
|
|
|
|
|
|
|
|
# Close the file
|
|
|
|
$oShaIo->close();
|
|
|
|
|
|
|
|
# Get the hash
|
|
|
|
$strHash = $oShaIo->result(STORAGE_FILTER_SHA);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'strHash', value => $strHash},
|
|
|
|
{name => 'lSize', value => $lSize}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# info - get information for path/file
|
|
|
|
####################################################################################################################################
|
|
|
|
sub info
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathFileExp,
|
|
|
|
$bIgnoreMissing,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '::fileStat', \@_,
|
|
|
|
{name => 'strPathFileExp'},
|
2017-07-25 18:44:38 +02:00
|
|
|
{name => 'bIgnoreMissing', optional => true, default => false},
|
2017-06-09 23:51:41 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
# Stat the path/file
|
2017-07-25 18:44:38 +02:00
|
|
|
my $oInfo = $self->driver()->info($self->pathGet($strPathFileExp), {bIgnoreMissing => $bIgnoreMissing});
|
2017-06-09 23:51:41 +02:00
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'oInfo', value => $oInfo, trace => true}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# linkCreate - create a link
|
|
|
|
####################################################################################################################################
|
|
|
|
sub linkCreate
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strSourcePathFileExp,
|
|
|
|
$strDestinationLinkExp,
|
|
|
|
$bHard,
|
|
|
|
$bRelative,
|
|
|
|
$bPathCreate,
|
|
|
|
$bIgnoreExists,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->linkCreate', \@_,
|
|
|
|
{name => 'strSourcePathFileExp'},
|
|
|
|
{name => 'strDestinationLinkExp'},
|
|
|
|
{name => 'bHard', optional=> true, default => false},
|
|
|
|
{name => 'bRelative', optional=> true, default => false},
|
|
|
|
{name => 'bPathCreate', optional=> true, default => true},
|
|
|
|
{name => 'bIgnoreExists', optional => true, default => false},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Get source and destination paths
|
|
|
|
my $strSourcePathFile = $self->pathGet($strSourcePathFileExp);
|
|
|
|
my $strDestinationLink = $self->pathGet($strDestinationLinkExp);
|
|
|
|
|
|
|
|
# Generate relative path if requested
|
|
|
|
if ($bRelative)
|
|
|
|
{
|
|
|
|
# Determine how much of the paths are common
|
|
|
|
my @strySource = split('/', $strSourcePathFile);
|
|
|
|
my @stryDestination = split('/', $strDestinationLink);
|
|
|
|
|
|
|
|
while (defined($strySource[0]) && defined($stryDestination[0]) && $strySource[0] eq $stryDestination[0])
|
|
|
|
{
|
|
|
|
shift(@strySource);
|
|
|
|
shift(@stryDestination);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Add relative path sections
|
|
|
|
$strSourcePathFile = '';
|
|
|
|
|
|
|
|
for (my $iIndex = 0; $iIndex < @stryDestination - 1; $iIndex++)
|
|
|
|
{
|
|
|
|
$strSourcePathFile .= '../';
|
|
|
|
}
|
|
|
|
|
|
|
|
# Add path to source
|
|
|
|
$strSourcePathFile .= join('/', @strySource);
|
|
|
|
|
|
|
|
logDebugMisc
|
|
|
|
(
|
|
|
|
$strOperation, 'apply relative path',
|
|
|
|
{name => 'strSourcePathFile', value => $strSourcePathFile, trace => true}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Create the link
|
|
|
|
$self->driver()->linkCreate(
|
|
|
|
$strSourcePathFile, $strDestinationLink, {bHard => $bHard, bPathCreate => $bPathCreate, bIgnoreExists => $bIgnoreExists});
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn($strOperation);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# list - list all files/paths in path
|
|
|
|
####################################################################################################################################
|
|
|
|
sub list
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathExp,
|
|
|
|
$strExpression,
|
|
|
|
$strSortOrder,
|
|
|
|
$bIgnoreMissing,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->list', \@_,
|
|
|
|
{name => 'strPathExp'},
|
|
|
|
{name => 'strExpression', optional => true},
|
|
|
|
{name => 'strSortOrder', optional => true, default => 'forward'},
|
|
|
|
{name => 'bIgnoreMissing', optional => true, default => false},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Get file list
|
2017-10-20 20:10:16 +02:00
|
|
|
my $rstryFileList = $self->driver()->list(
|
|
|
|
$self->pathGet($strPathExp), {strExpression => $strExpression, bIgnoreMissing => $bIgnoreMissing});
|
2017-06-09 23:51:41 +02:00
|
|
|
|
|
|
|
# Apply expression if defined
|
|
|
|
if (defined($strExpression))
|
|
|
|
{
|
|
|
|
@{$rstryFileList} = grep(/$strExpression/i, @{$rstryFileList});
|
|
|
|
}
|
|
|
|
|
|
|
|
# Reverse sort
|
|
|
|
if ($strSortOrder eq 'reverse')
|
|
|
|
{
|
|
|
|
@{$rstryFileList} = sort {$b cmp $a} @{$rstryFileList};
|
|
|
|
}
|
|
|
|
# Normal sort
|
|
|
|
else
|
|
|
|
{
|
|
|
|
@{$rstryFileList} = sort @{$rstryFileList};
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'stryFileList', value => $rstryFileList}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# manifest - build path/file/link manifest starting with base path and including all subpaths
|
|
|
|
####################################################################################################################################
|
|
|
|
sub manifest
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathExp,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->manifest', \@_,
|
|
|
|
{name => 'strPathExp'},
|
|
|
|
);
|
|
|
|
|
|
|
|
my $hManifest = $self->driver()->manifest($self->pathGet($strPathExp));
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'hManifest', value => $hManifest, trace => true}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# move - move path/file
|
|
|
|
####################################################################################################################################
|
|
|
|
sub move
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strSourcePathFileExp,
|
|
|
|
$strDestinationPathFileExp,
|
|
|
|
$bPathCreate,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->move', \@_,
|
|
|
|
{name => 'strSourcePathExp'},
|
|
|
|
{name => 'strDestinationPathExp'},
|
|
|
|
{name => 'bPathCreate', optional => true, default => false, trace => true},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Set operation variables
|
|
|
|
$self->driver()->move(
|
|
|
|
$self->pathGet($strSourcePathFileExp), $self->pathGet($strDestinationPathFileExp), {bPathCreate => $bPathCreate});
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# openRead - open file for reading
|
|
|
|
####################################################################################################################################
|
|
|
|
sub openRead
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$xFileExp,
|
|
|
|
$bIgnoreMissing,
|
|
|
|
$rhyFilter,
|
2017-11-06 19:51:12 +02:00
|
|
|
$strCipherPass,
|
2017-06-09 23:51:41 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->openRead', \@_,
|
|
|
|
{name => 'xFileExp'},
|
|
|
|
{name => 'bIgnoreMissing', optional => true, default => false},
|
|
|
|
{name => 'rhyFilter', optional => true},
|
2017-11-06 19:51:12 +02:00
|
|
|
{name => 'strCipherPass', optional => true, redact => true},
|
2017-06-09 23:51:41 +02:00
|
|
|
);
|
|
|
|
|
2017-11-06 19:51:12 +02:00
|
|
|
# Open the file
|
2017-06-09 23:51:41 +02:00
|
|
|
my $oFileIo = $self->driver()->openRead($self->pathGet($xFileExp), {bIgnoreMissing => $bIgnoreMissing});
|
|
|
|
|
|
|
|
# Apply filters if file is defined
|
2017-11-06 19:51:12 +02:00
|
|
|
if (defined($oFileIo))
|
2017-06-09 23:51:41 +02:00
|
|
|
{
|
2017-11-06 19:51:12 +02:00
|
|
|
# If cipher is set then add the filter so that decryption is the first filter applied to the data read before any of the
|
|
|
|
# other filters
|
|
|
|
if (defined($self->cipherType()))
|
2017-06-09 23:51:41 +02:00
|
|
|
{
|
2017-11-06 19:51:12 +02:00
|
|
|
$oFileIo = &STORAGE_FILTER_CIPHER_BLOCK->new(
|
|
|
|
$oFileIo, $self->cipherType(), defined($strCipherPass) ? $strCipherPass : $self->cipherPassUser(),
|
|
|
|
{strMode => STORAGE_DECRYPT});
|
|
|
|
}
|
|
|
|
|
|
|
|
# Apply any other filters
|
|
|
|
if (defined($rhyFilter))
|
|
|
|
{
|
|
|
|
foreach my $rhFilter (@{$rhyFilter})
|
|
|
|
{
|
|
|
|
$oFileIo = $rhFilter->{strClass}->new($oFileIo, @{$rhFilter->{rxyParam}});
|
|
|
|
}
|
2017-06-09 23:51:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'oFileIo', value => $oFileIo, trace => true},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# openWrite - open file for writing
|
|
|
|
####################################################################################################################################
|
|
|
|
sub openWrite
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$xFileExp,
|
|
|
|
$strMode,
|
|
|
|
$strUser,
|
|
|
|
$strGroup,
|
|
|
|
$lTimestamp,
|
|
|
|
$bAtomic,
|
|
|
|
$bPathCreate,
|
|
|
|
$rhyFilter,
|
2017-11-06 19:51:12 +02:00
|
|
|
$strCipherPass,
|
2017-06-09 23:51:41 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->openWrite', \@_,
|
|
|
|
{name => 'xFileExp'},
|
|
|
|
{name => 'strMode', optional => true, default => $self->{strDefaultFileMode}},
|
|
|
|
{name => 'strUser', optional => true},
|
|
|
|
{name => 'strGroup', optional => true},
|
|
|
|
{name => 'lTimestamp', optional => true},
|
|
|
|
{name => 'bAtomic', optional => true, default => false},
|
|
|
|
{name => 'bPathCreate', optional => true, default => false},
|
|
|
|
{name => 'rhyFilter', optional => true},
|
2017-11-06 19:51:12 +02:00
|
|
|
{name => 'strCipherPass', optional => true, redact => true},
|
2017-06-09 23:51:41 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
# Open the file
|
|
|
|
my $oFileIo = $self->driver()->openWrite($self->pathGet($xFileExp),
|
|
|
|
{strMode => $strMode, strUser => $strUser, strGroup => $strGroup, lTimestamp => $lTimestamp, bPathCreate => $bPathCreate,
|
|
|
|
bAtomic => $bAtomic});
|
|
|
|
|
2017-11-06 19:51:12 +02:00
|
|
|
# If cipher is set then add filter so that encryption is performed just before the data is actually written
|
|
|
|
if (defined($self->cipherType()))
|
|
|
|
{
|
|
|
|
$oFileIo = &STORAGE_FILTER_CIPHER_BLOCK->new(
|
|
|
|
$oFileIo, $self->cipherType(), defined($strCipherPass) ? $strCipherPass : $self->cipherPassUser());
|
|
|
|
}
|
|
|
|
|
|
|
|
# Apply any other filters
|
2017-06-09 23:51:41 +02:00
|
|
|
if (defined($rhyFilter))
|
|
|
|
{
|
|
|
|
foreach my $rhFilter (reverse(@{$rhyFilter}))
|
|
|
|
{
|
|
|
|
$oFileIo = $rhFilter->{strClass}->new($oFileIo, @{$rhFilter->{rxyParam}});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'oFileIo', value => $oFileIo, trace => true},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# owner - change ownership of path/file
|
|
|
|
####################################################################################################################################
|
|
|
|
sub owner
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathFileExp,
|
|
|
|
$strUser,
|
|
|
|
$strGroup
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->owner', \@_,
|
|
|
|
{name => 'strPathFileExp'},
|
|
|
|
{name => 'strUser', required => false},
|
|
|
|
{name => 'strGroup', required => false}
|
|
|
|
);
|
|
|
|
|
|
|
|
# Set ownership
|
|
|
|
$self->driver()->owner($self->pathGet($strPathFileExp), {strUser => $strUser, strGroup => $strGroup});
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# pathCreate - create path
|
|
|
|
####################################################################################################################################
|
|
|
|
sub pathCreate
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathExp,
|
|
|
|
$strMode,
|
|
|
|
$bIgnoreExists,
|
|
|
|
$bCreateParent,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->pathCreate', \@_,
|
|
|
|
{name => 'strPathExp'},
|
|
|
|
{name => 'strMode', optional => true, default => $self->{strDefaultPathMode}},
|
|
|
|
{name => 'bIgnoreExists', optional => true, default => false},
|
|
|
|
{name => 'bCreateParent', optional => true, default => false},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Create path
|
|
|
|
$self->driver()->pathCreate(
|
|
|
|
$self->pathGet($strPathExp), {strMode => $strMode, bIgnoreExists => $bIgnoreExists, bCreateParent => $bCreateParent});
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# pathExists - check if path exists
|
|
|
|
####################################################################################################################################
|
|
|
|
sub pathExists
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathExp,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->pathExists', \@_,
|
|
|
|
{name => 'strPathExp'},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Check exists
|
|
|
|
my $bExists = $self->driver()->pathExists($self->pathGet($strPathExp));
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'bExists', value => $bExists}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# pathGet - resolve a path expression into an absolute path
|
|
|
|
####################################################################################################################################
|
|
|
|
sub pathGet
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathExp, # File that that needs to be translated to a path
|
|
|
|
$bTemp, # Return the temp file name
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->pathGet', \@_,
|
|
|
|
{name => 'strPathExp', required => false, trace => true},
|
|
|
|
{name => 'bTemp', optional => true, default => false, trace => true},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Path and file to be returned
|
|
|
|
my $strPath;
|
|
|
|
my $strFile;
|
|
|
|
|
|
|
|
# Is this an absolute path type?
|
|
|
|
my $bAbsolute = false;
|
|
|
|
|
|
|
|
if (defined($strPathExp) && index($strPathExp, qw(/)) == 0)
|
|
|
|
{
|
|
|
|
$bAbsolute = true;
|
|
|
|
$strPath = $strPathExp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
# Is it a rule type
|
|
|
|
if (defined($strPathExp) && index($strPathExp, qw(<)) == 0)
|
|
|
|
{
|
|
|
|
# Extract the rule type
|
|
|
|
my $iPos = index($strPathExp, qw(>));
|
|
|
|
|
|
|
|
if ($iPos == -1)
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, "found < but not > in '${strPathExp}'");
|
|
|
|
}
|
|
|
|
|
|
|
|
my $strType = substr($strPathExp, 0, $iPos + 1);
|
|
|
|
|
|
|
|
# Extract the filename
|
|
|
|
if ($iPos < length($strPathExp) - 1)
|
|
|
|
{
|
|
|
|
$strFile = substr($strPathExp, $iPos + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Lookup the rule
|
|
|
|
if (!defined($self->{hRule}->{$strType}))
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, "storage rule '${strType}' does not exist");
|
|
|
|
}
|
|
|
|
|
|
|
|
# If rule is a ref then call the function
|
|
|
|
if (ref($self->{hRule}->{$strType}))
|
|
|
|
{
|
|
|
|
$strPath = $self->pathBase();
|
|
|
|
$strFile = $self->{hRule}{$strType}{fnRule}->($strType, $strFile, $self->{hRule}{$strType}{xData});
|
|
|
|
}
|
|
|
|
# Else get the path
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$strPath = $self->pathBase() . ($self->pathBase() =~ /\/$/ ? '' : qw{/}) . $self->{hRule}->{$strType};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# Else it must be relative
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$strPath = $self->pathBase();
|
|
|
|
$strFile = $strPathExp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Make sure a temp file is valid for this type and file
|
|
|
|
if ($bTemp)
|
|
|
|
{
|
|
|
|
# Error when temp files are not allowed
|
|
|
|
if (!$self->{bAllowTemp})
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, "temp file not supported for storage '" . $self->pathBase() . "'");
|
|
|
|
}
|
|
|
|
|
|
|
|
# The file must be defined
|
|
|
|
if (!$bAbsolute)
|
|
|
|
{
|
|
|
|
if (!defined($strFile))
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, 'file part must be defined when temp file specified');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Combine path and file
|
|
|
|
$strPath .= defined($strFile) ? ($strPath =~ /\/$/ ? '' : qw{/}) . "${strFile}" : '';
|
|
|
|
|
|
|
|
# Add temp extension
|
|
|
|
$strPath .= $bTemp ? ".$self->{strTempExtension}" : '';
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'strPath', value => $strPath, trace => true}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
2018-05-01 17:05:37 +02:00
|
|
|
# Sync path so newly added file entries are not lost
|
2017-06-09 23:51:41 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
sub pathSync
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strPathExp,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->pathSync', \@_,
|
|
|
|
{name => 'strPathExp'},
|
|
|
|
);
|
|
|
|
|
2018-05-01 17:05:37 +02:00
|
|
|
$self->driver()->pathSync($self->pathGet($strPathExp));
|
2017-06-09 23:51:41 +02:00
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn($strOperation);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# remove - remove path/file
|
|
|
|
####################################################################################################################################
|
|
|
|
sub remove
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$xstryPathFileExp,
|
|
|
|
$bIgnoreMissing,
|
|
|
|
$bRecurse,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->remove', \@_,
|
2017-07-25 18:44:38 +02:00
|
|
|
{name => 'xstryPathFileExp'},
|
2017-06-09 23:51:41 +02:00
|
|
|
{name => 'bIgnoreMissing', optional => true, default => true},
|
|
|
|
{name => 'bRecurse', optional => true, default => false, trace => true},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Evaluate expressions for all files
|
|
|
|
my @stryPathFileExp;
|
|
|
|
|
|
|
|
if (ref($xstryPathFileExp))
|
|
|
|
{
|
|
|
|
foreach my $strPathFileExp (@{$xstryPathFileExp})
|
|
|
|
{
|
|
|
|
push(@stryPathFileExp, $self->pathGet($strPathFileExp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Remove path(s)/file(s)
|
|
|
|
my $bRemoved = $self->driver()->remove(
|
|
|
|
ref($xstryPathFileExp) ? \@stryPathFileExp : $self->pathGet($xstryPathFileExp),
|
|
|
|
{bIgnoreMissing => $bIgnoreMissing, bRecurse => $bRecurse});
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'bRemoved', value => $bRemoved}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-11-06 19:51:12 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# encrypted - determine if the file is encrypted or not
|
|
|
|
####################################################################################################################################
|
|
|
|
sub encrypted
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strFileName,
|
|
|
|
$bIgnoreMissing,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->encrypted', \@_,
|
|
|
|
{name => 'strFileName'},
|
|
|
|
{name => 'bIgnoreMissing', optional => true, default => false},
|
|
|
|
);
|
|
|
|
|
|
|
|
my $tMagicSignature;
|
|
|
|
my $bEncrypted = false;
|
|
|
|
|
|
|
|
# Open the file via the driver
|
|
|
|
my $oFile = $self->driver()->openRead($self->pathGet($strFileName), {bIgnoreMissing => $bIgnoreMissing});
|
|
|
|
|
|
|
|
# If the file does not exist because we're ignoring missing (else it would error before this is executed) then determine if it
|
|
|
|
# should be encrypted based on the repo
|
|
|
|
if (!defined($oFile))
|
|
|
|
{
|
|
|
|
if (defined($self->{strCipherType}))
|
|
|
|
{
|
|
|
|
$bEncrypted = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
# If the file does exist, then read the magic signature
|
|
|
|
my $lSizeRead = $oFile->read(\$tMagicSignature, length(CIPHER_MAGIC));
|
|
|
|
|
|
|
|
# Close the file handle
|
|
|
|
$oFile->close();
|
|
|
|
|
|
|
|
# If the file is able to be read, then if it is encrypted it must at least have the magic signature, even if it were
|
|
|
|
# originally a 0 byte file
|
|
|
|
if (($lSizeRead > 0) && substr($tMagicSignature, 0, length(CIPHER_MAGIC)) eq CIPHER_MAGIC)
|
|
|
|
{
|
|
|
|
$bEncrypted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'bEncrypted', value => $bEncrypted}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# encryptionValid - determine if encyption set properly based on the value passed
|
|
|
|
####################################################################################################################################
|
|
|
|
sub encryptionValid
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$bEncrypted,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->encryptionValid', \@_,
|
|
|
|
{name => 'bEncrypted'},
|
|
|
|
);
|
|
|
|
|
|
|
|
my $bValid = true;
|
|
|
|
|
|
|
|
# If encryption is set on the file then make sure the repo is encrypted and visa-versa
|
|
|
|
if ($bEncrypted)
|
|
|
|
{
|
|
|
|
if (!defined($self->{strCipherType}))
|
|
|
|
{
|
|
|
|
$bValid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (defined($self->{strCipherType}))
|
|
|
|
{
|
|
|
|
$bValid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'bValid', value => $bValid}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# Getters
|
|
|
|
####################################################################################################################################
|
|
|
|
sub pathBase {shift->{strPathBase}}
|
|
|
|
sub driver {shift->{oDriver}}
|
2017-11-06 19:51:12 +02:00
|
|
|
sub cipherType {shift->{strCipherType}}
|
|
|
|
sub cipherPassUser {shift->{strCipherPassUser}}
|
2017-06-09 23:51:41 +02:00
|
|
|
|
|
|
|
1;
|