1use simply_fuse::attrs::{FileAttributes, SetFileAttributes};
2use simply_fuse::basic::*;
3use simply_fuse::error::{FSError, FSResult as Result};
4use simply_fuse::*;
5
6use std::ffi::OsStr;
7use std::io::BufRead;
8use std::path::Path;
9
10const TEST_MSG: &str = "hello_world!";
11
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13 let mount = &Path::new("./memfs-mount/");
14 let _ = std::fs::create_dir(mount);
15
16 let mut fs = MemFS::new();
17 fs.inodes
18 .push_entry(ROOT_INODE, "test".into(), Directory::default());
19
20 fs.inodes
21 .push_entry(2u64.into(), "test2".into(), Directory::default());
22
23 fs.inodes
24 .push_entry(3u64.into(), "test3".into(), Directory::default());
25
26 fs.inodes
27 .push_entry(1u64.into(), "root2".into(), Directory::default());
28
29 fs.inodes.push_entry(
30 ROOT_INODE,
31 "file".into(),
32 File::new(TEST_MSG.as_bytes().into()),
33 );
34
35 let mut r = Runner::new(fs, mount);
36 println!("{:#?}", r);
37 r.run_block()?;
38
39 Ok(())
40}
41
42#[derive(Debug)]
43pub struct File {
44 pub data: Vec<u8>,
45 pub attrs: FileAttributes,
46}
47
48impl File {
49 fn new(data: Vec<u8>) -> File {
50 File {
51 attrs: FileAttributes::builder()
52 .size(data.len() as u64)
53 .mode(libc::S_IFREG | 0o755)
54 .build(),
55
56 data,
57 }
58 }
59
60 fn size(&self) -> usize {
61 self.attrs.size() as usize
62 }
63}
64
65impl Attributable for File {
66 fn getattrs(&self) -> FileAttributes {
67 self.attrs
68 }
69}
70
71impl Filelike for File {}
72
73#[derive(Debug)]
74struct MemFS {
75 inodes: INodeTable<File>,
76}
77
78impl MemFS {
79 fn new() -> MemFS {
80 MemFS {
81 inodes: INodeTable::default(),
82 }
83 }
84}
85
86impl Filesystem for MemFS {
87 fn lookup(&mut self, parent: INode, name: &OsStr) -> Result<Lookup> {
88 let parent = self
89 .inodes
90 .get(parent)
91 .ok_or(FSError::NoEntry)
92 .and_then(|x| x.as_dir().ok_or(FSError::NotDirectory))?;
93
94 let (child_ino, child) = parent
95 .get(name)
96 .and_then(|ino| self.inodes.get(*ino).map(|x| (*ino, x)))
98 .ok_or(FSError::NoEntry)?;
99
100 Ok(Lookup::builder()
101 .attributes(child.getattrs())
102 .inode(child_ino)
103 .build())
104 }
105
106 fn getattr(&mut self, inode: INode) -> Result<FileAttributes> {
107 let entry = self.inodes.get(inode).ok_or(FSError::NoEntry)?;
108
109 Ok(entry.getattrs())
110 }
111
112 fn readdir(&mut self, dir_ino: INode, offset: u64) -> Result<Vec<DirEntry>> {
113 let dir_main = self.inodes.get(dir_ino).ok_or(FSError::NoEntry)?;
114 let dir = dir_main.as_dir().ok_or(FSError::NotDirectory)?;
115
116 let dots = [
117 DirEntry::builder()
118 .name(".".into())
119 .inode(dir_ino)
120 .typ(FileType::Directory)
121 .offset(1)
122 .build(),
123 DirEntry::builder()
124 .name("..".into())
125 .inode(dir_main.parent().unwrap_or(ROOT_INODE))
126 .typ(FileType::Directory)
127 .offset(2)
128 .build(),
129 ];
130
131 Ok(dots
132 .into_iter()
133 .chain(
134 dir.children()
135 .enumerate()
136 .map(
137 |(off, v)| (off + 3, v), )
139 .map(|(offset, (name, inode))| {
140 DirEntry::builder()
141 .name(name.clone())
142 .offset(offset as u64)
143 .inode(inode)
144 .typ(self.inodes.get(inode).unwrap().file_type())
145 .build()
146 }),
147 )
148 .skip(offset as usize)
149 .collect())
150 }
151
152 fn read(&mut self, ino: INode, offset: u64, size: u32) -> Result<&[u8]> {
153 let file = self.inodes.get(ino).ok_or(FSError::NoEntry)?;
154 let file = file.as_file().ok_or(FSError::NotFile)?;
155
156 let offset = offset as usize;
157 let size = size as usize;
158
159 let content = file.data.get(offset..).unwrap_or(&[]);
160 let content = &content[..std::cmp::min(file.size(), size)];
161
162 Ok(content)
163 }
164
165 fn write<T: BufRead>(&mut self, ino: INode, offset: u64, size: u32, mut buf: T) -> Result<u32> {
166 let file = self.inodes.get_mut(ino).ok_or(FSError::NoEntry)?;
167 let file = file.as_file_mut().ok_or(FSError::NotFile)?;
168
169 let offset = offset as usize;
170 let size = size as usize;
171
172 file.data
173 .resize(std::cmp::max(file.size(), offset + size), 0);
174
175 buf.read_exact(&mut file.data[offset..offset + size])
176 .unwrap();
177
178 file.attrs.set_size((offset + size) as u64);
179
180 Ok(size as u32)
181 }
182
183 fn setattr(&mut self, ino: INode, attrs: SetFileAttributes) -> Result<FileAttributes> {
184 let entry = self.inodes.get_mut(ino).ok_or(FSError::NoEntry)?;
185
186 match entry.kind_mut() {
187 INodeKind::Directory(dir) => dir.apply_attrs(attrs),
188 INodeKind::File(file) => file.attrs.apply_attrs(attrs),
189 };
190
191 Ok(entry.getattrs())
192 }
193}