Implement migration for old filesystems that don't have parent pointers.

This commit is contained in:
Sebastian Messmer 2016-06-27 20:03:44 -07:00
parent bfb397f44e
commit 3425760daf
6 changed files with 96 additions and 18 deletions

View File

@ -54,28 +54,36 @@ namespace bf = boost::filesystem;
namespace cryfs {
CryDevice::CryDevice(CryConfigFile configFile, unique_ref<BlockStore> blockStore, uint32_t myClientId)
: _fsBlobStore(
make_unique_ref<ParallelAccessFsBlobStore>(
make_unique_ref<CachingFsBlobStore>(
make_unique_ref<FsBlobStore>(
CreateBlobStore(std::move(blockStore), &configFile, myClientId)
)
)
)
),
: _fsBlobStore(CreateFsBlobStore(std::move(blockStore), &configFile, myClientId)),
_rootKey(GetOrCreateRootKey(&configFile)),
_onFsAction() {
}
unique_ref<parallelaccessfsblobstore::ParallelAccessFsBlobStore> CryDevice::CreateFsBlobStore(unique_ref<BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId) {
auto blobStore = CreateBlobStore(std::move(blockStore), configFile, myClientId);
#ifndef CRYFS_NO_COMPATIBILITY
auto fsBlobStore = FsBlobStore::migrateIfNeeded(std::move(blobStore), Key::FromString(configFile->config()->RootBlob()));
#else
auto fsBlobStore = make_unique_ref<FsBlobStore>(std::move(blobStore));
#endif
return make_unique_ref<ParallelAccessFsBlobStore>(
make_unique_ref<CachingFsBlobStore>(
std::move(fsBlobStore)
)
);
}
unique_ref<blobstore::BlobStore> CryDevice::CreateBlobStore(unique_ref<BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId) {
auto versionCountingEncryptedBlockStore = CreateVersionCountingEncryptedBlockStore(std::move(blockStore), configFile, myClientId);
// Create versionCountingEncryptedBlockStore not in the same line as BlobStoreOnBlocks, because it can modify BlocksizeBytes
// in the configFile and therefore has to be run before the second parameter to the BlobStoreOnBlocks parameter is evaluated.
return make_unique_ref<BlobStoreOnBlocks>(
make_unique_ref<CachingBlockStore>(
std::move(versionCountingEncryptedBlockStore)
),
configFile->config()->BlocksizeBytes());
make_unique_ref<CachingBlockStore>(
std::move(versionCountingEncryptedBlockStore)
),
configFile->config()->BlocksizeBytes());
}
unique_ref<BlockStore> CryDevice::CreateVersionCountingEncryptedBlockStore(unique_ref<BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId) {

View File

@ -49,6 +49,7 @@ private:
blockstore::Key GetOrCreateRootKey(CryConfigFile *config);
blockstore::Key CreateRootBlobAndReturnKey();
static cpputils::unique_ref<parallelaccessfsblobstore::ParallelAccessFsBlobStore> CreateFsBlobStore(cpputils::unique_ref<blockstore::BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId);
static cpputils::unique_ref<blobstore::BlobStore> CreateBlobStore(cpputils::unique_ref<blockstore::BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId);
static cpputils::unique_ref<blockstore::BlockStore> CreateVersionCountingEncryptedBlockStore(cpputils::unique_ref<blockstore::BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId);
static cpputils::unique_ref<blockstore::BlockStore> CreateEncryptedBlockStore(const CryConfig &config, cpputils::unique_ref<blockstore::BlockStore> baseBlockStore);

View File

@ -10,6 +10,7 @@ using blobstore::BlobStore;
using blockstore::Key;
using boost::none;
using std::function;
using std::vector;
namespace cryfs {
namespace fsblobstore {
@ -31,5 +32,38 @@ boost::optional<unique_ref<FsBlob>> FsBlobStore::load(const blockstore::Key &key
}
}
#ifndef CRYFS_NO_COMPATIBILITY
unique_ref<FsBlobStore> FsBlobStore::migrateIfNeeded(unique_ref<BlobStore> blobStore, const blockstore::Key &rootKey) {
auto rootBlob = blobStore->load(rootKey);
ASSERT(rootBlob != none, "Could not load root blob");
uint16_t format = FsBlobView::getFormatVersionHeader(**rootBlob);
auto fsBlobStore = make_unique_ref<FsBlobStore>(std::move(blobStore));
if (format == 0) {
// migration needed
std::cout << "Migrating file system for conflict resolution features. Please don't interrupt this process. This can take a while..." << std::flush;
fsBlobStore->_migrate(std::move(*rootBlob), blockstore::Key::Null());
std::cout << "done" << std::endl;
}
return fsBlobStore;
}
void FsBlobStore::_migrate(unique_ref<blobstore::Blob> node, const blockstore::Key &parentKey) {
FsBlobView::migrate(node.get(), parentKey);
if (FsBlobView::blobType(*node) == FsBlobView::BlobType::DIR) {
DirBlob dir(this, std::move(node), _getLstatSize());
vector<fspp::Dir::Entry> children;
dir.AppendChildrenTo(&children);
for (const auto &child : children) {
auto childEntry = dir.GetChild(child.name);
ASSERT(childEntry != none, "Couldn't load child, although it was returned as a child in the lsit.");
auto childBlob = _baseBlobStore->load(childEntry->key());
ASSERT(childBlob != none, "Couldn't load child blob");
_migrate(std::move(*childBlob), dir.key());
}
}
}
#endif
}
}
}

View File

@ -27,8 +27,16 @@ namespace cryfs {
uint64_t virtualBlocksizeBytes() const;
#ifndef CRYFS_NO_COMPATIBILITY
static cpputils::unique_ref<FsBlobStore> migrateIfNeeded(cpputils::unique_ref<blobstore::BlobStore> blobStore, const blockstore::Key &rootKey);
#endif
private:
#ifndef CRYFS_NO_COMPATIBILITY
void _migrate(cpputils::unique_ref<blobstore::Blob> node, const blockstore::Key &parentKey);
#endif
std::function<off_t(const blockstore::Key &)> _getLstatSize();
cpputils::unique_ref<blobstore::BlobStore> _baseBlobStore;

View File

@ -1,6 +1,24 @@
#include "FsBlobView.h"
using cpputils::Data;
namespace cryfs {
constexpr uint16_t FsBlobView::FORMAT_VERSION_HEADER;
constexpr unsigned int FsBlobView::HEADER_SIZE;
}
#ifndef CRYFS_NO_COMPATIBILITY
void FsBlobView::migrate(blobstore::Blob *blob, const blockstore::Key &parentKey) {
constexpr unsigned int OLD_HEADER_SIZE = sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t);
ASSERT(FsBlobView::getFormatVersionHeader(*blob) == 0, "Block already migrated");
// Resize blob and move data back
cpputils::Data data = blob->readAll();
blob->resize(blob->size() + blockstore::Key::BINARY_LENGTH);
blob->write(data.dataOffset(OLD_HEADER_SIZE), HEADER_SIZE, data.size() - OLD_HEADER_SIZE);
// Write parent pointer
blob->write(parentKey.data(), sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t), blockstore::Key::BINARY_LENGTH);
// Update format version number
blob->write(&FORMAT_VERSION_HEADER, 0, sizeof(FORMAT_VERSION_HEADER));
}
#endif
}

View File

@ -89,14 +89,23 @@ namespace cryfs {
return std::move(_baseBlob);
}
static uint16_t getFormatVersionHeader(const blobstore::Blob &blob) {
static_assert(sizeof(uint16_t) == sizeof(FORMAT_VERSION_HEADER), "Wrong type used to read format version header");
uint16_t actualFormatVersion;
blob.read(&actualFormatVersion, 0, sizeof(FORMAT_VERSION_HEADER));
return actualFormatVersion;
}
#ifndef CRYFS_NO_COMPATIBILITY
static void migrate(blobstore::Blob *blob, const blockstore::Key &parentKey);
#endif
private:
static constexpr uint16_t FORMAT_VERSION_HEADER = 1;
static constexpr unsigned int HEADER_SIZE = sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t) + blockstore::Key::BINARY_LENGTH;
static void _checkHeader(const blobstore::Blob &blob) {
static_assert(sizeof(uint16_t) == sizeof(FORMAT_VERSION_HEADER), "Wrong type used to read format version header");
uint16_t actualFormatVersion;
blob.read(&actualFormatVersion, 0, sizeof(FORMAT_VERSION_HEADER));
uint16_t actualFormatVersion = getFormatVersionHeader(blob);
if (FORMAT_VERSION_HEADER != actualFormatVersion) {
throw std::runtime_error("This file system entity has the wrong format. Was it created with a newer version of CryFS?");
}