mirror of
https://github.com/mhx/dwarfs.git
synced 2025-09-09 20:41:04 -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
|
If you have a lot of CPUs, increasing this number can help
|
||||||
speed up access to files in the filesystem.
|
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*:
|
- `-o decratio=`*value*:
|
||||||
The ratio over which a block is fully decompressed. Blocks
|
The ratio over which a block is fully decompressed. Blocks
|
||||||
are only decompressed partially, so each block has to carry
|
are only decompressed partially, so each block has to carry
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <dwarfs/file_stat.h>
|
||||||
|
|
||||||
namespace dwarfs::reader {
|
namespace dwarfs::reader {
|
||||||
|
|
||||||
struct metadata_options {
|
struct metadata_options {
|
||||||
@ -28,6 +33,8 @@ struct metadata_options {
|
|||||||
bool readonly{false};
|
bool readonly{false};
|
||||||
bool check_consistency{false};
|
bool check_consistency{false};
|
||||||
size_t block_size{512};
|
size_t block_size{512};
|
||||||
|
std::optional<file_stat::uid_type> fs_uid{};
|
||||||
|
std::optional<file_stat::gid_type> fs_gid{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dwarfs::reader
|
} // namespace dwarfs::reader
|
||||||
|
@ -1800,8 +1800,8 @@ metadata_<LoggerPolicy>::getattr_impl(inode_view iv,
|
|||||||
|
|
||||||
stbuf.set_ino(inode + inode_offset_);
|
stbuf.set_ino(inode + inode_offset_);
|
||||||
stbuf.set_blksize(options_.block_size);
|
stbuf.set_blksize(options_.block_size);
|
||||||
stbuf.set_uid(iv.getuid());
|
stbuf.set_uid(options_.fs_uid.value_or(iv.getuid()));
|
||||||
stbuf.set_gid(iv.getgid());
|
stbuf.set_gid(options_.fs_gid.value_or(iv.getgid()));
|
||||||
stbuf.set_mtime(resolution * (timebase + ivr.mtime_offset()));
|
stbuf.set_mtime(resolution * (timebase + ivr.mtime_offset()));
|
||||||
|
|
||||||
if (mtime_only) {
|
if (mtime_only) {
|
||||||
|
@ -1229,6 +1229,63 @@ TEST(filesystem, uid_gid_count) {
|
|||||||
EXPECT_EQ(349999, st99999.gid());
|
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) {
|
TEST(section_index_regression, github183) {
|
||||||
static constexpr uint64_t section_offset_mask{(UINT64_C(1) << 48) - 1};
|
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) {
|
if (tool.is_fuse) {
|
||||||
man_opts.erase("allow_root");
|
man_opts.erase("allow_root");
|
||||||
man_opts.erase("allow_other");
|
man_opts.erase("allow_other");
|
||||||
|
#ifdef _WIN32
|
||||||
|
man_opts.erase("uid");
|
||||||
|
man_opts.erase("gid");
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
EXPECT_TRUE(help_opts.contains("help"))
|
EXPECT_TRUE(help_opts.contains("help"))
|
||||||
<< tool_name << " missing help option";
|
<< tool_name << " missing help option";
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
@ -1055,6 +1056,7 @@ TEST_P(tools_test, end_to_end) {
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
"-oenable_nlink",
|
"-oenable_nlink",
|
||||||
"-oreadonly",
|
"-oreadonly",
|
||||||
|
"-ouid=2345,gid=3456",
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1075,6 +1077,7 @@ TEST_P(tools_test, end_to_end) {
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
bool enable_nlink{false};
|
bool enable_nlink{false};
|
||||||
bool readonly{false};
|
bool readonly{false};
|
||||||
|
bool uid_gid_override{false};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (size_t i = 0; i < all_options.size(); ++i) {
|
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") {
|
if (opt == "-oenable_nlink") {
|
||||||
enable_nlink = true;
|
enable_nlink = true;
|
||||||
}
|
}
|
||||||
|
if (opt.find("-ouid=") != std::string::npos) {
|
||||||
|
uid_gid_override = true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
args.push_back(opt);
|
args.push_back(opt);
|
||||||
}
|
}
|
||||||
@ -1120,6 +1126,18 @@ TEST_P(tools_test, end_to_end) {
|
|||||||
// This doesn't really work on Windows (yet)
|
// This doesn't really work on Windows (yet)
|
||||||
EXPECT_TRUE(check_readonly(mountpoint / "format.sh", readonly))
|
EXPECT_TRUE(check_readonly(mountpoint / "format.sh", readonly))
|
||||||
<< runner.cmdline();
|
<< 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
|
#endif
|
||||||
auto perfmon =
|
auto perfmon =
|
||||||
dwarfs::getxattr(mountpoint, "user.dwarfs.driver.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_interval_str{nullptr}; // TODO: const?? -> use string?
|
||||||
char const* cache_tidy_max_age_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?
|
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
|
#if DWARFS_PERFMON_ENABLED
|
||||||
char const* perfmon_enabled_str{nullptr}; // TODO: const?? -> use string?
|
char const* perfmon_enabled_str{nullptr}; // TODO: const?? -> use string?
|
||||||
char const* perfmon_trace_file_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_interval{std::chrono::minutes(5)};
|
||||||
std::chrono::milliseconds block_cache_tidy_max_age{std::chrono::minutes{10}};
|
std::chrono::milliseconds block_cache_tidy_max_age{std::chrono::minutes{10}};
|
||||||
size_t seq_detector_threshold{kDefaultSeqDetectorThreshold};
|
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};
|
bool is_help{false};
|
||||||
#ifdef DWARFS_BUILTIN_MANPAGE
|
#ifdef DWARFS_BUILTIN_MANPAGE
|
||||||
bool is_man{false};
|
bool is_man{false};
|
||||||
@ -236,6 +244,10 @@ constexpr struct ::fuse_opt dwarfs_opts[] = {
|
|||||||
DWARFS_OPT("readahead=%s", readahead_str, 0),
|
DWARFS_OPT("readahead=%s", readahead_str, 0),
|
||||||
DWARFS_OPT("debuglevel=%s", debuglevel_str, 0),
|
DWARFS_OPT("debuglevel=%s", debuglevel_str, 0),
|
||||||
DWARFS_OPT("workers=%s", workers_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("mlock=%s", mlock_str, 0),
|
||||||
DWARFS_OPT("decratio=%s", decompress_ratio_str, 0),
|
DWARFS_OPT("decratio=%s", decompress_ratio_str, 0),
|
||||||
DWARFS_OPT("offset=%s", image_offset_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 blocksize=SIZE set file I/O block size (512K)\n"
|
||||||
<< " -o readahead=SIZE set readahead size (0)\n"
|
<< " -o readahead=SIZE set readahead size (0)\n"
|
||||||
<< " -o workers=NUM number of worker threads (2)\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 mlock=NAME mlock mode: (none), try, must\n"
|
||||||
<< " -o decratio=NUM ratio for full decompression (0.8)\n"
|
<< " -o decratio=NUM ratio for full decompression (0.8)\n"
|
||||||
<< " -o offset=NUM|auto filesystem image offset in bytes (0)\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.enable_nlink = bool(opts.enable_nlink);
|
||||||
fsopts.metadata.readonly = bool(opts.readonly);
|
fsopts.metadata.readonly = bool(opts.readonly);
|
||||||
fsopts.metadata.block_size = opts.blocksize;
|
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;
|
fsopts.inode_offset = inode_offset;
|
||||||
|
|
||||||
if (opts.image_offset_str) {
|
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 =
|
||||||
opts.decompress_ratio_str ? to<double>(opts.decompress_ratio_str) : 0.8;
|
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 (opts.cache_tidy_strategy_str) {
|
||||||
if (auto it = cache_tidy_strategy_map.find(opts.cache_tidy_strategy_str);
|
if (auto it = cache_tidy_strategy_map.find(opts.cache_tidy_strategy_str);
|
||||||
it != cache_tidy_strategy_map.end()) {
|
it != cache_tidy_strategy_map.end()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user