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.
This commit is contained in:
parent
edc542e3c5
commit
397de9372f
@ -96,7 +96,7 @@ unique_ref<BlockStore> 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<FsBlobRef> 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<DirBlobRef>(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<FileBlobRef> CryDevice::CreateFileBlob() {
|
||||
return _fsBlobStore->createFileBlob();
|
||||
unique_ref<FileBlobRef> CryDevice::CreateFileBlob(const blockstore::Key &parent) {
|
||||
return _fsBlobStore->createFileBlob(parent);
|
||||
}
|
||||
|
||||
unique_ref<DirBlobRef> CryDevice::CreateDirBlob() {
|
||||
return _fsBlobStore->createDirBlob();
|
||||
unique_ref<DirBlobRef> CryDevice::CreateDirBlob(const blockstore::Key &parent) {
|
||||
return _fsBlobStore->createDirBlob(parent);
|
||||
}
|
||||
|
||||
unique_ref<SymlinkBlobRef> CryDevice::CreateSymlinkBlob(const bf::path &target) {
|
||||
return _fsBlobStore->createSymlinkBlob(target);
|
||||
unique_ref<SymlinkBlobRef> CryDevice::CreateSymlinkBlob(const bf::path &target, const blockstore::Key &parent) {
|
||||
return _fsBlobStore->createSymlinkBlob(target, parent);
|
||||
}
|
||||
|
||||
unique_ref<FsBlobRef> CryDevice::LoadBlob(const blockstore::Key &key) {
|
||||
|
@ -21,9 +21,9 @@ public:
|
||||
|
||||
void statfs(const boost::filesystem::path &path, struct ::statvfs *fsstat) override;
|
||||
|
||||
cpputils::unique_ref<parallelaccessfsblobstore::FileBlobRef> CreateFileBlob();
|
||||
cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> CreateDirBlob();
|
||||
cpputils::unique_ref<parallelaccessfsblobstore::SymlinkBlobRef> CreateSymlinkBlob(const boost::filesystem::path &target);
|
||||
cpputils::unique_ref<parallelaccessfsblobstore::FileBlobRef> CreateFileBlob(const blockstore::Key &parent);
|
||||
cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> CreateDirBlob(const blockstore::Key &parent);
|
||||
cpputils::unique_ref<parallelaccessfsblobstore::SymlinkBlobRef> CreateSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent);
|
||||
cpputils::unique_ref<parallelaccessfsblobstore::FsBlobRef> LoadBlob(const blockstore::Key &key);
|
||||
struct DirBlobWithParent {
|
||||
cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> blob;
|
||||
|
@ -43,7 +43,7 @@ unique_ref<fspp::OpenFile> 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);
|
||||
}
|
||||
|
@ -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<FsBlobRef> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -19,9 +19,9 @@ namespace cryfs {
|
||||
CachingFsBlobStore(cpputils::unique_ref<fsblobstore::FsBlobStore> baseBlobStore);
|
||||
~CachingFsBlobStore();
|
||||
|
||||
cpputils::unique_ref<FileBlobRef> createFileBlob();
|
||||
cpputils::unique_ref<DirBlobRef> createDirBlob();
|
||||
cpputils::unique_ref<SymlinkBlobRef> createSymlinkBlob(const boost::filesystem::path &target);
|
||||
cpputils::unique_ref<FileBlobRef> createFileBlob(const blockstore::Key &parent);
|
||||
cpputils::unique_ref<DirBlobRef> createDirBlob(const blockstore::Key &parent);
|
||||
cpputils::unique_ref<SymlinkBlobRef> createSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent);
|
||||
boost::optional<cpputils::unique_ref<FsBlobRef>> load(const blockstore::Key &key);
|
||||
void remove(cpputils::unique_ref<FsBlobRef> blob);
|
||||
uint64_t virtualBlocksizeBytes() const;
|
||||
@ -50,25 +50,25 @@ namespace cryfs {
|
||||
inline CachingFsBlobStore::~CachingFsBlobStore() {
|
||||
}
|
||||
|
||||
inline cpputils::unique_ref<FileBlobRef> CachingFsBlobStore::createFileBlob() {
|
||||
inline cpputils::unique_ref<FileBlobRef> 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<FileBlobRef>(_baseBlobStore->createFileBlob(), this);
|
||||
return cpputils::make_unique_ref<FileBlobRef>(_baseBlobStore->createFileBlob(parent), this);
|
||||
}
|
||||
|
||||
inline cpputils::unique_ref<DirBlobRef> CachingFsBlobStore::createDirBlob() {
|
||||
inline cpputils::unique_ref<DirBlobRef> 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<DirBlobRef>(_baseBlobStore->createDirBlob(), this);
|
||||
return cpputils::make_unique_ref<DirBlobRef>(_baseBlobStore->createDirBlob(parent), this);
|
||||
}
|
||||
|
||||
inline cpputils::unique_ref<SymlinkBlobRef> CachingFsBlobStore::createSymlinkBlob(const boost::filesystem::path &target) {
|
||||
inline cpputils::unique_ref<SymlinkBlobRef> 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<SymlinkBlobRef>(_baseBlobStore->createSymlinkBlob(target), this);
|
||||
return cpputils::make_unique_ref<SymlinkBlobRef>(_baseBlobStore->createSymlinkBlob(target, parent), this);
|
||||
}
|
||||
|
||||
inline void CachingFsBlobStore::remove(cpputils::unique_ref<FsBlobRef> blob) {
|
||||
|
@ -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<fsblobstore::FsBlob> releaseBaseBlob() {
|
||||
return std::move(_baseBlob);
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ void DirBlob::flush() {
|
||||
baseBlob().flush();
|
||||
}
|
||||
|
||||
unique_ref<DirBlob> DirBlob::InitializeEmptyDir(FsBlobStore *fsBlobStore, unique_ref<Blob> blob, std::function<off_t(const blockstore::Key&)> getLstatSize) {
|
||||
InitializeBlob(blob.get(), FsBlobView::BlobType::DIR);
|
||||
unique_ref<DirBlob> DirBlob::InitializeEmptyDir(FsBlobStore *fsBlobStore, unique_ref<Blob> blob, const blockstore::Key &parent, std::function<off_t(const blockstore::Key&)> getLstatSize) {
|
||||
InitializeBlob(blob.get(), FsBlobView::BlobType::DIR, parent);
|
||||
return make_unique_ref<DirBlob>(fsBlobStore, std::move(blob), getLstatSize);
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ namespace cryfs {
|
||||
constexpr static off_t DIR_LSTAT_SIZE = 4096;
|
||||
|
||||
static cpputils::unique_ref<DirBlob> InitializeEmptyDir(FsBlobStore *fsBlobStore, cpputils::unique_ref<blobstore::Blob> blob,
|
||||
const blockstore::Key &parent,
|
||||
std::function<off_t (const blockstore::Key&)> getLstatSize);
|
||||
|
||||
DirBlob(FsBlobStore *fsBlobStore, cpputils::unique_ref<blobstore::Blob> blob, std::function<off_t (const blockstore::Key&)> getLstatSize);
|
||||
|
@ -16,8 +16,8 @@ FileBlob::FileBlob(unique_ref<Blob> blob)
|
||||
ASSERT(baseBlob().blobType() == FsBlobView::BlobType::FILE, "Loaded blob is not a file");
|
||||
}
|
||||
|
||||
unique_ref<FileBlob> FileBlob::InitializeEmptyFile(unique_ref<Blob> blob) {
|
||||
InitializeBlob(blob.get(), FsBlobView::BlobType::FILE);
|
||||
unique_ref<FileBlob> FileBlob::InitializeEmptyFile(unique_ref<Blob> blob, const blockstore::Key &parent) {
|
||||
InitializeBlob(blob.get(), FsBlobView::BlobType::FILE, parent);
|
||||
return make_unique_ref<FileBlob>(std::move(blob));
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ namespace cryfs {
|
||||
|
||||
class FileBlob final: public FsBlob {
|
||||
public:
|
||||
static cpputils::unique_ref<FileBlob> InitializeEmptyFile(cpputils::unique_ref<blobstore::Blob> blob);
|
||||
static cpputils::unique_ref<FileBlob> InitializeEmptyFile(cpputils::unique_ref<blobstore::Blob> blob, const blockstore::Key &parent);
|
||||
|
||||
FileBlob(cpputils::unique_ref<blobstore::Blob> blob);
|
||||
|
||||
|
@ -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<blobstore::Blob> 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<blobstore::Blob> 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<blobstore::Blob> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,9 @@ namespace cryfs {
|
||||
public:
|
||||
FsBlobStore(cpputils::unique_ref<blobstore::BlobStore> baseBlobStore);
|
||||
|
||||
cpputils::unique_ref<FileBlob> createFileBlob();
|
||||
cpputils::unique_ref<DirBlob> createDirBlob();
|
||||
cpputils::unique_ref<SymlinkBlob> createSymlinkBlob(const boost::filesystem::path &target);
|
||||
cpputils::unique_ref<FileBlob> createFileBlob(const blockstore::Key &parent);
|
||||
cpputils::unique_ref<DirBlob> createDirBlob(const blockstore::Key &parent);
|
||||
cpputils::unique_ref<SymlinkBlob> createSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent);
|
||||
boost::optional<cpputils::unique_ref<FsBlob>> load(const blockstore::Key &key);
|
||||
void remove(cpputils::unique_ref<FsBlob> blob);
|
||||
uint64_t numBlocks() const;
|
||||
@ -40,19 +40,19 @@ namespace cryfs {
|
||||
: _baseBlobStore(std::move(baseBlobStore)) {
|
||||
}
|
||||
|
||||
inline cpputils::unique_ref<FileBlob> FsBlobStore::createFileBlob() {
|
||||
inline cpputils::unique_ref<FileBlob> 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<DirBlob> FsBlobStore::createDirBlob() {
|
||||
inline cpputils::unique_ref<DirBlob> 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<SymlinkBlob> FsBlobStore::createSymlinkBlob(const boost::filesystem::path &target) {
|
||||
inline cpputils::unique_ref<SymlinkBlob> 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 {
|
||||
|
@ -2,4 +2,5 @@
|
||||
|
||||
namespace cryfs {
|
||||
constexpr uint16_t FsBlobView::FORMAT_VERSION_HEADER;
|
||||
constexpr unsigned int FsBlobView::HEADER_SIZE;
|
||||
}
|
@ -17,15 +17,18 @@ namespace cryfs {
|
||||
SYMLINK = 0x02
|
||||
};
|
||||
|
||||
FsBlobView(cpputils::unique_ref<blobstore::Blob> baseBlob): _baseBlob(std::move(baseBlob)) {
|
||||
FsBlobView(cpputils::unique_ref<blobstore::Blob> 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<uint8_t>(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<BlobType>(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<blobstore::Blob> _baseBlob;
|
||||
blockstore::Key _parentPointer;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FsBlobView);
|
||||
};
|
||||
|
@ -18,8 +18,8 @@ SymlinkBlob::SymlinkBlob(unique_ref<Blob> blob)
|
||||
ASSERT(baseBlob().blobType() == FsBlobView::BlobType::SYMLINK, "Loaded blob is not a symlink");
|
||||
}
|
||||
|
||||
unique_ref<SymlinkBlob> SymlinkBlob::InitializeSymlink(unique_ref<Blob> blob, const bf::path &target) {
|
||||
InitializeBlob(blob.get(), FsBlobView::BlobType::SYMLINK);
|
||||
unique_ref<SymlinkBlob> SymlinkBlob::InitializeSymlink(unique_ref<Blob> 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());
|
||||
|
@ -11,7 +11,7 @@ namespace cryfs {
|
||||
class SymlinkBlob final: public FsBlob {
|
||||
public:
|
||||
static cpputils::unique_ref<SymlinkBlob> InitializeSymlink(cpputils::unique_ref<blobstore::Blob> blob,
|
||||
const boost::filesystem::path &target);
|
||||
const boost::filesystem::path &target, const blockstore::Key &parent);
|
||||
|
||||
SymlinkBlob(cpputils::unique_ref<blobstore::Blob> blob);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -36,8 +36,8 @@ optional<unique_ref<FsBlobRef>> ParallelAccessFsBlobStore::load(const Key &key)
|
||||
});
|
||||
}
|
||||
|
||||
unique_ref<DirBlobRef> ParallelAccessFsBlobStore::createDirBlob() {
|
||||
auto blob = _baseBlobStore->createDirBlob();
|
||||
unique_ref<DirBlobRef> ParallelAccessFsBlobStore::createDirBlob(const blockstore::Key &parent) {
|
||||
auto blob = _baseBlobStore->createDirBlob(parent);
|
||||
blob->setLstatSizeGetter(_getLstatSize());
|
||||
Key key = blob->key();
|
||||
return _parallelAccessStore.add<DirBlobRef>(key, std::move(blob), [] (cachingfsblobstore::FsBlobRef *resource) {
|
||||
@ -47,8 +47,8 @@ unique_ref<DirBlobRef> ParallelAccessFsBlobStore::createDirBlob() {
|
||||
});
|
||||
}
|
||||
|
||||
unique_ref<FileBlobRef> ParallelAccessFsBlobStore::createFileBlob() {
|
||||
auto blob = _baseBlobStore->createFileBlob();
|
||||
unique_ref<FileBlobRef> ParallelAccessFsBlobStore::createFileBlob(const blockstore::Key &parent) {
|
||||
auto blob = _baseBlobStore->createFileBlob(parent);
|
||||
Key key = blob->key();
|
||||
return _parallelAccessStore.add<FileBlobRef>(key, std::move(blob), [] (cachingfsblobstore::FsBlobRef *resource) {
|
||||
auto fileBlob = dynamic_cast<cachingfsblobstore::FileBlobRef*>(resource);
|
||||
@ -57,8 +57,8 @@ unique_ref<FileBlobRef> ParallelAccessFsBlobStore::createFileBlob() {
|
||||
});
|
||||
}
|
||||
|
||||
unique_ref<SymlinkBlobRef> ParallelAccessFsBlobStore::createSymlinkBlob(const bf::path &target) {
|
||||
auto blob = _baseBlobStore->createSymlinkBlob(target);
|
||||
unique_ref<SymlinkBlobRef> ParallelAccessFsBlobStore::createSymlinkBlob(const bf::path &target, const blockstore::Key &parent) {
|
||||
auto blob = _baseBlobStore->createSymlinkBlob(target, parent);
|
||||
Key key = blob->key();
|
||||
return _parallelAccessStore.add<SymlinkBlobRef>(key, std::move(blob), [] (cachingfsblobstore::FsBlobRef *resource) {
|
||||
auto symlinkBlob = dynamic_cast<cachingfsblobstore::SymlinkBlobRef*>(resource);
|
||||
|
@ -21,9 +21,9 @@ namespace cryfs {
|
||||
public:
|
||||
ParallelAccessFsBlobStore(cpputils::unique_ref<cachingfsblobstore::CachingFsBlobStore> baseBlobStore);
|
||||
|
||||
cpputils::unique_ref<FileBlobRef> createFileBlob();
|
||||
cpputils::unique_ref<DirBlobRef> createDirBlob();
|
||||
cpputils::unique_ref<SymlinkBlobRef> createSymlinkBlob(const boost::filesystem::path &target);
|
||||
cpputils::unique_ref<FileBlobRef> createFileBlob(const blockstore::Key &parent);
|
||||
cpputils::unique_ref<DirBlobRef> createDirBlob(const blockstore::Key &parent);
|
||||
cpputils::unique_ref<SymlinkBlobRef> createSymlinkBlob(const boost::filesystem::path &target, const blockstore::Key &parent);
|
||||
boost::optional<cpputils::unique_ref<FsBlobRef>> load(const blockstore::Key &key);
|
||||
void remove(cpputils::unique_ref<FsBlobRef> blob);
|
||||
uint64_t virtualBlocksizeBytes() const;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -23,6 +23,22 @@ public:
|
||||
auto createdFile = device().Load(path).value();
|
||||
return dynamic_pointer_move<CryNode>(createdFile).value();
|
||||
}
|
||||
|
||||
unique_ref<CryNode> CreateDir(const bf::path &path) {
|
||||
auto _parentDir = device().Load(path.parent_path()).value();
|
||||
auto parentDir = dynamic_pointer_move<CryDir>(_parentDir).value();
|
||||
parentDir->createDir(path.filename().native(), MODE_PUBLIC, 0, 0);
|
||||
auto createdDir = device().Load(path).value();
|
||||
return dynamic_pointer_move<CryNode>(createdDir).value();
|
||||
}
|
||||
|
||||
unique_ref<CryNode> CreateSymlink(const bf::path &path) {
|
||||
auto _parentDir = device().Load(path.parent_path()).value();
|
||||
auto parentDir = dynamic_pointer_move<CryDir>(_parentDir).value();
|
||||
parentDir->createSymlink(path.filename().native(), "/target", 0, 0);
|
||||
auto createdSymlink = device().Load(path).value();
|
||||
return dynamic_pointer_move<CryNode>(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());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user