mirror of
https://github.com/mhx/dwarfs.git
synced 2025-08-03 17:56:12 -04:00
feat: support building on OSX (should address gh #132)
This commit is contained in:
parent
b5fc39c496
commit
a97161e6da
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.DS_Store
|
||||
/@*
|
||||
/*.*fs
|
||||
/tmp/
|
||||
|
@ -225,6 +225,11 @@ endif()
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
if(APPLE)
|
||||
# For whatever reason, thrift is unhappy if we don't do this
|
||||
find_package(OpenSSL 1.1.1 MODULE REQUIRED)
|
||||
endif()
|
||||
|
||||
if(STATIC_BUILD_DO_NOT_USE)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
list(APPEND PKG_CONFIG_EXECUTABLE "--static")
|
||||
@ -576,7 +581,7 @@ list(APPEND BINARY_TARGETS dwarfsuniversal)
|
||||
list(APPEND MAIN_TARGETS mkdwarfs_main dwarfsck_main dwarfsbench_main
|
||||
dwarfsextract_main)
|
||||
|
||||
if(FUSE3_FOUND OR WINFSP)
|
||||
if(FUSE3_FOUND OR WINFSP OR APPLE)
|
||||
add_library(dwarfs_main src/dwarfs_main.cpp)
|
||||
target_compile_definitions(dwarfs_main PRIVATE _FILE_OFFSET_BITS=64)
|
||||
if(WINFSP)
|
||||
@ -586,6 +591,9 @@ if(FUSE3_FOUND OR WINFSP)
|
||||
target_link_libraries(dwarfs_main ${WINFSP})
|
||||
target_link_libraries(dwarfsuniversal delayimp.lib)
|
||||
target_link_options(dwarfsuniversal PRIVATE /DELAYLOAD:winfsp-x64.dll)
|
||||
elseif(APPLE)
|
||||
target_compile_definitions(dwarfs_main PRIVATE FUSE_USE_VERSION=29)
|
||||
target_link_libraries(dwarfs_main PkgConfig::FUSE)
|
||||
else()
|
||||
target_compile_definitions(dwarfs_main PRIVATE FUSE_USE_VERSION=35)
|
||||
target_link_libraries(dwarfs_main PkgConfig::FUSE3)
|
||||
@ -608,7 +616,7 @@ if(FUSE3_FOUND OR WINFSP)
|
||||
list(APPEND MAIN_TARGETS dwarfs_main)
|
||||
endif()
|
||||
|
||||
if(FUSE_FOUND AND (WITH_LEGACY_FUSE OR NOT FUSE3_FOUND))
|
||||
if(FUSE_FOUND AND (NOT APPLE) AND (WITH_LEGACY_FUSE OR NOT FUSE3_FOUND))
|
||||
add_library(dwarfs2_main src/dwarfs_main.cpp)
|
||||
target_compile_definitions(dwarfs2_main PRIVATE _FILE_OFFSET_BITS=64
|
||||
FUSE_USE_VERSION=29)
|
||||
@ -1086,11 +1094,15 @@ if(FALSE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(STATIC_BUILD_DO_NOT_USE AND NOT WIN32)
|
||||
if(STATIC_BUILD_DO_NOT_USE OR APPLE)
|
||||
foreach(tgt ${BINARY_TARGETS})
|
||||
list(APPEND FILES_TO_STRIP $<TARGET_FILE:${tgt}>)
|
||||
endforeach()
|
||||
add_custom_target(strip COMMAND strip -s ${FILES_TO_STRIP})
|
||||
if(APPLE)
|
||||
add_custom_target(strip COMMAND strip ${FILES_TO_STRIP})
|
||||
else()
|
||||
add_custom_target(strip COMMAND strip -s ${FILES_TO_STRIP})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PRJ_VERSION_FULL)
|
||||
@ -1110,7 +1122,7 @@ if(PRJ_VERSION_FULL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(STATIC_BUILD_DO_NOT_USE OR WIN32)
|
||||
if(STATIC_BUILD_DO_NOT_USE OR WIN32 OR APPLE)
|
||||
find_program(UPX_EXE upx upx.exe PATHS "c:/bin" DOC "ultimate packer for executables" REQUIRED)
|
||||
|
||||
set(UNIVERSAL_PACKED
|
||||
|
66
README.md
66
README.md
@ -23,6 +23,8 @@ A fast high compression read-only file system for Linux and Windows.
|
||||
- [Usage](#usage)
|
||||
- [Windows Support](#windows-support)
|
||||
- [Building on Windows](#building-on-windows)
|
||||
- [macOS Support](#macos-support)
|
||||
- [Building on macOS](#building-on-macos)
|
||||
- [Extended Attributes](#extended-attributes)
|
||||
- [Comparison](#comparison)
|
||||
- [With SquashFS](#with-squashfs)
|
||||
@ -507,6 +509,70 @@ your machine.
|
||||
> ninja test
|
||||
```
|
||||
|
||||
## macOS Support
|
||||
|
||||
Support for the macOS operating system is currently experimental.
|
||||
|
||||
The macOS version of the DwarFS filesystem driver relies on the awesome
|
||||
[macFUSE](https://https://osxfuse.github.io/) project.
|
||||
|
||||
### Building on macOS
|
||||
|
||||
Building on macOS involves a few steps, but should be relatively
|
||||
straightforward. This has so far only been tested on a 2014 iMac running
|
||||
macOS Big Sur. However, it seems to be possible to build universal (fat)
|
||||
binaries even on such an old platform.
|
||||
|
||||
- First, install [macFUSE](https://https://osxfuse.github.io/).
|
||||
|
||||
- Install the [mistletoe](https://pypi.org/project/mistletoe/) Python
|
||||
library, e.g.:
|
||||
|
||||
```
|
||||
$ pip3 install --user mistletoe
|
||||
```
|
||||
|
||||
- Install `ninja` using Homebrew (you can optionally also install `ccache`):
|
||||
|
||||
```
|
||||
$ brew install ninja
|
||||
```
|
||||
|
||||
- Clone the [vcpkg](https://vcpkg.io/),
|
||||
[lipo-dir-merge](https://github.com/faaxm/lipo-dir-merge) and
|
||||
DwarFS repositories:
|
||||
|
||||
```
|
||||
$ cd ~
|
||||
$ mkdir git
|
||||
$ cd git
|
||||
$ git clone https://github.com/Microsoft/vcpkg.git
|
||||
$ git clon ne https://github.com/faaxm/lipo-dir-merge
|
||||
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
|
||||
```
|
||||
|
||||
- Bootstrap `vcpkg`:
|
||||
|
||||
```
|
||||
$ ./vcpkg/bootstrap-vcpkg.sh
|
||||
```
|
||||
|
||||
- Build DwarFS:
|
||||
|
||||
```
|
||||
$ cd dwarfs
|
||||
$ git checkout experimental/osx-build
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ sh ../cmake/osx.sh rebuild-vcpkg
|
||||
$ sh ../cmake/osx.sh
|
||||
$ ninja
|
||||
$ export CTEST_PARALLEL_LEVEL=$(sysctl -n hw.logicalcpu)
|
||||
$ ninja test
|
||||
```
|
||||
|
||||
That's it!
|
||||
|
||||
## Extended Attributes
|
||||
|
||||
### Preserving Extended Attributes in DwarFS Images
|
||||
|
45
cmake/osx.sh
Executable file
45
cmake/osx.sh
Executable file
@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [[ -z "${VCPKG_ROOT}" ]]; then
|
||||
VCPKG_ROOT=$HOME/git/vcpkg
|
||||
fi
|
||||
|
||||
if [[ -z "${VCPKG_INSTALL_ROOT}" ]]; then
|
||||
VCPKG_INSTALL_ROOT=$HOME/git/@vcpkg-install
|
||||
fi
|
||||
|
||||
if [[ -z "${LIPO_DIR_MERGE}" ]]; then
|
||||
LIPO_DIR_MERGE=$HOME/git/lipo-dir-merge/lipo-dir-merge.py
|
||||
fi
|
||||
|
||||
build_mode=$1
|
||||
|
||||
if [[ -z $build_mode ]]; then
|
||||
build_mode="Release"
|
||||
fi
|
||||
|
||||
if [[ $build_mode == "rebuild-vcpkg" ]]; then
|
||||
for triplet in x64-osx arm64-osx; do
|
||||
rm -rf $VCPKG_INSTALL_ROOT/tmp/$triplet
|
||||
$VCPKG_ROOT/vcpkg install --triplet=$triplet --x-install-root=$VCPKG_INSTALL_ROOT/tmp/$triplet
|
||||
done
|
||||
|
||||
rm -rf $VCPKG_INSTALL_ROOT/uni-osx
|
||||
|
||||
echo "merging x64-osx and arm64-osx to uni-osx..."
|
||||
|
||||
python3 $LIPO_DIR_MERGE \
|
||||
$VCPKG_INSTALL_ROOT/tmp/x64-osx/x64-osx \
|
||||
$VCPKG_INSTALL_ROOT/tmp/arm64-osx/arm64-osx \
|
||||
$VCPKG_INSTALL_ROOT/uni-osx
|
||||
|
||||
echo "DONE"
|
||||
else
|
||||
cmake .. -GNinja \
|
||||
-DWITH_TESTS=ON -DPREFER_SYSTEM_ZSTD=ON -DUSE_JEMALLOC=OFF \
|
||||
-DCMAKE_BUILD_TYPE=$build_mode \
|
||||
-DCMAKE_PREFIX_PATH=$VCPKG_INSTALL_ROOT/uni-osx \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
|
||||
fi
|
@ -93,7 +93,8 @@ class cached_block_ final : public cached_block {
|
||||
|
||||
bool any_pages_swapped_out(std::vector<uint8_t>& tmp
|
||||
[[maybe_unused]]) const override {
|
||||
#ifndef _WIN32
|
||||
#if !(defined(_WIN32) || defined(__APPLE__))
|
||||
// TODO: should be possible to do this on Windows and macOS as well
|
||||
auto page_size = ::sysconf(_SC_PAGESIZE);
|
||||
tmp.resize((data_.size() + page_size - 1) / page_size);
|
||||
if (::mincore(const_cast<uint8_t*>(data_.data()), data_.size(),
|
||||
|
@ -328,10 +328,25 @@ void categorizer_manager_<LoggerPolicy>::set_metadata_requirements(
|
||||
template <typename LoggerPolicy>
|
||||
bool categorizer_manager_<LoggerPolicy>::deterministic_less(
|
||||
fragment_category a, fragment_category b) const {
|
||||
auto cmp = category_name(a.value()) <=> category_name(b.value());
|
||||
if (cmp != 0) {
|
||||
return cmp < 0;
|
||||
auto cna = category_name(a.value());
|
||||
auto cnb = category_name(b.value());
|
||||
|
||||
if (cna < cnb) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cna > cnb) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: the above can be replaced by the following once we have support for
|
||||
// spaceship operator everywhere
|
||||
//
|
||||
// auto cmp = category_name(a.value()) <=> category_name(b.value());
|
||||
// if (cmp != 0) {
|
||||
// return cmp < 0;
|
||||
// }
|
||||
|
||||
auto cat = DWARFS_NOTHROW(categories_.at(a.value()));
|
||||
auto categorizer = DWARFS_NOTHROW(categorizers_.at(cat.second));
|
||||
return categorizer->subcategory_less(a, b);
|
||||
|
@ -207,9 +207,15 @@ file_stat make_file_stat(fs::path const& path) {
|
||||
rv.size = st.st_size;
|
||||
rv.blksize = st.st_blksize;
|
||||
rv.blocks = st.st_blocks;
|
||||
#ifdef __APPLE__
|
||||
rv.atime = st.st_atimespec.tv_sec;
|
||||
rv.mtime = st.st_mtimespec.tv_sec;
|
||||
rv.ctime = st.st_ctimespec.tv_sec;
|
||||
#else
|
||||
rv.atime = st.st_atim.tv_sec;
|
||||
rv.mtime = st.st_mtim.tv_sec;
|
||||
rv.ctime = st.st_ctim.tv_sec;
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -716,7 +716,8 @@ void inode_manager_<LoggerPolicy>::try_scan_invalid(worker_group& wg,
|
||||
if (mm) {
|
||||
LOG_DEBUG << "successfully opened: " << p->path_as_string();
|
||||
|
||||
wg.add_job([this, p, ino, mm = std::move(mm)] {
|
||||
// TODO: p = p is a workaround for older Clang versions
|
||||
wg.add_job([this, p = p, ino, mm = std::move(mm)] {
|
||||
ino->scan(mm.get(), opts_, prog_);
|
||||
update_prog(ino, p);
|
||||
});
|
||||
|
@ -27,6 +27,11 @@
|
||||
|
||||
#include <boost/process/search_path.hpp>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach.h>
|
||||
#include <mach/thread_info.h>
|
||||
#endif
|
||||
|
||||
#include "dwarfs/mmap.h"
|
||||
#include "dwarfs/os_access_generic.h"
|
||||
#include "dwarfs/util.h"
|
||||
@ -132,7 +137,7 @@ void os_access_generic::thread_set_affinity(std::thread::id tid
|
||||
[[maybe_unused]],
|
||||
std::error_code& ec
|
||||
[[maybe_unused]]) const {
|
||||
#ifndef _WIN32
|
||||
#if !(defined(_WIN32) || defined(__APPLE__))
|
||||
cpu_set_t cpuset;
|
||||
|
||||
for (auto cpu : cpus) {
|
||||
@ -174,6 +179,24 @@ os_access_generic::thread_get_cpu_time(std::thread::id tid,
|
||||
|
||||
return std::chrono::nanoseconds(100 * (sys + user));
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
auto port = ::pthread_mach_thread_np(std_to_pthread_id(tid));
|
||||
|
||||
::thread_basic_info_data_t ti;
|
||||
::mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
||||
|
||||
if (::thread_info(port, THREAD_BASIC_INFO,
|
||||
reinterpret_cast<thread_info_t>(&ti),
|
||||
&count) != KERN_SUCCESS) {
|
||||
ec = std::make_error_code(std::errc::not_supported);
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::chrono::seconds(ti.user_time.seconds + ti.system_time.seconds) +
|
||||
std::chrono::microseconds(ti.user_time.microseconds +
|
||||
ti.system_time.microseconds);
|
||||
|
||||
#else
|
||||
|
||||
::clockid_t cid;
|
||||
|
@ -816,13 +816,21 @@ int op_statfs(char const* path, native_statvfs* st) {
|
||||
|
||||
#if DWARFS_FUSE_LOWLEVEL
|
||||
template <typename LoggerPolicy>
|
||||
void op_getxattr(fuse_req_t req, fuse_ino_t ino, char const* name,
|
||||
size_t size) {
|
||||
void op_getxattr(fuse_req_t req, fuse_ino_t ino, char const* name, size_t size
|
||||
#ifdef __APPLE__
|
||||
,
|
||||
uint32_t position
|
||||
#endif
|
||||
) {
|
||||
dUSERDATA;
|
||||
PERFMON_EXT_SCOPED_SECTION(userdata, op_getxattr)
|
||||
LOG_PROXY(LoggerPolicy, userdata.lgr);
|
||||
|
||||
LOG_DEBUG << __func__ << "(" << ino << ", " << name << ", " << size << ")";
|
||||
LOG_DEBUG << __func__ << "(" << ino << ", " << name << ", " << size
|
||||
#ifdef __APPLE__
|
||||
<< ", " << position
|
||||
#endif
|
||||
<< ")";
|
||||
|
||||
checked_reply_err(log_, req, [&] {
|
||||
std::ostringstream oss;
|
||||
@ -857,7 +865,12 @@ void op_getxattr(fuse_req_t req, fuse_ino_t ino, char const* name,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: figure out under which conditions we don't have ::view()
|
||||
#ifdef __APPLE__
|
||||
auto value = oss.str();
|
||||
#else
|
||||
auto value = oss.view();
|
||||
#endif
|
||||
|
||||
LOG_TRACE << __func__ << ": value.size=" << value.size()
|
||||
<< ", extra_size=" << extra_size;
|
||||
@ -912,7 +925,12 @@ void op_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) {
|
||||
|
||||
oss << inodeinfo_xattr << '\0';
|
||||
|
||||
// TODO: figure out under which conditions we don't have ::view()
|
||||
#ifdef __APPLE__
|
||||
auto xattrs = oss.str();
|
||||
#else
|
||||
auto xattrs = oss.view();
|
||||
#endif
|
||||
|
||||
LOG_TRACE << __func__ << ": xattrs.size=" << xattrs.size();
|
||||
|
||||
|
@ -248,8 +248,9 @@ TEST_P(options_test, cache_stress) {
|
||||
|
||||
for (auto const& [i, reqs] : folly::enumerate(data)) {
|
||||
auto& succ = success[i];
|
||||
threads.emplace_back([&] {
|
||||
for (auto const& req : reqs) {
|
||||
// TODO: preqs is a workaround for older Clang versions
|
||||
threads.emplace_back([&, preqs = &reqs] {
|
||||
for (auto const& req : *preqs) {
|
||||
auto fh = fs.open(req.inode);
|
||||
auto range = fs.readv(fh, req.size, req.offset);
|
||||
if (!range) {
|
||||
|
@ -57,6 +57,13 @@ namespace fs = std::filesystem;
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: this is a workaround for older Clang versions
|
||||
struct fs_path_hash {
|
||||
auto operator()(const std::filesystem::path& p) const noexcept {
|
||||
return std::filesystem::hash_value(p);
|
||||
}
|
||||
};
|
||||
|
||||
auto test_dir = fs::path(TEST_DATA_DIR).make_preferred();
|
||||
auto audio_data_dir = test_dir / "pcmaudio";
|
||||
|
||||
@ -700,7 +707,7 @@ TEST_P(term_logging_test, end_to_end) {
|
||||
auto err = t.err();
|
||||
auto it = log_level_strings.begin();
|
||||
|
||||
auto make_contains_regex = [fancy](auto m) {
|
||||
auto make_contains_regex = [fancy = fancy](auto m) {
|
||||
auto const& [color, prefix] = m->second;
|
||||
auto beg = fancy ? color : std::string_view{};
|
||||
auto end = fancy && !color.empty() ? "<normal>" : "";
|
||||
@ -2311,7 +2318,7 @@ TEST_P(map_file_error_test, delayed) {
|
||||
auto fs = t.fs_from_file("test.dwarfs");
|
||||
// fs.dump(std::cout, 2);
|
||||
|
||||
std::unordered_map<fs::path, std::string> actual_files;
|
||||
std::unordered_map<fs::path, std::string, fs_path_hash> actual_files;
|
||||
fs.walk([&](auto const& dev) {
|
||||
auto iv = dev.inode();
|
||||
if (iv.is_regular_file()) {
|
||||
@ -2360,8 +2367,8 @@ TEST_P(map_file_error_test, delayed) {
|
||||
failed_expected.end(),
|
||||
std::inserter(surprisingly_missing, surprisingly_missing.begin()));
|
||||
|
||||
std::unordered_map<fs::path, std::string> original_files(files.begin(),
|
||||
files.end());
|
||||
std::unordered_map<fs::path, std::string, fs_path_hash> original_files(
|
||||
files.begin(), files.end());
|
||||
|
||||
EXPECT_EQ(0, surprisingly_missing.size());
|
||||
|
||||
|
@ -38,7 +38,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/mount.h>
|
||||
#else
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
@ -123,10 +127,27 @@ class scoped_no_leak_check {
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
ssize_t portable_listxattr(const char* path, char* list, size_t size) {
|
||||
#ifdef __APPLE__
|
||||
return ::listxattr(path, list, size, 0);
|
||||
#else
|
||||
return ::listxattr(path, list, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t portable_getxattr(const char* path, const char* name, void* value,
|
||||
size_t size) {
|
||||
#ifdef __APPLE__
|
||||
return ::getxattr(path, name, value, size, 0, 0);
|
||||
#else
|
||||
return ::getxattr(path, name, value, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
pid_t get_dwarfs_pid(fs::path const& path) {
|
||||
std::array<char, 32> attr_buf;
|
||||
auto attr_len = ::getxattr(path.c_str(), "user.dwarfs.driver.pid",
|
||||
attr_buf.data(), attr_buf.size());
|
||||
auto attr_len = portable_getxattr(path.c_str(), "user.dwarfs.driver.pid",
|
||||
attr_buf.data(), attr_buf.size());
|
||||
if (attr_len < 0) {
|
||||
throw std::runtime_error("could not read pid from xattr");
|
||||
}
|
||||
@ -332,7 +353,7 @@ class subprocess {
|
||||
(append_arg(cmdline_, std::forward<Args>(args)), ...);
|
||||
|
||||
try {
|
||||
// std::cout << "running: " << cmdline() << "\n";
|
||||
// std::cerr << "running: " << cmdline() << "\n";
|
||||
c_ = bp::child(prog.string(), bp::args(cmdline_), bp::std_in.close(),
|
||||
bp::std_out > out_, bp::std_err > err_, ios_
|
||||
#ifdef _WIN32
|
||||
@ -346,6 +367,14 @@ class subprocess {
|
||||
}
|
||||
}
|
||||
|
||||
~subprocess() {
|
||||
if (pt_) {
|
||||
std::cerr << "subprocess still running in destructor: " << cmdline()
|
||||
<< "\n";
|
||||
pt_->join();
|
||||
}
|
||||
}
|
||||
|
||||
std::string cmdline() const {
|
||||
std::string cmd = prog_.string();
|
||||
if (!cmdline_.empty()) {
|
||||
@ -378,10 +407,13 @@ class subprocess {
|
||||
}
|
||||
|
||||
void interrupt() {
|
||||
std::cerr << "interrupting: " << cmdline() << "\n";
|
||||
#ifdef _WIN32
|
||||
::GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid());
|
||||
#else
|
||||
::kill(pid(), SIGINT);
|
||||
if (auto rv = ::kill(pid(), SIGINT); rv != 0) {
|
||||
std::cerr << "kill(" << pid() << ", SIGINT) = " << rv << "\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -438,7 +470,7 @@ class subprocess {
|
||||
std::vector<std::string> cmdline_;
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
#if !(defined(_WIN32) || defined(__APPLE__))
|
||||
class process_guard {
|
||||
public:
|
||||
process_guard() = default;
|
||||
@ -497,11 +529,21 @@ class driver_runner {
|
||||
|
||||
wait_until_file_ready(mountpoint, std::chrono::seconds(5));
|
||||
#else
|
||||
std::vector<std::string> options;
|
||||
#ifdef __APPLE__
|
||||
options.push_back("-o");
|
||||
options.push_back("noapplexattr");
|
||||
#endif
|
||||
if (!subprocess::check_run(driver, make_tool_arg(tool_arg), image,
|
||||
mountpoint, std::forward<Args>(args)...)) {
|
||||
mountpoint, options,
|
||||
std::forward<Args>(args)...)) {
|
||||
throw std::runtime_error("error running " + driver.string());
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
wait_until_file_ready(mountpoint, std::chrono::seconds(5));
|
||||
#else
|
||||
dwarfs_guard_ = process_guard(get_dwarfs_pid(mountpoint));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -518,7 +560,7 @@ class driver_runner {
|
||||
#endif
|
||||
std::forward<Args>(args)...);
|
||||
process_->run_background();
|
||||
#ifndef _WIN32
|
||||
#if !(defined(_WIN32) || defined(__APPLE__))
|
||||
dwarfs_guard_ = process_guard(process_->pid());
|
||||
#endif
|
||||
}
|
||||
@ -531,6 +573,27 @@ class driver_runner {
|
||||
#endif
|
||||
|
||||
if (!mountpoint_.empty()) {
|
||||
#ifdef __APPLE__
|
||||
auto umount = dwarfs::test::find_binary("umount");
|
||||
if (!umount) {
|
||||
throw std::runtime_error("no umount binary found");
|
||||
}
|
||||
subprocess::check_run(umount.value(), mountpoint_);
|
||||
bool rv{true};
|
||||
if (process_) {
|
||||
process_->wait();
|
||||
auto ec = process_->exit_code();
|
||||
if (ec != 0) {
|
||||
std::cerr << "driver failed to unmount:\nout:\n"
|
||||
<< process_->out() << "err:\n"
|
||||
<< process_->err() << "exit code: " << ec << "\n";
|
||||
rv = false;
|
||||
}
|
||||
}
|
||||
process_.reset();
|
||||
mountpoint_.clear();
|
||||
return rv;
|
||||
#else
|
||||
#ifndef _WIN32
|
||||
if (process_) {
|
||||
#endif
|
||||
@ -552,6 +615,7 @@ class driver_runner {
|
||||
mountpoint_.clear();
|
||||
return dwarfs_guard_.check_exit(std::chrono::seconds(5));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
@ -582,7 +646,7 @@ class driver_runner {
|
||||
}
|
||||
|
||||
private:
|
||||
#ifndef _WIN32
|
||||
#if !(defined(_WIN32) || defined(__APPLE__))
|
||||
static fs::path find_fusermount() {
|
||||
auto fusermount_bin = dwarfs::test::find_binary("fusermount");
|
||||
if (!fusermount_bin) {
|
||||
@ -606,7 +670,7 @@ class driver_runner {
|
||||
|
||||
fs::path mountpoint_;
|
||||
std::unique_ptr<subprocess> process_;
|
||||
#ifndef _WIN32
|
||||
#if !(defined(_WIN32) || defined(__APPLE__))
|
||||
process_guard dwarfs_guard_;
|
||||
#endif
|
||||
};
|
||||
@ -878,24 +942,26 @@ TEST_P(tools_test, end_to_end) {
|
||||
std::string buf;
|
||||
buf.resize(1);
|
||||
|
||||
auto r = ::listxattr(path.c_str(), buf.data(), buf.size());
|
||||
auto r = portable_listxattr(path.c_str(), buf.data(), buf.size());
|
||||
EXPECT_LT(r, 0) << runner.cmdline();
|
||||
EXPECT_EQ(ERANGE, errno) << runner.cmdline();
|
||||
r = ::listxattr(path.c_str(), buf.data(), 0);
|
||||
EXPECT_GT(r, 0) << runner.cmdline();
|
||||
r = portable_listxattr(path.c_str(), nullptr, 0);
|
||||
ASSERT_GT(r, 0) << runner.cmdline() << ::strerror(errno);
|
||||
buf.resize(r);
|
||||
r = ::listxattr(path.c_str(), buf.data(), buf.size());
|
||||
r = portable_listxattr(path.c_str(), buf.data(), buf.size());
|
||||
EXPECT_GT(r, 0) << runner.cmdline();
|
||||
EXPECT_EQ(ref, buf) << runner.cmdline();
|
||||
|
||||
buf.resize(1);
|
||||
r = ::getxattr(path.c_str(), kInodeInfoXattr, buf.data(), buf.size());
|
||||
r = portable_getxattr(path.c_str(), kInodeInfoXattr, buf.data(),
|
||||
buf.size());
|
||||
EXPECT_LT(r, 0) << runner.cmdline();
|
||||
EXPECT_EQ(ERANGE, errno) << runner.cmdline();
|
||||
r = ::getxattr(path.c_str(), kInodeInfoXattr, buf.data(), 0);
|
||||
EXPECT_GT(r, 0) << runner.cmdline();
|
||||
r = portable_getxattr(path.c_str(), kInodeInfoXattr, nullptr, 0);
|
||||
ASSERT_GT(r, 0) << runner.cmdline() << ::strerror(errno);
|
||||
buf.resize(r);
|
||||
r = ::getxattr(path.c_str(), kInodeInfoXattr, buf.data(), buf.size());
|
||||
r = portable_getxattr(path.c_str(), kInodeInfoXattr, buf.data(),
|
||||
buf.size());
|
||||
EXPECT_GT(r, 0) << runner.cmdline();
|
||||
|
||||
auto info = folly::parseJson(buf);
|
||||
@ -1045,18 +1111,25 @@ TEST_P(tools_test, end_to_end) {
|
||||
EXPECT_EQ(cdr.symlinks.size(), 2) << cdr;
|
||||
}
|
||||
|
||||
#define EXPECT_EC_IMPL(ec, cat, val) \
|
||||
EXPECT_TRUE(ec) << runner.cmdline(); \
|
||||
EXPECT_EQ(cat, (ec).category()) << runner.cmdline(); \
|
||||
EXPECT_EQ(val, (ec).value()) << runner.cmdline() << ": " << (ec).message()
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EXPECT_EC_UNIX_WIN(ec, unix, windows) \
|
||||
EXPECT_TRUE(ec) << runner.cmdline(); \
|
||||
EXPECT_EQ(std::system_category(), (ec).category()) << runner.cmdline(); \
|
||||
EXPECT_EQ(windows, (ec).value()) << runner.cmdline() << ": " << (ec).message()
|
||||
#define EXPECT_EC_UNIX_MAC_WIN(ec, unix, mac, windows) \
|
||||
EXPECT_EC_IMPL(ec, std::system_category(), windows)
|
||||
#elif defined(__APPLE__)
|
||||
#define EXPECT_EC_UNIX_MAC_WIN(ec, unix, mac, windows) \
|
||||
EXPECT_EC_IMPL(ec, std::generic_category(), mac)
|
||||
#else
|
||||
#define EXPECT_EC_UNIX_WIN(ec, unix, windows) \
|
||||
EXPECT_TRUE(ec) << runner.cmdline(); \
|
||||
EXPECT_EQ(std::generic_category(), (ec).category()) << runner.cmdline(); \
|
||||
EXPECT_EQ(unix, (ec).value()) << runner.cmdline() << ": " << (ec).message()
|
||||
#define EXPECT_EC_UNIX_MAC_WIN(ec, unix, mac, windows) \
|
||||
EXPECT_EC_IMPL(ec, std::generic_category(), unix)
|
||||
#endif
|
||||
|
||||
#define EXPECT_EC_UNIX_WIN(ec, unix, windows) \
|
||||
EXPECT_EC_UNIX_MAC_WIN(ec, unix, unix, windows)
|
||||
|
||||
TEST_P(tools_test, mutating_and_error_ops) {
|
||||
auto mode = GetParam();
|
||||
|
||||
@ -1136,7 +1209,7 @@ TEST_P(tools_test, mutating_and_error_ops) {
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::rename(file, name_inside_fs, ec);
|
||||
EXPECT_EC_UNIX_WIN(ec, ENOSYS, ERROR_ACCESS_DENIED);
|
||||
EXPECT_EC_UNIX_MAC_WIN(ec, ENOSYS, EACCES, ERROR_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1148,7 +1221,7 @@ TEST_P(tools_test, mutating_and_error_ops) {
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::rename(empty_dir, name_inside_fs, ec);
|
||||
EXPECT_EC_UNIX_WIN(ec, ENOSYS, ERROR_ACCESS_DENIED);
|
||||
EXPECT_EC_UNIX_MAC_WIN(ec, ENOSYS, EACCES, ERROR_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1162,7 +1235,7 @@ TEST_P(tools_test, mutating_and_error_ops) {
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::create_hard_link(file, name_inside_fs, ec);
|
||||
EXPECT_EC_UNIX_WIN(ec, ENOSYS, ERROR_ACCESS_DENIED);
|
||||
EXPECT_EC_UNIX_MAC_WIN(ec, ENOSYS, EACCES, ERROR_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1176,7 +1249,7 @@ TEST_P(tools_test, mutating_and_error_ops) {
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::create_symlink(file, name_inside_fs, ec);
|
||||
EXPECT_EC_UNIX_WIN(ec, ENOSYS, ERROR_ACCESS_DENIED);
|
||||
EXPECT_EC_UNIX_MAC_WIN(ec, ENOSYS, EACCES, ERROR_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1189,7 +1262,7 @@ TEST_P(tools_test, mutating_and_error_ops) {
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::create_directory_symlink(empty_dir, name_inside_fs, ec);
|
||||
EXPECT_EC_UNIX_WIN(ec, ENOSYS, ERROR_ACCESS_DENIED);
|
||||
EXPECT_EC_UNIX_MAC_WIN(ec, ENOSYS, EACCES, ERROR_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1212,7 +1285,7 @@ TEST_P(tools_test, mutating_and_error_ops) {
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::create_directory(name_inside_fs, ec);
|
||||
EXPECT_EC_UNIX_WIN(ec, ENOSYS, ERROR_ACCESS_DENIED);
|
||||
EXPECT_EC_UNIX_MAC_WIN(ec, ENOSYS, EACCES, ERROR_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
// read directory as file (non-mutating)
|
||||
|
Loading…
x
Reference in New Issue
Block a user