Implemented chmod/chown and fixed some minor details

This commit is contained in:
Sebastian Messmer 2015-04-21 23:18:50 +02:00
parent 7b40e22279
commit b96cc48639
9 changed files with 173 additions and 61 deletions

View File

@ -47,7 +47,7 @@ Key CryDevice::GetOrCreateRootKey(CryConfig *config) {
Key CryDevice::CreateRootBlobAndReturnKey() { Key CryDevice::CreateRootBlobAndReturnKey() {
auto rootBlob = _blobStore->create(); auto rootBlob = _blobStore->create();
Key rootBlobKey = rootBlob->key(); Key rootBlobKey = rootBlob->key();
DirBlob::InitializeEmptyDir(std::move(rootBlob)); DirBlob::InitializeEmptyDir(std::move(rootBlob), this);
return rootBlobKey; 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. //TODO Check whether the next path component is a dir.
// Right now, an assertion in DirBlob constructor will fail if it isn't. // Right now, an assertion in DirBlob constructor will fail if it isn't.
// But fuse should rather return the correct error code. // 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; Key childKey = currentDir->GetChild(component.c_str()).key;
currentBlob = _blobStore->load(childKey); 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) { void CryDevice::statfs(const bf::path &path, struct statvfs *fsstat) {

View File

@ -32,17 +32,11 @@ CryDir::CryDir(CryDevice *device, unique_ptr<DirBlob> parent, const Key &key)
CryDir::~CryDir() { 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) { unique_ptr<fspp::OpenFile> CryDir::createAndOpenFile(const string &name, mode_t mode) {
auto blob = LoadBlob(); auto blob = LoadBlob();
auto child = device()->CreateBlob(); auto child = device()->CreateBlob();
Key childkey = child->key(); 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! //TODO Do we need a return value in createDir for fspp? If not, change fspp Dir interface!
auto childblob = FileBlob::InitializeEmptyFile(std::move(child)); auto childblob = FileBlob::InitializeEmptyFile(std::move(child));
return make_unique<CryOpenFile>(std::move(childblob)); return make_unique<CryOpenFile>(std::move(childblob));
@ -52,12 +46,13 @@ void CryDir::createDir(const string &name, mode_t mode) {
auto blob = LoadBlob(); auto blob = LoadBlob();
auto child = device()->CreateBlob(); auto child = device()->CreateBlob();
Key childkey = child->key(); Key childkey = child->key();
blob->AddChildDir(name, childkey); blob->AddChildDir(name, childkey, mode);
DirBlob::InitializeEmptyDir(std::move(child)); DirBlob::InitializeEmptyDir(std::move(child), device());
} }
unique_ptr<DirBlob> CryDir::LoadBlob() const { 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 { unique_ptr<vector<fspp::Dir::Entry>> CryDir::children() const {

View File

@ -13,7 +13,6 @@ public:
CryDir(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key); CryDir(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key);
virtual ~CryDir(); virtual ~CryDir();
void stat(struct ::stat *result) const override;
//TODO return type variance to CryFile/CryDir? //TODO return type variance to CryFile/CryDir?
std::unique_ptr<fspp::OpenFile> createAndOpenFile(const std::string &name, mode_t mode) override; std::unique_ptr<fspp::OpenFile> createAndOpenFile(const std::string &name, mode_t mode) override;
void createDir(const std::string &name, mode_t mode) override; void createDir(const std::string &name, mode_t mode) override;

View File

@ -31,14 +31,6 @@ unique_ptr<fspp::OpenFile> CryFile::open(int flags) const {
return make_unique<CryOpenFile>(make_unique<FileBlob>(std::move(blob))); 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 { void CryFile::truncate(off_t size) const {
FileBlob(LoadBlob()).resize(size); FileBlob(LoadBlob()).resize(size);
} }

View File

@ -14,7 +14,6 @@ public:
CryFile(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key); CryFile(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key);
virtual ~CryFile(); virtual ~CryFile();
void stat(struct ::stat *result) const override;
std::unique_ptr<fspp::OpenFile> open(int flags) const override; std::unique_ptr<fspp::OpenFile> open(int flags) const override;
void truncate(off_t size) const override; void truncate(off_t size) const override;
fspp::Dir::EntryType getType() const override; fspp::Dir::EntryType getType() const override;

View File

@ -31,19 +31,23 @@ CryNode::~CryNode() {
} }
void CryNode::access(int mask) const { void CryNode::access(int mask) const {
//TODO
return; return;
throw FuseErrnoException(ENOTSUP); throw FuseErrnoException(ENOTSUP);
} }
void CryNode::rename(const bf::path &to) { void CryNode::rename(const bf::path &to) {
//TODO More efficient implementation possible: directly rename when it's actually not moved to a different directory //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->RemoveChild(_key);
_parent->flush(); _parent->flush();
auto targetDir = _device->LoadDirBlob(to.parent_path()); 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]) { void CryNode::utimens(const timespec times[2]) {
//TODO
throw FuseErrnoException(ENOTSUP); throw FuseErrnoException(ENOTSUP);
} }
@ -64,4 +68,22 @@ unique_ptr<Blob> CryNode::LoadBlob() const {
return _device->LoadBlob(_key); 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);
}
} }

View File

@ -14,6 +14,9 @@ class CryNode: public virtual fspp::Node {
public: public:
CryNode(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key); CryNode(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key);
void access(int mask) const override; 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 rename(const boost::filesystem::path &to) override;
void utimens(const timespec times[2]) override; void utimens(const timespec times[2]) override;
void remove() override; void remove() override;

View File

@ -5,7 +5,10 @@
#include "messmer/fspp/fuse/FuseErrnoException.h" #include "messmer/fspp/fuse/FuseErrnoException.h"
#include <messmer/blockstore/utils/Data.h> #include <messmer/blockstore/utils/Data.h>
#include <messmer/blobstore/implementations/onblocks/utils/Math.h>
#include "MagicNumbers.h" #include "MagicNumbers.h"
#include "../CryDevice.h"
#include "FileBlob.h"
using std::unique_ptr; using std::unique_ptr;
using std::make_unique; using std::make_unique;
@ -20,29 +23,26 @@ using blockstore::Data;
namespace cryfs { namespace cryfs {
DirBlob::DirBlob(unique_ptr<Blob> blob) : DirBlob::DirBlob(unique_ptr<Blob> blob, CryDevice *device) :
_blob(std::move(blob)), _entries(), _changed(false) { _device(device), _blob(std::move(blob)), _entries(), _changed(false) {
assert(magicNumber() == MagicNumbers::DIR); assert(magicNumber() == MagicNumbers::DIR);
_readEntriesFromBlob(); _readEntriesFromBlob();
} }
DirBlob::~DirBlob() { DirBlob::~DirBlob() {
flush(); _writeEntriesToBlob();
} }
void DirBlob::flush() { void DirBlob::flush() {
if (_changed) { _writeEntriesToBlob();
_writeEntriesToBlob();
_changed = false;
}
_blob->flush(); _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); blob->resize(1);
unsigned char magicNumber = MagicNumbers::DIR; unsigned char magicNumber = MagicNumbers::DIR;
blob->write(&magicNumber, 0, 1); 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 { unsigned char DirBlob::magicNumber() const {
@ -52,18 +52,28 @@ unsigned char DirBlob::magicNumber() const {
} }
void DirBlob::_writeEntriesToBlob() { void DirBlob::_writeEntriesToBlob() {
//TODO Resizing is imperformant if (_changed) {
_blob->resize(1); //TODO Resizing is imperformant
unsigned int offset = 1; _blob->resize(1);
for (const auto &entry : _entries) { unsigned int offset = 1;
unsigned char entryTypeMagicNumber = static_cast<unsigned char>(entry.type); for (const auto &entry : _entries) {
_blob->write(&entryTypeMagicNumber, offset, 1); unsigned char entryTypeMagicNumber = static_cast<unsigned char>(entry.type);
offset += 1; _blob->write(&entryTypeMagicNumber, offset, 1);
_blob->write(entry.name.c_str(), offset, entry.name.size() + 1); offset += 1;
offset += entry.name.size() + 1; _blob->write(entry.name.c_str(), offset, entry.name.size() + 1);
string keystr = entry.key.ToString(); offset += entry.name.size() + 1;
_blob->write(keystr.c_str(), offset, keystr.size() + 1); string keystr = entry.key.ToString();
offset += keystr.size() + 1; _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); std::string keystr(pos, keylength);
pos += keylength + 1; 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; return pos;
} }
@ -104,21 +125,21 @@ bool DirBlob::hasChild(const string &name) const {
return found != _entries.end(); return found != _entries.end();
} }
void DirBlob::AddChildDir(const std::string &name, const Key &blobKey) { void DirBlob::AddChildDir(const std::string &name, const Key &blobKey, mode_t mode) {
AddChild(name, blobKey, fspp::Dir::EntryType::DIR); AddChild(name, blobKey, fspp::Dir::EntryType::DIR, mode);
} }
void DirBlob::AddChildFile(const std::string &name, const Key &blobKey) { void DirBlob::AddChildFile(const std::string &name, const Key &blobKey, mode_t mode) {
AddChild(name, blobKey, fspp::Dir::EntryType::FILE); AddChild(name, blobKey, fspp::Dir::EntryType::FILE, mode);
} }
void DirBlob::AddChild(const std::string &name, const Key &blobKey, void DirBlob::AddChild(const std::string &name, const Key &blobKey,
fspp::Dir::EntryType entryType) { fspp::Dir::EntryType entryType, mode_t mode) {
if (hasChild(name)) { if (hasChild(name)) {
throw fspp::fuse::FuseErrnoException(EEXIST); throw fspp::fuse::FuseErrnoException(EEXIST);
} }
_entries.emplace_back(entryType, name, blobKey); _entries.emplace_back(entryType, name, blobKey, mode);
_changed = true; _changed = true;
} }
@ -132,17 +153,33 @@ const DirBlob::Entry &DirBlob::GetChild(const string &name) const {
return *found; 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) { 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()) { 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); _entries.erase(found);
_changed = true; _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 { void DirBlob::AppendChildrenTo(vector<fspp::Dir::Entry> *result) const {
result->reserve(result->size() + _entries.size()); result->reserve(result->size() + _entries.size());
for (const auto &entry : _entries) { 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;
}
}
} }

View File

@ -11,29 +11,50 @@
#include <vector> #include <vector>
namespace cryfs{ namespace cryfs{
class CryDevice;
class DirBlob { class DirBlob {
public: public:
struct Entry { 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; fspp::Dir::EntryType type;
std::string name; std::string name;
blockstore::Key key; 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(); virtual ~DirBlob();
void AppendChildrenTo(std::vector<fspp::Dir::Entry> *result) const; void AppendChildrenTo(std::vector<fspp::Dir::Entry> *result) const;
const Entry &GetChild(const std::string &name) const; const Entry &GetChild(const std::string &name) const;
void AddChildDir(const std::string &name, const blockstore::Key &blobKey); const Entry &GetChild(const blockstore::Key &key) const;
void AddChildFile(const std::string &name, const blockstore::Key &blobKey); void AddChildDir(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); 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 RemoveChild(const blockstore::Key &key);
void flush(); 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: private:
unsigned char magicNumber() const; unsigned char magicNumber() const;
@ -43,6 +64,9 @@ private:
void _readEntriesFromBlob(); void _readEntriesFromBlob();
void _writeEntriesToBlob(); void _writeEntriesToBlob();
std::vector<DirBlob::Entry>::iterator _findChild(const blockstore::Key &key);
CryDevice *_device;
std::unique_ptr<blobstore::Blob> _blob; std::unique_ptr<blobstore::Blob> _blob;
std::vector<Entry> _entries; std::vector<Entry> _entries;
bool _changed; bool _changed;