hellofs/
hellofs.rs

1extern crate fuse_rs;
2extern crate nix;
3
4use fuse_rs::{
5    fs::{DirEntry, FileInfo, FileStat, OpenFileInfo},
6    Filesystem,
7};
8use nix::{errno::Errno, fcntl::OFlag, sys::stat::SFlag};
9use std::{ffi::OsString, io::Read, path::Path};
10
11static HELLO_WORLD: &str = "Hello World!\n";
12
13struct HelloFS;
14
15impl Filesystem for HelloFS {
16    fn metadata(&self, path: &Path) -> fuse_rs::Result<FileStat> {
17        let mut stat = FileStat::new();
18        match path.to_str().expect("path") {
19            "/" => {
20                stat.st_mode = SFlag::S_IFDIR.bits() | 0o755;
21                stat.st_nlink = 3;
22            }
23            "/hello.txt" => {
24                stat.st_mode = SFlag::S_IFREG.bits() | 0o644;
25                stat.st_nlink = 1;
26                stat.st_size = HELLO_WORLD.len() as _;
27            }
28            _ => return Err(Errno::ENOENT),
29        }
30        Ok(stat)
31    }
32
33    fn read_dir(
34        &mut self,
35        path: &Path,
36        _offset: u64,
37        _file_info: FileInfo,
38    ) -> fuse_rs::Result<Vec<DirEntry>> {
39        if path != Path::new("/") {
40            return Err(Errno::ENOENT);
41        }
42
43        Ok(vec![".", "..", "hello.txt"]
44            .into_iter()
45            .map(|n| DirEntry {
46                name: OsString::from(n),
47                metadata: None,
48                offset: None,
49            })
50            .collect())
51    }
52
53    fn open(&mut self, path: &Path, file_info: &mut OpenFileInfo) -> fuse_rs::Result<()> {
54        if path != Path::new("/hello.txt") {
55            return Err(Errno::ENOENT);
56        }
57
58        if (file_info.flags().unwrap_or(OFlag::empty()) & OFlag::O_ACCMODE) != OFlag::O_RDONLY {
59            return Err(Errno::EACCES);
60        }
61
62        Ok(())
63    }
64
65    fn read(
66        &mut self,
67        path: &Path,
68        buf: &mut [u8],
69        offset: u64,
70        _file_info: FileInfo,
71    ) -> fuse_rs::Result<usize> {
72        if path != Path::new("/hello.txt") {
73            return Err(Errno::ENOENT);
74        }
75
76        let size = HELLO_WORLD.len() as u64;
77        let mut cap = buf.len() as u64;
78        if offset > size as _ {
79            return Ok(0);
80        }
81
82        if offset + cap > size {
83            cap = size - offset;
84        }
85
86        (&HELLO_WORLD.as_bytes()[offset as usize..cap as usize])
87            .read(buf)
88            .map_err(|e| Errno::from_i32(e.raw_os_error().expect("read error")))
89    }
90}
91
92fn main() -> Result<(), fuse_rs::Error> {
93    let opts = vec![
94        OsString::from("-s"),
95        OsString::from("-f"),
96        OsString::from("-d"),
97        OsString::from("-o"),
98        OsString::from("volname=hello_world"),
99        OsString::from("-o"),
100        OsString::from("ro"),
101    ];
102    static mut FS: HelloFS = HelloFS {};
103    unsafe {
104        fuse_rs::mount(
105            std::env::args_os().next().unwrap(),
106            "./hello_fs",
107            &mut FS,
108            opts,
109        )
110    }
111}