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() {
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) {

View File

@ -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 {

View File

@ -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;

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)));
}
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);
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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;