Skip to content

Instantly share code, notes, and snippets.

@starfleetcadet75
Created May 27, 2018 18:53
Show Gist options
  • Select an option

  • Save starfleetcadet75/20c3c1a6f62573cefc8e0a2ee1b4d7a8 to your computer and use it in GitHub Desktop.

Select an option

Save starfleetcadet75/20c3c1a6f62573cefc8e0a2ee1b4d7a8 to your computer and use it in GitHub Desktop.
Using FUSE in Rust
[package]
name = "rfuse"
version = "0.1.0"
[dependencies]
fuse = "0.3"
libc = "0.2.41"
time = "0.1.40"
serde_json = "1.0.18"
extern crate serde_json;
extern crate fuse;
extern crate libc;
extern crate time;
use fuse::{FileAttr, FileType, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use time::Timespec;
use libc::ENOENT;
use std::env;
use std::path::Path;
use std::ffi::OsStr;
use std::collections::BTreeMap;
struct JsonFilesystem {
/// JSON Value representing files and contents as Key-Value pairs.
tree: serde_json::Value,
/// Maps filenames to their inodes.
inodes: BTreeMap<String, u64>,
/// Maps inodes to their file attributes.
attrs: BTreeMap<u64, FileAttr>,
}
impl JsonFilesystem {
fn new(tree: serde_json::Value) -> JsonFilesystem {
let mut attrs = BTreeMap::new();
let mut inodes = BTreeMap::new();
let ts = time::now().to_timespec();
// Create entry for the root directory
attrs.insert(1, FileAttr {
ino: 1,
size: 0,
blocks: 0,
atime: ts,
mtime: ts,
ctime: ts,
crtime: ts,
kind: FileType::Directory,
perm: 0o755,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
flags: 0,
});
inodes.insert("/".to_string(), 1);
// Create entries for each file in the JSON tree
for (i, (key, value)) in tree.as_object().unwrap().iter().enumerate() {
let attr = FileAttr {
ino: i as u64 + 2,
size: value.to_string().len() as u64,
blocks: 0,
atime: ts,
mtime: ts,
ctime: ts,
crtime: ts,
kind: FileType::RegularFile,
perm: 0o644,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
flags: 0,
};
attrs.insert(attr.ino, attr);
inodes.insert(key.clone(), attr.ino);
}
JsonFilesystem {
tree: tree.clone(),
inodes: inodes,
attrs: attrs,
}
}
}
impl Filesystem for JsonFilesystem {
fn getattr(&mut self, _req: &Request, inode: u64, reply: ReplyAttr) {
println!("getattr(inode={})", inode);
match self.attrs.get(&inode) {
Some(attr) => {
let ttl = Timespec::new(1, 0);
reply.attr(&ttl, attr);
},
None => reply.error(ENOENT),
};
}
fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
println!("lookup(parent={}, name={})", parent, name.to_str().unwrap());
// Use the filename to lookup the inode
let inode = match self.inodes.get(name.to_str().unwrap()) {
Some(inode) => inode,
None => {
reply.error(ENOENT);
return;
},
};
match self.attrs.get(inode) {
Some(attr) => {
let ttl = Timespec::new(1, 0);
reply.entry(&ttl, attr, 0);
},
None => reply.error(ENOENT),
};
}
fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: i64, size: u32, reply: ReplyData) {
println!("read(inode={}, fh={}, offset={}, size={})", ino, fh, offset, size);
for (key, &inode) in self.inodes.iter() {
if inode == ino {
let value = self.tree.get(key).unwrap();
reply.data(value.to_string().as_bytes());
return;
}
}
reply.error(ENOENT);
}
fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: i64, mut reply: ReplyDirectory) {
println!("readdir(inode={}, fh={}, offset={})", ino, fh, offset);
if ino == 1 {
if offset == 0 {
reply.add(1, 0, FileType::Directory, &Path::new("."));
reply.add(1, 1, FileType::Directory, &Path::new(".."));
for (key, &inode) in &self.inodes {
// Skip over the root inode
if inode == 1 {
continue;
}
let offset = inode as i64;
println!("\tkey={}, inode={}, offset={}", key, inode, offset);
reply.add(inode, offset, FileType::RegularFile, key);
}
}
reply.ok();
} else {
reply.error(ENOENT);
}
}
}
fn main() {
let data = r#"{
"file1": "Random contents",
"file2": 124346,
"file3": "42"
}"#;
let tree: serde_json::Value = serde_json::from_str(data).unwrap();
let fs = JsonFilesystem::new(tree);
// Get the mountpoint from the first argument
let mountpoint = match env::args().nth(1) {
Some(path) => path,
None => {
println!("Usage: {} <MOUNTPOINT>", env::args().nth(0).unwrap());
return;
}
};
fuse::mount(fs, &mountpoint, &[]).expect("Failed to mount filesystem");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment