Implemented chmod/chown and fixed some minor details
This commit is contained in:
parent
7b40e22279
commit
b96cc48639
@ -47,7 +47,7 @@ Key CryDevice::GetOrCreateRootKey(CryConfig *config) {
|
||||
Key CryDevice::CreateRootBlobAndReturnKey() {
|
||||
auto rootBlob = _blobStore->create();
|
||||
Key rootBlobKey = rootBlob->key();
|
||||
DirBlob::InitializeEmptyDir(std::move(rootBlob));
|
||||
DirBlob::InitializeEmptyDir(std::move(rootBlob), this);
|
||||
return rootBlobKey;
|
||||
}
|
||||
|
||||
@ -81,13 +81,13 @@ unique_ptr<DirBlob> CryDevice::LoadDirBlob(const bf::path &path) {
|
||||
//TODO Check whether the next path component is a dir.
|
||||
// Right now, an assertion in DirBlob constructor will fail if it isn't.
|
||||
// But fuse should rather return the correct error code.
|
||||
unique_ptr<DirBlob> currentDir = make_unique<DirBlob>(std::move(currentBlob));
|
||||
unique_ptr<DirBlob> currentDir = make_unique<DirBlob>(std::move(currentBlob), this);
|
||||
|
||||
Key childKey = currentDir->GetChild(component.c_str()).key;
|
||||
currentBlob = _blobStore->load(childKey);
|
||||
}
|
||||
|
||||
return make_unique<DirBlob>(std::move(currentBlob));
|
||||
return make_unique<DirBlob>(std::move(currentBlob), this);
|
||||
}
|
||||
|
||||
void CryDevice::statfs(const bf::path &path, struct statvfs *fsstat) {
|
||||
|
@ -32,17 +32,11 @@ CryDir::CryDir(CryDevice *device, unique_ptr<DirBlob> parent, const Key &key)
|
||||
CryDir::~CryDir() {
|
||||
}
|
||||
|
||||
void CryDir::stat(struct ::stat *result) const {
|
||||
result->st_mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IWUSR;
|
||||
return;
|
||||
throw FuseErrnoException(ENOTSUP);
|
||||
}
|
||||
|
||||
unique_ptr<fspp::OpenFile> CryDir::createAndOpenFile(const string &name, mode_t mode) {
|
||||
auto blob = LoadBlob();
|
||||
auto child = device()->CreateBlob();
|
||||
Key childkey = child->key();
|
||||
blob->AddChildFile(name, childkey);
|
||||
blob->AddChildFile(name, childkey, mode);
|
||||
//TODO Do we need a return value in createDir for fspp? If not, change fspp Dir interface!
|
||||
auto childblob = FileBlob::InitializeEmptyFile(std::move(child));
|
||||
return make_unique<CryOpenFile>(std::move(childblob));
|
||||
@ -52,12 +46,13 @@ void CryDir::createDir(const string &name, mode_t mode) {
|
||||
auto blob = LoadBlob();
|
||||
auto child = device()->CreateBlob();
|
||||
Key childkey = child->key();
|
||||
blob->AddChildDir(name, childkey);
|
||||
DirBlob::InitializeEmptyDir(std::move(child));
|
||||
blob->AddChildDir(name, childkey, mode);
|
||||
DirBlob::InitializeEmptyDir(std::move(child), device());
|
||||
}
|
||||
|
||||
unique_ptr<DirBlob> CryDir::LoadBlob() const {
|
||||
return make_unique<DirBlob>(CryNode::LoadBlob());
|
||||
//TODO Without const_cast?
|
||||
return make_unique<DirBlob>(CryNode::LoadBlob(), const_cast<CryDevice*>(device()));
|
||||
}
|
||||
|
||||
unique_ptr<vector<fspp::Dir::Entry>> CryDir::children() const {
|
||||
|
@ -13,7 +13,6 @@ public:
|
||||
CryDir(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key);
|
||||
virtual ~CryDir();
|
||||
|
||||
void stat(struct ::stat *result) const override;
|
||||
//TODO return type variance to CryFile/CryDir?
|
||||
std::unique_ptr<fspp::OpenFile> createAndOpenFile(const std::string &name, mode_t mode) override;
|
||||
void createDir(const std::string &name, mode_t mode) override;
|
||||
|
@ -31,14 +31,6 @@ unique_ptr<fspp::OpenFile> CryFile::open(int flags) const {
|
||||
return make_unique<CryOpenFile>(make_unique<FileBlob>(std::move(blob)));
|
||||
}
|
||||
|
||||
void CryFile::stat(struct ::stat *result) const {
|
||||
result->st_mode = S_IFREG | S_IRUSR | S_IXUSR | S_IWUSR;
|
||||
//TODO Loading the blob for only getting the size is not very performant.
|
||||
result->st_size = FileBlob(LoadBlob()).size();
|
||||
return;
|
||||
throw FuseErrnoException(ENOTSUP);
|
||||
}
|
||||
|
||||
void CryFile::truncate(off_t size) const {
|
||||
FileBlob(LoadBlob()).resize(size);
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ public:
|
||||
CryFile(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key);
|
||||
virtual ~CryFile();
|
||||
|
||||
void stat(struct ::stat *result) const override;
|
||||
std::unique_ptr<fspp::OpenFile> open(int flags) const override;
|
||||
void truncate(off_t size) const override;
|
||||
fspp::Dir::EntryType getType() const override;
|
||||
|
@ -31,19 +31,23 @@ CryNode::~CryNode() {
|
||||
}
|
||||
|
||||
void CryNode::access(int mask) const {
|
||||
//TODO
|
||||
return;
|
||||
throw FuseErrnoException(ENOTSUP);
|
||||
}
|
||||
|
||||
void CryNode::rename(const bf::path &to) {
|
||||
//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.
|
||||
mode_t mode = _parent->GetChild(_key).mode;
|
||||
_parent->RemoveChild(_key);
|
||||
_parent->flush();
|
||||
auto targetDir = _device->LoadDirBlob(to.parent_path());
|
||||
targetDir->AddChild(to.filename().native(), _key, getType());
|
||||
targetDir->AddChild(to.filename().native(), _key, getType(), mode);
|
||||
}
|
||||
|
||||
void CryNode::utimens(const timespec times[2]) {
|
||||
//TODO
|
||||
throw FuseErrnoException(ENOTSUP);
|
||||
}
|
||||
|
||||
@ -64,4 +68,22 @@ unique_ptr<Blob> CryNode::LoadBlob() const {
|
||||
return _device->LoadBlob(_key);
|
||||
}
|
||||
|
||||
void CryNode::stat(struct ::stat *result) const {
|
||||
if(_parent.get() == nullptr) {
|
||||
//We arethe root directory.
|
||||
//TODO What should we do?
|
||||
result->st_mode = S_IFDIR;
|
||||
} else {
|
||||
_parent->statChild(_key, result);
|
||||
}
|
||||
}
|
||||
|
||||
void CryNode::chmod(mode_t mode) {
|
||||
_parent->chmodChild(_key, mode);
|
||||
}
|
||||
|
||||
void CryNode::chown(uid_t uid, gid_t gid) {
|
||||
_parent->chownChild(_key, uid, gid);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ class CryNode: public virtual fspp::Node {
|
||||
public:
|
||||
CryNode(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key);
|
||||
void access(int mask) const override;
|
||||
void stat(struct ::stat *result) const override;
|
||||
void chmod(mode_t mode) override;
|
||||
void chown(uid_t uid, gid_t gid) override;
|
||||
void rename(const boost::filesystem::path &to) override;
|
||||
void utimens(const timespec times[2]) override;
|
||||
void remove() override;
|
||||
|
@ -5,7 +5,10 @@
|
||||
#include "messmer/fspp/fuse/FuseErrnoException.h"
|
||||
|
||||
#include <messmer/blockstore/utils/Data.h>
|
||||
#include <messmer/blobstore/implementations/onblocks/utils/Math.h>
|
||||
#include "MagicNumbers.h"
|
||||
#include "../CryDevice.h"
|
||||
#include "FileBlob.h"
|
||||
|
||||
using std::unique_ptr;
|
||||
using std::make_unique;
|
||||
@ -20,29 +23,26 @@ using blockstore::Data;
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
DirBlob::DirBlob(unique_ptr<Blob> blob) :
|
||||
_blob(std::move(blob)), _entries(), _changed(false) {
|
||||
DirBlob::DirBlob(unique_ptr<Blob> blob, CryDevice *device) :
|
||||
_device(device), _blob(std::move(blob)), _entries(), _changed(false) {
|
||||
assert(magicNumber() == MagicNumbers::DIR);
|
||||
_readEntriesFromBlob();
|
||||
}
|
||||
|
||||
DirBlob::~DirBlob() {
|
||||
flush();
|
||||
_writeEntriesToBlob();
|
||||
}
|
||||
|
||||
void DirBlob::flush() {
|
||||
if (_changed) {
|
||||
_writeEntriesToBlob();
|
||||
_changed = false;
|
||||
}
|
||||
_writeEntriesToBlob();
|
||||
_blob->flush();
|
||||
}
|
||||
|
||||
unique_ptr<DirBlob> DirBlob::InitializeEmptyDir(unique_ptr<Blob> blob) {
|
||||
unique_ptr<DirBlob> DirBlob::InitializeEmptyDir(unique_ptr<Blob> blob, CryDevice *device) {
|
||||
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), device);
|
||||
}
|
||||
|
||||
unsigned char DirBlob::magicNumber() const {
|
||||
@ -52,18 +52,28 @@ unsigned char DirBlob::magicNumber() const {
|
||||
}
|
||||
|
||||
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;
|
||||
if (_changed) {
|
||||
//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;
|
||||
_blob->write(&entry.uid, offset, sizeof(uid_t));
|
||||
//TODO Writing them all in separate write calls is maybe imperformant. We could write the whole entry in one write call instead.
|
||||
offset += sizeof(uid_t);
|
||||
_blob->write(&entry.gid, offset, sizeof(gid_t));
|
||||
offset += sizeof(gid_t);
|
||||
_blob->write(&entry.mode, offset, sizeof(mode_t));
|
||||
offset += sizeof(mode_t);
|
||||
}
|
||||
_changed = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +103,18 @@ const char *DirBlob::readAndAddNextChild(const char *pos,
|
||||
std::string keystr(pos, keylength);
|
||||
pos += keylength + 1;
|
||||
|
||||
result->emplace_back(type, name, Key::FromString(keystr));
|
||||
//It might make sense to read all of them at once with a memcpy
|
||||
|
||||
uid_t uid = *(uid_t*)pos;
|
||||
pos += sizeof(uid_t);
|
||||
|
||||
gid_t gid = *(gid_t*)pos;
|
||||
pos += sizeof(gid_t);
|
||||
|
||||
mode_t mode = *(mode_t*)pos;
|
||||
pos += sizeof(mode_t);
|
||||
|
||||
result->emplace_back(type, name, Key::FromString(keystr), mode, uid, gid);
|
||||
return pos;
|
||||
}
|
||||
|
||||
@ -104,21 +125,21 @@ bool DirBlob::hasChild(const string &name) const {
|
||||
return found != _entries.end();
|
||||
}
|
||||
|
||||
void DirBlob::AddChildDir(const std::string &name, const Key &blobKey) {
|
||||
AddChild(name, blobKey, fspp::Dir::EntryType::DIR);
|
||||
void DirBlob::AddChildDir(const std::string &name, const Key &blobKey, mode_t mode) {
|
||||
AddChild(name, blobKey, fspp::Dir::EntryType::DIR, mode);
|
||||
}
|
||||
|
||||
void DirBlob::AddChildFile(const std::string &name, const Key &blobKey) {
|
||||
AddChild(name, blobKey, fspp::Dir::EntryType::FILE);
|
||||
void DirBlob::AddChildFile(const std::string &name, const Key &blobKey, mode_t mode) {
|
||||
AddChild(name, blobKey, fspp::Dir::EntryType::FILE, mode);
|
||||
}
|
||||
|
||||
void DirBlob::AddChild(const std::string &name, const Key &blobKey,
|
||||
fspp::Dir::EntryType entryType) {
|
||||
fspp::Dir::EntryType entryType, mode_t mode) {
|
||||
if (hasChild(name)) {
|
||||
throw fspp::fuse::FuseErrnoException(EEXIST);
|
||||
}
|
||||
|
||||
_entries.emplace_back(entryType, name, blobKey);
|
||||
_entries.emplace_back(entryType, name, blobKey, mode);
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
@ -132,17 +153,33 @@ const DirBlob::Entry &DirBlob::GetChild(const string &name) const {
|
||||
return *found;
|
||||
}
|
||||
|
||||
void DirBlob::RemoveChild(const Key &key) {
|
||||
const DirBlob::Entry &DirBlob::GetChild(const Key &key) const {
|
||||
auto found = std::find_if(_entries.begin(), _entries.end(), [key] (const Entry &entry) {
|
||||
return entry.key == key;
|
||||
return entry.key == key;
|
||||
});
|
||||
if (found == _entries.end()) {
|
||||
throw fspp::fuse::FuseErrnoException(ENOENT);
|
||||
throw fspp::fuse::FuseErrnoException(ENOENT);
|
||||
}
|
||||
return *found;
|
||||
}
|
||||
|
||||
void DirBlob::RemoveChild(const Key &key) {
|
||||
auto found = _findChild(key);
|
||||
_entries.erase(found);
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
std::vector<DirBlob::Entry>::iterator DirBlob::_findChild(const Key &key) {
|
||||
//TODO Code duplication with GetChild(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);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void DirBlob::AppendChildrenTo(vector<fspp::Dir::Entry> *result) const {
|
||||
result->reserve(result->size() + _entries.size());
|
||||
for (const auto &entry : _entries) {
|
||||
@ -150,4 +187,45 @@ void DirBlob::AppendChildrenTo(vector<fspp::Dir::Entry> *result) const {
|
||||
}
|
||||
}
|
||||
|
||||
void DirBlob::statChild(const Key &key, struct ::stat *result) const {
|
||||
auto child = GetChild(key);
|
||||
//TODO Loading the blob for only getting the size is not very performant.
|
||||
// Furthermore, this is the only reason why DirBlob needs a pointer to CryDevice, which is ugly
|
||||
result->st_mode = child.mode;
|
||||
result->st_uid = child.uid;
|
||||
result->st_gid = child.gid;
|
||||
//TODO If possible without performance loss, then for a directory, st_nlink should return number of dir entries (including "." and "..")
|
||||
result->st_nlink = 1;
|
||||
//TODO Handle file access times
|
||||
clock_gettime(CLOCK_REALTIME, &result->st_atim);
|
||||
result->st_mtim = result->st_ctim = result->st_atim;
|
||||
if (child.type == fspp::Dir::EntryType::FILE) {
|
||||
result->st_size = FileBlob(_device->LoadBlob(key)).size();
|
||||
} else {
|
||||
result->st_size = 4096;
|
||||
}
|
||||
//TODO Move ceilDivision to general utils which can be used by cryfs as well
|
||||
result->st_blocks = blobstore::onblocks::utils::ceilDivision(result->st_size, 512);
|
||||
result->st_blksize = _device->BLOCKSIZE_BYTES;
|
||||
}
|
||||
|
||||
void DirBlob::chmodChild(const Key &key, mode_t mode) {
|
||||
auto found = _findChild(key);
|
||||
assert ((S_ISREG(mode) && S_ISREG(found->mode)) || (S_ISDIR(mode) && S_ISDIR(found->mode)));
|
||||
found->mode = mode;
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
void DirBlob::chownChild(const Key &key, uid_t uid, gid_t gid) {
|
||||
auto found = _findChild(key);
|
||||
if (uid != (uid_t)-1) {
|
||||
found->uid = uid;
|
||||
_changed = true;
|
||||
}
|
||||
if (gid != (gid_t)-1) {
|
||||
found->gid = gid;
|
||||
_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,29 +11,50 @@
|
||||
#include <vector>
|
||||
|
||||
namespace cryfs{
|
||||
class CryDevice;
|
||||
|
||||
class DirBlob {
|
||||
public:
|
||||
struct Entry {
|
||||
Entry(fspp::Dir::EntryType type_, const std::string &name_, const blockstore::Key &key_): type(type_), name(name_), key(key_) {}
|
||||
//TODO Remove default value for parameters uid_ and gid_ and instead pass them in
|
||||
Entry(fspp::Dir::EntryType type_, const std::string &name_, const blockstore::Key &key_, mode_t mode_, uid_t uid_=0, gid_t gid_=0): type(type_), name(name_), key(key_), mode(mode_), uid(uid_), gid(gid_) {
|
||||
switch(type) {
|
||||
case fspp::Dir::EntryType::FILE:
|
||||
mode |= S_IFREG;
|
||||
break;
|
||||
case fspp::Dir::EntryType::DIR:
|
||||
mode |= S_IFDIR;
|
||||
break;
|
||||
}
|
||||
assert((S_ISREG(mode) && type == fspp::Dir::EntryType::FILE) || (S_ISDIR(mode) && type == fspp::Dir::EntryType::DIR));
|
||||
}
|
||||
|
||||
fspp::Dir::EntryType type;
|
||||
std::string name;
|
||||
blockstore::Key key;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
mode_t mode;
|
||||
};
|
||||
|
||||
static std::unique_ptr<DirBlob> InitializeEmptyDir(std::unique_ptr<blobstore::Blob> blob);
|
||||
static std::unique_ptr<DirBlob> InitializeEmptyDir(std::unique_ptr<blobstore::Blob> blob, CryDevice *device);
|
||||
|
||||
DirBlob(std::unique_ptr<blobstore::Blob> blob);
|
||||
DirBlob(std::unique_ptr<blobstore::Blob> blob, CryDevice *device);
|
||||
virtual ~DirBlob();
|
||||
|
||||
void AppendChildrenTo(std::vector<fspp::Dir::Entry> *result) 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 AddChild(const std::string &name, const blockstore::Key &blobKey, fspp::Dir::EntryType type);
|
||||
const Entry &GetChild(const blockstore::Key &key) const;
|
||||
void AddChildDir(const std::string &name, const blockstore::Key &blobKey, mode_t mode);
|
||||
void AddChildFile(const std::string &name, const blockstore::Key &blobKey, mode_t mode);
|
||||
void AddChild(const std::string &name, const blockstore::Key &blobKey, fspp::Dir::EntryType type, mode_t mode);
|
||||
void RemoveChild(const blockstore::Key &key);
|
||||
void flush();
|
||||
|
||||
void statChild(const blockstore::Key &key, struct ::stat *result) const;
|
||||
void chmodChild(const blockstore::Key &key, mode_t mode);
|
||||
void chownChild(const blockstore::Key &key, uid_t uid, gid_t gid);
|
||||
|
||||
private:
|
||||
unsigned char magicNumber() const;
|
||||
|
||||
@ -43,6 +64,9 @@ private:
|
||||
void _readEntriesFromBlob();
|
||||
void _writeEntriesToBlob();
|
||||
|
||||
std::vector<DirBlob::Entry>::iterator _findChild(const blockstore::Key &key);
|
||||
|
||||
CryDevice *_device;
|
||||
std::unique_ptr<blobstore::Blob> _blob;
|
||||
std::vector<Entry> _entries;
|
||||
bool _changed;
|
||||
|
Loading…
Reference in New Issue
Block a user