mirror of
https://github.com/mhx/dwarfs.git
synced 2025-09-08 20:12:56 -04:00
feat: allow uid/gid override in filesystem and FUSE driver (see gh #244)
This commit is contained in:
parent
2ff7602192
commit
3a895769de
@ -47,6 +47,14 @@ options:
|
||||
If you have a lot of CPUs, increasing this number can help
|
||||
speed up access to files in the filesystem.
|
||||
|
||||
- `-o uid=`*num*:
|
||||
Override the user ID for the whole file system. This option
|
||||
is not supported on Windows.
|
||||
|
||||
- `-o gid=`*num*:
|
||||
Override the group ID for the whole file system. This option
|
||||
is not supported on Windows.
|
||||
|
||||
- `-o decratio=`*value*:
|
||||
The ratio over which a block is fully decompressed. Blocks
|
||||
are only decompressed partially, so each block has to carry
|
||||
|
@ -21,6 +21,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
|
||||
#include <dwarfs/file_stat.h>
|
||||
|
||||
namespace dwarfs::reader {
|
||||
|
||||
struct metadata_options {
|
||||
@ -28,6 +33,8 @@ struct metadata_options {
|
||||
bool readonly{false};
|
||||
bool check_consistency{false};
|
||||
size_t block_size{512};
|
||||
std::optional<file_stat::uid_type> fs_uid{};
|
||||
std::optional<file_stat::gid_type> fs_gid{};
|
||||
};
|
||||
|
||||
} // namespace dwarfs::reader
|
||||
|
@ -1800,8 +1800,8 @@ metadata_<LoggerPolicy>::getattr_impl(inode_view iv,
|
||||
|
||||
stbuf.set_ino(inode + inode_offset_);
|
||||
stbuf.set_blksize(options_.block_size);
|
||||
stbuf.set_uid(iv.getuid());
|
||||
stbuf.set_gid(iv.getgid());
|
||||
stbuf.set_uid(options_.fs_uid.value_or(iv.getuid()));
|
||||
stbuf.set_gid(options_.fs_gid.value_or(iv.getgid()));
|
||||
stbuf.set_mtime(resolution * (timebase + ivr.mtime_offset()));
|
||||
|
||||
if (mtime_only) {
|
||||
|
@ -1229,6 +1229,63 @@ TEST(filesystem, uid_gid_count) {
|
||||
EXPECT_EQ(349999, st99999.gid());
|
||||
}
|
||||
|
||||
TEST(filesystem, uid_gid_override) {
|
||||
test::test_logger lgr;
|
||||
|
||||
auto input = std::make_shared<test::os_access_mock>();
|
||||
|
||||
input->add("", {1, 040755, 1, 0, 0, 10, 42, 0, 0, 0});
|
||||
input->add("foo16.txt", {2, 0100755, 1, 60000, 65535, 5, 42, 0, 0, 0},
|
||||
"hello");
|
||||
input->add("foo32.txt", {3, 0100755, 1, 65536, 4294967295, 5, 42, 0, 0, 0},
|
||||
"world");
|
||||
|
||||
auto fsimage = build_dwarfs(lgr, input, "null");
|
||||
|
||||
auto mm = std::make_shared<test::mmap_mock>(std::move(fsimage));
|
||||
|
||||
{
|
||||
reader::filesystem_options opts{.metadata = {
|
||||
.fs_uid = 99999,
|
||||
.fs_gid = 80000,
|
||||
}};
|
||||
|
||||
reader::filesystem_v2 fs(lgr, *input, mm, opts);
|
||||
|
||||
auto dev16 = fs.find("/foo16.txt");
|
||||
auto dev32 = fs.find("/foo32.txt");
|
||||
|
||||
ASSERT_TRUE(dev16);
|
||||
ASSERT_TRUE(dev32);
|
||||
|
||||
auto st16 = fs.getattr(dev16->inode());
|
||||
auto st32 = fs.getattr(dev32->inode());
|
||||
|
||||
EXPECT_EQ(99999, st16.uid());
|
||||
EXPECT_EQ(80000, st16.gid());
|
||||
EXPECT_EQ(99999, st32.uid());
|
||||
EXPECT_EQ(80000, st32.gid());
|
||||
}
|
||||
|
||||
{
|
||||
reader::filesystem_v2 fs(lgr, *input, mm);
|
||||
|
||||
auto dev16 = fs.find("/foo16.txt");
|
||||
auto dev32 = fs.find("/foo32.txt");
|
||||
|
||||
ASSERT_TRUE(dev16);
|
||||
ASSERT_TRUE(dev32);
|
||||
|
||||
auto st16 = fs.getattr(dev16->inode());
|
||||
auto st32 = fs.getattr(dev32->inode());
|
||||
|
||||
EXPECT_EQ(60000, st16.uid());
|
||||
EXPECT_EQ(65535, st16.gid());
|
||||
EXPECT_EQ(65536, st32.uid());
|
||||
EXPECT_EQ(4294967295, st32.gid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(section_index_regression, github183) {
|
||||
static constexpr uint64_t section_offset_mask{(UINT64_C(1) << 48) - 1};
|
||||
|
||||
|
@ -169,6 +169,10 @@ TEST_P(manpage_coverage_test, options) {
|
||||
if (tool.is_fuse) {
|
||||
man_opts.erase("allow_root");
|
||||
man_opts.erase("allow_other");
|
||||
#ifdef _WIN32
|
||||
man_opts.erase("uid");
|
||||
man_opts.erase("gid");
|
||||
#endif
|
||||
} else {
|
||||
EXPECT_TRUE(help_opts.contains("help"))
|
||||
<< tool_name << " missing help option";
|
||||
|
@ -37,6 +37,7 @@
|
||||
#ifndef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/mount.h>
|
||||
@ -1055,6 +1056,7 @@ TEST_P(tools_test, end_to_end) {
|
||||
#ifndef _WIN32
|
||||
"-oenable_nlink",
|
||||
"-oreadonly",
|
||||
"-ouid=2345,gid=3456",
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -1075,6 +1077,7 @@ TEST_P(tools_test, end_to_end) {
|
||||
#ifndef _WIN32
|
||||
bool enable_nlink{false};
|
||||
bool readonly{false};
|
||||
bool uid_gid_override{false};
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < all_options.size(); ++i) {
|
||||
@ -1087,6 +1090,9 @@ TEST_P(tools_test, end_to_end) {
|
||||
if (opt == "-oenable_nlink") {
|
||||
enable_nlink = true;
|
||||
}
|
||||
if (opt.find("-ouid=") != std::string::npos) {
|
||||
uid_gid_override = true;
|
||||
}
|
||||
#endif
|
||||
args.push_back(opt);
|
||||
}
|
||||
@ -1120,6 +1126,18 @@ TEST_P(tools_test, end_to_end) {
|
||||
// This doesn't really work on Windows (yet)
|
||||
EXPECT_TRUE(check_readonly(mountpoint / "format.sh", readonly))
|
||||
<< runner.cmdline();
|
||||
if (uid_gid_override) {
|
||||
struct ::stat st;
|
||||
ASSERT_EQ(0, ::lstat(mountpoint.string().c_str(), &st))
|
||||
<< runner.cmdline();
|
||||
EXPECT_EQ(st.st_uid, 2345) << runner.cmdline();
|
||||
EXPECT_EQ(st.st_gid, 3456) << runner.cmdline();
|
||||
ASSERT_EQ(0,
|
||||
::lstat((mountpoint / "format.sh").string().c_str(), &st))
|
||||
<< runner.cmdline();
|
||||
EXPECT_EQ(st.st_uid, 2345) << runner.cmdline();
|
||||
EXPECT_EQ(st.st_gid, 3456) << runner.cmdline();
|
||||
}
|
||||
#endif
|
||||
auto perfmon =
|
||||
dwarfs::getxattr(mountpoint, "user.dwarfs.driver.perfmon");
|
||||
|
@ -169,6 +169,10 @@ struct options {
|
||||
char const* cache_tidy_interval_str{nullptr}; // TODO: const?? -> use string?
|
||||
char const* cache_tidy_max_age_str{nullptr}; // TODO: const?? -> use string?
|
||||
char const* seq_detector_thresh_str{nullptr}; // TODO: const?? -> use string?
|
||||
#ifndef _WIN32
|
||||
char const* uid_str{nullptr}; // TODO: const?? -> use string?
|
||||
char const* gid_str{nullptr}; // TODO: const?? -> use string?
|
||||
#endif
|
||||
#if DWARFS_PERFMON_ENABLED
|
||||
char const* perfmon_enabled_str{nullptr}; // TODO: const?? -> use string?
|
||||
char const* perfmon_trace_file_str{nullptr}; // TODO: const?? -> use string?
|
||||
@ -189,6 +193,10 @@ struct options {
|
||||
std::chrono::milliseconds block_cache_tidy_interval{std::chrono::minutes(5)};
|
||||
std::chrono::milliseconds block_cache_tidy_max_age{std::chrono::minutes{10}};
|
||||
size_t seq_detector_threshold{kDefaultSeqDetectorThreshold};
|
||||
#ifndef _WIN32
|
||||
std::optional<file_stat::uid_type> fs_uid;
|
||||
std::optional<file_stat::gid_type> fs_gid;
|
||||
#endif
|
||||
bool is_help{false};
|
||||
#ifdef DWARFS_BUILTIN_MANPAGE
|
||||
bool is_man{false};
|
||||
@ -236,6 +244,10 @@ constexpr struct ::fuse_opt dwarfs_opts[] = {
|
||||
DWARFS_OPT("readahead=%s", readahead_str, 0),
|
||||
DWARFS_OPT("debuglevel=%s", debuglevel_str, 0),
|
||||
DWARFS_OPT("workers=%s", workers_str, 0),
|
||||
#ifndef _WIN32
|
||||
DWARFS_OPT("uid=%s", uid_str, 0),
|
||||
DWARFS_OPT("gid=%s", gid_str, 0),
|
||||
#endif
|
||||
DWARFS_OPT("mlock=%s", mlock_str, 0),
|
||||
DWARFS_OPT("decratio=%s", decompress_ratio_str, 0),
|
||||
DWARFS_OPT("offset=%s", image_offset_str, 0),
|
||||
@ -1202,6 +1214,10 @@ void usage(std::ostream& os, std::filesystem::path const& progname) {
|
||||
<< " -o blocksize=SIZE set file I/O block size (512K)\n"
|
||||
<< " -o readahead=SIZE set readahead size (0)\n"
|
||||
<< " -o workers=NUM number of worker threads (2)\n"
|
||||
#ifndef _WIN32
|
||||
<< " -o uid=NUM override user ID for file system\n"
|
||||
<< " -o gid=NUM override group ID for file system\n"
|
||||
#endif
|
||||
<< " -o mlock=NAME mlock mode: (none), try, must\n"
|
||||
<< " -o decratio=NUM ratio for full decompression (0.8)\n"
|
||||
<< " -o offset=NUM|auto filesystem image offset in bytes (0)\n"
|
||||
@ -1449,6 +1465,10 @@ void load_filesystem(dwarfs_userdata& userdata) {
|
||||
fsopts.metadata.enable_nlink = bool(opts.enable_nlink);
|
||||
fsopts.metadata.readonly = bool(opts.readonly);
|
||||
fsopts.metadata.block_size = opts.blocksize;
|
||||
#ifndef _WIN32
|
||||
fsopts.metadata.fs_uid = opts.fs_uid;
|
||||
fsopts.metadata.fs_gid = opts.fs_gid;
|
||||
#endif
|
||||
fsopts.inode_offset = inode_offset;
|
||||
|
||||
if (opts.image_offset_str) {
|
||||
@ -1603,6 +1623,16 @@ int dwarfs_main(int argc, sys_char** argv, iolayer const& iol) {
|
||||
opts.decompress_ratio =
|
||||
opts.decompress_ratio_str ? to<double>(opts.decompress_ratio_str) : 0.8;
|
||||
|
||||
#ifndef _WIN32
|
||||
if (opts.uid_str) {
|
||||
opts.fs_uid = to<file_stat::uid_type>(opts.uid_str);
|
||||
}
|
||||
|
||||
if (opts.gid_str) {
|
||||
opts.fs_gid = to<file_stat::gid_type>(opts.gid_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (opts.cache_tidy_strategy_str) {
|
||||
if (auto it = cache_tidy_strategy_map.find(opts.cache_tidy_strategy_str);
|
||||
it != cache_tidy_strategy_map.end()) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user