From 397de9372f0e09e5ffce9cacffbacfd0a6ea885e Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Mon, 27 Jun 2016 18:22:13 -0700 Subject: [PATCH] Each blob stores a parent pointer (i.e. the ID of the directory that contains this blob). This stores the directory structure in a conflict-proof way and can be used to resolve such conflicts. --- src/cryfs/filesystem/CryDevice.cpp | 16 ++++--- src/cryfs/filesystem/CryDevice.h | 6 +-- src/cryfs/filesystem/CryDir.cpp | 6 +-- src/cryfs/filesystem/CryNode.cpp | 14 +++++- src/cryfs/filesystem/CryNode.h | 3 ++ .../cachingfsblobstore/CachingFsBlobStore.h | 18 +++---- .../filesystem/cachingfsblobstore/FsBlobRef.h | 8 ++++ src/cryfs/filesystem/fsblobstore/DirBlob.cpp | 4 +- src/cryfs/filesystem/fsblobstore/DirBlob.h | 1 + src/cryfs/filesystem/fsblobstore/FileBlob.cpp | 4 +- src/cryfs/filesystem/fsblobstore/FileBlob.h | 2 +- src/cryfs/filesystem/fsblobstore/FsBlob.h | 16 +++++-- .../filesystem/fsblobstore/FsBlobStore.h | 18 +++---- .../filesystem/fsblobstore/FsBlobView.cpp | 1 + src/cryfs/filesystem/fsblobstore/FsBlobView.h | 47 ++++++++++++++----- .../filesystem/fsblobstore/SymlinkBlob.cpp | 4 +- .../filesystem/fsblobstore/SymlinkBlob.h | 2 +- .../parallelaccessfsblobstore/DirBlobRef.h | 12 ++++- .../parallelaccessfsblobstore/FileBlobRef.h | 12 ++++- .../parallelaccessfsblobstore/FsBlobRef.h | 2 + .../ParallelAccessFsBlobStore.cpp | 12 ++--- .../ParallelAccessFsBlobStore.h | 6 +-- .../SymlinkBlobRef.h | 12 ++++- test/cryfs/filesystem/CryNodeTest.cpp | 37 +++++++++++++++ 24 files changed, 193 insertions(+), 70 deletions(-) diff --git a/src/cryfs/filesystem/CryDevice.cpp b/src/cryfs/filesystem/CryDevice.cpp index 74326f1b..aec3fef0 100644 --- a/src/cryfs/filesystem/CryDevice.cpp +++ b/src/cryfs/filesystem/CryDevice.cpp @@ -96,7 +96,7 @@ unique_ref CryDevice::CreateVersionCountingEncryptedBlockStore(uniqu } Key CryDevice::CreateRootBlobAndReturnKey() { - auto rootBlob = _fsBlobStore->createDirBlob(); + auto rootBlob = _fsBlobStore->createDirBlob(blockstore::Key::Null()); rootBlob->flush(); // Don't cache, but directly write the root blob (this causes it to fail early if the base directory is not accessible) return rootBlob->key(); } @@ -150,6 +150,7 @@ CryDevice::BlobWithParent CryDevice::LoadBlobWithParent(const bf::path &path) { throw FuseErrnoException(EIO); } unique_ref currentBlob = std::move(*currentBlobOpt); + ASSERT(currentBlob->parentPointer() == Key::Null(), "Root Blob should have a nullptr as parent"); for (const bf::path &component : path.relative_path()) { auto currentDir = dynamic_pointer_move(currentBlob); @@ -168,6 +169,7 @@ CryDevice::BlobWithParent CryDevice::LoadBlobWithParent(const bf::path &path) { } parentBlob = std::move(*currentDir); currentBlob = std::move(*nextBlob); + ASSERT(currentBlob->parentPointer() == (*parentBlob)->key(), "Blob has wrong parent pointer"); } return BlobWithParent{std::move(currentBlob), std::move(parentBlob)}; @@ -194,16 +196,16 @@ void CryDevice::statfs(const bf::path &path, struct statvfs *fsstat) { //f_frsize, f_favail, f_fsid and f_flag are ignored in fuse, see http://fuse.sourcearchive.com/documentation/2.7.0/structfuse__operations_4e765e29122e7b6b533dc99849a52655.html#4e765e29122e7b6b533dc99849a52655 } -unique_ref CryDevice::CreateFileBlob() { - return _fsBlobStore->createFileBlob(); +unique_ref CryDevice::CreateFileBlob(const blockstore::Key &parent) { + return _fsBlobStore->createFileBlob(parent); } -unique_ref CryDevice::CreateDirBlob() { - return _fsBlobStore->createDirBlob(); +unique_ref CryDevice::CreateDirBlob(const blockstore::Key &parent) { + return _fsBlobStore->createDirBlob(parent); } -unique_ref CryDevice::CreateSymlinkBlob(const bf::path &target) { - return _fsBlobStore->createSymlinkBlob(target); +unique_ref CryDevice::CreateSymlinkBlob(const bf::path &target, const blockstore::Key &parent) { + return _fsBlobStore->createSymlinkBlob(target, parent); } unique_ref CryDevice::LoadBlob(const blockstore::Key &key) { diff --git a/src/cryfs/filesystem/CryDevice.h b/src/cryfs/filesystem/CryDevice.h index c4f2089c..1783c80e 100644 --- a/src/cryfs/filesystem/CryDevice.h +++ b/src/cryfs/filesystem/CryDevice.h @@ -21,9 +21,9 @@ public: void statfs(const boost::filesystem::path &path, struct ::statvfs *fsstat) override; - cpputils::unique_ref CreateFileBlob(); - cpputils::unique_ref CreateDirBlob(); - cpputils::unique_ref CreateSymlinkBlob(const boost::filesystem::path &target); + cpputils::unique_ref CreateFileBlob(const blockstore::Key &parent); + cpputils::unique_ref CreateDirBlob(const blockstore::Key &parent); + cpputils::unique_ref CreateSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent); cpputils::unique_ref LoadBlob(const blockstore::Key &key); struct DirBlobWithParent { cpputils::unique_ref blob; diff --git a/src/cryfs/filesystem/CryDir.cpp b/src/cryfs/filesystem/CryDir.cpp index f6911775..da3e1c61 100644 --- a/src/cryfs/filesystem/CryDir.cpp +++ b/src/cryfs/filesystem/CryDir.cpp @@ -43,7 +43,7 @@ unique_ref CryDir::createAndOpenFile(const string &name, mode_t //TODO Instead of doing nothing when we're the root directory, handle timestamps in the root dir correctly (and delete isRootDir() function) parent()->updateModificationTimestampForChild(key()); } - auto child = device()->CreateFileBlob(); + auto child = device()->CreateFileBlob(key()); auto now = cpputils::time::now(); auto dirBlob = LoadBlob(); dirBlob->AddChildFile(name, child->key(), mode, uid, gid, now, now); @@ -57,7 +57,7 @@ void CryDir::createDir(const string &name, mode_t mode, uid_t uid, gid_t gid) { parent()->updateModificationTimestampForChild(key()); } auto blob = LoadBlob(); - auto child = device()->CreateDirBlob(); + auto child = device()->CreateDirBlob(key()); auto now = cpputils::time::now(); blob->AddChildDir(name, child->key(), mode, uid, gid, now, now); } @@ -95,7 +95,7 @@ void CryDir::createSymlink(const string &name, const bf::path &target, uid_t uid parent()->updateModificationTimestampForChild(key()); } auto blob = LoadBlob(); - auto child = device()->CreateSymlinkBlob(target); + auto child = device()->CreateSymlinkBlob(target, key()); auto now = cpputils::time::now(); blob->AddChildSymlink(name, child->key(), uid, gid, now, now); } diff --git a/src/cryfs/filesystem/CryNode.cpp b/src/cryfs/filesystem/CryNode.cpp index 0524b47c..b6d0d2d1 100644 --- a/src/cryfs/filesystem/CryNode.cpp +++ b/src/cryfs/filesystem/CryNode.cpp @@ -100,6 +100,7 @@ void CryNode::rename(const bf::path &to) { oldEntry.lastAccessTime(), oldEntry.lastModificationTime(), onOverwritten); (*_parent)->RemoveChild(oldEntry.name()); // targetDir is now the new parent for this node. Adapt to it, so we can call further operations on this node object. + LoadBlob()->setParentPointer(targetDir->key()); _parent = cpputils::to_unique_ptr(std::move(targetDir)); } } @@ -149,7 +150,9 @@ const CryDevice *CryNode::device() const { } unique_ref CryNode::LoadBlob() const { - return _device->LoadBlob(_key); + auto blob = _device->LoadBlob(_key); + ASSERT(_parent == none || blob->parentPointer() == (*_parent)->key(), "Blob has wrong parent pointer."); + return blob; } const blockstore::Key &CryNode::key() const { @@ -197,4 +200,13 @@ void CryNode::chown(uid_t uid, gid_t gid) { (*_parent)->chownChild(_key, uid, gid); } +bool CryNode::checkParentPointer() { + auto parentPointer = LoadBlob()->parentPointer(); + if (_parent == none) { + return parentPointer == Key::Null(); + } else { + return parentPointer == (*_parent)->key(); + } +} + } diff --git a/src/cryfs/filesystem/CryNode.h b/src/cryfs/filesystem/CryNode.h index 5cab5476..e5c89858 100644 --- a/src/cryfs/filesystem/CryNode.h +++ b/src/cryfs/filesystem/CryNode.h @@ -23,6 +23,9 @@ public: void rename(const boost::filesystem::path &to) override; void utimens(timespec lastAccessTime, timespec lastModificationTime) override; + // used in test cases + bool checkParentPointer(); + protected: CryNode(); diff --git a/src/cryfs/filesystem/cachingfsblobstore/CachingFsBlobStore.h b/src/cryfs/filesystem/cachingfsblobstore/CachingFsBlobStore.h index 47e19cb7..37c0ddc9 100644 --- a/src/cryfs/filesystem/cachingfsblobstore/CachingFsBlobStore.h +++ b/src/cryfs/filesystem/cachingfsblobstore/CachingFsBlobStore.h @@ -19,9 +19,9 @@ namespace cryfs { CachingFsBlobStore(cpputils::unique_ref baseBlobStore); ~CachingFsBlobStore(); - cpputils::unique_ref createFileBlob(); - cpputils::unique_ref createDirBlob(); - cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target); + cpputils::unique_ref createFileBlob(const blockstore::Key &parent); + cpputils::unique_ref createDirBlob(const blockstore::Key &parent); + cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent); boost::optional> load(const blockstore::Key &key); void remove(cpputils::unique_ref blob); uint64_t virtualBlocksizeBytes() const; @@ -50,25 +50,25 @@ namespace cryfs { inline CachingFsBlobStore::~CachingFsBlobStore() { } - inline cpputils::unique_ref CachingFsBlobStore::createFileBlob() { + inline cpputils::unique_ref CachingFsBlobStore::createFileBlob(const blockstore::Key &parent) { // This already creates the file blob in the underlying blobstore. // We could also cache this operation, but that is more complicated (blockstore::CachingBlockStore does it) // and probably not worth it here. - return cpputils::make_unique_ref(_baseBlobStore->createFileBlob(), this); + return cpputils::make_unique_ref(_baseBlobStore->createFileBlob(parent), this); } - inline cpputils::unique_ref CachingFsBlobStore::createDirBlob() { + inline cpputils::unique_ref CachingFsBlobStore::createDirBlob(const blockstore::Key &parent) { // This already creates the file blob in the underlying blobstore. // We could also cache this operation, but that is more complicated (blockstore::CachingBlockStore does it) // and probably not worth it here. - return cpputils::make_unique_ref(_baseBlobStore->createDirBlob(), this); + return cpputils::make_unique_ref(_baseBlobStore->createDirBlob(parent), this); } - inline cpputils::unique_ref CachingFsBlobStore::createSymlinkBlob(const boost::filesystem::path &target) { + inline cpputils::unique_ref CachingFsBlobStore::createSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent) { // This already creates the file blob in the underlying blobstore. // We could also cache this operation, but that is more complicated (blockstore::CachingBlockStore does it) // and probably not worth it here. - return cpputils::make_unique_ref(_baseBlobStore->createSymlinkBlob(target), this); + return cpputils::make_unique_ref(_baseBlobStore->createSymlinkBlob(target, parent), this); } inline void CachingFsBlobStore::remove(cpputils::unique_ref blob) { diff --git a/src/cryfs/filesystem/cachingfsblobstore/FsBlobRef.h b/src/cryfs/filesystem/cachingfsblobstore/FsBlobRef.h index 104d1ba2..e20b89e2 100644 --- a/src/cryfs/filesystem/cachingfsblobstore/FsBlobRef.h +++ b/src/cryfs/filesystem/cachingfsblobstore/FsBlobRef.h @@ -15,6 +15,14 @@ public: virtual const blockstore::Key &key() const = 0; virtual off_t lstat_size() const = 0; + const blockstore::Key &parentPointer() const { + return _baseBlob->parentPointer(); + } + + void setParentPointer(const blockstore::Key &parentKey) { + return _baseBlob->setParentPointer(parentKey); + } + cpputils::unique_ref releaseBaseBlob() { return std::move(_baseBlob); } diff --git a/src/cryfs/filesystem/fsblobstore/DirBlob.cpp b/src/cryfs/filesystem/fsblobstore/DirBlob.cpp index a029f0d9..aaf13b5c 100644 --- a/src/cryfs/filesystem/fsblobstore/DirBlob.cpp +++ b/src/cryfs/filesystem/fsblobstore/DirBlob.cpp @@ -45,8 +45,8 @@ void DirBlob::flush() { baseBlob().flush(); } -unique_ref DirBlob::InitializeEmptyDir(FsBlobStore *fsBlobStore, unique_ref blob, std::function getLstatSize) { - InitializeBlob(blob.get(), FsBlobView::BlobType::DIR); +unique_ref DirBlob::InitializeEmptyDir(FsBlobStore *fsBlobStore, unique_ref blob, const blockstore::Key &parent, std::function getLstatSize) { + InitializeBlob(blob.get(), FsBlobView::BlobType::DIR, parent); return make_unique_ref(fsBlobStore, std::move(blob), getLstatSize); } diff --git a/src/cryfs/filesystem/fsblobstore/DirBlob.h b/src/cryfs/filesystem/fsblobstore/DirBlob.h index 0851f37d..444b1c64 100644 --- a/src/cryfs/filesystem/fsblobstore/DirBlob.h +++ b/src/cryfs/filesystem/fsblobstore/DirBlob.h @@ -18,6 +18,7 @@ namespace cryfs { constexpr static off_t DIR_LSTAT_SIZE = 4096; static cpputils::unique_ref InitializeEmptyDir(FsBlobStore *fsBlobStore, cpputils::unique_ref blob, + const blockstore::Key &parent, std::function getLstatSize); DirBlob(FsBlobStore *fsBlobStore, cpputils::unique_ref blob, std::function getLstatSize); diff --git a/src/cryfs/filesystem/fsblobstore/FileBlob.cpp b/src/cryfs/filesystem/fsblobstore/FileBlob.cpp index 6f951c04..6aeca632 100644 --- a/src/cryfs/filesystem/fsblobstore/FileBlob.cpp +++ b/src/cryfs/filesystem/fsblobstore/FileBlob.cpp @@ -16,8 +16,8 @@ FileBlob::FileBlob(unique_ref blob) ASSERT(baseBlob().blobType() == FsBlobView::BlobType::FILE, "Loaded blob is not a file"); } -unique_ref FileBlob::InitializeEmptyFile(unique_ref blob) { - InitializeBlob(blob.get(), FsBlobView::BlobType::FILE); +unique_ref FileBlob::InitializeEmptyFile(unique_ref blob, const blockstore::Key &parent) { + InitializeBlob(blob.get(), FsBlobView::BlobType::FILE, parent); return make_unique_ref(std::move(blob)); } diff --git a/src/cryfs/filesystem/fsblobstore/FileBlob.h b/src/cryfs/filesystem/fsblobstore/FileBlob.h index df32fa89..bf781c0b 100644 --- a/src/cryfs/filesystem/fsblobstore/FileBlob.h +++ b/src/cryfs/filesystem/fsblobstore/FileBlob.h @@ -9,7 +9,7 @@ namespace cryfs { class FileBlob final: public FsBlob { public: - static cpputils::unique_ref InitializeEmptyFile(cpputils::unique_ref blob); + static cpputils::unique_ref InitializeEmptyFile(cpputils::unique_ref blob, const blockstore::Key &parent); FileBlob(cpputils::unique_ref blob); diff --git a/src/cryfs/filesystem/fsblobstore/FsBlob.h b/src/cryfs/filesystem/fsblobstore/FsBlob.h index 9178134a..3db3f0d6 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlob.h +++ b/src/cryfs/filesystem/fsblobstore/FsBlob.h @@ -14,6 +14,8 @@ namespace cryfs { virtual off_t lstat_size() const = 0; const blockstore::Key &key() const; + const blockstore::Key &parentPointer() const; + void setParentPointer(const blockstore::Key &parentKey); protected: FsBlob(cpputils::unique_ref baseBlob); @@ -21,7 +23,7 @@ namespace cryfs { FsBlobView &baseBlob(); const FsBlobView &baseBlob() const; - static void InitializeBlob(blobstore::Blob *blob, FsBlobView::BlobType magicNumber); + static void InitializeBlob(blobstore::Blob *blob, FsBlobView::BlobType magicNumber, const blockstore::Key &parent); friend class FsBlobStore; virtual cpputils::unique_ref releaseBaseBlob(); @@ -57,13 +59,21 @@ namespace cryfs { return _baseBlob; } - inline void FsBlob::InitializeBlob(blobstore::Blob *blob, FsBlobView::BlobType magicNumber) { - FsBlobView::InitializeBlob(blob, magicNumber); + inline void FsBlob::InitializeBlob(blobstore::Blob *blob, FsBlobView::BlobType magicNumber, const blockstore::Key &parent) { + FsBlobView::InitializeBlob(blob, magicNumber, parent); } inline cpputils::unique_ref FsBlob::releaseBaseBlob() { return _baseBlob.releaseBaseBlob(); } + + inline const blockstore::Key &FsBlob::parentPointer() const { + return _baseBlob.parentPointer(); + } + + inline void FsBlob::setParentPointer(const blockstore::Key &parentKey) { + return _baseBlob.setParentPointer(parentKey); + } } } diff --git a/src/cryfs/filesystem/fsblobstore/FsBlobStore.h b/src/cryfs/filesystem/fsblobstore/FsBlobStore.h index 3d2ac248..7443a33e 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlobStore.h +++ b/src/cryfs/filesystem/fsblobstore/FsBlobStore.h @@ -17,9 +17,9 @@ namespace cryfs { public: FsBlobStore(cpputils::unique_ref baseBlobStore); - cpputils::unique_ref createFileBlob(); - cpputils::unique_ref createDirBlob(); - cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target); + cpputils::unique_ref createFileBlob(const blockstore::Key &parent); + cpputils::unique_ref createDirBlob(const blockstore::Key &parent); + cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent); boost::optional> load(const blockstore::Key &key); void remove(cpputils::unique_ref blob); uint64_t numBlocks() const; @@ -40,19 +40,19 @@ namespace cryfs { : _baseBlobStore(std::move(baseBlobStore)) { } - inline cpputils::unique_ref FsBlobStore::createFileBlob() { + inline cpputils::unique_ref FsBlobStore::createFileBlob(const blockstore::Key &parent) { auto blob = _baseBlobStore->create(); - return FileBlob::InitializeEmptyFile(std::move(blob)); + return FileBlob::InitializeEmptyFile(std::move(blob), parent); } - inline cpputils::unique_ref FsBlobStore::createDirBlob() { + inline cpputils::unique_ref FsBlobStore::createDirBlob(const blockstore::Key &parent) { auto blob = _baseBlobStore->create(); - return DirBlob::InitializeEmptyDir(this, std::move(blob), _getLstatSize()); + return DirBlob::InitializeEmptyDir(this, std::move(blob), parent, _getLstatSize()); } - inline cpputils::unique_ref FsBlobStore::createSymlinkBlob(const boost::filesystem::path &target) { + inline cpputils::unique_ref FsBlobStore::createSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent) { auto blob = _baseBlobStore->create(); - return SymlinkBlob::InitializeSymlink(std::move(blob), target); + return SymlinkBlob::InitializeSymlink(std::move(blob), target, parent); } inline uint64_t FsBlobStore::numBlocks() const { diff --git a/src/cryfs/filesystem/fsblobstore/FsBlobView.cpp b/src/cryfs/filesystem/fsblobstore/FsBlobView.cpp index c9cb7fbb..e1d2f01b 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlobView.cpp +++ b/src/cryfs/filesystem/fsblobstore/FsBlobView.cpp @@ -2,4 +2,5 @@ namespace cryfs { constexpr uint16_t FsBlobView::FORMAT_VERSION_HEADER; + constexpr unsigned int FsBlobView::HEADER_SIZE; } \ No newline at end of file diff --git a/src/cryfs/filesystem/fsblobstore/FsBlobView.h b/src/cryfs/filesystem/fsblobstore/FsBlobView.h index b29469ab..15af4f52 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlobView.h +++ b/src/cryfs/filesystem/fsblobstore/FsBlobView.h @@ -17,15 +17,18 @@ namespace cryfs { SYMLINK = 0x02 }; - FsBlobView(cpputils::unique_ref baseBlob): _baseBlob(std::move(baseBlob)) { + FsBlobView(cpputils::unique_ref baseBlob): _baseBlob(std::move(baseBlob)), _parentPointer(blockstore::Key::Null()) { _checkHeader(*_baseBlob); + _loadParentPointer(); } - static void InitializeBlob(blobstore::Blob *baseBlob, BlobType blobType) { + static void InitializeBlob(blobstore::Blob *baseBlob, BlobType blobType, const blockstore::Key &parent) { baseBlob->resize(sizeof(FORMAT_VERSION_HEADER) + 1); baseBlob->write(&FORMAT_VERSION_HEADER, 0, sizeof(FORMAT_VERSION_HEADER)); uint8_t blobTypeInt = static_cast(blobType); - baseBlob->write(&blobTypeInt, sizeof(FORMAT_VERSION_HEADER), 1); + baseBlob->write(&blobTypeInt, sizeof(FORMAT_VERSION_HEADER), sizeof(uint8_t)); + baseBlob->write(parent.data(), sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t), blockstore::Key::BINARY_LENGTH); + static_assert(HEADER_SIZE == sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t) + blockstore::Key::BINARY_LENGTH, "If this fails, the header is not initialized correctly in this function."); } static BlobType blobType(const blobstore::Blob &blob) { @@ -37,36 +40,45 @@ namespace cryfs { return _blobType(*_baseBlob); } + const blockstore::Key &parentPointer() const { + return _parentPointer; + } + + void setParentPointer(const blockstore::Key &parentKey) { + _parentPointer = parentKey; + _storeParentPointer(); + } + const blockstore::Key &key() const override { return _baseBlob->key(); } uint64_t size() const override { - return _baseBlob->size() - sizeof(FORMAT_VERSION_HEADER) - 1; + return _baseBlob->size() - HEADER_SIZE; } void resize(uint64_t numBytes) override { - return _baseBlob->resize(numBytes + sizeof(FORMAT_VERSION_HEADER) + 1); + return _baseBlob->resize(numBytes + HEADER_SIZE); } cpputils::Data readAll() const override { cpputils::Data data = _baseBlob->readAll(); - cpputils::Data dataWithoutHeader(data.size() - sizeof(FORMAT_VERSION_HEADER) - 1); + cpputils::Data dataWithoutHeader(data.size() - HEADER_SIZE); //Can we avoid this memcpy? Maybe by having Data::subdata() that returns a reference to the same memory region? Should we? - std::memcpy(dataWithoutHeader.data(), data.dataOffset(sizeof(FORMAT_VERSION_HEADER) + 1), dataWithoutHeader.size()); + std::memcpy(dataWithoutHeader.data(), data.dataOffset(HEADER_SIZE), dataWithoutHeader.size()); return dataWithoutHeader; } void read(void *target, uint64_t offset, uint64_t size) const override { - return _baseBlob->read(target, offset + sizeof(FORMAT_VERSION_HEADER) + 1, size); + return _baseBlob->read(target, offset + HEADER_SIZE, size); } uint64_t tryRead(void *target, uint64_t offset, uint64_t size) const override { - return _baseBlob->tryRead(target, offset + sizeof(FORMAT_VERSION_HEADER) + 1, size); + return _baseBlob->tryRead(target, offset + HEADER_SIZE, size); } void write(const void *source, uint64_t offset, uint64_t size) override { - return _baseBlob->write(source, offset + sizeof(FORMAT_VERSION_HEADER) + 1, size); + return _baseBlob->write(source, offset + HEADER_SIZE, size); } void flush() override { @@ -78,7 +90,8 @@ namespace cryfs { } private: - static constexpr uint16_t FORMAT_VERSION_HEADER = 0; + 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"); @@ -91,11 +104,21 @@ namespace cryfs { static BlobType _blobType(const blobstore::Blob &blob) { uint8_t result; - blob.read(&result, sizeof(FORMAT_VERSION_HEADER), 1); + blob.read(&result, sizeof(FORMAT_VERSION_HEADER), sizeof(uint8_t)); return static_cast(result); } + void _loadParentPointer() { + _baseBlob->read(_parentPointer.data(), sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t), blockstore::Key::BINARY_LENGTH); + } + + void _storeParentPointer() { + _baseBlob->write(_parentPointer.data(), sizeof(FORMAT_VERSION_HEADER) + sizeof(uint8_t), blockstore::Key::BINARY_LENGTH); + } + + cpputils::unique_ref _baseBlob; + blockstore::Key _parentPointer; DISALLOW_COPY_AND_ASSIGN(FsBlobView); }; diff --git a/src/cryfs/filesystem/fsblobstore/SymlinkBlob.cpp b/src/cryfs/filesystem/fsblobstore/SymlinkBlob.cpp index 9dee2a81..09bdcdce 100644 --- a/src/cryfs/filesystem/fsblobstore/SymlinkBlob.cpp +++ b/src/cryfs/filesystem/fsblobstore/SymlinkBlob.cpp @@ -18,8 +18,8 @@ SymlinkBlob::SymlinkBlob(unique_ref blob) ASSERT(baseBlob().blobType() == FsBlobView::BlobType::SYMLINK, "Loaded blob is not a symlink"); } -unique_ref SymlinkBlob::InitializeSymlink(unique_ref blob, const bf::path &target) { - InitializeBlob(blob.get(), FsBlobView::BlobType::SYMLINK); +unique_ref SymlinkBlob::InitializeSymlink(unique_ref blob, const bf::path &target, const blockstore::Key &parent) { + InitializeBlob(blob.get(), FsBlobView::BlobType::SYMLINK, parent); FsBlobView symlinkBlobView(std::move(blob)); string targetStr = target.native(); symlinkBlobView.resize(targetStr.size()); diff --git a/src/cryfs/filesystem/fsblobstore/SymlinkBlob.h b/src/cryfs/filesystem/fsblobstore/SymlinkBlob.h index 19186b4b..1a36f6f7 100644 --- a/src/cryfs/filesystem/fsblobstore/SymlinkBlob.h +++ b/src/cryfs/filesystem/fsblobstore/SymlinkBlob.h @@ -11,7 +11,7 @@ namespace cryfs { class SymlinkBlob final: public FsBlob { public: static cpputils::unique_ref InitializeSymlink(cpputils::unique_ref blob, - const boost::filesystem::path &target); + const boost::filesystem::path &target, const blockstore::Key &parent); SymlinkBlob(cpputils::unique_ref blob); diff --git a/src/cryfs/filesystem/parallelaccessfsblobstore/DirBlobRef.h b/src/cryfs/filesystem/parallelaccessfsblobstore/DirBlobRef.h index 46a42226..42424ae3 100644 --- a/src/cryfs/filesystem/parallelaccessfsblobstore/DirBlobRef.h +++ b/src/cryfs/filesystem/parallelaccessfsblobstore/DirBlobRef.h @@ -92,14 +92,22 @@ public: return _base->AppendChildrenTo(result); } - const blockstore::Key &key() const { + const blockstore::Key &key() const override { return _base->key(); } - off_t lstat_size() const { + off_t lstat_size() const override { return _base->lstat_size(); } + const blockstore::Key &parentPointer() const override { + return _base->parentPointer(); + } + + void setParentPointer(const blockstore::Key &parentKey) override { + return _base->setParentPointer(parentKey); + } + private: cachingfsblobstore::DirBlobRef *_base; diff --git a/src/cryfs/filesystem/parallelaccessfsblobstore/FileBlobRef.h b/src/cryfs/filesystem/parallelaccessfsblobstore/FileBlobRef.h index 26bc6e36..1372a399 100644 --- a/src/cryfs/filesystem/parallelaccessfsblobstore/FileBlobRef.h +++ b/src/cryfs/filesystem/parallelaccessfsblobstore/FileBlobRef.h @@ -32,14 +32,22 @@ public: return _base->flush(); } - const blockstore::Key &key() const { + const blockstore::Key &key() const override { return _base->key(); } - off_t lstat_size() const { + off_t lstat_size() const override { return _base->lstat_size(); } + const blockstore::Key &parentPointer() const override { + return _base->parentPointer(); + } + + void setParentPointer(const blockstore::Key &parentKey) override { + return _base->setParentPointer(parentKey); + } + private: cachingfsblobstore::FileBlobRef *_base; diff --git a/src/cryfs/filesystem/parallelaccessfsblobstore/FsBlobRef.h b/src/cryfs/filesystem/parallelaccessfsblobstore/FsBlobRef.h index 0f77a863..faffb159 100644 --- a/src/cryfs/filesystem/parallelaccessfsblobstore/FsBlobRef.h +++ b/src/cryfs/filesystem/parallelaccessfsblobstore/FsBlobRef.h @@ -13,6 +13,8 @@ public: virtual ~FsBlobRef() {} virtual const blockstore::Key &key() const = 0; virtual off_t lstat_size() const = 0; + virtual const blockstore::Key &parentPointer() const = 0; + virtual void setParentPointer(const blockstore::Key &parentKey) = 0; protected: FsBlobRef() {} diff --git a/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.cpp b/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.cpp index b9178d1e..212a8a4b 100644 --- a/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.cpp +++ b/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.cpp @@ -36,8 +36,8 @@ optional> ParallelAccessFsBlobStore::load(const Key &key) }); } -unique_ref ParallelAccessFsBlobStore::createDirBlob() { - auto blob = _baseBlobStore->createDirBlob(); +unique_ref ParallelAccessFsBlobStore::createDirBlob(const blockstore::Key &parent) { + auto blob = _baseBlobStore->createDirBlob(parent); blob->setLstatSizeGetter(_getLstatSize()); Key key = blob->key(); return _parallelAccessStore.add(key, std::move(blob), [] (cachingfsblobstore::FsBlobRef *resource) { @@ -47,8 +47,8 @@ unique_ref ParallelAccessFsBlobStore::createDirBlob() { }); } -unique_ref ParallelAccessFsBlobStore::createFileBlob() { - auto blob = _baseBlobStore->createFileBlob(); +unique_ref ParallelAccessFsBlobStore::createFileBlob(const blockstore::Key &parent) { + auto blob = _baseBlobStore->createFileBlob(parent); Key key = blob->key(); return _parallelAccessStore.add(key, std::move(blob), [] (cachingfsblobstore::FsBlobRef *resource) { auto fileBlob = dynamic_cast(resource); @@ -57,8 +57,8 @@ unique_ref ParallelAccessFsBlobStore::createFileBlob() { }); } -unique_ref ParallelAccessFsBlobStore::createSymlinkBlob(const bf::path &target) { - auto blob = _baseBlobStore->createSymlinkBlob(target); +unique_ref ParallelAccessFsBlobStore::createSymlinkBlob(const bf::path &target, const blockstore::Key &parent) { + auto blob = _baseBlobStore->createSymlinkBlob(target, parent); Key key = blob->key(); return _parallelAccessStore.add(key, std::move(blob), [] (cachingfsblobstore::FsBlobRef *resource) { auto symlinkBlob = dynamic_cast(resource); diff --git a/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.h b/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.h index 36beac14..d011ac88 100644 --- a/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.h +++ b/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.h @@ -21,9 +21,9 @@ namespace cryfs { public: ParallelAccessFsBlobStore(cpputils::unique_ref baseBlobStore); - cpputils::unique_ref createFileBlob(); - cpputils::unique_ref createDirBlob(); - cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target); + cpputils::unique_ref createFileBlob(const blockstore::Key &parent); + cpputils::unique_ref createDirBlob(const blockstore::Key &parent); + cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent); boost::optional> load(const blockstore::Key &key); void remove(cpputils::unique_ref blob); uint64_t virtualBlocksizeBytes() const; diff --git a/src/cryfs/filesystem/parallelaccessfsblobstore/SymlinkBlobRef.h b/src/cryfs/filesystem/parallelaccessfsblobstore/SymlinkBlobRef.h index 61a94b4e..e8179da1 100644 --- a/src/cryfs/filesystem/parallelaccessfsblobstore/SymlinkBlobRef.h +++ b/src/cryfs/filesystem/parallelaccessfsblobstore/SymlinkBlobRef.h @@ -16,14 +16,22 @@ public: return _base->target(); } - const blockstore::Key &key() const { + const blockstore::Key &key() const override { return _base->key(); } - off_t lstat_size() const { + off_t lstat_size() const override { return _base->lstat_size(); } + const blockstore::Key &parentPointer() const override { + return _base->parentPointer(); + } + + void setParentPointer(const blockstore::Key &parentKey) override { + return _base->setParentPointer(parentKey); + } + private: cachingfsblobstore::SymlinkBlobRef *_base; diff --git a/test/cryfs/filesystem/CryNodeTest.cpp b/test/cryfs/filesystem/CryNodeTest.cpp index ffe7bad1..be9f0ef9 100644 --- a/test/cryfs/filesystem/CryNodeTest.cpp +++ b/test/cryfs/filesystem/CryNodeTest.cpp @@ -23,6 +23,22 @@ public: auto createdFile = device().Load(path).value(); return dynamic_pointer_move(createdFile).value(); } + + unique_ref CreateDir(const bf::path &path) { + auto _parentDir = device().Load(path.parent_path()).value(); + auto parentDir = dynamic_pointer_move(_parentDir).value(); + parentDir->createDir(path.filename().native(), MODE_PUBLIC, 0, 0); + auto createdDir = device().Load(path).value(); + return dynamic_pointer_move(createdDir).value(); + } + + unique_ref CreateSymlink(const bf::path &path) { + auto _parentDir = device().Load(path.parent_path()).value(); + auto parentDir = dynamic_pointer_move(_parentDir).value(); + parentDir->createSymlink(path.filename().native(), "/target", 0, 0); + auto createdSymlink = device().Load(path).value(); + return dynamic_pointer_move(createdSymlink).value(); + } }; TEST_F(CryNodeTest, Rename_DoesntLeaveBlocksOver) { @@ -41,3 +57,24 @@ TEST_F(CryNodeTest, Rename_Overwrite_DoesntLeaveBlocksOver) { node->rename("/newexistingname"); EXPECT_EQ(2u, device().numBlocks()); // Only the blocks of one file are left } + +TEST_F(CryNodeTest, Rename_UpdatesParentPointers_File) { + this->CreateDir("/mydir"); + auto node = this->CreateFile("/oldname"); + node->rename("/mydir/newname"); + EXPECT_TRUE(node->checkParentPointer()); +} + +TEST_F(CryNodeTest, Rename_UpdatesParentPointers_Dir) { + this->CreateDir("/mydir"); + auto node = this->CreateDir("/oldname"); + node->rename("/mydir/newname"); + EXPECT_TRUE(node->checkParentPointer()); +} + +TEST_F(CryNodeTest, Rename_UpdatesParentPointers_Symlink) { + this->CreateDir("/mydir"); + auto node = this->CreateSymlink("/oldname"); + node->rename("/mydir/newname"); + EXPECT_TRUE(node->checkParentPointer()); +}