1use alloc::{collections::BTreeMap, string::String, sync::Arc, vec, vec::Vec};
8use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
9
10#[cfg(not(target_arch = "aarch64"))]
11use spin::RwLock;
12
13#[cfg(target_arch = "aarch64")]
14use super::bare_lock::RwLock;
15use super::{DirEntry, Filesystem, Metadata, NodeType, Permissions, VfsNode};
16use crate::error::{FsError, KernelError};
17
18static TMPFS_NEXT_INODE: AtomicU64 = AtomicU64::new(1);
20
21struct TmpNode {
23 node_type: NodeType,
24 data: RwLock<Vec<u8>>,
25 children: RwLock<BTreeMap<String, Arc<TmpNode>>>,
26 metadata: RwLock<Metadata>,
27 inode: u64,
28 parent_inode: u64,
29 bytes_used: Arc<AtomicUsize>,
31 size_limit: usize,
33}
34
35impl TmpNode {
36 fn new_file(
37 inode: u64,
38 parent_inode: u64,
39 permissions: Permissions,
40 bytes_used: Arc<AtomicUsize>,
41 size_limit: usize,
42 ) -> Self {
43 Self {
44 node_type: NodeType::File,
45 data: RwLock::new(Vec::new()),
46 children: RwLock::new(BTreeMap::new()),
47 metadata: RwLock::new(Metadata {
48 node_type: NodeType::File,
49 size: 0,
50 permissions,
51 uid: 0,
52 gid: 0,
53 created: crate::arch::timer::get_timestamp_secs(),
54 modified: crate::arch::timer::get_timestamp_secs(),
55 accessed: crate::arch::timer::get_timestamp_secs(),
56 inode,
57 }),
58 inode,
59 parent_inode,
60 bytes_used,
61 size_limit,
62 }
63 }
64
65 fn new_directory(
66 inode: u64,
67 parent_inode: u64,
68 permissions: Permissions,
69 bytes_used: Arc<AtomicUsize>,
70 size_limit: usize,
71 ) -> Self {
72 Self {
73 node_type: NodeType::Directory,
74 data: RwLock::new(Vec::new()),
75 children: RwLock::new(BTreeMap::new()),
76 metadata: RwLock::new(Metadata {
77 node_type: NodeType::Directory,
78 size: 0,
79 permissions,
80 uid: 0,
81 gid: 0,
82 created: crate::arch::timer::get_timestamp_secs(),
83 modified: crate::arch::timer::get_timestamp_secs(),
84 accessed: crate::arch::timer::get_timestamp_secs(),
85 inode,
86 }),
87 inode,
88 parent_inode,
89 bytes_used,
90 size_limit,
91 }
92 }
93
94 fn new_symlink(
95 inode: u64,
96 parent_inode: u64,
97 target: &str,
98 bytes_used: Arc<AtomicUsize>,
99 size_limit: usize,
100 ) -> Self {
101 let target_bytes = Vec::from(target.as_bytes());
102 let size = target_bytes.len();
103 Self {
104 node_type: NodeType::Symlink,
105 data: RwLock::new(target_bytes),
106 children: RwLock::new(BTreeMap::new()),
107 metadata: RwLock::new(Metadata {
108 node_type: NodeType::Symlink,
109 size,
110 permissions: Permissions::from_mode(0o777),
111 uid: 0,
112 gid: 0,
113 created: crate::arch::timer::get_timestamp_secs(),
114 modified: crate::arch::timer::get_timestamp_secs(),
115 accessed: crate::arch::timer::get_timestamp_secs(),
116 inode,
117 }),
118 inode,
119 parent_inode,
120 bytes_used,
121 size_limit,
122 }
123 }
124
125 fn check_space(&self, additional: usize) -> Result<(), KernelError> {
128 if self.size_limit == 0 {
129 return Ok(()); }
131 let current = self.bytes_used.load(Ordering::Relaxed);
132 if current.saturating_add(additional) > self.size_limit {
133 return Err(KernelError::FsError(FsError::NoSpace));
134 }
135 Ok(())
136 }
137}
138
139impl VfsNode for TmpNode {
140 fn node_type(&self) -> NodeType {
141 self.node_type
142 }
143
144 fn read(&self, offset: usize, buffer: &mut [u8]) -> Result<usize, KernelError> {
145 if self.node_type != NodeType::File {
146 return Err(KernelError::FsError(FsError::NotAFile));
147 }
148
149 let data = self.data.read();
150 if offset >= data.len() {
151 return Ok(0);
152 }
153
154 let bytes_to_read = core::cmp::min(buffer.len(), data.len() - offset);
155 buffer[..bytes_to_read].copy_from_slice(&data[offset..offset + bytes_to_read]);
156
157 self.metadata.write().accessed = crate::arch::timer::get_timestamp_secs();
158
159 Ok(bytes_to_read)
160 }
161
162 fn write(&self, offset: usize, data: &[u8]) -> Result<usize, KernelError> {
163 if self.node_type != NodeType::File {
164 return Err(KernelError::FsError(FsError::NotAFile));
165 }
166
167 let mut file_data = self.data.write();
168 let old_len = file_data.len();
169
170 let new_len = core::cmp::max(old_len, offset + data.len());
172 let growth = new_len.saturating_sub(old_len);
173
174 if growth > 0 {
176 self.check_space(growth)?;
177 }
178
179 if offset > file_data.len() {
181 file_data.resize(offset, 0);
182 }
183 if offset + data.len() > file_data.len() {
184 file_data.resize(offset + data.len(), 0);
185 }
186 file_data[offset..offset + data.len()].copy_from_slice(data);
187
188 if growth > 0 {
190 self.bytes_used.fetch_add(growth, Ordering::Relaxed);
191 }
192
193 let mut metadata = self.metadata.write();
194 metadata.size = file_data.len();
195 metadata.modified = crate::arch::timer::get_timestamp_secs();
196
197 Ok(data.len())
198 }
199
200 fn metadata(&self) -> Result<Metadata, KernelError> {
201 Ok(self.metadata.read().clone())
202 }
203
204 fn readdir(&self) -> Result<Vec<DirEntry>, KernelError> {
205 if self.node_type != NodeType::Directory {
206 return Err(KernelError::FsError(FsError::NotADirectory));
207 }
208
209 let children = self.children.read();
210 let mut entries = Vec::new();
211
212 entries.push(DirEntry {
213 name: String::from("."),
214 node_type: NodeType::Directory,
215 inode: self.inode,
216 });
217 entries.push(DirEntry {
218 name: String::from(".."),
219 node_type: NodeType::Directory,
220 inode: self.parent_inode,
221 });
222
223 for (name, child) in children.iter() {
224 entries.push(DirEntry {
225 name: name.clone(),
226 node_type: child.node_type,
227 inode: child.inode,
228 });
229 }
230
231 Ok(entries)
232 }
233
234 fn lookup(&self, name: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
235 if self.node_type != NodeType::Directory {
236 return Err(KernelError::FsError(FsError::NotADirectory));
237 }
238
239 let children = self.children.read();
240 children
241 .get(name)
242 .map(|node| node.clone() as Arc<dyn VfsNode>)
243 .ok_or(KernelError::FsError(FsError::NotFound))
244 }
245
246 fn create(
247 &self,
248 name: &str,
249 permissions: Permissions,
250 ) -> Result<Arc<dyn VfsNode>, KernelError> {
251 if self.node_type != NodeType::Directory {
252 return Err(KernelError::FsError(FsError::NotADirectory));
253 }
254
255 let mut children = self.children.write();
256 if children.contains_key(name) {
257 return Err(KernelError::FsError(FsError::AlreadyExists));
258 }
259
260 let inode = TMPFS_NEXT_INODE.fetch_add(1, Ordering::Relaxed);
261 let new_file = Arc::new(TmpNode::new_file(
262 inode,
263 self.inode,
264 permissions,
265 self.bytes_used.clone(),
266 self.size_limit,
267 ));
268 children.insert(String::from(name), new_file.clone());
269
270 Ok(new_file as Arc<dyn VfsNode>)
271 }
272
273 fn mkdir(&self, name: &str, permissions: Permissions) -> Result<Arc<dyn VfsNode>, KernelError> {
274 if self.node_type != NodeType::Directory {
275 return Err(KernelError::FsError(FsError::NotADirectory));
276 }
277
278 let mut children = self.children.write();
279 if children.contains_key(name) {
280 return Err(KernelError::FsError(FsError::AlreadyExists));
281 }
282
283 let inode = TMPFS_NEXT_INODE.fetch_add(1, Ordering::Relaxed);
284 let new_dir = Arc::new(TmpNode::new_directory(
285 inode,
286 self.inode,
287 permissions,
288 self.bytes_used.clone(),
289 self.size_limit,
290 ));
291 children.insert(String::from(name), new_dir.clone());
292
293 Ok(new_dir as Arc<dyn VfsNode>)
294 }
295
296 fn unlink(&self, name: &str) -> Result<(), KernelError> {
297 if self.node_type != NodeType::Directory {
298 return Err(KernelError::FsError(FsError::NotADirectory));
299 }
300
301 let mut children = self.children.write();
302
303 if let Some(node) = children.get(name) {
304 if node.node_type == NodeType::Directory {
305 let dir_children = node.children.read();
306 if !dir_children.is_empty() {
307 return Err(KernelError::FsError(FsError::DirectoryNotEmpty));
308 }
309 }
310
311 if node.node_type == NodeType::File {
313 let data = node.data.read();
314 let freed = data.len();
315 if freed > 0 {
316 let prev = self.bytes_used.fetch_sub(freed, Ordering::Relaxed);
318 if prev < freed {
320 self.bytes_used.store(0, Ordering::Relaxed);
321 }
322 }
323 }
324
325 children.remove(name);
326 Ok(())
327 } else {
328 Err(KernelError::FsError(FsError::NotFound))
329 }
330 }
331
332 fn truncate(&self, size: usize) -> Result<(), KernelError> {
333 if self.node_type != NodeType::File {
334 return Err(KernelError::FsError(FsError::NotAFile));
335 }
336
337 let mut data = self.data.write();
338 let old_len = data.len();
339
340 if size > old_len {
341 let growth = size - old_len;
343 self.check_space(growth)?;
344 data.resize(size, 0);
345 self.bytes_used.fetch_add(growth, Ordering::Relaxed);
346 } else if size < old_len {
347 let freed = old_len - size;
349 data.truncate(size);
350 let prev = self.bytes_used.fetch_sub(freed, Ordering::Relaxed);
351 if prev < freed {
352 self.bytes_used.store(0, Ordering::Relaxed);
353 }
354 }
355
356 let mut metadata = self.metadata.write();
357 metadata.size = size;
358 metadata.modified = crate::arch::timer::get_timestamp_secs();
359
360 Ok(())
361 }
362
363 fn link(&self, name: &str, target: Arc<dyn VfsNode>) -> Result<(), KernelError> {
364 if self.node_type != NodeType::Directory {
365 return Err(KernelError::FsError(FsError::NotADirectory));
366 }
367
368 if target.node_type() == NodeType::Directory {
369 return Err(KernelError::FsError(FsError::IsADirectory));
370 }
371
372 let mut children = self.children.write();
373 if children.contains_key(name) {
374 return Err(KernelError::FsError(FsError::AlreadyExists));
375 }
376
377 let target_meta = target.metadata()?;
379 let inode = target_meta.inode;
380
381 let new_node = Arc::new(TmpNode::new_file(
382 inode,
383 self.inode,
384 target_meta.permissions,
385 self.bytes_used.clone(),
386 self.size_limit,
387 ));
388
389 let mut buf = vec![0u8; target_meta.size];
390 if !buf.is_empty() {
391 let bytes_read = target.read(0, &mut buf)?;
392 buf.truncate(bytes_read);
393 }
394 if !buf.is_empty() {
395 new_node.write(0, &buf)?;
396 }
397
398 children.insert(String::from(name), new_node);
399 Ok(())
400 }
401
402 fn symlink(&self, name: &str, target: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
403 if self.node_type != NodeType::Directory {
404 return Err(KernelError::FsError(FsError::NotADirectory));
405 }
406
407 let mut children = self.children.write();
408 if children.contains_key(name) {
409 return Err(KernelError::FsError(FsError::AlreadyExists));
410 }
411
412 let inode = TMPFS_NEXT_INODE.fetch_add(1, Ordering::Relaxed);
413 let new_symlink = Arc::new(TmpNode::new_symlink(
414 inode,
415 self.inode,
416 target,
417 self.bytes_used.clone(),
418 self.size_limit,
419 ));
420 children.insert(String::from(name), new_symlink.clone());
421
422 Ok(new_symlink as Arc<dyn VfsNode>)
423 }
424
425 fn readlink(&self) -> Result<String, KernelError> {
426 if self.node_type != NodeType::Symlink {
427 return Err(KernelError::FsError(FsError::NotASymlink));
428 }
429
430 let data = self.data.read();
431 let s =
432 core::str::from_utf8(&data).map_err(|_| KernelError::FsError(FsError::InvalidPath))?;
433 Ok(String::from(s))
434 }
435
436 fn chmod(&self, permissions: Permissions) -> Result<(), KernelError> {
437 let mut metadata = self.metadata.write();
438 metadata.permissions = permissions;
439 metadata.modified = crate::arch::timer::get_timestamp_secs();
440 Ok(())
441 }
442}
443
444pub struct TmpFs {
446 root: Arc<TmpNode>,
447 bytes_used: Arc<AtomicUsize>,
449 size_limit: usize,
451}
452
453impl TmpFs {
454 pub fn new(size_limit: usize) -> Self {
457 let bytes_used = Arc::new(AtomicUsize::new(0));
458 let root_inode = TMPFS_NEXT_INODE.fetch_add(1, Ordering::Relaxed);
459 let root = Arc::new(TmpNode::new_directory(
460 root_inode,
461 root_inode,
462 Permissions::default(),
463 bytes_used.clone(),
464 size_limit,
465 ));
466
467 Self {
468 root,
469 bytes_used,
470 size_limit,
471 }
472 }
473
474 pub fn bytes_used(&self) -> usize {
476 self.bytes_used.load(Ordering::Relaxed)
477 }
478
479 pub fn size_limit(&self) -> usize {
481 self.size_limit
482 }
483}
484
485impl Default for TmpFs {
486 fn default() -> Self {
487 Self::new(128 * 1024 * 1024)
489 }
490}
491
492impl Filesystem for TmpFs {
493 fn root(&self) -> Arc<dyn VfsNode> {
494 self.root.clone() as Arc<dyn VfsNode>
495 }
496
497 fn name(&self) -> &str {
498 "tmpfs"
499 }
500
501 fn is_readonly(&self) -> bool {
502 false
503 }
504
505 fn sync(&self) -> Result<(), KernelError> {
506 Ok(())
508 }
509}
510
511#[cfg(test)]
512mod tests {
513 use alloc::vec;
514
515 use super::*;
516
517 #[test]
518 fn test_tmpfs_new() {
519 let fs = TmpFs::new(1024 * 1024);
520 assert_eq!(fs.name(), "tmpfs");
521 assert!(!fs.is_readonly());
522 assert_eq!(fs.size_limit(), 1024 * 1024);
523 assert_eq!(fs.bytes_used(), 0);
524 }
525
526 #[test]
527 fn test_tmpfs_default() {
528 let fs = TmpFs::default();
529 assert_eq!(fs.size_limit(), 128 * 1024 * 1024);
530 }
531
532 #[test]
533 fn test_tmpfs_root_is_directory() {
534 let fs = TmpFs::new(0);
535 let root = fs.root();
536 assert_eq!(root.node_type(), NodeType::Directory);
537 }
538
539 #[test]
540 fn test_tmpfs_sync() {
541 let fs = TmpFs::new(0);
542 assert!(fs.sync().is_ok());
543 }
544
545 #[test]
546 fn test_create_and_read_file() {
547 let fs = TmpFs::new(0);
548 let root = fs.root();
549
550 let file = root.create("test.txt", Permissions::default()).unwrap();
551 assert_eq!(file.node_type(), NodeType::File);
552
553 file.write(0, b"Hello, tmpfs!").unwrap();
554 assert_eq!(fs.bytes_used(), 13);
555
556 let mut buf = vec![0u8; 20];
557 let n = file.read(0, &mut buf).unwrap();
558 assert_eq!(n, 13);
559 assert_eq!(&buf[..13], b"Hello, tmpfs!");
560 }
561
562 #[test]
563 fn test_size_limit_enforcement() {
564 let fs = TmpFs::new(10); let root = fs.root();
566
567 let file = root.create("big.txt", Permissions::default()).unwrap();
568
569 assert!(file.write(0, b"12345678").is_ok());
571 assert_eq!(fs.bytes_used(), 8);
572
573 let result = file.write(8, b"abcde");
575 assert!(result.is_err());
576 assert_eq!(result.unwrap_err(), KernelError::FsError(FsError::NoSpace));
577
578 assert_eq!(fs.bytes_used(), 8);
580 }
581
582 #[test]
583 fn test_truncate_reclaims_space() {
584 let fs = TmpFs::new(100);
585 let root = fs.root();
586
587 let file = root.create("shrink.txt", Permissions::default()).unwrap();
588 file.write(0, b"0123456789").unwrap();
589 assert_eq!(fs.bytes_used(), 10);
590
591 file.truncate(3).unwrap();
592 assert_eq!(fs.bytes_used(), 3);
593
594 let meta = file.metadata().unwrap();
595 assert_eq!(meta.size, 3);
596 }
597
598 #[test]
599 fn test_truncate_grow_checks_space() {
600 let fs = TmpFs::new(10);
601 let root = fs.root();
602
603 let file = root.create("grow.txt", Permissions::default()).unwrap();
604 file.write(0, b"12345").unwrap();
605 assert_eq!(fs.bytes_used(), 5);
606
607 assert!(file.truncate(10).is_ok());
609 assert_eq!(fs.bytes_used(), 10);
610
611 let result = file.truncate(11);
613 assert!(result.is_err());
614 }
615
616 #[test]
617 fn test_unlink_reclaims_space() {
618 let fs = TmpFs::new(100);
619 let root = fs.root();
620
621 let file = root.create("temp.txt", Permissions::default()).unwrap();
622 file.write(0, b"some data").unwrap();
623 assert_eq!(fs.bytes_used(), 9);
624
625 root.unlink("temp.txt").unwrap();
626 assert_eq!(fs.bytes_used(), 0);
627 }
628
629 #[test]
630 fn test_mkdir_and_readdir() {
631 let fs = TmpFs::new(0);
632 let root = fs.root();
633
634 root.mkdir("subdir", Permissions::default()).unwrap();
635 root.create("file.txt", Permissions::default()).unwrap();
636
637 let entries = root.readdir().unwrap();
638 assert_eq!(entries.len(), 4); let names: Vec<&str> = entries.iter().map(|e| e.name.as_str()).collect();
641 assert!(names.contains(&"."));
642 assert!(names.contains(&".."));
643 assert!(names.contains(&"subdir"));
644 assert!(names.contains(&"file.txt"));
645 }
646
647 #[test]
648 fn test_nested_directories() {
649 let fs = TmpFs::new(0);
650 let root = fs.root();
651
652 let sub = root.mkdir("a", Permissions::default()).unwrap();
653 let subsub = sub.mkdir("b", Permissions::default()).unwrap();
654 let file = subsub.create("c.txt", Permissions::default()).unwrap();
655 file.write(0, b"nested").unwrap();
656
657 let a = root.lookup("a").unwrap();
659 let b = a.lookup("b").unwrap();
660 let c = b.lookup("c.txt").unwrap();
661
662 let mut buf = vec![0u8; 10];
663 let n = c.read(0, &mut buf).unwrap();
664 assert_eq!(&buf[..n], b"nested");
665 }
666
667 #[test]
668 fn test_symlink() {
669 let fs = TmpFs::new(0);
670 let root = fs.root();
671
672 let link = root.symlink("mylink", "/tmp/target").unwrap();
673 assert_eq!(link.node_type(), NodeType::Symlink);
674
675 let target = link.readlink().unwrap();
676 assert_eq!(target, "/tmp/target");
677 }
678
679 #[test]
680 fn test_unlink_nonempty_dir_fails() {
681 let fs = TmpFs::new(0);
682 let root = fs.root();
683
684 let dir = root.mkdir("occupied", Permissions::default()).unwrap();
685 dir.create("child", Permissions::default()).unwrap();
686
687 let result = root.unlink("occupied");
688 assert!(result.is_err());
689 assert_eq!(
690 result.unwrap_err(),
691 KernelError::FsError(FsError::DirectoryNotEmpty)
692 );
693 }
694
695 #[test]
696 fn test_chmod() {
697 let fs = TmpFs::new(0);
698 let root = fs.root();
699
700 let file = root.create("perm.txt", Permissions::default()).unwrap();
701 let ro = Permissions::read_only();
702 assert!(file.chmod(ro).is_ok());
703
704 let meta = file.metadata().unwrap();
705 assert!(meta.permissions.owner_read);
706 assert!(!meta.permissions.owner_write);
707 }
708
709 #[test]
710 fn test_multiple_files_share_limit() {
711 let fs = TmpFs::new(20);
712 let root = fs.root();
713
714 let f1 = root.create("a.txt", Permissions::default()).unwrap();
715 let f2 = root.create("b.txt", Permissions::default()).unwrap();
716
717 f1.write(0, b"1234567890").unwrap(); f2.write(0, b"1234567890").unwrap(); let result = f1.write(10, b"x");
722 assert!(result.is_err());
723 }
724}