Compare commits

...
135 Commits
Author SHA1 Message Date
Antonio SJ Musumeci ecb8492bfa checkpoint 2025-11-23 23:05:51 -06:00
Antonio SJ Musumeci f474b1dcff fuse_create.cpp 2025-11-23 21:51:48 -06:00
Antonio SJ Musumeci 7d21df6609 fuse_create.cpp 2025-11-23 21:48:49 -06:00
Antonio SJ Musumeci b1f0057b44 policy_ff.cpp 2025-11-23 21:43:48 -06:00
Antonio SJ Musumeci 212d1500f4 policy_ff.cpp 2025-11-23 21:42:49 -06:00
Antonio SJ Musumeci 8fb948d4f3 fuse_getattr.cpp 2025-11-23 17:33:47 -06:00
Antonio SJ Musumeci 9886623451 fuse_getattr.cpp 2025-11-23 17:33:38 -06:00
Antonio SJ Musumeci 1f38d51e13 fuse_getattr.cpp 2025-11-23 17:30:41 -06:00
Antonio SJ Musumeci a561c7b3ec fuse_getattr.cpp 2025-11-23 01:29:35 -06:00
Antonio SJ Musumeci 07c92a9881 fuse_getattr.cpp 2025-11-23 01:25:59 -06:00
Antonio SJ Musumeci 413a6b41e3 fuse_getattr.cpp 2025-11-23 01:19:53 -06:00
Antonio SJ Musumeci a0d9a11562 fuse_getattr.cpp 2025-11-23 01:19:24 -06:00
Antonio SJ Musumeci 8324de1c02 fuse_getattr.cpp 2025-11-23 01:19:05 -06:00
Antonio SJ Musumeci bae6d544ff fuse_getattr.cpp 2025-11-23 01:13:07 -06:00
Antonio SJ Musumeci 613cbf0a3a fuse_getattr.cpp 2025-11-23 01:12:56 -06:00
Antonio SJ Musumeci 0e06915d47 fuse_getattr.cpp 2025-11-23 01:12:49 -06:00
Antonio SJ Musumeci 0bc5501b34 fuse_getattr.cpp 2025-11-23 01:08:23 -06:00
Antonio SJ Musumeci 7339d27d87 fuse_getattr.cpp 2025-11-23 01:06:24 -06:00
Antonio SJ Musumeci 5c624e5549 fuse_getattr.cpp 2025-11-23 01:02:52 -06:00
Antonio SJ Musumeci 646562050a fuse_getattr.cpp 2025-11-23 00:54:55 -06:00
Antonio SJ Musumeci 1c54fabb6f fuse_getattr.cpp 2025-11-23 00:53:53 -06:00
Antonio SJ Musumeci be13186fef fuse_getattr.cpp 2025-11-23 00:50:18 -06:00
Antonio SJ Musumeci 0e0b65634d fuse_getattr.cpp 2025-11-23 00:46:34 -06:00
Antonio SJ Musumeci 0f1c3f7253 fuse_getattr.cpp 2025-11-23 00:43:34 -06:00
Antonio SJ Musumeci 8dce6b0736 fuse_getattr.cpp 2025-11-23 00:43:29 -06:00
Antonio SJ Musumeci 3b89280665 func_getattr_ff.cpp 2025-11-23 00:23:14 -06:00
Antonio SJ Musumeci 350fd82176 fuse_lowlevel.cpp 2025-11-23 00:21:40 -06:00
Antonio SJ Musumeci b73cb7eb67 fuse_lowlevel.cpp 2025-11-23 00:15:01 -06:00
Antonio SJ Musumeci fd6e382dd1 fuse_lowlevel.cpp 2025-11-22 23:45:03 -06:00
Antonio SJ Musumeci 65e2a67315 fuse_lowlevel.cpp 2025-11-22 23:44:58 -06:00
Antonio SJ Musumeci 157a582a5a fuse_lowlevel.cpp 2025-11-22 19:43:36 -06:00
Antonio SJ Musumeci a639dad8d6 debug.cpp 2025-11-22 19:42:33 -06:00
Antonio SJ Musumeci 8fc944b1a1 debug.cpp 2025-11-22 19:41:18 -06:00
Antonio SJ Musumeci a3dea6842e debug.cpp 2025-11-22 19:41:13 -06:00
Antonio SJ Musumeci f92bfca2ad debug.cpp 2025-11-22 19:40:42 -06:00
Antonio SJ Musumeci 8be2d84b30 debug.cpp 2025-11-22 19:40:14 -06:00
Antonio SJ Musumeci 905355f2fd func_getattr_ff.cpp 2025-11-22 19:33:58 -06:00
Antonio SJ Musumeci a260bd8364 func_getattr_ff.cpp 2025-11-22 19:30:02 -06:00
Antonio SJ Musumeci 2666f27590 func_getattr_ff.cpp 2025-11-22 19:29:46 -06:00
Antonio SJ Musumeci 3d9dea5e04 policy_ff.cpp 2025-11-22 19:24:12 -06:00
Antonio SJ Musumeci f8fa16d3c5 policy_ff.cpp 2025-11-22 19:04:59 -06:00
Antonio SJ Musumeci 355124e0d6 checkpoint 2025-11-22 16:14:16 -06:00
Antonio SJ Musumeci 60fb6f4d60 checkpoint 2025-11-22 16:13:12 -06:00
Antonio SJ Musumeci 99d6b79bd5 config.hpp 2025-11-22 16:11:17 -06:00
Antonio SJ Musumeci 82657ce64a config.hpp 2025-11-22 16:11:04 -06:00
Antonio SJ Musumeci bed8c77486 config.hpp 2025-11-22 16:08:59 -06:00
Antonio SJ Musumeci b5ea55a028 config.cpp 2025-11-22 16:08:34 -06:00
Antonio SJ Musumeci 15c2272040 config.cpp 2025-11-22 16:08:09 -06:00
Antonio SJ Musumeci 31d3ed3129 config.cpp 2025-11-22 16:07:46 -06:00
Antonio SJ Musumeci cedbaaf8d8 config.cpp 2025-11-22 16:07:39 -06:00
Antonio SJ Musumeci 7981f353e9 config.hpp 2025-11-22 16:07:00 -06:00
Antonio SJ Musumeci 0e9d68535b config.cpp 2025-11-22 16:06:38 -06:00
Antonio SJ Musumeci d654204088 fuse_open.cpp 2025-11-22 12:10:33 -06:00
Antonio SJ Musumeci 815bbc2f76 fuse_open.cpp 2025-11-22 10:50:51 -06:00
Antonio SJ Musumeci daed03e559 fuse_open.cpp 2025-11-21 15:46:02 -06:00
Antonio SJ Musumeci 1247b1f2fc fuse_open.cpp 2025-11-21 15:45:54 -06:00
Antonio SJ Musumeci 7a960c61bc fuse_open.cpp 2025-11-21 15:45:53 -06:00
Antonio SJ Musumeci 72350498b1 error.hpp 2025-11-21 15:23:12 -06:00
Antonio SJ Musumeci 96eb24cba6 func_getattr_ff.cpp 2025-11-21 14:59:15 -06:00
Antonio SJ Musumeci a6e99a40e2 fs_stat.hpp 2025-11-21 14:52:43 -06:00
Antonio SJ Musumeci 264bf1c5d7 fs_stat.hpp 2025-11-21 14:52:39 -06:00
Antonio SJ Musumeci 8e2bd55d4b checkpoint 2025-11-21 14:50:27 -06:00
Antonio SJ Musumeci 9ca5809b68 fs_stat.hpp 2025-11-21 13:57:16 -06:00
Antonio SJ Musumeci 6d42b3188c fs_stat.hpp 2025-11-21 13:57:06 -06:00
Antonio SJ Musumeci b6f87eaac9 fs_stat.hpp 2025-11-21 13:55:50 -06:00
Antonio SJ Musumeci 3b0efed6e2 fs_stat.hpp 2025-11-21 13:55:44 -06:00
Antonio SJ Musumeci 9ff31489a1 fs_stat.hpp 2025-11-21 13:53:46 -06:00
Antonio SJ Musumeci d831057dec fs_stat.hpp 2025-11-21 13:53:38 -06:00
Antonio SJ Musumeci 3432d4476b die.hpp 2025-11-21 13:49:30 -06:00
Antonio SJ Musumeci afd652cd84 fs_stat.hpp 2025-11-21 13:48:59 -06:00
Antonio SJ Musumeci 2f0b03efa5 fs_stat.hpp 2025-11-21 13:48:52 -06:00
Antonio SJ Musumeci 70701186d3 fs_stat.hpp 2025-11-21 13:48:43 -06:00
Antonio SJ Musumeci 989b2450f6 fs_stat.hpp 2025-11-21 13:48:32 -06:00
Antonio SJ Musumeci f22b1903bc die.hpp 2025-11-21 13:47:53 -06:00
Antonio SJ Musumeci a7485231fd fs_stat.hpp 2025-11-21 13:44:18 -06:00
Antonio SJ Musumeci 95ff413734 fs_stat.hpp 2025-11-21 13:43:46 -06:00
Antonio SJ Musumeci 56e6ec4eec fs_stat.hpp 2025-11-21 13:43:09 -06:00
Antonio SJ Musumeci 1bc965d4a6 fuse_getattr.cpp 2025-11-21 13:36:19 -06:00
Antonio SJ Musumeci ed276f5f92 fuse_getattr.cpp 2025-11-21 13:36:10 -06:00
Antonio SJ Musumeci 05eb6ce40d func_getattr_combine.cpp 2025-11-21 13:03:33 -06:00
Antonio SJ Musumeci 4d90595a53 func_getattr_combine.cpp 2025-11-21 13:03:22 -06:00
Antonio SJ Musumeci d75b96932d func_getattr_combine.cpp 2025-11-21 13:03:12 -06:00
Antonio SJ Musumeci 39e2860b25 func_getattr_combine.cpp 2025-11-21 13:03:08 -06:00
Antonio SJ Musumeci bf47a326f6 debug.cpp 2025-11-20 23:17:00 -06:00
Antonio SJ Musumeci 2996963ecc debug.cpp 2025-11-20 23:16:50 -06:00
Antonio SJ Musumeci 8828539402 debug.cpp 2025-11-20 23:16:41 -06:00
Antonio SJ Musumeci a316b48f3a debug.cpp 2025-11-20 23:16:34 -06:00
Antonio SJ Musumeci 6fad579f6a debug.cpp 2025-11-20 23:16:14 -06:00
Antonio SJ Musumeci f93b297a87 debug.cpp 2025-11-20 23:13:18 -06:00
Antonio SJ Musumeci 12bb659cbd func_getattr_ff.cpp 2025-11-20 22:33:18 -06:00
Antonio SJ Musumeci 2c667129f9 func_getattr_ff.cpp 2025-11-20 22:33:12 -06:00
Antonio SJ Musumeci a05365d84a func_getattr_ff.cpp 2025-11-20 22:31:51 -06:00
Antonio SJ Musumeci be66ba2c1d func_getattr_ff.cpp 2025-11-20 22:31:44 -06:00
Antonio SJ Musumeci eb60b1e244 fuse_getattr.cpp 2025-11-20 21:41:14 -06:00
Antonio SJ Musumeci 8f13226628 fuse_getattr.cpp 2025-11-20 21:41:11 -06:00
Antonio SJ Musumeci 414992916a fuse_getattr.cpp 2025-11-20 21:39:52 -06:00
Antonio SJ Musumeci 81ee9731fd fuse_lowlevel.cpp 2025-11-20 21:39:06 -06:00
Antonio SJ Musumeci 7023d97b74 fuse_lowlevel.cpp 2025-11-20 21:38:53 -06:00
Antonio SJ Musumeci 733a3708a4 fuse_lowlevel.cpp 2025-11-20 20:20:43 -06:00
Antonio SJ Musumeci 0566c45d12 fuse_getattr.cpp 2025-11-20 17:50:41 -06:00
Antonio SJ Musumeci d1ace6c392 fuse_getattr.cpp 2025-11-20 17:49:47 -06:00
Antonio SJ Musumeci 0a5ae5428b fuse_getattr.cpp 2025-11-20 17:29:47 -06:00
Antonio SJ Musumeci ae9a4c7267 fuse_lowlevel.cpp 2025-11-20 17:20:31 -06:00
Antonio SJ Musumeci 8d76393eac fuse_lowlevel.cpp 2025-11-20 17:20:16 -06:00
Antonio SJ Musumeci 5c4579cf0a fuse_lowlevel.cpp 2025-11-20 17:18:10 -06:00
Antonio SJ Musumeci dbefedd5b4 fuse_lowlevel.cpp 2025-11-20 17:18:04 -06:00
Antonio SJ Musumeci d0d9306191 fuse_lowlevel.cpp 2025-11-20 17:18:03 -06:00
Antonio SJ Musumeci fb5d491b53 fuse_lowlevel.cpp 2025-11-20 17:16:27 -06:00
Antonio SJ Musumeci 102b74f54a fuse_lowlevel.cpp 2025-11-20 17:16:15 -06:00
Antonio SJ Musumeci b5876ccb8d fuse_lowlevel.cpp 2025-11-20 17:09:57 -06:00
Antonio SJ Musumeci dc7bc4dc2d fuse_lowlevel.cpp 2025-11-20 17:09:26 -06:00
Antonio SJ Musumeci 470b75417a debug.cpp 2025-11-20 17:00:38 -06:00
Antonio SJ Musumeci d97a33d565 debug.cpp 2025-11-20 16:58:35 -06:00
Antonio SJ Musumeci 71854f8540 fuse_lowlevel.cpp 2025-11-20 16:57:20 -06:00
Antonio SJ Musumeci 6719956104 debug.cpp 2025-11-20 16:52:12 -06:00
Antonio SJ Musumeci bfd89ffe23 debug.cpp 2025-11-20 16:51:57 -06:00
Antonio SJ Musumeci 2eb1703bc4 debug.cpp 2025-11-20 16:51:47 -06:00
Antonio SJ Musumeci d58927dc4e debug.hpp 2025-11-20 16:50:53 -06:00
Antonio SJ Musumeci 71c9662dc1 fuse_lowlevel.cpp 2025-11-20 16:50:11 -06:00
Antonio SJ Musumeci 4869b83144 fuse_lowlevel.cpp 2025-11-20 16:49:03 -06:00
Antonio SJ Musumeci 115e13b168 debug.cpp 2025-11-20 16:32:22 -06:00
Antonio SJ Musumeci d8020f76ac debug.cpp 2025-11-20 16:29:39 -06:00
Antonio SJ Musumeci e6be2db077 debug.cpp 2025-11-20 16:27:08 -06:00
Antonio SJ Musumeci ebe716cded debug.cpp 2025-11-20 16:26:28 -06:00
Antonio SJ Musumeci 1280326539 debug.cpp 2025-11-20 16:25:06 -06:00
Antonio SJ Musumeci 51ec69f3a1 debug.cpp 2025-11-20 16:24:57 -06:00
Antonio SJ Musumeci c958a7eec5 debug.cpp 2025-11-20 16:20:09 -06:00
Antonio SJ Musumeci 69774b47e6 debug.cpp 2025-11-20 16:19:35 -06:00
Antonio SJ Musumeci 813151ec73 debug.cpp 2025-11-20 16:19:30 -06:00
Antonio SJ Musumeci c1b2072dc6 fuse_lowlevel.cpp 2025-11-20 16:17:33 -06:00
Antonio SJ Musumeci d5ef721266 fuse_getattr.cpp 2025-11-20 16:14:48 -06:00
Antonio SJ Musumeci fee7672479 fuse_getattr.cpp 2025-11-20 16:10:53 -06:00
Antonio SJ Musumeci ea3df0e248 fuse_getattr.cpp 2025-11-20 16:10:30 -06:00
Antonio SJ Musumeci d772afeb90 fuse_getattr.cpp 2025-11-20 15:48:17 -06:00
Antonio SJ Musumeci a61b587aed Change getattr and statx to bespoke policies
* Provides: slight improvement in performance as it no longer will
need to find and then act on the files.
* It doesn't make sense to support all original policy types. Most
people used 'newest' or 'ff' and 'combine' is a better default which
has same runtime as 'newest' but with better output.
2025-11-19 23:05:01 -06:00
42 changed files with 1442 additions and 271 deletions
-1
View File
@@ -65,7 +65,6 @@ OPT_FLAGS := -O0 \
$(SANITIZE) \
-fstack-protector-strong \
-Wextra \
-Werror \
-Wno-unused-parameter \
-DDEBUG
endif
+265
View File
@@ -0,0 +1,265 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <grp.h>
#include <linux/capability.h>
// Direct syscall wrappers since we're not using libcap
static int capset(cap_user_header_t header, const cap_user_data_t data) {
return syscall(SYS_capset, header, data);
}
static int capget(cap_user_header_t header, cap_user_data_t data) {
return syscall(SYS_capget, header, data);
}
void print_capabilities(const char *label) {
struct __user_cap_header_struct header;
struct __user_cap_data_struct data[2];
header.version = _LINUX_CAPABILITY_VERSION_3;
header.pid = 0;
if (capget(&header, data) < 0) {
perror("capget");
return;
}
printf("%s:\n", label);
printf(" Permitted: 0x%08x%08x\n", data[1].permitted, data[0].permitted);
printf(" Effective: 0x%08x%08x\n", data[1].effective, data[0].effective);
printf(" Inheritable: 0x%08x%08x\n", data[1].inheritable, data[0].inheritable);
// Check if CAP_DAC_READ_SEARCH is set
int cap_bit = CAP_DAC_READ_SEARCH;
int word = cap_bit / 32;
int bit = cap_bit % 32;
if (data[word].effective & (1 << bit)) {
printf(" CAP_DAC_READ_SEARCH is EFFECTIVE\n");
} else {
printf(" CAP_DAC_READ_SEARCH is NOT effective\n");
}
}
void print_ids(const char *label) {
printf("%s: uid=%d euid=%d gid=%d egid=%d\n",
label, getuid(), geteuid(), getgid(), getegid());
}
int setup_capabilities() {
struct __user_cap_header_struct header;
struct __user_cap_data_struct data[2];
printf("\n=== Setting up capabilities ===\n");
// Initialize header
header.version = _LINUX_CAPABILITY_VERSION_3;
header.pid = 0;
// Get current capabilities
if (capget(&header, data) < 0) {
perror("capget");
return -1;
}
print_capabilities("Before setup");
// Calculate bit position for CAP_DAC_READ_SEARCH
int cap_bit = CAP_DAC_READ_SEARCH;
int word = cap_bit / 32; // Which 32-bit word (0 or 1)
int bit = cap_bit % 32; // Which bit in that word
// Set CAP_DAC_READ_SEARCH in permitted, effective, and inheritable
data[word].permitted |= (1 << bit);
data[word].effective |= (1 << bit);
data[word].inheritable |= (1 << bit);
// Apply the capability set
if (capset(&header, data) < 0) {
perror("capset");
return -1;
}
print_capabilities("After capset");
// Enable ambient capabilities (survives UID changes)
// PR_CAP_AMBIENT = 47, PR_CAP_AMBIENT_RAISE = 2
if (prctl(47, 2, CAP_DAC_READ_SEARCH, 0, 0) < 0) {
perror("prctl PR_CAP_AMBIENT_RAISE");
printf("Warning: Ambient capabilities not supported (kernel < 4.3?)\n");
} else {
printf("Ambient capabilities set successfully\n");
}
// Keep capabilities across setuid
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
perror("prctl PR_SET_KEEPCAPS");
return -1;
}
printf("PR_SET_KEEPCAPS enabled\n");
return 0;
}
int drop_privileges(uid_t target_uid, gid_t target_gid) {
struct __user_cap_header_struct header;
struct __user_cap_data_struct data[2];
printf("\n=== Dropping privileges ===\n");
print_ids("Before drop");
// Set GID first (must be done while still root)
if (setgid(target_gid) < 0) {
perror("setgid");
return -1;
}
// Drop supplementary groups
if (setgroups(0, NULL) < 0) {
perror("setgroups");
return -1;
}
// Set UID
if (setuid(target_uid) < 0) {
perror("setuid");
return -1;
}
print_ids("After drop");
print_capabilities("After UID change (before re-apply)");
// Re-apply capabilities after UID change
header.version = _LINUX_CAPABILITY_VERSION_3;
header.pid = 0;
// Get current capabilities
if (capget(&header, data) < 0) {
perror("capget after setuid");
return -1;
}
// Re-enable CAP_DAC_READ_SEARCH in effective set
int cap_bit = CAP_DAC_READ_SEARCH;
int word = cap_bit / 32;
int bit = cap_bit % 32;
data[word].effective |= (1 << bit);
if (capset(&header, data) < 0) {
perror("capset after setuid");
return -1;
}
print_capabilities("Final capabilities");
return 0;
}
void test_file_access(const char *path) {
printf("\n=== Testing access to: %s ===\n", path);
struct stat st;
if (stat(path, &st) < 0) {
printf("stat() failed: %s\n", strerror(errno));
} else {
printf("stat() succeeded! Mode: %o, Owner: %d:%d\n",
st.st_mode & 0777, st.st_uid, st.st_gid);
}
int fd = open(path, O_RDONLY);
if (fd < 0) {
printf("open() failed: %s\n", strerror(errno));
} else {
printf("open() succeeded! fd=%d\n", fd);
char buf[128];
ssize_t n = read(fd, buf, sizeof(buf) - 1);
if (n > 0) {
buf[n] = '\0';
printf("Read %zd bytes: %.50s%s\n", n, buf, n > 50 ? "..." : "");
}
close(fd);
}
}
int main(int argc, char *argv[]) {
uid_t target_uid = 1000;
gid_t target_gid = 1000;
if (argc > 1) {
target_uid = atoi(argv[1]);
}
if (argc > 2) {
target_gid = atoi(argv[2]);
}
printf("CAP_DAC_READ_SEARCH Test Program (without libcap)\n");
printf("=================================================\n");
if (geteuid() != 0) {
fprintf(stderr, "Error: This program must be run as root\n");
fprintf(stderr, "Usage: sudo %s [target_uid] [target_gid]\n", argv[0]);
return 1;
}
print_ids("Initial state");
print_capabilities("Initial capabilities");
if (setup_capabilities() != 0) {
fprintf(stderr, "Failed to setup capabilities\n");
return 1;
}
if (drop_privileges(target_uid, target_gid) != 0) {
fprintf(stderr, "Failed to drop privileges\n");
return 1;
}
printf("\n=== Testing File Access ===\n");
printf("Now running as uid=%d with CAP_DAC_READ_SEARCH\n", getuid());
// Test accessing a root-owned file
printf("\nTrying to access /etc/shadow (normally requires root):\n");
test_file_access("/etc/shadow");
// Test accessing /root (usually 0700)
printf("\nTrying to access /root directory:\n");
test_file_access("/root");
// Provide instructions for custom test
printf("\n=== Custom Test Instructions ===\n");
printf("To test with your own restricted directory:\n");
printf("1. Create a test: sudo mkdir -p /tmp/test_restricted\n");
printf("2. Restrict it: sudo chmod 700 /tmp/test_restricted\n");
printf("3. Add a file: sudo sh -c 'echo test > /tmp/test_restricted/file.txt'\n");
printf("4. The program should be able to read it despite permissions\n");
if (argc > 3) {
printf("\nTesting custom path: %s\n", argv[3]);
test_file_access(argv[3]);
}
return 0;
}
/*
* Compilation (no libcap needed):
* gcc -o cap_test cap_test.c
*
* Usage:
* sudo ./cap_test [target_uid] [target_gid] [optional_test_path]
*
* Example:
* sudo ./cap_test 1000 1000
* sudo ./cap_test 1000 1000 /tmp/test_restricted/file.txt
*/
+34 -30
View File
@@ -275,7 +275,9 @@ static
void
debug_open_flags(const uint32_t flags_)
{
fmt::print("{}, ",open_accmode_to_str(flags_));
fmt::print(g_OUTPUT,
"{}, ",
open_accmode_to_str(flags_));
for(size_t i = 0; i < (sizeof(flags_) * 8); i++)
{
const char *str;
@@ -287,7 +289,7 @@ debug_open_flags(const uint32_t flags_)
if(str == NULL)
continue;
fmt::print("{}, ",str);
fmt::print(g_OUTPUT,"{}, ",str);
}
}
@@ -315,7 +317,7 @@ fuse_fopen_flag_to_str(const uint32_t offset_)
void
debug_fuse_open_out(const struct fuse_open_out *arg_)
{
fmt::print(stderr,
fmt::print(g_OUTPUT,
"fuse_open_out:"
" fh=0x{:#08x};"
" open_flags=0x{:#04x} (",
@@ -332,9 +334,9 @@ debug_fuse_open_out(const struct fuse_open_out *arg_)
if(str == NULL)
continue;
fmt::print(stderr,"{},",str);
fmt::print(g_OUTPUT,"{},",str);
}
fmt::print(stderr,");\n");
fmt::print(g_OUTPUT,");\n");
}
static
@@ -445,7 +447,7 @@ debug_fuse_mkdir_in(const void *arg_)
"fuse_mkdir_in:"
" mode={:o};"
" umask={:o};"
" name=%s;"
" name={};"
"\n"
,
arg->mode,
@@ -461,7 +463,7 @@ debug_fuse_unlink(const void *arg_)
fmt::print(g_OUTPUT,
"fuse_unlink:"
" name=%s;"
" name={};"
"\n"
,
name);
@@ -475,7 +477,7 @@ debug_fuse_rmdir(const void *arg_)
fmt::print(g_OUTPUT,
"fuse_mkdir:"
" name=%s;"
" name={};"
"\n"
,
name);
@@ -493,8 +495,8 @@ debug_fuse_symlink(const void *arg_)
fmt::print(g_OUTPUT,
"fuse_mkdir:"
" linkname=%s;"
" name=%s;"
" linkname={};"
" name={};"
"\n"
,
linkname,
@@ -514,9 +516,9 @@ debug_fuse_rename_in(const void *arg_)
fmt::print(g_OUTPUT,
"fuse_rename_in:"
" oldname=%s;"
" oldname={};"
" newdir={};"
" newname=%s;"
" newname={};"
"\n"
,
oldname,
@@ -536,7 +538,7 @@ debug_fuse_link_in(const void *arg_)
fmt::print(g_OUTPUT,
"fuse_link_in:"
" oldnodeid={};"
" name=%s;"
" name={};"
"\n"
,
arg->oldnodeid,
@@ -556,7 +558,7 @@ debug_fuse_create_in(const void *arg_)
"fuse_create_in:"
" mode={:o};"
" umask={:o};"
" name=%s;"
" name={};"
" flags=0x%X (",
arg->mode,
arg->umask,
@@ -574,7 +576,7 @@ debug_fuse_open_in(const void *arg_)
fmt::print(g_OUTPUT,
"fuse_open_in:"
" flags=0x%08X (",
" flags=0x{:08X} (",
arg->flags);
debug_open_flags(arg->flags);
fmt::print(g_OUTPUT,");\n");
@@ -639,7 +641,7 @@ debug_fuse_write_in(const void *arg_)
if(str == NULL)
continue;
fmt::print(g_OUTPUT,"%s,",str);
fmt::print(g_OUTPUT,"{},",str);
}
fmt::print(g_OUTPUT,");\n");
}
@@ -712,8 +714,8 @@ debug_fuse_setxattr_in(const void *arg_)
"fuse_setxattr_in:"
" size={};"
" flags=0x%X;"
" name=%s;"
" value=%s;"
" name={};"
" value={};"
"\n"
,
arg->size,
@@ -734,7 +736,7 @@ debug_fuse_getxattr_in(const void *arg_)
fmt::print(g_OUTPUT,
"fuse_getxattr_in:"
" size={};"
" name=%s;"
" name={};"
"\n"
,
arg->size,
@@ -763,7 +765,7 @@ debug_fuse_removexattr(const void *arg_)
fmt::print(g_OUTPUT,
"fuse_removexattr:"
" name=%s;"
" name={};"
"\n"
,
name);
@@ -816,7 +818,7 @@ debug_fuse_init_in(const struct fuse_init_in *arg_)
if(str == NULL)
continue;
fmt::print(g_OUTPUT,"%s, ",str);
fmt::print(g_OUTPUT,"{}, ",str);
}
fmt::print(g_OUTPUT,")\n");
}
@@ -932,7 +934,7 @@ debug_fuse_init_out(const uint64_t unique_,
if(str == NULL)
continue;
fmt::print(g_OUTPUT,"%s, ",str);
fmt::print(g_OUTPUT,"{}, ",str);
}
fmt::print(g_OUTPUT,
@@ -1100,13 +1102,14 @@ opcode_name(enum fuse_opcode op_)
{
static const char *names[] =
{
"INVALID",
"INVALID0",
"LOOKUP",
"FORGET",
"GETATTR",
"SETATTR",
"READLINK",
"SYMLINK",
"INVALID1",
"MKNOD",
"MKDIR",
"UNLINK",
@@ -1118,6 +1121,7 @@ opcode_name(enum fuse_opcode op_)
"WRITE",
"STATFS",
"RELEASE",
"INVALID3",
"FSYNC",
"SETXATTR",
"GETXATTR",
@@ -1161,9 +1165,9 @@ debug_fuse_in_header(const struct fuse_in_header *hdr_)
{
const void *arg = &hdr_[1];
fmt::print(stderr,
"unique=0x%016" PRIx64 ";"
" opcode=%s ({});"
fmt::print(g_OUTPUT,
"unique=0x{:016x};"
" opcode={} ({});"
" nodeid={};"
" uid={};"
" gid={};"
@@ -1275,10 +1279,10 @@ void
debug_fuse_out_header(const struct fuse_out_header *hdr_)
{
fmt::print(g_OUTPUT,
"unique=0x%016" PRIx64 ";"
"unique=0x{:016x};"
" opcode=RESPONSE;"
" error=%d (%s);"
" len={};"
" error={} ({});"
" len={};\n"
,
hdr_->unique,
hdr_->error,
@@ -1312,7 +1316,7 @@ debug_fuse_readlink(const uint64_t unique_,
" opcode=RESPONSE;"
" error=0 (Success);"
" len={}; || "
"readlink: linkname=%s"
"readlink: linkname={}"
"\n"
,
unique_,
+1
View File
@@ -51,6 +51,7 @@ void debug_fuse_lk_out(const uint64_t unique,
void debug_fuse_bmap_out(const uint64_t unique,
const struct fuse_bmap_out *arg);
void debug_fuse_in_header(const struct fuse_in_header *hdr);
void debug_fuse_out_header(const struct fuse_out_header *hdr);
std::string fuse_debug_init_flag_name(const uint64_t);
+6
View File
@@ -143,6 +143,9 @@ fuse_send_msg(struct fuse_ll *f,
out->len = iov_length(iov, count);
if(fuse_cfg.debug)
debug_fuse_out_header(out);
rv = writev(fuse_chan_fd(ch),iov,count);
if(rv == -1)
return -errno;
@@ -1794,6 +1797,9 @@ fuse_ll_buf_process_read(struct fuse_session *se_,
req->ctx.umask = 0;
req->ch = se_->ch;
if(fuse_cfg.debug)
debug_fuse_in_header(in);
err = ENOSYS;
if(in->opcode >= FUSE_MAXOPS)
goto reply_err;
+16
View File
@@ -0,0 +1,16 @@
#pragma once
template<typename T, typename U>
constexpr T sc(U&& value) {
return static_cast<T>(std::forward<U>(value));
}
template<typename T, typename U>
constexpr T dc(U&& value) {
return dynamic_cast<T>(std::forward<U>(value));
}
template<typename T, typename U>
constexpr T rc(U&& value) {
return reinterpret_cast<T>(std::forward<U>(value));
}
+4 -3
View File
@@ -92,15 +92,15 @@ Config::Config()
cache_statfs(0),
cache_symlinks(false),
cache_writeback(false),
category(func),
config_file(),
direct_io_allow_mmap(true),
dropcacheonclose(false),
export_support(true),
flushonclose(FlushOnClose::ENUM::OPENED_FOR_WRITE),
func(),
category(func),
follow_symlinks(FollowSymlinks::ENUM::NEVER),
fsname(),
func(),
fuse_msg_size("1M"),
gid_cache_expire_timeout(60 * 60),
gid_cache_remove_timeout(60 * 60 * 12),
@@ -231,7 +231,7 @@ Config::Config()
_map["func.chmod"] = &func.chmod;
_map["func.chown"] = &func.chown;
_map["func.create"] = &func.create;
_map["func.getattr"] = &func.getattr;
_map["func.getattr"] = &getattr;
_map["func.getxattr"] = &func.getxattr;
_map["func.link"] = &func.link;
_map["func.listxattr"] = &func.listxattr;
@@ -244,6 +244,7 @@ Config::Config()
_map["func.rename"] = &func.rename;
_map["func.rmdir"] = &func.rmdir;
_map["func.setxattr"] = &func.setxattr;
_map["func.statx"] = &statx;
_map["func.symlink"] = &func.symlink;
_map["func.truncate"] = &func.truncate;
_map["func.unlink"] = &func.unlink;
+6
View File
@@ -16,6 +16,9 @@
#pragma once
#include "func_getattr.hpp"
#include "func_statx.hpp"
#include "branches.hpp"
#include "category.hpp"
#include "config_cachefiles.hpp"
@@ -109,6 +112,9 @@ public:
Config& operator=(const Config&);
public:
Func2::GetAttr getattr{"combine"};
Func2::Statx statx{"combine"};
ConfigBOOL allow_idmap;
ConfigBOOL async_read;
Branches branches;
+1 -7
View File
@@ -19,12 +19,6 @@
#pragma once
#include "enum.hpp"
#include "follow_symlinks_enum.hpp"
enum class FollowSymlinksEnum
{
NEVER,
DIRECTORY,
REGULAR,
ALL
};
typedef Enum<FollowSymlinksEnum> FollowSymlinks;
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "fmt/core.h"
#include <cstdlib>
#define DIE(...) \
do { \
fmt::print(stderr, \
"{}:{} in {}: ", __FILE__, __LINE__, __func__); \
fmt::print(stderr, __VA_ARGS__); \
fmt::print(stderr, "\n"); \
std::abort(); \
} while(0)
+1 -1
View File
@@ -17,7 +17,7 @@ public:
operator int()
{
return (_err.has_value() ? _err.value() : -ENOENT);
return (_err.has_value() ? _err.value() : -ENXIO);
}
Err&
+9
View File
@@ -0,0 +1,9 @@
#pragma once
enum class FollowSymlinksEnum
{
NEVER,
DIRECTORY,
REGULAR,
ALL
};
+5 -14
View File
@@ -19,8 +19,7 @@
#pragma once
#include "to_neg_errno.hpp"
#include <string>
#include "to_cstr.hpp"
#include <sys/stat.h>
#include <sys/types.h>
@@ -29,25 +28,17 @@
namespace fs
{
template<typename PathType>
static
inline
int
lstat(const char *path_,
struct stat *st_)
lstat(const PathType &path_,
struct stat *st_)
{
int rv;
rv = ::lstat(path_,st_);
rv = ::lstat(to_cstr(path_),st_);
return ::to_neg_errno(rv);
}
static
inline
int
lstat(const std::string &path_,
struct stat *st_)
{
return fs::lstat(path_.c_str(),st_);
}
}
View File
+57 -6
View File
@@ -18,6 +18,11 @@
#pragma once
#include "casts.hpp"
#include "die.hpp"
#include "follow_symlinks_enum.hpp"
#include "fs_lstat.hpp"
#include "to_cstr.hpp"
#include "to_neg_errno.hpp"
#include <string>
@@ -29,25 +34,71 @@
namespace fs
{
template<typename PathType>
static
inline
int
stat(const char *path_,
struct stat *st_)
stat(const PathType &path_,
struct stat *st_)
{
int rv;
rv = ::stat(path_,st_);
rv = ::stat(to_cstr(path_),st_);
return ::to_neg_errno(rv);
}
template<typename PathType>
static
inline
int
stat(const std::string &path_,
struct stat *st_)
stat(const PathType &path_,
struct stat *st_,
FollowSymlinksEnum follow_)
{
return fs::stat(path_.c_str(),st_);
int rv;
switch(follow_)
{
case FollowSymlinksEnum::NEVER:
rv = fs::lstat(path_,st_);
return rv;
case FollowSymlinksEnum::DIRECTORY:
rv = fs::lstat(path_,st_);
if((rv >= 0) && S_ISLNK(st_->st_mode))
{
struct stat st;
rv = fs::stat(path_,&st);
if(rv < 0)
return rv;
if(S_ISDIR(st.st_mode))
*st_ = st;
}
return rv;
case FollowSymlinksEnum::REGULAR:
rv = fs::lstat(path_,st_);
if((rv >= 0) && S_ISLNK(st_->st_mode))
{
struct stat st;
rv = fs::stat(path_,&st);
if(rv < 0)
return rv;
if(S_ISREG(st.st_mode))
*st_ = st;
}
return rv;
case FollowSymlinksEnum::ALL:
rv = fs::stat(path_,st_);
if(rv < 0)
rv = fs::lstat(path_,st_);
return rv;
}
DIE("Should never reach this: follow_={}",sc<int>(follow_));
return -EINVAL;
}
}
+52 -9
View File
@@ -1,5 +1,7 @@
#pragma once
#include "follow_symlinks_enum.hpp"
#include "to_cstr.hpp"
#include "to_neg_errno.hpp"
#include "fuse_kernel.h"
@@ -17,11 +19,12 @@
namespace fs
{
template<typename PathType>
static
inline
int
statx(const int dirfd_,
const char *pathname_,
const PathType &pathname_,
const int flags_,
const unsigned int mask_,
struct fuse_statx *st_)
@@ -30,7 +33,7 @@ namespace fs
int rv;
rv = ::statx(dirfd_,
pathname_,
to_cstr(pathname_),
flags_,
mask_,
(struct statx*)st_);
@@ -41,19 +44,59 @@ namespace fs
#endif
}
template<typename PathType>
static
inline
int
statx(const int dirfd_,
const std::string &pathname_,
const PathType &pathname_,
const int flags_,
const unsigned int mask_,
struct fuse_statx *st_)
struct fuse_statx *st_,
FollowSymlinksEnum followsymlinks_)
{
return fs::statx(dirfd_,
pathname_.c_str(),
flags_,
mask_,
st_);
int rv;
switch(followsymlinks_)
{
case FollowSymlinksEnum::NEVER:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
return rv;
case FollowSymlinksEnum::DIRECTORY:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
if((rv >= 0) && S_ISLNK(st_->mode))
{
struct fuse_statx st;
rv = fs::statx(AT_FDCWD,pathname_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st);
if(rv < 0)
return rv;
if(S_ISDIR(st.mode))
*st_ = st;
}
return rv;
case FollowSymlinksEnum::REGULAR:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
if((rv >= 0) && S_ISLNK(st_->mode))
{
struct fuse_statx st;
rv = fs::statx(AT_FDCWD,pathname_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st);
if(rv < 0)
return rv;
if(S_ISREG(st.mode))
*st_ = st;
}
return rv;
case FollowSymlinksEnum::ALL:
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_FOLLOW,mask_,st_);
if(rv < 0)
rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
return rv;
}
return -ENOENT;
}
}
+76
View File
@@ -0,0 +1,76 @@
#pragma once
#include "func_getattr_base.hpp"
#include "func_getattr_factory.hpp"
#include "tofrom_string.hpp"
#include "fmt/core.h"
#include <atomic>
#include <cassert>
namespace Func2
{
class GetAttr : public ToFromString
{
private:
std::shared_ptr<Func2::GetAttrBase> _impl;
public:
GetAttr()
{
}
GetAttr(const std::string &name_)
{
_impl = Func2::GetAttrFactory::make(name_);
assert(_impl);
}
public:
int
operator()(const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
std::shared_ptr<Func2::GetAttrBase> p;
p = std::atomic_load(&_impl);
return (*p)(branches_,
fusepath_,
st_,
follow_symlinks_,
symlinkify_timeout_);
}
public:
std::string
to_string() const
{
std::shared_ptr<Func2::GetAttrBase> p;
p = std::atomic_load(&_impl);
return std::string(p->name());
}
int
from_string(const std::string_view str_)
{
std::shared_ptr<Func2::GetAttrBase> p;
p = Func2::GetAttrFactory::make(str_);
if(!p)
return -EINVAL;
_impl = std::atomic_load(&p);
return 0;
}
};
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include "follow_symlinks_enum.hpp"
#include "fs_path.hpp"
#include "branches.hpp"
#include "int_types.h"
#include "fuse.h"
#include <string_view>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
namespace Func2
{
class GetAttrBase
{
public:
GetAttrBase() {}
~GetAttrBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath,
struct stat *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout) = 0;
};
}
+68
View File
@@ -0,0 +1,68 @@
#include "func_getattr_combine.hpp"
#include "error.hpp"
#include "fs_inode.hpp"
#include "fs_stat.hpp"
#include "symlinkify.hpp"
#include "timespec_utils.hpp"
std::string_view
Func2::GetAttrCombine::name() const
{
return "combine";
}
int
Func2::GetAttrCombine::operator()(const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
Err err;
fs::path fullpath;
const Branch *first_branch;
first_branch = nullptr;
for(const auto &branch : branches_)
{
struct stat tmp_st;
fullpath = branch.path / fusepath_;
rv = fs::stat(fullpath,&tmp_st,follow_symlinks_);
if(rv < 0)
{
err = rv;
continue;
}
if(!first_branch)
{
*st_ = tmp_st;
first_branch = &branch;
continue;
}
st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim);
st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim);
st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim);
st_->st_nlink += tmp_st.st_nlink;
}
if(!first_branch)
return err;
if(symlinkify_timeout_ >= 0)
{
fullpath = first_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(first_branch->path,fusepath_,st_);
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrCombine : public GetAttrBase
{
public:
GetAttrCombine() {}
~GetAttrCombine() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
struct stat *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}
+39
View File
@@ -0,0 +1,39 @@
#include "func_getattr_factory.hpp"
#include "func_getattr_combine.hpp"
#include "func_getattr_ff.hpp"
#include "func_getattr_newest.hpp"
#include "policies.hpp"
bool
Func2::GetAttrFactory::valid(const std::string str_)
{
if(str_ == "combined")
return true;
if(str_ == "ff")
return true;
if(str_ == "newest")
return true;
if(Policies::Search::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::GetAttrBase>
Func2::GetAttrFactory::make(const std::string_view str_)
{
if(str_ == "combine")
return std::make_shared<Func2::GetAttrCombine>();
if(str_ == "ff")
return std::make_shared<Func2::GetAttrFF>();
if(str_ == "newest")
return std::make_shared<Func2::GetAttrNewest>();
if(Policies::Search::find(str_))
return std::make_shared<Func2::GetAttrCombine>();
return {};
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<GetAttrBase> make(const std::string_view str);
};
}
+50
View File
@@ -0,0 +1,50 @@
#include "func_getattr_ff.hpp"
#include "error.hpp"
#include "fs_stat.hpp"
#include "fs_inode.hpp"
#include "symlinkify.hpp"
std::string_view
Func2::GetAttrFF::name() const
{
return "ff";
}
int
Func2::GetAttrFF::operator()(const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
fs::path fullpath;
Err err;
err = -ENXIO;
for(const auto &branch : branches_)
{
fullpath = branch.path / fusepath_;
rv = fs::stat(fullpath,st_,follow_symlinks_);
if(rv < 0)
{
__builtin_trap();
err = rv;
continue;
}
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
fs::inode::calc(branch.path,fusepath_,st_);
return rv;
}
__builtin_trap();
return err;
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrFF : public GetAttrBase
{
public:
GetAttrFF() {}
~GetAttrFF() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
struct stat *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}
+57
View File
@@ -0,0 +1,57 @@
#include "func_getattr_newest.hpp"
#include "fs_stat.hpp"
#include "fs_inode.hpp"
#include "timespec_utils.hpp"
#include "symlinkify.hpp"
std::string_view
Func2::GetAttrNewest::name() const
{
return "newest";
}
int
Func2::GetAttrNewest::operator()(const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
fs::path fullpath;
const Branch *newest_branch;
newest_branch = nullptr;
for(const auto &branch : branches_)
{
struct stat tmp_st;
fullpath = branch.path / fusepath_;
rv = fs::stat(fullpath,&tmp_st,follow_symlinks_);
if(rv < 0)
continue;
if(!TimeSpec::is_newer(tmp_st.st_mtim,st_->st_mtim))
continue;
*st_ = tmp_st;
newest_branch = &branch;
}
if(!newest_branch)
return -ENOENT;
if(symlinkify_timeout_ >= 0)
{
fullpath = newest_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(newest_branch->path,fusepath_,st_);
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
#include "func_getattr_base.hpp"
namespace Func2
{
class GetAttrNewest : public GetAttrBase
{
public:
GetAttrNewest() {}
~GetAttrNewest() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
struct stat *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}
+81
View File
@@ -0,0 +1,81 @@
#pragma once
#include "func_statx_base.hpp"
#include "func_statx_factory.hpp"
#include "tofrom_string.hpp"
#include "fmt/core.h"
#include <atomic>
#include <assert.h>
namespace Func2
{
class Statx : public ToFromString
{
private:
std::shared_ptr<Func2::StatxBase> _impl;
public:
Statx()
{
}
Statx(const std::string &name_)
{
_impl = Func2::StatxFactory::make(name_);
assert(_impl);
}
public:
int
operator()(const Branches &branches_,
const fs::path &fusepath_,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
std::shared_ptr<Func2::StatxBase> p;
p = std::atomic_load(&_impl);
return (*p)(branches_,
fusepath_,
flags_,
mask_,
st_,
follow_symlinks_,
symlinkify_timeout_);
}
public:
std::string
to_string() const
{
std::shared_ptr<Func2::StatxBase> p;
p = std::atomic_load(&_impl);
return std::string(p->name());
}
int
from_string(const std::string_view str_)
{
std::shared_ptr<Func2::StatxBase> p;
p = Func2::StatxFactory::make(str_);
if(!p)
return -EINVAL;
_impl = std::atomic_load(&p);
return 0;
}
};
}
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include "follow_symlinks_enum.hpp"
#include "fs_path.hpp"
#include "branches.hpp"
#include "int_types.h"
#include "fuse.h"
#include <string_view>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
namespace Func2
{
class StatxBase
{
public:
StatxBase() {}
~StatxBase() {}
public:
virtual std::string_view name() const = 0;
public:
virtual int operator()(const Branches &branches,
const fs::path &fusepath,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout) = 0;
};
}
+71
View File
@@ -0,0 +1,71 @@
#include "func_statx_combine.hpp"
#include "fs_inode.hpp"
#include "fs_statx.hpp"
#include "symlinkify.hpp"
#include "timespec_utils.hpp"
std::string_view
Func2::StatxCombine::name() const
{
return "combine";
}
int
Func2::StatxCombine::operator()(const Branches &branches_,
const fs::path &fusepath_,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
fs::path fullpath;
const Branch *first_branch;
first_branch = nullptr;
for(const auto &branch : branches_)
{
struct fuse_statx tmp_st;
fullpath = branch.path / fusepath_;
rv = fs::statx(AT_FDCWD,
fullpath,
flags_|AT_SYMLINK_NOFOLLOW,
mask_,
&tmp_st,
follow_symlinks_);
if(rv < 0)
continue;
if(!first_branch)
{
*st_ = tmp_st;
first_branch = &branch;
continue;
}
st_->atime = TimeSpec::newest(st_->atime,tmp_st.atime);
st_->ctime = TimeSpec::newest(st_->ctime,tmp_st.ctime);
st_->mtime = TimeSpec::newest(st_->mtime,tmp_st.mtime);
st_->btime = TimeSpec::newest(st_->btime,tmp_st.btime);
st_->nlink += tmp_st.nlink;
}
if(!first_branch)
return -ENOENT;
if(symlinkify_timeout_ >= 0)
{
fullpath = first_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(first_branch->path,fusepath_,st_);
return 0;
}
+23
View File
@@ -0,0 +1,23 @@
#include "func_statx_base.hpp"
namespace Func2
{
class StatxCombine : public StatxBase
{
public:
StatxCombine() {}
~StatxCombine() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}
+39
View File
@@ -0,0 +1,39 @@
#include "func_statx_factory.hpp"
#include "func_statx_combine.hpp"
#include "func_statx_ff.hpp"
#include "func_statx_newest.hpp"
#include "policies.hpp"
bool
Func2::StatxFactory::valid(const std::string str_)
{
if(str_ == "combined")
return true;
if(str_ == "ff")
return true;
if(str_ == "newest")
return true;
if(Policies::Search::find(str_))
return true;
return false;
}
std::shared_ptr<Func2::StatxBase>
Func2::StatxFactory::make(const std::string_view str_)
{
if(str_ == "combine")
return std::make_shared<Func2::StatxCombine>();
if(str_ == "ff")
return std::make_shared<Func2::StatxFF>();
if(str_ == "newest")
return std::make_shared<Func2::StatxNewest>();
if(Policies::Search::find(str_))
return std::make_shared<Func2::StatxCombine>();
return {};
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "func_statx_base.hpp"
namespace Func2
{
class StatxFactory
{
public:
static bool valid(const std::string str);
static std::shared_ptr<StatxBase> make(const std::string_view str);
};
}
+48
View File
@@ -0,0 +1,48 @@
#include "func_statx_ff.hpp"
#include "fs_statx.hpp"
#include "fs_inode.hpp"
#include "symlinkify.hpp"
std::string_view
Func2::StatxFF::name() const
{
return "ff";
}
int
Func2::StatxFF::operator()(const Branches &branches_,
const fs::path &fusepath_,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
fs::path fullpath;
for(const auto &branch : branches_)
{
fullpath = branch.path / fusepath_;
rv = fs::statx(AT_FDCWD,
fullpath,
flags_|AT_SYMLINK_NOFOLLOW,
mask_,
st_,
follow_symlinks_);
if(rv < 0)
continue;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
fs::inode::calc(branch.path,fusepath_,st_);
return rv;
}
return -ENOENT;
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include "func_statx_base.hpp"
namespace Func2
{
class StatxFF : public StatxBase
{
public:
StatxFF() {}
~StatxFF() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}
+64
View File
@@ -0,0 +1,64 @@
#include "func_statx_newest.hpp"
#include "fs_statx.hpp"
#include "fs_inode.hpp"
#include "symlinkify.hpp"
#include "timespec_utils.hpp"
std::string_view
Func2::StatxNewest::name() const
{
return "newest";
}
int
Func2::StatxNewest::operator()(const Branches &branches_,
const fs::path &fusepath_,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st_,
const FollowSymlinksEnum follow_symlinks_,
const s64 symlinkify_timeout_)
{
int rv;
fs::path fullpath;
const Branch *newest_branch;
newest_branch = nullptr;
for(const auto &branch : branches_)
{
struct fuse_statx tmp_st;
fullpath = branch.path / fusepath_;
rv = fs::statx(AT_FDCWD,
fullpath,
flags_|AT_SYMLINK_NOFOLLOW,
mask_,
&tmp_st,
follow_symlinks_);
if(rv < 0)
continue;
if(not TimeSpec::is_newer(tmp_st.mtime,st_->mtime))
continue;
*st_ = tmp_st;
newest_branch = &branch;
}
if(!newest_branch)
return -ENOENT;
if(symlinkify_timeout_ >= 0)
{
fullpath = newest_branch->path / fusepath_;
symlinkify::convert_if_can_be_symlink(fullpath,
st_,
symlinkify_timeout_);
}
fs::inode::calc(newest_branch->path,fusepath_,st_);
return 0;
}
+23
View File
@@ -0,0 +1,23 @@
#include "func_statx_base.hpp"
namespace Func2
{
class StatxNewest : public StatxBase
{
public:
StatxNewest() {}
~StatxNewest() {}
public:
std::string_view name() const;
public:
int operator()(const Branches &branches,
const fs::path &fusepath,
const u32 flags_,
const u32 mask_,
struct fuse_statx *st,
const FollowSymlinksEnum follow_symlinks,
const s64 symlinkify_timeout);
};
}
+32 -93
View File
@@ -31,45 +31,11 @@
#include "fuse.h"
#include <signal.h>
#include <string>
static
void
_set_stat_if_leads_to_dir(const fs::path &path_,
struct stat *st_)
{
int rv;
struct stat st;
rv = fs::stat(path_,&st);
if(rv < 0)
return;
if(S_ISDIR(st.st_mode))
*st_ = st;
return;
}
static
void
_set_stat_if_leads_to_reg(const fs::path &path_,
struct stat *st_)
{
int rv;
struct stat st;
rv = fs::stat(path_,&st);
if(rv < 0)
return;
if(S_ISREG(st.st_mode))
*st_ = st;
return;
}
static
int
_getattr_fake_root(struct stat *st_)
@@ -117,58 +83,15 @@ _getattr_controlfile(struct stat *st_)
}
static
int
_getattr(const Policy::Search &searchFunc_,
const Branches &branches_,
const fs::path &fusepath_,
struct stat *st_,
const bool symlinkify_,
const time_t symlinkify_timeout_,
FollowSymlinks followsymlinks_)
bool
should_break(const fs::path &fusepath_)
{
int rv;
fs::path fullpath;
std::vector<Branch*> branches;
fs::path f = fusepath_.filename();
rv = searchFunc_(branches_,fusepath_,branches);
if(rv < 0)
return rv;
if(str::endswith(f,"Hook"))
return false;
fullpath = branches[0]->path / fusepath_;
switch(followsymlinks_)
{
case FollowSymlinks::ENUM::NEVER:
rv = fs::lstat(fullpath,st_);
break;
case FollowSymlinks::ENUM::DIRECTORY:
rv = fs::lstat(fullpath,st_);
if(S_ISLNK(st_->st_mode))
::_set_stat_if_leads_to_dir(fullpath,st_);
break;
case FollowSymlinks::ENUM::REGULAR:
rv = fs::lstat(fullpath,st_);
if(S_ISLNK(st_->st_mode))
::_set_stat_if_leads_to_reg(fullpath,st_);
break;
case FollowSymlinks::ENUM::ALL:
rv = fs::stat(fullpath,st_);
if(rv < 0)
rv = fs::lstat(fullpath,st_);
break;
}
if(rv < 0)
return rv;
if(symlinkify_ && symlinkify::can_be_symlink(*st_,symlinkify_timeout_))
symlinkify::convert(fullpath,st_);
fs::inode::calc(branches[0]->path,
fusepath_,
st_);
return 0;
return true;
}
int
@@ -178,13 +101,28 @@ _getattr(const fs::path &fusepath_,
{
int rv;
rv = ::_getattr(cfg.func.getattr.policy,
cfg.branches,
fusepath_,
st_,
cfg.symlinkify,
cfg.symlinkify_timeout,
cfg.follow_symlinks);
rv = cfg.getattr(cfg.branches,
fusepath_,
st_,
cfg.follow_symlinks,
cfg.symlinkify_timeout);
if(rv < 0)
{
fmt::println("getattr: {}\n"
" uid: {}\n"
" gid: {}\n"
" err: {}\n"
,
fusepath_.string(),
geteuid(),
getegid(),
strerror(-rv)
);
if(should_break(fusepath_))
raise(SIGTRAP);
}
if((rv < 0) && Config::is_rootdir(fusepath_))
return ::_getattr_fake_root(st_);
@@ -213,7 +151,8 @@ FUSE::getattr(const fuse_req_ctx_t *ctx_,
struct stat *st_,
fuse_timeouts_t *timeout_)
{
const ugid::Set ugid(ctx_);
// const ugid::Set ugid(ctx_);
const ugid::SetRootGuard _;
return FUSE::getattr(fusepath_,st_,timeout_);
}
+5 -1
View File
@@ -281,7 +281,8 @@ _open_for_insert_lambda(const fuse_req_ctx_t *ctx_,
{
int rv;
FileInfo *fi;
const ugid::Set ugid(ctx_);
//const ugid::Set ugid(ctx_);
const ugid::SetRootGuard asdf;
::_config_to_ffi_flags(cfg,ctx_->pid,ffi_);
@@ -438,6 +439,9 @@ _open(const fuse_req_ctx_t *ctx_,
return (val_.second.ref_count <= 0);
});
if(rv < 0)
__builtin_trap();
return rv;
}
+7 -104
View File
@@ -30,49 +30,11 @@
#include "symlinkify.hpp"
#include "ugid.hpp"
#include "fmt/core.h"
#include "fuse.h"
#include <string>
static
void
_set_stat_if_leads_to_dir(const fs::path &path_,
struct fuse_statx *st_)
{
int rv;
struct fuse_statx st;
rv = fs::statx(AT_FDCWD,path_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st);
if(rv < 0)
return;
if(S_ISDIR(st.mode))
*st_ = st;
return;
}
static
void
_set_stat_if_leads_to_reg(const fs::path &path_,
struct fuse_statx *st_)
{
int rv;
struct fuse_statx st;
rv = fs::statx(AT_FDCWD,path_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st);
if(rv < 0)
return;
if(S_ISREG(st.mode))
*st_ = st;
return;
}
static
int
_statx_fake_root(struct fuse_statx *st_)
@@ -113,63 +75,6 @@ _statx_controlfile(struct fuse_statx *st_)
return 0;
}
static
int
_statx(const Policy::Search &searchFunc_,
const Branches &branches_,
const fs::path &fusepath_,
const uint32_t flags_,
const uint32_t mask_,
struct fuse_statx *st_,
const bool symlinkify_,
const time_t symlinkify_timeout_,
FollowSymlinks followsymlinks_)
{
int rv;
fs::path fullpath;
std::vector<Branch*> branches;
rv = searchFunc_(branches_,fusepath_,branches);
if(rv < 0)
return rv;
fullpath = branches[0]->path / fusepath_;
switch(followsymlinks_)
{
case FollowSymlinks::ENUM::NEVER:
rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
break;
case FollowSymlinks::ENUM::DIRECTORY:
rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
if((rv >= 0) && S_ISLNK(st_->mode))
::_set_stat_if_leads_to_dir(fullpath,st_);
break;
case FollowSymlinks::ENUM::REGULAR:
rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
if((rv >= 0) && S_ISLNK(st_->mode))
::_set_stat_if_leads_to_reg(fullpath,st_);
break;
case FollowSymlinks::ENUM::ALL:
rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_FOLLOW,mask_,st_);
if(rv < 0)
rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_);
break;
}
if(rv < 0)
return rv;
if(symlinkify_ && symlinkify::can_be_symlink(*st_,symlinkify_timeout_))
symlinkify::convert(fullpath,st_);
fs::inode::calc(branches[0]->path,
fusepath_,
st_);
return 0;
}
static
int
_statx(const fs::path &fusepath_,
@@ -180,15 +85,13 @@ _statx(const fs::path &fusepath_,
{
int rv;
rv = ::_statx(cfg.func.getattr.policy,
cfg.branches,
fusepath_,
flags_,
mask_,
st_,
cfg.symlinkify,
cfg.symlinkify_timeout,
cfg.follow_symlinks);
rv = cfg.statx(cfg.branches,
fusepath_,
flags_,
mask_,
st_,
cfg.follow_symlinks,
cfg.symlinkify_timeout);
if((rv < 0) && Config::is_rootdir(fusepath_))
return ::_statx_fake_root(st_);
+6 -2
View File
@@ -37,7 +37,7 @@ _create(const Branches::Ptr &ibranches_,
int error;
fs::info_t info;
error = ENOENT;
error = ENXIO;
for(auto &branch : *ibranches_)
{
if(branch.ro_or_nc())
@@ -74,6 +74,8 @@ Policy::FF::Create::operator()(const Branches::Ptr &branches_,
return ::_create(branches_,paths_);
}
#include <signal.h>
int
Policy::FF::Search::operator()(const Branches::Ptr &branches_,
const fs::path &fusepath_,
@@ -89,5 +91,7 @@ Policy::FF::Search::operator()(const Branches::Ptr &branches_,
return 0;
}
return -ENOENT;
raise(SIGTRAP);
return -ENXIO;
}
+72
View File
@@ -0,0 +1,72 @@
#pragma once
namespace TimeSpec
{
static
inline
bool
is_newer(const timespec &t0_,
const timespec &t1_)
{
if(t0_.tv_sec > t1_.tv_sec)
return true;
if(t0_.tv_sec == t1_.tv_sec)
{
if(t0_.tv_nsec > t1_.tv_nsec)
return true;
}
return false;
}
static
inline
timespec
newest(const timespec &t0_,
const timespec &t1_)
{
if(t0_.tv_sec > t1_.tv_sec)
return t0_;
if(t0_.tv_sec == t1_.tv_sec)
{
if(t0_.tv_nsec > t1_.tv_nsec)
return t0_;
}
return t1_;
}
static
inline
bool
is_newer(const fuse_sx_time &t0_,
const fuse_sx_time &t1_)
{
if(t0_.tv_sec > t1_.tv_sec)
return true;
if(t0_.tv_sec == t1_.tv_sec)
{
if(t0_.tv_nsec > t1_.tv_nsec)
return true;
}
return false;
}
static
inline
fuse_sx_time
newest(const fuse_sx_time &t0_,
const fuse_sx_time &t1_)
{
if(t0_.tv_sec > t1_.tv_sec)
return t0_;
if(t0_.tv_sec == t1_.tv_sec)
{
if(t0_.tv_nsec > t1_.tv_nsec)
return t0_;
}
return t1_;
}
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <filesystem>
#include <string>
#include <type_traits>
template<typename PathType>
const char*
to_cstr(const PathType &p_)
{
if constexpr (std::is_same_v<std::decay_t<PathType>, std::filesystem::path>)
return p_.c_str();
if constexpr (std::is_same_v<std::decay_t<PathType>, std::string>)
return p_.c_str();
if constexpr (std::is_same_v<std::decay_t<PathType>, const char*> ||
std::is_same_v<std::decay_t<PathType>, char*>)
return p_;
abort();
return NULL;
}