From 3425760daff2712a810624da47f56b0c3f616a82 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Mon, 27 Jun 2016 20:03:44 -0700 Subject: [PATCH] Implement migration for old filesystems that don't have parent pointers. --- src/cryfs/filesystem/CryDevice.cpp | 34 +++++++++++------- src/cryfs/filesystem/CryDevice.h | 1 + .../filesystem/fsblobstore/FsBlobStore.cpp | 36 ++++++++++++++++++- .../filesystem/fsblobstore/FsBlobStore.h | 8 +++++ .../filesystem/fsblobstore/FsBlobView.cpp | 20 ++++++++++- src/cryfs/filesystem/fsblobstore/FsBlobView.h | 15 ++++++-- 6 files changed, 96 insertions(+), 18 deletions(-) diff --git a/src/cryfs/filesystem/CryDevice.cpp b/src/cryfs/filesystem/CryDevice.cpp index aec3fef0..1298ab5f 100644 --- a/src/cryfs/filesystem/CryDevice.cpp +++ b/src/cryfs/filesystem/CryDevice.cpp @@ -54,28 +54,36 @@ namespace bf = boost::filesystem; namespace cryfs { CryDevice::CryDevice(CryConfigFile configFile, unique_ref blockStore, uint32_t myClientId) -: _fsBlobStore( - make_unique_ref( - make_unique_ref( - make_unique_ref( - CreateBlobStore(std::move(blockStore), &configFile, myClientId) - ) - ) - ) - ), +: _fsBlobStore(CreateFsBlobStore(std::move(blockStore), &configFile, myClientId)), _rootKey(GetOrCreateRootKey(&configFile)), _onFsAction() { } +unique_ref CryDevice::CreateFsBlobStore(unique_ref 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(std::move(blobStore)); +#endif + + return make_unique_ref( + make_unique_ref( + std::move(fsBlobStore) + ) + ); +} + unique_ref CryDevice::CreateBlobStore(unique_ref 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( - make_unique_ref( - std::move(versionCountingEncryptedBlockStore) - ), - configFile->config()->BlocksizeBytes()); + make_unique_ref( + std::move(versionCountingEncryptedBlockStore) + ), + configFile->config()->BlocksizeBytes()); } unique_ref CryDevice::CreateVersionCountingEncryptedBlockStore(unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId) { diff --git a/src/cryfs/filesystem/CryDevice.h b/src/cryfs/filesystem/CryDevice.h index 1783c80e..ddeb8441 100644 --- a/src/cryfs/filesystem/CryDevice.h +++ b/src/cryfs/filesystem/CryDevice.h @@ -49,6 +49,7 @@ private: blockstore::Key GetOrCreateRootKey(CryConfigFile *config); blockstore::Key CreateRootBlobAndReturnKey(); + static cpputils::unique_ref CreateFsBlobStore(cpputils::unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId); static cpputils::unique_ref CreateBlobStore(cpputils::unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId); static cpputils::unique_ref CreateVersionCountingEncryptedBlockStore(cpputils::unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId); static cpputils::unique_ref CreateEncryptedBlockStore(const CryConfig &config, cpputils::unique_ref baseBlockStore); diff --git a/src/cryfs/filesystem/fsblobstore/FsBlobStore.cpp b/src/cryfs/filesystem/fsblobstore/FsBlobStore.cpp index 7200b0fc..3a163f1c 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlobStore.cpp +++ b/src/cryfs/filesystem/fsblobstore/FsBlobStore.cpp @@ -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> FsBlobStore::load(const blockstore::Key &key } } +#ifndef CRYFS_NO_COMPATIBILITY + unique_ref FsBlobStore::migrateIfNeeded(unique_ref 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(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 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 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 + +} } -} \ No newline at end of file diff --git a/src/cryfs/filesystem/fsblobstore/FsBlobStore.h b/src/cryfs/filesystem/fsblobstore/FsBlobStore.h index 7443a33e..cd058ad0 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlobStore.h +++ b/src/cryfs/filesystem/fsblobstore/FsBlobStore.h @@ -27,8 +27,16 @@ namespace cryfs { uint64_t virtualBlocksizeBytes() const; +#ifndef CRYFS_NO_COMPATIBILITY + static cpputils::unique_ref migrateIfNeeded(cpputils::unique_ref blobStore, const blockstore::Key &rootKey); +#endif + private: +#ifndef CRYFS_NO_COMPATIBILITY + void _migrate(cpputils::unique_ref node, const blockstore::Key &parentKey); +#endif + std::function _getLstatSize(); cpputils::unique_ref _baseBlobStore; diff --git a/src/cryfs/filesystem/fsblobstore/FsBlobView.cpp b/src/cryfs/filesystem/fsblobstore/FsBlobView.cpp index e1d2f01b..e6feb35b 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlobView.cpp +++ b/src/cryfs/filesystem/fsblobstore/FsBlobView.cpp @@ -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; -} \ No newline at end of file + +#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 +} diff --git a/src/cryfs/filesystem/fsblobstore/FsBlobView.h b/src/cryfs/filesystem/fsblobstore/FsBlobView.h index 15af4f52..63cc1ddb 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlobView.h +++ b/src/cryfs/filesystem/fsblobstore/FsBlobView.h @@ -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?"); }