Created
December 3, 2020 22:52
-
-
Save apselon/1d1f7d5815bbb39b1c479103d9b1153e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define FUSE_USE_VERSION 30 | |
#define _FILE_OFFSET_BITS 64 | |
#include <linux/limits.h> | |
#include <dirent.h> | |
#include <errno.h> | |
#include <fuse3/fuse.h> | |
#include <search.h> | |
#include <stddef.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stdbool.h> | |
enum ErrorCodes { | |
SUCCESS, | |
}; | |
enum { MAX_SIZE = 1 << 20 }; | |
struct FileSystem { | |
size_t num_catalogs; | |
int catalogs[MAX_SIZE]; | |
} aifs = {}; | |
int newest_stat(const char* path, struct stat* ans) | |
{ | |
char my_path[PATH_MAX] = "."; | |
strcat(my_path, path); | |
int ctl = -1; | |
time_t max_time = 0; | |
struct stat cur_st = {}; | |
for (size_t i = 0; i < aifs.num_catalogs; ++i) { | |
if (faccessat(aifs.catalogs[i], my_path, F_OK, AT_EACCESS)) { | |
continue; | |
} | |
fstatat(aifs.catalogs[i], my_path, &cur_st, AT_SYMLINK_NOFOLLOW); | |
if (cur_st.st_mtim.tv_sec > max_time) { | |
ctl = i; | |
max_time = cur_st.st_mtim.tv_sec; | |
if (ans == NULL) continue; | |
ans->st_mtim.tv_sec = max_time; | |
ans->st_nlink = 1; | |
ans->st_size = cur_st.st_size; | |
if (S_ISREG(cur_st.st_mode)) { | |
ans->st_mode = (0444 | S_IFREG) & cur_st.st_mode; | |
} | |
else if (S_ISDIR(cur_st.st_mode)) { | |
ans->st_mode = (0555 | S_IFDIR) & cur_st.st_mode; | |
} | |
} | |
} | |
return ctl; | |
}; | |
int my_open(const char* path, struct fuse_file_info* fi) | |
{ | |
int ctl = newest_stat(path, NULL); | |
if (-1 == ctl) { | |
return -ENOENT; | |
} | |
if (O_RDONLY != (fi->flags & O_ACCMODE)) { | |
return -EACCES; | |
} | |
return 0; | |
} | |
int my_read( | |
const char* path, | |
char* buf, | |
size_t size, | |
off_t off, | |
struct fuse_file_info* fi) | |
{ | |
struct stat st = {}; | |
int ctl = newest_stat(path, &st); | |
if (-1 == ctl) { | |
return -ENOENT; | |
} | |
if (off > st.st_size) { | |
return 0; | |
} | |
if (off + size > st.st_size) { | |
size = st.st_size - off; | |
} | |
char my_path[PATH_MAX] = "."; | |
strcat(my_path, path); | |
int fd = openat(aifs.catalogs[ctl], my_path, 0); | |
read(fd, buf, size); | |
close(fd); | |
return size; | |
} | |
int my_stat(const char* path, struct stat* st, struct fuse_file_info* fi) | |
{ | |
if (-1 != newest_stat(path, st)) { | |
return 0; | |
} | |
return -ENOENT; | |
} | |
int my_readdir( | |
const char* path, | |
void* buf, | |
fuse_fill_dir_t filler, | |
off_t offset, | |
struct fuse_file_info* fi, | |
enum fuse_readdir_flags flags) | |
{ | |
char my_path[PATH_MAX] = "."; | |
strcat(my_path, path); | |
filler(buf, ".", NULL, 0, 0); | |
filler(buf, "..", NULL, 0, 0); | |
ENTRY e; | |
hcreate(100); | |
for (size_t i = 0; i < aifs.num_catalogs; ++i) { | |
DIR* catalog = fdopendir(openat(aifs.catalogs[i], my_path, O_RDONLY)); | |
struct dirent* de = NULL; | |
while (NULL != (de = readdir(catalog))) { | |
e.key = de->d_name; | |
if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, "..") || | |
NULL != hsearch(e, FIND)) | |
continue; | |
e.data = NULL; | |
if (NULL == hsearch(e, ENTER)) { | |
perror("hsearch error"); | |
} | |
filler(buf, de->d_name, NULL, 0, 0); | |
} | |
closedir(catalog); | |
} | |
hdestroy(); | |
return SUCCESS; | |
} | |
static struct fuse_operations operations = { | |
.open = my_open, | |
.read = my_read, | |
.readdir = my_readdir, | |
.getattr = my_stat, | |
}; | |
int open_filesystem(const char* img) | |
{ | |
int ret_val = 0; | |
char my_data[MAX_SIZE] = ""; | |
strcpy(my_data, img); | |
char* cur_root_end = my_data; | |
char* cur_root_start = my_data; | |
size_t num_root = 0; | |
while (NULL != (cur_root_end = strchr(cur_root_end, ':'))) { | |
*cur_root_end = '\0'; | |
aifs.catalogs[num_root++] = open(cur_root_start, O_RDONLY); | |
cur_root_start = ++cur_root_end; | |
}; | |
aifs.catalogs[num_root++] = open(cur_root_start, O_RDONLY); | |
aifs.num_catalogs = num_root; | |
return ret_val; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
struct fuse_args args = FUSE_ARGS_INIT(argc, argv); | |
typedef struct { | |
char* src; | |
} my_options_t; | |
my_options_t opt = {}; | |
struct fuse_opt opt_specs[] = { | |
{"--src %s", offsetof(my_options_t, src), 0}, {NULL, 0, 0}}; | |
fuse_opt_parse(&args, &opt, opt_specs, NULL); | |
if (NULL != opt.src) { | |
open_filesystem(opt.src); | |
} | |
int ret = fuse_main(args.argc, args.argv, &operations, NULL); | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment