1use anyfs_backend::*;
15use std::collections::HashMap;
16use std::ffi::OsStr;
17use std::io::{Read, Write};
18use std::path::{Path, PathBuf};
19use std::sync::atomic::{AtomicU64, Ordering};
20use std::sync::RwLock;
21use std::time::SystemTime;
22
23pub struct InMemoryFs {
43 files: RwLock<HashMap<PathBuf, Vec<u8>>>,
45
46 dirs: RwLock<std::collections::HashSet<PathBuf>>,
48
49 symlinks: RwLock<HashMap<PathBuf, PathBuf>>,
51
52 xattrs: RwLock<HashMap<PathBuf, HashMap<String, Vec<u8>>>>,
54
55 inodes: RwLock<HashMap<PathBuf, u64>>,
57
58 inode_to_path: RwLock<HashMap<u64, PathBuf>>,
60
61 handles: RwLock<HashMap<u64, OpenFile>>,
63
64 locks: RwLock<HashMap<u64, LockState>>,
66
67 next_inode: AtomicU64,
69
70 next_handle: AtomicU64,
72}
73
74struct OpenFile {
76 path: PathBuf,
77 flags: OpenFlags,
78}
79
80#[derive(Clone, Copy, PartialEq)]
82enum LockState {
83 Unlocked,
84 Shared(usize), Exclusive,
86}
87
88impl InMemoryFs {
89 pub fn new() -> Self {
93 let fs = Self {
94 files: RwLock::new(HashMap::new()),
95 dirs: RwLock::new(std::collections::HashSet::new()),
96 symlinks: RwLock::new(HashMap::new()),
97 xattrs: RwLock::new(HashMap::new()),
98 inodes: RwLock::new(HashMap::new()),
99 inode_to_path: RwLock::new(HashMap::new()),
100 handles: RwLock::new(HashMap::new()),
101 locks: RwLock::new(HashMap::new()),
102 next_inode: AtomicU64::new(2), next_handle: AtomicU64::new(1),
104 };
105
106 fs.dirs.write().unwrap().insert(PathBuf::from("/"));
108 fs.assign_inode(Path::new("/"));
109
110 fs
111 }
112
113 fn assign_inode(&self, path: &Path) -> u64 {
115 let mut inodes = self.inodes.write().unwrap();
116
117 if let Some(&inode) = inodes.get(path) {
119 return inode;
120 }
121
122 let inode = if path == Path::new("/") {
124 ROOT_INODE
125 } else {
126 self.next_inode.fetch_add(1, Ordering::SeqCst)
127 };
128
129 inodes.insert(path.to_path_buf(), inode);
131 self.inode_to_path
132 .write()
133 .unwrap()
134 .insert(inode, path.to_path_buf());
135
136 inode
137 }
138
139 fn get_file_type(&self, path: &Path) -> Option<FileType> {
141 if self.symlinks.read().unwrap().contains_key(path) {
142 Some(FileType::Symlink)
143 } else if self.dirs.read().unwrap().contains(path) {
144 Some(FileType::Directory)
145 } else if self.files.read().unwrap().contains_key(path) {
146 Some(FileType::File)
147 } else {
148 None
149 }
150 }
151}
152
153impl Default for InMemoryFs {
154 fn default() -> Self {
155 Self::new()
156 }
157}
158
159impl FsRead for InMemoryFs {
164 fn read(&self, path: &Path) -> Result<Vec<u8>, FsError> {
165 self.files
166 .read()
167 .unwrap()
168 .get(path)
169 .cloned()
170 .ok_or_else(|| FsError::NotFound {
171 path: path.to_path_buf(),
172 })
173 }
174
175 fn read_to_string(&self, path: &Path) -> Result<String, FsError> {
176 let bytes = self.read(path)?;
177 String::from_utf8(bytes).map_err(|_| FsError::InvalidData {
178 path: path.to_path_buf(),
179 details: "file contents are not valid UTF-8".into(),
180 })
181 }
182
183 fn read_range(&self, path: &Path, offset: u64, len: usize) -> Result<Vec<u8>, FsError> {
184 let data = self.read(path)?;
185 let start = offset as usize;
186
187 if start >= data.len() {
188 return Ok(Vec::new());
189 }
190
191 let end = (start + len).min(data.len());
192 Ok(data[start..end].to_vec())
193 }
194
195 fn exists(&self, path: &Path) -> Result<bool, FsError> {
196 Ok(self.get_file_type(path).is_some())
197 }
198
199 fn metadata(&self, path: &Path) -> Result<Metadata, FsError> {
200 let file_type = self.get_file_type(path).ok_or_else(|| FsError::NotFound {
201 path: path.to_path_buf(),
202 })?;
203
204 let size = if file_type == FileType::File {
205 self.files
206 .read()
207 .unwrap()
208 .get(path)
209 .map(|d| d.len() as u64)
210 .unwrap_or(0)
211 } else {
212 0
213 };
214
215 let inode = self.inodes.read().unwrap().get(path).copied().unwrap_or(0);
216
217 Ok(Metadata {
218 file_type,
219 size,
220 permissions: Permissions::default_file(),
221 created: SystemTime::UNIX_EPOCH,
222 modified: SystemTime::UNIX_EPOCH,
223 accessed: SystemTime::UNIX_EPOCH,
224 inode,
225 nlink: 1,
226 })
227 }
228
229 fn open_read(&self, path: &Path) -> Result<Box<dyn Read + Send>, FsError> {
230 let data = self.read(path)?;
231 Ok(Box::new(std::io::Cursor::new(data)))
232 }
233}
234
235impl FsWrite for InMemoryFs {
240 fn write(&self, path: &Path, data: &[u8]) -> Result<(), FsError> {
241 self.assign_inode(path);
242 self.files
243 .write()
244 .unwrap()
245 .insert(path.to_path_buf(), data.to_vec());
246 Ok(())
247 }
248
249 fn append(&self, path: &Path, data: &[u8]) -> Result<(), FsError> {
250 let mut files = self.files.write().unwrap();
251 files
252 .entry(path.to_path_buf())
253 .or_default()
254 .extend_from_slice(data);
255 drop(files);
256 self.assign_inode(path);
257 Ok(())
258 }
259
260 fn remove_file(&self, path: &Path) -> Result<(), FsError> {
261 self.files
262 .write()
263 .unwrap()
264 .remove(path)
265 .ok_or_else(|| FsError::NotFound {
266 path: path.to_path_buf(),
267 })?;
268
269 if let Some(inode) = self.inodes.write().unwrap().remove(path) {
271 self.inode_to_path.write().unwrap().remove(&inode);
272 }
273
274 self.xattrs.write().unwrap().remove(path);
276
277 Ok(())
278 }
279
280 fn rename(&self, from: &Path, to: &Path) -> Result<(), FsError> {
281 let mut files = self.files.write().unwrap();
282 let data = files.remove(from).ok_or_else(|| FsError::NotFound {
283 path: from.to_path_buf(),
284 })?;
285 files.insert(to.to_path_buf(), data);
286 drop(files);
287
288 if let Some(inode) = self.inodes.write().unwrap().remove(from) {
290 self.inodes.write().unwrap().insert(to.to_path_buf(), inode);
291 self.inode_to_path
292 .write()
293 .unwrap()
294 .insert(inode, to.to_path_buf());
295 } else {
296 self.assign_inode(to);
297 }
298
299 if let Some(attrs) = self.xattrs.write().unwrap().remove(from) {
301 self.xattrs.write().unwrap().insert(to.to_path_buf(), attrs);
302 }
303
304 Ok(())
305 }
306
307 fn copy(&self, from: &Path, to: &Path) -> Result<(), FsError> {
308 let data = self.read(from)?;
309 self.write(to, &data)
310 }
311
312 fn truncate(&self, path: &Path, size: u64) -> Result<(), FsError> {
313 let mut files = self.files.write().unwrap();
314 let data = files.get_mut(path).ok_or_else(|| FsError::NotFound {
315 path: path.to_path_buf(),
316 })?;
317 data.resize(size as usize, 0);
318 Ok(())
319 }
320
321 fn open_write(&self, path: &Path) -> Result<Box<dyn Write + Send>, FsError> {
322 if !self.files.read().unwrap().contains_key(path) {
324 self.write(path, &[])?;
325 }
326
327 Ok(Box::new(std::io::Cursor::new(Vec::new())))
330 }
331}
332
333impl FsDir for InMemoryFs {
338 fn read_dir(&self, path: &Path) -> Result<ReadDirIter, FsError> {
339 if !self.dirs.read().unwrap().contains(path) {
340 return Err(FsError::NotFound {
341 path: path.to_path_buf(),
342 });
343 }
344
345 let mut entries = Vec::new();
346
347 for (file_path, data) in self.files.read().unwrap().iter() {
349 if let Some(parent) = file_path.parent() {
350 if parent == path {
351 if let Some(name) = file_path.file_name() {
352 entries.push(Ok(DirEntry {
353 name: name.to_string_lossy().into_owned(),
354 path: file_path.clone(),
355 file_type: FileType::File,
356 size: data.len() as u64,
357 inode: self
358 .inodes
359 .read()
360 .unwrap()
361 .get(file_path)
362 .copied()
363 .unwrap_or(0),
364 }));
365 }
366 }
367 }
368 }
369
370 for dir_path in self.dirs.read().unwrap().iter() {
372 if let Some(parent) = dir_path.parent() {
373 if parent == path && dir_path != path {
374 if let Some(name) = dir_path.file_name() {
375 entries.push(Ok(DirEntry {
376 name: name.to_string_lossy().into_owned(),
377 path: dir_path.clone(),
378 file_type: FileType::Directory,
379 size: 0,
380 inode: self
381 .inodes
382 .read()
383 .unwrap()
384 .get(dir_path)
385 .copied()
386 .unwrap_or(0),
387 }));
388 }
389 }
390 }
391 }
392
393 for link_path in self.symlinks.read().unwrap().keys() {
395 if let Some(parent) = link_path.parent() {
396 if parent == path {
397 if let Some(name) = link_path.file_name() {
398 entries.push(Ok(DirEntry {
399 name: name.to_string_lossy().into_owned(),
400 path: link_path.clone(),
401 file_type: FileType::Symlink,
402 size: 0,
403 inode: self
404 .inodes
405 .read()
406 .unwrap()
407 .get(link_path)
408 .copied()
409 .unwrap_or(0),
410 }));
411 }
412 }
413 }
414 }
415
416 Ok(ReadDirIter::from_vec(entries))
417 }
418
419 fn create_dir(&self, path: &Path) -> Result<(), FsError> {
420 let mut dirs = self.dirs.write().unwrap();
421
422 if dirs.contains(path) {
423 return Err(FsError::AlreadyExists {
424 path: path.to_path_buf(),
425 operation: "create_dir",
426 });
427 }
428
429 if let Some(parent) = path.parent() {
431 if parent != Path::new("") && parent != Path::new("/") && !dirs.contains(parent) {
432 return Err(FsError::NotFound {
433 path: parent.to_path_buf(),
434 });
435 }
436 }
437
438 dirs.insert(path.to_path_buf());
439 drop(dirs);
440 self.assign_inode(path);
441
442 Ok(())
443 }
444
445 fn create_dir_all(&self, path: &Path) -> Result<(), FsError> {
446 let mut current = PathBuf::new();
447
448 for component in path.components() {
449 current.push(component);
450
451 let mut dirs = self.dirs.write().unwrap();
452 if !dirs.contains(¤t) {
453 dirs.insert(current.clone());
454 drop(dirs);
455 self.assign_inode(¤t);
456 }
457 }
458
459 Ok(())
460 }
461
462 fn remove_dir(&self, path: &Path) -> Result<(), FsError> {
463 let has_files = self
465 .files
466 .read()
467 .unwrap()
468 .keys()
469 .any(|p| p.parent() == Some(path));
470
471 let has_subdirs = self
472 .dirs
473 .read()
474 .unwrap()
475 .iter()
476 .any(|p| p.parent() == Some(path) && p != path);
477
478 if has_files || has_subdirs {
479 return Err(FsError::DirectoryNotEmpty {
480 path: path.to_path_buf(),
481 });
482 }
483
484 if !self.dirs.write().unwrap().remove(path) {
485 return Err(FsError::NotFound {
486 path: path.to_path_buf(),
487 });
488 }
489
490 if let Some(inode) = self.inodes.write().unwrap().remove(path) {
492 self.inode_to_path.write().unwrap().remove(&inode);
493 }
494
495 Ok(())
496 }
497
498 fn remove_dir_all(&self, path: &Path) -> Result<(), FsError> {
499 self.files
501 .write()
502 .unwrap()
503 .retain(|p, _| !p.starts_with(path));
504
505 self.dirs.write().unwrap().retain(|p| !p.starts_with(path));
507
508 self.symlinks
510 .write()
511 .unwrap()
512 .retain(|p, _| !p.starts_with(path));
513
514 let paths_to_remove: Vec<_> = self
516 .inodes
517 .read()
518 .unwrap()
519 .keys()
520 .filter(|p| p.starts_with(path))
521 .cloned()
522 .collect();
523
524 for p in paths_to_remove {
525 if let Some(inode) = self.inodes.write().unwrap().remove(&p) {
526 self.inode_to_path.write().unwrap().remove(&inode);
527 }
528 }
529
530 Ok(())
531 }
532}
533
534impl FsLink for InMemoryFs {
539 fn symlink(&self, target: &Path, link: &Path) -> Result<(), FsError> {
540 if self.get_file_type(link).is_some() {
541 return Err(FsError::AlreadyExists {
542 path: link.to_path_buf(),
543 operation: "symlink",
544 });
545 }
546
547 self.symlinks
548 .write()
549 .unwrap()
550 .insert(link.to_path_buf(), target.to_path_buf());
551 self.assign_inode(link);
552
553 Ok(())
554 }
555
556 fn hard_link(&self, original: &Path, link: &Path) -> Result<(), FsError> {
557 let data = self.read(original)?;
559 self.write(link, &data)?;
560
561 Ok(())
563 }
564
565 fn read_link(&self, path: &Path) -> Result<PathBuf, FsError> {
566 self.symlinks
567 .read()
568 .unwrap()
569 .get(path)
570 .cloned()
571 .ok_or_else(|| FsError::InvalidData {
572 path: path.to_path_buf(),
573 details: "not a symbolic link".into(),
574 })
575 }
576
577 fn symlink_metadata(&self, path: &Path) -> Result<Metadata, FsError> {
578 let file_type = self.get_file_type(path).ok_or_else(|| FsError::NotFound {
579 path: path.to_path_buf(),
580 })?;
581
582 Ok(Metadata {
583 file_type,
584 size: 0,
585 permissions: Permissions::default_file(),
586 created: SystemTime::UNIX_EPOCH,
587 modified: SystemTime::UNIX_EPOCH,
588 accessed: SystemTime::UNIX_EPOCH,
589 inode: self.inodes.read().unwrap().get(path).copied().unwrap_or(0),
590 nlink: 1,
591 })
592 }
593}
594
595impl FsPermissions for InMemoryFs {
600 fn set_permissions(&self, path: &Path, _perm: Permissions) -> Result<(), FsError> {
601 if self.get_file_type(path).is_none() {
603 return Err(FsError::NotFound {
604 path: path.to_path_buf(),
605 });
606 }
607
608 Ok(())
610 }
611}
612
613impl FsSync for InMemoryFs {
618 fn sync(&self) -> Result<(), FsError> {
619 Ok(())
621 }
622
623 fn fsync(&self, path: &Path) -> Result<(), FsError> {
624 if self.get_file_type(path).is_none() {
626 return Err(FsError::NotFound {
627 path: path.to_path_buf(),
628 });
629 }
630
631 Ok(())
633 }
634}
635
636impl FsStats for InMemoryFs {
641 fn statfs(&self) -> Result<StatFs, FsError> {
642 let files = self.files.read().unwrap();
643 let used_bytes: u64 = files.values().map(|d| d.len() as u64).sum();
644 let used_inodes = files.len() + self.dirs.read().unwrap().len();
645
646 Ok(StatFs {
647 total_bytes: 1024 * 1024 * 100, used_bytes,
649 available_bytes: 1024 * 1024 * 100 - used_bytes,
650 total_inodes: 100_000,
651 used_inodes: used_inodes as u64,
652 available_inodes: 100_000 - used_inodes as u64,
653 block_size: 4096,
654 max_name_len: 255,
655 })
656 }
657}
658
659impl FsInode for InMemoryFs {
664 fn path_to_inode(&self, path: &Path) -> Result<u64, FsError> {
665 self.inodes
666 .read()
667 .unwrap()
668 .get(path)
669 .copied()
670 .ok_or_else(|| FsError::NotFound {
671 path: path.to_path_buf(),
672 })
673 }
674
675 fn inode_to_path(&self, inode: u64) -> Result<PathBuf, FsError> {
676 self.inode_to_path
677 .read()
678 .unwrap()
679 .get(&inode)
680 .cloned()
681 .ok_or(FsError::InodeNotFound { inode })
682 }
683
684 fn lookup(&self, parent_inode: u64, name: &OsStr) -> Result<u64, FsError> {
685 let parent_path = self.inode_to_path(parent_inode)?;
686 let child_path = parent_path.join(name);
687 self.path_to_inode(&child_path)
688 }
689
690 fn metadata_by_inode(&self, inode: u64) -> Result<Metadata, FsError> {
691 let path = self.inode_to_path(inode)?;
692 self.metadata(&path)
693 }
694}
695
696impl FsHandles for InMemoryFs {
701 fn open(&self, path: &Path, flags: OpenFlags) -> Result<Handle, FsError> {
702 if flags.create {
704 if !self.files.read().unwrap().contains_key(path) {
705 self.write(path, &[])?;
706 }
707 } else if !self.files.read().unwrap().contains_key(path) {
708 return Err(FsError::NotFound {
709 path: path.to_path_buf(),
710 });
711 }
712
713 let handle_id = self.next_handle.fetch_add(1, Ordering::SeqCst);
714
715 self.handles.write().unwrap().insert(
716 handle_id,
717 OpenFile {
718 path: path.to_path_buf(),
719 flags,
720 },
721 );
722
723 Ok(Handle(handle_id))
724 }
725
726 fn read_at(&self, handle: Handle, buf: &mut [u8], offset: u64) -> Result<usize, FsError> {
727 let handles = self.handles.read().unwrap();
728 let open_file = handles
729 .get(&handle.0)
730 .ok_or(FsError::InvalidHandle { handle })?;
731
732 if !open_file.flags.read {
734 return Err(FsError::PermissionDenied {
735 path: open_file.path.clone(),
736 operation: "read",
737 });
738 }
739
740 let files = self.files.read().unwrap();
741 let data = files.get(&open_file.path).ok_or(FsError::NotFound {
742 path: open_file.path.clone(),
743 })?;
744
745 let start = offset as usize;
746 if start >= data.len() {
747 return Ok(0);
748 }
749
750 let end = (start + buf.len()).min(data.len());
751 let bytes_read = end - start;
752 buf[..bytes_read].copy_from_slice(&data[start..end]);
753
754 Ok(bytes_read)
755 }
756
757 fn write_at(&self, handle: Handle, data: &[u8], offset: u64) -> Result<usize, FsError> {
758 let path = {
759 let handles = self.handles.read().unwrap();
760 let open_file = handles
761 .get(&handle.0)
762 .ok_or(FsError::InvalidHandle { handle })?;
763
764 if !open_file.flags.write {
766 return Err(FsError::PermissionDenied {
767 path: open_file.path.clone(),
768 operation: "write",
769 });
770 }
771
772 open_file.path.clone()
773 };
774
775 let mut files = self.files.write().unwrap();
776 let file_data = files.entry(path).or_default();
777
778 let start = offset as usize;
779 if start + data.len() > file_data.len() {
780 file_data.resize(start + data.len(), 0);
781 }
782 file_data[start..start + data.len()].copy_from_slice(data);
783
784 Ok(data.len())
785 }
786
787 fn close(&self, handle: Handle) -> Result<(), FsError> {
788 self.locks.write().unwrap().remove(&handle.0);
790
791 self.handles
793 .write()
794 .unwrap()
795 .remove(&handle.0)
796 .map(|_| ())
797 .ok_or(FsError::InvalidHandle { handle })
798 }
799}
800
801impl FsLock for InMemoryFs {
806 fn lock(&self, handle: Handle, lock_type: LockType) -> Result<(), FsError> {
807 if !self.handles.read().unwrap().contains_key(&handle.0) {
808 return Err(FsError::InvalidHandle { handle });
809 }
810
811 let mut locks = self.locks.write().unwrap();
812 let state = locks.entry(handle.0).or_insert(LockState::Unlocked);
813
814 match (*state, lock_type) {
815 (LockState::Unlocked, LockType::Shared) => {
816 *state = LockState::Shared(1);
817 Ok(())
818 }
819 (LockState::Unlocked, LockType::Exclusive) => {
820 *state = LockState::Exclusive;
821 Ok(())
822 }
823 (LockState::Shared(n), LockType::Shared) => {
824 *state = LockState::Shared(n + 1);
825 Ok(())
826 }
827 _ => Err(FsError::Conflict {
828 path: PathBuf::new(),
829 }),
830 }
831 }
832
833 fn try_lock(&self, handle: Handle, lock_type: LockType) -> Result<bool, FsError> {
834 if !self.handles.read().unwrap().contains_key(&handle.0) {
835 return Err(FsError::InvalidHandle { handle });
836 }
837
838 let mut locks = self.locks.write().unwrap();
839 let state = locks.entry(handle.0).or_insert(LockState::Unlocked);
840
841 match (*state, lock_type) {
842 (LockState::Unlocked, LockType::Shared) => {
843 *state = LockState::Shared(1);
844 Ok(true)
845 }
846 (LockState::Unlocked, LockType::Exclusive) => {
847 *state = LockState::Exclusive;
848 Ok(true)
849 }
850 (LockState::Shared(n), LockType::Shared) => {
851 *state = LockState::Shared(n + 1);
852 Ok(true)
853 }
854 _ => Ok(false),
855 }
856 }
857
858 fn unlock(&self, handle: Handle) -> Result<(), FsError> {
859 if !self.handles.read().unwrap().contains_key(&handle.0) {
860 return Err(FsError::InvalidHandle { handle });
861 }
862
863 let mut locks = self.locks.write().unwrap();
864 if let Some(state) = locks.get_mut(&handle.0) {
865 match *state {
866 LockState::Shared(1) => *state = LockState::Unlocked,
867 LockState::Shared(n) => *state = LockState::Shared(n - 1),
868 LockState::Exclusive => *state = LockState::Unlocked,
869 LockState::Unlocked => {}
870 }
871 }
872
873 Ok(())
874 }
875}
876
877impl FsXattr for InMemoryFs {
882 fn get_xattr(&self, path: &Path, name: &str) -> Result<Vec<u8>, FsError> {
883 if self.get_file_type(path).is_none() {
885 return Err(FsError::NotFound {
886 path: path.to_path_buf(),
887 });
888 }
889
890 self.xattrs
891 .read()
892 .unwrap()
893 .get(path)
894 .and_then(|attrs| attrs.get(name).cloned())
895 .ok_or_else(|| FsError::XattrNotFound {
896 path: path.to_path_buf(),
897 name: name.to_string(),
898 })
899 }
900
901 fn set_xattr(&self, path: &Path, name: &str, value: &[u8]) -> Result<(), FsError> {
902 if self.get_file_type(path).is_none() {
904 return Err(FsError::NotFound {
905 path: path.to_path_buf(),
906 });
907 }
908
909 self.xattrs
910 .write()
911 .unwrap()
912 .entry(path.to_path_buf())
913 .or_default()
914 .insert(name.to_string(), value.to_vec());
915
916 Ok(())
917 }
918
919 fn remove_xattr(&self, path: &Path, name: &str) -> Result<(), FsError> {
920 if self.get_file_type(path).is_none() {
922 return Err(FsError::NotFound {
923 path: path.to_path_buf(),
924 });
925 }
926
927 self.xattrs
928 .write()
929 .unwrap()
930 .get_mut(path)
931 .and_then(|attrs| attrs.remove(name))
932 .ok_or_else(|| FsError::XattrNotFound {
933 path: path.to_path_buf(),
934 name: name.to_string(),
935 })?;
936
937 Ok(())
938 }
939
940 fn list_xattr(&self, path: &Path) -> Result<Vec<String>, FsError> {
941 if self.get_file_type(path).is_none() {
943 return Err(FsError::NotFound {
944 path: path.to_path_buf(),
945 });
946 }
947
948 Ok(self
949 .xattrs
950 .read()
951 .unwrap()
952 .get(path)
953 .map(|attrs| attrs.keys().cloned().collect())
954 .unwrap_or_default())
955 }
956}
957
958fn main() {
963 println!("=== In-Memory Filesystem Reference Implementation ===\n");
964
965 let fs = InMemoryFs::new();
966
967 println!("--- Layer 1: Fs (FsRead + FsWrite + FsDir) ---\n");
969
970 fs.create_dir_all(Path::new("/project/src")).unwrap();
971 fs.write(Path::new("/project/README.md"), b"# My Project\n\nHello!")
972 .unwrap();
973 fs.write(Path::new("/project/src/main.rs"), b"fn main() {}")
974 .unwrap();
975
976 println!("Created project structure:");
977 for entry in fs.read_dir(Path::new("/project")).unwrap() {
978 let entry = entry.unwrap();
979 println!(" {} ({:?})", entry.name, entry.file_type);
980 }
981
982 let readme = fs.read_to_string(Path::new("/project/README.md")).unwrap();
983 println!("\nREADME.md content:\n{readme}");
984
985 println!("\n--- Layer 2: FsFull (+FsLink, +FsStats, +FsSync) ---\n");
987
988 fs.symlink(Path::new("/project/README.md"), Path::new("/project/docs"))
989 .unwrap();
990 let target = fs.read_link(Path::new("/project/docs")).unwrap();
991 println!("Symlink /project/docs -> {}", target.display());
992
993 let stats = fs.statfs().unwrap();
994 println!(
995 "Filesystem: {} bytes used, {} available",
996 stats.used_bytes, stats.available_bytes
997 );
998
999 fs.sync().unwrap();
1000 println!("Filesystem synced");
1001
1002 println!("\n--- Layer 3: FsFuse (+FsInode) ---\n");
1004
1005 let root_inode = fs.path_to_inode(Path::new("/")).unwrap();
1006 println!("Root inode: {root_inode} (should be {})", ROOT_INODE);
1007
1008 let project_inode = fs.lookup(root_inode, OsStr::new("project")).unwrap();
1009 println!("Project inode: {project_inode}");
1010
1011 let meta = fs.metadata_by_inode(project_inode).unwrap();
1012 println!("Project metadata: {:?}", meta.file_type);
1013
1014 println!("\n--- Layer 4: FsPosix (+FsHandles, +FsLock, +FsXattr) ---\n");
1016
1017 let handle = fs
1019 .open(Path::new("/project/data.bin"), OpenFlags::WRITE)
1020 .unwrap();
1021 fs.write_at(handle, b"HEADER", 0).unwrap();
1022 fs.write_at(handle, b"DATA", 6).unwrap();
1023 fs.close(handle).unwrap();
1024 println!("Wrote data.bin using handle-based I/O");
1025
1026 let handle = fs
1027 .open(Path::new("/project/data.bin"), OpenFlags::READ)
1028 .unwrap();
1029 let mut buf = [0u8; 10];
1030 let n = fs.read_at(handle, &mut buf, 0).unwrap();
1031 println!("Read {} bytes: {:?}", n, String::from_utf8_lossy(&buf[..n]));
1032 fs.close(handle).unwrap();
1033
1034 let handle = fs
1036 .open(Path::new("/project/data.bin"), OpenFlags::READ)
1037 .unwrap();
1038 fs.lock(handle, LockType::Shared).unwrap();
1039 println!("Acquired shared lock");
1040 fs.unlock(handle).unwrap();
1041 println!("Released lock");
1042 fs.close(handle).unwrap();
1043
1044 fs.set_xattr(Path::new("/project/README.md"), "user.author", b"Alice")
1046 .unwrap();
1047 let author = fs
1048 .get_xattr(Path::new("/project/README.md"), "user.author")
1049 .unwrap();
1050 println!("xattr user.author = {:?}", String::from_utf8_lossy(&author));
1051
1052 let attrs = fs.list_xattr(Path::new("/project/README.md")).unwrap();
1053 println!("All xattrs: {:?}", attrs);
1054
1055 println!("\n--- Using as Trait Objects ---\n");
1057
1058 fn use_as_fs(fs: &dyn Fs) {
1059 println!(
1060 " Works as &dyn Fs: {} files in root",
1061 fs.read_dir(Path::new("/")).unwrap().count()
1062 );
1063 }
1064
1065 fn use_as_full(fs: &dyn FsFull) {
1066 println!(
1067 " Works as &dyn FsFull: {} bytes total",
1068 fs.statfs().unwrap().total_bytes
1069 );
1070 }
1071
1072 fn use_as_fuse(fs: &dyn FsFuse) {
1073 println!(
1074 " Works as &dyn FsFuse: root inode = {}",
1075 fs.path_to_inode(Path::new("/")).unwrap()
1076 );
1077 }
1078
1079 fn use_as_posix(fs: &dyn FsPosix) {
1080 let handle = fs
1081 .open(Path::new("/project/README.md"), OpenFlags::READ)
1082 .unwrap();
1083 let mut buf = [0u8; 5];
1084 let n = fs.read_at(handle, &mut buf, 0).unwrap();
1085 fs.close(handle).unwrap();
1086 println!(" Works as &dyn FsPosix: read {} bytes", n);
1087 }
1088
1089 use_as_fs(&fs);
1090 use_as_full(&fs);
1091 use_as_fuse(&fs);
1092 use_as_posix(&fs);
1093
1094 println!("\n=== Reference implementation demonstration complete! ===");
1095}