1mod fat;
2pub mod mapping;
3mod mbr;
4pub mod path;
5
6use core::ops;
7
8use alloc::{boxed::Box, string::String, sync::Arc, vec, vec::Vec};
9use kernel_user_link::file::{BlockingMode, DirEntry, FileStat, FileType, OpenOptions};
10use mapping::MappingError;
11use path::PathBuf;
12use tracing::info;
13
14use crate::{
15 devices::{
16 ide::{self, IdeDeviceIndex, IdeDeviceType},
17 Device, DEVICES_FILESYSTEM_CLUSTER_MAGIC,
18 },
19 sync::{once::OnceLock, spin::mutex::Mutex},
20};
21
22use self::{
23 mbr::Mbr,
24 path::{Component, Path},
25};
26
27pub(crate) const ANOTHER_FILESYSTEM_MAPPING_INODE_MAGIC: u64 = 0xf11356573e;
29pub(crate) const NO_PARENT_DIR_SECTOR: u64 = 0xFFFF_FFFF_FFFF_FFFF;
30
31static EMPTY_FILESYSTEM: OnceLock<Arc<EmptyFileSystem>> = OnceLock::new();
32
33pub fn empty_filesystem() -> Arc<EmptyFileSystem> {
34 EMPTY_FILESYSTEM
35 .get_or_init(|| Arc::new(EmptyFileSystem))
36 .clone()
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub struct FileAttributes(pub u8);
41
42#[allow(dead_code)]
43impl FileAttributes {
44 pub const EMPTY: FileAttributes = FileAttributes(0);
45 pub const READ_ONLY: FileAttributes = FileAttributes(0b0000_0001);
46 pub const HIDDEN: FileAttributes = FileAttributes(0b0000_0010);
47 pub const SYSTEM: FileAttributes = FileAttributes(0b0000_0100);
48 pub const VOLUME_LABEL: FileAttributes = FileAttributes(0b0000_1000);
49 pub const DIRECTORY: FileAttributes = FileAttributes(0b0001_0000);
50 pub const ARCHIVE: FileAttributes = FileAttributes(0b0010_0000);
51
52 pub fn read_only(self) -> bool {
53 self.0 & Self::READ_ONLY.0 != 0
54 }
55
56 pub fn hidden(self) -> bool {
57 self.0 & Self::HIDDEN.0 != 0
58 }
59
60 pub fn system(self) -> bool {
61 self.0 & Self::SYSTEM.0 != 0
62 }
63
64 pub fn volume_label(self) -> bool {
65 self.0 & Self::VOLUME_LABEL.0 != 0
66 }
67
68 pub fn directory(self) -> bool {
69 self.0 & Self::DIRECTORY.0 != 0
70 }
71
72 pub fn archive(self) -> bool {
73 self.0 & Self::ARCHIVE.0 != 0
74 }
75
76 fn contains(&self, other: FileAttributes) -> bool {
77 self.0 & other.0 != 0
78 }
79}
80
81impl ops::BitOr for FileAttributes {
82 type Output = Self;
83
84 fn bitor(self, rhs: Self) -> Self::Output {
85 FileAttributes(self.0 | rhs.0)
86 }
87}
88
89impl ops::BitOrAssign for FileAttributes {
90 fn bitor_assign(&mut self, rhs: Self) {
91 self.0 |= rhs.0;
92 }
93}
94
95impl ops::BitAnd for FileAttributes {
96 type Output = Self;
97
98 fn bitand(self, rhs: Self) -> Self::Output {
99 FileAttributes(self.0 & rhs.0)
100 }
101}
102
103#[derive(Debug, Clone)]
104pub struct BaseNode {
105 name: String,
106 attributes: FileAttributes,
107 start_cluster: u64,
108 parent_dir_sector: u64,
109 parent_dir_index: u16,
113}
114
115impl BaseNode {
116 pub fn name(&self) -> &str {
117 &self.name
118 }
119
120 pub fn start_cluster(&self) -> u64 {
121 self.start_cluster
122 }
123
124 #[allow(dead_code)]
125 pub fn attributes(&self) -> FileAttributes {
126 self.attributes
127 }
128
129 #[allow(dead_code)]
130 pub fn parent_dir_sector(&self) -> u64 {
131 self.parent_dir_sector
132 }
133
134 #[allow(dead_code)]
135 pub fn parent_dir_index(&self) -> u16 {
136 self.parent_dir_index
137 }
138}
139
140#[derive(Debug, Clone)]
141pub struct FileNode {
142 base: BaseNode,
143 size: u64,
144 device: Option<Arc<dyn Device>>,
145}
146
147impl FileNode {
148 pub fn new_file(
149 name: String,
150 attributes: FileAttributes,
151 start_cluster: u64,
152 size: u64,
153 parent_dir_sector: u64,
154 parent_dir_index: u16,
155 ) -> Self {
156 assert!(!attributes.directory());
157 Self {
158 base: BaseNode {
159 name,
160 attributes,
161 start_cluster,
162 parent_dir_sector,
163 parent_dir_index,
164 },
165 size,
166 device: None,
167 }
168 }
169
170 pub fn new_device(name: String, attributes: FileAttributes, device: Arc<dyn Device>) -> Self {
171 assert!(!attributes.directory());
172 Self {
173 base: BaseNode {
174 name,
175 attributes,
176 start_cluster: DEVICES_FILESYSTEM_CLUSTER_MAGIC,
177 parent_dir_sector: NO_PARENT_DIR_SECTOR,
178 parent_dir_index: 0,
179 },
180 size: 0,
181 device: Some(device),
182 }
183 }
184
185 pub fn size(&self) -> u64 {
186 self.size
187 }
188
189 pub(self) fn set_size(&mut self, size: u64) {
190 self.size = size;
191 }
192
193 pub fn try_open_device(&mut self) -> Result<(), FileSystemError> {
194 if let Some(device) = self.device.take() {
195 self.device = Some(device.try_create().unwrap_or(Ok(device))?);
196 }
197
198 Ok(())
199 }
200}
201
202impl Drop for FileNode {
203 fn drop(&mut self) {
204 if let Some(device) = self.device.take() {
205 device.close().expect("Failed to close device");
206 }
207 }
208}
209
210#[derive(Debug, Clone)]
211pub struct DirectoryNode {
212 base: BaseNode,
213}
214
215impl DirectoryNode {
216 pub fn without_parent(name: String, attributes: FileAttributes, start_cluster: u64) -> Self {
217 Self::new(name, attributes, start_cluster, NO_PARENT_DIR_SECTOR, 0)
218 }
219
220 pub fn new(
221 name: String,
222 attributes: FileAttributes,
223 start_cluster: u64,
224 parent_dir_sector: u64,
225 parent_dir_index: u16,
226 ) -> Self {
227 assert!(attributes.directory());
228 Self {
229 base: BaseNode {
230 name,
231 attributes,
232 start_cluster,
233 parent_dir_sector,
234 parent_dir_index,
235 },
236 }
237 }
238}
239
240#[derive(Debug, Clone)]
242pub enum Node {
243 File(FileNode),
244 Directory(DirectoryNode),
245}
246
247impl From<FileNode> for Node {
248 fn from(file: FileNode) -> Self {
249 Self::File(file)
250 }
251}
252
253impl From<DirectoryNode> for Node {
254 fn from(dir: DirectoryNode) -> Self {
255 Self::Directory(dir)
256 }
257}
258
259impl Node {
260 pub fn new(
261 name: String,
262 attributes: FileAttributes,
263 start_cluster: u64,
264 size: u64,
265 parent_dir_sector: u64,
266 parent_dir_index: u16,
267 ) -> Self {
268 if attributes.directory() {
269 Self::Directory(DirectoryNode::new(
270 name,
271 attributes,
272 start_cluster,
273 parent_dir_sector,
274 parent_dir_index,
275 ))
276 } else {
277 Self::File(FileNode::new_file(
278 name,
279 attributes,
280 start_cluster,
281 size,
282 parent_dir_sector,
283 parent_dir_index,
284 ))
285 }
286 }
287
288 pub fn size(&self) -> u64 {
289 match self {
290 Self::File(file) => file.size,
291 Self::Directory(_) => 0,
292 }
293 }
294
295 pub fn name(&self) -> &str {
296 match self {
297 Self::File(file) => &file.name,
298 Self::Directory(dir) => &dir.name,
299 }
300 }
301
302 pub fn is_dir(&self) -> bool {
303 matches!(self, Self::Directory(_))
304 }
305
306 pub fn into_dir(self) -> Result<DirectoryNode, FileSystemError> {
307 match self {
308 Self::Directory(dir) => Ok(dir),
309 Self::File(_) => Err(FileSystemError::IsNotDirectory),
310 }
311 }
312
313 pub fn into_file(self) -> Result<FileNode, FileSystemError> {
314 match self {
315 Self::File(file) => Ok(file),
316 Self::Directory(_) => Err(FileSystemError::IsDirectory),
317 }
318 }
319
320 #[allow(dead_code)]
321 pub fn attributes(&self) -> FileAttributes {
322 match self {
323 Self::File(file) => file.attributes,
324 Self::Directory(dir) => dir.attributes,
325 }
326 }
327
328 pub fn as_file_stat(&self) -> FileStat {
329 FileStat {
330 size: self.size(),
331 file_type: match self {
332 Self::File(_) => FileType::File,
333 Self::Directory(_) => FileType::Directory,
334 },
335 }
336 }
337
338 pub fn try_open_device(&mut self) -> Result<(), FileSystemError> {
339 if let Self::File(file) = self {
340 file.try_open_device()?;
341 }
342
343 Ok(())
344 }
345}
346
347impl ops::Deref for FileNode {
348 type Target = BaseNode;
349
350 fn deref(&self) -> &Self::Target {
351 &self.base
352 }
353}
354
355impl ops::DerefMut for FileNode {
356 fn deref_mut(&mut self) -> &mut Self::Target {
357 &mut self.base
358 }
359}
360
361impl ops::Deref for DirectoryNode {
362 type Target = BaseNode;
363
364 fn deref(&self) -> &Self::Target {
365 &self.base
366 }
367}
368
369impl ops::DerefMut for DirectoryNode {
370 fn deref_mut(&mut self) -> &mut Self::Target {
371 &mut self.base
372 }
373}
374
375impl ops::Deref for Node {
376 type Target = BaseNode;
377
378 fn deref(&self) -> &Self::Target {
379 match self {
380 Self::File(file) => file,
381 Self::Directory(dir) => dir,
382 }
383 }
384}
385
386impl ops::DerefMut for Node {
387 fn deref_mut(&mut self) -> &mut Self::Target {
388 match self {
389 Self::File(file) => file,
390 Self::Directory(dir) => dir,
391 }
392 }
393}
394
395#[derive(Debug, Default)]
398pub struct AccessHelper {
399 current_cluster: u64,
400 cluster_index: u64,
401}
402
403pub enum DirTraverse {
404 Continue,
405 Stop,
406}
407
408pub trait FileSystem: Send + Sync {
411 fn open_root(&self) -> Result<DirectoryNode, FileSystemError>;
413
414 fn read_dir(
417 &self,
418 inode: &DirectoryNode,
419 handler: &mut dyn FnMut(Node) -> DirTraverse,
420 ) -> Result<(), FileSystemError>;
421
422 fn traverse_dir(&self, inode: &DirectoryNode, matcher: &str) -> Result<Node, FileSystemError> {
426 let mut entry = None;
427 self.read_dir(inode, &mut |inode| {
428 if inode.name() == matcher {
429 entry = Some(inode);
430 DirTraverse::Stop
431 } else {
432 DirTraverse::Continue
433 }
434 })?;
435 entry.ok_or(FileSystemError::FileNotFound)
436 }
437
438 fn create_node(
441 &self,
442 _parent: &DirectoryNode,
443 _name: &str,
444 _attributes: FileAttributes,
445 ) -> Result<Node, FileSystemError> {
446 Err(FileSystemError::OperationNotSupported)
447 }
448
449 fn read_file(
453 &self,
454 inode: &FileNode,
455 position: u64,
456 buf: &mut [u8],
457 _access_helper: &mut AccessHelper,
458 ) -> Result<u64, FileSystemError> {
459 if let Some(device) = &inode.device {
460 assert_eq!(inode.start_cluster, DEVICES_FILESYSTEM_CLUSTER_MAGIC);
461 device.read(position, buf)
462 } else {
463 Err(FileSystemError::ReadNotSupported)
464 }
465 }
466
467 fn write_file(
471 &self,
472 inode: &mut FileNode,
473 position: u64,
474 buf: &[u8],
475 _access_helper: &mut AccessHelper,
476 ) -> Result<u64, FileSystemError> {
477 if let Some(device) = &inode.device {
478 assert_eq!(inode.start_cluster, DEVICES_FILESYSTEM_CLUSTER_MAGIC);
479 device.write(position, buf)
480 } else {
481 Err(FileSystemError::WriteNotSupported)
482 }
483 }
484
485 fn flush_file(
488 &self,
489 _inode: &mut FileNode,
490 _access_helper: &mut AccessHelper,
491 ) -> Result<(), FileSystemError> {
492 Err(FileSystemError::WriteNotSupported)
493 }
494
495 fn close_file(
499 &self,
500 _inode: &FileNode,
501 _access_helper: AccessHelper,
502 ) -> Result<(), FileSystemError> {
503 Ok(())
504 }
505
506 fn set_file_size(&self, inode: &mut FileNode, size: u64) -> Result<(), FileSystemError> {
509 if let Some(device) = &inode.device {
510 assert_eq!(inode.start_cluster, DEVICES_FILESYSTEM_CLUSTER_MAGIC);
511 device.set_size(size)
512 } else {
513 Err(FileSystemError::WriteNotSupported)
514 }
515 }
516
517 fn unmount(self: Arc<Self>) {}
521}
522
523pub struct EmptyFileSystem;
524
525impl FileSystem for EmptyFileSystem {
526 fn open_root(&self) -> Result<DirectoryNode, FileSystemError> {
527 Err(FileSystemError::FileNotFound)
528 }
529
530 fn read_dir(
531 &self,
532 _inode: &DirectoryNode,
533 _handler: &mut dyn FnMut(Node) -> DirTraverse,
534 ) -> Result<(), FileSystemError> {
535 Err(FileSystemError::FileNotFound)
536 }
537}
538
539#[derive(Debug)]
540pub enum FileSystemError {
541 PartitionTableNotFound,
542 DeviceNotFound,
543 DiskReadError { sector: u64, error: ide::IdeError },
544 FatError(fat::FatError),
545 FileNotFound,
546 InvalidPath,
547 MustBeAbsolute,
548 IsNotDirectory,
549 IsDirectory,
550 ReadNotSupported,
551 WriteNotSupported,
552 OperationNotSupported,
553 CouldNotSetFileLength,
554 EndOfFile,
555 BufferNotLargeEnough(usize),
556 AlreadyExists,
557 MappingError(MappingError),
558}
559
560pub fn create_disk_mapping(hard_disk_index: usize) -> Result<(), FileSystemError> {
566 let ide_index = IdeDeviceIndex {
567 ty: IdeDeviceType::Ata,
568 index: hard_disk_index,
569 };
570
571 let device = ide::get_ide_device(ide_index).ok_or(FileSystemError::DeviceNotFound)?;
572
573 let mbr = Mbr::try_create_from_disk(&device)?;
574
575 let first_partition = &mbr.partition_table[0];
577 let filesystem = fat::load_fat_filesystem(
578 device,
579 first_partition.start_lba,
580 first_partition.size_in_sectors,
581 )?;
582 info!(
583 "Mapping / to FAT filesystem {:?} ({:?}), partition_type: 0x{:02X}",
584 filesystem.volume_label(),
585 filesystem.fat_type(),
586 first_partition.partition_type
587 );
588 mapping::mount("/", Arc::new(Mutex::new(filesystem)))?;
589
590 Ok(())
591}
592
593pub fn unmount_all() {
594 mapping::unmount_all();
596}
597
598pub(crate) fn open_inode<P: AsRef<Path>>(
602 path: P,
603) -> Result<(PathBuf, Arc<dyn FileSystem>, Node), FileSystemError> {
604 if !path.as_ref().is_absolute() {
605 return Err(FileSystemError::MustBeAbsolute);
607 }
608
609 let (mut canonical_path, remaining, mut mapping_node) = mapping::get_mapping(path.as_ref())?;
610 let mut filesystem = mapping_node.filesystem();
611
612 let opening_dir = path.as_ref().has_last_separator();
613 let mut remaining_components = remaining.components().peekable();
614
615 let mut dir = filesystem.open_root()?;
616 if remaining.is_root() || remaining.is_empty() {
617 return Ok((canonical_path, filesystem, dir.into()));
618 }
619
620 let mut children_after_mapping = 0;
622 while let Some(component) = remaining_components.next() {
623 let name = match component {
624 Component::RootDir | Component::CurDir => continue,
625 Component::Normal("") => continue,
626 Component::ParentDir => {
627 if children_after_mapping == 0 {
628 let parent = mapping_node.parent();
631 if let Some(parent) = parent {
632 mapping_node = parent.clone();
633 assert!(canonical_path.pop(), "must have parent");
634 filesystem = mapping_node.filesystem();
635 dir = filesystem.open_root()?;
636 }
637 } else {
638 children_after_mapping -= 1;
639 assert!(canonical_path.pop(), "must have parent");
640 }
641 continue;
642 }
643 Component::Normal(name) => name,
644 };
645 if children_after_mapping == 0 {
647 if let Some(child_mapping) = mapping_node.try_find_child(name) {
648 mapping_node = child_mapping;
649 canonical_path.push(name);
650 filesystem = mapping_node.filesystem();
651 children_after_mapping = 0;
652 dir = filesystem.open_root()?;
653 continue;
654 }
655 }
656
657 children_after_mapping += 1;
658 canonical_path.push(name);
659
660 let mut entry = filesystem.traverse_dir(&dir, name)?;
661
662 if remaining_components.peek().is_some() {
663 if let Node::Directory(dir_node) = entry {
664 dir = dir_node;
665 } else {
666 return Err(FileSystemError::IsNotDirectory);
667 }
668 } else {
669 return if opening_dir {
670 if entry.is_dir() {
671 Ok((canonical_path, filesystem, entry))
672 } else {
673 Err(FileSystemError::IsNotDirectory)
674 }
675 } else {
676 entry.try_open_device()?;
678 Ok((canonical_path, filesystem, entry))
679 };
680 }
681 }
682
683 Ok((canonical_path, filesystem, dir.into()))
686}
687
688#[derive(Debug, Clone, Copy, PartialEq, Eq)]
689pub struct FileAccess {
690 read: bool,
691 write: bool,
692}
693
694impl FileAccess {
695 pub const READ: Self = Self {
696 read: true,
697 write: false,
698 };
699 pub const WRITE: Self = Self {
700 read: false,
701 write: true,
702 };
703
704 fn new(read: bool, write: bool) -> Self {
705 Self { read, write }
706 }
707
708 fn is_read(&self) -> bool {
709 self.read
710 }
711
712 fn is_write(&self) -> bool {
713 self.write
714 }
715}
716
717impl ops::BitOr for FileAccess {
718 type Output = Self;
719
720 fn bitor(self, rhs: Self) -> Self::Output {
721 Self {
722 read: self.read || rhs.read,
723 write: self.write || rhs.write,
724 }
725 }
726}
727
728pub struct File {
730 filesystem: Arc<dyn FileSystem>,
731 path: Box<Path>,
732 inode: FileNode,
733 position: u64,
734 is_terminal: bool,
735 blocking_mode: BlockingMode,
736 access_helper: AccessHelper,
737 file_access: FileAccess,
738}
739
740#[allow(dead_code)]
742pub struct Directory {
743 inode: DirectoryNode,
744 path: Box<Path>,
745 position: u64,
746 dir_entries: Option<Vec<Node>>,
747 filesystem: Arc<dyn FileSystem>,
748}
749
750#[allow(dead_code)]
752#[repr(u8)]
753pub enum FilesystemNode {
754 File(File),
755 Directory(Directory),
756}
757
758#[allow(dead_code)]
759impl File {
760 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, FileSystemError> {
761 Self::open_blocking(path, BlockingMode::None, OpenOptions::default())
762 }
763
764 pub fn open_blocking<P: AsRef<Path>>(
765 path: P,
766 blocking_mode: BlockingMode,
767 open_options: OpenOptions,
768 ) -> Result<Self, FileSystemError> {
769 let (canonical_path, mut node, filesystem) = match open_inode(path.as_ref()) {
770 Ok((canonical_path, filesystem, inode)) => {
771 if open_options.is_create_new() {
772 return Err(FileSystemError::AlreadyExists);
773 }
774
775 (canonical_path, inode.into_file()?, filesystem)
776 }
777 Err(FileSystemError::FileNotFound)
778 if open_options.is_create() || open_options.is_create_new() =>
779 {
780 let path = path.as_ref();
781 let (canonical_path, filesystem, parent_inode) =
782 open_inode(path.parent().unwrap())?;
783 let filename = path.file_name().unwrap();
784 if filename == "." || filename == ".." || filename == "/" {
785 return Err(FileSystemError::InvalidPath);
786 }
787 let node = filesystem.create_node(
788 &parent_inode.into_dir()?,
789 filename,
790 FileAttributes::EMPTY,
791 )?;
792 (
793 canonical_path,
794 node.into_file()
795 .expect("This should be a valid file, we created it"),
796 filesystem,
797 )
798 }
799 Err(e) => return Err(e),
800 };
801
802 if open_options.is_truncate() {
803 if open_options.is_write() {
804 filesystem.set_file_size(&mut node, 0)?;
805 } else {
806 return Err(FileSystemError::WriteNotSupported);
807 }
808 }
809
810 let pos = if open_options.is_append() {
811 node.size()
812 } else {
813 0
814 };
815
816 let access = FileAccess::new(open_options.is_read(), open_options.is_write());
817
818 Self::from_inode(node, canonical_path, filesystem, pos, blocking_mode, access)
819 }
820
821 pub fn from_inode<P: AsRef<Path>>(
822 inode: FileNode,
823 path: P,
824 filesystem: Arc<dyn FileSystem>,
825 position: u64,
826 blocking_mode: BlockingMode,
827 file_access: FileAccess,
828 ) -> Result<Self, FileSystemError> {
829 Ok(Self {
830 filesystem,
831 path: path.as_ref().into(),
832 inode,
833 position,
834 is_terminal: false,
835 blocking_mode,
836 access_helper: AccessHelper::default(),
837 file_access,
838 })
839 }
840
841 pub fn read(&mut self, buf: &mut [u8]) -> Result<u64, FileSystemError> {
842 if !self.file_access.is_read() {
843 return Err(FileSystemError::ReadNotSupported);
844 }
845
846 let count = match self.blocking_mode {
847 BlockingMode::None => self.filesystem.read_file(
848 &self.inode,
849 self.position,
850 buf,
851 &mut self.access_helper,
852 )?,
853 BlockingMode::Line => {
854 let mut i = 0;
856 loop {
857 let mut char_buf = 0;
858 let read_byte = self.filesystem.read_file(
859 &self.inode,
860 self.position,
861 core::slice::from_mut(&mut char_buf),
862 &mut self.access_helper,
863 );
864
865 let read_byte = match read_byte {
866 Ok(read_byte) => read_byte,
867 Err(FileSystemError::EndOfFile) => {
868 return Ok(i as u64);
870 }
871 Err(e) => return Err(e),
872 };
873
874 if read_byte == 1 {
876 if i < buf.len() {
877 buf[i] = char_buf;
878 i += 1;
879 }
880 if char_buf == b'\n' || char_buf == b'\0' {
881 break;
882 }
883 } else {
884 for _ in 0..100 {
886 core::hint::spin_loop();
887 }
888 }
889 }
890 i as u64
891 }
892 BlockingMode::Block(size) => {
893 assert_eq!(size, 1, "Only block size 1 is supported");
895
896 loop {
898 let read_byte = self.filesystem.read_file(
899 &self.inode,
900 self.position,
901 buf,
902 &mut self.access_helper,
903 );
904
905 let read_byte = match read_byte {
906 Ok(read_byte) => read_byte,
907 Err(FileSystemError::EndOfFile) => {
908 break 0;
910 }
911 Err(e) => return Err(e),
912 };
913
914 if read_byte != 0 {
916 break read_byte;
917 }
918 for _ in 0..100 {
921 core::hint::spin_loop();
922 }
923 }
924 }
925 };
926
927 self.position += count;
928 Ok(count)
929 }
930
931 pub fn write(&mut self, buf: &[u8]) -> Result<u64, FileSystemError> {
932 if !self.file_access.is_write() {
933 return Err(FileSystemError::WriteNotSupported);
934 }
935
936 let written = self.filesystem.write_file(
937 &mut self.inode,
938 self.position,
939 buf,
940 &mut self.access_helper,
941 )?;
942 self.position += written;
943 Ok(written)
944 }
945
946 pub fn flush(&mut self) -> Result<(), FileSystemError> {
947 if !self.file_access.is_write() {
948 return Err(FileSystemError::WriteNotSupported);
949 }
950
951 self.filesystem
952 .flush_file(&mut self.inode, &mut self.access_helper)
953 }
954
955 pub fn seek(&mut self, position: u64) -> Result<(), FileSystemError> {
956 self.position = position;
957 Ok(())
958 }
959
960 pub fn filesize(&self) -> u64 {
961 self.inode.size()
962 }
963
964 pub fn path(&self) -> &Path {
965 &self.path
966 }
967
968 pub fn read_to_end(&mut self) -> Result<Vec<u8>, FileSystemError> {
969 let mut buf = vec![0; self.inode.size() as usize];
970 let mut position = 0;
971 loop {
972 let read = self.read(&mut buf[position..])?;
973 if read == 0 {
974 break;
975 }
976 position += read as usize;
977 }
978 Ok(buf)
979 }
980
981 pub fn is_blocking(&self) -> bool {
982 self.blocking_mode != BlockingMode::None
983 }
984
985 pub fn blocking_mode(&self) -> BlockingMode {
986 self.blocking_mode
987 }
988
989 pub fn set_blocking(&mut self, blocking_mode: BlockingMode) {
990 self.blocking_mode = blocking_mode;
991 }
992
993 pub fn is_terminal(&self) -> bool {
994 self.is_terminal
995 }
996
997 pub fn set_terminal(&mut self, is_terminal: bool) {
998 self.is_terminal = is_terminal;
999 }
1000
1001 pub fn size(&self) -> u64 {
1002 self.inode.size()
1003 }
1004
1005 pub fn current_position(&self) -> u64 {
1006 self.position
1007 }
1008
1009 pub fn set_size(&mut self, size: u64) -> Result<(), FileSystemError> {
1010 if !self.file_access.is_write() {
1011 return Err(FileSystemError::WriteNotSupported);
1012 }
1013
1014 self.filesystem.set_file_size(&mut self.inode, size)
1015 }
1016
1017 pub fn clone_inherit(&self) -> Self {
1020 let s = Self {
1021 filesystem: self.filesystem.clone(),
1022 path: self.path.clone(),
1023 inode: self.inode.clone(),
1024 position: 0,
1025 is_terminal: self.is_terminal,
1026 blocking_mode: self.blocking_mode,
1027 access_helper: AccessHelper::default(),
1028 file_access: self.file_access,
1029 };
1030
1031 if let Some(device) = s.inode.device.as_ref() {
1033 device
1034 .clone_device()
1035 .expect("Failed to clone device for file")
1037 }
1038
1039 s
1040 }
1041}
1042
1043impl Drop for File {
1044 fn drop(&mut self) {
1045 self.filesystem
1046 .close_file(&self.inode, core::mem::take(&mut self.access_helper))
1047 .expect("Failed to close file");
1048 }
1049}
1050
1051#[allow(dead_code)]
1052impl Directory {
1053 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, FileSystemError> {
1054 let (canonical_path, filesystem, inode) = open_inode(path.as_ref())?;
1055
1056 Self::from_inode(inode.into_dir()?, canonical_path, filesystem, 0)
1057 }
1058
1059 pub fn from_inode<P: AsRef<Path>>(
1060 inode: DirectoryNode,
1061 path: P,
1062 filesystem: Arc<dyn FileSystem>,
1063 position: u64,
1064 ) -> Result<Self, FileSystemError> {
1065 Ok(Self {
1066 path: path.as_ref().into(),
1067 inode,
1068 position,
1069 dir_entries: None,
1070 filesystem,
1071 })
1072 }
1073
1074 fn fetch_entries(&mut self) -> Result<(), FileSystemError> {
1075 if self.dir_entries.is_none() {
1076 let mut dir_entries = Vec::new();
1077 self.filesystem.read_dir(&self.inode, &mut |entry| {
1078 dir_entries.push(entry);
1079 DirTraverse::Continue
1080 })?;
1081 mapping::on_all_matching_mappings(&self.path, |path, _fs| {
1083 if path.components().count() == 1 {
1085 dir_entries.push(
1086 DirectoryNode::without_parent(
1087 path.components().next().unwrap().as_str().into(),
1088 FileAttributes::DIRECTORY,
1089 ANOTHER_FILESYSTEM_MAPPING_INODE_MAGIC,
1090 )
1091 .into(),
1092 );
1093 }
1094 })?;
1095
1096 self.dir_entries = Some(dir_entries);
1097 }
1098
1099 Ok(())
1100 }
1101
1102 pub fn path(&self) -> &Path {
1103 &self.path
1104 }
1105
1106 pub fn create_node(
1107 &mut self,
1108 name: &str,
1109 attributes: FileAttributes,
1110 ) -> Result<FilesystemNode, FileSystemError> {
1111 let node = self.filesystem.create_node(&self.inode, name, attributes)?;
1112
1113 let path = self.path.join(name);
1114
1115 match node {
1116 Node::File(file) => Ok(File::from_inode(
1117 file,
1118 path,
1119 self.filesystem.clone(),
1120 0,
1121 BlockingMode::None,
1122 FileAccess::READ | FileAccess::WRITE,
1124 )?
1125 .into()),
1126 Node::Directory(directory) => {
1127 Ok(Directory::from_inode(directory, path, self.filesystem.clone(), 0)?.into())
1128 }
1129 }
1130 }
1131
1132 pub fn read(&mut self, entries: &mut [DirEntry]) -> Result<usize, FileSystemError> {
1133 self.fetch_entries()?;
1134
1135 let dir_entries = self
1136 .dir_entries
1137 .as_ref()
1138 .expect("Entries must be initialized");
1139
1140 let mut i = 0;
1141 while i < entries.len() {
1142 if self.position >= dir_entries.len() as u64 {
1143 break;
1144 }
1145
1146 let entry = &dir_entries[self.position as usize];
1147 entries[i] = DirEntry {
1148 stat: entry.as_file_stat(),
1149 name: entry.name().into(),
1150 };
1151 i += 1;
1152 self.position += 1;
1153 }
1154
1155 Ok(i)
1156 }
1157}
1158
1159impl Clone for Directory {
1160 fn clone(&self) -> Self {
1161 Self {
1162 inode: self.inode.clone(),
1163 path: self.path.clone(),
1164 position: 0,
1165 dir_entries: None, filesystem: self.filesystem.clone(),
1167 }
1168 }
1169}
1170
1171#[allow(dead_code)]
1172impl FilesystemNode {
1173 pub fn as_file(&self) -> Result<&File, FileSystemError> {
1174 match self {
1175 Self::File(file) => Ok(file),
1176 Self::Directory(_) => Err(FileSystemError::IsDirectory),
1177 }
1178 }
1179
1180 pub fn as_file_mut(&mut self) -> Result<&mut File, FileSystemError> {
1181 match self {
1182 Self::File(file) => Ok(file),
1183 Self::Directory(_) => Err(FileSystemError::IsDirectory),
1184 }
1185 }
1186
1187 pub fn as_dir_mut(&mut self) -> Result<&mut Directory, FileSystemError> {
1188 match self {
1189 Self::File(_) => Err(FileSystemError::IsNotDirectory),
1190 Self::Directory(dir) => Ok(dir),
1191 }
1192 }
1193}
1194
1195impl From<File> for FilesystemNode {
1196 fn from(file: File) -> Self {
1197 Self::File(file)
1198 }
1199}
1200
1201impl From<Directory> for FilesystemNode {
1202 fn from(dir: Directory) -> Self {
1203 Self::Directory(dir)
1204 }
1205}