1use alloc::boxed::Box;
13use alloc::string::String;
14use alloc::vec::Vec;
15use alloc::collections::BTreeMap;
16use spin::rwlock::RwLock;
17use spin::Mutex;
18
19use super::*;
20use crate::device::manager::{BorrowedDeviceGuard, DeviceManager};
21use crate::device::DeviceType;
22
23#[derive(Clone, Default)]
25struct DirectoryEntries {
26 entries: BTreeMap<String, TmpNode>,
27}
28
29impl DirectoryEntries {
30 fn new() -> Self {
32 Self {
33 entries: BTreeMap::new(),
34 }
35 }
36
37 fn insert(&mut self, name: String, node: TmpNode) -> Option<TmpNode> {
39 self.entries.insert(name, node)
40 }
41
42 fn remove(&mut self, name: &str) -> Option<TmpNode> {
44 self.entries.remove(name)
45 }
46
47 fn get(&self, name: &str) -> Option<&TmpNode> {
49 self.entries.get(name)
50 }
51
52 fn get_mut(&mut self, name: &str) -> Option<&mut TmpNode> {
54 self.entries.get_mut(name)
55 }
56
57 fn contains(&self, name: &str) -> bool {
59 self.entries.contains_key(name)
60 }
61
62 fn contains_key(&self, name: &str) -> bool {
64 self.entries.contains_key(name)
65 }
66
67 fn entry_names(&self) -> impl Iterator<Item = &String> {
69 self.entries.keys()
70 }
71
72 fn entries(&self) -> impl Iterator<Item = (&String, &TmpNode)> {
74 self.entries.iter()
75 }
76
77 fn entries_mut(&mut self) -> impl Iterator<Item = (&String, &mut TmpNode)> {
79 self.entries.iter_mut()
80 }
81
82 fn len(&self) -> usize {
84 self.entries.len()
85 }
86
87 fn is_empty(&self) -> bool {
89 self.entries.is_empty()
90 }
91
92 fn clear(&mut self) {
94 self.entries.clear();
95 }
96}
97
98#[derive(Clone)]
100struct TmpNode {
101 name: String,
103 file_type: FileType,
105 content: Vec<u8>,
107 metadata: FileMetadata,
109 children: DirectoryEntries,
111}
112
113impl TmpNode {
114 fn new_file(name: String) -> Self {
116 Self {
117 name: name.clone(),
118 file_type: FileType::RegularFile,
119 content: Vec::new(),
120 metadata: FileMetadata {
121 file_type: FileType::RegularFile,
122 size: 0,
123 permissions: FilePermission {
124 read: true,
125 write: true,
126 execute: false,
127 },
128 created_time: crate::time::current_time(),
129 modified_time: crate::time::current_time(),
130 accessed_time: crate::time::current_time(),
131 },
132 children: DirectoryEntries::new(),
133 }
134 }
135
136 fn new_directory(name: String) -> Self {
138 Self {
139 name: name.clone(),
140 file_type: FileType::Directory,
141 content: Vec::new(),
142 metadata: FileMetadata {
143 file_type: FileType::Directory,
144 size: 0,
145 permissions: FilePermission {
146 read: true,
147 write: true,
148 execute: true,
149 },
150 created_time: crate::time::current_time(),
151 modified_time: crate::time::current_time(),
152 accessed_time: crate::time::current_time(),
153 },
154 children: DirectoryEntries::new(),
155 }
156 }
157
158 fn new_device(name: String, file_type: FileType) -> Self {
160 Self {
161 name: name.clone(),
162 file_type: file_type.clone(),
163 content: Vec::new(),
164 metadata: FileMetadata {
165 file_type,
166 size: 0,
167 permissions: FilePermission {
168 read: true,
169 write: true,
170 execute: false,
171 },
172 created_time: crate::time::current_time(),
173 modified_time: crate::time::current_time(),
174 accessed_time: crate::time::current_time(),
175 },
176 children: DirectoryEntries::new(),
177 }
178 }
179
180 fn update_size(&mut self, new_size: usize) {
182 self.metadata.size = new_size;
183 self.metadata.modified_time = crate::time::current_time();
184 }
185
186 fn update_access_time(&mut self) {
188 self.metadata.accessed_time = crate::time::current_time();
189 }
190}
191
192pub struct TmpFS {
194 mounted: bool,
195 mount_point: String,
196 root: RwLock<TmpNode>,
198 max_memory: usize,
200 current_memory: Mutex<usize>,
202}
203
204impl TmpFS {
205 pub fn new(max_memory: usize) -> Self {
207 let root = TmpNode::new_directory("/".to_string());
208
209 Self {
210 mounted: false,
211 mount_point: String::new(),
212 root: RwLock::new(root),
213 max_memory,
214 current_memory: Mutex::new(0),
215 }
216 }
217
218 pub fn memory_usage(&self) -> usize {
220 *self.current_memory.lock()
221 }
222
223 pub fn memory_limit(&self) -> usize {
225 self.max_memory
226 }
227
228 fn check_memory_limit(&self, additional_bytes: usize) -> Result<()> {
230 if self.max_memory == 0 {
231 return Ok(()); }
233
234 let current = *self.current_memory.lock();
235 if current + additional_bytes > self.max_memory {
236 return Err(FileSystemError {
237 kind: FileSystemErrorKind::NoSpace,
238 message: "TmpFS memory limit exceeded".to_string(),
239 });
240 }
241
242 Ok(())
243 }
244
245 fn add_memory_usage(&self, bytes: usize) {
247 *self.current_memory.lock() += bytes;
248 }
249
250 fn subtract_memory_usage(&self, bytes: usize) {
252 let mut current = self.current_memory.lock();
253 *current = current.saturating_sub(bytes);
254 }
255
256 fn find_node(&self, path: &str) -> Option<TmpNode> {
258 let normalized = self.normalize_path(path);
259
260 if normalized == "/" {
261 return Some(self.root.read().clone());
262 }
263
264 let parts: Vec<&str> = normalized.trim_start_matches('/').split('/').collect();
265 let root = self.root.read();
266 let mut current = &*root;
267
268 for part in parts {
269 if let Some(child) = current.children.get(part) {
270 current = child;
271 } else {
272 return None;
273 }
274 }
275
276 Some(current.clone())
277 }
278
279 fn find_node_mut<F, R>(&self, path: &str, f: F) -> Option<R>
281 where
282 F: FnOnce(&mut TmpNode) -> R,
283 {
284 let normalized = self.normalize_path(path);
285
286 if normalized == "/" {
287 let mut root = self.root.write();
288 return Some(f(&mut *root));
289 }
290
291 let parts: Vec<&str> = normalized.trim_start_matches('/').split('/').collect();
292 let mut root = self.root.write();
293 let mut current = &mut *root;
294
295 for part in parts {
296 if let Some(child) = current.children.get_mut(part) {
297 current = child;
298 } else {
299 return None;
300 }
301 }
302
303 Some(f(current))
304 }
305
306 fn find_parent_mut<F, R>(&self, path: &str, f: F) -> Result<R>
308 where
309 F: FnOnce(&mut TmpNode, &str) -> R,
310 {
311 let normalized = self.normalize_path(path);
312 let (parent_path, filename) = if let Some(pos) = normalized.rfind('/') {
313 let parent = if pos == 0 { "/" } else { &normalized[..pos] };
314 let name = &normalized[pos + 1..];
315 (parent, name)
316 } else {
317 return Err(FileSystemError {
318 kind: FileSystemErrorKind::InvalidPath,
319 message: "Invalid path".to_string(),
320 });
321 };
322
323 if parent_path == "/" {
324 let mut root = self.root.write();
325 return Ok(f(&mut *root, filename));
326 }
327
328 let parts: Vec<&str> = parent_path.trim_start_matches('/').split('/').collect();
329 let mut root = self.root.write();
330 let mut current = &mut *root;
331
332 for part in parts {
333 if let Some(child) = current.children.get_mut(part) {
334 if child.file_type != FileType::Directory {
335 return Err(FileSystemError {
336 kind: FileSystemErrorKind::NotADirectory,
337 message: "Parent path is not a directory".to_string(),
338 });
339 }
340 current = child;
341 } else {
342 return Err(FileSystemError {
343 kind: FileSystemErrorKind::NotFound,
344 message: "Parent directory not found".to_string(),
345 });
346 }
347 }
348
349 Ok(f(current, filename))
350 }
351
352 fn normalize_path(&self, path: &str) -> String {
354 if path.is_empty() || path == "/" {
355 return "/".to_string();
356 }
357
358 let mut normalized = path.to_string();
359 if !normalized.starts_with('/') {
360 normalized = format!("/{}", normalized);
361 }
362
363 if normalized.ends_with('/') && normalized.len() > 1 {
364 normalized.pop();
365 }
366
367 normalized
368 }
369}
370
371impl FileSystem for TmpFS {
372 fn mount(&mut self, mount_point: &str) -> Result<()> {
373 if self.mounted {
374 return Err(FileSystemError {
375 kind: FileSystemErrorKind::AlreadyExists,
376 message: "TmpFS already mounted".to_string(),
377 });
378 }
379 self.mounted = true;
380 self.mount_point = mount_point.to_string();
381 Ok(())
382 }
383
384 fn unmount(&mut self) -> Result<()> {
385 if !self.mounted {
386 return Err(FileSystemError {
387 kind: FileSystemErrorKind::NotFound,
388 message: "TmpFS not mounted".to_string(),
389 });
390 }
391 self.mounted = false;
392 self.mount_point = String::new();
393
394 *self.root.write() = TmpNode::new_directory("/".to_string());
396 *self.current_memory.lock() = 0;
397
398 Ok(())
399 }
400
401 fn name(&self) -> &str {
402 "tmpfs"
403 }
404}
405
406struct TmpFileHandle {
408 path: String,
409 position: RwLock<u64>,
410 file_type: FileType,
411 device_guard: Option<BorrowedDeviceGuard>,
412 fs: *const TmpFS, }
414
415unsafe impl Send for TmpFileHandle {}
417unsafe impl Sync for TmpFileHandle {}
418
419impl TmpFileHandle {
420 fn new(path: String, file_type: FileType, fs: &TmpFS) -> Self {
421 Self {
422 path,
423 position: RwLock::new(0),
424 file_type,
425 device_guard: None,
426 fs: fs as *const TmpFS,
427 }
428 }
429
430 fn new_with_device(path: String, file_type: FileType, device_guard: BorrowedDeviceGuard, fs: &TmpFS) -> Self {
431 Self {
432 path,
433 position: RwLock::new(0),
434 file_type,
435 device_guard: Some(device_guard),
436 fs: fs as *const TmpFS,
437 }
438 }
439
440 fn get_fs(&self) -> &TmpFS {
441 unsafe { &*self.fs }
442 }
443}
444
445impl FileHandle for TmpFileHandle {
446 fn read(&self, buffer: &mut [u8]) -> Result<usize> {
447 if let Some(ref device_guard) = self.device_guard {
449 let device_guard_ref = device_guard.device();
450 let mut device_write = device_guard_ref.write();
451
452 match device_write.device_type() {
453 DeviceType::Char => {
454 if let Some(char_device) = device_write.as_char_device() {
455 let mut bytes_read = 0;
456 for i in 0..buffer.len() {
457 if let Some(byte) = char_device.read_byte() {
458 buffer[i] = byte;
459 bytes_read += 1;
460 } else {
461 break;
462 }
463 }
464 return Ok(bytes_read);
465 } else {
466 return Err(FileSystemError {
467 kind: FileSystemErrorKind::NotSupported,
468 message: "Device is not a character device".to_string(),
469 });
470 }
471 },
472 DeviceType::Block => {
473 if let Some(block_device) = device_write.as_block_device() {
474 let request = Box::new(crate::device::block::request::BlockIORequest {
475 request_type: crate::device::block::request::BlockIORequestType::Read,
476 sector: 0,
477 sector_count: 1,
478 head: 0,
479 cylinder: 0,
480 buffer: vec![0; buffer.len().min(512)],
481 });
482
483 block_device.enqueue_request(request);
484 let results = block_device.process_requests();
485
486 if let Some(result) = results.first() {
487 match &result.result {
488 Ok(_) => {
489 let bytes_to_copy = buffer.len().min(result.request.buffer.len());
490 buffer[..bytes_to_copy].copy_from_slice(&result.request.buffer[..bytes_to_copy]);
491 return Ok(bytes_to_copy);
492 },
493 Err(e) => {
494 return Err(FileSystemError {
495 kind: FileSystemErrorKind::IoError,
496 message: format!("Block device read failed: {}", e),
497 });
498 }
499 }
500 }
501 return Ok(0);
502 } else {
503 return Err(FileSystemError {
504 kind: FileSystemErrorKind::NotSupported,
505 message: "Device is not a block device".to_string(),
506 });
507 }
508 },
509 _ => {
510 return Err(FileSystemError {
511 kind: FileSystemErrorKind::NotSupported,
512 message: "Unsupported device type".to_string(),
513 });
514 }
515 }
516 }
517
518 let fs = self.get_fs();
520 let mut position = self.position.write();
521
522 if let Some(mut node) = fs.find_node(&self.path) {
523 node.update_access_time();
524
525 if *position as usize >= node.content.len() {
526 return Ok(0); }
528
529 let available = node.content.len() - *position as usize;
530 let to_read = buffer.len().min(available);
531
532 buffer[..to_read].copy_from_slice(&node.content[*position as usize..*position as usize + to_read]);
533 *position += to_read as u64;
534
535 fs.find_node_mut(&self.path, |n| {
537 n.update_access_time();
538 });
539
540 Ok(to_read)
541 } else {
542 Err(FileSystemError {
543 kind: FileSystemErrorKind::NotFound,
544 message: "File not found".to_string(),
545 })
546 }
547 }
548
549 fn write(&self, buffer: &[u8]) -> Result<usize> {
550 if let Some(ref device_guard) = self.device_guard {
552 let device_guard_ref = device_guard.device();
553 let mut device_write = device_guard_ref.write();
554
555 match device_write.device_type() {
556 DeviceType::Char => {
557 if let Some(char_device) = device_write.as_char_device() {
558 let mut bytes_written = 0;
559 for &byte in buffer {
560 match char_device.write_byte(byte) {
561 Ok(_) => bytes_written += 1,
562 Err(_) => break,
563 }
564 }
565 return Ok(bytes_written);
566 } else {
567 return Err(FileSystemError {
568 kind: FileSystemErrorKind::NotSupported,
569 message: "Device is not a character device".to_string(),
570 });
571 }
572 },
573 DeviceType::Block => {
574 if let Some(block_device) = device_write.as_block_device() {
575 let request = Box::new(crate::device::block::request::BlockIORequest {
576 request_type: crate::device::block::request::BlockIORequestType::Write,
577 sector: 0,
578 sector_count: 1,
579 head: 0,
580 cylinder: 0,
581 buffer: buffer.to_vec(),
582 });
583
584 block_device.enqueue_request(request);
585 let results = block_device.process_requests();
586
587 if let Some(result) = results.first() {
588 match &result.result {
589 Ok(_) => return Ok(buffer.len()),
590 Err(e) => {
591 return Err(FileSystemError {
592 kind: FileSystemErrorKind::IoError,
593 message: format!("Block device write failed: {}", e),
594 });
595 }
596 }
597 }
598 return Ok(0);
599 } else {
600 return Err(FileSystemError {
601 kind: FileSystemErrorKind::NotSupported,
602 message: "Device is not a block device".to_string(),
603 });
604 }
605 },
606 _ => {
607 return Err(FileSystemError {
608 kind: FileSystemErrorKind::NotSupported,
609 message: "Unsupported device type".to_string(),
610 });
611 }
612 }
613 }
614
615 let fs = self.get_fs();
617 let mut position = self.position.write();
618
619 fs.check_memory_limit(buffer.len())?;
621
622 if let Some(result) = fs.find_node_mut(&self.path, |node| {
623 let old_size = node.content.len();
624 let new_position = *position as usize + buffer.len();
625
626 if new_position > node.content.len() {
628 node.content.resize(new_position, 0);
629 }
630
631 node.content[*position as usize..new_position].copy_from_slice(buffer);
633 node.update_size(node.content.len());
634
635 let size_increase = node.content.len().saturating_sub(old_size);
636 size_increase
637 }) {
638 *position += buffer.len() as u64;
639 fs.add_memory_usage(result);
640 Ok(buffer.len())
641 } else {
642 Err(FileSystemError {
643 kind: FileSystemErrorKind::NotFound,
644 message: "File not found".to_string(),
645 })
646 }
647 }
648
649 fn seek(&self, whence: SeekFrom) -> Result<u64> {
650 let fs = self.get_fs();
651 let mut position = self.position.write();
652
653 match whence {
654 SeekFrom::Start(offset) => {
655 *position = offset;
656 },
657 SeekFrom::Current(offset) => {
658 if offset >= 0 {
659 *position = position.saturating_add(offset as u64);
660 } else {
661 *position = position.saturating_sub((-offset) as u64);
662 }
663 },
664 SeekFrom::End(offset) => {
665 if let Some(node) = fs.find_node(&self.path) {
666 let end = node.content.len() as u64;
667 if offset >= 0 {
668 *position = end.saturating_add(offset as u64);
669 } else {
670 *position = end.saturating_sub((-offset) as u64);
671 }
672 } else {
673 return Err(FileSystemError {
674 kind: FileSystemErrorKind::NotFound,
675 message: "File not found".to_string(),
676 });
677 }
678 },
679 }
680
681 Ok(*position)
682 }
683
684 fn release(&self) -> Result<()> {
685 Ok(())
686 }
687
688 fn metadata(&self) -> Result<FileMetadata> {
689 let fs = self.get_fs();
690 if let Some(node) = fs.find_node(&self.path) {
691 Ok(node.metadata)
692 } else {
693 Err(FileSystemError {
694 kind: FileSystemErrorKind::NotFound,
695 message: "File not found".to_string(),
696 })
697 }
698 }
699}
700
701impl FileOperations for TmpFS {
702 fn open(&self, path: &str, _flags: u32) -> Result<Arc<dyn FileHandle>> {
703 let normalized = self.normalize_path(path);
704
705 if let Some(node) = self.find_node(&normalized) {
706 match node.file_type {
707 FileType::RegularFile | FileType::Directory => {
708 Ok(Arc::new(TmpFileHandle::new(normalized, node.file_type, self)))
709 },
710 FileType::CharDevice(ref info) | FileType::BlockDevice(ref info) => {
711 match DeviceManager::get_manager().borrow_device(info.device_id) {
713 Ok(guard) => {
714 Ok(Arc::new(TmpFileHandle::new_with_device(normalized, node.file_type, guard, self)))
715 },
716 Err(_) => {
717 Err(FileSystemError {
718 kind: FileSystemErrorKind::PermissionDenied,
719 message: "Failed to access device".to_string(),
720 })
721 }
722 }
723 },
724 _ => {
725 Err(FileSystemError {
726 kind: FileSystemErrorKind::NotSupported,
727 message: "Unsupported file type".to_string(),
728 })
729 }
730 }
731 } else {
732 Err(FileSystemError {
733 kind: FileSystemErrorKind::NotFound,
734 message: "File not found".to_string(),
735 })
736 }
737 }
738
739 fn read_dir(&self, path: &str) -> Result<Vec<DirectoryEntry>> {
740 let normalized = self.normalize_path(path);
741
742 if let Some(node) = self.find_node(&normalized) {
743 if node.file_type != FileType::Directory {
744 return Err(FileSystemError {
745 kind: FileSystemErrorKind::NotADirectory,
746 message: "Not a directory".to_string(),
747 });
748 }
749
750 let mut entries = Vec::new();
751 for (name, child) in node.children.entries() {
752 entries.push(DirectoryEntry {
753 name: name.clone(),
754 file_type: child.file_type.clone(),
755 size: child.metadata.size,
756 metadata: Some(child.metadata.clone()),
757 });
758 }
759
760 Ok(entries)
761 } else {
762 Err(FileSystemError {
763 kind: FileSystemErrorKind::NotFound,
764 message: "Directory not found".to_string(),
765 })
766 }
767 }
768
769 fn create_file(&self, path: &str, file_type: FileType) -> Result<()> {
770 self.find_parent_mut(path, |parent, filename| {
771 if parent.children.contains_key(filename) {
772 return Err(FileSystemError {
773 kind: FileSystemErrorKind::AlreadyExists,
774 message: "File already exists".to_string(),
775 });
776 }
777
778 let node = match file_type {
779 FileType::RegularFile => TmpNode::new_file(filename.to_string()),
780 FileType::Directory => TmpNode::new_directory(filename.to_string()),
781 FileType::CharDevice(_) | FileType::BlockDevice(_) => {
782 TmpNode::new_device(filename.to_string(), file_type)
783 },
784 _ => {
785 return Err(FileSystemError {
786 kind: FileSystemErrorKind::NotSupported,
787 message: "Unsupported file type".to_string(),
788 });
789 }
790 };
791
792 parent.children.insert(filename.to_string(), node);
793 parent.metadata.modified_time = crate::time::current_time();
794
795 Ok(())
796 })?
797 }
798
799 fn create_dir(&self, path: &str) -> Result<()> {
800 self.create_file(path, FileType::Directory)
801 }
802
803 fn remove(&self, path: &str) -> Result<()> {
804 self.find_parent_mut(path, |parent, filename| {
805 if let Some(node) = parent.children.get(filename) {
806 if node.file_type == FileType::Directory && !node.children.is_empty() {
808 return Err(FileSystemError {
809 kind: FileSystemErrorKind::NotSupported,
810 message: "Cannot remove non-empty directory".to_string(),
811 });
812 }
813
814 let memory_freed = node.content.len();
816
817 parent.children.remove(filename);
819 parent.metadata.modified_time = crate::time::current_time();
820
821 self.subtract_memory_usage(memory_freed);
823
824 Ok(())
825 } else {
826 Err(FileSystemError {
827 kind: FileSystemErrorKind::NotFound,
828 message: "File or directory not found".to_string(),
829 })
830 }
831 })?
832 }
833
834 fn metadata(&self, path: &str) -> Result<FileMetadata> {
835 let normalized = self.normalize_path(path);
836
837 if let Some(node) = self.find_node(&normalized) {
838 Ok(node.metadata)
839 } else {
840 Err(FileSystemError {
841 kind: FileSystemErrorKind::NotFound,
842 message: "File or directory not found".to_string(),
843 })
844 }
845 }
846
847 fn root_dir(&self) -> Result<Directory> {
848 Ok(Directory::open("/".to_string()))
849 }
850}
851
852pub struct TmpFSDriver;
854
855impl FileSystemDriver for TmpFSDriver {
856 fn name(&self) -> &'static str {
857 "tmpfs"
858 }
859
860 fn filesystem_type(&self) -> FileSystemType {
861 FileSystemType::Virtual }
863
864 fn create_from_block(&self, _block_device: Box<dyn BlockDevice>, _block_size: usize) -> Result<Box<dyn VirtualFileSystem>> {
865 Ok(Box::new(TmpFS::new(0)))
867 }
868
869 fn create_from_memory(&self, _memory_area: &crate::vm::vmem::MemoryArea) -> Result<Box<dyn VirtualFileSystem>> {
870 Ok(Box::new(TmpFS::new(0)))
872 }
873
874 fn create_with_params(&self, params: &dyn crate::fs::params::FileSystemParams) -> Result<Box<dyn VirtualFileSystem>> {
875 use crate::fs::params::*;
876
877 if let Some(tmpfs_params) = params.as_any().downcast_ref::<TmpFSParams>() {
879 return Ok(Box::new(TmpFS::new(tmpfs_params.memory_limit)));
880 }
881
882 if let Some(_basic_params) = params.as_any().downcast_ref::<BasicFSParams>() {
884 return Ok(Box::new(TmpFS::new(0))); }
886
887 Err(FileSystemError {
889 kind: FileSystemErrorKind::NotSupported,
890 message: "TmpFS requires TmpFSParams or BasicFSParams parameter type".to_string(),
891 })
892 }
893}
894
895impl TmpFSDriver {
896 pub fn create_with_limit(&self, max_memory: usize) -> Box<dyn VirtualFileSystem> {
898 Box::new(TmpFS::new(max_memory))
899 }
900
901 pub fn create_unlimited(&self) -> Box<dyn VirtualFileSystem> {
903 Box::new(TmpFS::new(0))
904 }
905}
906
907pub fn register_tmpfs_driver() {
909 let fs_driver_manager = crate::fs::get_fs_driver_manager();
910 fs_driver_manager.register_driver(Box::new(TmpFSDriver));
911}
912
913crate::driver_initcall!(register_tmpfs_driver);
915
916#[cfg(test)]
917mod tests {
918 use super::*;
919 use crate::device::{char::mockchar::MockCharDevice, Device};
920
921 #[test_case]
922 fn test_tmpfs_basic_operations() {
923 let tmpfs = TmpFS::new(0); tmpfs.create_dir("/test").unwrap();
927
928 tmpfs.create_file("/test/file.txt", FileType::RegularFile).unwrap();
930
931 let file = tmpfs.open("/test/file.txt", 0).unwrap();
933 let data = b"Hello, TmpFS!";
934 let bytes_written = file.write(data).unwrap();
935 assert_eq!(bytes_written, data.len());
936
937 file.seek(SeekFrom::Start(0)).unwrap();
939 let mut buffer = vec![0u8; data.len()];
940 let bytes_read = file.read(&mut buffer).unwrap();
941 assert_eq!(bytes_read, data.len());
942 assert_eq!(&buffer, data);
943
944 let entries = tmpfs.read_dir("/test").unwrap();
946 assert_eq!(entries.len(), 1);
947 assert_eq!(entries[0].name, "file.txt");
948 assert_eq!(entries[0].file_type, FileType::RegularFile);
949 }
950
951 #[test_case]
952 fn test_tmpfs_memory_limit() {
953 let tmpfs = TmpFS::new(100); tmpfs.create_file("/test.txt", FileType::RegularFile).unwrap();
956 let file = tmpfs.open("/test.txt", 0).unwrap();
957
958 let small_data = b"Small";
960 assert!(file.write(small_data).is_ok());
961
962 let large_data = vec![0u8; 200];
964 assert!(file.write(&large_data).is_err());
965
966 assert_eq!(tmpfs.memory_usage(), small_data.len());
968 }
969
970 #[test_case]
971 fn test_tmpfs_device_files() {
972 let tmpfs = TmpFS::new(0);
973
974 let mut char_device = Box::new(MockCharDevice::new(1, "tmpfs_char"));
976 char_device.set_read_data(vec![b'T', b'M', b'P', b'F', b'S']);
977 let device_id = DeviceManager::get_mut_manager().register_device(char_device as Box<dyn Device>);
978
979 let device_info = DeviceFileInfo {
981 device_id,
982 device_type: DeviceType::Char,
983 };
984
985 tmpfs.create_dir("/dev").unwrap();
986 tmpfs.create_file("/dev/tmpfs_char", FileType::CharDevice(device_info)).unwrap();
987
988 let device_file = tmpfs.open("/dev/tmpfs_char", 0).unwrap();
990 let mut buffer = [0u8; 5];
991 let bytes_read = device_file.read(&mut buffer).unwrap();
992 assert_eq!(bytes_read, 5);
993 assert_eq!(&buffer, b"TMPFS");
994 }
995
996 #[test_case]
997 fn test_tmpfs_file_operations() {
998 let tmpfs = TmpFS::new(0);
999
1000 tmpfs.create_dir("/home").unwrap();
1002 tmpfs.create_dir("/home/user").unwrap();
1003 tmpfs.create_file("/home/user/document.txt", FileType::RegularFile).unwrap();
1004
1005 let metadata = tmpfs.metadata("/home/user/document.txt").unwrap();
1007 assert_eq!(metadata.file_type, FileType::RegularFile);
1008 assert!(metadata.permissions.read);
1009 assert!(metadata.permissions.write);
1010
1011 tmpfs.remove("/home/user/document.txt").unwrap();
1013 assert!(tmpfs.open("/home/user/document.txt", 0).is_err());
1014
1015 tmpfs.create_file("/home/user/another.txt", FileType::RegularFile).unwrap();
1017 assert!(tmpfs.remove("/home/user").is_err());
1018
1019 tmpfs.remove("/home/user/another.txt").unwrap();
1021 tmpfs.remove("/home/user").unwrap();
1022 assert!(tmpfs.open("/home/user", 0).is_err());
1023 }
1024
1025 #[test_case]
1026 fn test_tmpfs_memory_management() {
1027 let tmpfs = TmpFS::new(1000); for i in 0..10 {
1031 let filename = format!("/file{}.txt", i);
1032 tmpfs.create_file(&filename, FileType::RegularFile).unwrap();
1033
1034 let file = tmpfs.open(&filename, 0).unwrap();
1035 let data = vec![i as u8; 50]; file.write(&data).unwrap();
1037 }
1038
1039 assert_eq!(tmpfs.memory_usage(), 500);
1041
1042 for i in 0..5 {
1044 let filename = format!("/file{}.txt", i);
1045 tmpfs.remove(&filename).unwrap();
1046 }
1047
1048 assert_eq!(tmpfs.memory_usage(), 250);
1050 }
1051
1052 #[test_case]
1053 fn test_tmpfs_large_file_operations() {
1054 let tmpfs = TmpFS::new(0); tmpfs.create_file("/large.bin", FileType::RegularFile).unwrap();
1057 let file = tmpfs.open("/large.bin", 0).unwrap();
1058
1059 let large_data = vec![0xAA; 8192]; let bytes_written = file.write(&large_data).unwrap();
1062 assert_eq!(bytes_written, large_data.len());
1063
1064 file.seek(SeekFrom::Start(4096)).unwrap();
1066 let pattern = vec![0x55; 1024];
1067 file.write(&pattern).unwrap();
1068
1069 file.seek(SeekFrom::Start(4096)).unwrap();
1071 let mut buffer = vec![0u8; 1024];
1072 let bytes_read = file.read(&mut buffer).unwrap();
1073 assert_eq!(bytes_read, 1024);
1074 assert_eq!(buffer, pattern);
1075
1076 let metadata = file.metadata().unwrap();
1078 assert_eq!(metadata.size, 8192);
1079 }
1080}