Created
May 17, 2018 08:09
-
-
Save rkfg/6ba436cb5f67a63ce05b7840c8ce775e to your computer and use it in GitHub Desktop.
Read-only FUSE filesystem in C++
This file contains hidden or 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
#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