Support symlinks
This commit is contained in:
parent
935549f822
commit
6821684654
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
42
src/CrySymlink.cpp
Normal 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
29
src/CrySymlink.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -6,7 +6,8 @@ namespace cryfs {
|
||||
|
||||
enum MagicNumbers {
|
||||
DIR = 0x00,
|
||||
FILE = 0x01
|
||||
FILE = 0x01,
|
||||
SYMLINK = 0x02
|
||||
};
|
||||
|
||||
}
|
||||
|
55
src/impl/SymlinkBlob.cpp
Normal file
55
src/impl/SymlinkBlob.cpp
Normal 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
30
src/impl/SymlinkBlob.h
Normal 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
|
Loading…
Reference in New Issue
Block a user