Skip to content

Instantly share code, notes, and snippets.

@apselon
Created December 3, 2020 22:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apselon/1d1f7d5815bbb39b1c479103d9b1153e to your computer and use it in GitHub Desktop.
Save apselon/1d1f7d5815bbb39b1c479103d9b1153e to your computer and use it in GitHub Desktop.
#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