kernel/fs/
tmpfs.rs

1//! TmpFS - Temporary File System (RAM-only)
2//! 
3//! This is a production-ready implementation of a temporary filesystem that stores
4//! all data in RAM. Unlike TestFileSystem, this implementation is optimized for
5//! practical use cases with features like:
6//! - Dynamic memory allocation for file content
7//! - Proper file permissions and timestamps
8//! - Efficient directory tree management
9//! - Support for device files and symbolic links
10//! - Memory usage optimization
11
12use 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/// Directory entries collection with type-safe operations
24#[derive(Clone, Default)]
25struct DirectoryEntries {
26    entries: BTreeMap<String, TmpNode>,
27}
28
29impl DirectoryEntries {
30    /// Create new empty directory entries
31    fn new() -> Self {
32        Self {
33            entries: BTreeMap::new(),
34        }
35    }
36
37    /// Add a new entry to the directory
38    fn insert(&mut self, name: String, node: TmpNode) -> Option<TmpNode> {
39        self.entries.insert(name, node)
40    }
41
42    /// Remove an entry from the directory
43    fn remove(&mut self, name: &str) -> Option<TmpNode> {
44        self.entries.remove(name)
45    }
46
47    /// Get a reference to an entry
48    fn get(&self, name: &str) -> Option<&TmpNode> {
49        self.entries.get(name)
50    }
51
52    /// Get a mutable reference to an entry
53    fn get_mut(&mut self, name: &str) -> Option<&mut TmpNode> {
54        self.entries.get_mut(name)
55    }
56
57    /// Check if an entry exists
58    fn contains(&self, name: &str) -> bool {
59        self.entries.contains_key(name)
60    }
61
62    /// Check if a key exists (alias for contains)
63    fn contains_key(&self, name: &str) -> bool {
64        self.entries.contains_key(name)
65    }
66
67    /// Get all entry names
68    fn entry_names(&self) -> impl Iterator<Item = &String> {
69        self.entries.keys()
70    }
71
72    /// Get all entries
73    fn entries(&self) -> impl Iterator<Item = (&String, &TmpNode)> {
74        self.entries.iter()
75    }
76
77    /// Get mutable iterator over entries
78    fn entries_mut(&mut self) -> impl Iterator<Item = (&String, &mut TmpNode)> {
79        self.entries.iter_mut()
80    }
81
82    /// Get the number of entries
83    fn len(&self) -> usize {
84        self.entries.len()
85    }
86
87    /// Check if directory is empty
88    fn is_empty(&self) -> bool {
89        self.entries.is_empty()
90    }
91
92    /// Clear all entries
93    fn clear(&mut self) {
94        self.entries.clear();
95    }
96}
97
98/// Node in the tmpfs filesystem
99#[derive(Clone)]
100struct TmpNode {
101    /// File name
102    name: String,
103    /// File type and associated data
104    file_type: FileType,
105    /// File content (only for regular files)
106    content: Vec<u8>,
107    /// File metadata
108    metadata: FileMetadata,
109    /// For directories: child nodes
110    children: DirectoryEntries,
111}
112
113impl TmpNode {
114    /// Create a new regular file node
115    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    /// Create a new directory node
137    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    /// Create a new device file node
159    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    /// Update file size and modification time
181    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    /// Update access time
187    fn update_access_time(&mut self) {
188        self.metadata.accessed_time = crate::time::current_time();
189    }
190}
191
192/// TmpFS - RAM-only filesystem
193pub struct TmpFS {
194    mounted: bool,
195    mount_point: String,
196    /// Root directory of the filesystem
197    root: RwLock<TmpNode>,
198    /// Maximum memory usage in bytes (0 = unlimited)
199    max_memory: usize,
200    /// Current memory usage in bytes
201    current_memory: Mutex<usize>,
202}
203
204impl TmpFS {
205    /// Create a new TmpFS instance
206    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    /// Get current memory usage
219    pub fn memory_usage(&self) -> usize {
220        *self.current_memory.lock()
221    }
222
223    /// Get maximum memory limit
224    pub fn memory_limit(&self) -> usize {
225        self.max_memory
226    }
227
228    /// Check if memory allocation is allowed
229    fn check_memory_limit(&self, additional_bytes: usize) -> Result<()> {
230        if self.max_memory == 0 {
231            return Ok(()); // Unlimited
232        }
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    /// Add to memory usage counter
246    fn add_memory_usage(&self, bytes: usize) {
247        *self.current_memory.lock() += bytes;
248    }
249
250    /// Subtract from memory usage counter
251    fn subtract_memory_usage(&self, bytes: usize) {
252        let mut current = self.current_memory.lock();
253        *current = current.saturating_sub(bytes);
254    }
255
256    /// Find a node by path
257    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    /// Find a mutable reference to a node by path
280    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    /// Find parent node and return mutable reference
307    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    /// Normalize path for consistent handling
353    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        // Clear all data to free memory
395        *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
406/// File handle for TmpFS files
407struct TmpFileHandle {
408    path: String,
409    position: RwLock<u64>,
410    file_type: FileType,
411    device_guard: Option<BorrowedDeviceGuard>,
412    fs: *const TmpFS, // Weak reference to filesystem
413}
414
415// Safety: TmpFileHandle is safe to send between threads as long as the filesystem outlives it
416unsafe 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        // Handle device files
448        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        // Handle regular files
519        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); // EOF
527            }
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            // Update the node's access time in the filesystem
536            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        // Handle device files
551        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        // Handle regular files
616        let fs = self.get_fs();
617        let mut position = self.position.write();
618        
619        // Check memory limit before writing
620        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            // Expand file if necessary
627            if new_position > node.content.len() {
628                node.content.resize(new_position, 0);
629            }
630            
631            // Write data
632            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                    // Try to borrow the device from DeviceManager
712                    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                // Check if directory is empty
807                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                // Calculate memory to free
815                let memory_freed = node.content.len();
816                
817                // Remove the node
818                parent.children.remove(filename);
819                parent.metadata.modified_time = crate::time::current_time();
820                
821                // Update memory usage
822                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
852/// TmpFS driver for creating TmpFS instances
853pub 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  // TmpFS is a virtual filesystem
862    }
863    
864    fn create_from_block(&self, _block_device: Box<dyn BlockDevice>, _block_size: usize) -> Result<Box<dyn VirtualFileSystem>> {
865        // TmpFS doesn't use block devices, but we can create an instance with unlimited memory
866        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        // TmpFS doesn't need specific memory area, create with unlimited memory
871        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        // Try to downcast to TmpFSParams first
878        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        // Try to downcast to BasicFSParams for compatibility
883        if let Some(_basic_params) = params.as_any().downcast_ref::<BasicFSParams>() {
884            return Ok(Box::new(TmpFS::new(0))); // Unlimited memory for basic params
885        }
886        
887        // If all downcasts fail, return error
888        Err(FileSystemError {
889            kind: FileSystemErrorKind::NotSupported,
890            message: "TmpFS requires TmpFSParams or BasicFSParams parameter type".to_string(),
891        })
892    }
893}
894
895impl TmpFSDriver {
896    /// Create a new TmpFS with specified memory limit
897    pub fn create_with_limit(&self, max_memory: usize) -> Box<dyn VirtualFileSystem> {
898        Box::new(TmpFS::new(max_memory))
899    }
900    
901    /// Create a new TmpFS with unlimited memory
902    pub fn create_unlimited(&self) -> Box<dyn VirtualFileSystem> {
903        Box::new(TmpFS::new(0))
904    }
905}
906
907/// Register TmpFS driver with the filesystem driver manager
908pub 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
913// Auto-register the TmpFS driver when this module is loaded
914crate::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); // Unlimited memory
924        
925        // Test directory creation
926        tmpfs.create_dir("/test").unwrap();
927        
928        // Test file creation
929        tmpfs.create_file("/test/file.txt", FileType::RegularFile).unwrap();
930        
931        // Test file opening and writing
932        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        // Test file reading
938        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        // Test directory listing
945        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); // 100 bytes limit
954        
955        tmpfs.create_file("/test.txt", FileType::RegularFile).unwrap();
956        let file = tmpfs.open("/test.txt", 0).unwrap();
957        
958        // Write within limit
959        let small_data = b"Small";
960        assert!(file.write(small_data).is_ok());
961        
962        // Try to write beyond limit
963        let large_data = vec![0u8; 200];
964        assert!(file.write(&large_data).is_err());
965        
966        // Check memory usage
967        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        // Create a character device
975        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        // Create device file
980        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        // Test device file access
989        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        // Create nested directories
1001        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        // Test metadata
1006        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        // Test file removal
1012        tmpfs.remove("/home/user/document.txt").unwrap();
1013        assert!(tmpfs.open("/home/user/document.txt", 0).is_err());
1014        
1015        // Test directory removal (should fail if not empty)
1016        tmpfs.create_file("/home/user/another.txt", FileType::RegularFile).unwrap();
1017        assert!(tmpfs.remove("/home/user").is_err());
1018        
1019        // Remove file and then directory
1020        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); // 1KB limit
1028        
1029        // Create multiple files
1030        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]; // 50 bytes per file
1036            file.write(&data).unwrap();
1037        }
1038        
1039        // Should use 500 bytes
1040        assert_eq!(tmpfs.memory_usage(), 500);
1041        
1042        // Remove some files
1043        for i in 0..5 {
1044            let filename = format!("/file{}.txt", i);
1045            tmpfs.remove(&filename).unwrap();
1046        }
1047        
1048        // Should use 250 bytes now
1049        assert_eq!(tmpfs.memory_usage(), 250);
1050    }
1051
1052    #[test_case]
1053    fn test_tmpfs_large_file_operations() {
1054        let tmpfs = TmpFS::new(0); // Unlimited
1055        
1056        tmpfs.create_file("/large.bin", FileType::RegularFile).unwrap();
1057        let file = tmpfs.open("/large.bin", 0).unwrap();
1058        
1059        // Write large data
1060        let large_data = vec![0xAA; 8192]; // 8KB
1061        let bytes_written = file.write(&large_data).unwrap();
1062        assert_eq!(bytes_written, large_data.len());
1063        
1064        // Seek to middle and write
1065        file.seek(SeekFrom::Start(4096)).unwrap();
1066        let pattern = vec![0x55; 1024];
1067        file.write(&pattern).unwrap();
1068        
1069        // Read back and verify
1070        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        // Check file size
1077        let metadata = file.metadata().unwrap();
1078        assert_eq!(metadata.size, 8192);
1079    }
1080}