1use alloc::{
8 boxed::Box, collections::BTreeMap, format, string::{String, ToString}, sync::{Arc, Weak}, vec, vec::Vec
9};
10use spin::{rwlock::RwLock, Mutex};
11use core::{any::Any, fmt::Debug};
12
13use crate::{device::{Device, DeviceType}, driver_initcall, fs::{
14 get_fs_driver_manager, DeviceFileInfo, FileMetadata, FileObject, FilePermission, FileSystemDriver, FileSystemError, FileSystemErrorKind, FileType
15}};
16use crate::object::capability::{StreamOps, StreamError};
17use crate::device::manager::DeviceManager;
18
19use super::super::core::{VfsNode, FileSystemOperations, DirectoryEntryInternal};
20
21pub struct TmpFS {
28 root: RwLock<Arc<TmpNode>>,
30 memory_limit: usize,
32 current_memory: Mutex<usize>,
34 next_file_id: Mutex<u64>,
36 name: String,
38}
39
40impl TmpFS {
41 pub fn new(memory_limit: usize) -> Arc<Self> {
43 let root = Arc::new(TmpNode::new_directory("/".to_string(), 1));
44 let fs = Arc::new(Self {
45 root: RwLock::new(Arc::clone(&root)),
46 memory_limit,
47 current_memory: Mutex::new(0),
48 next_file_id: Mutex::new(2), name: "tmpfs_v2".to_string(),
50 });
51 let fs_weak = Arc::downgrade(&(fs.clone() as Arc<dyn FileSystemOperations>));
52 root.set_filesystem(fs_weak);
53 debug_assert!(root.filesystem().is_some(), "TmpFS root node's filesystem() is None after set_filesystem");
54 fs
55 }
56
57 pub fn create_from_option_string(option: Option<&str>) -> Arc<dyn FileSystemOperations> {
60 let mut memory_limit = 0;
61 if let Some(opt) = option {
62 for part in opt.split(',') {
63 let part = part.trim();
64 if let Some(mem_str) = part.strip_prefix("mem=") {
65 if let Ok(val) = mem_str.parse::<usize>() {
66 memory_limit = val;
67 }
68 }
69 }
70 }
71 TmpFS::new(memory_limit) as Arc<dyn FileSystemOperations>
72 }
73
74 fn generate_file_id(&self) -> u64 {
76 let mut next_id = self.next_file_id.lock();
77 let id = *next_id;
78 *next_id += 1;
79 id
80 }
81
82 fn check_memory_limit(&self, additional_bytes: usize) -> Result<(), FileSystemError> {
84 if self.memory_limit == 0 {
85 return Ok(()); }
87
88 let current = *self.current_memory.lock();
89 if current + additional_bytes > self.memory_limit {
90 return Err(FileSystemError::new(
91 FileSystemErrorKind::NoSpace,
92 "TmpFS memory limit exceeded"
93 ));
94 }
95
96 Ok(())
97 }
98
99 fn add_memory_usage(&self, bytes: usize) {
101 if self.memory_limit > 0 {
102 *self.current_memory.lock() += bytes;
103 }
104 }
105
106 fn subtract_memory_usage(&self, bytes: usize) {
108 if self.memory_limit > 0 {
109 let mut current = self.current_memory.lock();
110 *current = current.saturating_sub(bytes);
111 }
112 }
113}
114
115impl FileSystemOperations for TmpFS {
116 fn lookup(
117 &self,
118 parent_node: &Arc<dyn VfsNode>,
119 name: &String,
120 ) -> Result<Arc<dyn VfsNode>, FileSystemError> {
121 let tmp_node = parent_node.as_any()
123 .downcast_ref::<TmpNode>()
124 .ok_or_else(|| FileSystemError::new(
125 FileSystemErrorKind::NotSupported,
126 "Invalid node type for TmpFS"
127 ))?;
128
129 if tmp_node.file_type() != FileType::Directory {
131 return Err(FileSystemError::new(
132 FileSystemErrorKind::NotADirectory,
133 "Parent is not a directory"
134 ));
135 }
136
137 match name.as_str() {
139 "." => {
140 return Ok(Arc::clone(&parent_node));
142 }
143 ".." => {
144 if let Some(parent_weak) = &tmp_node.parent() {
146 if let Some(parent) = parent_weak.upgrade() {
147 return Ok(parent as Arc<dyn VfsNode>);
150 }
151 }
152 }
153 _ => {
154 }
156 }
157
158 let children = tmp_node.children.read();
160 if let Some(child_node) = children.get(name) {
161 Ok(Arc::clone(child_node) as Arc<dyn VfsNode>)
162 } else {
163 Err(FileSystemError::new(
164 FileSystemErrorKind::NotFound,
165 "File not found"
166 ))
167 }
168 }
169
170 fn open(
171 &self,
172 node: &Arc<dyn VfsNode>,
173 _flags: u32,
174 ) -> Result<Arc<dyn FileObject>, FileSystemError> {
175 let tmp_node = Arc::downcast::<TmpNode>(node.clone())
176 .map_err(|_| FileSystemError::new(
177 FileSystemErrorKind::NotSupported,
178 "Invalid node type for TmpFS"
179 ))?;
180
181 let file_object = match tmp_node.file_type() {
182 FileType::RegularFile => TmpFileObject::new_regular(tmp_node),
183 FileType::Directory => TmpFileObject::new_directory(tmp_node),
184 FileType::CharDevice(info) | FileType::BlockDevice(info) => {
185 TmpFileObject::new_device(tmp_node, info)
186 }
187 _ => {
188 return Err(FileSystemError::new(
189 FileSystemErrorKind::NotSupported,
190 "Unsupported file type for open"
191 ));
192 }
193 };
194
195 Ok(Arc::new(file_object))
196 }
197
198 fn create(&self,
199 parent_node: &Arc<dyn VfsNode>,
200 name: &String,
201 file_type: FileType,
202 _mode: u32,
203 ) -> Result<Arc<dyn VfsNode>, FileSystemError> {
204 let tmp_parent = Arc::downcast::<TmpNode>(parent_node.clone())
205 .map_err(|_| FileSystemError::new(
206 FileSystemErrorKind::NotSupported,
207 "Invalid node type for TmpFS"
208 ))?;
209
210 if tmp_parent.file_type() != FileType::Directory {
212 return Err(FileSystemError::new(
213 FileSystemErrorKind::NotADirectory,
214 "Parent is not a directory"
215 ));
216 }
217 {
219 let children = tmp_parent.children.read();
220 if children.contains_key(name) {
221 return Err(FileSystemError::new(
222 FileSystemErrorKind::AlreadyExists,
223 "File already exists"
224 ));
225 }
226 }
227 let file_id = self.generate_file_id();
229 let new_node = match file_type {
230 FileType::RegularFile => {
231 Arc::new(TmpNode::new_file(name.clone().to_string(), file_id))
232 }
233 FileType::Directory => {
234 Arc::new(TmpNode::new_directory(name.clone().to_string(), file_id))
235 }
236 FileType::SymbolicLink(target_path) => {
237 self.add_memory_usage(target_path.len());
239 Arc::new(TmpNode::new_symlink(name.clone().to_string(), target_path, file_id))
240 }
241 FileType::CharDevice(_) | FileType::BlockDevice(_) => {
242 Arc::new(TmpNode::new_device(name.clone().to_string(), file_type, file_id))
243 }
244 _ => {
245 return Err(FileSystemError::new(
246 FileSystemErrorKind::NotSupported,
247 "Unsupported file type for creation"
248 ));
249 }
250 };
251 let fs_ref = parent_node.filesystem()
253 .ok_or_else(|| FileSystemError::new(
254 FileSystemErrorKind::NotSupported,
255 "Parent node does not have a filesystem reference"
256 ))?;
257 if fs_ref.upgrade().is_none() {
258 return Err(FileSystemError::new(
259 FileSystemErrorKind::NotSupported,
260 "Parent node's filesystem reference is dead (cannot upgrade)"
261 ));
262 }
263 if let Some(tmp_node) = new_node.as_any().downcast_ref::<TmpNode>() {
264 tmp_node.set_filesystem(fs_ref);
265 }
266 {
268 let mut children = tmp_parent.children.write();
269 new_node.set_parent(Arc::downgrade(&tmp_parent));
270 children.insert(name.clone(), Arc::clone(&new_node) as Arc<dyn VfsNode>);
271 }
272
273 Ok(new_node)
274 }
275
276 fn create_hardlink(
283 &self,
284 link_parent: &Arc<dyn VfsNode>,
285 link_name: &String,
286 target_node: &Arc<dyn VfsNode>,
287 ) -> Result<Arc<dyn VfsNode>, FileSystemError> {
288 let tmp_parent = link_parent.as_any()
290 .downcast_ref::<TmpNode>()
291 .ok_or_else(|| FileSystemError::new(
292 FileSystemErrorKind::NotSupported,
293 "Invalid parent node type for TmpFS"
294 ))?;
295
296 let tmp_target = target_node.as_any()
297 .downcast_ref::<TmpNode>()
298 .ok_or_else(|| FileSystemError::new(
299 FileSystemErrorKind::NotSupported,
300 "Invalid target node type for TmpFS"
301 ))?;
302
303 if tmp_parent.file_type() != FileType::Directory {
305 return Err(FileSystemError::new(
306 FileSystemErrorKind::NotADirectory,
307 "Parent is not a directory"
308 ));
309 }
310
311 if tmp_target.file_type() != FileType::RegularFile {
313 return Err(FileSystemError::new(
314 FileSystemErrorKind::InvalidOperation,
315 "Cannot create hard link to non-regular file"
316 ));
317 }
318
319 {
321 let children = tmp_parent.children.read();
322 if children.contains_key(link_name) {
323 return Err(FileSystemError::new(
324 FileSystemErrorKind::FileExists,
325 "Link name already exists"
326 ));
327 }
328 }
329
330 {
333 let mut metadata = tmp_target.metadata.write();
334 metadata.link_count += 1;
335 }
336
337 {
339 let mut children = tmp_parent.children.write();
340 children.insert(link_name.clone(), Arc::clone(target_node));
341 }
342
343 Ok(Arc::clone(target_node))
345 }
346
347
348 fn remove(
349 &self,
350 parent_node: &Arc<dyn VfsNode>,
351 name: &String,
352 ) -> Result<(), FileSystemError> {
353 let tmp_parent = parent_node.as_any()
354 .downcast_ref::<TmpNode>()
355 .ok_or_else(|| FileSystemError::new(
356 FileSystemErrorKind::NotSupported,
357 "Invalid node type for TmpFS"
358 ))?;
359
360 if tmp_parent.file_type() != FileType::Directory {
362 return Err(FileSystemError::new(
363 FileSystemErrorKind::NotADirectory,
364 "Parent is not a directory"
365 ));
366 }
367
368 let mut children = tmp_parent.children.write();
370 if let Some(removed_node) = children.get(name) {
371 if let Some(tmp_node) = removed_node.as_any().downcast_ref::<TmpNode>() {
373 if tmp_node.file_type() == FileType::Directory {
374 let child_children = tmp_node.children.read();
375 if !child_children.is_empty() {
376 return Err(FileSystemError::new(
377 FileSystemErrorKind::DirectoryNotEmpty,
378 "Directory not empty"
379 ));
380 }
381 }
382
383 match tmp_node.file_type() {
385 FileType::RegularFile | FileType::SymbolicLink(_) => {
386 let content = tmp_node.content.read();
387 self.subtract_memory_usage(content.len());
388 },
389 _ => {}
390 }
391 }
392 }
393
394 children.remove(name)
396 .ok_or_else(|| FileSystemError::new(
397 FileSystemErrorKind::NotFound,
398 "File not found"
399 ))?;
400
401 Ok(())
402 }
403
404 fn readdir(
405 &self,
406 node: &Arc<dyn VfsNode>,
407 ) -> Result<Vec<DirectoryEntryInternal>, FileSystemError> {
408 let tmp_node = node.as_any()
409 .downcast_ref::<TmpNode>()
410 .ok_or_else(|| FileSystemError::new(
411 FileSystemErrorKind::NotSupported,
412 "Invalid node type for TmpFS"
413 ))?;
414
415 if tmp_node.file_type() != FileType::Directory {
417 return Err(FileSystemError::new(
418 FileSystemErrorKind::NotADirectory,
419 "Not a directory"
420 ));
421 }
422
423 let mut entries = Vec::new();
424 let children = tmp_node.children.read();
425
426 for (name, child_node) in children.iter() {
427 if let Some(child_tmp_node) = child_node.as_any().downcast_ref::<TmpNode>() {
428 let metadata = child_tmp_node.metadata.read();
429 entries.push(DirectoryEntryInternal {
430 name: name.clone(),
431 file_type: child_tmp_node.file_type.read().clone(),
432 file_id: metadata.file_id,
433 });
434 }
435 }
436
437 Ok(entries)
438 }
439
440 fn root_node(&self) -> Arc<dyn VfsNode> {
441 Arc::clone(&*self.root.read()) as Arc<dyn VfsNode>
442 }
443
444 fn name(&self) -> &str {
445 &self.name
446 }
447}
448
449pub struct TmpNode {
454 name: RwLock<String>,
456 file_type: RwLock<FileType>,
458 metadata: RwLock<FileMetadata>,
460 content: RwLock<Vec<u8>>,
462 children: RwLock<BTreeMap<String, Arc<dyn VfsNode>>>,
464 parent: RwLock<Option<Weak<TmpNode>>>,
466 filesystem: RwLock<Option<Weak<dyn FileSystemOperations>>>,
468}
469
470impl Debug for TmpNode {
471 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
472 f.debug_struct("TmpNode")
473 .field("name", &self.name.read())
474 .field("file_type", &self.file_type.read())
475 .field("metadata", &self.metadata.read())
476 .field("parent", &self.parent.read().as_ref().map(|p| p.strong_count()))
477 .finish()
478 }
479}
480
481impl TmpNode {
482 pub fn new_file(name: String, file_id: u64) -> Self {
484 Self {
485 name: RwLock::new(name),
486 file_type: RwLock::new(FileType::RegularFile),
487 metadata: RwLock::new(FileMetadata {
488 file_type: FileType::RegularFile,
489 size: 0,
490 permissions: FilePermission {
491 read: true,
492 write: true,
493 execute: false,
494 },
495 created_time: 0, modified_time: 0,
497 accessed_time: 0,
498 file_id,
499 link_count: 1,
500 }),
501 content: RwLock::new(Vec::new()),
502 children: RwLock::new(BTreeMap::new()),
503 parent: RwLock::new(None), filesystem: RwLock::new(None),
505 }
506 }
507
508 pub fn new_directory(name: String, file_id: u64) -> Self {
510 Self {
511 name: RwLock::new(name),
512 file_type: RwLock::new(FileType::Directory),
513 metadata: RwLock::new(FileMetadata {
514 file_type: FileType::Directory,
515 size: 0,
516 permissions: FilePermission {
517 read: true,
518 write: true,
519 execute: true,
520 },
521 created_time: 0,
522 modified_time: 0,
523 accessed_time: 0,
524 file_id,
525 link_count: 1,
526 }),
527 content: RwLock::new(Vec::new()),
528 children: RwLock::new(BTreeMap::new()),
529 parent: RwLock::new(None), filesystem: RwLock::new(None),
531 }
532 }
533
534 pub fn new_device(name: String, file_type: FileType, file_id: u64) -> Self {
536 Self {
537 name: RwLock::new(name),
538 file_type: RwLock::new(file_type.clone()),
539 metadata: RwLock::new(FileMetadata {
540 file_type,
541 size: 0,
542 permissions: FilePermission {
543 read: true,
544 write: true,
545 execute: false,
546 },
547 created_time: 0,
548 modified_time: 0,
549 accessed_time: 0,
550 file_id,
551 link_count: 1,
552 }),
553 content: RwLock::new(Vec::new()),
554 children: RwLock::new(BTreeMap::new()),
555 parent: RwLock::new(None), filesystem: RwLock::new(None),
557 }
558 }
559
560 pub fn new_symlink(name: String, target: String, file_id: u64) -> Self {
562 Self {
563 name: RwLock::new(name),
564 file_type: RwLock::new(FileType::SymbolicLink(target.clone())),
565 metadata: RwLock::new(FileMetadata {
566 file_type: FileType::SymbolicLink(target.clone()),
567 size: target.len(),
568 permissions: FilePermission {
569 read: true,
570 write: true,
571 execute: false,
572 },
573 created_time: 0, modified_time: 0,
575 accessed_time: 0,
576 file_id,
577 link_count: 1,
578 }),
579 content: RwLock::new(target.into_bytes()),
581 children: RwLock::new(BTreeMap::new()),
582 parent: RwLock::new(None), filesystem: RwLock::new(None),
584 }
585 }
586
587 pub fn set_filesystem(&self, fs: Weak<dyn FileSystemOperations>) {
589 *self.filesystem.write() = Some(fs);
590 }
591
592 pub fn update_size(&self, new_size: u64) {
594 let mut metadata = self.metadata.write();
595 metadata.size = new_size as usize;
596 metadata.modified_time = 0; }
598
599 pub fn set_parent(&self, parent: Weak<TmpNode>) {
601 self.parent.write().replace(parent);
602 }
603
604 pub fn is_filesystem_root(&self) -> bool {
606 self.parent.read().is_none()
607 }
608
609 pub fn name(&self) -> String {
611 self.name.read().clone()
612 }
613
614 pub fn file_type(&self) -> FileType {
616 self.file_type.read().clone()
617 }
618
619 pub fn filesystem(&self) -> Option<Weak<dyn FileSystemOperations>> {
621 self.filesystem.read().clone()
622 }
623
624 pub fn parent(&self) -> Option<Weak<TmpNode>> {
626 self.parent.read().clone()
627 }
628}
629
630impl VfsNode for TmpNode {
631 fn id(&self) -> u64 {
632 self.metadata.read().file_id
633 }
634
635 fn filesystem(&self) -> Option<Weak<dyn FileSystemOperations>> {
636 self.filesystem.read().clone()
637 }
638
639 fn metadata(&self) -> Result<FileMetadata, FileSystemError> {
640 Ok(self.metadata.read().clone())
641 }
642
643 fn as_any(&self) -> &dyn Any {
644 self
645 }
646
647 fn read_link(&self) -> Result<String, FileSystemError> {
648 match &self.file_type() {
650 FileType::SymbolicLink(target) => Ok(target.clone()),
651 _ => Err(FileSystemError::new(
652 FileSystemErrorKind::NotSupported,
653 "Not a symbolic link"
654 ))
655 }
656 }
657}
658
659pub struct TmpFileObject {
665 node: Arc<TmpNode>,
667
668 position: RwLock<u64>,
670
671 device_guard: Option<Arc<dyn Device>>,
673}
674
675impl TmpFileObject {
676 pub fn new_regular(node: Arc<TmpNode>) -> Self {
678 Self {
679 node,
680 position: RwLock::new(0),
681 device_guard: None,
682 }
683 }
684
685 pub fn new_directory(node: Arc<TmpNode>) -> Self {
687 Self {
688 node,
689 position: RwLock::new(0),
690 device_guard: None,
691 }
692 }
693
694 pub fn new_device(node: Arc<TmpNode>, info: DeviceFileInfo) -> Self {
696 match DeviceManager::get_manager().get_device(info.device_id) {
698 Some(device_guard) => {
699 Self {
700 node,
701 position: RwLock::new(0),
702 device_guard: Some(device_guard),
703 }
704 },
705 None => {
706 panic!("Failed to borrow device {}", info.device_id);
708 }
709 }
710 }
711
712 fn read_device(&self, buffer: &mut [u8]) -> Result<usize, FileSystemError> {
713 if let Some(ref device_guard) = self.device_guard {
714 let device_guard_ref = device_guard.as_ref();
715
716 match device_guard_ref.device_type() {
717 DeviceType::Char => {
718 if let Some(char_device) = device_guard_ref.as_char_device() {
719 let mut bytes_read = 0;
720 for byte in buffer.iter_mut() {
721 match char_device.read_byte() {
722 Some(b) => {
723 *byte = b;
724 bytes_read += 1;
725 },
726 None => break,
727 }
728 }
729 return Ok(bytes_read);
730 } else {
731 return Err(FileSystemError {
732 kind: FileSystemErrorKind::NotSupported,
733 message: "Device is not a character device".to_string(),
734 });
735 }
736 },
737 DeviceType::Block => {
738 if let Some(block_device) = device_guard_ref.as_block_device() {
739 let request = Box::new(crate::device::block::request::BlockIORequest {
741 request_type: crate::device::block::request::BlockIORequestType::Read,
742 sector: 0,
743 sector_count: 1,
744 head: 0,
745 cylinder: 0,
746 buffer: buffer.to_vec(),
747 });
748
749 block_device.enqueue_request(request);
750 let results = block_device.process_requests();
751
752 if let Some(result) = results.first() {
753 match &result.result {
754 Ok(_) => return Ok(buffer.len()),
755 Err(e) => {
756 return Err(FileSystemError {
757 kind: FileSystemErrorKind::IoError,
758 message: format!("Block device read failed: {}", e),
759 });
760 }
761 }
762 }
763 return Ok(0);
764 } else {
765 return Err(FileSystemError {
766 kind: FileSystemErrorKind::NotSupported,
767 message: "Device is not a block device".to_string(),
768 });
769 }
770 },
771 _ => {
772 return Err(FileSystemError {
773 kind: FileSystemErrorKind::NotSupported,
774 message: "Unsupported device type".to_string(),
775 });
776 }
777 }
778 }
779
780 Err(FileSystemError {
781 kind: FileSystemErrorKind::NotSupported,
782 message: "No device guard available".to_string(),
783 })
784 }
785
786 fn read_regular_file(&self, buffer: &mut [u8]) -> Result<usize, FileSystemError> {
787 let mut position = self.position.write();
788
789 let content_guard = self.node.content.write();
792 if *position as usize >= content_guard.len() {
795 return Ok(0); }
797
798 let available = content_guard.len() - *position as usize;
799 let to_read = buffer.len().min(available);
800
801 buffer[..to_read].copy_from_slice(&content_guard[*position as usize..*position as usize + to_read]);
802 *position += to_read as u64;
803
804 Ok(to_read)
805 }
806
807 fn write_device(&self, buffer: &[u8]) -> Result<usize, FileSystemError> {
808 if let Some(ref device_guard) = self.device_guard {
809 let device_guard_ref = device_guard.as_ref();
810
811 match device_guard_ref.device_type() {
812 DeviceType::Char => {
813 if let Some(char_device) = device_guard_ref.as_char_device() {
814 let mut bytes_written = 0;
815 for &byte in buffer {
816 match char_device.write_byte(byte) {
817 Ok(_) => bytes_written += 1,
818 Err(_) => break,
819 }
820 }
821 return Ok(bytes_written);
822 } else {
823 return Err(FileSystemError {
824 kind: FileSystemErrorKind::NotSupported,
825 message: "Device is not a character device".to_string(),
826 });
827 }
828 },
829 DeviceType::Block => {
830 if let Some(block_device) = device_guard_ref.as_block_device() {
831 let request = Box::new(crate::device::block::request::BlockIORequest {
832 request_type: crate::device::block::request::BlockIORequestType::Write,
833 sector: 0,
834 sector_count: 1,
835 head: 0,
836 cylinder: 0,
837 buffer: buffer.to_vec(),
838 });
839
840 block_device.enqueue_request(request);
841 let results = block_device.process_requests();
842
843 if let Some(result) = results.first() {
844 match &result.result {
845 Ok(_) => return Ok(buffer.len()),
846 Err(e) => {
847 return Err(FileSystemError {
848 kind: FileSystemErrorKind::IoError,
849 message: format!("Block device write failed: {}", e),
850 });
851 }
852 }
853 }
854 return Ok(0);
855 } else {
856 return Err(FileSystemError {
857 kind: FileSystemErrorKind::NotSupported,
858 message: "Device is not a block device".to_string(),
859 });
860 }
861 },
862 _ => {
863 return Err(FileSystemError {
864 kind: FileSystemErrorKind::NotSupported,
865 message: "Unsupported device type".to_string(),
866 });
867 }
868 }
869 } else {
870 Err(FileSystemError {
871 kind: FileSystemErrorKind::NotSupported,
872 message: "No device guard available".to_string(),
873 })
874 }
875 }
876
877 fn write_regular_file(&self, buffer: &[u8]) -> Result<usize, FileSystemError> {
878 let mut position = self.position.write();
879
880 let mut content_guard = self.node.content.write();
882 let _old_size = content_guard.len();
883 let new_position = *position as usize + buffer.len();
884
885 if new_position > content_guard.len() {
887 content_guard.resize(new_position, 0);
888 }
889
890 content_guard[*position as usize..new_position].copy_from_slice(buffer);
892 let new_size = content_guard.len();
893
894 self.node.update_size(new_size as u64);
896
897 *position += buffer.len() as u64;
899 Ok(buffer.len())
900 }
901}
902
903impl StreamOps for TmpFileObject {
904 fn read(&self, buffer: &mut [u8]) -> Result<usize, StreamError> {
905 match self.node.file_type() {
906 FileType::RegularFile => {
907 self.read_regular_file(buffer)
908 .map_err(StreamError::from)
909 }
910 FileType::Directory => {
911 let node = self.node.clone();
913 let current_metadata = node.metadata.read();
919 let mut all_entries = vec![crate::fs::DirectoryEntryInternal {
920 name: ".".to_string(),
921 file_type: FileType::Directory,
922 size: current_metadata.size,
923 file_id: current_metadata.file_id,
924 metadata: Some(current_metadata.clone()),
925 }];
926
927 all_entries.push(crate::fs::DirectoryEntryInternal {
929 name: "..".to_string(),
930 file_type: FileType::Directory,
931 size: current_metadata.size,
932 file_id: current_metadata.file_id,
933 metadata: Some(current_metadata.clone()),
934 });
935
936 let children = node.children.read();
938 let mut regular_entries = Vec::new();
939 for (name, child) in children.iter() {
940 let metadata = child.metadata().unwrap();
941 regular_entries.push(crate::fs::DirectoryEntryInternal {
942 name: name.clone(),
943 file_type: child.file_type().unwrap().clone(),
944 size: metadata.size,
945 file_id: metadata.file_id,
946 metadata: Some(metadata.clone()),
947 });
948 }
949
950 regular_entries.sort_by_key(|entry| entry.file_id);
952
953 all_entries.extend(regular_entries);
955
956 let position = *self.position.read() as usize;
958
959 if position >= all_entries.len() {
960 return Ok(0); }
962
963 let internal_entry = &all_entries[position];
965
966 let dir_entry = crate::fs::DirectoryEntry::from_internal(internal_entry);
968
969 let entry_size = dir_entry.entry_size();
971
972 if buffer.len() < entry_size {
974 return Err(StreamError::InvalidArgument); }
976
977 let entry_bytes = unsafe {
979 core::slice::from_raw_parts(
980 &dir_entry as *const _ as *const u8,
981 entry_size
982 )
983 };
984
985 buffer[..entry_size].copy_from_slice(entry_bytes);
987
988 *self.position.write() += 1;
990
991 Ok(entry_size)
992 },
993 FileType::CharDevice(_) | FileType::BlockDevice(_) => {
994 self.read_device(buffer)
995 .map_err(StreamError::from)
996 }
997 _ => Err(StreamError::NotSupported)
998 }
999 }
1000
1001 fn write(&self, buffer: &[u8]) -> Result<usize, StreamError> {
1002 match self.node.file_type() {
1003 FileType::RegularFile => {
1004 self.write_regular_file(buffer).map_err(StreamError::from)
1005 }
1006 FileType::Directory => {
1007 Err(StreamError::from(FileSystemError::new(
1008 FileSystemErrorKind::IsADirectory,
1009 "Cannot write to directory"
1010 )))
1011 }
1012 FileType::CharDevice(_) | FileType::BlockDevice(_) => {
1013 self.write_device(buffer).map_err(StreamError::from)
1014 }
1015 _ => Err(StreamError::NotSupported)
1016 }
1017 }
1018}
1019
1020impl FileObject for TmpFileObject {
1021 fn seek(&self, pos: crate::fs::SeekFrom) -> Result<u64, StreamError> {
1022 use crate::fs::SeekFrom;
1023
1024 let mut position = self.position.write();
1025 let content = self.node.content.read();
1026 let file_size = content.len() as u64;
1027
1028 let new_pos = match pos {
1029 SeekFrom::Start(offset) => {
1030 if offset <= file_size {
1031 offset
1032 } else {
1033 return Err(StreamError::from(FileSystemError::new(
1034 FileSystemErrorKind::NotSupported,
1035 "Seek offset beyond EOF"
1036 )));
1037 }
1038 }
1039 SeekFrom::End(offset) => {
1040 if offset >= 0 {
1041 file_size + offset as u64
1042 } else {
1043 file_size.saturating_sub((-offset) as u64)
1044 }
1045 }
1046 SeekFrom::Current(offset) => {
1047 if offset >= 0 {
1048 *position + offset as u64
1049 } else {
1050 position.saturating_sub((-offset) as u64)
1051 }
1052 }
1053 };
1054
1055 *position = new_pos;
1056 Ok(new_pos)
1057 }
1058
1059 fn metadata(&self) -> Result<FileMetadata, StreamError> {
1060 self.node.metadata().map_err(StreamError::from)
1061 }
1062
1063 fn truncate(&self, size: u64) -> Result<(), StreamError> {
1064 if self.node.file_type() != FileType::RegularFile {
1065 return Err(StreamError::from(FileSystemError::new(
1066 FileSystemErrorKind::IsADirectory,
1067 "Cannot truncate non-regular file"
1068 )));
1069 }
1070
1071 let mut content = self.node.content.write();
1072 let old_size = content.len();
1073 let new_size = size as usize;
1074
1075 if new_size > old_size {
1076 content.resize(new_size, 0);
1078 } else if new_size < old_size {
1079 content.truncate(new_size);
1081 }
1082
1083 self.node.update_size(size);
1085
1086 Ok(())
1087 }
1088}
1089
1090pub struct TmpFSDriver;
1091
1092impl FileSystemDriver for TmpFSDriver {
1093
1094 fn filesystem_type(&self) -> crate::fs::FileSystemType {
1095 crate::fs::FileSystemType::Virtual
1096 }
1097
1098 fn create_from_memory(&self, _memory_area: &crate::vm::vmem::MemoryArea) -> Result<Arc<dyn FileSystemOperations>, FileSystemError> {
1099 Ok(TmpFS::new(0) as Arc<dyn FileSystemOperations>)
1100 }
1101
1102 fn create_from_params(&self, _params: &dyn crate::fs::params::FileSystemParams) -> Result<Arc<dyn FileSystemOperations>, FileSystemError> {
1103 Ok(TmpFS::create_from_option_string(None))
1104 }
1105
1106 fn create_from_option_string(&self, options: &str) -> Result<Arc<dyn FileSystemOperations>, FileSystemError> {
1107 let memory_limit = parse_tmpfs_size_option(options).unwrap_or(64 * 1024 * 1024); Ok(TmpFS::new(memory_limit))
1110 }
1111
1112 fn name(&self) -> &'static str {
1113 "tmpfs"
1114 }
1115}
1116
1117fn parse_tmpfs_size_option(options: &str) -> Option<usize> {
1122 for option in options.split(',') {
1123 if let Some(size_str) = option.strip_prefix("size=") {
1124 let size_str = size_str.trim();
1126 if size_str.is_empty() {
1127 continue;
1128 }
1129
1130 let (number_part, multiplier) = if size_str.ends_with('K') || size_str.ends_with('k') {
1131 (&size_str[..size_str.len()-1], 1024)
1132 } else if size_str.ends_with('M') || size_str.ends_with('m') {
1133 (&size_str[..size_str.len()-1], 1024 * 1024)
1134 } else if size_str.ends_with('G') || size_str.ends_with('g') {
1135 (&size_str[..size_str.len()-1], 1024 * 1024 * 1024)
1136 } else {
1137 (size_str, 1)
1138 };
1139
1140 if let Ok(number) = number_part.parse::<usize>() {
1141 return Some(number * multiplier);
1142 }
1143 }
1144 }
1145 None
1146}
1147
1148fn register_driver() {
1149 let fs_driver_manager = get_fs_driver_manager();
1150 fs_driver_manager.register_driver(Box::new(TmpFSDriver));
1151}
1152
1153driver_initcall!(register_driver);
1154
1155#[cfg(test)]
1156mod tests;