diff --git a/CMakeLists.txt b/CMakeLists.txt index 990957f..ed04bc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required (VERSION 3.12 FATAL_ERROR) project (fuse3-p7zip - VERSION 1.1.0 + VERSION 1.2.0 DESCRIPTION "fuse3 file system that uses the p7zip library to mount archives" LANGUAGES CXX ) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..714da51 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +BUILD_TYPE ?= "Debug" +DIR = ".build-$(BUILD_TYPE)" + +.PHONY: \ + build + +$(DIR): + mkdir -p "$(DIR)" + +build: + @cmake -DCMAKE_BUILD_TYPE="$(BUILD_TYPE)" -S . -B "$(DIR)" + @make -j -C "$(DIR)" install + +tidy: + @cp -f "$(shell git rev-parse --show-toplevel)/.clang-format" /tmp + @tidyall -a -j 4 diff --git a/README.md b/README.md index 30a210e..13a7389 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,22 @@ encoding `cp866` will be enforced for listing archived files/directories. ## Configuration +### Command line options + +* -p + + Provide a password which will be used if archive is protected with a password. + ### Environment variables * FUSE3_P7ZIP_LIBRARY Change where application searches for 7z.so library. By default this is `/usr/lib/p7zip/7z.so` +* FUSE3_P7ZIP_PASSWORD + + Provide a password which will be used if archive is protected with a password. + * FUSE3_P7ZIP_FORCE_ENCODING Some archives (especially those ones created on windows) have file names encoded in non Unicode encoding. This @@ -68,22 +78,22 @@ encoding `cp866` will be enforced for listing archived files/directories. * FUSE3_P7ZIP_FORMATS - When opening a file application tries formats in alphabetical order. Sometimes it's desired to open a file with - format later in the list. This environment variable allows to override formats order. + When opening a file application tries all formats in the alphabetical order. Sometimes it's desired to open a file + with a format later in the list. This environment variable allows to override formats order. for example (try open .iso file with Iso or Udf formats first and only fallback on APM and GPT formats) ``` FUSE3_P7ZIP_FORMATS="Iso:Udf:*:APM:GPT" fuse3-p7zip ubuntu-20.04-desktop-amd64.iso /tmp/mnt ``` - To check list of available formats run `7z i` command + To check the list of all available formats run `7z i` command ## Examples ### vifm config snippet (mount 7zip supported archive with fuse3-p7zip in vifm) ```vim -filetype *.7z,*.zip, +filetype *.7z, \*.dsl.dz,*.tar,*.a,*.so,lib*.so.*,*.zip,*.ova,*.sfs, \*.apk,*.apm,*.ar,*.arj,*.cab,*.chm,*.cpio,*.cramfs,*.deb,*.dll,*.dmg,*.doc,*.esd,*.exe, \*.flv,*.hxs,*.img,*.iso,*.iso,*.jar,*.lib,*.macho,*.msi,*.msp,*.nsis,*.pkg,*.pmd,*.ppt, diff --git a/build b/build deleted file mode 100755 index 1f6163f..0000000 --- a/build +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -set -Eeuo pipefail - -BUILD_TYPE=${BUILD_TYPE:-Debug} -DIR=".build-$BUILD_TYPE" - -cmake -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -S . -B "$DIR" -#cmake --build "$DIR" --target install -make -j -C "$DIR" install diff --git a/cmake/FindFUSE.cmake b/cmake/FindFUSE.cmake deleted file mode 100644 index 099573c..0000000 --- a/cmake/FindFUSE.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# Find the FUSE includes and library -# -# FUSE_INCLUDE_DIR - where to find fuse.h, etc. -# FUSE_LIBRARIES - List of libraries when using FUSE. -# FUSE_FOUND - True if FUSE lib is found. - -# check if already in cache, be silent -if (FUSE_INCLUDE_DIR) - SET (FUSE_FIND_QUIETLY TRUE) -endif (FUSE_INCLUDE_DIR) - -if (APPLE) - set (FUSE_NAMES libosxfuse.dylib fuse) - set (FUSE_SUFFIXES osxfuse fuse) -elseif(WINDOWS) - set (FUSE_NAMES libdokanfuse1) - set (FUSE_SUFFIXES dokanfuse1) -else() - set(FUSE_NAMES fuse) - set(FUSE_SUFFIXES fuse) -endif() - -# find includes -find_path (FUSE_INCLUDE_DIR fuse.h - PATHS /opt /opt/local /usr/pkg - PATH_SUFFIXES ${FUSE_SUFFIXES} -) - -# find lib -find_library (FUSE_LIBRARIES NAMES ${FUSE_NAMES}) - -include ("FindPackageHandleStandardArgs") -find_package_handle_standard_args ( - "FUSE" DEFAULT_MSG FUSE_INCLUDE_DIR FUSE_LIBRARIES -) - -mark_as_advanced (FUSE_INCLUDE_DIR FUSE_LIBRARIES) diff --git a/include/7zip.hpp b/include/7zip.hpp index f771dc3..14fcf24 100644 --- a/include/7zip.hpp +++ b/include/7zip.hpp @@ -1,4 +1,4 @@ -#ifndef __FUSE3_7Z__7ZIP_HPP_ +#ifndef __FUSE3_7Z__7ZIP_HPP_ #define __FUSE3_7Z__7ZIP_HPP_ #include @@ -90,22 +90,39 @@ namespace sevenzip { virtual bool notify_progress(uint64_t current, uint64_t of) const = 0; }; - class EmptyOpenCallback: public IOpenCallback { + class OpenCallback: public IOpenCallback { + public: + OpenCallback(std::string password = std::string()) + : _password(password) + {} + std::string request_password() const override { - return std::string(); + return _password; } + + private: + std::string _password; }; - class EmptyExtractCallback: public IExtractCallback { + class ExtractCallback: public IExtractCallback { + public: + ExtractCallback(std::string password = std::string()) + : _password(password) + {} + std::string request_password() const override { - return std::string(); + return _password; } + bool notify_progress(uint64_t, uint64_t) const override { return true; } + + private: + std::string _password; }; class IFile { @@ -167,7 +184,7 @@ namespace sevenzip { bool is_file() const; bool is_dir() const; - File extract(const IExtractCallback& callback = EmptyExtractCallback()) const; + File extract(const IExtractCallback& callback) const; size_t get_props_count() const; diff --git a/include/pattern.hpp b/include/pattern.hpp index 96f13ca..796768d 100644 --- a/include/pattern.hpp +++ b/include/pattern.hpp @@ -18,7 +18,7 @@ namespace pattern { class Uncopyable { public: - Uncopyable(const Uncopyable&) = delete; + Uncopyable(const Uncopyable&) = delete; Uncopyable& operator=(const Uncopyable&) = delete; protected: diff --git a/include/string.hpp b/include/string.hpp index dc7005c..1ab5831 100644 --- a/include/string.hpp +++ b/include/string.hpp @@ -1,4 +1,4 @@ -#ifndef __FUSE3_7Z__STRING_HPP_ +#ifndef __FUSE3_7Z__STRING_HPP_ #define __FUSE3_7Z__STRING_HPP_ #include @@ -10,6 +10,8 @@ std::string utf8(const wchar_t* str); std::string utf8(const char* str, const char* encoding); +std::wstring wide_str(const char* str); + std::vector split(const std::string& d, std::string str); #endif diff --git a/src/7zip/Archive.cpp b/src/7zip/Archive.cpp index 786c522..97e6e31 100644 --- a/src/7zip/Archive.cpp +++ b/src/7zip/Archive.cpp @@ -1,4 +1,4 @@ -#include "7zip-impl.hpp" +#include "7zip-impl.hpp" #include "exception.hpp" #include "string.hpp" #include "logger.hpp" @@ -103,10 +103,10 @@ namespace sevenzip { return ret; } - HRESULT WINAPI ImplArchive::CryptoGetTextPassword(BSTR* password) + HRESULT WINAPI ImplArchive::CryptoGetTextPassword(BSTR* pass) { - // std::string ret = callback.request_password(); - // com::BStr(ret).detach(*password); + LogDebug("%s %p", __PRETTY_FUNCTION__, pass); + *pass = SysAllocString(wide_str(callback.request_password().c_str()).c_str()); return S_OK; } diff --git a/src/7zip/ArchiveExtractor.cpp b/src/7zip/ArchiveExtractor.cpp index dc4be45..ae0443f 100644 --- a/src/7zip/ArchiveExtractor.cpp +++ b/src/7zip/ArchiveExtractor.cpp @@ -1,6 +1,7 @@ -#include "7zip-impl.hpp" +#include "7zip-impl.hpp" #include "exception.hpp" #include "logger.hpp" +#include "string.hpp" namespace sevenzip { ULONG WINAPI ImplArchiveExtractor::AddRef() @@ -52,7 +53,7 @@ namespace sevenzip { HRESULT WINAPI ImplArchiveExtractor::SetCompleted(const UInt64* completeValue) { - LogDebug("%s: %p", __PRETTY_FUNCTION__, completeValue); + LogDebug("%s: %p %llu", __PRETTY_FUNCTION__, completeValue, *completeValue); HRESULT ret = S_OK; if (completeValue) ret = callback.notify_progress(*completeValue, total) == true ? S_OK : S_FALSE; @@ -128,9 +129,8 @@ namespace sevenzip { HRESULT WINAPI ImplArchiveExtractor::CryptoGetTextPassword(BSTR* pass) { - LogDebug("%s: %p", __PRETTY_FUNCTION__, pass); - //ustring ret = callback.request_password(); - //com::BStr(ret).detach(*pass); + LogDebug("%s %p", __PRETTY_FUNCTION__, pass); + *pass = SysAllocString(wide_str(callback.request_password().c_str()).c_str()); return S_OK; } diff --git a/src/7zip/Format.cpp b/src/7zip/Format.cpp index 32a10e4..41b0cb4 100644 --- a/src/7zip/Format.cpp +++ b/src/7zip/Format.cpp @@ -6,8 +6,7 @@ #include namespace sevenzip { - struct Guid: public GUID { - }; + struct Guid: public GUID {}; class ImplFormat: public IFormat { public: diff --git a/src/7zip/ReadStream.cpp b/src/7zip/ReadStream.cpp index 1d339c3..b365db7 100644 --- a/src/7zip/ReadStream.cpp +++ b/src/7zip/ReadStream.cpp @@ -2,8 +2,7 @@ #include "exception.hpp" namespace sevenzip { - class FileReadStream::FileHandle: public std::FILE { - }; + class FileReadStream::FileHandle: public std::FILE {}; HRESULT check_error(FileReadStream::FileHandle* file) { diff --git a/src/7zip/WriteStream.cpp b/src/7zip/WriteStream.cpp index 288a81c..56713b9 100644 --- a/src/7zip/WriteStream.cpp +++ b/src/7zip/WriteStream.cpp @@ -3,8 +3,7 @@ #include "logger.hpp" namespace sevenzip { - class FileWriteStream::FileHandle: public std::FILE { - }; + class FileWriteStream::FileHandle: public std::FILE {}; HRESULT check_error(FileWriteStream::FileHandle* file) { diff --git a/src/fuse3.cpp b/src/fuse3.cpp index 254e66f..10dca82 100644 --- a/src/fuse3.cpp +++ b/src/fuse3.cpp @@ -1,4 +1,4 @@ -#include "fuse3.hpp" +#include "fuse3.hpp" #include "exception.hpp" #include "logger.hpp" #include "pattern.hpp" @@ -11,7 +11,10 @@ #include #include -static const fuse_opt opts_spec[] = {FUSE_OPT_END}; +#define CMD_OPT(t, m) \ + { \ + t, offsetof(struct cmd_params_t, m), 1 \ + } enum arg_status : int { ARG_DISCARD = 0, @@ -21,10 +24,18 @@ enum arg_status : int { struct Cache { using FileTree = std::map>; - sevenzip::IArchive* arc; - FileTree tree; + sevenzip::IArchive* arc; + sevenzip::ExtractCallback ecb; + FileTree tree; }; +static struct cmd_params_t { + char* password = nullptr; + std::vector cli_args; +} cmd_params; + +static const fuse_opt opts_spec[] = {CMD_OPT("--password=%s", password), CMD_OPT("-p %s", password), FUSE_OPT_END}; + class Fuse::Params: public fuse_cmdline_opts { public: ~Params(); @@ -33,13 +44,13 @@ class Fuse::Params: public fuse_cmdline_opts { void print_usage(); static int process_arg(Params* fuse, const char* arg, int key, struct fuse_args* outargs); - fuse_args args; - std::vector cli_args; + fuse_args args; }; Fuse::Params::~Params() { free(mountpoint); + fuse_opt_free_args(&args); } Fuse::Params::Params(int argc, char** argv) @@ -47,10 +58,17 @@ Fuse::Params::Params(int argc, char** argv) mountpoint = nullptr; args = FUSE_ARGS_INIT(argc, argv); - CheckResult(fuse_opt_parse(&args, this, opts_spec, (fuse_opt_proc_t)&process_arg) != -1, "fuse_opt_parse"); + CheckResult(fuse_opt_parse(&args, &cmd_params, opts_spec, (fuse_opt_proc_t)&process_arg) != -1, "fuse_opt_parse"); CheckResult(fuse_parse_cmdline(&args, this) == 0, "fuse_parse_cmdline"); + if (!cmd_params.password) { + auto password = std::getenv("FUSE3_P7ZIP_PASSWORD"); + if (password) { + cmd_params.password = password; + } + } + if (show_version) { printf("%s\n", PROJECT_VERSION); // printf("FUSE library version %s\n", fuse_pkgversion()); @@ -58,6 +76,9 @@ Fuse::Params::Params(int argc, char** argv) exit(0); } else if (show_help) { print_usage(); + } else if (cmd_params.cli_args.empty()) { + fprintf(stderr, "error: no archive specified\n"); + exit(0); } else if (!mountpoint) { fprintf(stderr, "error: no mountpoint specified\n"); exit(0); @@ -67,6 +88,8 @@ Fuse::Params::Params(int argc, char** argv) void Fuse::Params::print_usage() { printf("usage: fuse3-7z [options] \n\n"); + printf("Options:\n"); + printf(" -p provide password for protected archives\n"); fuse_cmdline_help(); fuse_lib_help(&args); exit(0); @@ -74,11 +97,12 @@ void Fuse::Params::print_usage() int Fuse::Params::process_arg(Fuse::Params* fuse, const char* arg, int key, struct fuse_args* outargs) { + // printf("key: %d, arg: %s\n", key, arg); switch (key) { case FUSE_OPT_KEY_NONOPT: - fuse->cli_args.emplace_back(arg); - if (fuse->cli_args.back().empty()) fuse->print_usage(); - if (fuse->cli_args.size() == 1) return ARG_DISCARD; + cmd_params.cli_args.emplace_back(arg); + if (cmd_params.cli_args.back().empty()) fuse->print_usage(); + if (cmd_params.cli_args.size() == 1) return ARG_DISCARD; default: return ARG_KEEP; } @@ -148,7 +172,7 @@ int Fuse::Operations::cb_open(const char* path, fuse_file_info* fi) if (el->second.second.st_size > size) return -E2BIG; } - auto tmpfile = el->second.first.extract().release(); + auto tmpfile = el->second.first.extract(cache->ecb).release(); fi->fh = reinterpret_cast(tmpfile); LogDebug("fuse3 open fh: %p", fi->fh); @@ -203,12 +227,20 @@ Fuse::Fuse(int argc, char** argv) const std::string& Fuse::path() const { - return _params->cli_args[0]; + return cmd_params.cli_args[0]; +} + +std::string Fuse::password() const +{ + if (cmd_params.password) { + return std::string(cmd_params.password); + } + return std::string(); } ssize_t Fuse::execute(sevenzip::IArchive* arc) { - static auto cache = Cache{arc, Cache::FileTree()}; + static auto cache = Cache{arc, sevenzip::ExtractCallback(password()), Cache::FileTree()}; auto root = sevenzip::Path("/"); auto root_stat = arc->stat(); root_stat.st_mode = (root_stat.st_mode & ~S_IFMT) | S_IFDIR; diff --git a/src/include/7zip-impl.hpp b/src/include/7zip-impl.hpp index ad2c552..dd09c45 100644 --- a/src/include/7zip-impl.hpp +++ b/src/include/7zip-impl.hpp @@ -1,4 +1,4 @@ -#ifndef __FUSE3_7Z__7ZIP_PRIVATE_HPP_ +#ifndef __FUSE3_7Z__7ZIP_PRIVATE_HPP_ #define __FUSE3_7Z__7ZIP_PRIVATE_HPP_ #include "7zip.hpp" diff --git a/src/include/com.hpp b/src/include/com.hpp index 110bf48..b9f7faa 100644 --- a/src/include/com.hpp +++ b/src/include/com.hpp @@ -1,4 +1,4 @@ -#ifndef __FUSE3_7Z__COM_HPP_ +#ifndef __FUSE3_7Z__COM_HPP_ #define __FUSE3_7Z__COM_HPP_ #include diff --git a/src/include/fuse3.hpp b/src/include/fuse3.hpp index 9c91c8f..ebae157 100644 --- a/src/include/fuse3.hpp +++ b/src/include/fuse3.hpp @@ -1,4 +1,4 @@ -#ifndef __FUSE3_7Z__FUSE3_HPP__ +#ifndef __FUSE3_7Z__FUSE3_HPP__ #define __FUSE3_7Z__FUSE3_HPP__ #define FUSE_USE_VERSION 35 @@ -19,6 +19,7 @@ class Fuse { ssize_t execute(sevenzip::IArchive* archive); const std::string& path() const; + std::string password() const; private: class Params; diff --git a/src/main.cpp b/src/main.cpp index a5dd490..98d01f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,7 +31,7 @@ try { } log().printf("open archive: %s", loop.path().c_str()); - auto arc = lib->open(loop.path(), sevenzip::EmptyOpenCallback()); + auto arc = lib->open(loop.path(), sevenzip::OpenCallback(loop.password())); return loop.execute(arc.get()); } catch (std::exception& e) { diff --git a/src/string.cpp b/src/string.cpp index daaade8..9601e14 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -1,4 +1,4 @@ -#include "string.hpp" +#include "string.hpp" #include "exception.hpp" #include #include @@ -27,6 +27,24 @@ std::string utf8(const wchar_t* wstr) return std::string(result.get()); } +std::wstring wide_str(const char* str) +{ + auto conv = std::unique_ptr(iconv_open("WCHAR_T", "UTF-8"), &iconv_close); + CheckErrno(conv.get() != reinterpret_cast(-1), "iconv_open: "); + + size_t in_size = std::strlen(str); + + auto in_ptr = const_cast(str); + size_t buf_len = in_size * 4; + size_t buf_size = buf_len * sizeof(wchar_t); + auto buf = std::unique_ptr(new wchar_t[buf_size + 1]()); + auto buf_ptr = (char*)buf.get(); + + CheckErrno(iconv(conv.get(), &in_ptr, &in_size, &buf_ptr, &buf_size) != static_cast(-1), "iconv: "); + + return std::wstring(buf.get()); +} + std::string utf8(const char* str, const char* encoding) { // https://gist.github.com/hakre/4188459 diff --git a/t/tidy b/t/tidy deleted file mode 100755 index bd01275..0000000 --- a/t/tidy +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -Eeuo pipefail - -cp -f "$(git rev-parse --show-toplevel)/.clang-format" /tmp - -tidyall -a -j 4