MountDir and BaseDir are configureable via command line

This commit is contained in:
Sebastian Messmer 2015-09-29 14:29:10 +02:00
parent 20f5d739b7
commit 27d3ffc472
12 changed files with 449 additions and 6 deletions

View File

@ -8,6 +8,8 @@ ADD_BII_TARGETS()
ACTIVATE_CPP14()
ADD_BOOST(program_options)
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
GIT_VERSION_INIT()

View File

@ -9,17 +9,21 @@
#include "messmer/fspp/impl/FilesystemImpl.h"
#include "filesystem/CryDevice.h"
#include "config/CryConfigLoader.h"
#include "program_options/Parser.h"
#include <gitversion/version.h>
using namespace cryfs;
namespace bf = boost::filesystem;
using blockstore::ondisk::OnDiskBlockStore;
using blockstore::inmemory::InMemoryBlockStore;
using program_options::ProgramOptions;
using cpputils::make_unique_ref;
using std::cout;
using std::endl;
using std::vector;
void showVersion() {
cout << "CryFS Version " << version::VERSION_STRING << endl;
@ -32,17 +36,20 @@ void showVersion() {
cout << endl;
}
void runFilesystem(int argc, char *argv[]) {
auto config = cryfs::CryConfigLoader().loadOrCreate(bf::path("/home/heinzi/cryfstest/config.json"));
auto blockStore = make_unique_ref<OnDiskBlockStore>(bf::path("/home/heinzi/cryfstest/root"));
cryfs::CryDevice device(std::move(config), std::move(blockStore));
void runFilesystem(const ProgramOptions &options) {
auto config = CryConfigLoader().loadOrCreate(bf::path("/home/heinzi/cryfstest/config.json"));
auto blockStore = make_unique_ref<OnDiskBlockStore>(bf::path(options.baseDir()));
CryDevice device(std::move(config), std::move(blockStore));
fspp::FilesystemImpl fsimpl(&device);
fspp::fuse::Fuse fuse(&fsimpl);
fuse.run(argc, argv);
vector<char*> fuseOptions = options.fuseOptions();
fuse.run(fuseOptions.size(), fuseOptions.data());
}
int main(int argc, char *argv[]) {
showVersion();
runFilesystem(argc, argv);
ProgramOptions options = program_options::Parser(argc, argv).parse();
runFilesystem(options);
return 0;
}

View File

@ -0,0 +1,82 @@
#include "Parser.h"
#include "utils.h"
#include <iostream>
namespace po = boost::program_options;
using namespace cryfs::program_options;
using std::pair;
using std::vector;
using std::cerr;
using std::string;
Parser::Parser(int argc, char *argv[]) :_options(_argsToVector(argc, argv)) {}
vector<char*> Parser::_argsToVector(int argc, char *argv[]) {
vector<char*> result;
for(int i = 0; i < argc; ++i) {
result.push_back(argv[i]);
}
return result;
}
ProgramOptions Parser::parse() const {
pair<vector<char*>, vector<char*>> options = splitAtDoubleDash(_options);
po::variables_map vm = _parseOptionsOrShowHelp(options.first);
string baseDir = vm["base-dir"].as<string>();
string mountDir = vm["mount-dir"].as<string>();
return ProgramOptions(baseDir, mountDir, options.second);
}
po::variables_map Parser::_parseOptionsOrShowHelp(const vector<char*> options) {
try {
return _parseOptions(options);
} catch(const std::exception &e) {
_showHelpAndExit();
}
}
po::variables_map Parser::_parseOptions(const vector<char*> options) {
po::options_description desc;
po::positional_options_description positional_desc;
_addAllowedOptions(&desc);
_addPositionalOptionForBaseDir(&desc, &positional_desc);
po::variables_map vm;
po::store(po::command_line_parser(options.size(), options.data())
.options(desc).positional(positional_desc).run(), vm);
if (vm.count("help")) {
_showHelpAndExit();
}
po::notify(vm);
return vm;
}
void Parser::_addAllowedOptions(po::options_description *desc) {
po::options_description options("Allowed options");
options.add_options()
("help,h", "show help message")
;
desc->add(options);
}
void Parser::_addPositionalOptionForBaseDir(po::options_description *desc, po::positional_options_description *positional) {
positional->add("base-dir", 1);
positional->add("mount-dir", 1);
po::options_description hidden("Hidden options");
hidden.add_options()
("base-dir", po::value<string>()->required(), "Base directory")
("mount-dir", po::value<string>()->required(), "Mount directory")
;
desc->add(hidden);
}
[[noreturn]] void Parser::_showHelpAndExit() {
cerr << "Usage: cryfs [options] rootDir mountPoint [-- [FUSE Mount Options]]\n";
po::options_description desc;
_addAllowedOptions(&desc);
cerr << desc << "\n";
exit(1);
}

View File

@ -0,0 +1,29 @@
#ifndef CRYFS_PROGRAMOPTIONS_PARSER_H
#define CRYFS_PROGRAMOPTIONS_PARSER_H
#include "ProgramOptions.h"
#include <boost/program_options.hpp>
namespace cryfs {
namespace program_options {
class Parser {
public:
Parser(int argc, char *argv[]);
ProgramOptions parse() const;
private:
static std::vector<char *> _argsToVector(int argc, char *argv[]);
static void _addAllowedOptions(boost::program_options::options_description *desc);
static void _addPositionalOptionForBaseDir(boost::program_options::options_description *desc,
boost::program_options::positional_options_description *positional);
[[noreturn]] static void _showHelpAndExit();
static boost::program_options::variables_map _parseOptionsOrShowHelp(const std::vector<char*> options);
static boost::program_options::variables_map _parseOptions(const std::vector<char*> options);
std::vector<char*> _options;
};
}
}
#endif

View File

@ -0,0 +1,31 @@
#include "ProgramOptions.h"
#include <cstring>
#include <messmer/cpp-utils/assert/assert.h>
using namespace cryfs::program_options;
using std::string;
using std::vector;
ProgramOptions::ProgramOptions(const string &baseDir, const string &mountDir, const vector<char*> &fuseOptions)
:_baseDir(baseDir), _mountDir(new char[mountDir.size()+1]), _fuseOptions(fuseOptions) {
std::memcpy(_mountDir, mountDir.c_str(), mountDir.size()+1);
// Fuse needs the mountDir passed as first option (first option = position 1, since 0 is the executable name)
ASSERT(_fuseOptions.size() >= 1, "There has to be one parameter at least for the executable name");
_fuseOptions.insert(_fuseOptions.begin()+1, _mountDir);
}
ProgramOptions::~ProgramOptions() {
delete[] _mountDir;
}
const string &ProgramOptions::baseDir() const {
return _baseDir;
}
string ProgramOptions::mountDir() const {
return string(_mountDir);
}
const vector<char *> &ProgramOptions::fuseOptions() const {
return _fuseOptions;
}

View File

@ -0,0 +1,26 @@
#ifndef CRYFS_PROGRAMOPTIONS_PROGRAMOPTIONS_H
#define CRYFS_PROGRAMOPTIONS_PROGRAMOPTIONS_H
#include <vector>
#include <string>
namespace cryfs {
namespace program_options {
class ProgramOptions {
public:
ProgramOptions(const std::string &baseDir, const std::string &mountDir, const std::vector<char *> &fuseOptions);
~ProgramOptions();
const std::string &baseDir() const;
std::string mountDir() const;
const std::vector<char *> &fuseOptions() const;
private:
std::string _baseDir;
char *_mountDir;
std::vector<char *> _fuseOptions;
};
}
}
#endif

View File

@ -0,0 +1,25 @@
#include "utils.h"
#include <algorithm>
using std::pair;
using std::make_pair;
using std::vector;
using std::string;
namespace cryfs {
namespace program_options {
pair<vector<char*>, vector<char*>> splitAtDoubleDash(const vector<char*> &options) {
auto doubleDashIterator = std::find(options.begin(), options.end(), string("--"));
vector<char*> beforeDoubleDash(options.begin(), doubleDashIterator);
vector<char*> afterDoubleDash;
afterDoubleDash.reserve(options.size()-beforeDoubleDash.size()+1);
afterDoubleDash.push_back(options[0]);
std::copy(doubleDashIterator+1, options.end(), std::back_inserter(afterDoubleDash));
return make_pair(
beforeDoubleDash,
afterDoubleDash
);
}
}
}

View File

@ -0,0 +1,18 @@
#ifndef CRYFS_PROGRAMOPTIONS_UTILS_H
#define CRYFS_PROGRAMOPTIONS_UTILS_H
#include <utility>
#include <vector>
namespace cryfs {
namespace program_options {
/**
* Splits an array of program options into two arrays of program options, split at a double dash '--' option.
* It will not simply split the array, but it will also prepend options[0] to the second array,
* since as a valid program options array, the second array should contain the executable name.
*/
std::pair<std::vector<char*>, std::vector<char*>> splitAtDoubleDash(const std::vector<char*> &options);
}
}
#endif

View File

@ -0,0 +1,55 @@
#include "testutils/ProgramOptionsTestBase.h"
#include "../../src/program_options/Parser.h"
using namespace cryfs::program_options;
using std::vector;
class ProgramOptionsParserTest: public ProgramOptionsTestBase {
public:
ProgramOptions parse(std::initializer_list<const char*> options) {
vector<char*> _options = ProgramOptionsTestBase::options(options);
return Parser(_options.size(), _options.data()).parse();
}
};
TEST_F(ProgramOptionsParserTest, MissingAllOptions) {
EXPECT_DEATH(
parse({"./myExecutable"}),
"Usage:"
);
}
TEST_F(ProgramOptionsParserTest, MissingDir) {
EXPECT_DEATH(
parse({"./myExecutable", "/home/user/baseDir"}),
"Usage:"
);
}
TEST_F(ProgramOptionsParserTest, HelpLongOption) {
EXPECT_DEATH(
parse({"./myExecutable", "--help"}),
"Usage:"
);
}
TEST_F(ProgramOptionsParserTest, HelpShortOption) {
EXPECT_DEATH(
parse({"./myExecutable", "-h"}),
"Usage:"
);
}
TEST_F(ProgramOptionsParserTest, NoSpecialOptions) {
ProgramOptions options = parse({"./myExecutable", "/home/user/baseDir", "/home/user/mountDir"});
EXPECT_EQ("/home/user/baseDir", options.baseDir());
EXPECT_EQ("/home/user/mountDir", options.mountDir());
EXPECT_VECTOR_EQ({"./myExecutable", "/home/user/mountDir"}, options.fuseOptions());
}
TEST_F(ProgramOptionsParserTest, FuseOptionGiven) {
ProgramOptions options = parse({"./myExecutable", "/home/user/baseDir", "/home/user/mountDir", "--", "-f"});
EXPECT_EQ("/home/user/baseDir", options.baseDir());
EXPECT_EQ("/home/user/mountDir", options.mountDir());
EXPECT_VECTOR_EQ({"./myExecutable", "/home/user/mountDir", "-f"}, options.fuseOptions());
}

View File

@ -0,0 +1,29 @@
#include "testutils/ProgramOptionsTestBase.h"
#include "../../src/program_options/ProgramOptions.h"
using namespace cryfs::program_options;
using std::vector;
class ProgramOptionsTest: public ProgramOptionsTestBase {};
TEST_F(ProgramOptionsTest, BaseDir) {
ProgramOptions testobj("/home/user/mydir", "", options({"./myExecutable"}));
EXPECT_EQ("/home/user/mydir", testobj.baseDir());
}
TEST_F(ProgramOptionsTest, MountDir) {
ProgramOptions testobj("", "/home/user/mydir", options({"./myExecutable"}));
EXPECT_EQ("/home/user/mydir", testobj.mountDir());
}
TEST_F(ProgramOptionsTest, EmptyFuseOptions) {
ProgramOptions testobj("/rootDir", "/home/user/mydir", options({"./myExecutable"}));
//Fuse should have the mount dir as first parameter
EXPECT_VECTOR_EQ({"./myExecutable", "/home/user/mydir"}, testobj.fuseOptions());
}
TEST_F(ProgramOptionsTest, SomeFuseOptions) {
ProgramOptions testobj("/rootDir", "/home/user/mydir", options({"./myExecutable", "-f", "--longoption"}));
//Fuse should have the mount dir as first parameter
EXPECT_VECTOR_EQ({"./myExecutable", "/home/user/mydir", "-f", "--longoption"}, testobj.fuseOptions());
}

View File

@ -0,0 +1,114 @@
#include "testutils/ProgramOptionsTestBase.h"
#include "../../src/program_options/utils.h"
using namespace cryfs::program_options;
using std::pair;
using std::vector;
using std::string;
class ProgramOptionsUtilsTest: public ProgramOptionsTestBase {};
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_ZeroOptions) {
vector<char*> input = options({"./executableName"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName"}, result.first);
EXPECT_VECTOR_EQ({"./executableName"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneShortOption) {
vector<char*> input = options({"./executableName", "-j"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "-j"}, result.first);
EXPECT_VECTOR_EQ({"./executableName"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneLongOption) {
vector<char*> input = options({"./executableName", "--myoption"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "--myoption"}, result.first);
EXPECT_VECTOR_EQ({"./executableName"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OnePositionalOption) {
vector<char*> input = options({"./executableName", "mypositionaloption"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption"}, result.first);
EXPECT_VECTOR_EQ({"./executableName"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneShortOption_DoubleDash) {
vector<char*> input = options({"./executableName", "-j", "--"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "-j"}, result.first);
EXPECT_VECTOR_EQ({"./executableName"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneLongOption_DoubleDash) {
vector<char*> input = options({"./executableName", "--myoption", "--"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "--myoption"}, result.first);
EXPECT_VECTOR_EQ({"./executableName"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OnePositionalOption_DoubleDash) {
vector<char*> input = options({"./executableName", "mypositionaloption", "--"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption"}, result.first);
EXPECT_VECTOR_EQ({"./executableName"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_DoubleDash_OneShortOption) {
vector<char*> input = options({"./executableName", "--", "-a"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName"}, result.first);
EXPECT_VECTOR_EQ({"./executableName", "-a"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_DoubleDash_OneLongOption) {
vector<char*> input = options({"./executableName", "--", "--myoption"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName"}, result.first);
EXPECT_VECTOR_EQ({"./executableName", "--myoption"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_DoubleDash_OnePositionalOption) {
vector<char*> input = options({"./executableName", "--", "mypositionaloption"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName"}, result.first);
EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneShortOption_DoubleDash_OneShortOption) {
vector<char*> input = options({"./executableName", "-j", "--", "-a"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "-j"}, result.first);
EXPECT_VECTOR_EQ({"./executableName", "-a"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneLongOption_DoubleDash_OneLongOption) {
vector<char*> input = options({"./executableName", "--myoption", "--", "--myotheroption"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "--myoption"}, result.first);
EXPECT_VECTOR_EQ({"./executableName", "--myotheroption"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OnePositionalOption_DoubleDash_OnePositionalOption) {
vector<char*> input = options({"./executableName", "mypositionaloption", "--", "otherpositionaloption"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption"}, result.first);
EXPECT_VECTOR_EQ({"./executableName", "otherpositionaloption"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_MoreOptions) {
vector<char*> input = options({"./executableName", "mypositionaloption", "myotherpositionaloption", "-j", "--alpha", "--", "filename", "--beta", "-j3"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption", "myotherpositionaloption", "-j", "--alpha"}, result.first);
EXPECT_VECTOR_EQ({"./executableName", "filename", "--beta", "-j3"}, result.second);
}
TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_RealisticCryfsOptions) {
vector<char*> input = options({"./executableName", "rootDir", "mountDir", "--", "-f"});
pair<vector<char*>,vector<char*>> result = splitAtDoubleDash(input);
EXPECT_VECTOR_EQ({"./executableName", "rootDir", "mountDir"}, result.first);
EXPECT_VECTOR_EQ({"./executableName", "-f"}, result.second);
}

View File

@ -0,0 +1,25 @@
#ifndef CRYFS_TEST_PROGRAMOPTIONS_PROGRAMOPTIONSTEST_H
#define CRYFS_TEST_PROGRAMOPTIONS_PROGRAMOPTIONSTEST_H
#include <google/gtest/gtest.h>
class ProgramOptionsTestBase: public ::testing::Test {
public:
std::vector<char*> options(std::initializer_list<const char*> options) {
std::vector<char*> result;
for (auto option : options) {
result.push_back(const_cast<char*>(option));
}
return result;
}
void EXPECT_VECTOR_EQ(std::initializer_list<const char*> expected, const std::vector<char*> &actual) {
std::vector<const char*> expectedVec(expected);
EXPECT_EQ(expectedVec.size(), actual.size());
for(unsigned int i = 0; i < expectedVec.size(); ++i) {
EXPECT_EQ(std::string(expectedVec[i]), std::string(actual[i]));
}
}
};
#endif