You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-10-23 21:28:56 +03:00
Pass a cipher spec rather than a type and passphrase.
The cipher type and passphrase were separate parameters in every function that reads or writes an encrypted file, every info file load and save, and every protocol message that hands a file to a local process. Anything added alongside them meant changing all of it again. A cipher spec keeps them together. The pass is a buffer rather than a string so an absent pass is simply NULL, and it is copied into the object so the caller is free to release whatever it was read from. The spec is packed and unpacked as a unit for the protocol and writes nothing but the type when there is no cipher. The digest the key derives with was a parameter of the block cipher filter, packed with every filter that crossed the protocol, and nothing but the tests ever set it. It is gone and the key derives with SHA-1 where that happens, since the spec is where the choice would go if there is ever more than one. The specs form a chain. cfgCipherSpecMainIdx() builds one from the options and caches it per repository, the info files are read with that, and each info file carries the spec for the files that depend on it, so nothing below the info files consults the options again. The cache is filled the first time a spec is asked for, so a command has to get the repo storage before then, since that is what pulls the cipher options down from a remote repository. An info file stores a pass but not a type, so the spec it carries takes the type of the spec the file was read with. That spec is never NULL, and is none when the file has no pass, so it can be handed on without a check. A spec is named for what it opens: cipherSpecMain from the configuration, cipherSpecArchive from archive.info, cipherSpecManifest from backup.info, and cipherSpecBackup from the manifest. That turned up names that said the opposite of what they held, since what backup called the backup passphrase is what opens manifests, and restore documented the passphrase it loads the manifest with as being for backup files. The test harness takes a spec as well, so the storage and backup harnesses no longer accept a type and pass pair, and the rule that a missing pass meant the main test pass is now spelled out in TEST_CIPHER_SPEC.
This commit is contained in:
@@ -52,6 +52,17 @@
|
||||
</release-improvement-list>
|
||||
|
||||
<release-development-list>
|
||||
<release-item>
|
||||
<github-pull-request id="2826"/>
|
||||
|
||||
<release-item-contributor-list>
|
||||
<release-item-contributor id="david.steele"/>
|
||||
<release-item-reviewer id="douglas.j.hunley"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Pass a cipher spec rather than a type and passphrase.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<github-pull-request id="2817"/>
|
||||
|
||||
|
||||
@@ -56,11 +56,8 @@ cmdAnnotate(void)
|
||||
storageRepoIdx(repoIdx);
|
||||
|
||||
// Attempt to load the backup info file
|
||||
const CipherType repoCipherType = cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx);
|
||||
|
||||
InfoBackup *infoBackup = infoBackupLoadFileReconstruct(
|
||||
storageRepoIdx(repoIdx), INFO_BACKUP_PATH_FILE_STR, repoCipherType,
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
storageRepoIdx(repoIdx), INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
if (infoBackupLabelExists(infoBackup, backupLabel))
|
||||
{
|
||||
@@ -75,9 +72,7 @@ cmdAnnotate(void)
|
||||
infoBackupDataAnnotationSet(infoBackup, backupLabel, cfgOptionKv(cfgOptAnnotation));
|
||||
|
||||
// Write the updated backup info
|
||||
infoBackupSaveFile(
|
||||
infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, repoCipherType,
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
}
|
||||
}
|
||||
CATCH_ANY()
|
||||
|
||||
@@ -54,11 +54,11 @@ archiveGetFile(
|
||||
storage, walDestination, .noCreatePath = true, .noSyncFile = true, .noSyncPath = true, .noAtomic = true);
|
||||
|
||||
// If there is a cipher then add the decrypt filter
|
||||
if (actual->cipherType != cipherTypeNone)
|
||||
if (cipherSpecType(actual->cipherSpecArchive) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioWriteFilterGroup(storageWriteIo(destination)),
|
||||
cipherBlockNewP(cipherModeDecrypt, actual->cipherType, BUFSTR(actual->cipherPassArchive)));
|
||||
cipherBlockNewP(cipherModeDecrypt, actual->cipherSpecArchive));
|
||||
compressible = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Archive Get File
|
||||
#ifndef COMMAND_ARCHIVE_GET_FILE_H
|
||||
#define COMMAND_ARCHIVE_GET_FILE_H
|
||||
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/type/string.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
@@ -17,8 +17,7 @@ typedef struct ArchiveGetFile
|
||||
const String *file; // File in the repo (with path, checksum, ext, etc.)
|
||||
unsigned int repoIdx; // Repo idx
|
||||
const String *archiveId; // Repo archive id
|
||||
CipherType cipherType; // Repo cipher type
|
||||
const String *cipherPassArchive; // Repo archive cipher pass
|
||||
const CipherSpec *cipherSpecArchive; // Repo archive cipher spec
|
||||
} ArchiveGetFile;
|
||||
|
||||
typedef struct ArchiveGetFileResult
|
||||
|
||||
@@ -94,8 +94,7 @@ typedef struct ArchiveGetFindCacheArchive
|
||||
typedef struct ArchiveGetFindCacheRepo
|
||||
{
|
||||
unsigned int repoIdx;
|
||||
CipherType cipherType; // Repo cipher type
|
||||
const String *cipherPassArchive; // Repo archive cipher pass
|
||||
const CipherSpec *cipherSpecArchive; // Repo archive cipher spec
|
||||
List *archiveList; // Cached list of archiveIds and associated paths
|
||||
StringList *warnList; // Track repo warnings so each is only reported once
|
||||
} ArchiveGetFindCacheRepo;
|
||||
@@ -213,8 +212,7 @@ archiveGetFind(
|
||||
strZ(strLstGet(segmentList, segmentIdx))),
|
||||
.repoIdx = cacheRepo->repoIdx,
|
||||
.archiveId = cacheArchive->archiveId,
|
||||
.cipherType = cacheRepo->cipherType,
|
||||
.cipherPassArchive = cacheRepo->cipherPassArchive,
|
||||
.cipherSpecArchive = cacheRepo->cipherSpecArchive,
|
||||
};
|
||||
|
||||
lstAdd(matchList, &archiveGetFile);
|
||||
@@ -235,8 +233,7 @@ archiveGetFind(
|
||||
.file = strNewFmt("%s/%s", strZ(cacheArchive->archiveId), strZ(archiveFileRequest)),
|
||||
.repoIdx = cacheRepo->repoIdx,
|
||||
.archiveId = cacheArchive->archiveId,
|
||||
.cipherType = cacheRepo->cipherType,
|
||||
.cipherPassArchive = cacheRepo->cipherPassArchive,
|
||||
.cipherSpecArchive = cacheRepo->cipherSpecArchive,
|
||||
};
|
||||
|
||||
lstAdd(matchList, &archiveGetFile);
|
||||
@@ -408,20 +405,18 @@ archiveGetCheck(const StringList *const archiveRequestList)
|
||||
ArchiveGetFindCacheRepo cacheRepo =
|
||||
{
|
||||
.repoIdx = repoIdx,
|
||||
.cipherType = cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
.archiveList = lstNewP(sizeof(ArchiveGetFindCacheArchive)),
|
||||
.warnList = strLstNew(),
|
||||
};
|
||||
|
||||
// Attempt to load the archive info file
|
||||
const InfoArchive *const info = infoArchiveLoadFile(
|
||||
storageRepoIdx(repoIdx), INFO_ARCHIVE_PATH_FILE_STR, cacheRepo.cipherType,
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
storageRepoIdx(repoIdx), INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
// Copy cipher pass into the result list context once rather than making a copy per candidate file later
|
||||
// Build cipher spec in the result list context once rather than rebuilding it per candidate file later
|
||||
MEM_CONTEXT_BEGIN(lstMemContext(result.archiveFileMapList))
|
||||
{
|
||||
cacheRepo.cipherPassArchive = strDup(infoArchiveCipherPass(info));
|
||||
cacheRepo.cipherSpecArchive = cipherSpecDup(infoArchiveCipherSpec(info));
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
|
||||
@@ -933,8 +928,7 @@ archiveGetAsyncCallback(void *const data, const unsigned int clientIdx)
|
||||
pckWriteStrP(param, actual->file);
|
||||
pckWriteU32P(param, actual->repoIdx);
|
||||
pckWriteStrP(param, actual->archiveId);
|
||||
pckWriteU64P(param, actual->cipherType);
|
||||
pckWriteStrP(param, actual->cipherPassArchive);
|
||||
cipherSpecPack(param, actual->cipherSpecArchive);
|
||||
}
|
||||
|
||||
MEM_CONTEXT_PRIOR_BEGIN()
|
||||
|
||||
@@ -38,8 +38,7 @@ archiveGetFileProtocol(PackRead *const param)
|
||||
ArchiveGetFile actual = {.file = pckReadStrP(param)};
|
||||
actual.repoIdx = pckReadU32P(param);
|
||||
actual.archiveId = pckReadStrP(param);
|
||||
actual.cipherType = pckReadU64P(param);
|
||||
actual.cipherPassArchive = pckReadStrP(param);
|
||||
actual.cipherSpecArchive = cipherSpecNewPack(param);
|
||||
|
||||
lstAdd(actualList, &actual);
|
||||
}
|
||||
|
||||
@@ -266,11 +266,11 @@ archivePushFile(
|
||||
.compressible = compressible);
|
||||
|
||||
// If there is a cipher then add the encrypt filter
|
||||
if (repoData->cipherType != cipherTypeNone)
|
||||
if (cipherSpecType(repoData->cipherSpecArchive) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioWriteFilterGroup(storageWriteIo(destination[repoListIdx])),
|
||||
cipherBlockNewP(cipherModeEncrypt, repoData->cipherType, BUFSTR(repoData->cipherPass)));
|
||||
cipherBlockNewP(cipherModeEncrypt, repoData->cipherSpecArchive));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ Archive Push File
|
||||
#define COMMAND_ARCHIVE_PUSH_FILE_H
|
||||
|
||||
#include "common/compress/helper.h"
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/type/string.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
@@ -17,8 +17,7 @@ typedef struct ArchivePushFileRepoData
|
||||
{
|
||||
unsigned int repoIdx;
|
||||
const String *archiveId;
|
||||
CipherType cipherType;
|
||||
const String *cipherPass;
|
||||
const CipherSpec *cipherSpecArchive; // Repo archive cipher spec
|
||||
} ArchivePushFileRepoData;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
|
||||
@@ -48,8 +48,7 @@ archivePushFileProtocol(PackRead *const param)
|
||||
|
||||
ArchivePushFileRepoData repo = {.repoIdx = pckReadU32P(param)};
|
||||
repo.archiveId = pckReadStrP(param);
|
||||
repo.cipherType = pckReadU64P(param);
|
||||
repo.cipherPass = pckReadStrP(param);
|
||||
repo.cipherSpecArchive = cipherSpecNewPack(param);
|
||||
pckReadObjEndP(param);
|
||||
|
||||
lstAdd(repoList, &repo);
|
||||
|
||||
@@ -230,13 +230,9 @@ archivePushCheck(const bool pgPathSet)
|
||||
// Get the repo storage in case it is remote and encryption settings need to be pulled down
|
||||
storageRepoIdx(repoIdx);
|
||||
|
||||
// Get cipher type
|
||||
const CipherType repoCipherType = cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx);
|
||||
|
||||
// Attempt to load the archive info file
|
||||
const InfoArchive *const info = infoArchiveLoadFile(
|
||||
storageRepoIdx(repoIdx), INFO_ARCHIVE_PATH_FILE_STR, repoCipherType,
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
storageRepoIdx(repoIdx), INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
// Get archive id for the most recent version -- archive-push will only operate against the most recent version
|
||||
const String *const archiveId = infoPgArchiveId(infoArchivePg(info), infoPgDataCurrentId(infoArchivePg(info)));
|
||||
@@ -268,8 +264,7 @@ archivePushCheck(const bool pgPathSet)
|
||||
{
|
||||
.repoIdx = repoIdx,
|
||||
.archiveId = strDup(archiveId),
|
||||
.cipherType = repoCipherType,
|
||||
.cipherPass = strDup(infoArchiveCipherPass(info)),
|
||||
.cipherSpecArchive = cipherSpecDup(infoArchiveCipherSpec(info)),
|
||||
};
|
||||
|
||||
lstAdd(result.repoList, &archivePushFileRepoData);
|
||||
@@ -493,8 +488,7 @@ archivePushAsyncCallback(void *const data, const unsigned int clientIdx)
|
||||
pckWriteObjBeginP(param);
|
||||
pckWriteU32P(param, data->repoIdx);
|
||||
pckWriteStrP(param, data->archiveId);
|
||||
pckWriteU64P(param, data->cipherType);
|
||||
pckWriteStrP(param, data->cipherPass);
|
||||
cipherSpecPack(param, data->cipherSpecArchive);
|
||||
pckWriteObjEndP(param);
|
||||
}
|
||||
|
||||
|
||||
@@ -165,9 +165,7 @@ backupInit(const InfoBackup *const infoBackup)
|
||||
// Get archive info
|
||||
if (cfgOptionBool(cfgOptArchiveCheck))
|
||||
{
|
||||
result->archiveInfo = infoArchiveLoadFile(
|
||||
storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cfgOptionStrId(cfgOptRepoCipherType),
|
||||
cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
result->archiveInfo = infoArchiveLoadFile(storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMain());
|
||||
result->archiveId = infoArchiveId(result->archiveInfo);
|
||||
}
|
||||
|
||||
@@ -207,10 +205,9 @@ cmdBackup(void)
|
||||
storageRepo();
|
||||
|
||||
// Load backup.info
|
||||
InfoBackup *const infoBackup = infoBackupLoadFileReconstruct(
|
||||
storageRepo(), INFO_BACKUP_PATH_FILE_STR, cfgOptionStrId(cfgOptRepoCipherType), cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
InfoBackup *const infoBackup = infoBackupLoadFileReconstruct(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMain());
|
||||
const InfoPgData infoPg = infoPgDataCurrent(infoBackupPg(infoBackup));
|
||||
const String *const cipherPassBackup = infoPgCipherPass(infoBackupPg(infoBackup));
|
||||
const CipherSpec *const cipherSpecManifest = infoBackupCipherSpec(infoBackup);
|
||||
|
||||
// Get pg storage and database objects
|
||||
BackupData *const backupData = backupInit(infoBackup);
|
||||
@@ -239,14 +236,14 @@ cmdBackup(void)
|
||||
|
||||
// Build an incremental backup if type is not full (manifestPrior will be freed in this call)
|
||||
if (!backupBuildIncr(infoBackup, manifest, manifestPrior, backupStartResult.walSegmentName))
|
||||
manifestCipherSubPassSet(manifest, cipherPassGen(cfgOptionStrId(cfgOptRepoCipherType)));
|
||||
manifestCipherSpecSet(manifest, cipherSpecGen(cfgOptionStrId(cfgOptRepoCipherType)));
|
||||
|
||||
// Set delta if it is not already set and the manifest requires it
|
||||
if (!cfgOptionBool(cfgOptDelta) && varBool(manifestData(manifest)->backupOptionDelta))
|
||||
cfgOptionSet(cfgOptDelta, cfgSourceParam, BOOL_TRUE_VAR);
|
||||
|
||||
// Resume a backup when possible
|
||||
if (!backupResume(manifest, cipherPassBackup))
|
||||
if (!backupResume(manifest, cipherSpecManifest))
|
||||
{
|
||||
manifestBackupLabelSet(
|
||||
manifest,
|
||||
@@ -255,10 +252,10 @@ cmdBackup(void)
|
||||
}
|
||||
|
||||
// Save the manifest before processing starts
|
||||
backupManifestSaveCopy(manifest, cipherPassBackup, false);
|
||||
backupManifestSaveCopy(manifest, cipherSpecManifest, false);
|
||||
|
||||
// Process the backup manifest
|
||||
backupProcess(backupData, manifest, cipherPassBackup);
|
||||
backupProcess(backupData, manifest, cipherSpecManifest);
|
||||
|
||||
// Check that the clusters are alive and correctly configured after the backup
|
||||
backupDbPing(backupData, true);
|
||||
@@ -286,7 +283,7 @@ cmdBackup(void)
|
||||
dbFree(backupData->dbPrimary);
|
||||
|
||||
// Check and copy WAL segments required to make the backup consistent
|
||||
backupArchiveCheckCopy(backupData, manifest, cipherPassBackup);
|
||||
backupArchiveCheckCopy(backupData, manifest, cipherSpecManifest);
|
||||
|
||||
// The primary protocol connection won't be used anymore so free it. This needs to happen after backupArchiveCheckCopy() so
|
||||
// the backup lock is held on the remote which allows conditional archiving based on the backup lock. Any further access to
|
||||
|
||||
@@ -3,11 +3,11 @@ Save a copy of the backup manifest during processing to preserve checksums for a
|
||||
resume is disabled since an incremental copy will not be used in a future backup unless resume is enabled beforehand.
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
backupManifestSaveCopy(Manifest *const manifest, const String *const cipherPassBackup, const bool final)
|
||||
backupManifestSaveCopy(Manifest *const manifest, const CipherSpec *const cipherSpecManifest, const bool final)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(MANIFEST, manifest);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPassBackup);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecManifest);
|
||||
FUNCTION_LOG_PARAM(BOOL, final);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
@@ -25,8 +25,7 @@ backupManifestSaveCopy(Manifest *const manifest, const String *const cipherPassB
|
||||
STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strZ(manifestData(manifest)->backupLabel))));
|
||||
|
||||
// Add encryption filter if required
|
||||
cipherBlockFilterGroupAdd(
|
||||
ioWriteFilterGroup(write), cfgOptionStrId(cfgOptRepoCipherType), cipherModeEncrypt, cipherPassBackup);
|
||||
cipherBlockFilterGroupAdd(ioWriteFilterGroup(write), cipherModeEncrypt, cipherSpecManifest);
|
||||
|
||||
// Save file
|
||||
manifestSave(manifest, write);
|
||||
@@ -41,12 +40,12 @@ backupManifestSaveCopy(Manifest *const manifest, const String *const cipherPassB
|
||||
Check and copy WAL segments required to make the backup consistent
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
backupArchiveCheckCopy(const BackupData *const backupData, Manifest *const manifest, const String *const cipherPassBackup)
|
||||
backupArchiveCheckCopy(const BackupData *const backupData, Manifest *const manifest, const CipherSpec *const cipherSpecManifest)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(BACKUP_DATA, backupData);
|
||||
FUNCTION_LOG_PARAM(MANIFEST, manifest);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPassBackup);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecManifest);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(manifest != NULL);
|
||||
@@ -67,7 +66,7 @@ backupArchiveCheckCopy(const BackupData *const backupData, Manifest *const manif
|
||||
strZ(pgLsnToWalSegment(backupData->timeline, lsnStop, backupData->walSegmentSize)));
|
||||
|
||||
// Save the backup manifest before getting archive logs in case of failure
|
||||
backupManifestSaveCopy(manifest, cipherPassBackup, false);
|
||||
backupManifestSaveCopy(manifest, cipherSpecManifest, false);
|
||||
|
||||
// Use base path to set ownership and mode
|
||||
const ManifestPath *const basePath = manifestPathFind(manifest, MANIFEST_TARGET_PGDATA_STR);
|
||||
@@ -103,8 +102,7 @@ backupArchiveCheckCopy(const BackupData *const backupData, Manifest *const manif
|
||||
|
||||
// Decrypt with archive key if encrypted
|
||||
cipherBlockFilterGroupAdd(
|
||||
filterGroup, cfgOptionStrId(cfgOptRepoCipherType), cipherModeDecrypt,
|
||||
infoArchiveCipherPass(backupData->archiveInfo));
|
||||
filterGroup, cipherModeDecrypt, infoArchiveCipherSpec(backupData->archiveInfo));
|
||||
|
||||
// Compress/decompress if archive and backup do not have the same compression settings
|
||||
if (archiveCompressType != backupCompressType)
|
||||
@@ -121,7 +119,7 @@ backupArchiveCheckCopy(const BackupData *const backupData, Manifest *const manif
|
||||
|
||||
// Encrypt with backup key if encrypted
|
||||
cipherBlockFilterGroupAdd(
|
||||
filterGroup, cfgOptionStrId(cfgOptRepoCipherType), cipherModeEncrypt, manifestCipherSubPass(manifest));
|
||||
filterGroup, cipherModeEncrypt, manifestCipherSpec(manifest));
|
||||
|
||||
// Add size filter last to calculate repo size
|
||||
ioFilterGroupAdd(filterGroup, ioSizeNew());
|
||||
@@ -188,7 +186,7 @@ backupComplete(InfoBackup *const infoBackup, Manifest *const manifest)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
manifestValidate(manifest, true);
|
||||
|
||||
backupManifestSaveCopy(manifest, infoPgCipherPass(infoBackupPg(infoBackup)), true);
|
||||
backupManifestSaveCopy(manifest, infoBackupCipherSpec(infoBackup), true);
|
||||
|
||||
storageCopy(
|
||||
storageNewReadP(
|
||||
@@ -204,8 +202,7 @@ backupComplete(InfoBackup *const infoBackup, Manifest *const manifest)
|
||||
storageRepo(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupLabel)));
|
||||
|
||||
cipherBlockFilterGroupAdd(
|
||||
ioReadFilterGroup(storageReadIo(manifestRead)), cfgOptionStrId(cfgOptRepoCipherType), cipherModeDecrypt,
|
||||
infoPgCipherPass(infoBackupPg(infoBackup)));
|
||||
ioReadFilterGroup(storageReadIo(manifestRead)), cipherModeDecrypt, infoBackupCipherSpec(infoBackup));
|
||||
|
||||
StorageWrite *const manifestWrite = storageNewWriteP(
|
||||
storageRepoWrite(),
|
||||
@@ -216,8 +213,7 @@ backupComplete(InfoBackup *const infoBackup, Manifest *const manifest)
|
||||
ioFilterGroupAdd(ioWriteFilterGroup(storageWriteIo(manifestWrite)), compressFilterP(compressTypeGz, 9));
|
||||
|
||||
cipherBlockFilterGroupAdd(
|
||||
ioWriteFilterGroup(storageWriteIo(manifestWrite)), cfgOptionStrId(cfgOptRepoCipherType), cipherModeEncrypt,
|
||||
infoPgCipherPass(infoBackupPg(infoBackup)));
|
||||
ioWriteFilterGroup(storageWriteIo(manifestWrite)), cipherModeEncrypt, infoBackupCipherSpec(infoBackup));
|
||||
|
||||
storageCopyP(manifestRead, manifestWrite);
|
||||
|
||||
@@ -233,19 +229,13 @@ backupComplete(InfoBackup *const infoBackup, Manifest *const manifest)
|
||||
// Add manifest and save backup.info (infoBackupSaveFile() is responsible for proper syncing)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
infoBackupDataAdd(infoBackup, manifest);
|
||||
|
||||
infoBackupSaveFile(
|
||||
infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cfgOptionStrId(cfgOptRepoCipherType),
|
||||
cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMain());
|
||||
|
||||
// Save archive.info/copy so the timestamps will be updated to prevent lifecycle settings from removing the files early
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
infoArchiveSaveFile(
|
||||
infoArchiveLoadFile(
|
||||
storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cfgOptionStrId(cfgOptRepoCipherType),
|
||||
cfgOptionStrNull(cfgOptRepoCipherPass)),
|
||||
storageRepoWrite(), INFO_ARCHIVE_PATH_FILE_STR, cfgOptionStrId(cfgOptRepoCipherType),
|
||||
cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
infoArchiveLoadFile(storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMain()), storageRepoWrite(),
|
||||
INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMain());
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
|
||||
@@ -221,12 +221,10 @@ backupFilePut(
|
||||
}
|
||||
|
||||
// Add encryption filter if required
|
||||
if (manifestCipherSubPass(manifest) != NULL)
|
||||
if (cipherSpecType(manifestCipherSpec(manifest)) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioWriteFilterGroup(storageWriteIo(write)),
|
||||
cipherBlockNewP(
|
||||
cipherModeEncrypt, cfgOptionStrId(cfgOptRepoCipherType), BUFSTR(manifestCipherSubPass(manifest))));
|
||||
ioWriteFilterGroup(storageWriteIo(write)), cipherBlockNewP(cipherModeEncrypt, manifestCipherSpec(manifest)));
|
||||
|
||||
repoChecksum = true;
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ typedef struct BackupFileResult
|
||||
static List *
|
||||
backupFile(
|
||||
const String *const repoFile, const uint64_t bundleId, const bool bundleRaw, const unsigned int blockIncrReference,
|
||||
const CompressType repoFileCompressType, const int repoFileCompressLevel, const CipherType cipherType,
|
||||
const String *const cipherPass, const String *const pgVersionForce, const PgPageSize pageSize, const List *const fileList)
|
||||
const CompressType repoFileCompressType, const int repoFileCompressLevel, const CipherSpec *const cipherSpecBackup,
|
||||
const String *const pgVersionForce, const PgPageSize pageSize, const List *const fileList)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING, repoFile); // Repo file
|
||||
@@ -66,15 +66,14 @@ backupFile(
|
||||
FUNCTION_LOG_PARAM(UINT, blockIncrReference); // Block incremental reference to use in map
|
||||
FUNCTION_LOG_PARAM(ENUM, repoFileCompressType); // Compress type for repo file
|
||||
FUNCTION_LOG_PARAM(INT, repoFileCompressLevel); // Compression level for repo file
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType); // Encryption type
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass); // Password to access the repo file if encrypted
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecBackup); // Cipher spec to encrypt the backup file
|
||||
FUNCTION_LOG_PARAM(ENUM, pageSize); // Page size
|
||||
FUNCTION_LOG_PARAM(STRING, pgVersionForce); // Force pg version
|
||||
FUNCTION_LOG_PARAM(LIST, fileList); // List of files to backup
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(repoFile != NULL);
|
||||
ASSERT((cipherType == cipherTypeNone && cipherPass == NULL) || (cipherType != cipherTypeNone && cipherPass != NULL));
|
||||
ASSERT(cipherSpecBackup != NULL);
|
||||
ASSERT(fileList != NULL && !lstEmpty(fileList));
|
||||
ASSERT(pgPageSizeValid(pageSize));
|
||||
|
||||
@@ -217,7 +216,7 @@ backupFile(
|
||||
}
|
||||
|
||||
// Are the files compressible during the copy?
|
||||
const bool compressible = repoFileCompressType == compressTypeNone && cipherType == cipherTypeNone;
|
||||
const bool compressible = repoFileCompressType == compressTypeNone && cipherSpecType(cipherSpecBackup) == cipherTypeNone;
|
||||
|
||||
// Copy files that need to be copied
|
||||
StorageWrite *write = NULL;
|
||||
@@ -276,9 +275,9 @@ backupFile(
|
||||
|
||||
// Encrypt filter
|
||||
IoFilter *const encrypt =
|
||||
cipherType != cipherTypeNone ?
|
||||
cipherSpecType(cipherSpecBackup) != cipherTypeNone ?
|
||||
cipherBlockNewP(
|
||||
cipherModeEncrypt, cipherType, BUFSTR(cipherPass), .raw = bundleRaw || file->blockIncrSize != 0) :
|
||||
cipherModeEncrypt, cipherSpecBackup, .raw = bundleRaw || file->blockIncrSize != 0) :
|
||||
NULL;
|
||||
|
||||
// If block incremental then add the filter and pass compress/encrypt filters to it since each block is
|
||||
@@ -293,11 +292,11 @@ backupFile(
|
||||
blockMap = bufNew(0);
|
||||
IoWrite *const blockMapWrite = ioBufferWriteNew(blockMap);
|
||||
|
||||
if (cipherType != cipherTypeNone)
|
||||
if (cipherSpecType(cipherSpecBackup) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioWriteFilterGroup(blockMapWrite),
|
||||
cipherBlockNewP(cipherModeDecrypt, cipherType, BUFSTR(cipherPass), .raw = true));
|
||||
cipherBlockNewP(cipherModeDecrypt, cipherSpecBackup, .raw = true));
|
||||
}
|
||||
|
||||
ioWriteOpen(blockMapWrite);
|
||||
|
||||
@@ -46,7 +46,7 @@ backupBuildIncrPrior(const InfoBackup *const infoBackup)
|
||||
{
|
||||
result = manifestLoadFile(
|
||||
storageRepo(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupLabelPrior)),
|
||||
cfgOptionStrId(cfgOptRepoCipherType), infoPgCipherPass(infoBackupPg(infoBackup)));
|
||||
infoBackupCipherSpec(infoBackup));
|
||||
const ManifestData *const manifestPriorData = manifestData(result);
|
||||
|
||||
LOG_INFO_FMT(
|
||||
@@ -144,7 +144,7 @@ backupBuildIncr(
|
||||
manifestBuildIncr(manifest, manifestPrior, (BackupType)cfgOptionStrId(cfgOptType), archiveStart);
|
||||
|
||||
// Set the cipher subpass from prior manifest since we want a single subpass for the entire backup set
|
||||
manifestCipherSubPassSet(manifest, manifestCipherSubPass(manifestPrior));
|
||||
manifestCipherSpecSet(manifest, manifestCipherSpec(manifestPrior));
|
||||
|
||||
// Incremental was built
|
||||
result = true;
|
||||
|
||||
@@ -333,8 +333,7 @@ typedef struct BackupJobData
|
||||
const String *const backupLabel; // Backup label (defines the backup path)
|
||||
const bool backupStandby; // Backup from standby
|
||||
RegExp *standbyExp; // Identify files that may be copied from the standby
|
||||
const CipherType cipherType; // Cipher type
|
||||
const String *const cipherSubPass; // Passphrase used to encrypt files in the backup
|
||||
const CipherSpec *const cipherSpecBackup; // Cipher spec used to encrypt files in the backup
|
||||
const PgPageSize pageSize; // Page size
|
||||
const CompressType compressType; // Backup compression type
|
||||
const int compressLevel; // Compress level if backup is compressed
|
||||
@@ -685,8 +684,7 @@ backupJobCallback(void *const data, const unsigned int clientIdx)
|
||||
|
||||
pckWriteU32P(param, jobData->compressType);
|
||||
pckWriteI32P(param, jobData->compressLevel);
|
||||
pckWriteU64P(param, jobData->cipherSubPass == NULL ? cipherTypeNone : cipherTypeAes256Cbc);
|
||||
pckWriteStrP(param, jobData->cipherSubPass);
|
||||
cipherSpecPack(param, jobData->cipherSpecBackup);
|
||||
pckWriteU32P(param, jobData->pageSize);
|
||||
pckWriteStrP(param, cfgOptionStrNull(cfgOptPgVersionForce));
|
||||
}
|
||||
@@ -771,12 +769,12 @@ backupJobCallback(void *const data, const unsigned int clientIdx)
|
||||
Process the backup manifest
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
backupProcess(const BackupData *const backupData, Manifest *const manifest, const String *const cipherPassBackup)
|
||||
backupProcess(const BackupData *const backupData, Manifest *const manifest, const CipherSpec *const cipherSpecManifest)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(BACKUP_DATA, backupData);
|
||||
FUNCTION_LOG_PARAM(MANIFEST, manifest);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPassBackup);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecManifest);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(manifest != NULL);
|
||||
@@ -799,8 +797,7 @@ backupProcess(const BackupData *const backupData, Manifest *const manifest, cons
|
||||
.backupStandby = backupData->dbStandby != NULL,
|
||||
.compressType = compressTypeEnum(cfgOptionStrId(cfgOptCompressType)),
|
||||
.compressLevel = cfgOptionInt(cfgOptCompressLevel),
|
||||
.cipherType = cfgOptionStrId(cfgOptRepoCipherType),
|
||||
.cipherSubPass = manifestCipherSubPass(manifest),
|
||||
.cipherSpecBackup = manifestCipherSpec(manifest),
|
||||
.pageSize = backupData->pageSize,
|
||||
.delta = cfgOptionBool(cfgOptDelta),
|
||||
.bundle = cfgOptionBool(cfgOptRepoBundle),
|
||||
@@ -929,7 +926,7 @@ backupProcess(const BackupData *const backupData, Manifest *const manifest, cons
|
||||
// Save the manifest periodically to preserve checksums for resume
|
||||
if (sizeProgress - manifestSaveLast >= manifestSaveSize)
|
||||
{
|
||||
backupManifestSaveCopy(manifest, cipherPassBackup, false);
|
||||
backupManifestSaveCopy(manifest, cipherSpecManifest, false);
|
||||
manifestSaveLast = sizeProgress;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,8 +115,7 @@ backupFileProtocol(PackRead *const param)
|
||||
const unsigned int blockIncrReference = (unsigned int)pckReadU64P(param);
|
||||
const CompressType repoFileCompressType = (CompressType)pckReadU32P(param);
|
||||
const int repoFileCompressLevel = pckReadI32P(param);
|
||||
const CipherType cipherType = (CipherType)pckReadU64P(param);
|
||||
const String *const cipherPass = pckReadStrP(param);
|
||||
const CipherSpec *const cipherSpecBackup = cipherSpecNewPack(param);
|
||||
const PgPageSize pageSize = pckReadU32P(param);
|
||||
const String *const pgVersionForce = pckReadStrP(param);
|
||||
|
||||
@@ -163,7 +162,7 @@ backupFileProtocol(PackRead *const param)
|
||||
|
||||
// Backup file
|
||||
const List *const resultList = backupFile(
|
||||
repoFile, bundleId, bundleRaw, blockIncrReference, repoFileCompressType, repoFileCompressLevel, cipherType, cipherPass,
|
||||
repoFile, bundleId, bundleRaw, blockIncrReference, repoFileCompressType, repoFileCompressLevel, cipherSpecBackup,
|
||||
pgVersionForce, pageSize, fileList);
|
||||
|
||||
// Return result
|
||||
|
||||
@@ -169,11 +169,11 @@ backupResumeClean(
|
||||
|
||||
// Helper to find a resumable backup
|
||||
static const Manifest *
|
||||
backupResumeFind(const Manifest *const manifest, const String *const cipherPassBackup)
|
||||
backupResumeFind(const Manifest *const manifest, const CipherSpec *const cipherSpecManifest)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(MANIFEST, manifest);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPassBackup);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecManifest);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(manifest != NULL);
|
||||
@@ -217,8 +217,7 @@ backupResumeFind(const Manifest *const manifest, const String *const cipherPassB
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
manifestResume = manifestLoadFile(
|
||||
storageRepo(), manifestFile, cfgOptionStrId(cfgOptRepoCipherType), cipherPassBackup);
|
||||
manifestResume = manifestLoadFile(storageRepo(), manifestFile, cipherSpecManifest);
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
@@ -296,11 +295,11 @@ backupResumeFind(const Manifest *const manifest, const String *const cipherPassB
|
||||
}
|
||||
|
||||
static bool
|
||||
backupResume(Manifest *const manifest, const String *const cipherPassBackup)
|
||||
backupResume(Manifest *const manifest, const CipherSpec *const cipherSpecManifest)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(MANIFEST, manifest);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPassBackup);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecManifest);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(manifest != NULL);
|
||||
@@ -309,7 +308,7 @@ backupResume(Manifest *const manifest, const String *const cipherPassBackup)
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
const Manifest *const manifestResume = backupResumeFind(manifest, cipherPassBackup);
|
||||
const Manifest *const manifestResume = backupResumeFind(manifest, cipherSpecManifest);
|
||||
|
||||
// If a resumable backup was found set the label and cipher subpass
|
||||
if (manifestResume)
|
||||
@@ -325,7 +324,7 @@ backupResume(Manifest *const manifest, const String *const cipherPassBackup)
|
||||
strZ(manifestData(manifest)->backupLabel));
|
||||
|
||||
// Copy cipher subpass since it was used to encrypt the resumable files
|
||||
manifestCipherSubPassSet(manifest, manifestCipherSubPass(manifestResume));
|
||||
manifestCipherSpecSet(manifest, manifestCipherSpec(manifestResume));
|
||||
|
||||
// Clean resumed backup
|
||||
const String *const backupPath = strNewFmt(STORAGE_REPO_BACKUP "/%s", strZ(manifestData(manifest)->backupLabel));
|
||||
|
||||
@@ -92,7 +92,7 @@ checkStandby(const DbGetResult dbGroup, const unsigned int pgPathDefinedTotal)
|
||||
// Check that the backup and archive info files exist and are valid for the current database of the stanza
|
||||
checkStanzaInfoPg(
|
||||
storageRepo, dbPgControl(dbGroup.standby).version, dbPgControl(dbGroup.standby).systemId,
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx), cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
cfgCipherSpecMainIdx(repoIdx));
|
||||
}
|
||||
|
||||
LOG_INFO("switch wal not performed because this is a standby");
|
||||
@@ -137,12 +137,11 @@ checkPrimary(const DbGetResult dbGroup)
|
||||
// Check that the backup and archive info files exist and are valid for the current database of the stanza
|
||||
checkStanzaInfoPg(
|
||||
storageRepo, dbPgControl(dbGroup.primary).version, dbPgControl(dbGroup.primary).systemId,
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx), cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
// Attempt to load the archive info file and retrieve the archiveId
|
||||
const InfoArchive *const archiveInfo = infoArchiveLoadFile(
|
||||
storageRepo, INFO_ARCHIVE_PATH_FILE_STR, cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
storageRepo, INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
repoArchiveId[repoIdx] = infoArchiveId(archiveInfo);
|
||||
}
|
||||
|
||||
@@ -124,15 +124,13 @@ checkStanzaInfo(const InfoPgData *const archiveInfo, const InfoPgData *const bac
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN void
|
||||
checkStanzaInfoPg(
|
||||
const Storage *const storage, const unsigned int pgVersion, const uint64_t pgSystemId, const CipherType cipherType,
|
||||
const String *const cipherPass)
|
||||
const Storage *const storage, const unsigned int pgVersion, const uint64_t pgSystemId, const CipherSpec *const cipherSpecMain)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STORAGE, storage);
|
||||
FUNCTION_TEST_PARAM(UINT, pgVersion);
|
||||
FUNCTION_TEST_PARAM(UINT64, pgSystemId);
|
||||
FUNCTION_TEST_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_TEST_PARAM(CIPHER_SPEC, cipherSpecMain);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(storage != NULL);
|
||||
@@ -140,9 +138,9 @@ checkStanzaInfoPg(
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Check that the backup and archive info files exist
|
||||
const InfoArchive *const infoArchive = infoArchiveLoadFile(storage, INFO_ARCHIVE_PATH_FILE_STR, cipherType, cipherPass);
|
||||
const InfoArchive *const infoArchive = infoArchiveLoadFile(storage, INFO_ARCHIVE_PATH_FILE_STR, cipherSpecMain);
|
||||
const InfoPgData archiveInfoPg = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
|
||||
const InfoBackup *const infoBackup = infoBackupLoadFile(storage, INFO_BACKUP_PATH_FILE_STR, cipherType, cipherPass);
|
||||
const InfoBackup *const infoBackup = infoBackupLoadFile(storage, INFO_BACKUP_PATH_FILE_STR, cipherSpecMain);
|
||||
const InfoPgData backupInfoPg = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
|
||||
|
||||
// Check that the info files pg data match each other
|
||||
|
||||
@@ -4,6 +4,7 @@ Check Command Common
|
||||
#ifndef COMMAND_CHECK_COMMON_H
|
||||
#define COMMAND_CHECK_COMMON_H
|
||||
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/type/string.h"
|
||||
#include "db/db.h"
|
||||
#include "info/infoPg.h"
|
||||
@@ -19,7 +20,6 @@ FN_EXTERN void checkStanzaInfo(const InfoPgData *archiveInfo, const InfoPgData *
|
||||
|
||||
// Load and validate the database data of the info files against each other and the current database
|
||||
FN_EXTERN void checkStanzaInfoPg(
|
||||
const Storage *storage, const unsigned int pgVersion, const uint64_t pgSystemId, CipherType cipherType,
|
||||
const String *cipherPass);
|
||||
const Storage *storage, const unsigned int pgVersion, const uint64_t pgSystemId, const CipherSpec *cipherSpecMain);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -585,8 +585,7 @@ removeExpiredArchive(const InfoBackup *const infoBackup, const bool timeBasedFul
|
||||
{
|
||||
// Attempt to load the archive info file
|
||||
const InfoArchive *const infoArchive = infoArchiveLoadFile(
|
||||
storageRepoIdx(repoIdx), INFO_ARCHIVE_PATH_FILE_STR, cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
storageRepoIdx(repoIdx), INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
const InfoPg *const infoArchivePgData = infoArchivePg(infoArchive);
|
||||
|
||||
// Get a list of archive directories (e.g. 9.6-1, 10-2, etc) sorted by the db-id (number after the dash).
|
||||
@@ -897,8 +896,7 @@ removeExpiredBackup(const InfoBackup *const infoBackup, const String *const adho
|
||||
if (adhocBackupLabel != NULL && strBeginsWith(strLstGet(backupList, 0), strSubN(adhocBackupLabel, 0, 16)))
|
||||
{
|
||||
const Manifest *const manifestResume = manifestLoadFile(
|
||||
storageRepoIdx(repoIdx), manifestFileName, cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
infoPgCipherPass(infoBackupPg(infoBackup)));
|
||||
storageRepoIdx(repoIdx), manifestFileName, infoBackupCipherSpec(infoBackup));
|
||||
|
||||
// If the ancestor of the resumable backup no longer exists in backup.info then it can be removed
|
||||
if (!infoBackupLabelExists(infoBackup, manifestData(manifestResume)->backupLabelPrior))
|
||||
@@ -1096,9 +1094,7 @@ cmdExpire(void)
|
||||
TRY_BEGIN()
|
||||
{
|
||||
// Load backup.info for this repo
|
||||
infoBackup = infoBackupLoadFileReconstruct(
|
||||
storageRepo, INFO_BACKUP_PATH_FILE_STR, cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
infoBackup = infoBackupLoadFileReconstruct(storageRepo, INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
// When expire oldest requested, expire the oldest full backup by lowering retention for this execution
|
||||
if (expireOldest)
|
||||
@@ -1180,8 +1176,7 @@ cmdExpire(void)
|
||||
if (!cfgOptionValid(cfgOptDryRun) || !cfgOptionBool(cfgOptDryRun))
|
||||
{
|
||||
infoBackupSaveFile(
|
||||
infoBackup, storageRepoIdxWrite(repoIdx), INFO_BACKUP_PATH_FILE_STR,
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx), cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
infoBackup, storageRepoIdxWrite(repoIdx), INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
}
|
||||
|
||||
// Remove all files on disk that are now expired
|
||||
|
||||
@@ -132,7 +132,6 @@ typedef struct InfoRepoData
|
||||
{
|
||||
unsigned int key; // User-defined repo key
|
||||
CipherType cipher; // Encryption type
|
||||
const String *cipherPass; // Passphrase if the repo is encrypted (else NULL)
|
||||
int stanzaStatus; // Status code of the stanza on this repo
|
||||
unsigned int backupIdx; // Index of the next backup that may be a candidate for sorting
|
||||
InfoBackup *backupInfo; // Contents of the backup.info file of the stanza on this repo
|
||||
@@ -1478,7 +1477,7 @@ infoUpdateStanza(
|
||||
// Attempt to load the backup info file
|
||||
stanzaRepo->repoList[repoIdx].backupInfo = infoBackupLoadFile(
|
||||
storage, strNewFmt(STORAGE_PATH_BACKUP "/%s/%s", strZ(stanzaRepo->name), INFO_BACKUP_FILE),
|
||||
stanzaRepo->repoList[repoIdx].cipher, stanzaRepo->repoList[repoIdx].cipherPass);
|
||||
cfgCipherSpecMainIdx(repoIdx));
|
||||
}
|
||||
CATCH(FileMissingError)
|
||||
{
|
||||
@@ -1502,15 +1501,14 @@ infoUpdateStanza(
|
||||
{
|
||||
stanzaRepo->repoList[repoIdx].archiveInfo = infoArchiveLoadFile(
|
||||
storage, strNewFmt(STORAGE_PATH_ARCHIVE "/%s/%s", strZ(stanzaRepo->name), INFO_ARCHIVE_FILE),
|
||||
stanzaRepo->repoList[repoIdx].cipher, stanzaRepo->repoList[repoIdx].cipherPass);
|
||||
cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
// If a specific backup exists on this repo then attempt to load the manifest
|
||||
if (backupLabel != NULL)
|
||||
{
|
||||
stanzaRepo->repoList[repoIdx].manifest = manifestLoadFile(
|
||||
storage, strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupLabel)),
|
||||
stanzaRepo->repoList[repoIdx].cipher,
|
||||
infoPgCipherPass(infoBackupPg(stanzaRepo->repoList[repoIdx].backupInfo)));
|
||||
infoBackupCipherSpec(stanzaRepo->repoList[repoIdx].backupInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1600,7 +1598,6 @@ infoRender(void)
|
||||
{
|
||||
.key = cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoIdx),
|
||||
.cipher = cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
.cipherPass = cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx),
|
||||
.error = NULL,
|
||||
};
|
||||
|
||||
@@ -1673,7 +1670,6 @@ infoRender(void)
|
||||
{
|
||||
.key = cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoListIdx),
|
||||
.cipher = cfgOptionIdxStrId(cfgOptRepoCipherType, repoListIdx),
|
||||
.cipherPass = cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoListIdx),
|
||||
.error = NULL,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -231,12 +231,11 @@ cmdManifestBlockDeltaRender(const Manifest *const manifest, const ManifestFile *
|
||||
.offset = file->bundleOffset + file->sizeRepo - file->blockIncrMapSize,
|
||||
.limit = VARUINT64(file->blockIncrMapSize));
|
||||
|
||||
if (manifestCipherSubPass(manifest) != NULL)
|
||||
if (cipherSpecType(manifestCipherSpec(manifest)) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioReadFilterGroup(storageReadIo(read)),
|
||||
cipherBlockNewP(
|
||||
cipherModeDecrypt, cipherTypeAes256Cbc, BUFSTR(manifestCipherSubPass(manifest)), .raw = true));
|
||||
cipherBlockNewP(cipherModeDecrypt, manifestCipherSpec(manifest), .raw = true));
|
||||
}
|
||||
|
||||
ioReadOpen(storageReadIo(read));
|
||||
@@ -442,16 +441,12 @@ cmdManifestRender(void)
|
||||
storageRepo();
|
||||
|
||||
// Load backup.info and cipher
|
||||
const InfoBackup *const infoBackup = infoBackupLoadFile(
|
||||
storageRepo(), INFO_BACKUP_PATH_FILE_STR, cfgOptionStrId(cfgOptRepoCipherType),
|
||||
cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
const String *const cipherPass = infoPgCipherPass(infoBackupPg(infoBackup));
|
||||
const CipherType cipherType = cipherPass == NULL ? cipherTypeNone : cipherTypeAes256Cbc;
|
||||
const InfoBackup *const infoBackup = infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMain());
|
||||
|
||||
// Load manifest
|
||||
const Manifest *const manifest = manifestLoadFile(
|
||||
storageRepo(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(cfgOptionStr(cfgOptSet))),
|
||||
cipherType, cipherPass);
|
||||
infoBackupCipherSpec(infoBackup));
|
||||
|
||||
// Manifest info
|
||||
const ManifestData *const data = manifestData(manifest);
|
||||
|
||||
@@ -56,18 +56,18 @@ storageGetProcess(IoWrite *const destination)
|
||||
{
|
||||
// Determine the passphrase using the following pattern:
|
||||
//
|
||||
// REPO / (repo passphrase)
|
||||
// / archive / (repo passphrase)
|
||||
// REPO / (main passphrase)
|
||||
// / archive / (main passphrase)
|
||||
// / archive / stanza / (archive passphrase)
|
||||
// / backup / (repo passphrase)
|
||||
// / backup / stanza / (backup passphrase)
|
||||
// / backup / stanza / set / (manifest passphrase)
|
||||
// / backup / stanza / backup.history / (backup passphrase)
|
||||
// / backup / (main passphrase)
|
||||
// / backup / stanza / (manifest passphrase)
|
||||
// / backup / stanza / set / (backup passphrase)
|
||||
// / backup / stanza / backup.history / (manifest passphrase)
|
||||
//
|
||||
// Nothing should be stored at the top level of the repo except the backup/archive paths. The backup/archive paths
|
||||
// should contain only stanza paths.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
const String *cipherPass = NULL;
|
||||
const CipherSpec *cipherSpec = NULL;
|
||||
const StringList *const filePathSplitLst = strLstNewSplit(file, FSLASH_STR);
|
||||
|
||||
// At a minimum the path must contain archive/backup, a stanza, and a file
|
||||
@@ -86,32 +86,32 @@ storageGetProcess(IoWrite *const destination)
|
||||
// Archive path
|
||||
if (strEq(strLstGet(filePathSplitLst, 0), STORAGE_PATH_ARCHIVE_STR))
|
||||
{
|
||||
cipherPass = cfgOptionStr(cfgOptRepoCipherPass);
|
||||
cipherSpec = cfgCipherSpecMain();
|
||||
|
||||
// Find the archive passphrase
|
||||
if (!strEndsWithZ(file, INFO_ARCHIVE_FILE) && !strEndsWithZ(file, INFO_ARCHIVE_FILE INFO_COPY_EXT))
|
||||
{
|
||||
const InfoArchive *const info = infoArchiveLoadFile(
|
||||
storageRepo(), strNewFmt(STORAGE_PATH_ARCHIVE "/%s/%s", strZ(stanza), INFO_ARCHIVE_FILE),
|
||||
repoCipherType, cipherPass);
|
||||
cipherPass = infoArchiveCipherPass(info);
|
||||
cfgCipherSpecMain());
|
||||
cipherSpec = infoArchiveCipherSpec(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Backup path
|
||||
if (strEq(strLstGet(filePathSplitLst, 0), STORAGE_PATH_BACKUP_STR))
|
||||
{
|
||||
cipherPass = cfgOptionStr(cfgOptRepoCipherPass);
|
||||
cipherSpec = cfgCipherSpecMain();
|
||||
|
||||
if (!strEndsWithZ(file, INFO_BACKUP_FILE) && !strEndsWithZ(file, INFO_BACKUP_FILE INFO_COPY_EXT))
|
||||
{
|
||||
// Find the backup passphrase
|
||||
// Find the manifest passphrase
|
||||
const InfoBackup *const info = infoBackupLoadFile(
|
||||
storageRepo(), strNewFmt(STORAGE_PATH_BACKUP "/%s/%s", strZ(stanza), INFO_BACKUP_FILE),
|
||||
repoCipherType, cipherPass);
|
||||
cipherPass = infoBackupCipherPass(info);
|
||||
cfgCipherSpecMain());
|
||||
const CipherSpec *const cipherSpecManifest = infoBackupCipherSpec(info);
|
||||
|
||||
// Find the manifest passphrase
|
||||
// Find the backup passphrase if not a manifest
|
||||
if (!strEq(strLstGet(filePathSplitLst, 2), STRDEF(BACKUP_PATH_HISTORY)) &&
|
||||
!strEndsWithZ(file, BACKUP_MANIFEST_FILE) &&
|
||||
!strEndsWithZ(file, BACKUP_MANIFEST_FILE INFO_COPY_EXT))
|
||||
@@ -121,19 +121,24 @@ storageGetProcess(IoWrite *const destination)
|
||||
strNewFmt(
|
||||
STORAGE_PATH_BACKUP "/%s/%s/%s", strZ(stanza), strZ(strLstGet(filePathSplitLst, 2)),
|
||||
BACKUP_MANIFEST_FILE),
|
||||
repoCipherType, cipherPass);
|
||||
cipherPass = manifestCipherSubPass(manifest);
|
||||
cipherSpecManifest);
|
||||
cipherSpec = manifestCipherSpec(manifest);
|
||||
}
|
||||
// Else use the manifest passphrase
|
||||
else
|
||||
cipherSpec = cipherSpecManifest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error when unable to determine cipher passphrase
|
||||
if (cipherPass == NULL)
|
||||
if (cipherSpec == NULL)
|
||||
THROW_FMT(OptionInvalidValueError, "unable to determine cipher passphrase for '%s'", strZ(file));
|
||||
|
||||
ASSERT(cipherSpecType(cipherSpec) != cipherTypeNone);
|
||||
|
||||
// Add encryption filter
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(source), repoCipherType, cipherModeDecrypt, cipherPass);
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(source), cipherModeDecrypt, cipherSpec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,7 @@ struct BlockDelta
|
||||
BlockDeltaPub pub; // Publicly accessible variables
|
||||
size_t blockSize; // Block size
|
||||
size_t checksumSize; // Checksum size
|
||||
CipherType cipherType; // Cipher type
|
||||
String *cipherPass; // Cipher passphrase
|
||||
const CipherSpec *cipherSpecBackup; // Cipher spec
|
||||
CompressType compressType; // Compress type
|
||||
|
||||
const BlockDeltaSuperBlock *superBlockData; // Current super block data
|
||||
@@ -57,21 +56,20 @@ typedef struct BlockDeltaReference
|
||||
FN_EXTERN BlockDelta *
|
||||
blockDeltaNew(
|
||||
const BlockMap *const blockMap, const size_t blockSize, const size_t checksumSize, const Buffer *const blockChecksum,
|
||||
const CipherType cipherType, const String *const cipherPass, const CompressType compressType)
|
||||
const CipherSpec *const cipherSpecBackup, const CompressType compressType)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(BLOCK_MAP, blockMap);
|
||||
FUNCTION_TEST_PARAM(SIZE, blockSize);
|
||||
FUNCTION_TEST_PARAM(SIZE, checksumSize);
|
||||
FUNCTION_TEST_PARAM(BUFFER, blockChecksum);
|
||||
FUNCTION_TEST_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_TEST_PARAM(CIPHER_SPEC, cipherSpecBackup);
|
||||
FUNCTION_TEST_PARAM(ENUM, compressType);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(blockMap != NULL);
|
||||
ASSERT(blockSize > 0);
|
||||
ASSERT(cipherType == cipherTypeNone || cipherPass != NULL);
|
||||
ASSERT(cipherSpecBackup != NULL);
|
||||
|
||||
OBJ_NEW_BEGIN(BlockDelta, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
@@ -83,8 +81,7 @@ blockDeltaNew(
|
||||
},
|
||||
.blockSize = blockSize,
|
||||
.checksumSize = checksumSize,
|
||||
.cipherType = cipherType,
|
||||
.cipherPass = strDup(cipherPass),
|
||||
.cipherSpecBackup = cipherSpecDup(cipherSpecBackup),
|
||||
.compressType = compressType,
|
||||
.write =
|
||||
{
|
||||
@@ -237,11 +234,10 @@ blockDeltaNext(BlockDelta *const this, const BlockDeltaRead *const readDelta, Io
|
||||
}
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
|
||||
if (this->cipherType != cipherTypeNone)
|
||||
if (cipherSpecType(this->cipherSpecBackup) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioReadFilterGroup(this->limitRead),
|
||||
cipherBlockNewP(cipherModeDecrypt, this->cipherType, BUFSTR(this->cipherPass), .raw = true));
|
||||
ioReadFilterGroup(this->limitRead), cipherBlockNewP(cipherModeDecrypt, this->cipherSpecBackup, .raw = true));
|
||||
}
|
||||
|
||||
if (this->compressType != compressTypeNone)
|
||||
|
||||
@@ -9,7 +9,7 @@ optional because the file to restore may not exist so all the blocks will need t
|
||||
|
||||
#include "command/backup/blockMap.h"
|
||||
#include "common/compress/helper.h"
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/spec.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
@@ -37,8 +37,8 @@ typedef struct BlockDeltaWrite
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
FN_EXTERN BlockDelta *blockDeltaNew(
|
||||
const BlockMap *blockMap, size_t blockSize, size_t checksumSize, const Buffer *blockChecksum, CipherType cipherType,
|
||||
const String *cipherPass, const CompressType compressType);
|
||||
const BlockMap *blockMap, size_t blockSize, size_t checksumSize, const Buffer *blockChecksum,
|
||||
const CipherSpec *cipherSpecBackup, const CompressType compressType);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
|
||||
@@ -30,7 +30,7 @@ typedef struct RestoreFileResult
|
||||
static List *
|
||||
restoreFile(
|
||||
const String *const repoFile, const unsigned int repoIdx, const CompressType repoFileCompressType, const time_t copyTimeBegin,
|
||||
const bool delta, const bool deltaForce, const bool bundleRaw, const String *const cipherPass,
|
||||
const bool delta, const bool deltaForce, const bool bundleRaw, const CipherSpec *const cipherSpecBackup,
|
||||
const StringList *const referenceList, List *const fileList)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
@@ -41,7 +41,7 @@ restoreFile(
|
||||
FUNCTION_LOG_PARAM(BOOL, delta);
|
||||
FUNCTION_LOG_PARAM(BOOL, deltaForce);
|
||||
FUNCTION_LOG_PARAM(BOOL, bundleRaw);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecBackup);
|
||||
FUNCTION_LOG_PARAM(STRING_LIST, referenceList); // List of references (for block incremental)
|
||||
FUNCTION_LOG_PARAM(LIST, fileList); // List of files to restore
|
||||
FUNCTION_LOG_END();
|
||||
@@ -220,7 +220,9 @@ restoreFile(
|
||||
if (fileResult->result == restoreResultCopy)
|
||||
{
|
||||
storageReadMultiAddP(
|
||||
repoFileRead, repoFile, .compressible = repoFileCompressType == compressTypeNone && cipherPass == NULL,
|
||||
repoFileRead, repoFile,
|
||||
.compressible =
|
||||
repoFileCompressType == compressTypeNone && cipherSpecType(cipherSpecBackup) == cipherTypeNone,
|
||||
.offset = file->offset, .limit = file->limit);
|
||||
}
|
||||
}
|
||||
@@ -259,11 +261,10 @@ restoreFile(
|
||||
// blocks need to be fetched from the repository. If we got here there must be at least one block to fetch.
|
||||
IoRead *const blockMapRead = ioLimitReadNew(storageReadMultiIo(repoFileRead), varUInt64(file->limit));
|
||||
|
||||
if (cipherPass != NULL)
|
||||
if (cipherSpecType(cipherSpecBackup) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioReadFilterGroup(blockMapRead),
|
||||
cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, BUFSTR(cipherPass), .raw = true));
|
||||
ioReadFilterGroup(blockMapRead), cipherBlockNewP(cipherModeDecrypt, cipherSpecBackup, .raw = true));
|
||||
}
|
||||
|
||||
ioReadOpen(blockMapRead);
|
||||
@@ -278,8 +279,8 @@ restoreFile(
|
||||
|
||||
// Apply delta to file
|
||||
BlockDelta *const blockDelta = blockDeltaNew(
|
||||
blockMap, file->blockIncrSize, file->blockIncrChecksumSize, file->blockChecksum,
|
||||
cipherPass == NULL ? cipherTypeNone : cipherTypeAes256Cbc, cipherPass, repoFileCompressType);
|
||||
blockMap, file->blockIncrSize, file->blockIncrChecksumSize, file->blockChecksum, cipherSpecBackup,
|
||||
repoFileCompressType);
|
||||
|
||||
for (unsigned int readIdx = 0; readIdx < blockDeltaReadSize(blockDelta); readIdx++)
|
||||
{
|
||||
@@ -333,11 +334,9 @@ restoreFile(
|
||||
IoFilterGroup *const filterGroup = ioWriteFilterGroup(storageWriteIo(pgFileWrite));
|
||||
|
||||
// Add decryption filter
|
||||
if (cipherPass != NULL)
|
||||
if (cipherSpecType(cipherSpecBackup) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
filterGroup,
|
||||
cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, BUFSTR(cipherPass), .raw = bundleRaw));
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeDecrypt, cipherSpecBackup, .raw = bundleRaw));
|
||||
}
|
||||
|
||||
// Add decompression filter
|
||||
|
||||
@@ -336,7 +336,7 @@ typedef struct RestoreJobData
|
||||
Manifest *manifest; // Backup manifest
|
||||
List *queueList; // List of processing queues
|
||||
RegExp *zeroExp; // Identify files that should be sparse zeroed
|
||||
const String *cipherSubPass; // Passphrase used to decrypt files in the backup
|
||||
const CipherSpec *cipherSpecBackup; // Cipher spec used to decrypt files in the backup
|
||||
const String *rootReplaceUser; // User to replace invalid users when root
|
||||
const String *rootReplaceGroup; // Group to replace invalid group when root
|
||||
} RestoreJobData;
|
||||
@@ -429,7 +429,7 @@ restoreJobCallback(void *const data, const unsigned int clientIdx)
|
||||
pckWriteBoolP(param, cfgOptionBool(cfgOptDelta));
|
||||
pckWriteBoolP(param, cfgOptionBool(cfgOptDelta) && cfgOptionBool(cfgOptForce));
|
||||
pckWriteBoolP(param, file.bundleId != 0 && manifestData(jobData->manifest)->bundleRaw);
|
||||
pckWriteStrP(param, jobData->cipherSubPass);
|
||||
cipherSpecPack(param, jobData->cipherSpecBackup);
|
||||
pckWriteStrLstP(param, manifestReferenceList(jobData->manifest));
|
||||
|
||||
fileAdded = true;
|
||||
|
||||
@@ -46,7 +46,7 @@ restoreFileProtocol(PackRead *const param)
|
||||
const bool delta = pckReadBoolP(param);
|
||||
const bool deltaForce = pckReadBoolP(param);
|
||||
const bool bundleRaw = pckReadBoolP(param);
|
||||
const String *const cipherPass = pckReadStrP(param);
|
||||
const CipherSpec *const cipherSpecBackup = cipherSpecNewPack(param);
|
||||
const StringList *const referenceList = pckReadStrLstP(param);
|
||||
|
||||
// Build the file list
|
||||
@@ -85,7 +85,7 @@ restoreFileProtocol(PackRead *const param)
|
||||
|
||||
// Restore files
|
||||
const List *const resultList = restoreFile(
|
||||
repoFile, repoIdx, repoFileCompressType, copyTimeBegin, delta, deltaForce, bundleRaw, cipherPass, referenceList,
|
||||
repoFile, repoIdx, repoFileCompressType, copyTimeBegin, delta, deltaForce, bundleRaw, cipherSpecBackup, referenceList,
|
||||
fileList);
|
||||
|
||||
// Return result
|
||||
|
||||
@@ -11,6 +11,7 @@ Restore Command
|
||||
#include "command/restore/timeline.h"
|
||||
#include "common/regExp.h"
|
||||
#include "common/user.h"
|
||||
#include "config/config.h"
|
||||
#include "config/exec.h"
|
||||
#include "info/infoArchive.h"
|
||||
#include "info/infoBackup.h"
|
||||
@@ -58,24 +59,21 @@ cmdRestore(void)
|
||||
|
||||
jobData.manifest = manifestLoadFile(
|
||||
storageRepoIdx(backupData.repoIdx),
|
||||
strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupData.backupSet)), backupData.repoCipherType,
|
||||
backupData.backupCipherPass);
|
||||
strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupData.backupSet)), backupData.cipherSpecManifest);
|
||||
|
||||
// Verify that the selected timeline is valid for the backup -- including current and latest timelines
|
||||
if (manifestData(jobData.manifest)->backupOptionOnline)
|
||||
{
|
||||
const ManifestData *const data = manifestData(jobData.manifest);
|
||||
const InfoArchive *const archiveInfo = infoArchiveLoadFile(
|
||||
storageRepoIdx(backupData.repoIdx), INFO_ARCHIVE_PATH_FILE_STR,
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, backupData.repoIdx),
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, backupData.repoIdx));
|
||||
storageRepoIdx(backupData.repoIdx), INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMainIdx(backupData.repoIdx));
|
||||
|
||||
timelineVerify(
|
||||
storageRepoIdx(backupData.repoIdx),
|
||||
strNewFmt("%s-%u", strZ(pgVersionToStr(data->pgVersion)), data->pgId), data->pgVersion,
|
||||
cvtZToUIntBase(strZ(strSubN(data->archiveStart, 0, 8)), 16), pgLsnFromStr(data->lsnStart),
|
||||
cfgOptionStrNull(cfgOptTargetTimeline), cfgOptionSeq(cfgOptType),
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, backupData.repoIdx), infoArchiveCipherPass(archiveInfo));
|
||||
infoArchiveCipherSpec(archiveInfo));
|
||||
}
|
||||
|
||||
// Remotes (if any) are no longer needed since the rest of the repository reads will be done by the local processes
|
||||
@@ -91,8 +89,8 @@ cmdRestore(void)
|
||||
// Validate manifest. Don't use strict mode because we'd rather ignore problems that won't affect a restore.
|
||||
manifestValidate(jobData.manifest, false);
|
||||
|
||||
// Get the cipher subpass used to decrypt files in the backup
|
||||
jobData.cipherSubPass = manifestCipherSubPass(jobData.manifest);
|
||||
// Get the cipher spec used to decrypt files in the backup
|
||||
jobData.cipherSpecBackup = manifestCipherSpec(jobData.manifest);
|
||||
|
||||
// Validate the manifest
|
||||
restoreManifestValidate(jobData.manifest, backupData.backupSet);
|
||||
|
||||
@@ -4,8 +4,7 @@ Get the backup set to restore
|
||||
typedef struct RestoreBackupData
|
||||
{
|
||||
unsigned int repoIdx; // Internal repo index
|
||||
CipherType repoCipherType; // Repo encryption type (0 = none)
|
||||
const String *backupCipherPass; // Passphrase of backup files if repo is encrypted (else NULL)
|
||||
const CipherSpec *cipherSpecManifest; // Cipher spec to open the manifest, none when not encrypted
|
||||
const String *backupSet; // Backup set to restore
|
||||
} RestoreBackupData;
|
||||
|
||||
@@ -16,7 +15,7 @@ typedef struct RestoreBackupData
|
||||
|
||||
// Helper function for restoreBackupSet
|
||||
static RestoreBackupData
|
||||
restoreBackupData(const String *const backupLabel, const unsigned int repoIdx, const String *const backupCipherPass)
|
||||
restoreBackupData(const String *const backupLabel, const unsigned int repoIdx, const CipherSpec *const cipherSpecManifest)
|
||||
{
|
||||
ASSERT(backupLabel != NULL);
|
||||
|
||||
@@ -26,8 +25,7 @@ restoreBackupData(const String *const backupLabel, const unsigned int repoIdx, c
|
||||
{
|
||||
restoreBackup.backupSet = strDup(backupLabel);
|
||||
restoreBackup.repoIdx = repoIdx;
|
||||
restoreBackup.repoCipherType = cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx);
|
||||
restoreBackup.backupCipherPass = strDup(backupCipherPass);
|
||||
restoreBackup.cipherSpecManifest = cipherSpecDup(cipherSpecManifest);
|
||||
}
|
||||
MEM_CONTEXT_PRIOR_END();
|
||||
|
||||
@@ -103,9 +101,7 @@ restoreBackupSet(void)
|
||||
// Attempt to load backup.info
|
||||
TRY_BEGIN()
|
||||
{
|
||||
infoBackup = infoBackupLoadFile(
|
||||
storageRepoIdx(repoIdx), INFO_BACKUP_PATH_FILE_STR, cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
infoBackup = infoBackupLoadFile(storageRepoIdx(repoIdx), INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
@@ -160,7 +156,7 @@ restoreBackupSet(void)
|
||||
{
|
||||
found = true;
|
||||
|
||||
result = restoreBackupData(backupData.backupLabel, repoIdx, infoPgCipherPass(infoBackupPg(infoBackup)));
|
||||
result = restoreBackupData(backupData.backupLabel, repoIdx, infoBackupCipherSpec(infoBackup));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -187,7 +183,7 @@ restoreBackupSet(void)
|
||||
strZ(latestBackup.backupLabel));
|
||||
}
|
||||
|
||||
result = restoreBackupData(latestBackup.backupLabel, repoIdx, infoPgCipherPass(infoBackupPg(infoBackup)));
|
||||
result = restoreBackupData(latestBackup.backupLabel, repoIdx, infoBackupCipherSpec(infoBackup));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -198,7 +194,7 @@ restoreBackupSet(void)
|
||||
{
|
||||
if (strEq(infoBackupData(infoBackup, backupIdx).backupLabel, backupSetRequested))
|
||||
{
|
||||
result = restoreBackupData(backupSetRequested, repoIdx, infoPgCipherPass(infoBackupPg(infoBackup)));
|
||||
result = restoreBackupData(backupSetRequested, repoIdx, infoBackupCipherSpec(infoBackup));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,15 +78,14 @@ Load history file
|
||||
***********************************************************************************************************************************/
|
||||
static List *
|
||||
historyLoad(
|
||||
const Storage *const storageRepo, const String *const archiveId, const unsigned int timeline, const CipherType cipherType,
|
||||
const String *const cipherPass)
|
||||
const Storage *const storageRepo, const String *const archiveId, const unsigned int timeline,
|
||||
const CipherSpec *const cipherSpecArchive)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storageRepo);
|
||||
FUNCTION_LOG_PARAM(STRING, archiveId);
|
||||
FUNCTION_LOG_PARAM(UINT, timeline);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_LOG_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecArchive);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
List *result;
|
||||
@@ -95,7 +94,7 @@ historyLoad(
|
||||
{
|
||||
const String *const historyFile = strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%08X.history", strZ(archiveId), timeline);
|
||||
StorageRead *const storageRead = storageNewReadP(storageRepo, historyFile);
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(storageReadIo(storageRead)), cipherType, cipherModeDecrypt, cipherPass);
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(storageReadIo(storageRead)), cipherModeDecrypt, cipherSpecArchive);
|
||||
const Buffer *const history = storageGetP(storageRead);
|
||||
|
||||
TRY_BEGIN()
|
||||
@@ -159,7 +158,7 @@ FN_EXTERN void
|
||||
timelineVerify(
|
||||
const Storage *const storageRepo, const String *const archiveId, const unsigned int pgVersion,
|
||||
const unsigned int timelineBackup, const uint64_t lsnBackup, const String *timelineTargetStr, const unsigned int recoveryType,
|
||||
const CipherType cipherType, const String *const cipherPass)
|
||||
const CipherSpec *const cipherSpecArchive)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storageRepo);
|
||||
@@ -169,8 +168,7 @@ timelineVerify(
|
||||
FUNCTION_LOG_PARAM(UINT64, lsnBackup);
|
||||
FUNCTION_LOG_PARAM(STRING, timelineTargetStr);
|
||||
FUNCTION_LOG_PARAM(UINT, recoveryType);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_LOG_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecArchive);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(storageRepo != NULL);
|
||||
@@ -223,7 +221,7 @@ timelineVerify(
|
||||
{
|
||||
// Search through the history for the target timeline to make sure it includes the backup timeline. This follows
|
||||
// the logic in PostgreSQL's readTimeLineHistory() and tliOfPointInHistory() but is a bit simplified for our usage.
|
||||
const List *const historyList = historyLoad(storageRepo, archiveId, timelineTarget, cipherType, cipherPass);
|
||||
const List *const historyList = historyLoad(storageRepo, archiveId, timelineTarget, cipherSpecArchive);
|
||||
unsigned int timelineFound = 0;
|
||||
|
||||
for (unsigned int historyIdx = 0; historyIdx < lstSize(historyList); historyIdx++)
|
||||
|
||||
@@ -4,7 +4,7 @@ Timeline Management
|
||||
#ifndef COMMAND_RESTORE_TIMELINE_H
|
||||
#define COMMAND_RESTORE_TIMELINE_H
|
||||
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/spec.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@@ -12,8 +12,7 @@ Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Verify that target timeline is valid for a backup
|
||||
FN_EXTERN void timelineVerify(
|
||||
const Storage *storageRepo, const String *archiveId, unsigned int pgVersion, unsigned int timelineBackup,
|
||||
uint64_t lsnBackup, const String *timelineTargetStr, unsigned int recoveryType, CipherType cipherType,
|
||||
const String *cipherPass);
|
||||
const Storage *storageRepo, const String *archiveId, unsigned int pgVersion, unsigned int timelineBackup, uint64_t lsnBackup,
|
||||
const String *timelineTargetStr, unsigned int recoveryType, const CipherSpec *cipherSpecArchive);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,24 +15,32 @@ Stanza Commands Handler
|
||||
#include "storage/helper.h"
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN String *
|
||||
cipherPassGen(const CipherType cipherType)
|
||||
FN_EXTERN CipherSpec *
|
||||
cipherSpecGen(const CipherType cipherType)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
String *result = NULL;
|
||||
CipherSpec *result;
|
||||
|
||||
if (cipherType != cipherTypeNone)
|
||||
if (cipherType == cipherTypeNone)
|
||||
result = cipherSpecNewNone();
|
||||
else
|
||||
{
|
||||
uint8_t buffer[48]; // 48 is the amount of entropy needed to get a 64 base key
|
||||
cryptoRandomBytes(buffer, sizeof(buffer));
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
uint8_t buffer[48]; // 48 is the amount of entropy needed to get a 64 base key
|
||||
cryptoRandomBytes(buffer, sizeof(buffer));
|
||||
|
||||
result = strNewEncode(encodingBase64, BUF(buffer, sizeof(buffer)));
|
||||
// The pass is the encoded text rather than the bytes it encodes, so it is stored and derived from as that text
|
||||
result = cipherSpecNew(cipherType, BUFSTR(strNewEncode(encodingBase64, BUF(buffer, sizeof(buffer)))));
|
||||
cipherSpecMove(result, memContextPrior());
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(STRING, result);
|
||||
FUNCTION_TEST_RETURN(CIPHER_SPEC, result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
|
||||
@@ -10,8 +10,8 @@ Stanza Commands Handler
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Generate a cipher
|
||||
FN_EXTERN String *cipherPassGen(CipherType cipherType);
|
||||
// Generate cipher spec with a new pass, none when the type is none
|
||||
FN_EXTERN CipherSpec *cipherSpecGen(CipherType cipherType);
|
||||
|
||||
// Validate and return database information
|
||||
FN_EXTERN PgControl pgValidate(void);
|
||||
|
||||
@@ -75,33 +75,27 @@ cmdStanzaCreate(void)
|
||||
}
|
||||
|
||||
// If the repo is encrypted, generate a cipher passphrase for encrypting subsequent archive files
|
||||
const String *cipherPassSub = cipherPassGen(cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx));
|
||||
const CipherSpec *const cipherSpecArchive = cipherSpecGen(cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx));
|
||||
|
||||
// Create and save archive info
|
||||
infoArchive = infoArchiveNew(pgControl.version, pgControl.systemId, cipherPassSub);
|
||||
infoArchive = infoArchiveNew(pgControl.version, pgControl.systemId, cipherSpecArchive);
|
||||
|
||||
infoArchiveSaveFile(
|
||||
infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR,
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx), cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
infoArchiveSaveFile(infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
// If the repo is encrypted, generate a cipher passphrase for encrypting subsequent backup files
|
||||
cipherPassSub = cipherPassGen(cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx));
|
||||
// If the repo is encrypted, generate a cipher passphrase for encrypting subsequent manifests
|
||||
const CipherSpec *const cipherSpecManifest = cipherSpecGen(cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx));
|
||||
|
||||
// Create and save backup info
|
||||
infoBackup = infoBackupNew(pgControl.version, pgControl.systemId, pgControl.catalogVersion, cipherPassSub);
|
||||
infoBackup = infoBackupNew(pgControl.version, pgControl.systemId, pgControl.catalogVersion, cipherSpecManifest);
|
||||
|
||||
infoBackupSaveFile(
|
||||
infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR,
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx), cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
infoBackupSaveFile(infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
}
|
||||
// Else if at least one archive and one backup info file exists, then ensure both are valid
|
||||
else if ((archiveInfoFileExists || archiveInfoFileCopyExists) && (backupInfoFileExists || backupInfoFileCopyExists))
|
||||
{
|
||||
// Error if there is a mismatch between the archive and backup info files or the database version/system Id matches
|
||||
// current database
|
||||
checkStanzaInfoPg(
|
||||
storageRepoReadStanza, pgControl.version, pgControl.systemId,
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx), cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
checkStanzaInfoPg(storageRepoReadStanza, pgControl.version, pgControl.systemId, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
// The files are valid - upgrade
|
||||
const String *sourceFile = NULL;
|
||||
|
||||
@@ -51,13 +51,11 @@ cmdStanzaUpgrade(void)
|
||||
|
||||
// Load the info files (errors if missing)
|
||||
InfoArchive *const infoArchive = infoArchiveLoadFile(
|
||||
storageRepoReadStanza, INFO_ARCHIVE_PATH_FILE_STR, cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
storageRepoReadStanza, INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
InfoPgData archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
|
||||
|
||||
InfoBackup *const infoBackup = infoBackupLoadFile(
|
||||
storageRepoReadStanza, INFO_BACKUP_PATH_FILE_STR, cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
storageRepoReadStanza, INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
InfoPgData backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
|
||||
|
||||
// Since the file save of archive.info and backup.info are not atomic, then check and update each separately.
|
||||
@@ -83,19 +81,11 @@ cmdStanzaUpgrade(void)
|
||||
|
||||
// Save archive info
|
||||
if (infoArchiveUpgrade)
|
||||
{
|
||||
infoArchiveSaveFile(
|
||||
infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR,
|
||||
cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx), cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
}
|
||||
infoArchiveSaveFile(infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
// Save backup info
|
||||
if (infoBackupUpgrade)
|
||||
{
|
||||
infoBackupSaveFile(
|
||||
infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR, cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx),
|
||||
cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx));
|
||||
}
|
||||
infoBackupSaveFile(infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR, cfgCipherSpecMainIdx(repoIdx));
|
||||
|
||||
if (!(infoArchiveUpgrade || infoBackupUpgrade))
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ Verify File
|
||||
FN_EXTERN VerifyResult
|
||||
verifyFile(
|
||||
const String *const filePathName, const uint64_t offset, const Variant *const limit, const CompressType compressType,
|
||||
const Buffer *const fileChecksum, const uint64_t fileSize, const String *const cipherPass)
|
||||
const Buffer *const fileChecksum, const uint64_t fileSize, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING, filePathName); // Fully qualified file name
|
||||
@@ -27,7 +27,7 @@ verifyFile(
|
||||
FUNCTION_LOG_PARAM(ENUM, compressType); // Compression type
|
||||
FUNCTION_LOG_PARAM(BUFFER, fileChecksum); // Checksum for the file
|
||||
FUNCTION_LOG_PARAM(UINT64, fileSize); // Size of file
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass); // Password to access the repo file if encrypted
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec); // Cipher spec to access the repo file if encrypted
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(filePathName != NULL);
|
||||
@@ -45,8 +45,8 @@ verifyFile(
|
||||
IoFilterGroup *const filterGroup = ioReadFilterGroup(read);
|
||||
|
||||
// Add decryption filter
|
||||
if (cipherPass != NULL)
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, BUFSTR(cipherPass)));
|
||||
if (cipherSpecType(cipherSpec) != cipherTypeNone)
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeDecrypt, cipherSpec));
|
||||
|
||||
// Add decompression filter
|
||||
if (compressType != compressTypeNone)
|
||||
|
||||
@@ -5,7 +5,7 @@ Verify File
|
||||
#define COMMAND_VERIFY_FILE_H
|
||||
|
||||
#include "common/compress/helper.h"
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/spec.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
File result
|
||||
@@ -25,6 +25,6 @@ Functions
|
||||
// Verify a file in the pgBackRest repository
|
||||
FN_EXTERN VerifyResult verifyFile(
|
||||
const String *filePathName, uint64_t offset, const Variant *limit, CompressType compressType, const Buffer *fileChecksum,
|
||||
uint64_t fileSize, const String *cipherPass);
|
||||
uint64_t fileSize, const CipherSpec *cipherSpec);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,12 +41,12 @@ verifyFileProtocol(PackRead *const param)
|
||||
const CompressType compressType = (CompressType)pckReadU32P(param);
|
||||
const Buffer *const fileChecksum = pckReadBinP(param);
|
||||
const uint64_t fileSize = pckReadU64P(param);
|
||||
const String *const cipherPass = pckReadStrP(param);
|
||||
const CipherSpec *const cipherSpec = cipherSpecNewPack(param);
|
||||
|
||||
// Return result
|
||||
pckWriteU32P(
|
||||
protocolServerResultData(result),
|
||||
verifyFile(filePathName, offset, limit, compressType, fileChecksum, fileSize, cipherPass));
|
||||
verifyFile(filePathName, offset, limit, compressType, fileChecksum, fileSize, cipherSpec));
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
|
||||
@@ -123,9 +123,8 @@ typedef struct VerifyJobData
|
||||
String *currentBackup; // In progress backup, if any
|
||||
const InfoPg *pgHistory; // Database history list
|
||||
bool backupProcessing; // Are we processing WAL or are we processing backups
|
||||
const String *manifestCipherPass; // Cipher pass for reading backup manifests
|
||||
const String *walCipherPass; // Cipher pass for reading WAL files
|
||||
const String *backupCipherPass; // Cipher pass for reading backup files referenced in a manifest
|
||||
const CipherSpec *cipherSpecManifest; // Cipher spec for reading backup manifests
|
||||
const CipherSpec *cipherSpecArchive; // Cipher spec for reading WAL files
|
||||
unsigned int jobErrorTotal; // Total errors that occurred during the job execution
|
||||
List *archiveIdResultList; // Archive results
|
||||
List *backupResultList; // Backup results
|
||||
@@ -168,11 +167,11 @@ verifyInvalidFileAdd(List *const invalidFileList, const VerifyResult reason, con
|
||||
Load a file into memory
|
||||
***********************************************************************************************************************************/
|
||||
static StorageRead *
|
||||
verifyFileLoad(const String *const pathFileName, const String *const cipherPass)
|
||||
verifyFileLoad(const String *const pathFileName, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRING, pathFileName); // Fully qualified path/file name
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass); // Password to open file if encrypted
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec); // Cipher spec to open file if encrypted
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(pathFileName != NULL);
|
||||
@@ -183,8 +182,7 @@ verifyFileLoad(const String *const pathFileName, const String *const cipherPass)
|
||||
// *read points to a location within result so update result with contents based on necessary filters
|
||||
IoRead *const read = storageReadIo(result);
|
||||
|
||||
cipherBlockFilterGroupAdd(
|
||||
ioReadFilterGroup(read), cfgOptionStrId(cfgOptRepoCipherType), cipherModeDecrypt, cipherPass);
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(read), cipherModeDecrypt, cipherSpec);
|
||||
ioFilterGroupAdd(ioReadFilterGroup(read), cryptoHashNew(hashTypeSha1));
|
||||
|
||||
// If the file is compressed, add a decompression filter
|
||||
@@ -198,12 +196,12 @@ verifyFileLoad(const String *const pathFileName, const String *const cipherPass)
|
||||
Get status of info files in the repository
|
||||
***********************************************************************************************************************************/
|
||||
static VerifyInfoFile
|
||||
verifyInfoFile(const String *const pathFileName, const bool keepFile, const String *const cipherPass)
|
||||
verifyInfoFile(const String *const pathFileName, const bool keepFile, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING, pathFileName); // Fully qualified path/file name
|
||||
FUNCTION_LOG_PARAM(BOOL, keepFile); // Should the file be kept in memory?
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass); // Password to open file if encrypted
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec); // Cipher spec to open file if encrypted
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
FUNCTION_AUDIT_STRUCT();
|
||||
@@ -216,17 +214,17 @@ verifyInfoFile(const String *const pathFileName, const bool keepFile, const Stri
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
IoRead *const infoRead = storageReadIo(verifyFileLoad(pathFileName, cipherPass));
|
||||
IoRead *const infoRead = storageReadIo(verifyFileLoad(pathFileName, cipherSpec));
|
||||
|
||||
// If directed to keep the loaded file in memory, then move the file into the result, else drain the io and close it
|
||||
if (keepFile)
|
||||
{
|
||||
if (strBeginsWith(pathFileName, INFO_BACKUP_PATH_FILE_STR))
|
||||
result.backup = infoBackupMove(infoBackupNewLoad(infoRead), memContextPrior());
|
||||
result.backup = infoBackupMove(infoBackupNewLoad(infoRead, cipherSpec), memContextPrior());
|
||||
else if (strBeginsWith(pathFileName, INFO_ARCHIVE_PATH_FILE_STR))
|
||||
result.archive = infoArchiveMove(infoArchiveNewLoad(infoRead), memContextPrior());
|
||||
result.archive = infoArchiveMove(infoArchiveNewLoad(infoRead, cipherSpec), memContextPrior());
|
||||
else
|
||||
result.manifest = manifestMove(manifestNewLoad(infoRead), memContextPrior());
|
||||
result.manifest = manifestMove(manifestNewLoad(infoRead, cipherSpec), memContextPrior());
|
||||
}
|
||||
else
|
||||
ioReadDrain(infoRead);
|
||||
@@ -270,8 +268,7 @@ verifyArchiveInfoFile(void)
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Get the main info file
|
||||
const VerifyInfoFile verifyArchiveInfo = verifyInfoFile(
|
||||
INFO_ARCHIVE_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
const VerifyInfoFile verifyArchiveInfo = verifyInfoFile(INFO_ARCHIVE_PATH_FILE_STR, true, cfgCipherSpecMain());
|
||||
|
||||
// If the main file did not error, then report on the copy's status and check checksums
|
||||
if (verifyArchiveInfo.errorCode == 0)
|
||||
@@ -281,7 +278,7 @@ verifyArchiveInfoFile(void)
|
||||
|
||||
// Attempt to load the copy and report on it's status but don't keep it in memory
|
||||
const VerifyInfoFile verifyArchiveInfoCopy = verifyInfoFile(
|
||||
INFO_ARCHIVE_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
INFO_ARCHIVE_PATH_FILE_COPY_STR, false, cfgCipherSpecMain());
|
||||
|
||||
// If the copy loaded successfully, then check the checksums
|
||||
if (verifyArchiveInfoCopy.errorCode == 0)
|
||||
@@ -295,8 +292,7 @@ verifyArchiveInfoFile(void)
|
||||
else
|
||||
{
|
||||
// Attempt to load the copy
|
||||
const VerifyInfoFile verifyArchiveInfoCopy = verifyInfoFile(
|
||||
INFO_ARCHIVE_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
const VerifyInfoFile verifyArchiveInfoCopy = verifyInfoFile(INFO_ARCHIVE_PATH_FILE_COPY_STR, true, cfgCipherSpecMain());
|
||||
|
||||
// If loaded successfully, then return the copy as usable
|
||||
if (verifyArchiveInfoCopy.errorCode == 0)
|
||||
@@ -324,8 +320,7 @@ verifyBackupInfoFile(void)
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Get the main info file
|
||||
const VerifyInfoFile verifyBackupInfo = verifyInfoFile(
|
||||
INFO_BACKUP_PATH_FILE_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
const VerifyInfoFile verifyBackupInfo = verifyInfoFile(INFO_BACKUP_PATH_FILE_STR, true, cfgCipherSpecMain());
|
||||
|
||||
// If the main file did not error, then report on the copy's status and check checksums
|
||||
if (verifyBackupInfo.errorCode == 0)
|
||||
@@ -334,8 +329,7 @@ verifyBackupInfoFile(void)
|
||||
infoBackupMove(result, memContextPrior());
|
||||
|
||||
// Attempt to load the copy and report on it's status but don't keep it in memory
|
||||
const VerifyInfoFile verifyBackupInfoCopy = verifyInfoFile(
|
||||
INFO_BACKUP_PATH_FILE_COPY_STR, false, cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
const VerifyInfoFile verifyBackupInfoCopy = verifyInfoFile(INFO_BACKUP_PATH_FILE_COPY_STR, false, cfgCipherSpecMain());
|
||||
|
||||
// If the copy loaded successfully, then check the checksums
|
||||
if (verifyBackupInfoCopy.errorCode == 0)
|
||||
@@ -349,8 +343,7 @@ verifyBackupInfoFile(void)
|
||||
else
|
||||
{
|
||||
// Attempt to load the copy
|
||||
const VerifyInfoFile verifyBackupInfoCopy = verifyInfoFile(
|
||||
INFO_BACKUP_PATH_FILE_COPY_STR, true, cfgOptionStrNull(cfgOptRepoCipherPass));
|
||||
const VerifyInfoFile verifyBackupInfoCopy = verifyInfoFile(INFO_BACKUP_PATH_FILE_COPY_STR, true, cfgCipherSpecMain());
|
||||
|
||||
// If loaded successfully, then return the copy as usable
|
||||
if (verifyBackupInfoCopy.errorCode == 0)
|
||||
@@ -370,12 +363,12 @@ Get the manifest file
|
||||
***********************************************************************************************************************************/
|
||||
static Manifest *
|
||||
verifyManifestFile(
|
||||
VerifyBackupResult *const backupResult, const String *const cipherPass, bool currentBackup, const InfoPg *const pgHistory,
|
||||
unsigned int *const jobErrorTotal)
|
||||
VerifyBackupResult *const backupResult, const CipherSpec *const cipherSpecManifest, bool currentBackup,
|
||||
const InfoPg *const pgHistory, unsigned int *const jobErrorTotal)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM_P(VERIFY_BACKUP_RESULT, backupResult); // The result set for the backup being processed
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass); // Passphrase to access the manifest file
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecManifest); // Cipher spec to access the manifest file
|
||||
FUNCTION_LOG_PARAM(BOOL, currentBackup); // Is this possibly a backup currently in progress?
|
||||
FUNCTION_LOG_PARAM(INFO_PG, pgHistory); // Database history
|
||||
FUNCTION_LOG_PARAM_P(UINT, jobErrorTotal); // Pointer to the overall job error total
|
||||
@@ -388,7 +381,7 @@ verifyManifestFile(
|
||||
const String *const fileName = strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupResult->backupLabel));
|
||||
|
||||
// Get the main manifest file
|
||||
const VerifyInfoFile verifyManifestInfo = verifyInfoFile(fileName, true, cipherPass);
|
||||
const VerifyInfoFile verifyManifestInfo = verifyInfoFile(fileName, true, cipherSpecManifest);
|
||||
|
||||
// If the main file did not error, then report on the copy's status and check checksums
|
||||
if (verifyManifestInfo.errorCode == 0)
|
||||
@@ -402,7 +395,7 @@ verifyManifestFile(
|
||||
|
||||
// Attempt to load the copy and report on it's status but don't keep it in memory
|
||||
const VerifyInfoFile verifyManifestInfoCopy = verifyInfoFile(
|
||||
strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), false, cipherPass);
|
||||
strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), false, cipherSpecManifest);
|
||||
|
||||
// If the copy loaded successfully, then check the checksums
|
||||
if (verifyManifestInfoCopy.errorCode == 0)
|
||||
@@ -423,7 +416,7 @@ verifyManifestFile(
|
||||
currentBackup = false;
|
||||
|
||||
const VerifyInfoFile verifyManifestInfoCopy = verifyInfoFile(
|
||||
strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), true, cipherPass);
|
||||
strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), true, cipherSpecManifest);
|
||||
|
||||
// If loaded successfully, then return the copy as usable
|
||||
if (verifyManifestInfoCopy.errorCode == 0)
|
||||
@@ -662,7 +655,7 @@ verifyBackupSet(VerifyJobData *const jobData, const String *const backupLabel)
|
||||
{
|
||||
const Manifest *const manifest = manifestLoadFile(
|
||||
storageRepo(), strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupLabel)),
|
||||
cfgOptionStrId(cfgOptRepoCipherType), jobData->manifestCipherPass);
|
||||
jobData->cipherSpecManifest);
|
||||
|
||||
// Check files for block incremental
|
||||
bool hasBlockIncr = false;
|
||||
@@ -836,7 +829,7 @@ verifyArchive(VerifyJobData *const jobData)
|
||||
strNewFmt(
|
||||
STORAGE_REPO_ARCHIVE "/%s/%s/%s", strZ(archiveResult->archiveId), strZ(walPath),
|
||||
strZ(strLstGet(jobData->walFileList, 0))),
|
||||
jobData->walCipherPass);
|
||||
jobData->cipherSpecArchive);
|
||||
|
||||
const PgWal walInfo = pgWalFromBuffer(
|
||||
storageGetP(walRead, .exactSize = PG_WAL_HEADER_SIZE), cfgOptionStrNull(cfgOptPgVersionForce));
|
||||
@@ -872,7 +865,7 @@ verifyArchive(VerifyJobData *const jobData)
|
||||
pckWriteU32P(param, compressTypeFromName(filePathName));
|
||||
pckWriteBinP(param, checksum);
|
||||
pckWriteU64P(param, archiveResult->pgWalInfo.size);
|
||||
pckWriteStrP(param, jobData->walCipherPass);
|
||||
cipherSpecPack(param, jobData->cipherSpecArchive);
|
||||
|
||||
// Assign job to result, prepending the archiveId to the key for consistency with backup processing
|
||||
const String *const jobKey = strNewFmt("%s/%s", strZ(archiveResult->archiveId), strZ(filePathName));
|
||||
@@ -973,7 +966,7 @@ verifyBackup(VerifyJobData *const jobData)
|
||||
|
||||
// Get a usable backup manifest file
|
||||
Manifest *const manifest = verifyManifestFile(
|
||||
backupResult, jobData->manifestCipherPass, inProgressBackup, jobData->pgHistory, &jobData->jobErrorTotal);
|
||||
backupResult, jobData->cipherSpecManifest, inProgressBackup, jobData->pgHistory, &jobData->jobErrorTotal);
|
||||
|
||||
// If a usable backup.manifest file is not found
|
||||
if (manifest == NULL)
|
||||
@@ -989,15 +982,7 @@ verifyBackup(VerifyJobData *const jobData)
|
||||
{
|
||||
// Move the manifest to the jobData for processing
|
||||
jobData->manifest = manifestMove(manifest, jobData->memContext);
|
||||
|
||||
// Initialize the jobData
|
||||
MEM_CONTEXT_BEGIN(jobData->memContext)
|
||||
{
|
||||
// Get the cipher subpass used to decrypt files in the backup and initialize the file list index
|
||||
jobData->backupCipherPass = strDup(manifestCipherSubPass(jobData->manifest));
|
||||
jobData->manifestFileIdx = 0;
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
jobData->manifestFileIdx = 0;
|
||||
|
||||
const ManifestData *const manData = manifestData(jobData->manifest);
|
||||
|
||||
@@ -1114,7 +1099,7 @@ verifyBackup(VerifyJobData *const jobData)
|
||||
pckWriteU32P(param, compressTypeNone);
|
||||
pckWriteBinP(param, BUF(fileData.checksumRepoSha1, HASH_TYPE_SHA1_SIZE));
|
||||
pckWriteU64P(param, fileData.sizeRepo);
|
||||
pckWriteStrP(param, NULL);
|
||||
cipherSpecPack(param, cipherSpecNewNone());
|
||||
}
|
||||
// Else use the file checksum, which may require additional filters, e.g. decompression
|
||||
else
|
||||
@@ -1122,7 +1107,7 @@ verifyBackup(VerifyJobData *const jobData)
|
||||
pckWriteU32P(param, manifestData(jobData->manifest)->backupOptionCompressType);
|
||||
pckWriteBinP(param, BUF(fileData.checksumSha1, HASH_TYPE_SHA1_SIZE));
|
||||
pckWriteU64P(param, fileData.size);
|
||||
pckWriteStrP(param, jobData->backupCipherPass);
|
||||
cipherSpecPack(param, manifestCipherSpec(jobData->manifest));
|
||||
}
|
||||
|
||||
// Assign job to result (prepend backup label being processed to the key since some files are in a prior
|
||||
@@ -1639,8 +1624,8 @@ verifyProcess(const bool verboseText)
|
||||
.walPathList = NULL,
|
||||
.walFileList = strLstNew(),
|
||||
.pgHistory = infoArchivePg(archiveInfo),
|
||||
.manifestCipherPass = infoPgCipherPass(infoBackupPg(backupInfo)),
|
||||
.walCipherPass = infoPgCipherPass(infoArchivePg(archiveInfo)),
|
||||
.cipherSpecManifest = infoBackupCipherSpec(backupInfo),
|
||||
.cipherSpecArchive = infoArchiveCipherSpec(archiveInfo),
|
||||
.archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator = archiveIdComparator),
|
||||
.backupResultList = lstNewP(sizeof(VerifyBackupResult), .comparator = lstComparatorStr),
|
||||
};
|
||||
|
||||
@@ -384,25 +384,24 @@ cipherBlockInputSame(const THIS_VOID)
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN IoFilter *
|
||||
cipherBlockNew(const CipherMode mode, const CipherType cipherType, const Buffer *const pass, const CipherBlockNewParam param)
|
||||
cipherBlockNew(const CipherMode mode, const CipherSpec *const cipherSpec, const CipherBlockNewParam param)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, mode);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(BUFFER, pass); // Use FUNCTION_TEST so passphrase is not logged
|
||||
FUNCTION_LOG_PARAM(STRING, param.digest);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_PARAM(BOOL, param.raw);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(pass != NULL);
|
||||
ASSERT(!bufEmpty(pass));
|
||||
ASSERT(cipherSpec != NULL);
|
||||
ASSERT(cipherSpecType(cipherSpec) != cipherTypeNone);
|
||||
ASSERT(cipherSpecPass(cipherSpec) != NULL && !bufEmpty(cipherSpecPass(cipherSpec)));
|
||||
|
||||
// Init crypto subsystem
|
||||
cryptoInit();
|
||||
|
||||
// Lookup cipher by name. This means the ciphers passed in must exactly match a name expected by OpenSSL. This is a good thing
|
||||
// since the name required by the openssl command-line tool will match what is used by pgBackRest.
|
||||
char *const cipherTypeZ = zNewStrId(cipherType);
|
||||
char *const cipherTypeZ = zNewStrId(cipherSpecType(cipherSpec));
|
||||
const EVP_CIPHER *cipher = EVP_get_cipherbyname(cipherTypeZ);
|
||||
|
||||
if (!cipher)
|
||||
@@ -410,17 +409,6 @@ cipherBlockNew(const CipherMode mode, const CipherType cipherType, const Buffer
|
||||
|
||||
zFree(cipherTypeZ);
|
||||
|
||||
// Lookup digest. If not defined it will be set to sha1.
|
||||
const EVP_MD *digest = NULL;
|
||||
|
||||
if (param.digest)
|
||||
digest = EVP_get_digestbyname(strZ(param.digest));
|
||||
else
|
||||
digest = EVP_sha1();
|
||||
|
||||
if (!digest)
|
||||
THROW_FMT(AssertError, "unable to load digest '%s'", strZ(param.digest));
|
||||
|
||||
OBJ_NEW_BEGIN(CipherBlock, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||
{
|
||||
*this = (CipherBlock)
|
||||
@@ -428,8 +416,10 @@ cipherBlockNew(const CipherMode mode, const CipherType cipherType, const Buffer
|
||||
.mode = mode,
|
||||
.raw = param.raw,
|
||||
.cipher = cipher,
|
||||
.digest = digest,
|
||||
.pass = bufDup(pass),
|
||||
|
||||
// The key is always derived with SHA-1. Deriving it with anything else is not supported yet.
|
||||
.digest = EVP_sha1(),
|
||||
.pass = bufDup(cipherSpecPass(cipherSpec)),
|
||||
};
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
@@ -442,9 +432,7 @@ cipherBlockNew(const CipherMode mode, const CipherType cipherType, const Buffer
|
||||
PackWrite *const packWrite = pckWriteNewP();
|
||||
|
||||
pckWriteU64P(packWrite, mode);
|
||||
pckWriteU64P(packWrite, cipherType);
|
||||
pckWriteBinP(packWrite, pass);
|
||||
pckWriteStrP(packWrite, param.digest);
|
||||
cipherSpecPack(packWrite, cipherSpec);
|
||||
pckWriteBoolP(packWrite, param.raw);
|
||||
pckWriteEndP(packWrite);
|
||||
|
||||
@@ -468,12 +456,10 @@ cipherBlockNewPack(const Pack *const paramList)
|
||||
{
|
||||
PackRead *const paramListPack = pckReadNew(paramList);
|
||||
const CipherMode cipherMode = (CipherMode)pckReadU64P(paramListPack);
|
||||
const CipherType cipherType = (CipherType)pckReadU64P(paramListPack);
|
||||
const Buffer *const pass = pckReadBinP(paramListPack);
|
||||
const String *const digest = pckReadStrP(paramListPack);
|
||||
const CipherSpec *const cipherSpec = cipherSpecNewPack(paramListPack);
|
||||
const bool raw = pckReadBoolP(paramListPack);
|
||||
|
||||
result = ioFilterMove(cipherBlockNewP(cipherMode, cipherType, pass, .digest = digest, .raw = raw), memContextPrior());
|
||||
result = ioFilterMove(cipherBlockNewP(cipherMode, cipherSpec, .raw = raw), memContextPrior());
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
@@ -482,20 +468,19 @@ cipherBlockNewPack(const Pack *const paramList)
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN IoFilterGroup *
|
||||
cipherBlockFilterGroupAdd(IoFilterGroup *const filterGroup, const CipherType type, const CipherMode mode, const String *const pass)
|
||||
cipherBlockFilterGroupAdd(IoFilterGroup *const filterGroup, const CipherMode mode, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace);
|
||||
FUNCTION_LOG_PARAM(IO_FILTER_GROUP, filterGroup);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, type);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, mode);
|
||||
FUNCTION_TEST_PARAM(STRING, pass); // Use FUNCTION_TEST so passphrase is not logged
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(filterGroup != NULL);
|
||||
ASSERT((type == cipherTypeNone && pass == NULL) || (type != cipherTypeNone && pass != NULL));
|
||||
ASSERT(cipherSpec != NULL);
|
||||
|
||||
if (type != cipherTypeNone)
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(mode, type, BUFSTR(pass)));
|
||||
if (cipherSpecType(cipherSpec) != cipherTypeNone)
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(mode, cipherSpec));
|
||||
|
||||
FUNCTION_LOG_RETURN(IO_FILTER_GROUP, filterGroup);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Block Cipher Header
|
||||
#ifndef COMMON_CRYPTO_CIPHERBLOCK_H
|
||||
#define COMMON_CRYPTO_CIPHERBLOCK_H
|
||||
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/io/filter/group.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@@ -18,21 +18,19 @@ Constructors
|
||||
typedef struct CipherBlockNewParam
|
||||
{
|
||||
VAR_PARAM_HEADER;
|
||||
const String *digest; // Digest to use (defaults to SHA-1)
|
||||
bool raw; // Omit header magic to save space
|
||||
} CipherBlockNewParam;
|
||||
|
||||
#define cipherBlockNewP(mode, cipherType, pass, ...) \
|
||||
cipherBlockNew(mode, cipherType, pass, (CipherBlockNewParam){VAR_PARAM_INIT, __VA_ARGS__})
|
||||
#define cipherBlockNewP(mode, cipherSpec, ...) \
|
||||
cipherBlockNew(mode, cipherSpec, (CipherBlockNewParam){VAR_PARAM_INIT, __VA_ARGS__})
|
||||
|
||||
FN_EXTERN IoFilter *cipherBlockNew(CipherMode mode, CipherType cipherType, const Buffer *pass, CipherBlockNewParam param);
|
||||
FN_EXTERN IoFilter *cipherBlockNew(CipherMode mode, const CipherSpec *cipherSpec, CipherBlockNewParam param);
|
||||
FN_EXTERN IoFilter *cipherBlockNewPack(const Pack *paramList);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Helper functions
|
||||
***********************************************************************************************************************************/
|
||||
// Add a block cipher to an io object
|
||||
FN_EXTERN IoFilterGroup *cipherBlockFilterGroupAdd(
|
||||
IoFilterGroup *filterGroup, CipherType type, CipherMode mode, const String *pass);
|
||||
// Add a block cipher to an io object. Nothing is added when the repository is not encrypted.
|
||||
FN_EXTERN IoFilterGroup *cipherBlockFilterGroupAdd(IoFilterGroup *filterGroup, CipherMode mode, const CipherSpec *cipherSpec);
|
||||
|
||||
#endif
|
||||
|
||||
96
src/common/crypto/spec.c
Normal file
96
src/common/crypto/spec.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/***********************************************************************************************************************************
|
||||
Cipher Spec
|
||||
***********************************************************************************************************************************/
|
||||
#include <build.h>
|
||||
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
struct CipherSpec
|
||||
{
|
||||
CipherSpecPub pub; // Publicly accessible variables
|
||||
};
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN CipherSpec *
|
||||
cipherSpecNew(const CipherType type, const Buffer *const pass)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRING_ID, type);
|
||||
FUNCTION_TEST_PARAM(BUFFER, pass);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT((type == cipherTypeNone) == (pass == NULL));
|
||||
ASSERT(pass == NULL || !bufEmpty(pass));
|
||||
|
||||
OBJ_NEW_BEGIN(CipherSpec, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
*this = (CipherSpec){.pub = {.type = type}};
|
||||
|
||||
if (this->pub.type != cipherTypeNone)
|
||||
this->pub.pass = bufDup(pass);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(CIPHER_SPEC, this);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN CipherSpec *
|
||||
cipherSpecNewPack(PackRead *const packRead)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(PACK_READ, packRead);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(packRead != NULL);
|
||||
|
||||
OBJ_NEW_BEGIN(CipherSpec, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
*this = (CipherSpec){.pub = {.type = (CipherType)pckReadStrIdP(packRead)}};
|
||||
|
||||
// Nothing else was written when there is no cipher. The pass is read here rather than copied in since this context is the
|
||||
// one it belongs in.
|
||||
if (this->pub.type != cipherTypeNone)
|
||||
this->pub.pass = pckReadBinP(packRead);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(CIPHER_SPEC, this);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN void
|
||||
cipherSpecPack(PackWrite *const packWrite, const CipherSpec *const this)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(PACK_WRITE, packWrite);
|
||||
FUNCTION_TEST_PARAM(CIPHER_SPEC, this);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(packWrite != NULL);
|
||||
ASSERT(this != NULL);
|
||||
|
||||
pckWriteStrIdP(packWrite, cipherSpecType(this));
|
||||
|
||||
// Nothing else is needed when there is no cipher
|
||||
if (cipherSpecType(this) != cipherTypeNone)
|
||||
pckWriteBinP(packWrite, cipherSpecPass(this));
|
||||
|
||||
FUNCTION_TEST_RETURN_VOID();
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN void
|
||||
cipherSpecToLog(const CipherSpec *const this, StringStatic *const debugLog)
|
||||
{
|
||||
char typeZ[STRID_MAX + 1];
|
||||
strIdToZ(cipherSpecType(this), typeZ);
|
||||
|
||||
// The pass is never logged
|
||||
strStcFmt(debugLog, "{type: %s}", typeZ);
|
||||
}
|
||||
101
src/common/crypto/spec.h
Normal file
101
src/common/crypto/spec.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/***********************************************************************************************************************************
|
||||
Cipher Spec
|
||||
|
||||
Everything needed to encrypt or decrypt, kept together so that adding to it does not mean changing every function and protocol
|
||||
message that carries it.
|
||||
|
||||
The passphrase (pass) contains the bytes the key is derived from. There is no pass when the type is none, and the pass is never
|
||||
logged.
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_CRYPTO_SPEC_H
|
||||
#define COMMON_CRYPTO_SPEC_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct CipherSpec CipherSpec;
|
||||
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/type/buffer.h"
|
||||
#include "common/type/object.h"
|
||||
#include "common/type/pack.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
// Create from a pass
|
||||
FN_EXTERN CipherSpec *cipherSpecNew(CipherType type, const Buffer *pass);
|
||||
|
||||
// Create for no encryption
|
||||
FN_INLINE_ALWAYS CipherSpec *
|
||||
cipherSpecNewNone(void)
|
||||
{
|
||||
return cipherSpecNew(cipherTypeNone, NULL);
|
||||
}
|
||||
|
||||
// Create from a pack written by cipherSpecPack()
|
||||
FN_EXTERN CipherSpec *cipherSpecNewPack(PackRead *packRead);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct CipherSpecPub
|
||||
{
|
||||
CipherType type; // Cipher type, none when not encrypted
|
||||
const Buffer *pass; // Passphrase text or key bytes
|
||||
} CipherSpecPub;
|
||||
|
||||
// Cipher type
|
||||
FN_INLINE_ALWAYS CipherType
|
||||
cipherSpecType(const CipherSpec *const this)
|
||||
{
|
||||
return THIS_PUB(CipherSpec)->type;
|
||||
}
|
||||
|
||||
// Passphrase text or key bytes
|
||||
FN_INLINE_ALWAYS const Buffer *
|
||||
cipherSpecPass(const CipherSpec *const this)
|
||||
{
|
||||
return THIS_PUB(CipherSpec)->pass;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Duplicate
|
||||
FN_INLINE_ALWAYS CipherSpec *
|
||||
cipherSpecDup(const CipherSpec *const this)
|
||||
{
|
||||
return cipherSpecNew(cipherSpecType(this), cipherSpecPass(this));
|
||||
}
|
||||
|
||||
// Write to a pack so it can be passed over a protocol
|
||||
FN_EXTERN void cipherSpecPack(PackWrite *packWrite, const CipherSpec *this);
|
||||
|
||||
// Move to a new parent mem context
|
||||
FN_INLINE_ALWAYS CipherSpec *
|
||||
cipherSpecMove(CipherSpec *const this, MemContext *const parentNew)
|
||||
{
|
||||
return objMove(this, parentNew);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Destructor
|
||||
***********************************************************************************************************************************/
|
||||
FN_INLINE_ALWAYS void
|
||||
cipherSpecFree(CipherSpec *const this)
|
||||
{
|
||||
objFree(this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
FN_EXTERN void cipherSpecToLog(const CipherSpec *this, StringStatic *debugLog);
|
||||
|
||||
#define FUNCTION_LOG_CIPHER_SPEC_TYPE \
|
||||
CipherSpec *
|
||||
#define FUNCTION_LOG_CIPHER_SPEC_FORMAT(value, buffer, bufferSize) \
|
||||
FUNCTION_LOG_OBJECT_FORMAT(value, cipherSpecToLog, buffer, bufferSize)
|
||||
|
||||
#endif
|
||||
@@ -1078,3 +1078,39 @@ cfgOptionInvalidate(const ConfigOption optionId)
|
||||
|
||||
FUNCTION_TEST_RETURN_VOID();
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN const CipherSpec *
|
||||
cfgCipherSpecMainIdx(const unsigned int repoIdx)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(UINT, repoIdx);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(repoIdx < cfgOptionGroupIdxTotal(cfgOptGrpRepo));
|
||||
|
||||
// Allocate a slot per repo. Each repo has its own cipher type and passphrase so cipher spec cannot be shared between them.
|
||||
if (configLocal->cipherSpecMain == NULL)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(configLocal->memContext)
|
||||
{
|
||||
configLocal->cipherSpecMain = memNewPtrArray(cfgOptionGroupIdxTotal(cfgOptGrpRepo));
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
|
||||
// Get cipher spec if it doesn't exist
|
||||
if (configLocal->cipherSpecMain[repoIdx] == NULL)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(configLocal->memContext)
|
||||
{
|
||||
const CipherType cipherType = cfgOptionIdxStrId(cfgOptRepoCipherType, repoIdx);
|
||||
|
||||
configLocal->cipherSpecMain[repoIdx] = cipherSpecNew(
|
||||
cipherType, cipherType == cipherTypeNone ? NULL : BUFSTR(cfgOptionIdxStr(cfgOptRepoCipherPass, repoIdx)));
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN_CONST(CIPHER_SPEC, configLocal->cipherSpecMain[repoIdx]);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ sets the command and options and determines which options are valid for a comman
|
||||
#ifndef CONFIG_CONFIG_H
|
||||
#define CONFIG_CONFIG_H
|
||||
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/log.h"
|
||||
#include "common/type/stringId.h"
|
||||
#include "common/type/stringList.h"
|
||||
@@ -238,6 +239,21 @@ FN_EXTERN bool cfgOptionValid(ConfigOption optionId);
|
||||
FN_EXTERN bool cfgOptionTest(ConfigOption optionId);
|
||||
FN_EXTERN bool cfgOptionIdxTest(ConfigOption optionId, unsigned int optionIdx);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Cipher Functions
|
||||
|
||||
Main cipher spec for a repository, built from the cipher options and cached per repo since the options cannot change while a command
|
||||
runs. This is the top of the chain. The info files are read with it and each of those carries the cipher spec for the files that
|
||||
depend on it, so nothing further down needs to consult the options again.
|
||||
***********************************************************************************************************************************/
|
||||
FN_EXTERN const CipherSpec *cfgCipherSpecMainIdx(unsigned int repoIdx);
|
||||
|
||||
FN_INLINE_ALWAYS const CipherSpec *
|
||||
cfgCipherSpecMain(void)
|
||||
{
|
||||
return cfgCipherSpecMainIdx(cfgOptionIdxDefault(cfgOptRepoCipherType));
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Option Source Enum
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ typedef struct Config
|
||||
|
||||
ConfigOptionGroupData optionGroup[CFG_OPTION_GROUP_TOTAL]; // Option group data
|
||||
ConfigOptionData option[CFG_OPTION_TOTAL]; // Option data
|
||||
|
||||
CipherSpec **cipherSpecMain; // Main cipher spec for the cipher options by repo index
|
||||
} Config;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
|
||||
@@ -94,10 +94,10 @@ BUFFER_STRDEF_STATIC(INFO_CHECKSUM_END_BUF, "}}");
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN Info *
|
||||
infoNew(const String *const cipherPass)
|
||||
infoNew(const CipherSpec *const cipherSpecSub)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass); // Use FUNCTION_TEST so cipher is not logged
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecSub);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
OBJ_NEW_BEGIN(Info, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
@@ -105,7 +105,7 @@ infoNew(const String *const cipherPass)
|
||||
*this = (Info){};
|
||||
|
||||
// Cipher used to encrypt/decrypt subsequent dependent files. Value may be NULL.
|
||||
infoCipherPassSet(this, cipherPass);
|
||||
infoCipherSpecSet(this, cipherSpecSub);
|
||||
this->pub.backrestVersion = STRDEF(PROJECT_VERSION);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
@@ -120,10 +120,12 @@ infoNew(const String *const cipherPass)
|
||||
#define INFO_KEY_CIPHER_PASS "cipher-pass"
|
||||
|
||||
FN_EXTERN Info *
|
||||
infoNewLoad(IoRead *const read, InfoLoadNewCallback *const callbackFunction, void *const callbackData)
|
||||
infoNewLoad(
|
||||
IoRead *const read, const CipherSpec *const cipherSpec, InfoLoadNewCallback *const callbackFunction, void *const callbackData)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(IO_READ, read);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_PARAM(FUNCTIONP, callbackFunction);
|
||||
FUNCTION_LOG_PARAM_P(VOID, callbackData);
|
||||
FUNCTION_LOG_END();
|
||||
@@ -131,6 +133,7 @@ infoNewLoad(IoRead *const read, InfoLoadNewCallback *const callbackFunction, voi
|
||||
FUNCTION_AUDIT_CALLBACK();
|
||||
|
||||
ASSERT(read != NULL);
|
||||
ASSERT(cipherSpec != NULL);
|
||||
ASSERT(callbackFunction != NULL);
|
||||
ASSERT(callbackData != NULL);
|
||||
|
||||
@@ -213,7 +216,9 @@ infoNewLoad(IoRead *const read, InfoLoadNewCallback *const callbackFunction, voi
|
||||
{
|
||||
MEM_CONTEXT_OBJ_BEGIN(this)
|
||||
{
|
||||
this->pub.cipherPass = varStr(jsonToVar(value->value));
|
||||
// The dependent files are encrypted with the same cipher type as this one
|
||||
this->pub.cipherSpec = cipherSpecNew(
|
||||
cipherSpecType(cipherSpec), BUFSTR(varStr(jsonToVar(value->value))));
|
||||
}
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
}
|
||||
@@ -250,6 +255,10 @@ infoNewLoad(IoRead *const read, InfoLoadNewCallback *const callbackFunction, voi
|
||||
}
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
// A file with no cipher section has no encrypted dependent files
|
||||
if (this->pub.cipherSpec == NULL)
|
||||
infoCipherSpecSet(this, NULL);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
@@ -366,10 +375,12 @@ infoSave(Info *const this, IoWrite *const write, InfoSaveCallback *const callbac
|
||||
infoSaveValue(&data, INFO_SECTION_BACKREST, INFO_KEY_VERSION, jsonFromVar(VARSTRDEF(PROJECT_VERSION)));
|
||||
|
||||
// Add cipher passphrase if defined
|
||||
if (infoCipherPass(this) != NULL)
|
||||
if (cipherSpecType(infoCipherSpec(this)) != cipherTypeNone)
|
||||
{
|
||||
callbackFunction(callbackData, STRDEF(INFO_SECTION_CIPHER), &data);
|
||||
infoSaveValue(&data, INFO_SECTION_CIPHER, INFO_KEY_CIPHER_PASS, jsonFromVar(VARSTR(infoCipherPass(this))));
|
||||
infoSaveValue(
|
||||
&data, INFO_SECTION_CIPHER, INFO_KEY_CIPHER_PASS,
|
||||
jsonFromVar(VARSTR(strNewBuf(cipherSpecPass(infoCipherSpec(this))))));
|
||||
}
|
||||
|
||||
// Flush out any additional sections
|
||||
@@ -395,11 +406,11 @@ infoSave(Info *const this, IoWrite *const write, InfoSaveCallback *const callbac
|
||||
Getters/Setters
|
||||
***********************************************************************************************************************************/
|
||||
FN_EXTERN void
|
||||
infoCipherPassSet(Info *const this, const String *const cipherPass)
|
||||
infoCipherSpecSet(Info *const this, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(INFO, this);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_TEST_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
FUNCTION_AUDIT_IF(memContextCurrent() != objMemContext(this)); // Do not audit calls from within the object
|
||||
@@ -408,7 +419,8 @@ infoCipherPassSet(Info *const this, const String *const cipherPass)
|
||||
|
||||
MEM_CONTEXT_OBJ_BEGIN(this)
|
||||
{
|
||||
this->pub.cipherPass = strDup(cipherPass);
|
||||
// Copy so the caller is free to release what was passed in, and so the getter never returns NULL
|
||||
this->pub.cipherSpec = cipherSpec == NULL ? cipherSpecNewNone() : cipherSpecDup(cipherSpec);
|
||||
}
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ Object type
|
||||
typedef struct Info Info;
|
||||
typedef struct InfoSave InfoSave;
|
||||
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/ini.h"
|
||||
#include "common/type/json.h"
|
||||
#include "storage/storage.h"
|
||||
@@ -38,10 +39,12 @@ typedef void InfoSaveCallback(void *data, const String *sectionNext, InfoSave *i
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
FN_EXTERN Info *infoNew(const String *cipherPassSub);
|
||||
FN_EXTERN Info *infoNew(const CipherSpec *cipherSpecSub);
|
||||
|
||||
// Create new object and load contents from a file
|
||||
FN_EXTERN Info *infoNewLoad(IoRead *read, InfoLoadNewCallback *callbackFunction, void *callbackData);
|
||||
// Create new object and load contents from a file. The cipher spec the file is read with supplies the type for the cipher spec
|
||||
// built from the pass stored in it.
|
||||
FN_EXTERN Info *infoNewLoad(
|
||||
IoRead *read, const CipherSpec *cipherSpec, InfoLoadNewCallback *callbackFunction, void *callbackData);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
@@ -49,17 +52,19 @@ Getters/Setters
|
||||
typedef struct InfoPub
|
||||
{
|
||||
const String *backrestVersion; // pgBackRest version
|
||||
const String *cipherPass; // Cipher passphrase if set
|
||||
const CipherSpec *cipherSpec; // Cipher spec for dependent files
|
||||
} InfoPub;
|
||||
|
||||
// Cipher passphrase if set
|
||||
FN_INLINE_ALWAYS const String *
|
||||
infoCipherPass(const Info *const this)
|
||||
// Cipher spec for the files that depend on this one, e.g. the manifest for backup.info. Never NULL, so it can be handed on
|
||||
// without a check, and none when there is no pass.
|
||||
FN_INLINE_ALWAYS const CipherSpec *
|
||||
infoCipherSpec(const Info *const this)
|
||||
{
|
||||
return THIS_PUB(Info)->cipherPass;
|
||||
return THIS_PUB(Info)->cipherSpec;
|
||||
}
|
||||
|
||||
FN_EXTERN void infoCipherPassSet(Info *this, const String *cipherPass);
|
||||
// Set cipher spec for dependent files. NULL means they are not encrypted.
|
||||
FN_EXTERN void infoCipherSpecSet(Info *this, const CipherSpec *cipherSpec);
|
||||
|
||||
// pgBackRest version
|
||||
FN_INLINE_ALWAYS const String *
|
||||
|
||||
@@ -57,12 +57,12 @@ infoArchiveNewInternal(void)
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN InfoArchive *
|
||||
infoArchiveNew(const unsigned int pgVersion, const uint64_t pgSystemId, const String *const cipherPassSub)
|
||||
infoArchiveNew(const unsigned int pgVersion, const uint64_t pgSystemId, const CipherSpec *const cipherSpecSub)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(UINT, pgVersion);
|
||||
FUNCTION_LOG_PARAM(UINT64, pgSystemId);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPassSub);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecSub);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(pgVersion > 0 && pgSystemId > 0);
|
||||
@@ -74,7 +74,7 @@ infoArchiveNew(const unsigned int pgVersion, const uint64_t pgSystemId, const St
|
||||
this = infoArchiveNewInternal();
|
||||
|
||||
// Initialize the pg data
|
||||
this->pub.infoPg = infoPgNew(infoPgArchive, cipherPassSub);
|
||||
this->pub.infoPg = infoPgNew(infoPgArchive, cipherSpecSub);
|
||||
infoArchivePgSet(this, pgVersion, pgSystemId);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
@@ -84,10 +84,11 @@ infoArchiveNew(const unsigned int pgVersion, const uint64_t pgSystemId, const St
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN InfoArchive *
|
||||
infoArchiveNewLoad(IoRead *const read)
|
||||
infoArchiveNewLoad(IoRead *const read, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(IO_READ, read);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(read != NULL);
|
||||
@@ -97,7 +98,7 @@ infoArchiveNewLoad(IoRead *const read)
|
||||
OBJ_NEW_BASE_BEGIN(InfoArchive, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoArchiveNewInternal();
|
||||
this->pub.infoPg = infoPgNewLoad(read, infoPgArchive, NULL, NULL);
|
||||
this->pub.infoPg = infoPgNewLoad(read, infoPgArchive, cipherSpec, NULL, NULL);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
@@ -207,8 +208,7 @@ typedef struct InfoArchiveLoadFileData
|
||||
MemContext *memContext; // Mem context
|
||||
const Storage *storage; // Storage to load from
|
||||
const String *fileName; // Base filename
|
||||
CipherType cipherType; // Cipher type
|
||||
const String *cipherPass; // Cipher passphrase
|
||||
const CipherSpec *cipherSpec; // Cipher spec
|
||||
InfoArchive *infoArchive; // Loaded infoArchive object
|
||||
} InfoArchiveLoadFileData;
|
||||
|
||||
@@ -234,11 +234,12 @@ infoArchiveLoadFileCallback(void *const data, const unsigned int try)
|
||||
|
||||
// Attempt to load the file
|
||||
IoRead *const read = storageReadIo(storageNewReadP(loadData->storage, fileName));
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(read), loadData->cipherType, cipherModeDecrypt, loadData->cipherPass);
|
||||
cipherBlockFilterGroupAdd(
|
||||
ioReadFilterGroup(read), cipherModeDecrypt, loadData->cipherSpec);
|
||||
|
||||
MEM_CONTEXT_BEGIN(loadData->memContext)
|
||||
{
|
||||
loadData->infoArchive = infoArchiveNewLoad(read);
|
||||
loadData->infoArchive = infoArchiveNewLoad(read, loadData->cipherSpec);
|
||||
result = true;
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
@@ -251,26 +252,24 @@ infoArchiveLoadFileCallback(void *const data, const unsigned int try)
|
||||
|
||||
FN_EXTERN InfoArchive *
|
||||
infoArchiveLoadFile(
|
||||
const Storage *const storage, const String *const fileName, const CipherType cipherType, const String *const cipherPass)
|
||||
const Storage *const storage, const String *const fileName, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storage);
|
||||
FUNCTION_LOG_PARAM(STRING, fileName);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(storage != NULL);
|
||||
ASSERT(fileName != NULL);
|
||||
ASSERT((cipherType == cipherTypeNone && cipherPass == NULL) || (cipherType != cipherTypeNone && cipherPass != NULL));
|
||||
ASSERT(cipherSpec != NULL);
|
||||
|
||||
InfoArchiveLoadFileData data =
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
.storage = storage,
|
||||
.fileName = fileName,
|
||||
.cipherType = cipherType,
|
||||
.cipherPass = cipherPass,
|
||||
.cipherSpec = cipherSpec,
|
||||
};
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
@@ -304,28 +303,26 @@ infoArchiveLoadFile(
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN void
|
||||
infoArchiveSaveFile(
|
||||
InfoArchive *const infoArchive, const Storage *const storage, const String *const fileName, const CipherType cipherType,
|
||||
const String *const cipherPass)
|
||||
InfoArchive *const infoArchive, const Storage *const storage, const String *const fileName, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(INFO_ARCHIVE, infoArchive);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storage);
|
||||
FUNCTION_LOG_PARAM(STRING, fileName);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(infoArchive != NULL);
|
||||
ASSERT(storage != NULL);
|
||||
ASSERT(fileName != NULL);
|
||||
ASSERT((cipherType == cipherTypeNone && cipherPass == NULL) || (cipherType != cipherTypeNone && cipherPass != NULL));
|
||||
ASSERT(cipherSpec != NULL);
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Write output into a buffer since it needs to be saved to storage twice
|
||||
Buffer *const buffer = bufNew(ioBufferSize());
|
||||
IoWrite *const write = ioBufferWriteNew(buffer);
|
||||
cipherBlockFilterGroupAdd(ioWriteFilterGroup(write), cipherType, cipherModeEncrypt, cipherPass);
|
||||
cipherBlockFilterGroupAdd(ioWriteFilterGroup(write), cipherModeEncrypt, cipherSpec);
|
||||
infoArchiveSave(infoArchive, write);
|
||||
|
||||
// Save the file and make a copy
|
||||
|
||||
@@ -9,7 +9,7 @@ Object type
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct InfoArchive InfoArchive;
|
||||
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/type/object.h"
|
||||
#include "common/type/string.h"
|
||||
#include "info/infoPg.h"
|
||||
@@ -29,10 +29,10 @@ STRING_DECLARE(INFO_ARCHIVE_PATH_FILE_COPY_STR);
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
FN_EXTERN InfoArchive *infoArchiveNew(const unsigned int pgVersion, const uint64_t pgSystemId, const String *cipherPassSub);
|
||||
FN_EXTERN InfoArchive *infoArchiveNew(const unsigned int pgVersion, const uint64_t pgSystemId, const CipherSpec *cipherSpecSub);
|
||||
|
||||
// Create new object and load contents from IoRead
|
||||
FN_EXTERN InfoArchive *infoArchiveNewLoad(IoRead *read);
|
||||
FN_EXTERN InfoArchive *infoArchiveNewLoad(IoRead *read, const CipherSpec *cipherSpec);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
@@ -59,11 +59,11 @@ infoArchiveId(const InfoArchive *const this)
|
||||
return infoPgArchiveId(infoArchivePg(this), infoPgDataCurrentId(infoArchivePg(this)));
|
||||
}
|
||||
|
||||
// Cipher passphrase
|
||||
FN_INLINE_ALWAYS const String *
|
||||
infoArchiveCipherPass(const InfoArchive *const this)
|
||||
// Cipher spec for dependent files
|
||||
FN_INLINE_ALWAYS const CipherSpec *
|
||||
infoArchiveCipherSpec(const InfoArchive *const this)
|
||||
{
|
||||
return infoPgCipherPass(infoArchivePg(this));
|
||||
return infoPgCipherSpec(infoArchivePg(this));
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@@ -93,12 +93,11 @@ infoArchiveFree(InfoArchive *const this)
|
||||
Helper functions
|
||||
***********************************************************************************************************************************/
|
||||
// Load archive info
|
||||
FN_EXTERN InfoArchive *infoArchiveLoadFile(
|
||||
const Storage *storage, const String *fileName, CipherType cipherType, const String *cipherPass);
|
||||
FN_EXTERN InfoArchive *infoArchiveLoadFile(const Storage *storage, const String *fileName, const CipherSpec *cipherSpec);
|
||||
|
||||
// Save archive info
|
||||
FN_EXTERN void infoArchiveSaveFile(
|
||||
InfoArchive *infoArchive, const Storage *storage, const String *fileName, CipherType cipherType, const String *cipherPass);
|
||||
InfoArchive *infoArchive, const Storage *storage, const String *fileName, const CipherSpec *cipherSpec);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
|
||||
@@ -66,13 +66,14 @@ infoBackupNewInternal(void)
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN InfoBackup *
|
||||
infoBackupNew(
|
||||
const unsigned int pgVersion, const uint64_t pgSystemId, const unsigned int pgCatalogVersion, const String *const cipherPassSub)
|
||||
const unsigned int pgVersion, const uint64_t pgSystemId, const unsigned int pgCatalogVersion,
|
||||
const CipherSpec *const cipherSpecSub)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(UINT, pgVersion);
|
||||
FUNCTION_LOG_PARAM(UINT64, pgSystemId);
|
||||
FUNCTION_LOG_PARAM(UINT, pgCatalogVersion);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPassSub);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecSub);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(pgVersion > 0 && pgSystemId > 0 && pgCatalogVersion > 0);
|
||||
@@ -84,7 +85,7 @@ infoBackupNew(
|
||||
this = infoBackupNewInternal();
|
||||
|
||||
// Initialize the pg data
|
||||
this->pub.infoPg = infoPgNew(infoPgBackup, cipherPassSub);
|
||||
this->pub.infoPg = infoPgNew(infoPgBackup, cipherSpecSub);
|
||||
infoBackupPgSet(this, pgVersion, pgSystemId, pgCatalogVersion);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
@@ -233,10 +234,11 @@ infoBackupLoadCallback(void *const data, const String *const section, const Stri
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN InfoBackup *
|
||||
infoBackupNewLoad(IoRead *const read)
|
||||
infoBackupNewLoad(IoRead *const read, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(IO_READ, read);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(read != NULL);
|
||||
@@ -246,7 +248,7 @@ infoBackupNewLoad(IoRead *const read)
|
||||
OBJ_NEW_BASE_BEGIN(InfoBackup, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoBackupNewInternal();
|
||||
this->pub.infoPg = infoPgNewLoad(read, infoPgBackup, infoBackupLoadCallback, this);
|
||||
this->pub.infoPg = infoPgNewLoad(read, infoPgBackup, cipherSpec, infoBackupLoadCallback, this);
|
||||
this->pub.updated = false;
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
@@ -670,8 +672,7 @@ typedef struct InfoBackupLoadFileData
|
||||
MemContext *memContext; // Mem context
|
||||
const Storage *storage; // Storage to load from
|
||||
const String *fileName; // Base filename
|
||||
CipherType cipherType; // Cipher type
|
||||
const String *cipherPass; // Cipher passphrase
|
||||
const CipherSpec *cipherSpec; // Cipher spec
|
||||
InfoBackup *infoBackup; // Loaded infoBackup object
|
||||
} InfoBackupLoadFileData;
|
||||
|
||||
@@ -697,11 +698,12 @@ infoBackupLoadFileCallback(void *const data, const unsigned int try)
|
||||
|
||||
// Attempt to load the file
|
||||
IoRead *const read = storageReadIo(storageNewReadP(loadData->storage, fileName));
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(read), loadData->cipherType, cipherModeDecrypt, loadData->cipherPass);
|
||||
cipherBlockFilterGroupAdd(
|
||||
ioReadFilterGroup(read), cipherModeDecrypt, loadData->cipherSpec);
|
||||
|
||||
MEM_CONTEXT_BEGIN(loadData->memContext)
|
||||
{
|
||||
loadData->infoBackup = infoBackupNewLoad(read);
|
||||
loadData->infoBackup = infoBackupNewLoad(read, loadData->cipherSpec);
|
||||
result = true;
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
@@ -714,26 +716,24 @@ infoBackupLoadFileCallback(void *const data, const unsigned int try)
|
||||
|
||||
FN_EXTERN InfoBackup *
|
||||
infoBackupLoadFile(
|
||||
const Storage *const storage, const String *const fileName, const CipherType cipherType, const String *const cipherPass)
|
||||
const Storage *const storage, const String *const fileName, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storage);
|
||||
FUNCTION_LOG_PARAM(STRING, fileName);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(storage != NULL);
|
||||
ASSERT(fileName != NULL);
|
||||
ASSERT((cipherType == cipherTypeNone && cipherPass == NULL) || (cipherType != cipherTypeNone && cipherPass != NULL));
|
||||
ASSERT(cipherSpec != NULL);
|
||||
|
||||
InfoBackupLoadFileData data =
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
.storage = storage,
|
||||
.fileName = fileName,
|
||||
.cipherType = cipherType,
|
||||
.cipherPass = cipherPass,
|
||||
.cipherSpec = cipherSpec,
|
||||
};
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
@@ -786,20 +786,19 @@ infoBackupSetExists(const InfoBackup *const this, const String *const backupSet)
|
||||
|
||||
FN_EXTERN InfoBackup *
|
||||
infoBackupLoadFileReconstruct(
|
||||
const Storage *const storage, const String *const fileName, const CipherType cipherType, const String *const cipherPass)
|
||||
const Storage *const storage, const String *const fileName, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storage);
|
||||
FUNCTION_LOG_PARAM(STRING, fileName);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(storage != NULL);
|
||||
ASSERT(fileName != NULL);
|
||||
ASSERT((cipherType == cipherTypeNone && cipherPass == NULL) || (cipherType != cipherTypeNone && cipherPass != NULL));
|
||||
ASSERT(cipherSpec != NULL);
|
||||
|
||||
InfoBackup *const infoBackup = infoBackupLoadFile(storage, fileName, cipherType, cipherPass);
|
||||
InfoBackup *const infoBackup = infoBackupLoadFile(storage, fileName, cipherSpec);
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
@@ -865,8 +864,7 @@ infoBackupLoadFileReconstruct(
|
||||
if (storageExistsP(storage, manifestFileName))
|
||||
{
|
||||
bool found = false;
|
||||
const Manifest *const manifest = manifestLoadFile(
|
||||
storage, manifestFileName, cipherType, infoPgCipherPass(infoBackupPg(infoBackup)));
|
||||
const Manifest *const manifest = manifestLoadFile(storage, manifestFileName, infoBackupCipherSpec(infoBackup));
|
||||
const ManifestData *const manData = manifestData(manifest);
|
||||
|
||||
// If the pg data for the manifest exists in the history, then add it to current, but if something doesn't match
|
||||
@@ -902,21 +900,19 @@ infoBackupLoadFileReconstruct(
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN void
|
||||
infoBackupSaveFile(
|
||||
InfoBackup *const infoBackup, const Storage *const storage, const String *const fileName, const CipherType cipherType,
|
||||
const String *const cipherPass)
|
||||
InfoBackup *const infoBackup, const Storage *const storage, const String *const fileName, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(INFO_BACKUP, infoBackup);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storage);
|
||||
FUNCTION_LOG_PARAM(STRING, fileName);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(infoBackup != NULL);
|
||||
ASSERT(storage != NULL);
|
||||
ASSERT(fileName != NULL);
|
||||
ASSERT((cipherType == cipherTypeNone && cipherPass == NULL) || (cipherType != cipherTypeNone && cipherPass != NULL));
|
||||
ASSERT(cipherSpec != NULL);
|
||||
|
||||
if (infoBackup->pub.updated)
|
||||
{
|
||||
@@ -925,7 +921,7 @@ infoBackupSaveFile(
|
||||
// Write output into a buffer since it needs to be saved to storage twice
|
||||
Buffer *const buffer = bufNew(ioBufferSize());
|
||||
IoWrite *const write = ioBufferWriteNew(buffer);
|
||||
cipherBlockFilterGroupAdd(ioWriteFilterGroup(write), cipherType, cipherModeEncrypt, cipherPass);
|
||||
cipherBlockFilterGroupAdd(ioWriteFilterGroup(write), cipherModeEncrypt, cipherSpec);
|
||||
infoBackupSave(infoBackup, write);
|
||||
|
||||
// Save the file and make a copy
|
||||
|
||||
@@ -21,6 +21,7 @@ typedef enum
|
||||
backupTypeIncr = STRID5("incr", 0x90dc90),
|
||||
} BackupType;
|
||||
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/type/object.h"
|
||||
#include "common/type/string.h"
|
||||
#include "common/type/stringList.h"
|
||||
@@ -77,10 +78,10 @@ typedef struct InfoBackupData
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
FN_EXTERN InfoBackup *infoBackupNew(
|
||||
unsigned int pgVersion, uint64_t pgSystemId, unsigned int pgCatalogVersion, const String *cipherPassSub);
|
||||
unsigned int pgVersion, uint64_t pgSystemId, unsigned int pgCatalogVersion, const CipherSpec *cipherSpecSub);
|
||||
|
||||
// Create new object and load contents from IoRead
|
||||
FN_EXTERN InfoBackup *infoBackupNewLoad(IoRead *read);
|
||||
FN_EXTERN InfoBackup *infoBackupNewLoad(IoRead *read, const CipherSpec *cipherSpec);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
@@ -102,11 +103,11 @@ infoBackupPg(const InfoBackup *const this)
|
||||
|
||||
FN_EXTERN InfoBackup *infoBackupPgSet(InfoBackup *this, unsigned int pgVersion, uint64_t pgSystemId, unsigned int pgCatalogVersion);
|
||||
|
||||
// Cipher passphrase
|
||||
FN_INLINE_ALWAYS const String *
|
||||
infoBackupCipherPass(const InfoBackup *const this)
|
||||
// Cipher spec for dependent files
|
||||
FN_INLINE_ALWAYS const CipherSpec *
|
||||
infoBackupCipherSpec(const InfoBackup *const this)
|
||||
{
|
||||
return infoPgCipherPass(infoBackupPg(this));
|
||||
return infoPgCipherSpec(infoBackupPg(this));
|
||||
}
|
||||
|
||||
// Return a structure of the backup data from a specific index
|
||||
@@ -173,16 +174,15 @@ infoBackupFree(InfoBackup *const this)
|
||||
Helper functions
|
||||
***********************************************************************************************************************************/
|
||||
// Load backup info
|
||||
FN_EXTERN InfoBackup *infoBackupLoadFile(
|
||||
const Storage *storage, const String *fileName, CipherType cipherType, const String *cipherPass);
|
||||
FN_EXTERN InfoBackup *infoBackupLoadFile(const Storage *storage, const String *fileName, const CipherSpec *cipherSpec);
|
||||
|
||||
// Load backup info and update it by adding valid backups from the repo or removing backups no longer in the repo
|
||||
FN_EXTERN InfoBackup *infoBackupLoadFileReconstruct(
|
||||
const Storage *storage, const String *fileName, CipherType cipherType, const String *cipherPass);
|
||||
const Storage *storage, const String *fileName, const CipherSpec *cipherSpec);
|
||||
|
||||
// Save backup info
|
||||
FN_EXTERN void infoBackupSaveFile(
|
||||
InfoBackup *infoBackup, const Storage *storage, const String *fileName, CipherType cipherType, const String *cipherPass);
|
||||
InfoBackup *infoBackup, const Storage *storage, const String *fileName, const CipherSpec *cipherSpec);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
|
||||
@@ -62,11 +62,11 @@ infoPgNewInternal(const InfoPgType type)
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN InfoPg *
|
||||
infoPgNew(const InfoPgType type, const String *const cipherPassSub)
|
||||
infoPgNew(const InfoPgType type, const CipherSpec *const cipherSpecSub)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, type);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPassSub);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpecSub);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
InfoPg *this;
|
||||
@@ -74,7 +74,7 @@ infoPgNew(const InfoPgType type, const String *const cipherPassSub)
|
||||
OBJ_NEW_BASE_BEGIN(InfoPg, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoPgNewInternal(type);
|
||||
this->pub.info = infoNew(cipherPassSub);
|
||||
this->pub.info = infoNew(cipherSpecSub);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
@@ -155,11 +155,14 @@ infoPgLoadCallback(void *const data, const String *const section, const String *
|
||||
}
|
||||
|
||||
FN_EXTERN InfoPg *
|
||||
infoPgNewLoad(IoRead *const read, const InfoPgType type, InfoLoadNewCallback *const callbackFunction, void *const callbackData)
|
||||
infoPgNewLoad(
|
||||
IoRead *const read, const InfoPgType type, const CipherSpec *const cipherSpec, InfoLoadNewCallback *const callbackFunction,
|
||||
void *const callbackData)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(IO_READ, read);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, type);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_PARAM(FUNCTIONP, callbackFunction);
|
||||
FUNCTION_LOG_PARAM_P(VOID, callbackData);
|
||||
FUNCTION_LOG_END();
|
||||
@@ -185,7 +188,7 @@ infoPgNewLoad(IoRead *const read, const InfoPgType type, InfoLoadNewCallback *co
|
||||
.infoPg = this,
|
||||
};
|
||||
|
||||
this->pub.info = infoNewLoad(read, infoPgLoadCallback, &loadData);
|
||||
this->pub.info = infoNewLoad(read, cipherSpec, infoPgLoadCallback, &loadData);
|
||||
|
||||
CHECK(FormatError, !lstEmpty(this->pub.history), "history is missing");
|
||||
CHECK(FormatError, loadData.currentId > 0, "current id is missing");
|
||||
|
||||
@@ -47,10 +47,11 @@ typedef enum
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
FN_EXTERN InfoPg *infoPgNew(InfoPgType type, const String *cipherPassSub);
|
||||
FN_EXTERN InfoPg *infoPgNew(InfoPgType type, const CipherSpec *cipherSpecSub);
|
||||
|
||||
// Create new object and load contents from a file
|
||||
FN_EXTERN InfoPg *infoPgNewLoad(IoRead *read, InfoPgType type, InfoLoadNewCallback *callbackFunction, void *callbackData);
|
||||
FN_EXTERN InfoPg *infoPgNewLoad(
|
||||
IoRead *read, InfoPgType type, const CipherSpec *cipherSpec, InfoLoadNewCallback *callbackFunction, void *callbackData);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
@@ -71,11 +72,11 @@ infoPgInfo(const InfoPg *const this)
|
||||
return THIS_PUB(InfoPg)->info;
|
||||
}
|
||||
|
||||
// Return the cipher passphrase
|
||||
FN_INLINE_ALWAYS const String *
|
||||
infoPgCipherPass(const InfoPg *const this)
|
||||
// Cipher spec for dependent files
|
||||
FN_INLINE_ALWAYS const CipherSpec *
|
||||
infoPgCipherSpec(const InfoPg *const this)
|
||||
{
|
||||
return infoCipherPass(infoPgInfo(this));
|
||||
return infoCipherSpec(infoPgInfo(this));
|
||||
}
|
||||
|
||||
// Return current pgId from the history
|
||||
|
||||
@@ -669,10 +669,11 @@ manifestBuildComplete(
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN Manifest *
|
||||
manifestNewLoad(IoRead *const read)
|
||||
manifestNewLoad(IoRead *const read, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(IO_READ, read);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(read != NULL);
|
||||
@@ -703,7 +704,7 @@ manifestNewLoad(IoRead *const read)
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
|
||||
this->pub.info = infoNewLoad(read, manifestLoadCallback, &loadData);
|
||||
this->pub.info = infoNewLoad(read, cipherSpec, manifestLoadCallback, &loadData);
|
||||
this->pub.data.backrestVersion = infoBackrestVersion(this->pub.info);
|
||||
|
||||
// Add the label to the reference list in case the manifest was created before 2.42 when the explicit reference list was
|
||||
|
||||
@@ -37,8 +37,8 @@ typedef struct Manifest Manifest;
|
||||
|
||||
#include "command/backup/common.h"
|
||||
#include "common/compress/helper.h"
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/hash.h"
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/type/object.h"
|
||||
#include "common/type/variant.h"
|
||||
#include "info/info.h"
|
||||
@@ -218,7 +218,7 @@ FN_EXTERN Manifest *manifestNewBuild(
|
||||
const Pack *tablespaceList);
|
||||
|
||||
// Load a manifest from IO
|
||||
FN_EXTERN Manifest *manifestNewLoad(IoRead *read);
|
||||
FN_EXTERN Manifest *manifestNewLoad(IoRead *read, const CipherSpec *cipherSpec);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
@@ -236,17 +236,17 @@ typedef struct ManifestPub
|
||||
StringList *referenceList; // List of file references
|
||||
} ManifestPub;
|
||||
|
||||
// Get/set the cipher subpassphrase
|
||||
FN_INLINE_ALWAYS const String *
|
||||
manifestCipherSubPass(const Manifest *const this)
|
||||
// Get cipher spec for the files this manifest describes, set the pass they are encrypted with
|
||||
FN_INLINE_ALWAYS const CipherSpec *
|
||||
manifestCipherSpec(const Manifest *const this)
|
||||
{
|
||||
return infoCipherPass(THIS_PUB(Manifest)->info);
|
||||
return infoCipherSpec(THIS_PUB(Manifest)->info);
|
||||
}
|
||||
|
||||
FN_INLINE_ALWAYS void
|
||||
manifestCipherSubPassSet(Manifest *const this, const String *const cipherSubPass)
|
||||
manifestCipherSpecSet(Manifest *const this, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
infoCipherPassSet(THIS_PUB(Manifest)->info, cipherSubPass);
|
||||
infoCipherSpecSet(THIS_PUB(Manifest)->info, cipherSpec);
|
||||
}
|
||||
|
||||
// Get manifest configuration and options
|
||||
@@ -507,8 +507,7 @@ manifestFree(Manifest *const this)
|
||||
Helper functions
|
||||
***********************************************************************************************************************************/
|
||||
// Load backup manifest
|
||||
FN_EXTERN Manifest *manifestLoadFile(
|
||||
const Storage *storage, const String *fileName, CipherType cipherType, const String *cipherPass);
|
||||
FN_EXTERN Manifest *manifestLoadFile(const Storage *storage, const String *fileName, const CipherSpec *cipherSpec);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
|
||||
@@ -1013,8 +1013,7 @@ typedef struct ManifestLoadFileData
|
||||
MemContext *memContext; // Mem context
|
||||
const Storage *storage; // Storage to load from
|
||||
const String *fileName; // Base filename
|
||||
CipherType cipherType; // Cipher type
|
||||
const String *cipherPass; // Cipher passphrase
|
||||
const CipherSpec *cipherSpec; // Cipher spec
|
||||
Manifest *manifest; // Loaded manifest object
|
||||
} ManifestLoadFileData;
|
||||
|
||||
@@ -1040,11 +1039,11 @@ manifestLoadFileCallback(void *const data, const unsigned int try)
|
||||
|
||||
// Attempt to load the file
|
||||
IoRead *const read = storageReadIo(storageNewReadP(loadData->storage, fileName));
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(read), loadData->cipherType, cipherModeDecrypt, loadData->cipherPass);
|
||||
cipherBlockFilterGroupAdd(ioReadFilterGroup(read), cipherModeDecrypt, loadData->cipherSpec);
|
||||
|
||||
MEM_CONTEXT_BEGIN(loadData->memContext)
|
||||
{
|
||||
loadData->manifest = manifestNewLoad(read);
|
||||
loadData->manifest = manifestNewLoad(read, loadData->cipherSpec);
|
||||
result = true;
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
@@ -1057,26 +1056,24 @@ manifestLoadFileCallback(void *const data, const unsigned int try)
|
||||
|
||||
FN_EXTERN Manifest *
|
||||
manifestLoadFile(
|
||||
const Storage *const storage, const String *const fileName, const CipherType cipherType, const String *const cipherPass)
|
||||
const Storage *const storage, const String *const fileName, const CipherSpec *const cipherSpec)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STORAGE, storage);
|
||||
FUNCTION_LOG_PARAM(STRING, fileName);
|
||||
FUNCTION_LOG_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||
FUNCTION_LOG_PARAM(CIPHER_SPEC, cipherSpec);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(storage != NULL);
|
||||
ASSERT(fileName != NULL);
|
||||
ASSERT((cipherType == cipherTypeNone && cipherPass == NULL) || (cipherType != cipherTypeNone && cipherPass != NULL));
|
||||
ASSERT(cipherSpec != NULL);
|
||||
|
||||
ManifestLoadFileData data =
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
.storage = storage,
|
||||
.fileName = fileName,
|
||||
.cipherType = cipherType,
|
||||
.cipherPass = cipherPass,
|
||||
.cipherSpec = cipherSpec,
|
||||
};
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
|
||||
@@ -123,6 +123,7 @@ src_pgbackrest = [
|
||||
'common/crypto/cipherBlock.c',
|
||||
'common/crypto/common.c',
|
||||
'common/crypto/hash.c',
|
||||
'common/crypto/spec.c',
|
||||
'common/crypto/xxhash.c',
|
||||
'common/debug.c',
|
||||
'common/encode.c',
|
||||
|
||||
@@ -372,6 +372,7 @@ unit:
|
||||
- common/crypto/common
|
||||
- common/crypto/hash
|
||||
- common/crypto/md5.vendor: included
|
||||
- common/crypto/spec
|
||||
- common/crypto/xxhash
|
||||
|
||||
# --------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -96,12 +96,12 @@ hrnBackupScriptSet(const HrnBackupScript *const script, const unsigned int scrip
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
static void
|
||||
backupProcess(const BackupData *const backupData, Manifest *const manifest, const String *const cipherPassBackup)
|
||||
backupProcess(const BackupData *const backupData, Manifest *const manifest, const CipherSpec *const cipherSpecManifest)
|
||||
{
|
||||
FUNCTION_HARNESS_BEGIN();
|
||||
FUNCTION_HARNESS_PARAM(BACKUP_DATA, backupData);
|
||||
FUNCTION_HARNESS_PARAM(MANIFEST, manifest);
|
||||
FUNCTION_HARNESS_PARAM(STRING, cipherPassBackup);
|
||||
FUNCTION_HARNESS_PARAM(CIPHER_SPEC, cipherSpecManifest);
|
||||
FUNCTION_HARNESS_END();
|
||||
|
||||
// If any file changes are scripted then make them
|
||||
@@ -142,7 +142,7 @@ backupProcess(const BackupData *const backupData, Manifest *const manifest, cons
|
||||
hrnBackupLocal.scriptSize = 0;
|
||||
}
|
||||
|
||||
backupProcess_SHIMMED(backupData, manifest, cipherPassBackup);
|
||||
backupProcess_SHIMMED(backupData, manifest, cipherSpecManifest);
|
||||
|
||||
FUNCTION_HARNESS_RETURN_VOID();
|
||||
}
|
||||
@@ -216,8 +216,8 @@ hrnBackupPqScript(const unsigned int pgVersion, const time_t backupTimeStart, Hr
|
||||
if (!param.noPriorWal)
|
||||
{
|
||||
InfoArchive *infoArchive = infoArchiveLoadFile(
|
||||
storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, param.cipherType == 0 ? cipherTypeNone : param.cipherType,
|
||||
param.cipherPass == NULL ? NULL : STR(param.cipherPass));
|
||||
storageRepo(), INFO_ARCHIVE_PATH_FILE_STR,
|
||||
param.cipherSpecMain == NULL ? cipherSpecNewNone() : param.cipherSpecMain);
|
||||
const String *archiveId = infoArchiveId(infoArchive);
|
||||
StringList *walSegmentList = pgLsnRangeToWalSegmentList(
|
||||
param.timeline, lsnStart - pgControl.walSegmentSize, param.noWal ? lsnStart - pgControl.walSegmentSize : lsnStop,
|
||||
@@ -244,8 +244,7 @@ hrnBackupPqScript(const unsigned int pgVersion, const time_t backupTimeStart, Hr
|
||||
|
||||
// Encrypt with the archive passphrase, which is what archive-push writes WAL with
|
||||
cipherBlockFilterGroupAdd(
|
||||
ioWriteFilterGroup(storageWriteIo(write)), param.cipherType == 0 ? cipherTypeNone : param.cipherType,
|
||||
cipherModeEncrypt, infoArchiveCipherPass(infoArchive));
|
||||
ioWriteFilterGroup(storageWriteIo(write)), cipherModeEncrypt, infoArchiveCipherSpec(infoArchive));
|
||||
|
||||
storagePutP(write, walBuffer);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@ typedef struct HrnBackupPqScriptParam
|
||||
bool noArchiveCheck; // Do not check archive
|
||||
bool walSwitch; // WAL switch is required
|
||||
CompressType walCompressType; // Compress type for the archive files
|
||||
CipherType cipherType; // Cipher type
|
||||
const char *cipherPass; // Cipher pass
|
||||
const CipherSpec *cipherSpecMain; // Cipher spec the repo is configured with
|
||||
unsigned int walTotal; // Total WAL to write
|
||||
unsigned int timeline; // Timeline to use for WAL files
|
||||
const String *pgVersionForce; // PG version to use when control/catalog not found
|
||||
|
||||
@@ -27,7 +27,7 @@ hrnBlockDeltaRender(const BlockMap *const blockMap, const size_t blockSize, cons
|
||||
ASSERT(blockSize > 0);
|
||||
|
||||
String *const result = strNew();
|
||||
BlockDelta *const blockDelta = blockDeltaNew(blockMap, blockSize, checksumSize, NULL, cipherTypeNone, NULL, compressTypeNone);
|
||||
BlockDelta *const blockDelta = blockDeltaNew(blockMap, blockSize, checksumSize, NULL, cipherSpecNewNone(), compressTypeNone);
|
||||
|
||||
for (unsigned int readIdx = 0; readIdx < blockDeltaReadSize(blockDelta); readIdx++)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,10 @@ Config option constants
|
||||
#define TEST_CIPHER_PASS "xmainx"
|
||||
#define TEST_CIPHER_PASS_ARCHIVE "xarchivex"
|
||||
|
||||
// Cipher spec for a test pass, defaulting to the main pass, since most tests encrypt with that
|
||||
#define TEST_CIPHER_SPEC_PASS(pass) cipherSpecNew(cipherTypeAes256Cbc, BUFSTRZ(pass))
|
||||
#define TEST_CIPHER_SPEC TEST_CIPHER_SPEC_PASS(TEST_CIPHER_PASS)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Load a test configuration
|
||||
|
||||
|
||||
@@ -82,8 +82,7 @@ static struct HrnHostLocal
|
||||
StringId repoHost; // Host acting as repository
|
||||
StringId storage; // Storage type
|
||||
CompressType compressType; // Compress type
|
||||
CipherType cipherType; // Cipher type
|
||||
const String *cipherPass; // Cipher passphrase
|
||||
const CipherSpec *cipherSpecMain; // Cipher spec the repo is configured with
|
||||
unsigned int repoTotal; // Repository total
|
||||
unsigned int restoreTotal; // Restore counter used to name spool path
|
||||
bool tls; // Use TLS instead of SSH?
|
||||
@@ -705,10 +704,10 @@ hrnHostConfig(HrnHost *const this)
|
||||
strCatFmt(config, "repo1-path=%s\n", strZ(hrnHostRepo1Path(this)));
|
||||
strCatZ(config, "repo1-retention-full=2\n");
|
||||
|
||||
if (hrnHostLocal.cipherType != cipherTypeNone)
|
||||
if (cipherSpecType(hrnHostLocal.cipherSpecMain) != cipherTypeNone)
|
||||
{
|
||||
strCatFmt(config, "repo1-cipher-type=%s\n", zNewStrId(hrnHostLocal.cipherType));
|
||||
strCatFmt(config, "repo1-cipher-pass=%s\n", strZ(hrnHostLocal.cipherPass));
|
||||
strCatFmt(config, "repo1-cipher-type=%s\n", zNewStrId(cipherSpecType(hrnHostLocal.cipherSpecMain)));
|
||||
strCatFmt(config, "repo1-cipher-pass=%s\n", strZ(strNewBuf(cipherSpecPass(hrnHostLocal.cipherSpecMain))));
|
||||
}
|
||||
|
||||
if (hrnHostLocal.bundle)
|
||||
@@ -1030,18 +1029,11 @@ hrnHostGet(const StringId id)
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
CipherType
|
||||
hrnHostCipherType(void)
|
||||
const CipherSpec *
|
||||
hrnHostCipherSpec(void)
|
||||
{
|
||||
FUNCTION_HARNESS_VOID();
|
||||
FUNCTION_HARNESS_RETURN(STRING_ID, hrnHostLocal.cipherType);
|
||||
}
|
||||
|
||||
const String *
|
||||
hrnHostCipherPass(void)
|
||||
{
|
||||
FUNCTION_HARNESS_VOID();
|
||||
FUNCTION_HARNESS_RETURN(UINT, hrnHostLocal.cipherPass);
|
||||
FUNCTION_HARNESS_RETURN(CIPHER_SPEC, hrnHostLocal.cipherSpecMain);
|
||||
}
|
||||
|
||||
CompressType
|
||||
@@ -1235,8 +1227,8 @@ hrnHostBuild(const int line, const HrnHostTestDefine *const testMatrix, const si
|
||||
hrnHostLocal.repoHost = strIdFromZ(testDef->repo);
|
||||
hrnHostLocal.storage = strIdFromZ(testDef->stg);
|
||||
hrnHostLocal.compressType = compressTypeEnum(strIdFromZ(testDef->cmp));
|
||||
hrnHostLocal.cipherType = testDef->enc ? cipherTypeAes256Cbc : cipherTypeNone;
|
||||
hrnHostLocal.cipherPass = testDef->enc ? strNewZ(HRN_CIPHER_PASSPHRASE) : NULL;
|
||||
hrnHostLocal.cipherSpecMain =
|
||||
testDef->enc ? cipherSpecNew(cipherTypeAes256Cbc, BUFSTRZ(HRN_CIPHER_PASSPHRASE)) : cipherSpecNewNone();
|
||||
hrnHostLocal.repoTotal = testDef->rt;
|
||||
hrnHostLocal.tls = testDef->tls;
|
||||
hrnHostLocal.bundle = testDef->bnd;
|
||||
|
||||
@@ -9,6 +9,7 @@ Object type
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct HrnHost HrnHost;
|
||||
|
||||
#include "common/crypto/spec.h"
|
||||
#include "common/type/object.h"
|
||||
#include "common/type/string.h"
|
||||
#include "postgres/client.h"
|
||||
@@ -433,11 +434,8 @@ hrnHostSqlCommit(HrnHost *const this)
|
||||
/***********************************************************************************************************************************
|
||||
Helper functions
|
||||
***********************************************************************************************************************************/
|
||||
// Cipher Type
|
||||
CipherType hrnHostCipherType(void);
|
||||
|
||||
// Cipher Passphrase
|
||||
const String *hrnHostCipherPass(void);
|
||||
// Cipher Spec
|
||||
const CipherSpec *hrnHostCipherSpec(void);
|
||||
|
||||
// Compress Type
|
||||
CompressType hrnHostCompressType(void);
|
||||
|
||||
@@ -67,15 +67,13 @@ testStorageGet(const Storage *const storage, const char *const file, const char
|
||||
IoFilterGroup *filterGroup = ioReadFilterGroup(storageReadIo(read));
|
||||
|
||||
// Add decrypt filter
|
||||
if (param.cipherType != 0 && param.cipherType != cipherTypeNone)
|
||||
if (param.cipherSpec != NULL && cipherSpecType(param.cipherSpec) != cipherTypeNone)
|
||||
{
|
||||
// Default to main cipher pass
|
||||
if (param.cipherPass == NULL)
|
||||
param.cipherPass = TEST_CIPHER_PASS;
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeDecrypt, param.cipherSpec));
|
||||
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeDecrypt, param.cipherType, BUFSTRZ(param.cipherPass)));
|
||||
|
||||
strCatFmt(filter, "enc[%s,%s] ", zNewStrId(param.cipherType), param.cipherPass);
|
||||
strCatFmt(
|
||||
filter, "enc[%s,%s] ", zNewStrId(cipherSpecType(param.cipherSpec)),
|
||||
strZ(strNewBuf(cipherSpecPass(param.cipherSpec))));
|
||||
}
|
||||
|
||||
// Add decompress filter
|
||||
@@ -394,14 +392,8 @@ hrnStoragePut(
|
||||
}
|
||||
|
||||
// Add encrypted filter
|
||||
if (param.cipherType != 0 && param.cipherType != cipherTypeNone)
|
||||
{
|
||||
// Default to main cipher pass
|
||||
if (param.cipherPass == NULL)
|
||||
param.cipherPass = TEST_CIPHER_PASS;
|
||||
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeEncrypt, param.cipherType, BUFSTRZ(param.cipherPass)));
|
||||
}
|
||||
if (param.cipherSpec != NULL && cipherSpecType(param.cipherSpec) != cipherTypeNone)
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeEncrypt, param.cipherSpec));
|
||||
|
||||
// Add file name
|
||||
printf(
|
||||
|
||||
@@ -8,6 +8,7 @@ Helper functions for testing storage and related functions.
|
||||
|
||||
#include "common/compress/helper.h"
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/crypto/spec.h"
|
||||
#include "storage/storage.intern.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@@ -19,8 +20,7 @@ typedef struct TestStorageGetParam
|
||||
bool remove; // Remove file after testing?
|
||||
bool nullOnMissing; // NULL when file is missing
|
||||
CompressType compressType; // Compression extension added to file name (limited gz and bz2)
|
||||
CipherType cipherType;
|
||||
const char *cipherPass; // If pass=null but cipherType set, defaults to TEST_CIPHER_PASS
|
||||
const CipherSpec *cipherSpec; // Cipher spec the file is encrypted with
|
||||
const char *comment; // Comment
|
||||
} TestStorageGetParam;
|
||||
|
||||
@@ -202,8 +202,7 @@ typedef struct HrnStoragePutParam
|
||||
mode_t modeFile; // File mode if not the default
|
||||
time_t timeModified; // Time file was last modified
|
||||
CompressType compressType; // Limited to gz and bz2 (lz4 and zstd are not always available)
|
||||
CipherType cipherType;
|
||||
const char *cipherPass;
|
||||
const CipherSpec *cipherSpec; // Cipher spec to encrypt the file with
|
||||
const char *comment; // Comment
|
||||
} HrnStoragePutParam;
|
||||
|
||||
|
||||
@@ -1057,11 +1057,11 @@ testRun(void)
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"1={\"db-id\":" HRN_PG_SYSTEMID_10_Z ",\"db-version\":\"10\"}",
|
||||
.cipherType = cipherTypeAes256Cbc);
|
||||
.cipherSpec = TEST_CIPHER_SPEC);
|
||||
|
||||
HRN_STORAGE_PUT(
|
||||
storageRepoWrite(), STORAGE_REPO_ARCHIVE "/10-1/01ABCDEF01ABCDEF01ABCDEF-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
buffer, .compressType = compressTypeGz, .cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS_ARCHIVE);
|
||||
buffer, .compressType = compressTypeGz, .cipherSpec = TEST_CIPHER_SPEC_PASS(TEST_CIPHER_PASS_ARCHIVE));
|
||||
|
||||
// Add encryption options
|
||||
argList = strLstNew();
|
||||
|
||||
@@ -179,8 +179,8 @@ testRun(void)
|
||||
ArchivePushFileRepoData *repoData = lstGet(result.repoList, 0);
|
||||
TEST_RESULT_UINT(repoData->repoIdx, 0, "check repo idx");
|
||||
TEST_RESULT_STR_Z(repoData->archiveId, "9.6-1", "check archive id");
|
||||
TEST_RESULT_UINT(repoData->cipherType, cipherTypeNone, "check cipher type");
|
||||
TEST_RESULT_STR_Z(repoData->cipherPass, NULL, "check cipher pass (not set in this test)");
|
||||
TEST_RESULT_UINT(cipherSpecType(repoData->cipherSpecArchive), cipherTypeNone, "check cipher type");
|
||||
TEST_RESULT_PTR(cipherSpecPass(repoData->cipherSpecArchive), NULL, "check cipher pass (not set in this test)");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("mismatched repos when pg-path not present");
|
||||
@@ -223,8 +223,8 @@ testRun(void)
|
||||
repoData = lstGet(result.repoList, 0);
|
||||
TEST_RESULT_UINT(repoData->repoIdx, 0, "check repo idx");
|
||||
TEST_RESULT_STR_Z(repoData->archiveId, "9.6-1", "check archive id");
|
||||
TEST_RESULT_UINT(repoData->cipherType, cipherTypeNone, "check cipher type");
|
||||
TEST_RESULT_STR_Z(repoData->cipherPass, NULL, "check cipher pass (not set in this test)");
|
||||
TEST_RESULT_UINT(cipherSpecType(repoData->cipherSpecArchive), cipherTypeNone, "check cipher type");
|
||||
TEST_RESULT_PTR(cipherSpecPass(repoData->cipherSpecArchive), NULL, "check cipher pass (not set in this test)");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("matched repos when pg-path not present");
|
||||
@@ -247,14 +247,14 @@ testRun(void)
|
||||
repoData = lstGet(result.repoList, 0);
|
||||
TEST_RESULT_UINT(repoData->repoIdx, 0, "check repo idx");
|
||||
TEST_RESULT_STR_Z(repoData->archiveId, "9.6-1", "check repo2 archive id");
|
||||
TEST_RESULT_UINT(repoData->cipherType, cipherTypeNone, "check repo2 cipher pass");
|
||||
TEST_RESULT_STR_Z(repoData->cipherPass, NULL, "check repo2 cipher pass (not set in this test)");
|
||||
TEST_RESULT_UINT(cipherSpecType(repoData->cipherSpecArchive), cipherTypeNone, "check repo2 cipher pass");
|
||||
TEST_RESULT_PTR(cipherSpecPass(repoData->cipherSpecArchive), NULL, "check repo2 cipher pass (not set in this test)");
|
||||
|
||||
repoData = lstGet(result.repoList, 1);
|
||||
TEST_RESULT_UINT(repoData->repoIdx, 1, "check repo idx");
|
||||
TEST_RESULT_STR_Z(repoData->archiveId, "9.6-2", "check repo4 archive id");
|
||||
TEST_RESULT_UINT(repoData->cipherType, cipherTypeNone, "check repo4 cipher type");
|
||||
TEST_RESULT_STR_Z(repoData->cipherPass, NULL, "check repo4 cipher pass (not set in this test)");
|
||||
TEST_RESULT_UINT(cipherSpecType(repoData->cipherSpecArchive), cipherTypeNone, "check repo4 cipher type");
|
||||
TEST_RESULT_PTR(cipherSpecPass(repoData->cipherSpecArchive), NULL, "check repo4 cipher pass (not set in this test)");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
@@ -544,7 +544,7 @@ testRun(void)
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"1={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}",
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = "badpassphrase");
|
||||
.cipherSpec = TEST_CIPHER_SPEC_PASS("badpassphrase"));
|
||||
|
||||
// repo3 is not encrypted
|
||||
HRN_INFO_PUT(
|
||||
|
||||
@@ -27,8 +27,7 @@ Get a list of all files in the backup and a redacted version of the manifest tha
|
||||
static String *
|
||||
testBackupValidateFile(
|
||||
const Storage *const storage, const String *const path, Manifest *const manifest, const ManifestData *const manifestData,
|
||||
const String *const fileName, uint64_t fileSize, ManifestFilePack **const filePack, const CipherType cipherType,
|
||||
const String *const cipherPass)
|
||||
const String *const fileName, uint64_t fileSize, ManifestFilePack **const filePack)
|
||||
{
|
||||
FUNCTION_HARNESS_BEGIN();
|
||||
FUNCTION_HARNESS_PARAM(STORAGE, storage);
|
||||
@@ -38,13 +37,14 @@ testBackupValidateFile(
|
||||
FUNCTION_HARNESS_PARAM(STRING, fileName);
|
||||
FUNCTION_HARNESS_PARAM(UINT64, fileSize);
|
||||
FUNCTION_HARNESS_PARAM_P(VOID, filePack);
|
||||
FUNCTION_HARNESS_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_HARNESS_PARAM(STRING, cipherPass);
|
||||
FUNCTION_HARNESS_END();
|
||||
|
||||
String *const result = strNew();
|
||||
ManifestFile file = manifestFileUnpack(manifest, *filePack);
|
||||
|
||||
// Every backup in a set shares the passphrase stored in the manifest, including files referenced from a prior backup
|
||||
const CipherSpec *const cipherSpecBackup = manifestCipherSpec(manifest);
|
||||
|
||||
// Output name and size
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
if (file.bundleId != 0)
|
||||
@@ -89,11 +89,10 @@ testBackupValidateFile(
|
||||
.offset = file.bundleOffset + file.sizeRepo - file.blockIncrMapSize,
|
||||
.limit = VARUINT64(file.blockIncrMapSize));
|
||||
|
||||
if (cipherType != cipherTypeNone)
|
||||
if (cipherSpecType(cipherSpecBackup) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioReadFilterGroup(storageReadIo(read)),
|
||||
cipherBlockNewP(cipherModeDecrypt, cipherType, BUFSTR(cipherPass), .raw = true));
|
||||
ioReadFilterGroup(storageReadIo(read)), cipherBlockNewP(cipherModeDecrypt, cipherSpecBackup, .raw = true));
|
||||
}
|
||||
|
||||
ioReadOpen(storageReadIo(read));
|
||||
@@ -129,7 +128,7 @@ testBackupValidateFile(
|
||||
bufUsedSet(fileBuffer, bufSize(fileBuffer));
|
||||
|
||||
BlockDelta *const blockDelta = blockDeltaNew(
|
||||
blockMap, file.blockIncrSize, file.blockIncrChecksumSize, NULL, cipherType, cipherPass,
|
||||
blockMap, file.blockIncrSize, file.blockIncrChecksumSize, NULL, cipherSpecBackup,
|
||||
manifestData->backupOptionCompressType);
|
||||
|
||||
for (unsigned int readIdx = 0; readIdx < blockDeltaReadSize(blockDelta); readIdx++)
|
||||
@@ -170,11 +169,10 @@ testBackupValidateFile(
|
||||
.limit = VARUINT64(file.sizeRepo));
|
||||
const bool raw = file.bundleId != 0 && manifest->pub.data.bundleRaw;
|
||||
|
||||
if (cipherType != cipherTypeNone)
|
||||
if (cipherSpecType(cipherSpecBackup) != cipherTypeNone)
|
||||
{
|
||||
ioFilterGroupAdd(
|
||||
ioReadFilterGroup(storageReadIo(read)),
|
||||
cipherBlockNewP(cipherModeDecrypt, cipherType, BUFSTR(cipherPass), .raw = raw));
|
||||
ioReadFilterGroup(storageReadIo(read)), cipherBlockNewP(cipherModeDecrypt, cipherSpecBackup, .raw = raw));
|
||||
}
|
||||
|
||||
if (manifestData->backupOptionCompressType != compressTypeNone)
|
||||
@@ -255,7 +253,7 @@ testBackupValidateFile(
|
||||
static String *
|
||||
testBackupValidateList(
|
||||
const Storage *const storage, const String *const path, Manifest *const manifest, const ManifestData *const manifestData,
|
||||
StringList *const manifestFileList, const CipherType cipherType, const String *const cipherPass, String *const result)
|
||||
StringList *const manifestFileList, String *const result)
|
||||
{
|
||||
FUNCTION_HARNESS_BEGIN();
|
||||
FUNCTION_HARNESS_PARAM(STORAGE, storage);
|
||||
@@ -263,8 +261,6 @@ testBackupValidateList(
|
||||
FUNCTION_HARNESS_PARAM(MANIFEST, manifest);
|
||||
FUNCTION_HARNESS_PARAM_P(VOID, manifestData);
|
||||
FUNCTION_HARNESS_PARAM(STRING_LIST, manifestFileList);
|
||||
FUNCTION_HARNESS_PARAM(STRING_ID, cipherType);
|
||||
FUNCTION_HARNESS_PARAM(STRING, cipherPass);
|
||||
FUNCTION_HARNESS_PARAM(STRING, result);
|
||||
FUNCTION_HARNESS_END();
|
||||
|
||||
@@ -353,10 +349,7 @@ testBackupValidateList(
|
||||
manifestFileList, (String *const)*filePack, .required = true);
|
||||
strLstRemoveIdx(manifestFileList, manifestFileIdx);
|
||||
|
||||
strCat(
|
||||
result,
|
||||
testBackupValidateFile(
|
||||
storage, path, manifest, manifestData, info.name, info.size, filePack, cipherType, cipherPass));
|
||||
strCat(result, testBackupValidateFile(storage, path, manifest, manifestData, info.name, info.size, filePack));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -402,8 +395,7 @@ testBackupValidateList(
|
||||
typedef struct TestBackupValidateParam
|
||||
{
|
||||
VAR_PARAM_HEADER;
|
||||
CipherType cipherType; // Cipher type
|
||||
const char *cipherPass; // Cipher pass
|
||||
const CipherSpec *cipherSpecMain; // Cipher spec the repo is configured with
|
||||
} TestBackupValidateParam;
|
||||
|
||||
#define testBackupValidateP(storage, path, ...) \
|
||||
@@ -415,8 +407,7 @@ testBackupValidate(const Storage *const storage, const String *const path, const
|
||||
FUNCTION_HARNESS_BEGIN();
|
||||
FUNCTION_HARNESS_PARAM(STORAGE, storage);
|
||||
FUNCTION_HARNESS_PARAM(STRING, path);
|
||||
FUNCTION_HARNESS_PARAM(UINT64, param.cipherType);
|
||||
FUNCTION_HARNESS_PARAM(STRINGZ, param.cipherPass);
|
||||
FUNCTION_HARNESS_PARAM(CIPHER_SPEC, param.cipherSpecMain);
|
||||
FUNCTION_HARNESS_END();
|
||||
|
||||
ASSERT(storage != NULL);
|
||||
@@ -429,11 +420,9 @@ testBackupValidate(const Storage *const storage, const String *const path, const
|
||||
// Build a list of files in the backup path and verify against the manifest
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
const InfoBackup *const infoBackup = infoBackupLoadFile(
|
||||
storageRepo(), INFO_BACKUP_PATH_FILE_STR, param.cipherType == 0 ? cipherTypeNone : param.cipherType,
|
||||
param.cipherPass == NULL ? NULL : STR(param.cipherPass));
|
||||
storageRepo(), INFO_BACKUP_PATH_FILE_STR, param.cipherSpecMain == NULL ? cipherSpecNewNone() : param.cipherSpecMain);
|
||||
Manifest *manifest = manifestLoadFile(
|
||||
storage, strNewFmt("%s/" BACKUP_MANIFEST_FILE, strZ(path)), param.cipherType == 0 ? cipherTypeNone : param.cipherType,
|
||||
param.cipherPass == NULL ? NULL : infoBackupCipherPass(infoBackup));
|
||||
storage, strNewFmt("%s/" BACKUP_MANIFEST_FILE, strZ(path)), infoBackupCipherSpec(infoBackup));
|
||||
|
||||
// Build list of files in the manifest
|
||||
StringList *const manifestFileList = strLstNew();
|
||||
@@ -442,10 +431,7 @@ testBackupValidate(const Storage *const storage, const String *const path, const
|
||||
strLstAdd(manifestFileList, manifestFileUnpack(manifest, manifestFilePackGet(manifest, fileIdx)).name);
|
||||
|
||||
// Validate files on disk against the manifest
|
||||
const CipherType cipherType = param.cipherType == 0 ? cipherTypeNone : param.cipherType;
|
||||
const String *const cipherPass = param.cipherPass == NULL ? NULL : manifestCipherSubPass(manifest);
|
||||
|
||||
testBackupValidateList(storage, path, manifest, manifestData(manifest), manifestFileList, cipherType, cipherPass, result);
|
||||
testBackupValidateList(storage, path, manifest, manifestData(manifest), manifestFileList, result);
|
||||
|
||||
// Check remaining files in the manifest -- these should all be references
|
||||
for (unsigned int manifestFileIdx = 0; manifestFileIdx < strLstSize(manifestFileList); manifestFileIdx++)
|
||||
@@ -473,7 +459,7 @@ testBackupValidate(const Storage *const storage, const String *const path, const
|
||||
.compressType = manifestData(manifest)->backupOptionCompressType,
|
||||
.blockIncr = file.blockIncrMapSize != 0),
|
||||
sizeof(STORAGE_REPO_BACKUP)),
|
||||
file.sizeRepo, filePack, cipherType, cipherPass));
|
||||
file.sizeRepo, filePack));
|
||||
}
|
||||
|
||||
// Make sure both backup.manifest files exist since we skipped them in the callback above
|
||||
@@ -1326,7 +1312,8 @@ testRun(void)
|
||||
ioFilterParamList(
|
||||
blockIncrNew(
|
||||
3, 3, 8, 2, 4, 5, NULL, compressFilterP(compressTypeGz, 1, .raw = true),
|
||||
cipherBlockNewP(cipherModeEncrypt, cipherTypeAes256Cbc, BUFSTRDEF(TEST_CIPHER_PASS), .raw = true)))),
|
||||
cipherBlockNewP(
|
||||
cipherModeEncrypt, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF(TEST_CIPHER_PASS)), .raw = true)))),
|
||||
"block incr pack");
|
||||
}
|
||||
|
||||
@@ -1690,7 +1677,7 @@ testRun(void)
|
||||
|
||||
HRN_STORAGE_PATH_CREATE(storageRepoWrite(), STORAGE_REPO_BACKUP "/20191003-105320F");
|
||||
|
||||
TEST_RESULT_PTR(backupResumeFind((Manifest *)1, NULL), NULL, "find resumable backup");
|
||||
TEST_RESULT_PTR(backupResumeFind((Manifest *)1, cipherSpecNewNone()), NULL, "find resumable backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
"P00 WARN: backup '20191003-105320F' cannot be resumed: partially deleted by prior resume or invalid");
|
||||
@@ -1704,7 +1691,7 @@ testRun(void)
|
||||
|
||||
HRN_STORAGE_PUT_EMPTY(storageRepoWrite(), STORAGE_REPO_BACKUP "/20191003-105320F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT);
|
||||
|
||||
TEST_RESULT_PTR(backupResumeFind((Manifest *)1, NULL), NULL, "find resumable backup");
|
||||
TEST_RESULT_PTR(backupResumeFind((Manifest *)1, cipherSpecNewNone()), NULL, "find resumable backup");
|
||||
|
||||
TEST_RESULT_LOG("P00 INFO: backup '20191003-105320F' cannot be resumed: resume is disabled");
|
||||
|
||||
@@ -1727,7 +1714,7 @@ testRun(void)
|
||||
|
||||
HRN_STORAGE_PUT_Z(storageRepoWrite(), STORAGE_REPO_BACKUP "/20191003-105320F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, "X");
|
||||
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, NULL), NULL, "find resumable backup");
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, cipherSpecNewNone()), NULL, "find resumable backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
"P00 WARN: backup '20191003-105320F' cannot be resumed: unable to read"
|
||||
@@ -1759,7 +1746,7 @@ testRun(void)
|
||||
storageNewWriteP(
|
||||
storageRepoWrite(), STRDEF(STORAGE_REPO_BACKUP "/20191003-105320F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT))));
|
||||
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, NULL), NULL, "find resumable backup");
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, cipherSpecNewNone()), NULL, "find resumable backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
"P00 WARN: backup '20191003-105320F' cannot be resumed:"
|
||||
@@ -1781,7 +1768,7 @@ testRun(void)
|
||||
storageNewWriteP(
|
||||
storageRepoWrite(), STRDEF(STORAGE_REPO_BACKUP "/20191003-105320F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT))));
|
||||
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, NULL), NULL, "find resumable backup");
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, cipherSpecNewNone()), NULL, "find resumable backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
"P00 WARN: backup '20191003-105320F' cannot be resumed:"
|
||||
@@ -1803,7 +1790,7 @@ testRun(void)
|
||||
storageNewWriteP(
|
||||
storageRepoWrite(), STRDEF(STORAGE_REPO_BACKUP "/20191003-105320F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT))));
|
||||
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, NULL), NULL, "find resumable backup");
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, cipherSpecNewNone()), NULL, "find resumable backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
"P00 WARN: backup '20191003-105320F' cannot be resumed:"
|
||||
@@ -1824,7 +1811,7 @@ testRun(void)
|
||||
storageNewWriteP(
|
||||
storageRepoWrite(), STRDEF(STORAGE_REPO_BACKUP "/20191003-105320F/" BACKUP_MANIFEST_FILE INFO_COPY_EXT))));
|
||||
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, NULL), NULL, "find resumable backup");
|
||||
TEST_RESULT_PTR(backupResumeFind(manifest, cipherSpecNewNone()), NULL, "find resumable backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
"P00 WARN: backup '20191003-105320F' cannot be resumed:"
|
||||
@@ -3663,7 +3650,8 @@ testRun(void)
|
||||
{
|
||||
// Load the previous manifest and null out the checksum-page option to be sure it gets set to false in this backup
|
||||
const String *manifestPriorFile = STRDEF(STORAGE_REPO_BACKUP "/20191103-165320F/" BACKUP_MANIFEST_FILE);
|
||||
Manifest *manifestPrior = manifestNewLoad(storageReadIo(storageNewReadP(storageRepo(), manifestPriorFile)));
|
||||
Manifest *manifestPrior = manifestNewLoad(
|
||||
storageReadIo(storageNewReadP(storageRepo(), manifestPriorFile)), cipherSpecNewNone());
|
||||
manifestPrior->pub.data.backupOptionChecksumPage = NULL;
|
||||
manifestSave(manifestPrior, storageWriteIo(storageNewWriteP(storageRepoWrite(), manifestPriorFile)));
|
||||
|
||||
@@ -3853,8 +3841,8 @@ testRun(void)
|
||||
|
||||
// Run backup
|
||||
hrnBackupPqScriptP(
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS, .walTotal = 2, .walSwitch = true);
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherSpecMain = TEST_CIPHER_SPEC,
|
||||
.walTotal = 2, .walSwitch = true);
|
||||
TEST_RESULT_VOID(hrnCmdBackup(), "backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
@@ -3874,8 +3862,7 @@ testRun(void)
|
||||
|
||||
TEST_RESULT_STR_Z(
|
||||
testBackupValidateP(
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS),
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherSpecMain = TEST_CIPHER_SPEC),
|
||||
".> {d=20191108-080000F}\n"
|
||||
"bundle/1/pg_data/PG_VERSION {s=2, ts=-400000}\n"
|
||||
"bundle/1/pg_data/global/pg_control {s=8192}\n"
|
||||
@@ -3932,8 +3919,8 @@ testRun(void)
|
||||
|
||||
// Run backup
|
||||
hrnBackupPqScriptP(
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS, .walTotal = 2, .walSwitch = true);
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherSpecMain = TEST_CIPHER_SPEC,
|
||||
.walTotal = 2, .walSwitch = true);
|
||||
TEST_RESULT_VOID(hrnCmdBackup(), "backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
@@ -3960,8 +3947,7 @@ testRun(void)
|
||||
|
||||
TEST_RESULT_STR_Z(
|
||||
testBackupValidateP(
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS),
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherSpecMain = TEST_CIPHER_SPEC),
|
||||
".> {d=20191108-080000F}\n"
|
||||
"bundle/1/pg_data/PG_VERSION {s=2, ts=-500000}\n"
|
||||
"bundle/1/pg_data/global/pg_control {s=8192}\n"
|
||||
@@ -4029,8 +4015,8 @@ testRun(void)
|
||||
|
||||
// Run backup
|
||||
hrnBackupPqScriptP(
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS, .walTotal = 2, .walSwitch = true);
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherSpecMain = TEST_CIPHER_SPEC,
|
||||
.walTotal = 2, .walSwitch = true);
|
||||
TEST_RESULT_VOID(hrnCmdBackup(), "backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
@@ -4058,8 +4044,7 @@ testRun(void)
|
||||
|
||||
TEST_RESULT_STR_Z(
|
||||
testBackupValidateP(
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS),
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherSpecMain = TEST_CIPHER_SPEC),
|
||||
".> {d=20191108-080000F_20191110-153320D}\n"
|
||||
"bundle/1/pg_data/block-age-multiplier {s=32768, m=1:{0,1}, ts=-86400}\n"
|
||||
"bundle/1/pg_data/block-age-to-zero {s=16384, ts=-172800}\n"
|
||||
@@ -4095,8 +4080,8 @@ testRun(void)
|
||||
|
||||
// Run backup
|
||||
hrnBackupPqScriptP(
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS, .walTotal = 1, .walSwitch = false);
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherSpecMain = TEST_CIPHER_SPEC,
|
||||
.walTotal = 1, .walSwitch = false);
|
||||
TEST_RESULT_VOID(hrnCmdBackup(), "backup");
|
||||
|
||||
TEST_RESULT_LOG(
|
||||
@@ -4121,8 +4106,7 @@ testRun(void)
|
||||
|
||||
TEST_RESULT_STR_Z(
|
||||
testBackupValidateP(
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS),
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherSpecMain = TEST_CIPHER_SPEC),
|
||||
".> {d=20191108-080000F_20191111-052640I}\n"
|
||||
"pg_data/backup_label.gz {s=17, ts=+2}\n"
|
||||
"pg_data/global/pg_control.gz {s=8192}\n"
|
||||
@@ -4186,8 +4170,8 @@ testRun(void)
|
||||
{.op = hrnBackupScriptOpUpdate, .file = storagePathP(storagePg(), STRDEF("global/1")),
|
||||
.time = backupTimeStart + 1, .content = fileGrow});
|
||||
hrnBackupPqScriptP(
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS, .walTotal = 2, .walSwitch = true);
|
||||
PG_VERSION_11, backupTimeStart, .walCompressType = compressTypeNone, .cipherSpecMain = TEST_CIPHER_SPEC,
|
||||
.walTotal = 2, .walSwitch = true);
|
||||
TEST_RESULT_VOID(hrnCmdBackup(), "backup");
|
||||
|
||||
// Make sure that global/1 grew as expected but the extra bytes were not copied
|
||||
@@ -4211,8 +4195,7 @@ testRun(void)
|
||||
|
||||
TEST_RESULT_STR_Z(
|
||||
testBackupValidateP(
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS),
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"), .cipherSpecMain = TEST_CIPHER_SPEC),
|
||||
".> {d=20191111-192000F}\n"
|
||||
"bundle/1/pg_data/PG_VERSION {s=2}\n"
|
||||
"bundle/1/pg_data/global/pg_control {s=8192}\n"
|
||||
|
||||
@@ -753,10 +753,7 @@ testRun(void)
|
||||
|
||||
// Version mismatch
|
||||
TEST_ERROR(
|
||||
checkStanzaInfoPg(
|
||||
storageRepoIdx(0), PG_VERSION_18, HRN_PG_SYSTEMID_18, cfgOptionIdxStrId(cfgOptRepoCipherType, 0),
|
||||
cfgOptionIdxStr(cfgOptRepoCipherPass, 0)),
|
||||
FileInvalidError,
|
||||
checkStanzaInfoPg(storageRepoIdx(0), PG_VERSION_18, HRN_PG_SYSTEMID_18, cfgCipherSpecMainIdx(0)), FileInvalidError,
|
||||
"backup and archive info files exist but do not match the database\n"
|
||||
"HINT: is this the correct stanza?\n"
|
||||
"HINT: did an error occur during stanza-upgrade?");
|
||||
@@ -766,10 +763,7 @@ testRun(void)
|
||||
|
||||
// SystemId mismatch
|
||||
TEST_ERROR(
|
||||
checkStanzaInfoPg(
|
||||
storageRepoIdx(0), PG_VERSION_96, 6569239123849665699, cfgOptionIdxStrId(cfgOptRepoCipherType, 0),
|
||||
cfgOptionIdxStr(cfgOptRepoCipherPass, 0)),
|
||||
FileInvalidError,
|
||||
checkStanzaInfoPg(storageRepoIdx(0), PG_VERSION_96, 6569239123849665699, cfgCipherSpecMainIdx(0)), FileInvalidError,
|
||||
"backup and archive info files exist but do not match the database\n"
|
||||
"HINT: is this the correct stanza?\n"
|
||||
"HINT: did an error occur during stanza-upgrade?");
|
||||
|
||||
@@ -156,7 +156,7 @@ testRun(void)
|
||||
|
||||
// Create backup.info
|
||||
InfoBackup *infoBackup = NULL;
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase), cipherSpecNewNone()), "get backup.info");
|
||||
|
||||
// Load Parameters
|
||||
StringList *argList = strLstDup(argListAvoidWarn);
|
||||
@@ -190,7 +190,7 @@ testRun(void)
|
||||
{
|
||||
// Create backup.info
|
||||
InfoBackup *infoBackup = NULL;
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase), cipherSpecNewNone()), "get backup.info");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("retention-full not set - nothing expired");
|
||||
@@ -251,7 +251,7 @@ testRun(void)
|
||||
{
|
||||
// Create backup.info
|
||||
InfoBackup *infoBackup = NULL;
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase), cipherSpecNewNone()), "get backup.info");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("retention-diff not set - nothing expired");
|
||||
@@ -334,7 +334,7 @@ testRun(void)
|
||||
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702"
|
||||
",\"db-version\":\"9.4\"}");
|
||||
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent)), "get backup.info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent), cipherSpecNewNone()), "get backup.info");
|
||||
|
||||
// Load parameters
|
||||
argList = strLstDup(argListAvoidWarn);
|
||||
@@ -386,7 +386,8 @@ testRun(void)
|
||||
|
||||
InfoBackup *infoBackup = NULL;
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
// Put some files in the backup directories
|
||||
HRN_STORAGE_PUT_Z(storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152100F/" BOGUS_STR, BOGUS_STR);
|
||||
@@ -429,7 +430,7 @@ testRun(void)
|
||||
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702"
|
||||
",\"db-version\":\"9.4\"}");
|
||||
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent)), "get backup.info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent), cipherSpecNewNone()), "get backup.info");
|
||||
|
||||
TEST_RESULT_VOID(removeExpiredBackup(infoBackup, NULL, 0), "remove backups - backup.info current empty");
|
||||
|
||||
@@ -477,7 +478,8 @@ testRun(void)
|
||||
",\"db-version\":\"9.4\"}");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
// Committed backup (in backup.info) and an older orphan backup that is not in backup.info and has no manifest copy
|
||||
HRN_STORAGE_PUT_Z(storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152138F/" BOGUS_STR, BOGUS_STR);
|
||||
@@ -537,7 +539,7 @@ testRun(void)
|
||||
",\"db-version\":\"9.4\"}");
|
||||
|
||||
InfoBackup *infoBackup = NULL;
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent)), "get backup.info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoContent), cipherSpecNewNone()), "get backup.info");
|
||||
|
||||
TEST_RESULT_VOID(removeExpiredArchive(infoBackup, false, 0), "archive retention not set");
|
||||
TEST_RESULT_LOG(
|
||||
@@ -644,7 +646,8 @@ testRun(void)
|
||||
",\"db-version\":\"10\"}\n");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
HRN_INFO_PUT(
|
||||
storageRepoWrite(), INFO_ARCHIVE_PATH_FILE,
|
||||
@@ -885,13 +888,13 @@ testRun(void)
|
||||
"archive sub path repo1 not removed");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(1), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(1), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info repo2");
|
||||
TEST_RESULT_BOOL(
|
||||
strLstExists(infoBackupDataLabelList(infoBackup, NULL), STRDEF("20181119-152138F")), false,
|
||||
"backup removed from repo2");
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(0), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(0), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info repo1");
|
||||
TEST_RESULT_BOOL(
|
||||
strLstExists(infoBackupDataLabelList(infoBackup, NULL), STRDEF("20181119-152138F")), true, "backup exists repo1");
|
||||
@@ -1125,7 +1128,7 @@ testRun(void)
|
||||
"P00 INFO: repo2: 10-2 no archive to remove");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"repo1: get backup.info");
|
||||
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 2, "repo1: backup.info updated on disk");
|
||||
TEST_RESULT_STRLST_Z(
|
||||
@@ -1133,7 +1136,7 @@ testRun(void)
|
||||
"20181119-152900F\n20181119-152900F_20181119-152500I\n", "repo1: remaining current backups correct");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(1), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(1), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"repo2: get backup.info");
|
||||
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 4, "repo2: backup.info updated on disk");
|
||||
TEST_RESULT_STRLST_Z(
|
||||
@@ -1256,7 +1259,8 @@ testRun(void)
|
||||
",\"db-version\":\"10\"}\n");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
archiveGenerate(storageRepoWrite(), STORAGE_REPO_ARCHIVE, 1, 5, "9.4-1", "0000000100000000");
|
||||
|
||||
@@ -1338,7 +1342,8 @@ testRun(void)
|
||||
",\"db-version\":\"10\"}\n");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
HRN_STORAGE_PUT_EMPTY(storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152138F/" BACKUP_MANIFEST_FILE);
|
||||
|
||||
@@ -1601,7 +1606,8 @@ testRun(void)
|
||||
",\"db-version\":\"10\"}\n");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
HRN_INFO_PUT(
|
||||
storageRepoWrite(), INFO_ARCHIVE_PATH_FILE,
|
||||
@@ -1669,7 +1675,8 @@ testRun(void)
|
||||
",\"db-version\":\"10\"}\n");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
archiveGenerate(storageRepoWrite(), STORAGE_REPO_ARCHIVE, 1, 10, "9.4-1", "0000000100000000");
|
||||
|
||||
@@ -2064,7 +2071,8 @@ testRun(void)
|
||||
|
||||
InfoBackup *infoBackup = NULL;
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
// Create "latest" symlink
|
||||
const String *latestLink = storagePathP(storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/latest"));
|
||||
@@ -2302,7 +2310,8 @@ testRun(void)
|
||||
|
||||
// Load the backup info. Do not store a manifest file for the adhoc backup for code coverage
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL), "get backup.info");
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get backup.info");
|
||||
|
||||
HRN_STORAGE_PATH_CREATE(
|
||||
storageRepoWrite(), STORAGE_REPO_BACKUP "/20181119-152850F_20181119-152252D",
|
||||
@@ -2451,7 +2460,7 @@ testRun(void)
|
||||
"[db:history]\n"
|
||||
"1={\"db-id\":6625592122879095702,\"db-version\":\"9.4\"}\n"
|
||||
"2={\"db-id\":6626363367545678089,\"db-version\":\"12\"}",
|
||||
.cipherType = cipherTypeAes256Cbc);
|
||||
.cipherSpec = TEST_CIPHER_SPEC);
|
||||
|
||||
const String *backupInfoContent = STRDEF(
|
||||
TEST_BACKUP_CURRENT
|
||||
@@ -2460,16 +2469,16 @@ testRun(void)
|
||||
"cipher-pass=\"somepass\"\n"
|
||||
TEST_BACKUP_DB);
|
||||
|
||||
HRN_INFO_PUT(storageRepoIdxWrite(1), INFO_BACKUP_PATH_FILE, strZ(backupInfoContent), .cipherType = cipherTypeAes256Cbc);
|
||||
HRN_INFO_PUT(storageRepoIdxWrite(1), INFO_BACKUP_PATH_FILE, strZ(backupInfoContent), .cipherSpec = TEST_CIPHER_SPEC);
|
||||
HRN_INFO_PUT(
|
||||
storageRepoIdxWrite(1), STORAGE_REPO_BACKUP "/20181119-152850F/" BACKUP_MANIFEST_FILE,
|
||||
"[backup]\nbackup-type=\"full\"\n", .cipherType = cipherTypeAes256Cbc, .cipherPass = "somepass");
|
||||
"[backup]\nbackup-type=\"full\"\n", .cipherSpec = TEST_CIPHER_SPEC_PASS("somepass"));
|
||||
HRN_INFO_PUT(
|
||||
storageRepoIdxWrite(1), STORAGE_REPO_BACKUP "/20181119-152850F_20181119-152252D/" BACKUP_MANIFEST_FILE,
|
||||
"[backup]\nbackup-type=\"diff\"\n", .cipherType = cipherTypeAes256Cbc, .cipherPass = "somepass");
|
||||
"[backup]\nbackup-type=\"diff\"\n", .cipherSpec = TEST_CIPHER_SPEC_PASS("somepass"));
|
||||
HRN_INFO_PUT(
|
||||
storageRepoIdxWrite(1), STORAGE_REPO_BACKUP "/20181119-152850F_20181200-152252D/" BACKUP_MANIFEST_FILE INFO_COPY_EXT,
|
||||
strZ(manifestContent), .cipherType = cipherTypeAes256Cbc, .cipherPass = "somepass", .comment = "resumable backup");
|
||||
strZ(manifestContent), .cipherSpec = TEST_CIPHER_SPEC_PASS("somepass"), .comment = "resumable backup");
|
||||
|
||||
// archives to repo2
|
||||
archiveGenerate(storageRepoIdxWrite(1), STORAGE_REPO_ARCHIVE, 2, 10, "12-2", "0000000100000000");
|
||||
@@ -2530,7 +2539,7 @@ testRun(void)
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702"
|
||||
",\"db-version\":\"9.4\"}"))),
|
||||
",\"db-version\":\"9.4\"}")), cipherSpecNewNone()),
|
||||
"empty backup.info");
|
||||
|
||||
TEST_RESULT_UINT(expireTimeBasedBackup(infoBackup, (time_t)(timeNow - (40 * SEC_PER_DAY)), 0), 0, "no backups to expire");
|
||||
@@ -2569,7 +2578,7 @@ testRun(void)
|
||||
// Set the log level to detail so archive expiration messages are seen
|
||||
harnessLogLevelSet(logLevelDetail);
|
||||
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase)), "get backup.info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(backupInfoBase), cipherSpecNewNone()), "get backup.info");
|
||||
TEST_RESULT_VOID(cmdExpire(), "repo-retention-full not set for time-based");
|
||||
TEST_RESULT_LOG(
|
||||
"P00 WARN: option 'repo1-retention-full' is not set for 'repo1-retention-full-type=time', the repository may run out"
|
||||
@@ -2712,7 +2721,7 @@ testRun(void)
|
||||
// Expire oldest from backup.info only, leaving the backup and archives on disk then save backup.info without oldest backup
|
||||
TEST_RESULT_UINT(expireTimeBasedBackup(infoBackup, (time_t)(timeNow - (25 * SEC_PER_DAY)), 0), 1, "expire oldest backup");
|
||||
TEST_RESULT_VOID(
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"save backup.info without oldest");
|
||||
TEST_RESULT_LOG("P00 INFO: repo1: expire time-based backup 20181119-152138F");
|
||||
TEST_RESULT_VOID(cmdExpire(), "only oldest backup expired");
|
||||
|
||||
@@ -1045,7 +1045,7 @@ testRun(void)
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"1={\"db-id\":6626363367545678089,\"db-version\":\"9.5\"}\n",
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS,
|
||||
.cipherSpec = TEST_CIPHER_SPEC,
|
||||
.comment = "write encrypted archive.info, stanza1, repo2");
|
||||
HRN_INFO_PUT(
|
||||
storageTest, TEST_PATH "/repo2/" STORAGE_PATH_BACKUP "/stanza1/" INFO_BACKUP_FILE,
|
||||
@@ -1072,7 +1072,7 @@ testRun(void)
|
||||
"[db:history]\n"
|
||||
"1={\"db-catalog-version\":201510051,\"db-control-version\":942,\"db-system-id\":6626363367545678089"
|
||||
",\"db-version\":\"9.5\"}\n",
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS,
|
||||
.cipherSpec = TEST_CIPHER_SPEC,
|
||||
.comment = "write encrypted backup.info, stanza1, repo2");
|
||||
|
||||
// Add WAL on repo1 and encrypted repo2 for stanza1
|
||||
@@ -1143,7 +1143,7 @@ testRun(void)
|
||||
TEST_MANIFEST_LINK_DEFAULT
|
||||
TEST_MANIFEST_PATH
|
||||
TEST_MANIFEST_PATH_DEFAULT,
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = "somepass",
|
||||
.cipherSpec = TEST_CIPHER_SPEC_PASS("somepass"),
|
||||
.comment = "write encrypted manifest, stanza1, repo2");
|
||||
|
||||
// Create a stanza on repo2 that is not on repo1
|
||||
@@ -1159,7 +1159,7 @@ testRun(void)
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"1={\"db-id\":6626363367545678089,\"db-version\":\"9.4\"}\n",
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS,
|
||||
.cipherSpec = TEST_CIPHER_SPEC,
|
||||
.comment = "write encrypted archive.info, repo2, stanza3");
|
||||
HRN_INFO_PUT(
|
||||
storageTest, TEST_PATH "/repo2/" STORAGE_PATH_BACKUP "/stanza3/" INFO_BACKUP_FILE,
|
||||
@@ -1185,7 +1185,7 @@ testRun(void)
|
||||
"[db:history]\n"
|
||||
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6626363367545678089"
|
||||
",\"db-version\":\"9.4\"}\n",
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS,
|
||||
.cipherSpec = TEST_CIPHER_SPEC,
|
||||
.comment = "write encrypted backup.info, repo2, stanza3");
|
||||
|
||||
// Store some WAL in stanza on repo2 that is not on repo1
|
||||
@@ -3069,7 +3069,7 @@ testRun(void)
|
||||
"[db:history]\n"
|
||||
"1={\"db-catalog-version\":201510051,\"db-control-version\":942,\"db-system-id\":6626363367545678089"
|
||||
",\"db-version\":\"9.5\"}\n",
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS,
|
||||
.cipherSpec = TEST_CIPHER_SPEC,
|
||||
.comment = "backup.info without current, repo2, stanza1");
|
||||
|
||||
TEST_RESULT_STR_Z(
|
||||
|
||||
@@ -108,8 +108,7 @@ testRun(void)
|
||||
HRN_CFG_LOAD(cfgCmdBackup, argList);
|
||||
|
||||
hrnBackupPqScriptP(
|
||||
PG_VERSION_14, backupTimeStart, .noArchiveCheck = true, .noWal = true, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS);
|
||||
PG_VERSION_14, backupTimeStart, .noArchiveCheck = true, .noWal = true, .cipherSpecMain = TEST_CIPHER_SPEC);
|
||||
TEST_RESULT_VOID(hrnCmdBackup(), "backup repo2");
|
||||
}
|
||||
|
||||
@@ -137,7 +136,7 @@ testRun(void)
|
||||
// Munge the pg_control checksum since it will vary by architecture
|
||||
Manifest *manifest = manifestLoadFile(
|
||||
storageRepo(), STRDEF(STORAGE_REPO_BACKUP "/20191002-070640F_20191003-105320D/" BACKUP_MANIFEST_FILE),
|
||||
cipherTypeNone, NULL);
|
||||
cipherSpecNewNone());
|
||||
|
||||
ManifestFile file = manifestFileFind(manifest, STRDEF(MANIFEST_TARGET_PGDATA "/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL));
|
||||
file.checksumSha1 = bufPtr(bufNewDecode(encodingHex, STRDEF("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")));
|
||||
@@ -155,8 +154,7 @@ testRun(void)
|
||||
HRN_CFG_LOAD(cfgCmdBackup, argList);
|
||||
|
||||
hrnBackupPqScriptP(
|
||||
PG_VERSION_14, backupTimeStart, .noArchiveCheck = true, .noWal = true, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = TEST_CIPHER_PASS);
|
||||
PG_VERSION_14, backupTimeStart, .noArchiveCheck = true, .noWal = true, .cipherSpecMain = TEST_CIPHER_SPEC);
|
||||
TEST_RESULT_VOID(hrnCmdBackup(), "backup repo2");
|
||||
}
|
||||
|
||||
|
||||
@@ -402,31 +402,30 @@ testRun(void)
|
||||
HRN_STORAGE_PUT(storageFixture, strZ(fileName), fileBuffer);
|
||||
HRN_STORAGE_PUT_Z(storageFixture, strZ(fileRawName), fileRawContent);
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_ARCHIVE "/test/" INFO_ARCHIVE_FILE, archiveInfoFileBuffer,
|
||||
.cipherType = cipherTypeAes256Cbc);
|
||||
storageFixture, STORAGE_PATH_ARCHIVE "/test/" INFO_ARCHIVE_FILE, archiveInfoFileBuffer, .cipherSpec = TEST_CIPHER_SPEC);
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_ARCHIVE "/test/" INFO_ARCHIVE_FILE ".copy", archiveInfoFileBuffer,
|
||||
.cipherType = cipherTypeAes256Cbc);
|
||||
.cipherSpec = TEST_CIPHER_SPEC);
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_BACKUP "/test/" INFO_BACKUP_FILE, backupInfoFileBuffer, .cipherType = cipherTypeAes256Cbc);
|
||||
storageFixture, STORAGE_PATH_BACKUP "/test/" INFO_BACKUP_FILE, backupInfoFileBuffer, .cipherSpec = TEST_CIPHER_SPEC);
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_BACKUP "/test/" INFO_BACKUP_FILE ".copy", backupInfoFileBuffer,
|
||||
.cipherType = cipherTypeAes256Cbc);
|
||||
.cipherSpec = TEST_CIPHER_SPEC);
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_ARCHIVE "/test/12-1/000000010000000100000001-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
archiveFileBuffer, .cipherType = cipherTypeAes256Cbc, .cipherPass = "custom");
|
||||
archiveFileBuffer, .cipherSpec = TEST_CIPHER_SPEC_PASS("custom"));
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_BACKUP "/test/latest/" BACKUP_MANIFEST_FILE, manifestFileBuffer,
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = "custom");
|
||||
.cipherSpec = TEST_CIPHER_SPEC_PASS("custom"));
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_BACKUP "/test/latest/" BACKUP_MANIFEST_FILE ".copy", manifestFileBuffer,
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = "custom");
|
||||
.cipherSpec = TEST_CIPHER_SPEC_PASS("custom"));
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_BACKUP "/test/backup.history/2020/label.manifest.gz", manifestFileBuffer,
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = "custom");
|
||||
.cipherSpec = TEST_CIPHER_SPEC_PASS("custom"));
|
||||
HRN_STORAGE_PUT(
|
||||
storageFixture, STORAGE_PATH_BACKUP "/test/latest/pg_data/backup_label", backupLabelBuffer,
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = "custom2");
|
||||
.cipherSpec = TEST_CIPHER_SPEC_PASS("custom2"));
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("error when missing source");
|
||||
|
||||
@@ -236,7 +236,7 @@ testRun(void)
|
||||
ioBufferReadNewOpen(BUF(bufPtr(destination) + (bufUsed(destination) - (size_t)mapSize), (size_t)mapSize)), 3, 5);
|
||||
|
||||
// Perform block delta
|
||||
BlockDelta *blockDelta = blockDeltaNew(blockMap, 3, 5, NULL, cipherTypeNone, NULL, compressTypeGz);
|
||||
BlockDelta *blockDelta = blockDeltaNew(blockMap, 3, 5, NULL, cipherSpecNewNone(), compressTypeGz);
|
||||
const BlockDeltaRead *blockDeltaRead = blockDeltaReadGet(blockDelta, 0);
|
||||
IoRead *read = ioBufferReadNewOpen(destination);
|
||||
|
||||
@@ -289,7 +289,7 @@ testRun(void)
|
||||
|
||||
HRN_STORAGE_PUT_Z(
|
||||
storageRepoWrite(), zNewFmt(STORAGE_REPO_BACKUP "/%s/%s", strZ(repoFileReferenceFull), strZ(repoFile1)),
|
||||
"acefile", .compressType = compressTypeGz, .cipherType = cipherTypeAes256Cbc, .cipherPass = "badpass",
|
||||
"acefile", .compressType = compressTypeGz, .cipherSpec = TEST_CIPHER_SPEC_PASS("badpass"),
|
||||
.comment = "create a compressed encrypted repo file");
|
||||
|
||||
List *fileList = lstNewP(sizeof(RestoreFile));
|
||||
@@ -311,7 +311,7 @@ testRun(void)
|
||||
TEST_ERROR(
|
||||
restoreFile(
|
||||
strNewFmt(STORAGE_REPO_BACKUP "/%s/%s.gz", strZ(repoFileReferenceFull), strZ(repoFile1)), repoIdx, compressTypeGz,
|
||||
0, false, false, false, STRDEF("badpass"), NULL, fileList),
|
||||
0, false, false, false, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("badpass")), NULL, fileList),
|
||||
ChecksumError,
|
||||
"error restoring 'normal': actual checksum 'd1cd8a7d11daa26814b93eb604e1d49ab4b43770' does not match expected checksum"
|
||||
" 'ffffffffffffffffffffffffffffffffffffffff'");
|
||||
@@ -2070,45 +2070,45 @@ testRun(void)
|
||||
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_11, 1, 0xA1, NULL, CFGOPTVAL_RESTORE_TYPE_DEFAULT, cipherTypeNone,
|
||||
NULL),
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_11, 1, 0xA1, NULL, CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherSpecNewNone()),
|
||||
"follow current timeline because of version");
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_11, 1, 0xA1, STRDEF("latest"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
"follow latest timeline as requested");
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 1, 0xA1, NULL, cipherTypeNone, CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
NULL),
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 1, 0xA1, NULL, CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherSpecNewNone()),
|
||||
"follow latest timeline because of version");
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 1, 0xA1, STRDEF("current"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
"follow current timeline as requested");
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 1, 0xA1, STRDEF("1"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
"follow requested timeline (same as current)");
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 0x10, 0xA1, STRDEF("0x10"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
"follow requested hex timeline (same as current)");
|
||||
TEST_ERROR(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 0x10, 0xA1, STRDEF("bogus"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
DbMismatchError, "invalid target timeline 'bogus'");
|
||||
|
||||
HRN_STORAGE_PUT_Z(storageTest, "repo/archive/test1/17-1/00000009.history", "8");
|
||||
TEST_ERROR(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 8, 0xA1, STRDEF("9"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
FormatError,
|
||||
"invalid timeline '9' at '" TEST_PATH "/repo/archive/test1/17-1/00000009.history':"
|
||||
" invalid history line format '8'");
|
||||
@@ -2121,27 +2121,27 @@ testRun(void)
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 10, 0x4FFFFFF, NULL, CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
"follow current timeline");
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 9, 0x4FFFFFF, NULL, CFGOPTVAL_RESTORE_TYPE_IMMEDIATE,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
"follow current timeline (based on type immediate)");
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 9, 0x4FFFFFF, NULL, CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
"follow latest timeline");
|
||||
TEST_RESULT_VOID(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 9, 0x4FFFFFF, STRDEF("10"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
"target timeline found");
|
||||
TEST_ERROR(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 9, 0x6000000, STRDEF("10"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
DbMismatchError,
|
||||
"target timeline A forked from backup timeline 9 at 0/5000000 which is before backup lsn of 0/6000000\n"
|
||||
"HINT: was the target timeline created by accidentally promoting a standby?\n"
|
||||
@@ -2155,7 +2155,7 @@ testRun(void)
|
||||
TEST_ERROR(
|
||||
timelineVerify(
|
||||
storageRepoIdx(0), STRDEF("17-1"), PG_VERSION_12, 6, 0x4FFFFFF, STRDEF("11"), CFGOPTVAL_RESTORE_TYPE_DEFAULT,
|
||||
cipherTypeNone, NULL),
|
||||
cipherSpecNewNone()),
|
||||
DbMismatchError, "backup timeline 6, lsn 0/4ffffff is not in the history of target timeline B\n"
|
||||
"HINT: was the target timeline created by promoting from a timeline < latest?");
|
||||
}
|
||||
@@ -2287,7 +2287,7 @@ testRun(void)
|
||||
// Store the file also to the encrypted repo
|
||||
HRN_STORAGE_PUT_Z(
|
||||
storageRepoIdxWrite(1), TEST_REPO_PATH PG_FILE_PGVERSION, PG_VERSION_11_Z "\n",
|
||||
.cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS_ARCHIVE);
|
||||
.cipherSpec = TEST_CIPHER_SPEC_PASS(TEST_CIPHER_PASS_ARCHIVE));
|
||||
|
||||
// pg_tblspc
|
||||
HRN_MANIFEST_PATH_ADD(manifest, .name = MANIFEST_TARGET_PGDATA "/" MANIFEST_TARGET_PGTBLSPC);
|
||||
@@ -2307,8 +2307,9 @@ testRun(void)
|
||||
|
||||
// Read the manifest, set a cipher passphrase and store it to the encrypted repo
|
||||
Manifest *manifestEncrypted = manifestLoadFile(
|
||||
storageRepoIdxWrite(0), STRDEF(STORAGE_REPO_BACKUP "/" TEST_LABEL "/" BACKUP_MANIFEST_FILE), cipherTypeNone, NULL);
|
||||
manifestCipherSubPassSet(manifestEncrypted, STRDEF(TEST_CIPHER_PASS_ARCHIVE));
|
||||
storageRepoIdxWrite(0), STRDEF(STORAGE_REPO_BACKUP "/" TEST_LABEL "/" BACKUP_MANIFEST_FILE),
|
||||
cipherSpecNewNone());
|
||||
manifestCipherSpecSet(manifestEncrypted, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF(TEST_CIPHER_PASS_ARCHIVE)));
|
||||
|
||||
// Open file for write
|
||||
IoWrite *write = storageWriteIo(
|
||||
@@ -2319,19 +2320,21 @@ testRun(void)
|
||||
// Add encryption filter and save the encrypted manifest
|
||||
#define TEST_CIPHER_PASS_MANIFEST "backpass"
|
||||
cipherBlockFilterGroupAdd(
|
||||
ioWriteFilterGroup(write), cfgOptionIdxStrId(cfgOptRepoCipherType, 1), cipherModeEncrypt,
|
||||
STRDEF(TEST_CIPHER_PASS_MANIFEST));
|
||||
ioWriteFilterGroup(write), cipherModeEncrypt,
|
||||
cipherSpecNew(cfgOptionIdxStrId(cfgOptRepoCipherType, 1), BUFSTRDEF(TEST_CIPHER_PASS_MANIFEST)));
|
||||
manifestSave(manifestEncrypted, write);
|
||||
|
||||
// Write backup.info to the encrypted repo
|
||||
HRN_INFO_PUT(
|
||||
storageRepoIdxWrite(1), INFO_BACKUP_PATH_FILE, TEST_RESTORE_BACKUP_INFO "\n[cipher]\ncipher-pass=\""
|
||||
TEST_CIPHER_PASS_MANIFEST "\"\n\n" TEST_RESTORE_BACKUP_INFO_DB, .cipherType = cipherTypeAes256Cbc);
|
||||
TEST_CIPHER_PASS_MANIFEST "\"\n\n" TEST_RESTORE_BACKUP_INFO_DB, .cipherSpec = TEST_CIPHER_SPEC);
|
||||
|
||||
// Write archive.info to the encrypted repo
|
||||
InfoArchive *infoArchive = infoArchiveNew(PG_VERSION_11, 6569239123849665679, STRDEF(TEST_CIPHER_PASS_ARCHIVE));
|
||||
InfoArchive *infoArchive = infoArchiveNew(
|
||||
PG_VERSION_11, 6569239123849665679, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF(TEST_CIPHER_PASS_ARCHIVE)));
|
||||
infoArchiveSaveFile(
|
||||
infoArchive, storageRepoIdxWrite(1), INFO_ARCHIVE_PATH_FILE_STR, cipherTypeAes256Cbc, STRDEF(TEST_CIPHER_PASS));
|
||||
infoArchive, storageRepoIdxWrite(1), INFO_ARCHIVE_PATH_FILE_STR,
|
||||
cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF(TEST_CIPHER_PASS)));
|
||||
|
||||
TEST_RESULT_VOID(hrnCmdRestore(), "successful restore");
|
||||
|
||||
@@ -2376,7 +2379,8 @@ testRun(void)
|
||||
|
||||
// Store archive.info to repo1 - repo1 will be selected because of the priority order
|
||||
infoArchive = infoArchiveNew(PG_VERSION_11, 6569239123849665679, NULL);
|
||||
infoArchiveSaveFile(infoArchive, storageRepoIdxWrite(0), INFO_ARCHIVE_PATH_FILE_STR, cipherTypeNone, NULL);
|
||||
infoArchiveSaveFile(
|
||||
infoArchive, storageRepoIdxWrite(0), INFO_ARCHIVE_PATH_FILE_STR, cipherSpecNewNone());
|
||||
|
||||
hrnCfgArgRawZ(argList, cfgOptTargetTimeline, "0xff");
|
||||
HRN_CFG_LOAD(cfgCmdRestore, argList);
|
||||
|
||||
@@ -133,42 +133,53 @@ testRun(void)
|
||||
InfoArchive *infoArchive = NULL;
|
||||
TEST_ASSIGN(
|
||||
infoArchive,
|
||||
infoArchiveLoadFile(storageRepoIdx(1), INFO_ARCHIVE_PATH_FILE_STR, cipherTypeAes256Cbc, STRDEF("12345678")),
|
||||
infoArchiveLoadFile(
|
||||
storageRepoIdx(1), INFO_ARCHIVE_PATH_FILE_STR, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("12345678"))),
|
||||
"load archive info from encrypted repo2");
|
||||
TEST_RESULT_PTR_NE(infoArchiveCipherPass(infoArchive), NULL, "cipher sub set");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoArchiveCipherSpec(infoArchive)), cipherTypeAes256Cbc, "cipher sub set");
|
||||
|
||||
InfoBackup *infoBackup = NULL;
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(1), INFO_BACKUP_PATH_FILE_STR, cipherTypeAes256Cbc, STRDEF("12345678")),
|
||||
infoBackup,
|
||||
infoBackupLoadFile(
|
||||
storageRepoIdx(1), INFO_BACKUP_PATH_FILE_STR, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("12345678"))),
|
||||
"load backup info from encrypted repo2");
|
||||
TEST_RESULT_PTR_NE(infoBackupCipherPass(infoBackup), NULL, "cipher sub set");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoBackupCipherSpec(infoBackup)), cipherTypeAes256Cbc, "cipher sub set");
|
||||
|
||||
TEST_RESULT_BOOL(
|
||||
strEq(infoArchiveCipherPass(infoArchive), infoBackupCipherPass(infoBackup)), false,
|
||||
bufEq(cipherSpecPass(infoArchiveCipherSpec(infoArchive)), cipherSpecPass(infoBackupCipherSpec(infoBackup))), false,
|
||||
"cipher sub different for archive and backup");
|
||||
|
||||
// Confirm non-encrypted repo created successfully
|
||||
TEST_ASSIGN(
|
||||
infoArchive, infoArchiveLoadFile(storageRepoIdx(2), INFO_ARCHIVE_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoArchive,
|
||||
infoArchiveLoadFile(storageRepoIdx(2), INFO_ARCHIVE_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"load archive info from repo3");
|
||||
TEST_RESULT_PTR(infoArchiveCipherPass(infoArchive), NULL, "archive cipher sub not set on non-encrypted repo");
|
||||
TEST_RESULT_UINT(
|
||||
cipherSpecType(infoArchiveCipherSpec(infoArchive)), cipherTypeNone,
|
||||
"archive cipher sub not set on non-encrypted repo");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(2), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(2), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"load backup info from repo3");
|
||||
TEST_RESULT_PTR(infoBackupCipherPass(infoBackup), NULL, "backup cipher sub not set on non-encrypted repo");
|
||||
TEST_RESULT_UINT(
|
||||
cipherSpecType(infoBackupCipherSpec(infoBackup)), cipherTypeNone,
|
||||
"backup cipher sub not set on non-encrypted repo");
|
||||
|
||||
// Confirm other repo encrypted with different password
|
||||
TEST_ASSIGN(
|
||||
infoArchive,
|
||||
infoArchiveLoadFile(storageRepoIdx(3), INFO_ARCHIVE_PATH_FILE_STR, cipherTypeAes256Cbc, STRDEF("87654321")),
|
||||
infoArchiveLoadFile(
|
||||
storageRepoIdx(3), INFO_ARCHIVE_PATH_FILE_STR, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("87654321"))),
|
||||
"load archive info from encrypted repo4");
|
||||
TEST_RESULT_PTR_NE(infoArchiveCipherPass(infoArchive), NULL, "cipher sub set");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoArchiveCipherSpec(infoArchive)), cipherTypeAes256Cbc, "cipher sub set");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepoIdx(3), INFO_BACKUP_PATH_FILE_STR, cipherTypeAes256Cbc, STRDEF("87654321")),
|
||||
infoBackup,
|
||||
infoBackupLoadFile(
|
||||
storageRepoIdx(3), INFO_BACKUP_PATH_FILE_STR, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("87654321"))),
|
||||
"load backup info from encrypted repo4");
|
||||
TEST_RESULT_PTR_NE(infoBackupCipherPass(infoBackup), NULL, "cipher sub set");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoBackupCipherSpec(infoBackup)), cipherTypeAes256Cbc, "cipher sub set");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("cmdStanzaCreate missing files - multi-repo and encryption");
|
||||
|
||||
@@ -238,7 +238,8 @@ testRun(void)
|
||||
|
||||
InfoPg *infoPg = NULL;
|
||||
TEST_ASSIGN(
|
||||
infoPg, infoArchivePg(infoArchiveNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_ARCHIVE_INFO_BASE)))),
|
||||
infoPg,
|
||||
infoArchivePg(infoArchiveNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_ARCHIVE_INFO_BASE)), cipherSpecNewNone())),
|
||||
"infoPg from archive.info");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -268,7 +269,8 @@ testRun(void)
|
||||
harnessLogLevelSet(logLevelDetail);
|
||||
|
||||
backupResult.status = backupValid;
|
||||
TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_ASSIGN(
|
||||
manifest, verifyManifestFile(&backupResult, cipherSpecNewNone(), false, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg version mismatch");
|
||||
TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
|
||||
TEST_RESULT_LOG(
|
||||
@@ -303,7 +305,8 @@ testRun(void)
|
||||
.comment = "manifest copy - invalid system-id");
|
||||
|
||||
backupResult.status = backupValid;
|
||||
TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_ASSIGN(
|
||||
manifest, verifyManifestFile(&backupResult, cipherSpecNewNone(), false, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg system-id mismatch");
|
||||
TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
|
||||
TEST_RESULT_LOG(
|
||||
@@ -337,7 +340,8 @@ testRun(void)
|
||||
.comment = "manifest copy - invalid db-id");
|
||||
|
||||
backupResult.status = backupValid;
|
||||
TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_ASSIGN(
|
||||
manifest, verifyManifestFile(&backupResult, cipherSpecNewNone(), false, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg db-id mismatch");
|
||||
TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
|
||||
TEST_RESULT_LOG(
|
||||
@@ -355,7 +359,8 @@ testRun(void)
|
||||
storageRepoWrite(), TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/db/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE
|
||||
INFO_COPY_EXT, TEST_INVALID_BACKREST_INFO, .comment = "invalid manifest copy");
|
||||
|
||||
TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_ASSIGN(
|
||||
manifest, verifyManifestFile(&backupResult, cipherSpecNewNone(), false, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
|
||||
TEST_RESULT_LOG(
|
||||
"P00 DETAIL: unable to open missing file '" TEST_PATH "/repo/backup/db/20181119-152138F/backup.manifest' for read\n"
|
||||
@@ -369,7 +374,8 @@ testRun(void)
|
||||
storageRepoWrite(), TEST_PATH "/repo/" STORAGE_PATH_BACKUP "/db/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE,
|
||||
TEST_INVALID_BACKREST_INFO, .comment = "invalid manifest");
|
||||
|
||||
TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_ASSIGN(
|
||||
manifest, verifyManifestFile(&backupResult, cipherSpecNewNone(), true, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_RESULT_PTR(manifest, NULL, "manifest not set");
|
||||
TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
|
||||
TEST_RESULT_LOG(
|
||||
@@ -395,7 +401,8 @@ testRun(void)
|
||||
.comment = "valid manifest");
|
||||
|
||||
backupResult.status = backupValid;
|
||||
TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_ASSIGN(
|
||||
manifest, verifyManifestFile(&backupResult, cipherSpecNewNone(), true, infoPg, &jobErrorTotal), "verify manifest");
|
||||
TEST_RESULT_PTR_NE(manifest, NULL, "manifest set");
|
||||
TEST_RESULT_UINT(backupResult.status, backupValid, "manifest usable");
|
||||
TEST_RESULT_LOG("P00 DETAIL: backup '20181119-152138F' manifest.copy does not match manifest");
|
||||
@@ -485,7 +492,8 @@ testRun(void)
|
||||
// Create backup.info
|
||||
InfoBackup *backupInfo = NULL;
|
||||
TEST_ASSIGN(
|
||||
backupInfo, infoBackupNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_BACKUP_INFO_MULTI_HISTORY_BASE))),
|
||||
backupInfo,
|
||||
infoBackupNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_BACKUP_INFO_MULTI_HISTORY_BASE)), cipherSpecNewNone()),
|
||||
"backup.info multi-history");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -504,7 +512,7 @@ testRun(void)
|
||||
"db-version=\"11\"\n"
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}"))),
|
||||
"2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}")), cipherSpecNewNone()),
|
||||
"archive.info missing history");
|
||||
|
||||
TEST_ERROR(
|
||||
@@ -526,7 +534,7 @@ testRun(void)
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"1={\"db-id\":6625592122879095777,\"db-version\":\"9.6\"}\n"
|
||||
"2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}"))),
|
||||
"2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}")), cipherSpecNewNone()),
|
||||
"archive.info history system id mismatch");
|
||||
|
||||
TEST_ERROR(
|
||||
@@ -548,7 +556,7 @@ testRun(void)
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"1={\"db-id\":" HRN_PG_SYSTEMID_96_Z ",\"db-version\":\"18\"}\n"
|
||||
"2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}"))),
|
||||
"2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}")), cipherSpecNewNone()),
|
||||
"archive.info history version mismatch");
|
||||
|
||||
TEST_ERROR(
|
||||
@@ -570,7 +578,7 @@ testRun(void)
|
||||
"\n"
|
||||
"[db:history]\n"
|
||||
"3={\"db-id\":" HRN_PG_SYSTEMID_96_Z ",\"db-version\":\"10\"}\n"
|
||||
"2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}"))),
|
||||
"2={\"db-id\":" HRN_PG_SYSTEMID_11_Z ",\"db-version\":\"11\"}")), cipherSpecNewNone()),
|
||||
"archive.info history id mismatch");
|
||||
|
||||
TEST_ERROR(
|
||||
@@ -587,10 +595,12 @@ testRun(void)
|
||||
InfoBackup *backupInfo = NULL;
|
||||
InfoArchive *archiveInfo = NULL;
|
||||
TEST_ASSIGN(
|
||||
backupInfo, infoBackupNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_BACKUP_INFO_MULTI_HISTORY_BASE))),
|
||||
backupInfo,
|
||||
infoBackupNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_BACKUP_INFO_MULTI_HISTORY_BASE)), cipherSpecNewNone()),
|
||||
"backup.info multi-history");
|
||||
TEST_ASSIGN(
|
||||
archiveInfo, infoArchiveNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE))),
|
||||
archiveInfo,
|
||||
infoArchiveNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE)), cipherSpecNewNone()),
|
||||
"archive.info multi-history");
|
||||
InfoPg *pgHistory = infoArchivePg(archiveInfo);
|
||||
|
||||
@@ -867,17 +877,17 @@ testRun(void)
|
||||
HRN_CFG_LOAD(cfgCmdVerify, argList);
|
||||
|
||||
HRN_INFO_PUT(
|
||||
storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_NO_CURRENT_BACKUP, .cipherType = cipherTypeAes256Cbc,
|
||||
storageRepoWrite(), INFO_BACKUP_PATH_FILE, TEST_NO_CURRENT_BACKUP, .cipherSpec = TEST_CIPHER_SPEC,
|
||||
.comment = "encrypted backup.info");
|
||||
HRN_INFO_PUT(
|
||||
storageRepoWrite(), INFO_BACKUP_PATH_FILE INFO_COPY_EXT, TEST_NO_CURRENT_BACKUP,
|
||||
.cipherType = cipherTypeAes256Cbc, .comment = "encrypted backup.info.copy");
|
||||
.cipherSpec = TEST_CIPHER_SPEC, .comment = "encrypted backup.info.copy");
|
||||
HRN_INFO_PUT(
|
||||
storageRepoWrite(), INFO_ARCHIVE_PATH_FILE, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE,
|
||||
.cipherType = cipherTypeAes256Cbc, .comment = "encrypted archive.info");
|
||||
.cipherSpec = TEST_CIPHER_SPEC, .comment = "encrypted archive.info");
|
||||
HRN_INFO_PUT(
|
||||
storageRepoWrite(), INFO_ARCHIVE_PATH_FILE INFO_COPY_EXT, TEST_ARCHIVE_INFO_MULTI_HISTORY_BASE,
|
||||
.cipherType = cipherTypeAes256Cbc, .comment = "encrypted archive.info.copy");
|
||||
.cipherSpec = TEST_CIPHER_SPEC, .comment = "encrypted archive.info.copy");
|
||||
|
||||
TEST_RESULT_VOID(cmdVerify(), "usable encrypted backup and archive info files");
|
||||
TEST_RESULT_LOG("");
|
||||
@@ -899,20 +909,23 @@ testRun(void)
|
||||
String *filePathName = strNewZ(STORAGE_REPO_ARCHIVE "/testfile");
|
||||
HRN_STORAGE_PUT_EMPTY(storageRepoWrite(), strZ(filePathName));
|
||||
TEST_RESULT_UINT(
|
||||
verifyFile(filePathName, 0, NULL, compressTypeNone, HASH_TYPE_SHA1_ZERO_BUF, 0, NULL), verifyOk, "file ok");
|
||||
verifyFile(filePathName, 0, NULL, compressTypeNone, HASH_TYPE_SHA1_ZERO_BUF, 0, cipherSpecNewNone()),
|
||||
verifyOk, "file ok");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("file size invalid in archive");
|
||||
|
||||
HRN_STORAGE_PUT_Z(storageRepoWrite(), strZ(filePathName), fileContents);
|
||||
TEST_RESULT_UINT(
|
||||
verifyFile(filePathName, 0, NULL, compressTypeNone, fileChecksum, 0, NULL), verifySizeInvalid, "file size invalid");
|
||||
verifyFile(filePathName, 0, NULL, compressTypeNone, fileChecksum, 0, cipherSpecNewNone()),
|
||||
verifySizeInvalid, "file size invalid");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("file missing in archive");
|
||||
|
||||
TEST_RESULT_UINT(
|
||||
verifyFile(strNewFmt(STORAGE_REPO_ARCHIVE "/missingFile"), 0, NULL, compressTypeNone, fileChecksum, 0, NULL),
|
||||
verifyFile(
|
||||
strNewFmt(STORAGE_REPO_ARCHIVE "/missingFile"), 0, NULL, compressTypeNone, fileChecksum, 0, cipherSpecNewNone()),
|
||||
verifyFileMissing, "file missing");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -921,15 +934,19 @@ testRun(void)
|
||||
// Create a compressed encrypted repo file in backup
|
||||
filePathName = strCatZ(strNew(), STORAGE_REPO_BACKUP "/testfile");
|
||||
HRN_STORAGE_PUT_Z(
|
||||
storageRepoWrite(), strZ(filePathName), fileContents, .compressType = compressTypeGz, .cipherType = cipherTypeAes256Cbc,
|
||||
.cipherPass = "pass");
|
||||
storageRepoWrite(), strZ(filePathName), fileContents, .compressType = compressTypeGz,
|
||||
.cipherSpec = TEST_CIPHER_SPEC_PASS("pass"));
|
||||
|
||||
strCatZ(filePathName, ".gz");
|
||||
TEST_RESULT_UINT(
|
||||
verifyFile(filePathName, 0, NULL, compressTypeGz, fileChecksum, fileSize, STRDEF("pass")),
|
||||
verifyFile(
|
||||
filePathName, 0, NULL, compressTypeGz, fileChecksum, fileSize,
|
||||
cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("pass"))),
|
||||
verifyOk, "file encrypted compressed ok");
|
||||
TEST_RESULT_UINT(
|
||||
verifyFile(filePathName, 0, NULL, compressTypeGz, bufNewDecode(encodingHex, STRDEF("aa")), fileSize, STRDEF("pass")),
|
||||
verifyFile(
|
||||
filePathName, 0, NULL, compressTypeGz, bufNewDecode(encodingHex, STRDEF("aa")), fileSize,
|
||||
cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("pass"))),
|
||||
verifyChecksumMismatch, "file encrypted compressed checksum mismatch");
|
||||
}
|
||||
|
||||
@@ -2497,7 +2514,7 @@ testRun(void)
|
||||
HRN_CFG_LOAD(cfgCmdBackup, argList);
|
||||
|
||||
hrnBackupPqScriptP(
|
||||
PG_VERSION_11, BACKUP_EPOCH + 200000, .cipherType = cipherTypeAes256Cbc, .cipherPass = TEST_CIPHER_PASS);
|
||||
PG_VERSION_11, BACKUP_EPOCH + 200000, .cipherSpecMain = TEST_CIPHER_SPEC);
|
||||
TEST_RESULT_VOID(hrnCmdBackup(), "backup");
|
||||
TEST_RESULT_LOG(
|
||||
"P00 INFO: execute backup start: backup begins after the next regular checkpoint completes\n"
|
||||
|
||||
@@ -72,18 +72,43 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("CipherBlock"))
|
||||
{
|
||||
// Cipher and digest errors
|
||||
// Cipher error
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_ERROR(
|
||||
cipherBlockNewP(cipherModeEncrypt, cipherTypeNone, BUFSTRZ(TEST_PASS)), AssertError, "unable to load cipher 'none'");
|
||||
TEST_ERROR(
|
||||
cipherBlockNewP(cipherModeEncrypt, cipherTypeAes256Cbc, testPass, .digest = STRDEF(BOGUS_STR)), AssertError,
|
||||
"unable to load digest 'BOGUS'");
|
||||
cipherBlockNewP(cipherModeEncrypt, cipherSpecNew(strIdFromZ(BOGUS_STR), testPass)), AssertError,
|
||||
"unable to load cipher 'BOGUS'");
|
||||
|
||||
// Initialization of object
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
CipherBlock *cipherBlock = (CipherBlock *)ioFilterDriver(
|
||||
cipherBlockNewP(cipherModeEncrypt, cipherTypeAes256Cbc, BUFSTRZ(TEST_PASS)));
|
||||
// Build from a duplicate to show the copy carries the type and pass of the original
|
||||
TEST_RESULT_UINT(cipherSpecType(cipherSpecDup(cipherSpecNewNone())), cipherTypeNone, "dup of none");
|
||||
|
||||
const CipherSpec *const cipherSpec = cipherSpecDup(cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF(TEST_PASS)));
|
||||
|
||||
TEST_RESULT_UINT(cipherSpecType(cipherSpec), cipherTypeAes256Cbc, "dup type");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(cipherSpec)), TEST_PASS, "dup pass");
|
||||
|
||||
// A pack carries nothing but the type when there is no cipher
|
||||
PackWrite *packWrite = pckWriteNewP();
|
||||
|
||||
cipherSpecPack(packWrite, cipherSpecNewNone());
|
||||
pckWriteEndP(packWrite);
|
||||
|
||||
TEST_RESULT_UINT(
|
||||
cipherSpecType(cipherSpecNewPack(pckReadNew(pckWriteResult(packWrite)))), cipherTypeNone, "unpack none");
|
||||
|
||||
// Else it carries the type and pass
|
||||
packWrite = pckWriteNewP();
|
||||
|
||||
cipherSpecPack(packWrite, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
pckWriteEndP(packWrite);
|
||||
|
||||
const CipherSpec *const cipherSpecUnpack = cipherSpecNewPack(pckReadNew(pckWriteResult(packWrite)));
|
||||
|
||||
TEST_RESULT_UINT(cipherSpecType(cipherSpecUnpack), cipherTypeAes256Cbc, "unpack type");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(cipherSpecUnpack)), TEST_PASS, "unpack pass");
|
||||
|
||||
CipherBlock *cipherBlock = (CipherBlock *)ioFilterDriver(cipherBlockNewP(cipherModeEncrypt, cipherSpec));
|
||||
TEST_RESULT_INT(cipherBlock->mode, cipherModeEncrypt, "mode is valid");
|
||||
TEST_RESULT_UINT(bufSize(cipherBlock->pass), strlen(TEST_PASS), "passphrase size is valid");
|
||||
TEST_RESULT_BOOL(memcmp(bufPtrConst(cipherBlock->pass), TEST_PASS, strlen(TEST_PASS)) == 0, true, "passphrase is valid");
|
||||
@@ -98,7 +123,7 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
Buffer *encryptBuffer = bufNew(TEST_BUFFER_SIZE);
|
||||
|
||||
IoFilter *blockEncryptFilter = cipherBlockNewP(cipherModeEncrypt, cipherTypeAes256Cbc, testPass);
|
||||
IoFilter *blockEncryptFilter = cipherBlockNewP(cipherModeEncrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
blockEncryptFilter = cipherBlockNewPack(ioFilterParamList(blockEncryptFilter));
|
||||
CipherBlock *blockEncrypt = (CipherBlock *)ioFilterDriver(blockEncryptFilter);
|
||||
|
||||
@@ -149,7 +174,7 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
Buffer *decryptBuffer = bufNew(TEST_BUFFER_SIZE);
|
||||
|
||||
IoFilter *blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, testPass, .digest = STRDEF("sha1"));
|
||||
IoFilter *blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
blockDecryptFilter = cipherBlockNewPack(ioFilterParamList(blockDecryptFilter));
|
||||
CipherBlock *blockDecrypt = (CipherBlock *)ioFilterDriver(blockDecryptFilter);
|
||||
|
||||
@@ -169,7 +194,7 @@ testRun(void)
|
||||
|
||||
// Decrypt in small chunks to test buffering
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, testPass);
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
blockDecrypt = (CipherBlock *)ioFilterDriver(blockDecryptFilter);
|
||||
|
||||
bufUsedZero(decryptBuffer);
|
||||
@@ -210,7 +235,7 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("encrypt zero byte file with no magic");
|
||||
|
||||
blockEncryptFilter = cipherBlockNewP(cipherModeEncrypt, cipherTypeAes256Cbc, testPass, .raw = true);
|
||||
blockEncryptFilter = cipherBlockNewP(cipherModeEncrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass), .raw = true);
|
||||
blockEncrypt = (CipherBlock *)ioFilterDriver(blockEncryptFilter);
|
||||
|
||||
bufUsedZero(encryptBuffer);
|
||||
@@ -223,13 +248,13 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("error on decrypt expecting magic");
|
||||
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, testPass);
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
TEST_ERROR(ioFilterProcessInOut(blockDecryptFilter, encryptBuffer, decryptBuffer), CryptoError, "cipher header invalid");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("decrypt zero byte file with no magic");
|
||||
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, testPass, .raw = true);
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass), .raw = true);
|
||||
blockDecrypt = (CipherBlock *)ioFilterDriver(blockDecryptFilter);
|
||||
|
||||
bufUsedZero(decryptBuffer);
|
||||
@@ -243,7 +268,7 @@ testRun(void)
|
||||
|
||||
// Invalid cipher header
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, testPass);
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
blockDecrypt = (CipherBlock *)ioFilterDriver(blockDecryptFilter);
|
||||
|
||||
TEST_ERROR(
|
||||
@@ -254,7 +279,7 @@ testRun(void)
|
||||
|
||||
// Invalid encrypted data cannot be flushed
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, testPass);
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
blockDecrypt = (CipherBlock *)ioFilterDriver(blockDecryptFilter);
|
||||
|
||||
bufUsedZero(decryptBuffer);
|
||||
@@ -268,7 +293,7 @@ testRun(void)
|
||||
|
||||
// File with no header should not flush
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, testPass);
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
blockDecrypt = (CipherBlock *)ioFilterDriver(blockDecryptFilter);
|
||||
|
||||
bufUsedZero(decryptBuffer);
|
||||
@@ -279,7 +304,7 @@ testRun(void)
|
||||
|
||||
// File with header only should error
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, testPass);
|
||||
blockDecryptFilter = cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, testPass));
|
||||
blockDecrypt = (CipherBlock *)ioFilterDriver(blockDecryptFilter);
|
||||
|
||||
bufUsedZero(decryptBuffer);
|
||||
@@ -294,11 +319,13 @@ testRun(void)
|
||||
IoFilterGroup *filterGroup = ioFilterGroupNew();
|
||||
|
||||
TEST_RESULT_PTR(
|
||||
cipherBlockFilterGroupAdd(filterGroup, cipherTypeNone, cipherModeEncrypt, NULL), filterGroup, " no filter add");
|
||||
cipherBlockFilterGroupAdd(
|
||||
filterGroup, cipherModeEncrypt, cipherSpecNewNone()), filterGroup, " no filter add");
|
||||
TEST_RESULT_UINT(ioFilterGroupSize(filterGroup), 0, " check no filter add");
|
||||
|
||||
TEST_RESULT_VOID(
|
||||
cipherBlockFilterGroupAdd(filterGroup, cipherTypeAes256Cbc, cipherModeEncrypt, STRDEF("X")), " filter add");
|
||||
cipherBlockFilterGroupAdd(
|
||||
filterGroup, cipherModeEncrypt, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("X"))), " filter add");
|
||||
TEST_RESULT_UINT(ioFilterGroupSize(filterGroup), 1, " check filter add");
|
||||
}
|
||||
|
||||
|
||||
@@ -936,6 +936,10 @@ testRun(void)
|
||||
hrnCfgArgRawZ(argList, cfgOptStanza, "db");
|
||||
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path");
|
||||
hrnCfgArgRawZ(argList, cfgOptRepoRetentionFull, "1");
|
||||
hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 1, TEST_PATH "/repo1");
|
||||
hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 2, TEST_PATH "/repo2");
|
||||
hrnCfgArgKeyRawStrId(argList, cfgOptRepoCipherType, 2, cipherTypeAes256Cbc);
|
||||
hrnCfgEnvKeyRawZ(cfgOptRepoCipherPass, 2, "passphrase");
|
||||
hrnCfgArgRawZ(argList, cfgOptLockPath, HRN_PATH "/lock");
|
||||
hrnCfgArgRawZ(argList, cfgOptLogPath, TEST_PATH);
|
||||
hrnCfgArgRawZ(argList, cfgOptLogLevelConsole, "off");
|
||||
@@ -958,6 +962,16 @@ testRun(void)
|
||||
TEST_RESULT_INT(socketLocal.tcpKeepAliveInterval, 888, "check socketLocal.tcpKeepAliveInterval");
|
||||
TEST_RESULT_INT(getpriority(PRIO_PROCESS, (id_t)getpid()), 19, "check priority");
|
||||
|
||||
hrnCfgEnvKeyRemoveRaw(cfgOptRepoCipherPass, 2);
|
||||
|
||||
// Cipher spec is cached per repo since each repo has its own cipher type and passphrase
|
||||
TEST_RESULT_UINT(cipherSpecType(cfgCipherSpecMainIdx(0)), cipherTypeNone, "repo1 cipher spec");
|
||||
|
||||
const CipherSpec *const cipherSpecMain = cfgCipherSpecMainIdx(1);
|
||||
|
||||
TEST_RESULT_UINT(cipherSpecType(cipherSpecMain), cipherTypeAes256Cbc, "repo2 cipher spec");
|
||||
TEST_RESULT_PTR(cfgCipherSpecMainIdx(1), cipherSpecMain, "repo2 cipher spec is cached");
|
||||
|
||||
cmdLockReleaseP();
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1781,6 +1781,8 @@ testRun(void)
|
||||
hrnCfgArgKeyRawZ(argList, cfgOptRepoS3Bucket, 1, " test ");
|
||||
hrnCfgArgKeyRawZ(argList, cfgOptRepoS3Endpoint, 1, "test");
|
||||
hrnCfgArgKeyRawZ(argList, cfgOptRepoS3Region, 1, "test");
|
||||
hrnCfgArgKeyRawStrId(argList, cfgOptRepoCipherType, 1, cipherTypeAes256Cbc);
|
||||
hrnCfgEnvKeyRawZ(cfgOptRepoCipherPass, 1, "xxx-cipher");
|
||||
strLstAddZ(argList, TEST_COMMAND_BACKUP);
|
||||
hrnCfgEnvKeyRawZ(cfgOptRepoS3Key, 1, "xxx");
|
||||
hrnCfgEnvKeyRawZ(cfgOptRepoS3KeySecret, 1, "xxx");
|
||||
@@ -1820,8 +1822,16 @@ testRun(void)
|
||||
TEST_RESULT_INT(cfgOptionSource(cfgOptBufferSize), cfgSourceDefault, "buffer-size is source default");
|
||||
TEST_RESULT_Z(cfgOptionName(cfgOptBufferSize), "buffer-size", "buffer-size name");
|
||||
|
||||
// Cipher spec is built once per repo and then cached
|
||||
const CipherSpec *const cipherSpecMain = cfgCipherSpecMain();
|
||||
|
||||
TEST_RESULT_UINT(cipherSpecType(cipherSpecMain), cipherTypeAes256Cbc, "repo1 cipher spec type");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(cipherSpecMain)), "xxx-cipher", "repo1 cipher spec pass");
|
||||
TEST_RESULT_PTR(cfgCipherSpecMainIdx(0), cipherSpecMain, "repo1 cipher spec is cached");
|
||||
|
||||
hrnCfgEnvKeyRemoveRaw(cfgOptRepoS3Key, 1);
|
||||
hrnCfgEnvKeyRemoveRaw(cfgOptRepoS3KeySecret, 1);
|
||||
hrnCfgEnvKeyRemoveRaw(cfgOptRepoCipherPass, 1);
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("global is a valid stanza prefix");
|
||||
@@ -1841,6 +1851,7 @@ testRun(void)
|
||||
TEST_RESULT_VOID(cfgParseP(storageTest, strLstSize(argList), strLstPtr(argList), .noResetLogLevel = true), "parse config");
|
||||
|
||||
TEST_RESULT_STR_Z(cfgOptionStr(cfgOptPgPath), "/path/to/global/stanza", "default pg-path");
|
||||
TEST_RESULT_UINT(cipherSpecType(cfgCipherSpecMainIdx(0)), cipherTypeNone, "no cipher spec when repo is not encrypted");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("warnings for environment variables, command-line and config file options");
|
||||
|
||||
@@ -38,14 +38,14 @@ testRun(void)
|
||||
// Load and test move function
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
TEST_ASSIGN(info, infoArchiveNewLoad(ioBufferReadNew(contentLoad)), "load new archive info");
|
||||
TEST_ASSIGN(info, infoArchiveNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone()), "load new archive info");
|
||||
TEST_RESULT_VOID(infoArchiveMove(info, memContextPrior()), "move info");
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
TEST_RESULT_STR_Z(infoArchiveId(info), "9.6-1", "archiveId set");
|
||||
TEST_RESULT_PTR(infoArchivePg(info), info->pub.infoPg, "infoPg set");
|
||||
TEST_RESULT_STR(infoArchiveCipherPass(info), NULL, "no cipher sub");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoArchiveCipherSpec(info)), cipherTypeNone, "no cipher sub");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("infoArchive save (in memory)");
|
||||
@@ -64,7 +64,7 @@ testRun(void)
|
||||
info, infoArchiveNew(PG_VERSION_96, 6569239123849665679, NULL), "infoArchiveNew() - no sub cipher");
|
||||
TEST_RESULT_STR_Z(infoArchiveId(info), "9.6-1", "archiveId set");
|
||||
TEST_RESULT_PTR(infoArchivePg(info), info->pub.infoPg, "infoPg set");
|
||||
TEST_RESULT_STR(infoArchiveCipherPass(info), NULL, "no cipher sub");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoArchiveCipherSpec(info)), cipherTypeNone, "no cipher sub");
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoArchivePg(info)), 1, "history set");
|
||||
|
||||
Buffer *contentCompare = bufNew(0);
|
||||
@@ -79,18 +79,22 @@ testRun(void)
|
||||
TEST_ASSIGN(
|
||||
info,
|
||||
infoArchiveNew(
|
||||
PG_VERSION_10, 6569239123849665999, STRDEF("zWa/6Xtp-IVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO")),
|
||||
PG_VERSION_10, 6569239123849665999,
|
||||
cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("zWa/6Xtp-IVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO"))),
|
||||
"infoArchiveNew() - cipher sub");
|
||||
|
||||
contentSave = bufNew(0);
|
||||
|
||||
TEST_RESULT_VOID(infoArchiveSave(info, ioBufferWriteNew(contentSave)), "save new with cipher");
|
||||
|
||||
TEST_ASSIGN(info, infoArchiveNewLoad(ioBufferReadNew(contentSave)), "load encrypted archive info");
|
||||
TEST_ASSIGN(
|
||||
info, infoArchiveNewLoad(ioBufferReadNew(contentSave), cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("x"))),
|
||||
"load encrypted archive info");
|
||||
TEST_RESULT_STR_Z(infoArchiveId(info), "10-1", "archiveId set");
|
||||
TEST_RESULT_PTR(infoArchivePg(info), infoArchivePg(info), "infoPg set");
|
||||
TEST_RESULT_STR_Z(
|
||||
infoArchiveCipherPass(info), "zWa/6Xtp-IVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO", "cipher sub set");
|
||||
strNewBuf(cipherSpecPass(infoArchiveCipherSpec(info))),
|
||||
"zWa/6Xtp-IVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO", "cipher sub set");
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoArchivePg(info)), 1, "history set");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -121,7 +125,7 @@ testRun(void)
|
||||
"1={\"db-id\":6625592122879095702,\"db-version\":\"9.6\"}\n"
|
||||
"2={\"db-id\":6626363367545678089,\"db-version\":\"17\"}\n");
|
||||
|
||||
TEST_ASSIGN(info, infoArchiveNewLoad(ioBufferReadNew(contentLoad)), "new archive info");
|
||||
TEST_ASSIGN(info, infoArchiveNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone()), "new archive info");
|
||||
TEST_RESULT_STR_Z(infoArchiveIdHistoryMatch(info, 2, 170000, 6626363367545678089), "17-2", "full match found");
|
||||
|
||||
TEST_RESULT_STR_Z(infoArchiveIdHistoryMatch(info, 2, 90600, 6625592122879095702), "9.6-1", "partial match found");
|
||||
@@ -142,7 +146,7 @@ testRun(void)
|
||||
TEST_TITLE("load archive info file - error");
|
||||
|
||||
TEST_ERROR(
|
||||
infoArchiveLoadFile(storageTest, STRDEF(INFO_ARCHIVE_FILE), cipherTypeNone, NULL), FileMissingError,
|
||||
infoArchiveLoadFile(storageTest, STRDEF(INFO_ARCHIVE_FILE), cipherSpecNewNone()), FileMissingError,
|
||||
"unable to load info file '" TEST_PATH "/archive.info' or '" TEST_PATH "/archive.info.copy':\n"
|
||||
"FileMissingError: unable to open missing file '" TEST_PATH "/archive.info' for read\n"
|
||||
"FileMissingError: unable to open missing file '" TEST_PATH "/archive.info.copy' for read\n"
|
||||
@@ -156,13 +160,18 @@ testRun(void)
|
||||
|
||||
InfoArchive *infoArchive = infoArchiveNew(PG_VERSION_10, 6569239123849665999, NULL);
|
||||
TEST_RESULT_VOID(
|
||||
infoArchiveSaveFile(infoArchive, storageTest, STRDEF(INFO_ARCHIVE_FILE), cipherTypeNone, NULL), "save archive info");
|
||||
infoArchiveSaveFile(infoArchive, storageTest, STRDEF(INFO_ARCHIVE_FILE), cipherSpecNewNone()),
|
||||
"save archive info");
|
||||
|
||||
TEST_ASSIGN(infoArchive, infoArchiveLoadFile(storageTest, STRDEF(INFO_ARCHIVE_FILE), cipherTypeNone, NULL), "load main");
|
||||
TEST_ASSIGN(
|
||||
infoArchive, infoArchiveLoadFile(storageTest, STRDEF(INFO_ARCHIVE_FILE), cipherSpecNewNone()),
|
||||
"load main");
|
||||
TEST_RESULT_UINT(infoPgDataCurrent(infoArchivePg(infoArchive)).systemId, 6569239123849665999, "check file loaded");
|
||||
|
||||
HRN_STORAGE_REMOVE(storageTest, INFO_ARCHIVE_FILE, .errorOnMissing = true, .comment = "remove main so only copy exists");
|
||||
TEST_ASSIGN(infoArchive, infoArchiveLoadFile(storageTest, STRDEF(INFO_ARCHIVE_FILE), cipherTypeNone, NULL), "load copy");
|
||||
TEST_ASSIGN(
|
||||
infoArchive, infoArchiveLoadFile(storageTest, STRDEF(INFO_ARCHIVE_FILE), cipherSpecNewNone()),
|
||||
"load copy");
|
||||
TEST_RESULT_UINT(infoPgDataCurrent(infoArchivePg(infoArchive)).systemId, 6569239123849665999, "check file loaded");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ testRun(void)
|
||||
// Load and test move function then make sure ignore-section is ignored
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentLoad)), "new backup info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone()), "new backup info");
|
||||
TEST_RESULT_VOID(infoBackupMove(infoBackup, memContextPrior()), "move info");
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
@@ -68,9 +68,9 @@ testRun(void)
|
||||
TEST_RESULT_VOID(infoBackupSave(infoBackup, ioBufferWriteNew(contentCompare)), "save backup info from new");
|
||||
TEST_RESULT_STR(strNewBuf(contentCompare), strNewBuf(contentSave), "check save");
|
||||
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentCompare)), "load backup info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentCompare), cipherSpecNewNone()), "load backup info");
|
||||
TEST_RESULT_PTR(infoBackupPg(infoBackup), infoBackup->pub.infoPg, "infoPg set");
|
||||
TEST_RESULT_STR(infoBackupCipherPass(infoBackup), NULL, "cipher sub not set");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoBackupCipherSpec(infoBackup)), cipherTypeNone, "cipher sub not set");
|
||||
TEST_RESULT_INT(infoBackupDataTotal(infoBackup), 0, "infoBackupDataTotal returns 0");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -80,7 +80,7 @@ testRun(void)
|
||||
infoBackup,
|
||||
infoBackupNew(
|
||||
PG_VERSION_10, 6569239123849665999, hrnPgCatalogVersion(PG_VERSION_10),
|
||||
STRDEF("zWa/6Xtp-IVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO")),
|
||||
cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("zWa/6Xtp-IVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO"))),
|
||||
"infoBackupNew() - cipher sub");
|
||||
|
||||
contentSave = bufNew(0);
|
||||
@@ -88,10 +88,13 @@ testRun(void)
|
||||
TEST_RESULT_VOID(infoBackupSave(infoBackup, ioBufferWriteNew(contentSave)), "save new with cipher sub");
|
||||
|
||||
infoBackup = NULL;
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentSave)), "load backup info with cipher sub");
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupNewLoad(ioBufferReadNew(contentSave), cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("x"))),
|
||||
"load backup info with cipher sub");
|
||||
TEST_RESULT_PTR(infoBackupPg(infoBackup), infoBackupPg(infoBackup), "infoPg set");
|
||||
TEST_RESULT_STR_Z(
|
||||
infoBackupCipherPass(infoBackup), "zWa/6Xtp-IVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO", "cipher sub set");
|
||||
strNewBuf(cipherSpecPass(infoBackupCipherSpec(infoBackup))),
|
||||
"zWa/6Xtp-IVZC5444yXB+cgFDFl7MxGlgkZSaoPvTGirhPygu4jOKOXf9LO4vjfO", "cipher sub set");
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoBackupPg(infoBackup)), 1, "history set");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -154,7 +157,7 @@ testRun(void)
|
||||
"1={\"db-catalog-version\":201608131,\"db-control-version\":960,\"db-system-id\":6569239123849665679"
|
||||
",\"db-version\":\"9.6\"}\n");
|
||||
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentLoad)), "new backup info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone()), "new backup info");
|
||||
|
||||
TEST_RESULT_INT(infoBackupDataTotal(infoBackup), 3, "backup list contains backups");
|
||||
|
||||
@@ -312,9 +315,6 @@ testRun(void)
|
||||
"[backup:target]\n"
|
||||
"pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n"
|
||||
"\n"
|
||||
"[cipher]\n"
|
||||
"cipher-pass=\"somepass\"\n"
|
||||
"\n"
|
||||
"[target:file]\n"
|
||||
"pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"size\":4,\"timestamp\":1565282114}\n"
|
||||
"pg_data/postgresql.conf={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"repo-size\":24,\"size\":7,"
|
||||
@@ -325,7 +325,7 @@ testRun(void)
|
||||
"pg_data={}\n"
|
||||
TEST_MANIFEST_PATH_DEFAULT);
|
||||
|
||||
TEST_ASSIGN(manifest, manifestNewLoad(ioBufferReadNew(manifestContent)), "load manifest");
|
||||
TEST_ASSIGN(manifest, manifestNewLoad(ioBufferReadNew(manifestContent), cipherSpecNewNone()), "load manifest");
|
||||
TEST_RESULT_VOID(infoBackupDataAdd(infoBackup, manifest), "add a backup");
|
||||
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 1, "backup added to current");
|
||||
TEST_ASSIGN(backupData, infoBackupData(infoBackup, 0), "get added backup");
|
||||
@@ -433,7 +433,9 @@ testRun(void)
|
||||
"pg_data/base/65536={\"user\":false}\n" \
|
||||
TEST_MANIFEST_PATH_DEFAULT
|
||||
|
||||
TEST_ASSIGN(manifest, manifestNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_MANIFEST_INCR))), "load manifest");
|
||||
TEST_ASSIGN(
|
||||
manifest, manifestNewLoad(ioBufferReadNew(harnessInfoChecksumZ(TEST_MANIFEST_INCR)), cipherSpecNewNone()),
|
||||
"load manifest");
|
||||
TEST_RESULT_VOID(infoBackupDataAdd(infoBackup, manifest), "add a backup");
|
||||
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 2, "backup added to current");
|
||||
TEST_ASSIGN(backupData, infoBackupData(infoBackup, 1), "get added backup");
|
||||
@@ -568,9 +570,6 @@ testRun(void)
|
||||
"[backup:target]\n"
|
||||
"pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n"
|
||||
"\n"
|
||||
"[cipher]\n"
|
||||
"cipher-pass=\"somepass\"\n"
|
||||
"\n"
|
||||
"[target:file]\n"
|
||||
"pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"size\":4,\"timestamp\":1565282114}\n"
|
||||
"pg_data/postgresql.conf={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"repo-size\":24,\"size\":7,"
|
||||
@@ -608,9 +607,6 @@ testRun(void)
|
||||
"[backup:target]\n"
|
||||
"pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n"
|
||||
"\n"
|
||||
"[cipher]\n"
|
||||
"cipher-pass=\"somepass\"\n"
|
||||
"\n"
|
||||
"[target:file]\n"
|
||||
"pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"size\":4,\"timestamp\":1565282114}\n"
|
||||
TEST_MANIFEST_FILE_DEFAULT
|
||||
@@ -646,9 +642,6 @@ testRun(void)
|
||||
"[backup:target]\n"
|
||||
"pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n"
|
||||
"\n"
|
||||
"[cipher]\n"
|
||||
"cipher-pass=\"somepass\"\n"
|
||||
"\n"
|
||||
"[target:file]\n"
|
||||
"pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"size\":4,\"timestamp\":1565282114}\n"
|
||||
TEST_MANIFEST_FILE_DEFAULT
|
||||
@@ -684,9 +677,6 @@ testRun(void)
|
||||
"[backup:target]\n"
|
||||
"pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n"
|
||||
"\n"
|
||||
"[cipher]\n"
|
||||
"cipher-pass=\"somepass\"\n"
|
||||
"\n"
|
||||
"[target:file]\n"
|
||||
"pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"size\":4,\"timestamp\":1565282114}\n"
|
||||
TEST_MANIFEST_FILE_DEFAULT
|
||||
@@ -722,7 +712,7 @@ testRun(void)
|
||||
"upgrade db");
|
||||
TEST_RESULT_BOOL(infoBackup->pub.updated, true, "info updated");
|
||||
TEST_RESULT_VOID(
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"save backup info");
|
||||
TEST_RESULT_BOOL(infoBackup->pub.updated, false, "info not updated");
|
||||
|
||||
@@ -731,7 +721,7 @@ testRun(void)
|
||||
HRN_STORAGE_TIME(storageRepo(), INFO_BACKUP_PATH_FILE, timeBeforeSave);
|
||||
|
||||
TEST_RESULT_VOID(
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"save backup again");
|
||||
|
||||
// Check that timestamp was not updated
|
||||
@@ -741,13 +731,14 @@ testRun(void)
|
||||
// Reload infoBackup to be sure it was updated
|
||||
infoBackup = NULL;
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup, infoBackupLoadFile(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"get saved backup info");
|
||||
TEST_RESULT_INT(infoBackupDataTotal(infoBackup), 2, "backup list contains backups to be removed");
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoBackupPg(infoBackup)), 2, "multiple DB history");
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFileReconstruct(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup,
|
||||
infoBackupLoadFileReconstruct(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"reconstruct");
|
||||
TEST_RESULT_INT(infoBackupDataTotal(infoBackup), 1, "backup list contains 1 backup");
|
||||
TEST_ASSIGN(backupData, infoBackupData(infoBackup, 0), "get the backup");
|
||||
@@ -769,7 +760,8 @@ testRun(void)
|
||||
storageRepoWrite(), STORAGE_REPO_BACKUP "/20190818-084502F_20190820-084502I", .recurse = true,
|
||||
.comment = "remove dependent backup from disk");
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFileReconstruct(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup,
|
||||
infoBackupLoadFileReconstruct(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"reconstruct does not attempt to add back dependent backup");
|
||||
TEST_RESULT_LOG(
|
||||
"P00 WARN: backup '20190818-084502F_20190820-084502I' missing manifest removed from backup.info\n"
|
||||
@@ -869,12 +861,13 @@ testRun(void)
|
||||
.comment = "write manifest for backup in a set that is in backup.info but whose prior backup is not");
|
||||
|
||||
TEST_RESULT_VOID(
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackupSaveFile(infoBackup, storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"save updated backup info");
|
||||
|
||||
infoBackup = NULL;
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFileReconstruct(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherTypeNone, NULL),
|
||||
infoBackup,
|
||||
infoBackupLoadFileReconstruct(storageRepo(), INFO_BACKUP_PATH_FILE_STR, cipherSpecNewNone()),
|
||||
"reconstruct");
|
||||
TEST_RESULT_STRLST_Z(
|
||||
infoBackupDataLabelList(infoBackup, NULL),
|
||||
@@ -896,7 +889,7 @@ testRun(void)
|
||||
TEST_TITLE("load backup info file - error");
|
||||
|
||||
TEST_ERROR(
|
||||
infoBackupLoadFile(storageTest, STRDEF(INFO_BACKUP_FILE), cipherTypeNone, NULL), FileMissingError,
|
||||
infoBackupLoadFile(storageTest, STRDEF(INFO_BACKUP_FILE), cipherSpecNewNone()), FileMissingError,
|
||||
"unable to load info file '" TEST_PATH "/backup.info' or '" TEST_PATH "/backup.info.copy':\n"
|
||||
"FileMissingError: unable to open missing file '" TEST_PATH "/backup.info' for read\n"
|
||||
"FileMissingError: unable to open missing file '" TEST_PATH "/backup.info.copy' for read\n"
|
||||
@@ -908,13 +901,18 @@ testRun(void)
|
||||
|
||||
InfoBackup *infoBackup = infoBackupNew(PG_VERSION_10, 6569239123849665999, hrnPgCatalogVersion(PG_VERSION_10), NULL);
|
||||
TEST_RESULT_VOID(
|
||||
infoBackupSaveFile(infoBackup, storageTest, STRDEF(INFO_BACKUP_FILE), cipherTypeNone, NULL), "save backup info");
|
||||
infoBackupSaveFile(
|
||||
infoBackup, storageTest, STRDEF(INFO_BACKUP_FILE), cipherSpecNewNone()), "save backup info");
|
||||
|
||||
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, STRDEF(INFO_BACKUP_FILE), cipherTypeNone, NULL), "load main");
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageTest, STRDEF(INFO_BACKUP_FILE), cipherSpecNewNone()),
|
||||
"load main");
|
||||
TEST_RESULT_UINT(infoPgDataCurrent(infoBackupPg(infoBackup)).systemId, 6569239123849665999, "check file loaded");
|
||||
|
||||
HRN_STORAGE_REMOVE(storageTest, INFO_BACKUP_FILE, .errorOnMissing = true, .comment = "remove main so only copy exists");
|
||||
TEST_ASSIGN(infoBackup, infoBackupLoadFile(storageTest, STRDEF(INFO_BACKUP_FILE), cipherTypeNone, NULL), "load copy");
|
||||
TEST_ASSIGN(
|
||||
infoBackup, infoBackupLoadFile(storageTest, STRDEF(INFO_BACKUP_FILE), cipherSpecNewNone()),
|
||||
"load copy");
|
||||
TEST_RESULT_UINT(infoPgDataCurrent(infoBackupPg(infoBackup)).systemId, 6569239123849665999, "check file loaded");
|
||||
}
|
||||
|
||||
@@ -998,7 +996,7 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("check dependency lists");
|
||||
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentLoad)), "new backup info");
|
||||
TEST_ASSIGN(infoBackup, infoBackupNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone()), "new backup info");
|
||||
|
||||
TEST_ASSIGN(dependencyList, infoBackupDataDependentList(infoBackup, STRDEF("20200317-181625F")), "full");
|
||||
TEST_RESULT_STRLST_Z(
|
||||
|
||||
@@ -38,12 +38,14 @@ testRun(void)
|
||||
|
||||
TEST_ASSIGN(infoPg, infoPgNew(infoPgBackup, NULL), "infoPgNew(cipherTypeNone, NULL)");
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoPg), 0, " 0 history");
|
||||
TEST_RESULT_STR(infoCipherPass(infoPgInfo(infoPg)), NULL, " cipherPass NULL");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoCipherSpec(infoPgInfo(infoPg))), cipherTypeNone, " cipher spec none");
|
||||
TEST_RESULT_INT(infoPgDataCurrentId(infoPg), 0, " 0 historyCurrent");
|
||||
|
||||
TEST_ASSIGN(infoPg, infoPgNew(infoPgArchive, STRDEF("123xyz")), "infoPgNew(cipherTypeAes256Cbc, 123xyz)");
|
||||
TEST_ASSIGN(
|
||||
infoPg, infoPgNew(infoPgArchive, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("123xyz"))),
|
||||
"infoPgNew(cipherTypeAes256Cbc, 123xyz)");
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoPg), 0, " 0 history");
|
||||
TEST_RESULT_STR_Z(infoCipherPass(infoPgInfo(infoPg)), "123xyz", " cipherPass set");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(infoCipherSpec(infoPgInfo(infoPg)))), "123xyz", " cipherPass set");
|
||||
TEST_RESULT_INT(infoPgDataCurrentId(infoPg), 0, " 0 historyCurrent");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -71,13 +73,14 @@ testRun(void)
|
||||
TEST_RESULT_UINT(pgData.systemId, 6569239123849665999, " system-id updated");
|
||||
TEST_RESULT_UINT(pgData.version, PG_VERSION_18, " version updated");
|
||||
TEST_RESULT_UINT(pgData.catalogVersion, 0, " catalog version not set for archive");
|
||||
TEST_RESULT_STR(infoCipherPass(infoPgInfo(infoPg)), NULL, " cipherPass not set");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoCipherSpec(infoPgInfo(infoPg))), cipherTypeNone, " cipher spec none");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_ASSIGN(
|
||||
infoPg,
|
||||
infoPgSet(
|
||||
infoPgNew(infoPgBackup, STRDEF("123xyz")), infoPgBackup, PG_VERSION_18, 6569239123849665679,
|
||||
infoPgNew(infoPgBackup, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("123xyz"))), infoPgBackup,
|
||||
PG_VERSION_18, 6569239123849665679,
|
||||
hrnPgCatalogVersion(PG_VERSION_18)),
|
||||
"infoPgSet - infoPgBackup");
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoPg), 1, " 1 history");
|
||||
@@ -87,7 +90,7 @@ testRun(void)
|
||||
TEST_RESULT_UINT(pgData.systemId, 6569239123849665679, " system-id set");
|
||||
TEST_RESULT_UINT(pgData.version, PG_VERSION_18, " version set");
|
||||
TEST_RESULT_UINT(pgData.catalogVersion, 202506291, " catalog version updated");
|
||||
TEST_RESULT_STR_Z(infoCipherPass(infoPgInfo(infoPg)), "123xyz", " cipherPass set");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(infoCipherSpec(infoPgInfo(infoPg)))), "123xyz", " cipherPass set");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
@@ -117,7 +120,9 @@ testRun(void)
|
||||
InfoPg *infoPg = NULL;
|
||||
|
||||
TEST_ASSIGN(
|
||||
infoPg, infoPgNewLoad(ioBufferReadNew(contentLoad), infoPgArchive, harnessInfoLoadNewCallback, callbackContent),
|
||||
infoPg,
|
||||
infoPgNewLoad(
|
||||
ioBufferReadNew(contentLoad), infoPgArchive, cipherSpecNewNone(), harnessInfoLoadNewCallback, callbackContent),
|
||||
"load file");
|
||||
TEST_RESULT_STR_Z(
|
||||
callbackContent,
|
||||
@@ -133,7 +138,7 @@ testRun(void)
|
||||
TEST_RESULT_UINT(pgData.systemId, 6569239123849665679, " system-id set");
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoPg), 1, " check pg data total");
|
||||
TEST_RESULT_STR_Z(infoPgArchiveId(infoPg, 0), "18-1", " check pg archive id");
|
||||
TEST_RESULT_STR(infoPgCipherPass(infoPg), NULL, " no cipher passphrase");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoPgCipherSpec(infoPg)), cipherTypeNone, " no cipher passphrase");
|
||||
|
||||
Buffer *contentSave = bufNew(0);
|
||||
|
||||
@@ -167,7 +172,8 @@ testRun(void)
|
||||
|
||||
callbackContent = strNew();
|
||||
|
||||
TEST_ASSIGN(infoPg, infoPgNewLoad(ioBufferReadNew(contentLoad), infoPgBackup, NULL, NULL), "load file");
|
||||
TEST_ASSIGN(
|
||||
infoPg, infoPgNewLoad(ioBufferReadNew(contentLoad), infoPgBackup, cipherSpecNewNone(), NULL, NULL), "load file");
|
||||
TEST_RESULT_STR_Z(callbackContent, "", " check callback content");
|
||||
|
||||
TEST_RESULT_INT(infoPgDataTotal(infoPg), 2, " check pg data total");
|
||||
|
||||
@@ -78,11 +78,11 @@ testRun(void)
|
||||
{
|
||||
Info *info = NULL;
|
||||
|
||||
TEST_ASSIGN(info, infoNew(STRDEF("123xyz")), "infoNew(cipher)");
|
||||
TEST_RESULT_STR_Z(infoCipherPass(info), "123xyz", " cipherPass is set");
|
||||
TEST_ASSIGN(info, infoNew(cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("123xyz"))), "infoNew(cipher)");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(infoCipherSpec(info))), "123xyz", " cipherPass is set");
|
||||
|
||||
TEST_ASSIGN(info, infoNew(NULL), "infoNew(NULL)");
|
||||
TEST_RESULT_STR(infoCipherPass(info), NULL, " cipherPass is NULL");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoCipherSpec(info)), cipherTypeNone, " cipher spec is none");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
@@ -97,8 +97,8 @@ testRun(void)
|
||||
String *callbackContent = strNew();
|
||||
|
||||
TEST_ERROR(
|
||||
infoNewLoad(ioBufferReadNew(contentLoad), harnessInfoLoadNewCallback, callbackContent), FormatError,
|
||||
"expected format 5 but found 4");
|
||||
infoNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone(), harnessInfoLoadNewCallback, callbackContent),
|
||||
FormatError, "expected format 5 but found 4");
|
||||
TEST_RESULT_STR_Z(callbackContent, "", " check callback content");
|
||||
|
||||
// Checksum not found
|
||||
@@ -108,8 +108,8 @@ testRun(void)
|
||||
"backrest-format=5\n");
|
||||
|
||||
TEST_ERROR(
|
||||
infoNewLoad(ioBufferReadNew(contentLoad), harnessInfoLoadNewCallback, callbackContent), ChecksumError,
|
||||
"invalid checksum, actual 'a3765a8c2c1e5d35274a0b0ce118f4031faff0bd' but no checksum found");
|
||||
infoNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone(), harnessInfoLoadNewCallback, callbackContent),
|
||||
ChecksumError, "invalid checksum, actual 'a3765a8c2c1e5d35274a0b0ce118f4031faff0bd' but no checksum found");
|
||||
TEST_RESULT_STR_Z(callbackContent, "", " check callback content");
|
||||
|
||||
// Checksum invalid
|
||||
@@ -122,8 +122,8 @@ testRun(void)
|
||||
"bogus=\"BOGUS\"\n");
|
||||
|
||||
TEST_ERROR(
|
||||
infoNewLoad(ioBufferReadNew(contentLoad), harnessInfoLoadNewCallback, callbackContent), ChecksumError,
|
||||
"invalid checksum, actual 'fe989a75dcf7a0261e57d210707c0db741462763' but expected 'BOGUS'");
|
||||
infoNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone(), harnessInfoLoadNewCallback, callbackContent),
|
||||
ChecksumError, "invalid checksum, actual 'fe989a75dcf7a0261e57d210707c0db741462763' but expected 'BOGUS'");
|
||||
TEST_RESULT_STR_Z(callbackContent, "", " check callback content");
|
||||
|
||||
// Crypto expected
|
||||
@@ -135,10 +135,12 @@ testRun(void)
|
||||
"backrest-version=\"2.17\"\n");
|
||||
|
||||
IoRead *read = ioBufferReadNew(contentLoad);
|
||||
ioFilterGroupAdd(ioReadFilterGroup(read), cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, BUFSTRDEF("X")));
|
||||
ioFilterGroupAdd(
|
||||
ioReadFilterGroup(read),
|
||||
cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("X"))));
|
||||
|
||||
TEST_ERROR(
|
||||
infoNewLoad(read, harnessInfoLoadNewCallback, callbackContent), CryptoError,
|
||||
infoNewLoad(read, cipherSpecNewNone(), harnessInfoLoadNewCallback, callbackContent), CryptoError,
|
||||
"cipher header invalid\n"
|
||||
"HINT: is or was the repo encrypted?");
|
||||
TEST_RESULT_STR_Z(callbackContent, "", " check callback content");
|
||||
@@ -153,9 +155,10 @@ testRun(void)
|
||||
callbackContent = strNew();
|
||||
|
||||
TEST_ASSIGN(
|
||||
info, infoNewLoad(ioBufferReadNew(contentLoad), harnessInfoLoadNewCallback, callbackContent), "info with other cipher");
|
||||
info, infoNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone(), harnessInfoLoadNewCallback, callbackContent),
|
||||
"info with other cipher");
|
||||
TEST_RESULT_STR_Z(callbackContent, "", " check callback content");
|
||||
TEST_RESULT_STR(infoCipherPass(info), NULL, " check cipher pass not set");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoCipherSpec(info)), cipherTypeNone, " check cipher pass not set");
|
||||
|
||||
// Base file with content
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -169,9 +172,10 @@ testRun(void)
|
||||
callbackContent = strNew();
|
||||
|
||||
TEST_ASSIGN(
|
||||
info, infoNewLoad(ioBufferReadNew(contentLoad), harnessInfoLoadNewCallback, callbackContent), "info with content");
|
||||
info, infoNewLoad(ioBufferReadNew(contentLoad), cipherSpecNewNone(), harnessInfoLoadNewCallback, callbackContent),
|
||||
"info with content");
|
||||
TEST_RESULT_STR_Z(callbackContent, "[c] key=1\n[d] key=1\n", " check callback content");
|
||||
TEST_RESULT_STR(infoCipherPass(info), NULL, " check cipher pass not set");
|
||||
TEST_RESULT_UINT(cipherSpecType(infoCipherSpec(info)), cipherTypeNone, " check cipher pass not set");
|
||||
|
||||
Buffer *contentSave = bufNew(0);
|
||||
|
||||
@@ -194,9 +198,12 @@ testRun(void)
|
||||
|
||||
TEST_ASSIGN(
|
||||
info,
|
||||
infoNewLoad(ioBufferReadNew(contentLoad), harnessInfoLoadNewCallback, callbackContent), "info with content and cipher");
|
||||
infoNewLoad(
|
||||
ioBufferReadNew(contentLoad), cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("x")), harnessInfoLoadNewCallback,
|
||||
callbackContent),
|
||||
"info with content and cipher");
|
||||
TEST_RESULT_STR_Z(callbackContent, "[c] key=1\n[d] key=1\n", " check callback content");
|
||||
TEST_RESULT_STR_Z(infoCipherPass(info), "somepass", " check cipher pass set");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(infoCipherSpec(info))), "somepass", " check cipher pass set");
|
||||
TEST_RESULT_STR_Z(infoBackrestVersion(info), PROJECT_VERSION, " check backrest version");
|
||||
|
||||
contentSave = bufNew(0);
|
||||
|
||||
@@ -1469,7 +1469,9 @@ testRun(void)
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
TEST_ASSIGN(manifest, manifestNewLoad(ioBufferReadNew(contentLoad)), "load manifest");
|
||||
TEST_ASSIGN(
|
||||
manifest, manifestNewLoad(ioBufferReadNew(contentLoad), cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("x"))),
|
||||
"load manifest");
|
||||
TEST_RESULT_VOID(manifestMove(manifest, memContextPrior()), "move manifest");
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
@@ -1481,7 +1483,7 @@ testRun(void)
|
||||
manifestTargetFind(manifest, STRDEF("bogus")), AssertError, "unable to find 'bogus' in manifest target list");
|
||||
TEST_RESULT_STR_Z(manifestData(manifest)->backupLabel, "20190808-163540F", "check manifest data");
|
||||
|
||||
TEST_RESULT_STR_Z(manifestCipherSubPass(manifest), "somepass", "check cipher subpass");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(manifestCipherSpec(manifest))), "somepass", "check cipher subpass");
|
||||
|
||||
TEST_RESULT_VOID(
|
||||
manifestTargetUpdate(manifest, MANIFEST_TARGET_PGDATA_STR, STRDEF("/pg/base"), NULL), "update target no change");
|
||||
@@ -1671,7 +1673,7 @@ testRun(void)
|
||||
TEST_MANIFEST_LINK
|
||||
TEST_MANIFEST_LINK_DEFAULT
|
||||
TEST_MANIFEST_PATH
|
||||
TEST_MANIFEST_PATH_DEFAULT))),
|
||||
TEST_MANIFEST_PATH_DEFAULT)), cipherSpecNewNone()),
|
||||
"load manifest");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1768,9 +1770,11 @@ testRun(void)
|
||||
TEST_RESULT_STR_Z(manifestPathPg(STRDEF("pg_data/PG_VERSION")), "PG_VERSION", "check pg_data path/file");
|
||||
TEST_RESULT_STR_Z(manifestPathPg(STRDEF("pg_tblspc/1")), "pg_tblspc/1", "check pg_tblspc path/file");
|
||||
|
||||
TEST_RESULT_STR_Z(manifestCipherSubPass(manifest), NULL, "check cipher subpass");
|
||||
TEST_RESULT_VOID(manifestCipherSubPassSet(manifest, STRDEF("supersecret")), "cipher subpass set");
|
||||
TEST_RESULT_STR_Z(manifestCipherSubPass(manifest), "supersecret", "check cipher subpass");
|
||||
TEST_RESULT_UINT(cipherSpecType(manifestCipherSpec(manifest)), cipherTypeNone, "check cipher subpass");
|
||||
TEST_RESULT_VOID(
|
||||
manifestCipherSpecSet(manifest, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("supersecret"))),
|
||||
"cipher subpass set");
|
||||
TEST_RESULT_STR_Z(strNewBuf(cipherSpecPass(manifestCipherSpec(manifest))), "supersecret", "check cipher subpass");
|
||||
|
||||
// Absolute target paths
|
||||
TEST_RESULT_STR_Z(manifestTargetPath(manifest, manifestTargetBase(manifest)), "/pg/base", "base target path");
|
||||
@@ -1957,11 +1961,11 @@ testRun(void)
|
||||
TEST_TITLE("load validation errors");
|
||||
|
||||
TEST_ERROR(
|
||||
manifestNewLoad(ioBufferReadNew(BUFSTRDEF("[target:file]\npg_data/bogus={\"size\":0}"))), FormatError,
|
||||
"missing timestamp for file 'pg_data/bogus'");
|
||||
manifestNewLoad(ioBufferReadNew(BUFSTRDEF("[target:file]\npg_data/bogus={\"size\":0}")), cipherSpecNewNone()),
|
||||
FormatError, "missing timestamp for file 'pg_data/bogus'");
|
||||
TEST_ERROR(
|
||||
manifestNewLoad(ioBufferReadNew(BUFSTRDEF("[target:file]\npg_data/bogus={\"timestamp\":0}"))), FormatError,
|
||||
"missing size for file 'pg_data/bogus'");
|
||||
manifestNewLoad(ioBufferReadNew(BUFSTRDEF("[target:file]\npg_data/bogus={\"timestamp\":0}")), cipherSpecNewNone()),
|
||||
FormatError, "missing size for file 'pg_data/bogus'");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
@@ -1970,7 +1974,7 @@ testRun(void)
|
||||
Manifest *manifest = NULL;
|
||||
|
||||
TEST_ERROR(
|
||||
manifestLoadFile(storageTest, BACKUP_MANIFEST_FILE_STR, cipherTypeNone, NULL), FileMissingError,
|
||||
manifestLoadFile(storageTest, BACKUP_MANIFEST_FILE_STR, cipherSpecNewNone()), FileMissingError,
|
||||
"unable to load backup manifest file '" TEST_PATH "/backup.manifest' or '" TEST_PATH "/backup.manifest.copy':\n"
|
||||
"FileMissingError: unable to open missing file '" TEST_PATH "/backup.manifest' for read\n"
|
||||
"FileMissingError: unable to open missing file '" TEST_PATH "/backup.manifest.copy' for read");
|
||||
@@ -2034,14 +2038,18 @@ testRun(void)
|
||||
"user=\"user1\"\n"
|
||||
|
||||
HRN_INFO_PUT(storageTest, BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_CONTENT, .comment = "write manifest copy");
|
||||
TEST_ASSIGN(manifest, manifestLoadFile(storageTest, STRDEF(BACKUP_MANIFEST_FILE), cipherTypeNone, NULL), "load copy");
|
||||
TEST_ASSIGN(
|
||||
manifest, manifestLoadFile(storageTest, STRDEF(BACKUP_MANIFEST_FILE), cipherSpecNewNone()),
|
||||
"load copy");
|
||||
TEST_RESULT_UINT(manifestData(manifest)->pgSystemId, 1000000000000000094, "check file loaded");
|
||||
TEST_RESULT_STR_Z(manifestData(manifest)->backrestVersion, PROJECT_VERSION, "check backrest version");
|
||||
|
||||
HRN_STORAGE_REMOVE(storageTest, BACKUP_MANIFEST_FILE INFO_COPY_EXT, .errorOnMissing = true);
|
||||
|
||||
HRN_INFO_PUT(storageTest, BACKUP_MANIFEST_FILE, TEST_MANIFEST_CONTENT, .comment = "write main manifest");
|
||||
TEST_ASSIGN(manifest, manifestLoadFile(storageTest, STRDEF(BACKUP_MANIFEST_FILE), cipherTypeNone, NULL), "load main");
|
||||
TEST_ASSIGN(
|
||||
manifest, manifestLoadFile(storageTest, STRDEF(BACKUP_MANIFEST_FILE), cipherSpecNewNone()),
|
||||
"load main");
|
||||
TEST_RESULT_UINT(manifestData(manifest)->pgSystemId, 1000000000000000094, "check file loaded");
|
||||
|
||||
TEST_RESULT_VOID(manifestFree(manifest), "free manifest");
|
||||
|
||||
@@ -200,14 +200,14 @@ testRun(void)
|
||||
{
|
||||
// Check backups before the backup so we know how many will exist after
|
||||
const InfoBackup *infoBackup = infoBackupLoadFile(
|
||||
hrnHostRepo1Storage(repo), STRDEF("backup/" HRN_STANZA "/backup.info"), hrnHostCipherType(), hrnHostCipherPass());
|
||||
hrnHostRepo1Storage(repo), STRDEF("backup/" HRN_STANZA "/backup.info"), hrnHostCipherSpec());
|
||||
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 1, "backup total = 1");
|
||||
|
||||
TEST_HOST_BR(repo, CFGCMD_BACKUP, .option = "--type=full --backup-standby --repo1-retention-full=1 --no-expire-auto");
|
||||
|
||||
// Expire was disabled so the backup total has increased
|
||||
infoBackup = infoBackupLoadFile(
|
||||
hrnHostRepo1Storage(repo), STRDEF("backup/" HRN_STANZA "/backup.info"), hrnHostCipherType(), hrnHostCipherPass());
|
||||
hrnHostRepo1Storage(repo), STRDEF("backup/" HRN_STANZA "/backup.info"), hrnHostCipherSpec());
|
||||
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 2, "backup total = 2");
|
||||
|
||||
// Now force an expire
|
||||
@@ -215,7 +215,7 @@ testRun(void)
|
||||
|
||||
// Backup has been expired
|
||||
infoBackup = infoBackupLoadFile(
|
||||
hrnHostRepo1Storage(repo), STRDEF("backup/" HRN_STANZA "/backup.info"), hrnHostCipherType(), hrnHostCipherPass());
|
||||
hrnHostRepo1Storage(repo), STRDEF("backup/" HRN_STANZA "/backup.info"), hrnHostCipherSpec());
|
||||
TEST_RESULT_UINT(infoBackupDataTotal(infoBackup), 1, "backup total = 1");
|
||||
|
||||
// Stop the standby since restores to primary will break it
|
||||
|
||||
@@ -302,7 +302,7 @@ testRun(void)
|
||||
|
||||
MEM_CONTEXT_BEGIN(testContext)
|
||||
{
|
||||
manifest = manifestNewLoad(ioBufferReadNew(contentSave));
|
||||
manifest = manifestNewLoad(ioBufferReadNew(contentSave), cipherSpecNewNone());
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
|
||||
|
||||
@@ -381,8 +381,8 @@ testRun(void)
|
||||
IoFilterGroup *filterGroup = ioReadFilterGroup(storageReadIo(fileRead));
|
||||
ioFilterGroupAdd(filterGroup, ioSizeNew());
|
||||
ioFilterGroupAdd(filterGroup, cryptoHashNew(hashTypeSha1));
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeEncrypt, cipherTypeAes256Cbc, BUFSTRZ("x")));
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeDecrypt, cipherTypeAes256Cbc, BUFSTRZ("x")));
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeEncrypt, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("x"))));
|
||||
ioFilterGroupAdd(filterGroup, cipherBlockNewP(cipherModeDecrypt, cipherSpecNew(cipherTypeAes256Cbc, BUFSTRDEF("x"))));
|
||||
ioFilterGroupAdd(filterGroup, compressFilterP(compressTypeGz, 3));
|
||||
ioFilterGroupAdd(filterGroup, decompressFilterP(compressTypeGz));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user