Skip to content

Instantly share code, notes, and snippets.

@rkfg
Created May 17, 2018 08:09
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 rkfg/6ba436cb5f67a63ce05b7840c8ce775e to your computer and use it in GitHub Desktop.
Save rkfg/6ba436cb5f67a63ce05b7840c8ce775e to your computer and use it in GitHub Desktop.
Read-only FUSE filesystem in C++
#include <iostream>
#include <cstring>
#include <unordered_map>
#include <memory>
#include <boost/unordered_map.hpp>
#define FUSE_USE_VERSION 26
#define _FILE_OFFSET_BITS 64
#include <fuse.h>
using namespace std;
struct file {
file() = default;
file(const file&) = delete;
file& operator=(file&&) = default;
file(const string& c) :
content(c) {
}
string content;
};
struct dir {
dir() = default;
dir(const dir&) = delete;
dir& operator=(dir&&) = default;
boost::unordered_map<string, dir> dirs; // STL sucks
unordered_map<string, file> files;
dir& create_dir(const std::string& name) {
return dirs[name] = dir();
}
file& create_file(const std::string& name, const std::string& content) {
return files[name] = file(content);
}
};
dir nodir;
file nofile;
bool operator!(const dir& d) {
return &d == &nodir;
}
bool operator!(const file& d) {
return &d == &nofile;
}
dir all_dirs;
tuple<dir&, file&> find_dir(const char* path) {
unique_ptr<char> p(strdup(path));
char* ptr;
char* pc = strtok_r(p.get(), "/", &ptr);
auto cur = &all_dirs;
while (pc != NULL) {
auto found = cur->dirs.find(pc);
if (found == cur->dirs.end()) {
auto found_file = cur->files.find(pc);
if (found_file == cur->files.end()) {
return {nodir, nofile};
} else {
return {*cur, found_file->second};
}
}
cur = &found->second;
pc = strtok_r(NULL, "/", &ptr);
}
return {*cur, nofile};
}
int readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t off, struct fuse_file_info *fi) {
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
auto cur = find_dir(path);
auto& cur_dir = get<0>(cur);
if (!cur_dir) {
return -ENOENT;
}
for (auto& f : cur_dir.files) {
filler(buf, f.first.c_str(), NULL, 0);
}
for (auto& f : cur_dir.dirs) {
filler(buf, f.first.c_str(), NULL, 0);
}
return 0;
}
int getattr(const char *path, struct stat *s) {
string p(path);
if (p == "." || p == ".." || p == "/") {
s->st_mode = 0755 | S_IFDIR;
return 0;
}
auto cur = find_dir(path);
auto& cur_dir = get<0>(cur);
auto& cur_file = get<1>(cur);
if (!cur_dir) {
return -ENOENT;
}
if (!cur_file) {
s->st_mode = 0755 | S_IFDIR;
return 0;
}
s->st_mode = 0644 | S_IFREG;
s->st_size = cur_file.content.length();
return 0;
}
int fileread(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
auto cur = find_dir(path);
auto& cur_dir = get<0>(cur);
auto& cur_file = get<1>(cur);
if (!cur_dir || !cur_file) {
return -ENOENT;
}
auto s = min(cur_file.content.length() - offset, size);
memcpy(buf, cur_file.content.data(), s);
return s;
}
int main(int argc, char* argv[]) {
fuse_operations ops;
memset(&ops, 0, sizeof(ops));
ops.getattr = getattr;
ops.readdir = readdir;
ops.read = fileread;
all_dirs.create_file("readme.txt", "Hello, world!\n");
auto& testdir = all_dirs.create_dir("testdir");
testdir.create_file("LICENSE", "GNU GPL v3\n");
testdir.create_file("praise.txt", "Windoze suxxxx! L1n00xx foreva!\n");
fuse_main(argc, argv, &ops, NULL);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment