If a migration was interrupted, continue on next mount

This commit is contained in:
Sebastian Messmer 2019-01-21 01:27:32 -08:00
parent ad6125a7e4
commit 652a95dd0d
5 changed files with 32 additions and 2 deletions

View File

@ -32,6 +32,7 @@ CryConfig::CryConfig()
, _exclusiveClientId(none) , _exclusiveClientId(none)
#ifndef CRYFS_NO_COMPATIBILITY #ifndef CRYFS_NO_COMPATIBILITY
, _hasVersionNumbers(true) , _hasVersionNumbers(true)
, _hasParentPointers(true)
#endif #endif
{ {
} }
@ -53,6 +54,7 @@ CryConfig CryConfig::load(const Data &data) {
cfg._exclusiveClientId = pt.get_optional<uint32_t>("cryfs.exclusiveClientId"); cfg._exclusiveClientId = pt.get_optional<uint32_t>("cryfs.exclusiveClientId");
#ifndef CRYFS_NO_COMPATIBILITY #ifndef CRYFS_NO_COMPATIBILITY
cfg._hasVersionNumbers = pt.get<bool>("cryfs.migrations.hasVersionNumbers", false); cfg._hasVersionNumbers = pt.get<bool>("cryfs.migrations.hasVersionNumbers", false);
cfg._hasParentPointers = pt.get<bool>("cryfs.migrations.hasParentPointers", false);
#endif #endif
optional<string> filesystemIdOpt = pt.get_optional<string>("cryfs.filesystemId"); optional<string> filesystemIdOpt = pt.get_optional<string>("cryfs.filesystemId");
@ -81,6 +83,7 @@ Data CryConfig::save() const {
} }
#ifndef CRYFS_NO_COMPATIBILITY #ifndef CRYFS_NO_COMPATIBILITY
pt.put<bool>("cryfs.migrations.hasVersionNumbers", _hasVersionNumbers); pt.put<bool>("cryfs.migrations.hasVersionNumbers", _hasVersionNumbers);
pt.put<bool>("cryfs.migrations.hasParentPointers", _hasParentPointers);
#endif #endif
stringstream stream; stringstream stream;
@ -172,6 +175,14 @@ bool CryConfig::HasVersionNumbers() const {
void CryConfig::SetHasVersionNumbers(bool value) { void CryConfig::SetHasVersionNumbers(bool value) {
_hasVersionNumbers = value; _hasVersionNumbers = value;
} }
bool CryConfig::HasParentPointers() const {
return _hasParentPointers;
}
void CryConfig::SetHasParentPointers(bool value) {
_hasParentPointers = value;
}
#endif #endif
} }

View File

@ -56,6 +56,11 @@ public:
// Version numbers cannot be disabled, but the file system will be migrated to version numbers automatically. // Version numbers cannot be disabled, but the file system will be migrated to version numbers automatically.
bool HasVersionNumbers() const; bool HasVersionNumbers() const;
void SetHasVersionNumbers(bool value); void SetHasVersionNumbers(bool value);
// This is a trigger to recognize old file systems that didn't have version numbers.
// Version numbers cannot be disabled, but the file system will be migrated to version numbers automatically.
bool HasParentPointers() const;
void SetHasParentPointers(bool value);
#endif #endif
static CryConfig load(const cpputils::Data &data); static CryConfig load(const cpputils::Data &data);
@ -73,6 +78,7 @@ private:
boost::optional<uint32_t> _exclusiveClientId; boost::optional<uint32_t> _exclusiveClientId;
#ifndef CRYFS_NO_COMPATIBILITY #ifndef CRYFS_NO_COMPATIBILITY
bool _hasVersionNumbers; bool _hasVersionNumbers;
bool _hasParentPointers;
#endif #endif
CryConfig &operator=(const CryConfig &rhs) = delete; CryConfig &operator=(const CryConfig &rhs) = delete;

View File

@ -80,7 +80,14 @@ unique_ref<fsblobstore::FsBlobStore> CryDevice::MigrateOrCreateFsBlobStore(uniqu
if ("" == rootBlobId) { if ("" == rootBlobId) {
return make_unique_ref<FsBlobStore>(std::move(blobStore)); return make_unique_ref<FsBlobStore>(std::move(blobStore));
} }
return FsBlobStore::migrateIfNeeded(std::move(blobStore), BlockId::FromString(rootBlobId)); if (!configFile->config()->HasParentPointers()) {
auto result = FsBlobStore::migrateIfNeeded(std::move(blobStore), BlockId::FromString(rootBlobId));
// Don't migrate again if it was successful
configFile->config()->SetHasParentPointers(true);
configFile->save();
return result;
}
return make_unique_ref<FsBlobStore>(std::move(blobStore));
} }
#endif #endif
@ -106,6 +113,7 @@ unique_ref<BlockStore2> CryDevice::CreateIntegrityEncryptedBlockStore(unique_ref
if (!configFile->config()->HasVersionNumbers()) { if (!configFile->config()->HasVersionNumbers()) {
IntegrityBlockStore2::migrateFromBlockstoreWithoutVersionNumbers(encryptedBlockStore.get(), integrityFilePath, myClientId); IntegrityBlockStore2::migrateFromBlockstoreWithoutVersionNumbers(encryptedBlockStore.get(), integrityFilePath, myClientId);
configFile->config()->SetBlocksizeBytes(configFile->config()->BlocksizeBytes() + IntegrityBlockStore2::HEADER_LENGTH - blockstore::BlockId::BINARY_LENGTH); // Minus BlockId size because EncryptedBlockStore doesn't store the BlockId anymore (that was moved to IntegrityBlockStore) configFile->config()->SetBlocksizeBytes(configFile->config()->BlocksizeBytes() + IntegrityBlockStore2::HEADER_LENGTH - blockstore::BlockId::BINARY_LENGTH); // Minus BlockId size because EncryptedBlockStore doesn't store the BlockId anymore (that was moved to IntegrityBlockStore)
// Don't migrate again if it was successful
configFile->config()->SetHasVersionNumbers(true); configFile->config()->SetHasVersionNumbers(true);
configFile->save(); configFile->save();
} }

View File

@ -2,6 +2,7 @@
#include "FileBlob.h" #include "FileBlob.h"
#include "DirBlob.h" #include "DirBlob.h"
#include "SymlinkBlob.h" #include "SymlinkBlob.h"
#include <cryfs/config/CryConfigFile.h>
using cpputils::unique_ref; using cpputils::unique_ref;
using cpputils::make_unique_ref; using cpputils::make_unique_ref;

View File

@ -10,7 +10,11 @@ namespace cryfs {
void FsBlobView::migrate(blobstore::Blob *blob, const blockstore::BlockId &parentId) { void FsBlobView::migrate(blobstore::Blob *blob, const blockstore::BlockId &parentId) {
constexpr unsigned int OLD_HEADER_SIZE = sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t); constexpr unsigned int OLD_HEADER_SIZE = sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t);
ASSERT(FsBlobView::getFormatVersionHeader(*blob) == 0, "Block already migrated"); if(FsBlobView::getFormatVersionHeader(*blob) != 0) {
// blob already migrated
return;
}
// Resize blob and move data back // Resize blob and move data back
cpputils::Data data = blob->readAll(); cpputils::Data data = blob->readAll();
blob->resize(blob->size() + blockstore::BlockId::BINARY_LENGTH); blob->resize(blob->size() + blockstore::BlockId::BINARY_LENGTH);