Support symlinks

This commit is contained in:
Sebastian Meßmer 2015-04-23 09:18:30 +02:00
parent 935549f822
commit 6821684654
10 changed files with 185 additions and 8 deletions

View File

@ -4,6 +4,7 @@
#include "CryDir.h"
#include "CryFile.h"
#include "CrySymlink.h"
#include "messmer/fspp/fuse/FuseErrnoException.h"
#include "messmer/blobstore/implementations/onblocks/BlobStoreOnBlocks.h"
@ -68,6 +69,8 @@ unique_ptr<fspp::Node> CryDevice::Load(const bf::path &path) {
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 if (entry.type == fspp::Dir::EntryType::SYMLINK) {
return make_unique<CrySymlink>(this, std::move(parent), entry.key);
} else {
throw FuseErrnoException(EIO);
}

View File

@ -9,6 +9,7 @@
#include "CryDevice.h"
#include "CryFile.h"
#include "CryOpenFile.h"
#include "impl/SymlinkBlob.h"
//TODO Get rid of this in favor of exception hierarchy
using fspp::fuse::CHECK_RETVAL;
@ -67,8 +68,12 @@ fspp::Dir::EntryType CryDir::getType() const {
return fspp::Dir::EntryType::DIR;
}
void CryDir::createSymlink(const string &name, const bf::path &target) {
//TODO
void CryDir::createSymlink(const string &name, const bf::path &target, uid_t uid, gid_t gid) {
auto blob = LoadBlob();
auto child = device()->CreateBlob();
Key childkey = child->key();
blob->AddChildSymlink(name, childkey, uid, gid);
SymlinkBlob::InitializeSymlink(std::move(child), target);
}
}

View File

@ -16,7 +16,7 @@ public:
//TODO return type variance to CryFile/CryDir?
std::unique_ptr<fspp::OpenFile> createAndOpenFile(const std::string &name, mode_t mode, uid_t uid, gid_t gid) override;
void createDir(const std::string &name, mode_t mode, uid_t uid, gid_t gid) override;
void createSymlink(const std::string &name, const boost::filesystem::path &target) override;
void createSymlink(const std::string &name, const boost::filesystem::path &target, uid_t uid, gid_t gid) override;
//TODO Make Entry a public class instead of hidden in DirBlob (which is not publicly visible)
std::unique_ptr<std::vector<fspp::Dir::Entry>> children() const override;

42
src/CrySymlink.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "CrySymlink.h"
#include "messmer/fspp/fuse/FuseErrnoException.h"
#include "CryDevice.h"
#include "CrySymlink.h"
#include "impl/SymlinkBlob.h"
//TODO Get rid of this in favor of exception hierarchy
using fspp::fuse::CHECK_RETVAL;
using fspp::fuse::FuseErrnoException;
namespace bf = boost::filesystem;
using std::unique_ptr;
using std::make_unique;
using std::string;
using std::vector;
using blockstore::Key;
namespace cryfs {
CrySymlink::CrySymlink(CryDevice *device, unique_ptr<DirBlob> parent, const Key &key)
: CryNode(device, std::move(parent), key) {
}
CrySymlink::~CrySymlink() {
}
unique_ptr<SymlinkBlob> CrySymlink::LoadBlob() const {
return make_unique<SymlinkBlob>(CryNode::LoadBlob());
}
fspp::Dir::EntryType CrySymlink::getType() const {
return fspp::Dir::EntryType::SYMLINK;
}
bf::path CrySymlink::target() const {
return LoadBlob()->target();
}
}

29
src/CrySymlink.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#ifndef CRYFS_LIB_CRYSYMLINK_H_
#define CRYFS_LIB_CRYSYMLINK_H_
#include <messmer/fspp/fs_interface/Symlink.h>
#include "CryNode.h"
#include "impl/SymlinkBlob.h"
#include "impl/DirBlob.h"
namespace cryfs {
class CrySymlink: public fspp::Symlink, CryNode {
public:
CrySymlink(CryDevice *device, std::unique_ptr<DirBlob> parent, const blockstore::Key &key);
virtual ~CrySymlink();
boost::filesystem::path target() const override;
fspp::Dir::EntryType getType() const override;
private:
std::unique_ptr<SymlinkBlob> LoadBlob() const;
DISALLOW_COPY_AND_ASSIGN(CrySymlink);
};
}
#endif

View File

@ -9,6 +9,7 @@
#include "MagicNumbers.h"
#include "../CryDevice.h"
#include "FileBlob.h"
#include "SymlinkBlob.h"
using std::unique_ptr;
using std::make_unique;
@ -133,6 +134,10 @@ void DirBlob::AddChildFile(const std::string &name, const Key &blobKey, mode_t m
AddChild(name, blobKey, fspp::Dir::EntryType::FILE, mode, uid, gid);
}
void DirBlob::AddChildSymlink(const std::string &name, const blockstore::Key &blobKey, uid_t uid, gid_t gid) {
AddChild(name, blobKey, fspp::Dir::EntryType::SYMLINK, S_IFLNK | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH, uid, gid);
}
void DirBlob::AddChild(const std::string &name, const Key &blobKey,
fspp::Dir::EntryType entryType, mode_t mode, uid_t uid, gid_t gid) {
if (hasChild(name)) {
@ -189,7 +194,7 @@ 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.
//TODO Loading the blob for only getting the size of the file/symlink 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;
@ -201,8 +206,14 @@ void DirBlob::statChild(const Key &key, struct ::stat *result) const {
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 {
} else if (child.type == fspp::Dir::EntryType::DIR) {
//TODO Why do dirs have 4096 bytes in size? Does that make sense?
result->st_size = 4096;
} else if (child.type == fspp::Dir::EntryType::SYMLINK) {
//TODO Necessary with fuse or does fuse set this on symlinks anyhow?
result->st_size = SymlinkBlob(_device->LoadBlob(key)).target().native().size();
} else {
assert(false);
}
//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);
@ -211,7 +222,7 @@ void DirBlob::statChild(const Key &key, struct ::stat *result) const {
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)));
assert ((S_ISREG(mode) && S_ISREG(found->mode)) || (S_ISDIR(mode) && S_ISDIR(found->mode)) || (S_ISLNK(mode)));
found->mode = mode;
_changed = true;
}

View File

@ -25,7 +25,7 @@ public:
mode |= S_IFDIR;
break;
}
assert((S_ISREG(mode) && type == fspp::Dir::EntryType::FILE) || (S_ISDIR(mode) && type == fspp::Dir::EntryType::DIR));
assert((S_ISREG(mode) && type == fspp::Dir::EntryType::FILE) || (S_ISDIR(mode) && type == fspp::Dir::EntryType::DIR) || (type == fspp::Dir::EntryType::SYMLINK));
}
fspp::Dir::EntryType type;
@ -46,6 +46,7 @@ public:
const Entry &GetChild(const blockstore::Key &key) const;
void AddChildDir(const std::string &name, const blockstore::Key &blobKey, mode_t mode, uid_t uid, gid_t gid);
void AddChildFile(const std::string &name, const blockstore::Key &blobKey, mode_t mode, uid_t uid, gid_t gid);
void AddChildSymlink(const std::string &name, const blockstore::Key &blobKey, uid_t uid, gid_t gid);
void AddChild(const std::string &name, const blockstore::Key &blobKey, fspp::Dir::EntryType type, mode_t mode, uid_t uid, gid_t gid);
void RemoveChild(const blockstore::Key &key);
void flush();

View File

@ -6,7 +6,8 @@ namespace cryfs {
enum MagicNumbers {
DIR = 0x00,
FILE = 0x01
FILE = 0x01,
SYMLINK = 0x02
};
}

55
src/impl/SymlinkBlob.cpp Normal file
View File

@ -0,0 +1,55 @@
#include "SymlinkBlob.h"
#include "MagicNumbers.h"
#include <messmer/blockstore/utils/Key.h>
#include <cassert>
using std::unique_ptr;
using std::make_unique;
using std::string;
using blobstore::Blob;
namespace bf = boost::filesystem;
namespace cryfs {
SymlinkBlob::SymlinkBlob(unique_ptr<Blob> blob)
: _target(_readTargetFromBlob(*blob)) {
}
SymlinkBlob::SymlinkBlob(const bf::path &target) :_target(target) {
}
SymlinkBlob::~SymlinkBlob() {
}
unique_ptr<SymlinkBlob> SymlinkBlob::InitializeSymlink(unique_ptr<Blob> blob, const bf::path &target) {
assert(blob.get() != nullptr);
string targetStr = target.native();
blob->resize(1 + targetStr.size());
unsigned char magicNumber = MagicNumbers::SYMLINK;
blob->write(&magicNumber, 0, 1);
blob->write(targetStr.c_str(), 1, targetStr.size());
return make_unique<SymlinkBlob>(target);
}
void SymlinkBlob::_checkMagicNumber(const Blob &blob) {
unsigned char value;
blob.read(&value, 0, 1);
assert(value == MagicNumbers::SYMLINK);
}
bf::path SymlinkBlob::_readTargetFromBlob(const blobstore::Blob &blob) {
_checkMagicNumber(blob);
size_t targetStrSize = blob.size() - 1; // -1 because of the magic number
char targetStr[targetStrSize + 1]; // +1 because of the nullbyte
blob.read(targetStr, 1, targetStrSize);
targetStr[targetStrSize] = '\0';
return targetStr;
}
const bf::path &SymlinkBlob::target() const {
return _target;
}
}

30
src/impl/SymlinkBlob.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#ifndef CRYFS_LIB_IMPL_SYMLINKBLOB_H_
#define CRYFS_LIB_IMPL_SYMLINKBLOB_H_
#include <messmer/blobstore/interface/Blob.h>
#include <boost/filesystem/path.hpp>
#include <memory>
namespace cryfs {
class SymlinkBlob {
public:
static std::unique_ptr<SymlinkBlob> InitializeSymlink(std::unique_ptr<blobstore::Blob> blob, const boost::filesystem::path &target);
SymlinkBlob(std::unique_ptr<blobstore::Blob> blob);
SymlinkBlob(const boost::filesystem::path &target);
virtual ~SymlinkBlob();
const boost::filesystem::path &target() const;
private:
boost::filesystem::path _target;
static void _checkMagicNumber(const blobstore::Blob &blob);
static boost::filesystem::path _readTargetFromBlob(const blobstore::Blob &blob);
};
}
#endif