1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2026-05-22 10:15:16 +02:00
Files
pgbackrest/src/command/archive/get/file.c
T
David Steele 6c23830991 Add encryption capability to Info* objects.
Info objects can be stored encrypted and loaded with a cipher type and passphrase.
2018-11-28 14:41:10 -05:00

147 lines
5.7 KiB
C

/***********************************************************************************************************************************
Archive Get File
***********************************************************************************************************************************/
#include "command/archive/get/file.h"
#include "command/archive/common.h"
#include "command/control/control.h"
#include "common/debug.h"
#include "common/io/filter/group.h"
#include "common/log.h"
#include "compress/gzip.h"
#include "compress/gzipDecompress.h"
#include "config/config.h"
#include "crypto/crypto.h"
#include "info/infoArchive.h"
#include "postgres/interface.h"
#include "storage/helper.h"
#include "storage/helper.h"
/***********************************************************************************************************************************
Check if a WAL file exists in the repository
***********************************************************************************************************************************/
static String *
archiveGetCheck(const String *archiveFile)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, archiveFile);
FUNCTION_TEST_ASSERT(archiveFile != NULL);
FUNCTION_DEBUG_END();
String *result = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
// Get pg control info
PgControl controlInfo = pgControlFromFile(cfgOptionStr(cfgOptPgPath));
// Attempt to load the archive info file
InfoArchive *info = infoArchiveNew(
storageRepo(), STRING_CONST(STORAGE_REPO_ARCHIVE "/" INFO_ARCHIVE_FILE), false, cipherTypeNone, NULL);
// Loop through the pg history in case the WAL we need is not in the most recent archive id
String *archiveId = NULL;
const String *archiveFileActual = NULL;
for (unsigned int pgIdx = 0; pgIdx < infoPgDataTotal(infoArchivePg(info)); pgIdx++)
{
InfoPgData pgData = infoPgData(infoArchivePg(info), pgIdx);
// Only use the archive id if it matches the current cluster
if (pgData.systemId == controlInfo.systemId && pgData.version == controlInfo.version)
{
archiveId = infoPgArchiveId(infoArchivePg(info), pgIdx);
// If a WAL segment search among the possible file names
if (walIsSegment(archiveFile))
{
String *walSegmentFile = walSegmentFind(storageRepo(), archiveId, archiveFile);
if (walSegmentFile != NULL)
{
archiveFileActual = strNewFmt("%s/%s", strPtr(strSubN(archiveFile, 0, 16)), strPtr(walSegmentFile));
break;
}
}
// Else if not a WAL segment, see if it exists in the archive dir
else if (
storageExistsNP(
storageRepo(), strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strPtr(archiveId), strPtr(archiveFile))))
{
archiveFileActual = archiveFile;
break;
}
}
}
// Error if no archive id was found -- this indicates a mismatch with the current cluster
if (archiveId == NULL)
{
THROW_FMT(
ArchiveMismatchError, "unable to retrieve the archive id for database version '%s' and system-id '%" PRIu64 "'",
strPtr(pgVersionToStr(controlInfo.version)), controlInfo.systemId);
}
if (archiveFileActual != NULL)
{
memContextSwitch(MEM_CONTEXT_OLD());
result = strNewFmt("%s/%s", strPtr(archiveId), strPtr(archiveFileActual));
}
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT(STRING, result);
}
/***********************************************************************************************************************************
Copy a file from the archive to the specified destination
***********************************************************************************************************************************/
int
archiveGetFile(const String *archiveFile, const String *walDestination)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, archiveFile);
FUNCTION_DEBUG_PARAM(STRING, walDestination);
FUNCTION_TEST_ASSERT(archiveFile != NULL);
FUNCTION_TEST_ASSERT(walDestination != NULL);
FUNCTION_DEBUG_END();
// By default result indicates WAL segment not found
int result = 1;
// Test for stop file
lockStopTest();
MEM_CONTEXT_TEMP_BEGIN()
{
// Make sure the file exists and other checks pass
String *archiveFileActual = archiveGetCheck(archiveFile);
if (archiveFileActual != NULL)
{
StorageFileWrite *destination = storageNewWriteP(
storageLocalWrite(), walDestination, .noCreatePath = true, .noSyncFile = true, .noSyncPath = true,
.noAtomic = true);
// If file is gzipped then add the decompression filter
if (strEndsWithZ(archiveFileActual, "." GZIP_EXT))
{
IoFilterGroup *filterGroup = ioFilterGroupNew();
ioFilterGroupAdd(filterGroup, gzipDecompressFilter(gzipDecompressNew(false)));
ioWriteFilterGroupSet(storageFileWriteIo(destination), filterGroup);
}
// Copy the file
storageCopyNP(
storageNewReadNP(storageRepo(), strNewFmt("%s/%s", STORAGE_REPO_ARCHIVE, strPtr(archiveFileActual))), destination);
// The WAL file was found
result = 0;
}
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT(INT, result);
}