1use arc_swap::ArcSwap;
13use std::collections::HashMap;
14use std::ffi::CStr;
15use std::io::{Error, Result};
16use std::ops::Deref;
17use std::path::{Component, Path};
18use std::sync::atomic::{AtomicU64, Ordering};
19use std::sync::{Arc, Mutex};
20use std::time::{Duration, SystemTime};
21
22use crate::abi::fuse_abi::{stat64, Attr};
23use crate::api::filesystem::*;
24
25const PSEUDOFS_NEXT_INODE: u64 = 2;
27const PSEUDOFS_DEFAULT_ATTR_TIMEOUT: u64 = 1 << 32;
28const PSEUDOFS_DEFAULT_ENTRY_TIMEOUT: u64 = PSEUDOFS_DEFAULT_ATTR_TIMEOUT;
29
30type Inode = u64;
31type Handle = u64;
32
33struct PseudoInode {
34 ino: u64,
35 parent: u64,
36 children: ArcSwap<Vec<Arc<PseudoInode>>>,
37 name: String,
38}
39
40impl PseudoInode {
41 fn new(ino: u64, parent: u64, name: String) -> Self {
42 PseudoInode {
43 ino,
44 parent,
45 children: ArcSwap::new(Arc::new(Vec::new())),
46 name,
47 }
48 }
49
50 fn insert_child(&self, child: Arc<PseudoInode>) {
52 let mut children = self.children.load().deref().deref().clone();
53
54 children.push(child);
55
56 self.children.store(Arc::new(children));
57 }
58
59 fn remove_child(&self, child: Arc<PseudoInode>) {
60 let mut children = self.children.load().deref().deref().clone();
61
62 children
63 .iter()
64 .position(|x| x.name == child.name)
65 .map(|pos| children.remove(pos))
66 .unwrap();
67
68 self.children.store(Arc::new(children));
69 }
70}
71
72pub struct PseudoFs {
73 next_inode: AtomicU64,
74 root_inode: Arc<PseudoInode>,
75 inodes: ArcSwap<HashMap<u64, Arc<PseudoInode>>>,
76 lock: Mutex<()>, }
78
79impl PseudoFs {
80 pub fn new() -> Self {
81 let root_inode = Arc::new(PseudoInode::new(ROOT_ID, ROOT_ID, String::from("/")));
82 let fs = PseudoFs {
83 next_inode: AtomicU64::new(PSEUDOFS_NEXT_INODE),
84 root_inode: root_inode.clone(),
85 inodes: ArcSwap::new(Arc::new(HashMap::new())),
86 lock: Mutex::new(()),
87 };
88
89 let _guard = fs.lock.lock().unwrap();
91 fs.insert_inode(root_inode);
92 drop(_guard);
93
94 fs
95 }
96
97 pub fn mount(&self, mountpoint: &str) -> Result<u64> {
100 let path = Path::new(mountpoint);
101 if !path.has_root() {
102 error!("pseudo fs mount failure: invalid mount path {}", mountpoint);
103 return Err(Error::from_raw_os_error(libc::EINVAL));
104 }
105
106 let mut inodes = self.inodes.load();
107 let mut inode = &self.root_inode;
108
109 'outer: for component in path.components() {
110 trace!("pseudo fs mount iterate {:?}", component.as_os_str());
111 match component {
112 Component::RootDir => continue,
113 Component::CurDir => continue,
114 Component::ParentDir => inode = inodes.get(&inode.parent).unwrap(),
115 Component::Prefix(_) => {
116 error!("unsupported path: {}", mountpoint);
117 return Err(Error::from_raw_os_error(libc::EINVAL));
118 }
119 Component::Normal(path) => {
120 let name = path.to_str().unwrap();
121
122 for child in inode.children.load().iter() {
124 if child.name == name {
125 inode = inodes.get(&child.ino).unwrap();
126 continue 'outer;
127 }
128 }
129
130 let _guard = self.lock.lock();
132 for child in inode.children.load().iter() {
133 if child.name == name {
134 inode = inodes.get(&child.ino).unwrap();
135 continue 'outer;
136 }
137 }
138
139 let new_node = self.create_inode(name, inode);
140 inodes = self.inodes.load();
141 inode = inodes.get(&new_node.ino).unwrap();
142 }
143 }
144 }
145
146 Ok(inode.ino)
148 }
149
150 pub fn path_walk(&self, mountpoint: &str) -> Result<Option<u64>> {
151 let path = Path::new(mountpoint);
152 if !path.has_root() {
153 error!("pseudo fs walk failure: invalid path {}", mountpoint);
154 return Err(Error::from_raw_os_error(libc::EINVAL));
155 }
156
157 let inodes = self.inodes.load();
158 let mut inode = &self.root_inode;
159
160 'outer: for component in path.components() {
161 debug!("pseudo fs iterate {:?}", component.as_os_str());
162 match component {
163 Component::RootDir => continue,
164 Component::CurDir => continue,
165 Component::ParentDir => inode = inodes.get(&inode.parent).unwrap(),
166 Component::Prefix(_) => {
167 error!("unsupported path: {}", mountpoint);
168 return Err(Error::from_raw_os_error(libc::EINVAL));
169 }
170 Component::Normal(path) => {
171 let name = path.to_str().ok_or_else(|| {
172 error!("Path {:?} can't be converted safely", path);
173 Error::from_raw_os_error(libc::EINVAL)
174 })?;
175
176 for child in inode.children.load().iter() {
178 if child.name == name {
179 inode = inodes.get(&child.ino).unwrap();
180 continue 'outer;
181 }
182 }
183
184 let _guard = self.lock.lock();
186 for child in inode.children.load().iter() {
187 if child.name == name {
188 inode = inodes.get(&child.ino).unwrap();
189 continue 'outer;
190 }
191 }
192
193 debug!("name {} is not found, path is {}", name, mountpoint);
194 return Ok(None);
195 }
196 }
197 }
198
199 Ok(Some(inode.ino))
203 }
204
205 fn new_inode(&self, parent: u64, name: &str) -> Arc<PseudoInode> {
206 let ino = self.next_inode.fetch_add(1, Ordering::Relaxed);
207
208 Arc::new(PseudoInode::new(ino, parent, name.to_owned()))
209 }
210
211 fn insert_inode(&self, inode: Arc<PseudoInode>) {
213 let mut hashmap = self.inodes.load().deref().deref().clone();
214
215 hashmap.insert(inode.ino, inode);
216
217 self.inodes.store(Arc::new(hashmap));
218 }
219
220 fn create_inode(&self, name: &str, parent: &Arc<PseudoInode>) -> Arc<PseudoInode> {
222 let inode = self.new_inode(parent.ino, name);
223
224 self.insert_inode(inode.clone());
225 parent.insert_child(inode.clone());
226
227 inode
228 }
229
230 fn remove_inode(&self, inode: &Arc<PseudoInode>) {
231 let mut hashmap = self.inodes.load().deref().deref().clone();
232
233 hashmap.remove(&inode.ino);
234
235 self.inodes.store(Arc::new(hashmap));
236 }
237
238 pub fn get_parent_inode(&self, ino: u64) -> Option<u64> {
239 let _guard = self.lock.lock();
240 let inodes = self.inodes.load();
241 inodes.get(&ino).map(|o| o.parent)
242 }
243
244 #[allow(dead_code)]
245 pub fn evict_inode(&self, ino: u64) {
246 let _guard = self.lock.lock();
247 let inodes = self.inodes.load();
248
249 let inode = inodes.get(&ino).unwrap();
250 if ino == inode.parent {
253 return;
254 }
255
256 let parent = inodes.get(&inode.parent).unwrap();
257 parent.remove_child(inode.clone());
258
259 self.remove_inode(inode);
260 }
261
262 fn get_entry(&self, ino: u64) -> Entry {
263 let mut attr = Attr {
264 ..Default::default()
265 };
266 attr.ino = ino;
267 #[cfg(target_os = "linux")]
268 {
269 attr.mode = libc::S_IFDIR | libc::S_IRWXU | libc::S_IRWXG | libc::S_IRWXO;
270 }
271 #[cfg(target_os = "macos")]
272 {
273 attr.mode = (libc::S_IFDIR | libc::S_IRWXU | libc::S_IRWXG | libc::S_IRWXO) as u32;
274 }
275 let now = SystemTime::now();
276 attr.ctime = now
277 .duration_since(SystemTime::UNIX_EPOCH)
278 .unwrap()
279 .as_secs();
280 attr.mtime = attr.ctime;
281 attr.atime = attr.ctime;
282 attr.blksize = 4096;
283 Entry {
284 inode: ino,
285 generation: 0,
286 attr: attr.into(),
287 attr_flags: 0,
288 attr_timeout: Duration::from_secs(PSEUDOFS_DEFAULT_ATTR_TIMEOUT),
289 entry_timeout: Duration::from_secs(PSEUDOFS_DEFAULT_ENTRY_TIMEOUT),
290 }
291 }
292
293 fn do_readdir(
294 &self,
295 parent: u64,
296 size: u32,
297 offset: u64,
298 add_entry: &mut dyn FnMut(DirEntry) -> Result<usize>,
299 ) -> Result<()> {
300 if size == 0 {
301 return Ok(());
302 }
303
304 let inodes = self.inodes.load();
305 let inode = inodes
306 .get(&parent)
307 .ok_or_else(|| Error::from_raw_os_error(libc::ENOENT))?;
308 let mut next = offset + 1;
309 let children = inode.children.load();
310
311 if offset >= children.len() as u64 {
312 return Ok(());
313 }
314
315 for child in children[offset as usize..].iter() {
316 match add_entry(DirEntry {
317 ino: child.ino,
318 offset: next,
319 type_: 0,
320 name: child.name.clone().as_bytes(),
321 }) {
322 Ok(0) => break,
323 Ok(_) => next += 1,
324 Err(r) => return Err(r),
325 }
326 }
327
328 Ok(())
329 }
330}
331
332impl Default for PseudoFs {
333 fn default() -> Self {
334 Self::new()
335 }
336}
337
338impl FileSystem for PseudoFs {
339 type Inode = Inode;
340 type Handle = Handle;
341
342 fn lookup(&self, _: &Context, parent: u64, name: &CStr) -> Result<Entry> {
343 let inodes = self.inodes.load();
344 let pinode = inodes
345 .get(&parent)
346 .ok_or_else(|| Error::from_raw_os_error(libc::ENOENT))?;
347 let child_name = name
348 .to_str()
349 .map_err(|_| Error::from_raw_os_error(libc::EINVAL))?;
350 let mut ino: u64 = 0;
351 if child_name == "." {
352 ino = pinode.ino;
353 } else if child_name == ".." {
354 ino = pinode.parent;
355 } else {
356 for child in pinode.children.load().iter() {
357 if child.name == child_name {
358 ino = child.ino;
359 break;
360 }
361 }
362 }
363
364 if ino == 0 {
365 Err(Error::from_raw_os_error(libc::ENOENT))
367 } else {
368 Ok(self.get_entry(ino))
369 }
370 }
371
372 fn getattr(&self, _: &Context, inode: u64, _: Option<u64>) -> Result<(stat64, Duration)> {
373 let ino = self
374 .inodes
375 .load()
376 .get(&inode)
377 .map(|inode| inode.ino)
378 .ok_or_else(|| Error::from_raw_os_error(libc::ENOENT))?;
379 let entry = self.get_entry(ino);
380
381 Ok((entry.attr, entry.attr_timeout))
382 }
383
384 fn readdir(
385 &self,
386 _ctx: &Context,
387 inode: u64,
388 _: u64,
389 size: u32,
390 offset: u64,
391 add_entry: &mut dyn FnMut(DirEntry) -> Result<usize>,
392 ) -> Result<()> {
393 self.do_readdir(inode, size, offset, add_entry)
394 }
395
396 fn readdirplus(
397 &self,
398 _ctx: &Context,
399 inode: u64,
400 _handle: u64,
401 size: u32,
402 offset: u64,
403 add_entry: &mut dyn FnMut(DirEntry, Entry) -> Result<usize>,
404 ) -> Result<()> {
405 self.do_readdir(inode, size, offset, &mut |dir_entry| {
406 let entry = self.get_entry(dir_entry.ino);
407 add_entry(dir_entry, entry)
408 })
409 }
410
411 fn access(&self, _ctx: &Context, _inode: u64, _mask: u32) -> Result<()> {
412 Ok(())
413 }
414}
415
416#[cfg(feature = "persist")]
418pub mod persist {
419 use std::collections::HashMap;
420 use std::io::{Error as IoError, ErrorKind, Result};
421 use std::sync::atomic::Ordering;
422 use std::sync::Arc;
423
424 use dbs_snapshot::Snapshot;
425 use versionize::{VersionMap, Versionize, VersionizeResult};
426 use versionize_derive::Versionize;
427
428 use super::{PseudoFs, PseudoInode};
429 use crate::api::filesystem::ROOT_ID;
430
431 #[derive(Versionize, PartialEq, Debug, Default, Clone)]
432 struct PseudoInodeState {
433 ino: u64,
434 parent: u64,
435 name: String,
436 }
437
438 #[derive(Versionize, PartialEq, Debug, Default)]
439 pub struct PseudoFsState {
440 next_inode: u64,
441 inodes: Vec<PseudoInodeState>,
442 }
443
444 impl PseudoFs {
445 fn get_version_map() -> VersionMap {
446 let mut vm = VersionMap::new();
447 vm.set_type_version(PseudoFsState::type_id(), 1);
448
449 vm
452 }
453
454 pub fn save_to_bytes(&self) -> Result<Vec<u8>> {
458 let mut inodes = Vec::new();
459 let next_inode = self.next_inode.load(Ordering::Relaxed);
460
461 let _guard = self.lock.lock().unwrap();
462 for inode in self.inodes.load().values() {
463 if inode.ino == ROOT_ID {
464 continue;
466 }
467
468 inodes.push(PseudoInodeState {
469 ino: inode.ino,
470 parent: inode.parent,
471 name: inode.name.clone(),
472 });
473 }
474 let state = PseudoFsState { next_inode, inodes };
475
476 let vm = PseudoFs::get_version_map();
477 let target_version = vm.latest_version();
478 let mut s = Snapshot::new(vm, target_version);
479 let mut buf = Vec::new();
480 s.save(&mut buf, &state).map_err(|e| {
481 IoError::new(
482 ErrorKind::Other,
483 format!("Failed to save PseudoFs to bytes: {:?}", e),
484 )
485 })?;
486
487 Ok(buf)
488 }
489
490 pub fn restore_from_bytes(&self, buf: &mut Vec<u8>) -> Result<()> {
492 let state: PseudoFsState =
493 Snapshot::load(&mut buf.as_slice(), buf.len(), PseudoFs::get_version_map())
494 .map_err(|e| {
495 IoError::new(
496 ErrorKind::Other,
497 format!("Failed to load PseudoFs from bytes: {:?}", e),
498 )
499 })?
500 .0;
501 self.restore_from_state(&state)
502 }
503
504 fn restore_from_state(&self, state: &PseudoFsState) -> Result<()> {
505 let mut inode_map = HashMap::new();
507 let mut state_inodes = state.inodes.clone();
508 for inode in state_inodes.iter() {
509 let inode = Arc::new(PseudoInode::new(
510 inode.ino,
511 inode.parent,
512 inode.name.clone(),
513 ));
514 inode_map.insert(inode.ino, inode);
515 }
516
517 inode_map.insert(self.root_inode.ino, self.root_inode.clone());
519
520 state_inodes.sort_by(|a, b| a.ino.cmp(&b.ino));
522 for inode in state_inodes.iter() {
523 let inode = inode_map
524 .get(&inode.ino)
525 .ok_or_else(|| {
526 IoError::new(
527 ErrorKind::InvalidData,
528 format!("invalid inode {}", inode.ino),
529 )
530 })?
531 .clone();
532 let parent = inode_map.get_mut(&inode.parent).ok_or_else(|| {
533 IoError::new(
534 ErrorKind::InvalidData,
535 format!(
536 "invalid parent inode {} for inode {}",
537 inode.parent, inode.ino
538 ),
539 )
540 })?;
541 parent.insert_child(inode);
542 }
543 self.inodes.store(Arc::new(inode_map));
544
545 self.next_inode.store(state.next_inode, Ordering::Relaxed);
547
548 Ok(())
549 }
550 }
551
552 mod test {
553
554 #[test]
555 fn save_restore_test() {
556 use crate::api::pseudo_fs::PseudoFs;
557
558 let fs = &PseudoFs::new();
559 let paths = vec!["/a", "/a/b", "/a/b/c", "/b", "/b/a/c", "/d"];
560
561 for path in paths.iter() {
562 fs.mount(path).unwrap();
563 }
564
565 let mut buf = fs.save_to_bytes().unwrap();
567
568 let restored_fs = &PseudoFs::new();
570 restored_fs.restore_from_bytes(&mut buf).unwrap();
571
572 let next_inode = fs.next_inode.load(std::sync::atomic::Ordering::Relaxed);
574 let restored_next_inode = restored_fs
575 .next_inode
576 .load(std::sync::atomic::Ordering::Relaxed);
577 assert_eq!(next_inode, restored_next_inode);
578
579 for path in paths.iter() {
580 let inode = fs.path_walk(path).unwrap();
581 let restored_inode = restored_fs.path_walk(path).unwrap();
582 assert_eq!(inode, restored_inode);
583 }
584 }
585 }
586}
587
588#[cfg(test)]
589mod tests {
590 use super::*;
591 use std::ffi::CString;
592
593 fn create_fuse_context() -> Context {
594 Context::new()
595 }
596
597 #[test]
598 fn test_pseudofs_new() {
599 let fs = PseudoFs::new();
600
601 assert_eq!(fs.next_inode.load(Ordering::Relaxed), 2);
602 assert_eq!(fs.root_inode.ino, ROOT_ID);
603 assert_eq!(fs.root_inode.children.load().len(), 0);
604 assert_eq!(fs.inodes.load().len(), 1);
605 }
606
607 #[test]
608 fn test_pseudofs_mount() {
609 let fs = PseudoFs::new();
610
611 assert_eq!(
612 fs.mount("test").unwrap_err().raw_os_error().unwrap(),
613 libc::EINVAL
614 );
615
616 let a1 = fs.mount("/a").unwrap();
617 let a2 = fs.mount("/a").unwrap();
618 assert_eq!(a1, a2);
619 let a3 = fs.mount("/./a").unwrap();
620 assert_eq!(a1, a3);
621 let a4 = fs.mount("/../a").unwrap();
622 assert_eq!(a1, a4);
623 let a5 = fs.mount("/../../a").unwrap();
624 assert_eq!(a1, a5);
625
626 let c1 = fs.mount("/a/b/c").unwrap();
627 let c1_i = fs.inodes.load().get(&c1).unwrap().clone();
628 let b1 = fs.mount("/a/b").unwrap();
629 assert_eq!(c1, c1_i.ino);
630 assert_eq!(c1_i.parent, b1);
631
632 let _e1 = fs.mount("/a/b/c/d/e").unwrap();
633 }
634
635 #[test]
636 fn test_pseudofs_lookup() {
637 let fs = PseudoFs::new();
638 let a1 = fs.mount("/a").unwrap();
639 let b1 = fs.mount("/a/b").unwrap();
640 let c1 = fs.mount("/a/b/c").unwrap();
641
642 assert!(fs
643 .lookup(
644 &create_fuse_context(),
645 0x1000_0000,
646 &CString::new(".").unwrap()
647 )
648 .is_err());
649 assert_eq!(
650 fs.lookup(
651 &create_fuse_context(),
652 ROOT_ID,
653 &CString::new("..").unwrap()
654 )
655 .unwrap()
656 .inode,
657 ROOT_ID
658 );
659 assert_eq!(
660 fs.lookup(&create_fuse_context(), ROOT_ID, &CString::new(".").unwrap())
661 .unwrap()
662 .inode,
663 ROOT_ID
664 );
665 assert_eq!(
666 fs.lookup(&create_fuse_context(), ROOT_ID, &CString::new("a").unwrap())
667 .unwrap()
668 .inode,
669 a1
670 );
671 assert!(fs
672 .lookup(
673 &create_fuse_context(),
674 ROOT_ID,
675 &CString::new("a_no").unwrap()
676 )
677 .is_err());
678 assert_eq!(
679 fs.lookup(&create_fuse_context(), a1, &CString::new("b").unwrap())
680 .unwrap()
681 .inode,
682 b1
683 );
684 assert!(fs
685 .lookup(&create_fuse_context(), a1, &CString::new("b_no").unwrap())
686 .is_err());
687 assert_eq!(
688 fs.lookup(&create_fuse_context(), b1, &CString::new("c").unwrap())
689 .unwrap()
690 .inode,
691 c1
692 );
693 assert!(fs
694 .lookup(&create_fuse_context(), b1, &CString::new("c_no").unwrap())
695 .is_err());
696
697 assert_eq!(fs.path_walk("/a").unwrap(), Some(a1));
698 assert_eq!(fs.path_walk("/a/b").unwrap(), Some(b1));
699 assert_eq!(fs.path_walk("/a/b/c").unwrap(), Some(c1));
700 assert_eq!(fs.path_walk("/a/b/d").unwrap(), None);
701 assert_eq!(fs.path_walk("/a/b/c/d").unwrap(), None);
702
703 fs.evict_inode(b1);
704 fs.evict_inode(a1);
705 }
706
707 #[test]
708 fn test_pseudofs_getattr() {
709 let fs = PseudoFs::new();
710 let a1 = fs.mount("/a").unwrap();
711
712 fs.getattr(&create_fuse_context(), ROOT_ID, None).unwrap();
713 fs.getattr(&create_fuse_context(), a1, None).unwrap();
714 assert!(fs.getattr(&create_fuse_context(), 0x1000, None).is_err());
715
716 fs.evict_inode(a1);
717 fs.evict_inode(ROOT_ID);
718 }
719
720 #[test]
721 fn test_pseudofs_readdir() {
722 let fs = PseudoFs::new();
723 let _ = fs.mount("/a").unwrap();
724 let _ = fs.mount("/b").unwrap();
725
726 fs.readdir(&create_fuse_context(), ROOT_ID, 0, 0, 0, &mut |_| Ok(1))
727 .unwrap();
728 fs.readdir(&create_fuse_context(), ROOT_ID, 0, 1, 0, &mut |_| Ok(1))
729 .unwrap();
730 fs.readdir(&create_fuse_context(), ROOT_ID, 0, 1, 1, &mut |_| Ok(1))
731 .unwrap();
732 fs.readdir(&create_fuse_context(), ROOT_ID, 0, 2, 0, &mut |_| Ok(1))
733 .unwrap();
734 fs.readdir(&create_fuse_context(), ROOT_ID, 0, 3, 0, &mut |_| Ok(1))
735 .unwrap();
736 fs.readdir(&create_fuse_context(), ROOT_ID, 0, 3, 3, &mut |_| Ok(1))
737 .unwrap();
738 assert!(fs
739 .readdir(&create_fuse_context(), 0x1000, 0, 3, 0, &mut |_| Ok(1))
740 .is_err());
741 }
742
743 #[test]
744 fn test_pseudofs_readdir_plus() {
745 let fs = PseudoFs::new();
746 let _ = fs.mount("/a").unwrap();
747 let _ = fs.mount("/b").unwrap();
748
749 fs.readdirplus(&create_fuse_context(), ROOT_ID, 0, 0, 0, &mut |_, _| Ok(1))
750 .unwrap();
751 fs.readdirplus(&create_fuse_context(), ROOT_ID, 0, 1, 0, &mut |_, _| Ok(1))
752 .unwrap();
753 fs.readdirplus(&create_fuse_context(), ROOT_ID, 0, 1, 1, &mut |_, _| Ok(1))
754 .unwrap();
755 fs.readdirplus(&create_fuse_context(), ROOT_ID, 0, 2, 0, &mut |_, _| Ok(1))
756 .unwrap();
757 fs.readdirplus(&create_fuse_context(), ROOT_ID, 0, 3, 0, &mut |_, _| Ok(1))
758 .unwrap();
759 fs.readdirplus(&create_fuse_context(), ROOT_ID, 0, 3, 3, &mut |_, _| Ok(1))
760 .unwrap();
761 assert!(fs
762 .readdirplus(&create_fuse_context(), 0x1000, 0, 3, 0, &mut |_, _| Ok(1))
763 .is_err());
764 }
765
766 #[test]
767 fn test_pseudofs_access() {
768 let fs = PseudoFs::new();
769 let a1 = fs.mount("/a").unwrap();
770 let ctx = create_fuse_context();
771
772 fs.access(&ctx, a1, 0).unwrap();
773 }
774}