CryDevice::BlobWithParent CryDevice::LoadBlobWithParent(const bf::path &path) { optional<unique_ref<DirBlobRef>> parentBlob = none; optional<unique_ref<FsBlobRef>> currentBlobOpt = _fsBlobStore->load(_rootKey); if (currentBlobOpt == none) { LOG(ERROR) << "Could not load root blob. Is the base directory accessible?"; throw FuseErrnoException(EIO); } unique_ref<FsBlobRef> currentBlob = std::move(*currentBlobOpt); for (const bf::path &component : path.relative_path()) { auto currentDir = dynamic_pointer_move<DirBlobRef>(currentBlob); if (currentDir == none) { throw FuseErrnoException(ENOTDIR); // Path component is not a dir } auto childOpt = (*currentDir)->GetChild(component.c_str()); if (childOpt == boost::none) { throw FuseErrnoException(ENOENT); // Child entry in directory not found } Key childKey = childOpt->key(); auto nextBlob = _fsBlobStore->load(childKey); if (nextBlob == none) { throw FuseErrnoException(ENOENT); // Blob for directory entry not found } parentBlob = std::move(*currentDir); currentBlob = std::move(*nextBlob); } return BlobWithParent{std::move(currentBlob), std::move(parentBlob)}; //TODO (I think this is resolved, but I should test it) // Running the python script, waiting for "Create files in sequential order...", then going into dir ~/tmp/cryfs-mount-.../Bonnie.../ and calling "ls" // crashes cryfs with a sigsegv. // Possible reason: Many parallel changes to a directory blob are a race condition. Need something like ParallelAccessStore! }
void CryNode::rename(const bf::path &to) { device()->callFsActionCallbacks(); if (_parent == none) { //We are the root direcory. throw FuseErrnoException(EBUSY); } auto targetDirWithParent = _device->LoadDirBlobWithParent(to.parent_path()); auto targetDir = std::move(targetDirWithParent.blob); auto targetDirParent = std::move(targetDirWithParent.parent); auto old = (*_parent)->GetChild(_key); if (old == boost::none) { throw FuseErrnoException(EIO); } fsblobstore::DirEntry oldEntry = *old; // Copying this (instead of only keeping the reference) is necessary, because the operations below (i.e. RenameChild()) might make a reference invalid. auto onOverwritten = [this] (const blockstore::Key &key) { device()->RemoveBlob(key); }; _updateParentModificationTimestamp(); if (targetDir->key() == (*_parent)->key()) { targetDir->RenameChild(oldEntry.key(), to.filename().native(), onOverwritten); } else { _updateTargetDirModificationTimestamp(*targetDir, std::move(targetDirParent)); targetDir->AddOrOverwriteChild(to.filename().native(), oldEntry.key(), oldEntry.type(), oldEntry.mode(), oldEntry.uid(), oldEntry.gid(), 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. _parent = cpputils::to_unique_ptr(std::move(targetDir)); } }
void CryDevice::RemoveBlob(const blockstore::Key &key) { auto blob = _fsBlobStore->load(key); if (blob == none) { LOG(ERROR) << "Could not load blob " << key.ToString() << ". Is the base directory accessible?"; throw FuseErrnoException(EIO); } _fsBlobStore->remove(std::move(*blob)); }
unique_ref<FsBlobRef> CryDevice::LoadBlob(const blockstore::Key &key) { auto blob = _fsBlobStore->load(key); if (blob == none) { LOG(ERROR) << "Could not load blob " << key.ToString() << ". Is the base directory accessible?"; throw FuseErrnoException(EIO); } return std::move(*blob); }
CryDevice::DirBlobWithParent CryDevice::LoadDirBlobWithParent(const bf::path &path) { auto blob = LoadBlobWithParent(path); auto dir = dynamic_pointer_move<DirBlobRef>(blob.blob); if (dir == none) { throw FuseErrnoException(ENOTDIR); // Loaded blob is not a directory } return DirBlobWithParent{std::move(*dir), std::move(blob.parent)}; }
void CryNode::chown(uid_t uid, gid_t gid) { device()->callFsActionCallbacks(); if (_parent == none) { //We are the root direcory. //TODO What should we do? throw FuseErrnoException(EIO); } (*_parent)->chownChild(_key, uid, gid); }
void CryNode::chmod(mode_t mode) { device()->callFsActionCallbacks(); if (_parent == none) { //We are the root direcory. //TODO What should we do? throw FuseErrnoException(EIO); } (*_parent)->chmodChild(_key, mode); }
void CryNode::utimens(timespec lastAccessTime, timespec lastModificationTime) { device()->callFsActionCallbacks(); if (_parent == none) { //We are the root direcory. //TODO What should we do? throw FuseErrnoException(EIO); } (*_parent)->utimensChild(_key, lastAccessTime, lastModificationTime); }
void CryNode::removeNode() { //TODO Instead of all these if-else and having _parent being an optional, we could also introduce a CryRootDir which inherits from fspp::Dir. if (_parent == none) { //We are the root direcory. //TODO What should we do? throw FuseErrnoException(EIO); } (*_parent)->RemoveChild(_key); _device->RemoveBlob(_key); }
void CryNode::rename(const bf::path &to) { device()->callFsActionCallbacks(); if (_parent == none) { //We are the root direcory. //TODO What should we do? throw FuseErrnoException(EIO); } //TODO More efficient implementation possible: directly rename when it's actually not moved to a different directory // It's also quite ugly code because in the parent==targetDir case, it depends on _parent not overriding the changes made by targetDir. auto old = (*_parent)->GetChild(_key); auto mode = old.mode; auto uid = old.uid; auto gid = old.gid; (*_parent)->RemoveChild(_key); (*_parent)->flush(); auto targetDir = _device->LoadDirBlob(to.parent_path()); targetDir->AddChild(to.filename().native(), _key, getType(), mode, uid, gid); }
void CryNode::utimens(const timespec times[2]) { device()->callFsActionCallbacks(); //TODO throw FuseErrnoException(ENOTSUP); }
void CryNode::access(int mask) const { device()->callFsActionCallbacks(); //TODO return; throw FuseErrnoException(ENOTSUP); }