Implement cryfs-unmount for unmounting filesystems
This commit is contained in:
parent
7adbe4e3ca
commit
58cb91102d
@ -479,7 +479,7 @@ jobs:
|
||||
OMP_NUM_THREADS: "1"
|
||||
CXXFLAGS: "-O2 -fsanitize=thread -fno-omit-frame-pointer"
|
||||
BUILD_TYPE: "Debug"
|
||||
GTEST_ARGS: "--gtest_filter=-LoggingTest.LoggingAlsoWorksAfterFork:AssertTest_DebugBuild.*:CliTest_Setup.*:CliTest_IntegrityCheck.*:*/CliTest_WrongEnvironment.*"
|
||||
GTEST_ARGS: "--gtest_filter=-LoggingTest.LoggingAlsoWorksAfterFork:AssertTest_DebugBuild.*:CliTest_Setup.*:CliTest_IntegrityCheck.*:*/CliTest_WrongEnvironment.*:CliTest_Unmount.*"
|
||||
CMAKE_FLAGS: ""
|
||||
RUN_TESTS: true
|
||||
clang_tidy:
|
||||
|
@ -12,6 +12,7 @@ New Features & Improvements:
|
||||
* New block size options: 4KB and 16KB
|
||||
* New default block size: 16KB. This should decrease the size of the ciphertext directory for most users.
|
||||
* Increased scrypt hardness to (N=1048576, r=4, p=8) to make it harder to crack the key while allowing cryfs to take advantage of multicore machines.
|
||||
* cryfs-unmount tool to unmount filesystems
|
||||
|
||||
Fixed bugs:
|
||||
* `du` shows correct file system size on Mac OS X.
|
||||
|
@ -8,4 +8,5 @@ add_subdirectory(blockstore)
|
||||
add_subdirectory(blobstore)
|
||||
add_subdirectory(cryfs)
|
||||
add_subdirectory(cryfs-cli)
|
||||
add_subdirectory(cryfs-unmount)
|
||||
add_subdirectory(stats)
|
||||
|
26
src/cpp-utils/system/path.h
Normal file
26
src/cpp-utils/system/path.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_SYSTEM_PATH_H
|
||||
#define MESSMER_CPPUTILS_SYSTEM_PATH_H
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <cpp-utils/macros.h>
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
inline bool path_is_just_drive_letter(const boost::filesystem::path& path) {
|
||||
return path.has_root_path() && !path.has_root_directory() && !path.has_parent_path();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline constexpr bool path_is_just_drive_letter(const boost::filesystem::path& /*path*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_SRC_CLI_CALLAFTERTIMEOUT_H
|
||||
#define MESSMER_CRYFS_SRC_CLI_CALLAFTERTIMEOUT_H
|
||||
#ifndef MESSMER_CRYFSCLI_CALLAFTERTIMEOUT_H
|
||||
#define MESSMER_CRYFSCLI_CALLAFTERTIMEOUT_H
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <cpp-utils/thread/LoopThread.h>
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
class CallAfterTimeout final {
|
||||
public:
|
||||
CallAfterTimeout(boost::chrono::milliseconds timeout, std::function<void()> callback);
|
||||
|
@ -30,6 +30,7 @@
|
||||
//TODO Many functions accessing the ProgramOptions object. Factor out into class that stores it as a member.
|
||||
//TODO Factor out class handling askPassword
|
||||
|
||||
using namespace cryfs_cli;
|
||||
using namespace cryfs;
|
||||
namespace bf = boost::filesystem;
|
||||
using namespace cpputils::logging;
|
||||
@ -66,7 +67,7 @@ using gitversion::VersionCompare;
|
||||
//TODO Replace ASSERTs with other error handling when it is not a programming error but an environment influence (e.g. a block is missing)
|
||||
//TODO Can we improve performance by setting compiler parameter -maes for scrypt?
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
|
||||
Cli::Cli(RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, shared_ptr<Console> console):
|
||||
_keyGenerator(keyGenerator), _scryptSettings(scryptSettings), _console(), _noninteractive(false), _idleUnmounter(none), _device(none) {
|
||||
@ -262,12 +263,8 @@ namespace cryfs {
|
||||
|
||||
_initLogfile(options);
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::cout << "\nMounting filesystem. To unmount, call:\n$ umount " << options.mountDir() << "\n" << std::endl;
|
||||
#else
|
||||
std::cout << "\nMounting filesystem. To unmount, call:\n$ fusermount -u " << options.mountDir() << "\n"
|
||||
std::cout << "\nMounting filesystem. To unmount, call:\n$ cryfs-unmount " << options.mountDir() << "\n"
|
||||
<< std::endl;
|
||||
#endif
|
||||
fuse->run(options.mountDir(), options.fuseOptions());
|
||||
|
||||
if (stoppedBecauseOfIntegrityViolation) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_CLI_H
|
||||
#define MESSMER_CRYFS_CLI_H
|
||||
#ifndef MESSMER_CRYFSCLI_CLI_H
|
||||
#define MESSMER_CRYFSCLI_CLI_H
|
||||
|
||||
#include "program_options/ProgramOptions.h"
|
||||
#include <cryfs/config/CryConfigFile.h>
|
||||
@ -14,7 +14,7 @@
|
||||
#include <cryfs/config/CryConfigLoader.h>
|
||||
#include <cryfs/ErrorCodes.h>
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
class Cli final {
|
||||
public:
|
||||
Cli(cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings& scryptSettings, std::shared_ptr<cpputils::Console> console);
|
||||
@ -23,9 +23,9 @@ namespace cryfs {
|
||||
private:
|
||||
void _checkForUpdates(cpputils::unique_ref<cpputils::HttpClient> httpClient);
|
||||
void _runFilesystem(const program_options::ProgramOptions &options, std::function<void()> onMounted);
|
||||
CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options, const LocalStateDir& localStateDir);
|
||||
void _checkConfigIntegrity(const boost::filesystem::path& basedir, const LocalStateDir& localStateDir, const CryConfigFile& config, bool allowReplacedFilesystem);
|
||||
boost::optional<CryConfigLoader::ConfigLoadResult> _loadOrCreateConfigFile(boost::filesystem::path configFilePath, LocalStateDir localStateDir, const boost::optional<std::string> &cipher, const boost::optional<uint32_t> &blocksizeBytes, bool allowFilesystemUpgrade, const boost::optional<bool> &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem);
|
||||
cryfs::CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options, const cryfs::LocalStateDir& localStateDir);
|
||||
void _checkConfigIntegrity(const boost::filesystem::path& basedir, const cryfs::LocalStateDir& localStateDir, const cryfs::CryConfigFile& config, bool allowReplacedFilesystem);
|
||||
boost::optional<cryfs::CryConfigLoader::ConfigLoadResult> _loadOrCreateConfigFile(boost::filesystem::path configFilePath, cryfs::LocalStateDir localStateDir, const boost::optional<std::string> &cipher, const boost::optional<uint32_t> &blocksizeBytes, bool allowFilesystemUpgrade, const boost::optional<bool> &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem);
|
||||
boost::filesystem::path _determineConfigFile(const program_options::ProgramOptions &options);
|
||||
static std::function<std::string()> _askPasswordForExistingFilesystem(std::shared_ptr<cpputils::Console> console);
|
||||
static std::function<std::string()> _askPasswordForNewFilesystem(std::shared_ptr<cpputils::Console> console);
|
||||
@ -37,11 +37,11 @@ namespace cryfs {
|
||||
void _sanityChecks(const program_options::ProgramOptions &options);
|
||||
void _checkMountdirDoesntContainBasedir(const program_options::ProgramOptions &options);
|
||||
bool _pathContains(const boost::filesystem::path &parent, const boost::filesystem::path &child);
|
||||
void _checkDirAccessible(const boost::filesystem::path &dir, const std::string &name, ErrorCode errorCode);
|
||||
std::shared_ptr<cpputils::TempFile> _checkDirWriteable(const boost::filesystem::path &dir, const std::string &name, ErrorCode errorCode);
|
||||
void _checkDirReadable(const boost::filesystem::path &dir, std::shared_ptr<cpputils::TempFile> tempfile, const std::string &name, ErrorCode errorCode);
|
||||
void _checkDirAccessible(const boost::filesystem::path &dir, const std::string &name, cryfs::ErrorCode errorCode);
|
||||
std::shared_ptr<cpputils::TempFile> _checkDirWriteable(const boost::filesystem::path &dir, const std::string &name, cryfs::ErrorCode errorCode);
|
||||
void _checkDirReadable(const boost::filesystem::path &dir, std::shared_ptr<cpputils::TempFile> tempfile, const std::string &name, cryfs::ErrorCode errorCode);
|
||||
boost::optional<cpputils::unique_ref<CallAfterTimeout>> _createIdleCallback(boost::optional<double> minutes, std::function<void()> callback);
|
||||
void _sanityCheckFilesystem(CryDevice *device);
|
||||
void _sanityCheckFilesystem(cryfs::CryDevice *device);
|
||||
|
||||
|
||||
cpputils::RandomGenerator &_keyGenerator;
|
||||
@ -49,7 +49,7 @@ namespace cryfs {
|
||||
std::shared_ptr<cpputils::Console> _console;
|
||||
bool _noninteractive;
|
||||
boost::optional<cpputils::unique_ref<CallAfterTimeout>> _idleUnmounter;
|
||||
boost::optional<cpputils::unique_ref<CryDevice>> _device;
|
||||
boost::optional<cpputils::unique_ref<cryfs::CryDevice>> _device;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Cli);
|
||||
};
|
||||
|
@ -6,7 +6,7 @@
|
||||
using std::string;
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
const string Environment::FRONTEND_KEY = "CRYFS_FRONTEND";
|
||||
const string Environment::FRONTEND_NONINTERACTIVE = "noninteractive";
|
||||
const string Environment::NOUPDATECHECK_KEY = "CRYFS_NO_UPDATE_CHECK";
|
||||
|
@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_CLI_ENVIRONMENT_H
|
||||
#define MESSMER_CRYFS_CLI_ENVIRONMENT_H
|
||||
#ifndef MESSMER_CRYFSCLI_ENVIRONMENT_H
|
||||
#define MESSMER_CRYFSCLI_ENVIRONMENT_H
|
||||
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
|
||||
class Environment {
|
||||
public:
|
||||
|
@ -13,7 +13,7 @@ using boost::property_tree::ptree;
|
||||
using boost::property_tree::json_parser_error;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
|
||||
VersionChecker::VersionChecker(HttpClient* httpClient)
|
||||
: _versionInfo(_getVersionInfo(httpClient)) {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef MESSMER_CRYFS_SRC_CLI_VERSIONCHECKER_H
|
||||
#define MESSMER_CRYFS_SRC_CLI_VERSIONCHECKER_H
|
||||
#ifndef MESSMER_CRYFSCLI_VERSIONCHECKER_H
|
||||
#define MESSMER_CRYFSCLI_VERSIONCHECKER_H
|
||||
|
||||
#include <cpp-utils/macros.h>
|
||||
#include <string>
|
||||
@ -8,7 +8,7 @@
|
||||
#include <cpp-utils/network/HttpClient.h>
|
||||
#include <cpp-utils/pointer/unique_ref.h>
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
class VersionChecker final {
|
||||
public:
|
||||
//TODO Write a cpputils::shared_ref and use it
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <cpp-utils/network/CurlHttpClient.h>
|
||||
#endif
|
||||
|
||||
using namespace cryfs;
|
||||
using namespace cryfs_cli;
|
||||
using cpputils::Random;
|
||||
using cpputils::SCrypt;
|
||||
using cpputils::IOStreamConsole;
|
||||
@ -35,13 +35,13 @@ int main(int argc, const char *argv[]) {
|
||||
#endif
|
||||
return Cli(keyGenerator, SCrypt::DefaultSettings, make_shared<IOStreamConsole>())
|
||||
.main(argc, argv, std::move(httpClient), []{});
|
||||
} catch (const CryfsException &e) {
|
||||
} catch (const cryfs::CryfsException &e) {
|
||||
if (e.what() != string()) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
}
|
||||
return exitCode(e.errorCode());
|
||||
} catch (const std::exception &e) {
|
||||
cerr << "Error: " << e.what();
|
||||
return exitCode(ErrorCode::UnspecifiedError);
|
||||
return exitCode(cryfs::ErrorCode::UnspecifiedError);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace bf = boost::filesystem;
|
||||
using namespace cryfs::program_options;
|
||||
using namespace cryfs_cli::program_options;
|
||||
using cryfs::CryConfigConsole;
|
||||
using cryfs::CryfsException;
|
||||
using cryfs::ErrorCode;
|
||||
|
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_PROGRAMOPTIONS_PARSER_H
|
||||
#define MESSMER_CRYFS_PROGRAMOPTIONS_PARSER_H
|
||||
#ifndef MESSMER_CRYFSCLI_PROGRAMOPTIONS_PARSER_H
|
||||
#define MESSMER_CRYFSCLI_PROGRAMOPTIONS_PARSER_H
|
||||
|
||||
#include "ProgramOptions.h"
|
||||
#include <boost/program_options.hpp>
|
||||
#include <cryfs/ErrorCodes.h>
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
namespace program_options {
|
||||
class Parser final {
|
||||
public:
|
||||
@ -21,7 +21,7 @@ namespace cryfs {
|
||||
static void _addPositionalOptionForBaseDir(boost::program_options::options_description *desc,
|
||||
boost::program_options::positional_options_description *positional);
|
||||
static void _showHelp();
|
||||
[[noreturn]] static void _showHelpAndExit(const std::string& message, ErrorCode errorCode);
|
||||
[[noreturn]] static void _showHelpAndExit(const std::string& message, cryfs::ErrorCode errorCode);
|
||||
[[noreturn]] static void _showCiphersAndExit(const std::vector<std::string> &supportedCiphers);
|
||||
[[noreturn]] static void _showVersionAndExit();
|
||||
static boost::program_options::variables_map _parseOptionsOrShowHelp(const std::vector<std::string> &options, const std::vector<std::string> &supportedCiphers);
|
||||
|
@ -1,8 +1,9 @@
|
||||
#include "ProgramOptions.h"
|
||||
#include <cstring>
|
||||
#include <cpp-utils/assert/assert.h>
|
||||
#include <cpp-utils/system/path.h>
|
||||
|
||||
using namespace cryfs::program_options;
|
||||
using namespace cryfs_cli::program_options;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using boost::optional;
|
||||
@ -16,11 +17,7 @@ ProgramOptions::ProgramOptions(bf::path baseDir, bf::path mountDir, optional<bf:
|
||||
boost::optional<bool> missingBlockIsIntegrityViolation,
|
||||
vector<string> fuseOptions)
|
||||
: _configFile(std::move(configFile)), _baseDir(bf::absolute(std::move(baseDir))), _mountDir(std::move(mountDir)),
|
||||
#if defined(_MSC_VER)
|
||||
_mountDirIsDriveLetter(_mountDir.has_root_path() && !_mountDir.has_root_directory() && !_mountDir.has_parent_path()),
|
||||
#else
|
||||
_mountDirIsDriveLetter(false),
|
||||
#endif
|
||||
_mountDirIsDriveLetter(cpputils::path_is_just_drive_letter(_mountDir)),
|
||||
_foreground(foreground),
|
||||
_allowFilesystemUpgrade(allowFilesystemUpgrade), _allowReplacedFilesystem(allowReplacedFilesystem), _allowIntegrityViolations(allowIntegrityViolations),
|
||||
_cipher(std::move(cipher)), _blocksizeBytes(std::move(blocksizeBytes)), _unmountAfterIdleMinutes(std::move(unmountAfterIdleMinutes)),
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_PROGRAMOPTIONS_PROGRAMOPTIONS_H
|
||||
#define MESSMER_CRYFS_PROGRAMOPTIONS_PROGRAMOPTIONS_H
|
||||
#ifndef MESSMER_CRYFSCLI_PROGRAMOPTIONS_PROGRAMOPTIONS_H
|
||||
#define MESSMER_CRYFSCLI_PROGRAMOPTIONS_PROGRAMOPTIONS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@ -8,7 +8,7 @@
|
||||
#include <cpp-utils/macros.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
namespace program_options {
|
||||
class ProgramOptions final {
|
||||
public:
|
||||
|
@ -7,7 +7,7 @@ using std::make_pair;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
namespace program_options {
|
||||
pair<vector<string>, vector<string>> splitAtDoubleDash(const vector<string> &options) {
|
||||
auto doubleDashIterator = std::find(options.begin(), options.end(), string("--"));
|
||||
|
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_PROGRAMOPTIONS_UTILS_H
|
||||
#define MESSMER_CRYFS_PROGRAMOPTIONS_UTILS_H
|
||||
#ifndef MESSMER_CRYFSCLI_PROGRAMOPTIONS_UTILS_H
|
||||
#define MESSMER_CRYFSCLI_PROGRAMOPTIONS_UTILS_H
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace cryfs {
|
||||
namespace cryfs_cli {
|
||||
namespace program_options {
|
||||
/**
|
||||
* Splits an array of program options into two arrays of program options, split at a double dash '--' option.
|
||||
|
24
src/cryfs-unmount/CMakeLists.txt
Normal file
24
src/cryfs-unmount/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
project (cryfs-unmount)
|
||||
INCLUDE(GNUInstallDirs)
|
||||
|
||||
set(SOURCES
|
||||
program_options/ProgramOptions.cpp
|
||||
program_options/Parser.cpp
|
||||
Cli.cpp
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC cpp-utils cryfs fspp-fuse)
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
target_activate_cpp14(${PROJECT_NAME})
|
||||
|
||||
add_executable(${PROJECT_NAME}_bin main_unmount.cpp)
|
||||
set_target_properties(${PROJECT_NAME}_bin PROPERTIES OUTPUT_NAME cryfs-unmount)
|
||||
target_link_libraries(${PROJECT_NAME}_bin PUBLIC ${PROJECT_NAME})
|
||||
target_enable_style_warnings(${PROJECT_NAME}_bin)
|
||||
target_activate_cpp14(${PROJECT_NAME}_bin)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}_bin
|
||||
CONFIGURATIONS Debug Release RelWithDebInfo
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
36
src/cryfs-unmount/Cli.cpp
Normal file
36
src/cryfs-unmount/Cli.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "Cli.h"
|
||||
#include <fspp/fuse/Fuse.h>
|
||||
#include <cryfs-unmount/program_options/Parser.h>
|
||||
#include <gitversion/gitversion.h>
|
||||
#include <cryfs/CryfsException.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using fspp::fuse::Fuse;
|
||||
using cryfs_unmount::program_options::Parser;
|
||||
using cryfs_unmount::program_options::ProgramOptions;
|
||||
|
||||
namespace cryfs_unmount {
|
||||
|
||||
namespace {
|
||||
void _showVersion() {
|
||||
std::cout << "CryFS Version " << gitversion::VersionString() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Cli::main(int argc, const char* argv[]) {
|
||||
_showVersion();
|
||||
ProgramOptions options = Parser(argc, argv).parse();
|
||||
|
||||
if (!boost::filesystem::exists(options.mountDir())) {
|
||||
throw cryfs::CryfsException("Given mountdir doesn't exist", cryfs::ErrorCode::InaccessibleMountDir);
|
||||
}
|
||||
// TODO This doesn't seem to work with relative paths
|
||||
std::cout << "Unmounting CryFS filesystem at " << options.mountDir() << "." << std::endl;
|
||||
Fuse::unmount(options.mountDir());
|
||||
|
||||
// TODO Wait until it is actually unmounted and then show a better success message?
|
||||
std::cout << "Filesystem is unmounting now." << std::endl;
|
||||
}
|
||||
|
||||
}
|
14
src/cryfs-unmount/Cli.h
Normal file
14
src/cryfs-unmount/Cli.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFSUNMOUNT_CLI_H
|
||||
#define MESSMER_CRYFSUNMOUNT_CLI_H
|
||||
|
||||
namespace cryfs_unmount {
|
||||
|
||||
class Cli final {
|
||||
public:
|
||||
void main(int argc, const char* argv[]);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
38
src/cryfs-unmount/main_unmount.cpp
Normal file
38
src/cryfs-unmount/main_unmount.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#if defined(_MSC_VER)
|
||||
#include <Windows.h>
|
||||
#include <VersionHelpers.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <cryfs/CryfsException.h>
|
||||
#include <cpp-utils/assert/backtrace.h>
|
||||
#include "Cli.h"
|
||||
|
||||
using std::cerr;
|
||||
using cryfs::ErrorCode;
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
#if defined(_MSC_VER)
|
||||
if (!IsWindows7SP1OrGreater()) {
|
||||
std::cerr << "CryFS is currently only supported on Windows 7 SP1 (or later)." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
cpputils::showBacktraceOnCrash();
|
||||
|
||||
try {
|
||||
cryfs_unmount::Cli().main(argc, argv);
|
||||
}
|
||||
catch (const cryfs::CryfsException &e) {
|
||||
if (e.what() != std::string()) {
|
||||
std::cerr << "Error " << static_cast<int>(e.errorCode()) << ": " << e.what() << std::endl;
|
||||
}
|
||||
return exitCode(e.errorCode());
|
||||
}
|
||||
catch (const std::runtime_error &e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return exitCode(ErrorCode::UnspecifiedError);
|
||||
}
|
||||
return exitCode(ErrorCode::Success);
|
||||
}
|
128
src/cryfs-unmount/program_options/Parser.cpp
Normal file
128
src/cryfs-unmount/program_options/Parser.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
#include "Parser.h"
|
||||
#include <iostream>
|
||||
#include <boost/optional.hpp>
|
||||
#include <cryfs/config/CryConfigConsole.h>
|
||||
#include <cryfs/CryfsException.h>
|
||||
#include <cryfs-cli/Environment.h>
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace bf = boost::filesystem;
|
||||
using namespace cryfs_unmount::program_options;
|
||||
using cryfs::CryConfigConsole;
|
||||
using cryfs::CryfsException;
|
||||
using cryfs::ErrorCode;
|
||||
using std::vector;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
Parser::Parser(int argc, const char *argv[])
|
||||
:_options(_argsToVector(argc, argv)) {
|
||||
}
|
||||
|
||||
vector<string> Parser::_argsToVector(int argc, const char *argv[]) {
|
||||
vector<string> result;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
result.push_back(argv[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ProgramOptions Parser::parse() const {
|
||||
po::variables_map vm = _parseOptionsOrShowHelp(_options);
|
||||
|
||||
if (!vm.count("mount-dir")) {
|
||||
_showHelpAndExit("Please specify a mount directory.", ErrorCode::InvalidArguments);
|
||||
}
|
||||
bf::path mountDir = vm["mount-dir"].as<string>();
|
||||
|
||||
return ProgramOptions(std::move(mountDir));
|
||||
}
|
||||
|
||||
po::variables_map Parser::_parseOptionsOrShowHelp(const vector<string> &options) {
|
||||
try {
|
||||
return _parseOptions(options);
|
||||
}
|
||||
catch (const CryfsException& e) {
|
||||
// If CryfsException is thrown, we already know what's wrong.
|
||||
// Show usage information and pass through the exception, don't catch it.
|
||||
if (e.errorCode() != ErrorCode::Success) {
|
||||
_showHelp();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
_showHelpAndExit("Invalid arguments", ErrorCode::InvalidArguments);
|
||||
}
|
||||
}
|
||||
|
||||
po::variables_map Parser::_parseOptions(const vector<string> &options) {
|
||||
po::options_description desc;
|
||||
po::positional_options_description positional_desc;
|
||||
_addAllowedOptions(&desc);
|
||||
_addPositionalOptionForBaseDir(&desc, &positional_desc);
|
||||
|
||||
po::variables_map vm;
|
||||
vector<const char*> _options = _to_const_char_vector(options);
|
||||
po::store(po::command_line_parser(_options.size(), _options.data())
|
||||
.options(desc).positional(positional_desc).run(), vm);
|
||||
if (vm.count("help")) {
|
||||
_showHelpAndExit("", ErrorCode::Success);
|
||||
}
|
||||
if (vm.count("version")) {
|
||||
_showVersionAndExit();
|
||||
}
|
||||
po::notify(vm);
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
vector<const char*> Parser::_to_const_char_vector(const vector<string> &options) {
|
||||
vector<const char*> result;
|
||||
result.reserve(options.size());
|
||||
for (const string &option : options) {
|
||||
result.push_back(option.c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Parser::_addAllowedOptions(po::options_description *desc) {
|
||||
po::options_description options("Allowed options");
|
||||
string cipher_description = "Cipher to use for encryption. See possible values by calling cryfs with --show-ciphers. Default: ";
|
||||
cipher_description += CryConfigConsole::DEFAULT_CIPHER;
|
||||
string blocksize_description = "The block size used when storing ciphertext blocks (in bytes). Default: ";
|
||||
blocksize_description += std::to_string(CryConfigConsole::DEFAULT_BLOCKSIZE_BYTES);
|
||||
options.add_options()
|
||||
("help,h", "show help message")
|
||||
("version", "Show CryFS version number")
|
||||
;
|
||||
desc->add(options);
|
||||
}
|
||||
|
||||
void Parser::_addPositionalOptionForBaseDir(po::options_description *desc, po::positional_options_description *positional) {
|
||||
positional->add("mount-dir", 1);
|
||||
po::options_description hidden("Hidden options");
|
||||
hidden.add_options()
|
||||
("mount-dir", po::value<string>(), "Mount directory")
|
||||
;
|
||||
desc->add(hidden);
|
||||
}
|
||||
|
||||
void Parser::_showHelp() {
|
||||
cerr << "Usage: cryfs-unmount [mountPoint]\n";
|
||||
po::options_description desc;
|
||||
_addAllowedOptions(&desc);
|
||||
cerr << desc << endl;
|
||||
}
|
||||
|
||||
[[noreturn]] void Parser::_showHelpAndExit(const std::string& message, ErrorCode errorCode) {
|
||||
_showHelp();
|
||||
throw CryfsException(message, errorCode);
|
||||
}
|
||||
|
||||
[[noreturn]] void Parser::_showVersionAndExit() {
|
||||
// no need to show version because it was already shown in the CryFS header before parsing program options
|
||||
throw CryfsException("", ErrorCode::Success);
|
||||
}
|
37
src/cryfs-unmount/program_options/Parser.h
Normal file
37
src/cryfs-unmount/program_options/Parser.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFSUNMOUNT_PROGRAMOPTIONS_PARSER_H
|
||||
#define MESSMER_CRYFSUNMOUNT_PROGRAMOPTIONS_PARSER_H
|
||||
|
||||
#include "ProgramOptions.h"
|
||||
#include <boost/program_options.hpp>
|
||||
#include <cryfs/ErrorCodes.h>
|
||||
|
||||
namespace cryfs_unmount {
|
||||
namespace program_options {
|
||||
class Parser final {
|
||||
public:
|
||||
Parser(int argc, const char *argv[]);
|
||||
|
||||
ProgramOptions parse() const;
|
||||
|
||||
private:
|
||||
static std::vector<std::string> _argsToVector(int argc, const char *argv[]);
|
||||
static std::vector<const char*> _to_const_char_vector(const std::vector<std::string> &options);
|
||||
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);
|
||||
static void _showHelp();
|
||||
[[noreturn]] static void _showHelpAndExit(const std::string& message, cryfs::ErrorCode errorCode);
|
||||
[[noreturn]] static void _showCiphersAndExit(const std::vector<std::string> &supportedCiphers);
|
||||
[[noreturn]] static void _showVersionAndExit();
|
||||
static boost::program_options::variables_map _parseOptionsOrShowHelp(const std::vector<std::string> &options);
|
||||
static boost::program_options::variables_map _parseOptions(const std::vector<std::string> &options);
|
||||
|
||||
std::vector<std::string> _options;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Parser);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
25
src/cryfs-unmount/program_options/ProgramOptions.cpp
Normal file
25
src/cryfs-unmount/program_options/ProgramOptions.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "ProgramOptions.h"
|
||||
#include <cstring>
|
||||
#include <cpp-utils/assert/assert.h>
|
||||
#include <cpp-utils/system/path.h>
|
||||
|
||||
using namespace cryfs_unmount::program_options;
|
||||
using std::string;
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
ProgramOptions::ProgramOptions(bf::path mountDir)
|
||||
:_mountDir(std::move(mountDir)),
|
||||
_mountDirIsDriveLetter(cpputils::path_is_just_drive_letter(_mountDir))
|
||||
{
|
||||
if (!_mountDirIsDriveLetter) {
|
||||
_mountDir = bf::absolute(std::move(_mountDir));
|
||||
}
|
||||
}
|
||||
|
||||
const bf::path &ProgramOptions::mountDir() const {
|
||||
return _mountDir;
|
||||
}
|
||||
|
||||
bool ProgramOptions::mountDirIsDriveLetter() const {
|
||||
return _mountDirIsDriveLetter;
|
||||
}
|
30
src/cryfs-unmount/program_options/ProgramOptions.h
Normal file
30
src/cryfs-unmount/program_options/ProgramOptions.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFSUNMOUNT_PROGRAMOPTIONS_PROGRAMOPTIONS_H
|
||||
#define MESSMER_CRYFSUNMOUNT_PROGRAMOPTIONS_PROGRAMOPTIONS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <boost/optional.hpp>
|
||||
#include <cpp-utils/macros.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace cryfs_unmount {
|
||||
namespace program_options {
|
||||
class ProgramOptions final {
|
||||
public:
|
||||
ProgramOptions(boost::filesystem::path mountDir);
|
||||
ProgramOptions(ProgramOptions &&rhs) = default;
|
||||
|
||||
const boost::filesystem::path &mountDir() const;
|
||||
bool mountDirIsDriveLetter() const;
|
||||
|
||||
private:
|
||||
boost::filesystem::path _mountDir;
|
||||
bool _mountDirIsDriveLetter;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProgramOptions);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -7,9 +7,15 @@
|
||||
#include <iostream>
|
||||
#include <cpp-utils/assert/assert.h>
|
||||
#include <cpp-utils/logging/logging.h>
|
||||
#include <cpp-utils/process/subprocess.h>
|
||||
#include <csignal>
|
||||
#include "InvalidFilesystem.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <codecvt>
|
||||
#include <dokan/dokan.h>
|
||||
#endif
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
@ -307,14 +313,24 @@ bool Fuse::running() const {
|
||||
}
|
||||
|
||||
void Fuse::stop() {
|
||||
unmount(_mountdir, false);
|
||||
}
|
||||
|
||||
void Fuse::unmount(const bf::path& mountdir, bool force) {
|
||||
//TODO Find better way to unmount (i.e. don't use external fusermount). Unmounting by kill(getpid(), SIGINT) worked, but left the mount directory transport endpoint as not connected.
|
||||
#ifdef __APPLE__
|
||||
int ret = system(("umount " + _mountdir.string()).c_str());
|
||||
#if defined(__APPLE__)
|
||||
int returncode = cpputils::Subprocess::call(std::string("umount ") + mountdir.string()).exitcode;
|
||||
#elif defined(_MSC_VER)
|
||||
std::wstring mountdir_ = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(mountdir.string());
|
||||
BOOL success = DokanRemoveMountPoint(mountdir_.c_str());
|
||||
int returncode = success ? 0 : -1;
|
||||
#else
|
||||
int ret = system(("fusermount -z -u " + _mountdir.string()).c_str()); // "-z" takes care that if the filesystem can't be unmounted right now because something is opened, it will be unmounted as soon as it can be.
|
||||
std::string command = force ? "fusermount -u" : "fusermount -z -u"; // "-z" takes care that if the filesystem can't be unmounted right now because something is opened, it will be unmounted as soon as it can be.
|
||||
int returncode = cpputils::Subprocess::call(
|
||||
command + " " + mountdir.string()).exitcode;
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
LOG(ERR, "Could not unmount filesystem");
|
||||
if (returncode != 0) {
|
||||
throw std::runtime_error("Could not unmount filesystem");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@ public:
|
||||
bool running() const;
|
||||
void stop();
|
||||
|
||||
static void unmount(const boost::filesystem::path &mountdir, bool force = false);
|
||||
|
||||
int getattr(const boost::filesystem::path &path, fspp::fuse::STAT *stbuf);
|
||||
int fgetattr(const boost::filesystem::path &path, fspp::fuse::STAT *stbuf, fuse_file_info *fileinfo);
|
||||
int readlink(const boost::filesystem::path &path, char *buf, size_t size);
|
||||
|
@ -49,6 +49,7 @@ set(SOURCES
|
||||
assert/assert_debug_test.cpp
|
||||
system/GetTotalMemoryTest.cpp
|
||||
system/TimeTest.cpp
|
||||
system/PathTest.cpp
|
||||
system/FiletimeTest.cpp
|
||||
system/MemoryTest.cpp
|
||||
system/HomedirTest.cpp
|
||||
|
32
test/cpp-utils/system/PathTest.cpp
Normal file
32
test/cpp-utils/system/PathTest.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <cpp-utils/system/path.h>
|
||||
|
||||
using cpputils::path_is_just_drive_letter;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
TEST(PathTest, pathIsJustDriveLetter) {
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C"));
|
||||
EXPECT_TRUE(path_is_just_drive_letter("C:"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:\\"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:/"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:\\test"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:\\test\\"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("/"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter(""));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
TEST(PathTest, onNonWindowsWeDontHaveDriveLetterPaths) {
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:\\"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:/"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:\\test"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("C:\\test\\"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter("/"));
|
||||
EXPECT_FALSE(path_is_just_drive_letter(""));
|
||||
}
|
||||
|
||||
#endif
|
@ -12,12 +12,12 @@ set(SOURCES
|
||||
EnvironmentTest.cpp
|
||||
VersionCheckerTest.cpp
|
||||
CliTest_IntegrityCheck.cpp
|
||||
CryfsUnmountTest.cpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest cryfs-cli)
|
||||
target_link_libraries(${PROJECT_NAME} googletest cryfs-cli cryfs-unmount fspp-fuse)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
target_activate_cpp14(${PROJECT_NAME})
|
||||
|
||||
|
@ -8,7 +8,7 @@ using cpputils::make_unique_ref;
|
||||
using boost::chrono::milliseconds;
|
||||
using boost::chrono::minutes;
|
||||
using boost::this_thread::sleep_for;
|
||||
using namespace cryfs;
|
||||
using namespace cryfs_cli;
|
||||
|
||||
class CallAfterTimeoutTest : public ::testing::Test {
|
||||
public:
|
||||
|
25
test/cryfs-cli/CryfsUnmountTest.cpp
Normal file
25
test/cryfs-cli/CryfsUnmountTest.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "testutils/CliTest.h"
|
||||
#include <cryfs-cli/Cli.h>
|
||||
#include <cryfs-unmount/Cli.h>
|
||||
|
||||
using CliTest_Unmount = CliTest;
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
namespace {
|
||||
void unmount(const bf::path& mountdir) {
|
||||
std::vector<const char*> _args = {"cryfs-unmount", mountdir.string().c_str()};
|
||||
cryfs_unmount::Cli().main(2, _args.data());
|
||||
}
|
||||
|
||||
TEST_F(CliTest_Unmount, givenMountedFilesystem_whenUnmounting_thenSucceeds) {
|
||||
// we're passing in boost::none as mountdir so EXPECT_RUN_SUCCESS doesn't unmount itself.
|
||||
// if the unmount we're calling here in the onMounted callback wouldn't work, EXPECT_RUN_SUCCESS
|
||||
// would never return and this would be a deadlock.
|
||||
EXPECT_RUN_SUCCESS({basedir.string().c_str(), mountdir.string().c_str(), "-f"}, boost::none, [this] () {
|
||||
unmount(mountdir);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO Test calling with invalid args, valid '--version' or '--help' args, with a non-mounted mountdir and a nonexisting mountdir.
|
||||
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <cpp-utils/system/env.h>
|
||||
|
||||
using namespace cryfs;
|
||||
using namespace cryfs_cli;
|
||||
using std::string;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
|
@ -8,7 +8,7 @@ using cpputils::FakeHttpClient;
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
using boost::none;
|
||||
using namespace cryfs;
|
||||
using namespace cryfs_cli;
|
||||
|
||||
class VersionCheckerTest: public ::testing::Test {
|
||||
public:
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <cpp-utils/testutils/CaptureStderrRAII.h>
|
||||
|
||||
using namespace cryfs;
|
||||
using namespace cryfs::program_options;
|
||||
using namespace cryfs_cli::program_options;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using boost::none;
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <cryfs-cli/program_options/ProgramOptions.h>
|
||||
#include <cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h>
|
||||
|
||||
using namespace cryfs::program_options;
|
||||
using namespace cryfs_cli::program_options;
|
||||
using boost::none;
|
||||
using boost::optional;
|
||||
using std::ostream;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "testutils/ProgramOptionsTestBase.h"
|
||||
#include <cryfs-cli/program_options/utils.h>
|
||||
|
||||
using namespace cryfs::program_options;
|
||||
using namespace cryfs_cli::program_options;
|
||||
using std::pair;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <cpp-utils/lock/ConditionBarrier.h>
|
||||
#include "../../cryfs/testutils/MockConsole.h"
|
||||
#include "../../cryfs/testutils/TestWithFakeHomeDirectory.h"
|
||||
#include <fspp/fuse/Fuse.h>
|
||||
#include <cryfs/ErrorCodes.h>
|
||||
#include <cpp-utils/testutils/CaptureStderrRAII.h>
|
||||
#include <regex>
|
||||
@ -53,7 +54,7 @@ public:
|
||||
ON_CALL(*console, askPassword(testing::StrEq("Password: "))).WillByDefault(testing::Return("pass"));
|
||||
ON_CALL(*console, askPassword(testing::StrEq("Confirm Password: "))).WillByDefault(testing::Return("pass"));
|
||||
// Run Cryfs
|
||||
return cryfs::Cli(keyGenerator, cpputils::SCrypt::TestSettings, console).main(_args.size(), _args.data(), _httpClient(), std::move(onMounted));
|
||||
return cryfs_cli::Cli(keyGenerator, cpputils::SCrypt::TestSettings, console).main(_args.size(), _args.data(), _httpClient(), std::move(onMounted));
|
||||
}
|
||||
|
||||
void EXPECT_EXIT_WITH_HELP_MESSAGE(const std::vector<std::string>& args, const std::string &message, cryfs::ErrorCode errorCode) {
|
||||
@ -90,18 +91,7 @@ public:
|
||||
};
|
||||
|
||||
static void _unmount(const boost::filesystem::path &mountDir) {
|
||||
int returncode = -1;
|
||||
#if defined(__APPLE__)
|
||||
returncode = cpputils::Subprocess::call(std::string("umount ") + mountDir.string().c_str() + " 2>/dev/null").exitcode;
|
||||
#elif defined(_MSC_VER)
|
||||
std::wstring mountDir_ = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(mountDir.string());
|
||||
BOOL success = DokanRemoveMountPoint(mountDir_.c_str());
|
||||
returncode = success ? 0 : -1;
|
||||
#else
|
||||
returncode = cpputils::Subprocess::call(
|
||||
std::string("fusermount -u ") + mountDir.string().c_str() + " 2>/dev/null").exitcode;
|
||||
#endif
|
||||
EXPECT_EQ(0, returncode);
|
||||
fspp::fuse::Fuse::unmount(mountDir, true);
|
||||
}
|
||||
|
||||
FilesystemOutput run_filesystem(const std::vector<std::string>& args, boost::optional<boost::filesystem::path> mountDirForUnmounting, std::function<void()> onMounted) {
|
||||
|
Loading…
Reference in New Issue
Block a user