Implement migration for old filesystems that don't have parent pointers.
This commit is contained in:
parent
bfb397f44e
commit
3425760daf
@ -54,28 +54,36 @@ namespace bf = boost::filesystem;
|
|||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
|
|
||||||
CryDevice::CryDevice(CryConfigFile configFile, unique_ref<BlockStore> blockStore, uint32_t myClientId)
|
CryDevice::CryDevice(CryConfigFile configFile, unique_ref<BlockStore> blockStore, uint32_t myClientId)
|
||||||
: _fsBlobStore(
|
: _fsBlobStore(CreateFsBlobStore(std::move(blockStore), &configFile, myClientId)),
|
||||||
make_unique_ref<ParallelAccessFsBlobStore>(
|
|
||||||
make_unique_ref<CachingFsBlobStore>(
|
|
||||||
make_unique_ref<FsBlobStore>(
|
|
||||||
CreateBlobStore(std::move(blockStore), &configFile, myClientId)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
_rootKey(GetOrCreateRootKey(&configFile)),
|
_rootKey(GetOrCreateRootKey(&configFile)),
|
||||||
_onFsAction() {
|
_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) {
|
unique_ref<blobstore::BlobStore> CryDevice::CreateBlobStore(unique_ref<BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId) {
|
||||||
auto versionCountingEncryptedBlockStore = CreateVersionCountingEncryptedBlockStore(std::move(blockStore), configFile, myClientId);
|
auto versionCountingEncryptedBlockStore = CreateVersionCountingEncryptedBlockStore(std::move(blockStore), configFile, myClientId);
|
||||||
// Create versionCountingEncryptedBlockStore not in the same line as BlobStoreOnBlocks, because it can modify BlocksizeBytes
|
// 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.
|
// in the configFile and therefore has to be run before the second parameter to the BlobStoreOnBlocks parameter is evaluated.
|
||||||
return make_unique_ref<BlobStoreOnBlocks>(
|
return make_unique_ref<BlobStoreOnBlocks>(
|
||||||
make_unique_ref<CachingBlockStore>(
|
make_unique_ref<CachingBlockStore>(
|
||||||
std::move(versionCountingEncryptedBlockStore)
|
std::move(versionCountingEncryptedBlockStore)
|
||||||
),
|
),
|
||||||
configFile->config()->BlocksizeBytes());
|
configFile->config()->BlocksizeBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ref<BlockStore> CryDevice::CreateVersionCountingEncryptedBlockStore(unique_ref<BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId) {
|
unique_ref<BlockStore> CryDevice::CreateVersionCountingEncryptedBlockStore(unique_ref<BlockStore> blockStore, CryConfigFile *configFile, uint32_t myClientId) {
|
||||||
|
@ -49,6 +49,7 @@ private:
|
|||||||
|
|
||||||
blockstore::Key GetOrCreateRootKey(CryConfigFile *config);
|
blockstore::Key GetOrCreateRootKey(CryConfigFile *config);
|
||||||
blockstore::Key CreateRootBlobAndReturnKey();
|
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<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> 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);
|
static cpputils::unique_ref<blockstore::BlockStore> CreateEncryptedBlockStore(const CryConfig &config, cpputils::unique_ref<blockstore::BlockStore> baseBlockStore);
|
||||||
|
@ -10,6 +10,7 @@ using blobstore::BlobStore;
|
|||||||
using blockstore::Key;
|
using blockstore::Key;
|
||||||
using boost::none;
|
using boost::none;
|
||||||
using std::function;
|
using std::function;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
namespace fsblobstore {
|
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
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
@ -27,8 +27,16 @@ namespace cryfs {
|
|||||||
|
|
||||||
uint64_t virtualBlocksizeBytes() const;
|
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:
|
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();
|
std::function<off_t(const blockstore::Key &)> _getLstatSize();
|
||||||
|
|
||||||
cpputils::unique_ref<blobstore::BlobStore> _baseBlobStore;
|
cpputils::unique_ref<blobstore::BlobStore> _baseBlobStore;
|
||||||
|
@ -1,6 +1,24 @@
|
|||||||
#include "FsBlobView.h"
|
#include "FsBlobView.h"
|
||||||
|
|
||||||
|
using cpputils::Data;
|
||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
constexpr uint16_t FsBlobView::FORMAT_VERSION_HEADER;
|
constexpr uint16_t FsBlobView::FORMAT_VERSION_HEADER;
|
||||||
constexpr unsigned int FsBlobView::HEADER_SIZE;
|
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
|
||||||
|
}
|
||||||
|
@ -89,14 +89,23 @@ namespace cryfs {
|
|||||||
return std::move(_baseBlob);
|
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:
|
private:
|
||||||
static constexpr uint16_t FORMAT_VERSION_HEADER = 1;
|
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 constexpr unsigned int HEADER_SIZE = sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t) + blockstore::Key::BINARY_LENGTH;
|
||||||
|
|
||||||
static void _checkHeader(const blobstore::Blob &blob) {
|
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 = getFormatVersionHeader(blob);
|
||||||
uint16_t actualFormatVersion;
|
|
||||||
blob.read(&actualFormatVersion, 0, sizeof(FORMAT_VERSION_HEADER));
|
|
||||||
if (FORMAT_VERSION_HEADER != actualFormatVersion) {
|
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?");
|
throw std::runtime_error("This file system entity has the wrong format. Was it created with a newer version of CryFS?");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user