Skip to content

Instantly share code, notes, and snippets.

@jmillikin
Created October 6, 2018 17:43
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 jmillikin/827bc1c174f3444f33ff70933d4db16a to your computer and use it in GitHub Desktop.
Save jmillikin/827bc1c174f3444f33ff70933d4db16a to your computer and use it in GitHub Desktop.
use std::ffi::CString;
use std::io;
use std::time::Duration;
extern crate fuse;
use fuse::fs::{NodeId, Request};
use fuse::Respond;
struct MyFS {}
impl fuse::fs::Filesystem for MyFS {
fn mount_name(&self) -> String {
"hello-world".to_string()
}
fn mount_type(&self) -> String {
"hello-world".to_string()
}
fn init(&mut self, request: &fuse::fs::InitRequest) -> io::Result<fuse::fs::InitResponse> {
let mut resp = request.new_response();
//let mut flags = resp.flags();
//flags.set(fuse::fs::InitFlag::READDIRPLUS, false);
//resp.set_flags(flags);
resp.set_max_write(131072);
resp.set_time_gran(1);
Ok(resp)
}
fn lookup(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::LookupRequest,
) -> Respond<fuse::fs::LookupResponse> {
let mut resp = request.new_response();
resp.set_cache_duration(Duration::new(1, 0));
if request.name().to_bytes() == b"foobar" {
resp.set_node_id(123, 1);
resp.mut_attr().set_mode(0x8000 /* S_IFREG */ | 0o755);
} else if request.name().to_bytes() == b"foobar.dir" {
resp.set_node_id(124, 1);
resp.mut_attr().set_mode(0x4000 /* S_IFDIR */ | 0o755);
} else if request.name().to_bytes() == b"foobar.fifo" {
resp.set_node_id(125, 1);
resp.mut_attr().set_mode(0x1000 /* S_IFIFO */ | 0o755);
} else if request.name().to_bytes() == b"foobar.chr" {
resp.set_node_id(126, 1);
resp.mut_attr().set_mode(0x2000 /* S_IFCHR */ | 0o755);
} else {
return ctx.respond_err(io::Error::from_raw_os_error(2 /* ENOENT */));
}
resp.mut_attr().set_size(13);
resp.mut_attr().set_nlink(1);
ctx.respond_ok(resp)
}
fn getattr(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::GetattrRequest,
) -> Respond<fuse::fs::GetattrResponse> {
let mut resp = request.new_response();
resp.set_cache_duration(Duration::new(1, 0));
let attr = resp.mut_attr();
if request.node_id() == 1 {
attr.set_user_id(1000);
attr.set_group_id(1000);
attr.set_mode(0x4000 /* S_IFDIR */ | 0o755);
attr.set_nlink(2);
} else if request.node_id() == 123 {
attr.set_user_id(1000);
attr.set_group_id(1000);
attr.set_mode(0x8000 /* S_IFREG */ | 0o755);
attr.set_size(b"Hello world!\n".len() as u64);
attr.set_nlink(2);
} else if request.node_id() == 124 {
attr.set_user_id(1000);
attr.set_group_id(1000);
attr.set_mode(0x4000 /* S_IFDIR */ | 0o755);
attr.set_nlink(2);
} else if request.node_id() == 125 {
attr.set_user_id(1000);
attr.set_group_id(1000);
attr.set_mode(0x1000 /* S_IFIFO */ | 0o755);
attr.set_nlink(2);
} else if request.node_id() == 126 {
attr.set_user_id(1000);
attr.set_group_id(1000);
attr.set_mode(0x2000 /* S_IFCHR */ | 0o755);
attr.set_nlink(2);
} else {
return ctx.respond_err(io::Error::from_raw_os_error(2 /* ENOENT */));
}
ctx.respond_ok(resp)
}
fn open(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::OpenRequest,
) -> Respond<fuse::fs::OpenResponse> {
let mut resp = request.new_response();
resp.set_handle(1234);
ctx.respond_ok(resp)
}
fn read(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::ReadRequest,
) -> Respond<fuse::fs::ReadResponse> {
if request.handle() != 1234 {
return ctx.respond_err(io::Error::from_raw_os_error(5 /* EIO */));
}
let mut resp = request.new_response();
let mut value = Vec::new();
value.extend_from_slice(b"Hello world!\n");
resp.set_value(&value).unwrap();
ctx.respond_ok(resp)
}
fn write(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::WriteRequest,
) -> Respond<fuse::fs::WriteResponse> {
if request.handle() != 1234 {
return ctx.respond_err(io::Error::from_raw_os_error(5 /* EIO */));
}
let mut resp = request.new_response();
resp.set_size(request.value().len() as u32);
ctx.respond_ok(resp)
}
fn opendir(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::OpendirRequest,
) -> Respond<fuse::fs::OpendirResponse> {
let mut resp = request.new_response();
resp.set_handle(12345);
ctx.respond_ok(resp)
}
fn readdir(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::ReaddirRequest,
) -> Respond<fuse::fs::ReaddirResponse> {
let mut resp = request.new_response();
if request.offset() != 0 {
return ctx.respond_ok(resp);
}
{
let name = CString::new("foobar").unwrap();
let mut dirent = resp.push(NodeId::new(123).unwrap(), 1, &name).unwrap();
dirent.set_node_kind(fuse::fs::NodeKind::REG);
if let Some(node) = dirent.mut_node() {
node.mut_attr().set_size(13);
node.mut_attr().set_nlink(1);
}
}
{
let name = CString::new("foobar.dir").unwrap();
let mut dirent = resp.push(NodeId::new(124).unwrap(), 2, &name).unwrap();
dirent.set_node_kind(fuse::fs::NodeKind::DIR);
}
{
let name = CString::new("foobar.fifo").unwrap();
let mut dirent = resp.push(NodeId::new(125).unwrap(), 3, &name).unwrap();
dirent.set_node_kind(fuse::fs::NodeKind::FIFO);
}
{
let name = CString::new("foobar.chr").unwrap();
let mut dirent = resp.push(NodeId::new(126).unwrap(), 4, &name).unwrap();
dirent.set_node_kind(fuse::fs::NodeKind::CHR);
println!("dirent:\n{:?}", dirent);
}
ctx.respond_ok(resp)
}
fn releasedir(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::ReleasedirRequest,
) -> Respond<fuse::fs::ReleasedirResponse> {
let resp = request.new_response();
ctx.respond_ok(resp)
}
fn statfs(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::StatfsRequest,
) -> Respond<fuse::fs::StatfsResponse> {
let resp = request.new_response();
ctx.respond_ok(resp)
}
fn listxattr(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::ListxattrRequest,
) -> Respond<fuse::fs::ListxattrResponse> {
let mut resp = request.new_response();
resp.push(&CString::new("SOME_TEST_XATTR").unwrap())
.unwrap();
resp.push(&CString::new("ANOTHER.TEST.ATTR").unwrap())
.unwrap();
ctx.respond_ok(resp)
}
fn getxattr(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::GetxattrRequest,
) -> Respond<fuse::fs::GetxattrResponse> {
let mut resp = request.new_response();
if request.name().to_bytes() == b"SOME_TEST_XATTR" {
resp.set_value(&[72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33])
.unwrap();
return ctx.respond_ok(resp);
}
if request.name().to_bytes() == b"ANOTHER.TEST.ATTR" {
resp.set_value(&[1, 2, 3, 0, 4, 5, 6]).unwrap();
return ctx.respond_ok(resp);
}
return ctx.respond_err(io::Error::from_raw_os_error(61 /* ENODATA */));
}
fn setxattr(
&self,
ctx: fuse::ServerContext,
request: &fuse::fs::SetxattrRequest,
) -> Respond<fuse::fs::SetxattrResponse> {
let resp = request.new_response();
ctx.respond_ok(resp)
}
}
fn main() {
let fs = MyFS {};
let mountpoint = std::env::args_os().nth(1).unwrap();
let mut vol = fuse::mount(fs, mountpoint).unwrap();
vol.run().unwrap();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment