- Refactor DirBlob: Keep an in-memory vector of the dir entries instead of regularly parsing it
- Implement file deletion and dir deletion
This commit is contained in:
parent
787d4f5382
commit
9ecbe437ab
@ -58,15 +58,15 @@ unique_ptr<fspp::Node> CryDevice::Load(const bf::path &path) {
|
||||
|
||||
if (path.parent_path().empty()) {
|
||||
//We are asked to load the root directory '/'.
|
||||
return make_unique<CryDir>(this, _rootKey);
|
||||
return make_unique<CryDir>(this, nullptr, _rootKey);
|
||||
}
|
||||
auto parent = LoadDirBlob(path.parent_path());
|
||||
auto entry = parent->GetChild(path.filename().native());
|
||||
|
||||
if (entry.first == fspp::Dir::EntryType::DIR) {
|
||||
return make_unique<CryDir>(this, entry.second);
|
||||
} else if (entry.first == fspp::Dir::EntryType::FILE) {
|
||||
return make_unique<CryFile>(this, std::move(parent), entry.second);
|
||||
if (entry.type == fspp::Dir::EntryType::DIR) {
|
||||
return make_unique<CryDir>(this, std::move(parent), entry.key);
|
||||
} else if (entry.type == fspp::Dir::EntryType::FILE) {
|
||||
return make_unique<CryFile>(this, std::move(parent), entry.key);
|
||||
} else {
|
||||
throw FuseErrnoException(EIO);
|
||||
}
|
||||
@ -81,7 +81,7 @@ unique_ptr<DirBlob> CryDevice::LoadDirBlob(const bf::path &path) {
|
||||
// But fuse should rather return the correct error code.
|
||||
unique_ptr<DirBlob> currentDir = make_unique<DirBlob>(std::move(currentBlob));
|
||||
|
||||
Key childKey = currentDir->GetChild(component.c_str()).second;
|
||||
Key childKey = currentDir->GetChild(component.c_str()).key;
|
||||
currentBlob = _blobStore->load(childKey);
|
||||
}
|
||||
|
||||
@ -100,4 +100,8 @@ unique_ptr<blobstore::Blob> CryDevice::LoadBlob(const blockstore::Key &key) {
|
||||
return _blobStore->load(key);
|
||||
}
|
||||
|
||||
void CryDevice::RemoveBlob(const blockstore::Key &key) {
|
||||
_blobStore->remove(_blobStore->load(key));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ public:
|
||||
|
||||
std::unique_ptr<blobstore::Blob> CreateBlob();
|
||||
std::unique_ptr<blobstore::Blob> LoadBlob(const blockstore::Key &key);
|
||||
void RemoveBlob(const blockstore::Key &key);
|
||||
|
||||
private:
|
||||
blockstore::Key GetOrCreateRootKey(CryConfig *config);
|
||||
|
@ -25,8 +25,8 @@ using blockstore::Key;
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
CryDir::CryDir(CryDevice *device, const Key &key)
|
||||
: _device(device), _key(key) {
|
||||
CryDir::CryDir(CryDevice *device, unique_ptr<DirBlob> parent, const Key &key)
|
||||
: _device(device), _parent(std::move(parent)), _key(key) {
|
||||
}
|
||||
|
||||
CryDir::~CryDir() {
|
||||
@ -61,7 +61,8 @@ unique_ptr<DirBlob> CryDir::LoadBlob() const {
|
||||
}
|
||||
|
||||
void CryDir::rmdir() {
|
||||
throw FuseErrnoException(ENOTSUP);
|
||||
_parent->RemoveChild(_key);
|
||||
_device->RemoveBlob(_key);
|
||||
}
|
||||
|
||||
unique_ptr<vector<fspp::Dir::Entry>> CryDir::children() const {
|
||||
|
@ -10,7 +10,7 @@ namespace cryfs {
|
||||
|
||||
class CryDir: public fspp::Dir, CryNode {
|
||||
public:
|
||||
CryDir(CryDevice *device, const blockstore::Key &key);
|
||||
CryDir(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key);
|
||||
virtual ~CryDir();
|
||||
|
||||
void stat(struct ::stat *result) const override;
|
||||
@ -24,6 +24,7 @@ public:
|
||||
|
||||
private:
|
||||
CryDevice *_device;
|
||||
std::unique_ptr<DirBlob> _parent;
|
||||
blockstore::Key _key;
|
||||
|
||||
std::unique_ptr<DirBlob> LoadBlob() const;
|
||||
|
@ -46,7 +46,8 @@ void CryFile::truncate(off_t size) const {
|
||||
}
|
||||
|
||||
void CryFile::unlink() {
|
||||
throw FuseErrnoException(ENOTSUP);
|
||||
_parent->RemoveChild(_key);
|
||||
_device->RemoveBlob(_key);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,23 +18,31 @@ using blobstore::Blob;
|
||||
using blockstore::Key;
|
||||
using blockstore::Data;
|
||||
|
||||
//TODO Refactor: Keep a parsed dir structure (list of entries and blob keys they're pointing to) in memory and serialize/deserialize it
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
DirBlob::DirBlob(unique_ptr<Blob> blob)
|
||||
: _blob(std::move(blob)) {
|
||||
DirBlob::DirBlob(unique_ptr<Blob> blob) :
|
||||
_blob(std::move(blob)), _entries(), _changed(false) {
|
||||
assert(magicNumber() == MagicNumbers::DIR);
|
||||
_readEntriesFromBlob();
|
||||
}
|
||||
|
||||
DirBlob::~DirBlob() {
|
||||
flush();
|
||||
}
|
||||
|
||||
void DirBlob::flush() {
|
||||
if (_changed) {
|
||||
_writeEntriesToBlob();
|
||||
_changed = false;
|
||||
}
|
||||
_blob->flush();
|
||||
}
|
||||
|
||||
unique_ptr<DirBlob> DirBlob::InitializeEmptyDir(unique_ptr<Blob> blob) {
|
||||
blob->resize(1);
|
||||
unsigned char magicNumber = MagicNumbers::DIR;
|
||||
blob->write(&magicNumber, 0, 1);
|
||||
return make_unique<DirBlob>(std::move(blob));
|
||||
return make_unique < DirBlob > (std::move(blob));
|
||||
}
|
||||
|
||||
unsigned char DirBlob::magicNumber() const {
|
||||
@ -43,39 +51,57 @@ unsigned char DirBlob::magicNumber() const {
|
||||
return number;
|
||||
}
|
||||
|
||||
void DirBlob::AppendChildrenTo(vector<fspp::Dir::Entry> *result) const {
|
||||
Data entries(_blob->size()-1);
|
||||
_blob->read(entries.data(), 1, _blob->size()-1);
|
||||
|
||||
const char *pos = (const char*)entries.data();
|
||||
while(pos < (const char*)entries.data()+entries.size()) {
|
||||
pos = readAndAddNextChild(pos, result);
|
||||
void DirBlob::_writeEntriesToBlob() {
|
||||
//TODO Resizing is imperformant
|
||||
_blob->resize(1);
|
||||
unsigned int offset = 1;
|
||||
for (const auto &entry : _entries) {
|
||||
unsigned char entryTypeMagicNumber = static_cast<unsigned char>(entry.type);
|
||||
_blob->write(&entryTypeMagicNumber, offset, 1);
|
||||
offset += 1;
|
||||
_blob->write(entry.name.c_str(), offset, entry.name.size() + 1);
|
||||
offset += entry.name.size() + 1;
|
||||
string keystr = entry.key.ToString();
|
||||
_blob->write(keystr.c_str(), offset, keystr.size() + 1);
|
||||
offset += keystr.size() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void DirBlob::_readEntriesFromBlob() {
|
||||
_entries.clear();
|
||||
Data data(_blob->size() - 1);
|
||||
_blob->read(data.data(), 1, _blob->size() - 1);
|
||||
|
||||
const char *pos = (const char*) data.data();
|
||||
while (pos < (const char*) data.data() + data.size()) {
|
||||
pos = readAndAddNextChild(pos, &_entries);
|
||||
}
|
||||
}
|
||||
|
||||
const char *DirBlob::readAndAddNextChild(const char *pos,
|
||||
vector<DirBlob::Entry> *result) const {
|
||||
// Read type magic number (whether it is a dir or a file)
|
||||
fspp::Dir::EntryType type =
|
||||
static_cast<fspp::Dir::EntryType>(*reinterpret_cast<const unsigned char*>(pos));
|
||||
pos += 1;
|
||||
|
||||
size_t namelength = strlen(pos);
|
||||
std::string name(pos, namelength);
|
||||
pos += namelength + 1;
|
||||
|
||||
size_t keylength = strlen(pos);
|
||||
std::string keystr(pos, keylength);
|
||||
pos += keylength + 1;
|
||||
|
||||
result->emplace_back(type, name, Key::FromString(keystr));
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool DirBlob::hasChild(const string &name) const {
|
||||
//TODO Faster implementation without creating children array possible
|
||||
vector<fspp::Dir::Entry> children;
|
||||
AppendChildrenTo(&children);
|
||||
for (const auto &child : children) {
|
||||
if (child.name == name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *DirBlob::readAndAddNextChild(const char *pos, vector<fspp::Dir::Entry> *result) const {
|
||||
// Read type magic number (whether it is a dir or a file)
|
||||
fspp::Dir::EntryType type = static_cast<fspp::Dir::EntryType>(*reinterpret_cast<const unsigned char*>(pos));
|
||||
pos += 1;
|
||||
|
||||
size_t length = strlen(pos);
|
||||
std::string name(pos, length);
|
||||
result->emplace_back(fspp::Dir::Entry(type, name));
|
||||
const char *posAfterName = pos + length + 1;
|
||||
const char *posAfterKey = posAfterName + strlen(posAfterName) + 1;
|
||||
return posAfterKey;
|
||||
auto found = std::find_if(_entries.begin(), _entries.end(), [name] (const Entry &entry) {
|
||||
return entry.name == name;
|
||||
});
|
||||
return found != _entries.end();
|
||||
}
|
||||
|
||||
void DirBlob::AddChildDir(const std::string &name, const Key &blobKey) {
|
||||
@ -86,43 +112,42 @@ void DirBlob::AddChildFile(const std::string &name, const Key &blobKey) {
|
||||
AddChild(name, blobKey, fspp::Dir::EntryType::FILE);
|
||||
}
|
||||
|
||||
void DirBlob::AddChild(const std::string &name, const Key &blobKey, fspp::Dir::EntryType entryType) {
|
||||
void DirBlob::AddChild(const std::string &name, const Key &blobKey,
|
||||
fspp::Dir::EntryType entryType) {
|
||||
if (hasChild(name)) {
|
||||
throw fspp::fuse::FuseErrnoException(EEXIST);
|
||||
throw fspp::fuse::FuseErrnoException(EEXIST);
|
||||
}
|
||||
|
||||
//TODO blob.resize(blob.size()+X) has to traverse tree twice. Better would be blob.addSize(X) which returns old size
|
||||
uint64_t oldBlobSize = _blob->size();
|
||||
string blobKeyStr = blobKey.ToString();
|
||||
_blob->resize(oldBlobSize + name.size() + 1 + blobKeyStr.size() + 1);
|
||||
|
||||
//Write entry type
|
||||
unsigned char entryTypeMagicNumber = static_cast<unsigned char>(entryType);
|
||||
_blob->write(&entryTypeMagicNumber, oldBlobSize, 1);
|
||||
//Write entry name inclusive null terminator
|
||||
_blob->write(name.c_str(), oldBlobSize + 1, name.size()+1);
|
||||
//Write blob key inclusive null terminator
|
||||
_blob->write(blobKeyStr.c_str(), oldBlobSize + 1 + name.size() + 1, blobKeyStr.size()+1);
|
||||
_entries.emplace_back(entryType, name, blobKey);
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
pair<fspp::Dir::EntryType, Key> DirBlob::GetChild(const string &name) const {
|
||||
Data entries(_blob->size()-1);
|
||||
_blob->read(entries.data(), 1, _blob->size()-1);
|
||||
|
||||
const char *pos = (const char*)entries.data();
|
||||
while(pos < (const char*)entries.data()+entries.size()) {
|
||||
fspp::Dir::EntryType type = static_cast<fspp::Dir::EntryType>(*reinterpret_cast<const unsigned char*>(pos));
|
||||
pos += 1; // Skip entry type magic number (whether it is a dir or a file)
|
||||
size_t name_length = strlen(pos);
|
||||
if (name_length == name.size() && 0==std::memcmp(pos, name.c_str(), name_length)) {
|
||||
pos += strlen(pos) + 1; // Skip name
|
||||
return make_pair(type, Key::FromString(pos)); // Return key
|
||||
}
|
||||
pos += strlen(pos) + 1; // Skip name
|
||||
pos += strlen(pos) + 1; // Skip key
|
||||
const DirBlob::Entry &DirBlob::GetChild(const string &name) const {
|
||||
auto found = std::find_if(_entries.begin(), _entries.end(), [name] (const Entry &entry) {
|
||||
return entry.name == name;
|
||||
});
|
||||
if (found == _entries.end()) {
|
||||
throw fspp::fuse::FuseErrnoException(ENOENT);
|
||||
}
|
||||
throw fspp::fuse::FuseErrnoException(ENOENT);
|
||||
return *found;
|
||||
}
|
||||
|
||||
void DirBlob::RemoveChild(const Key &key) {
|
||||
auto found = std::find_if(_entries.begin(), _entries.end(), [key] (const Entry &entry) {
|
||||
return entry.key == key;
|
||||
});
|
||||
if (found == _entries.end()) {
|
||||
throw fspp::fuse::FuseErrnoException(ENOENT);
|
||||
}
|
||||
_entries.erase(found);
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
void DirBlob::AppendChildrenTo(vector<fspp::Dir::Entry> *result) const {
|
||||
result->reserve(result->size() + _entries.size());
|
||||
for (const auto &entry : _entries) {
|
||||
result->emplace_back(entry.type, entry.name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,27 +14,39 @@ namespace cryfs{
|
||||
|
||||
class DirBlob {
|
||||
public:
|
||||
struct Entry {
|
||||
Entry(fspp::Dir::EntryType type_, const std::string &name_, const blockstore::Key &key_): type(type_), name(name_), key(key_) {}
|
||||
fspp::Dir::EntryType type;
|
||||
std::string name;
|
||||
blockstore::Key key;
|
||||
};
|
||||
|
||||
static std::unique_ptr<DirBlob> InitializeEmptyDir(std::unique_ptr<blobstore::Blob> blob);
|
||||
|
||||
DirBlob(std::unique_ptr<blobstore::Blob> blob);
|
||||
virtual ~DirBlob();
|
||||
|
||||
void AppendChildrenTo(std::vector<fspp::Dir::Entry> *result) const;
|
||||
//TODO Use struct instead of pair
|
||||
std::pair<fspp::Dir::EntryType, blockstore::Key> GetChild(const std::string &name) const;
|
||||
const Entry &GetChild(const std::string &name) const;
|
||||
void AddChildDir(const std::string &name, const blockstore::Key &blobKey);
|
||||
void AddChildFile(const std::string &name, const blockstore::Key &blobKey);
|
||||
void RemoveChild(const blockstore::Key &key);
|
||||
void flush();
|
||||
|
||||
private:
|
||||
unsigned char magicNumber() const;
|
||||
|
||||
void AddChild(const std::string &name, const blockstore::Key &blobKey, fspp::Dir::EntryType type);
|
||||
|
||||
const char *readAndAddNextChild(const char *pos, std::vector<fspp::Dir::Entry> *result) const;
|
||||
const char *getStartingPosOfEntry(const char *pos, const std::string &name) const;
|
||||
const char *readAndAddNextChild(const char *pos, std::vector<Entry> *result) const;
|
||||
bool hasChild(const std::string &name) const;
|
||||
|
||||
void _readEntriesFromBlob();
|
||||
void _writeEntriesToBlob();
|
||||
|
||||
std::unique_ptr<blobstore::Blob> _blob;
|
||||
std::vector<Entry> _entries;
|
||||
bool _changed;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DirBlob);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user