1#![allow(dead_code)]
11
12use alloc::{collections::BTreeMap, string::String, sync::Arc, vec, vec::Vec};
13use core::sync::atomic::{AtomicU64, Ordering};
14
15#[cfg(not(target_arch = "aarch64"))]
16use spin::RwLock;
17
18#[cfg(target_arch = "aarch64")]
19use super::bare_lock::RwLock;
20use super::{DirEntry, Filesystem, Metadata, NodeType, Permissions, VfsNode};
21use crate::error::{FsError, KernelError};
22
23const FAT32_EOC: u32 = 0x0FFF_FFF8;
25
26const FAT32_FREE: u32 = 0x0000_0000;
28
29const DIR_ENTRY_SIZE: usize = 32;
31
32const ATTR_READ_ONLY: u8 = 0x01;
34const ATTR_HIDDEN: u8 = 0x02;
35const ATTR_SYSTEM: u8 = 0x04;
36const ATTR_DIRECTORY: u8 = 0x10;
37const ATTR_LONG_NAME: u8 = 0x0F;
38
39#[derive(Debug, Clone)]
41pub struct Bpb {
42 pub bytes_per_sector: u16,
43 pub sectors_per_cluster: u8,
44 pub reserved_sectors: u16,
45 pub num_fats: u8,
46 pub total_sectors_32: u32,
47 pub fat_size_32: u32,
48 pub root_cluster: u32,
49 pub fs_info_sector: u16,
50}
51
52impl Bpb {
53 pub fn parse(sector: &[u8]) -> Result<Self, KernelError> {
55 if sector.len() < 512 {
56 return Err(KernelError::FsError(FsError::CorruptedData));
57 }
58
59 if sector[510] != 0x55 || sector[511] != 0xAA {
61 return Err(KernelError::FsError(FsError::CorruptedData));
62 }
63
64 let bytes_per_sector = u16::from_le_bytes([sector[11], sector[12]]);
65 let sectors_per_cluster = sector[13];
66 let reserved_sectors = u16::from_le_bytes([sector[14], sector[15]]);
67 let num_fats = sector[16];
68 let total_sectors_32 = u32::from_le_bytes([sector[32], sector[33], sector[34], sector[35]]);
69 let fat_size_32 = u32::from_le_bytes([sector[36], sector[37], sector[38], sector[39]]);
70 let root_cluster = u32::from_le_bytes([sector[44], sector[45], sector[46], sector[47]]);
71 let fs_info_sector = u16::from_le_bytes([sector[48], sector[49]]);
72
73 if bytes_per_sector == 0 || sectors_per_cluster == 0 || num_fats == 0 {
74 return Err(KernelError::FsError(FsError::CorruptedData));
75 }
76
77 Ok(Self {
78 bytes_per_sector,
79 sectors_per_cluster,
80 reserved_sectors,
81 num_fats,
82 total_sectors_32,
83 fat_size_32,
84 root_cluster,
85 fs_info_sector,
86 })
87 }
88
89 fn data_start_sector(&self) -> u32 {
91 self.reserved_sectors as u32 + (self.num_fats as u32 * self.fat_size_32)
92 }
93
94 fn cluster_to_sector(&self, cluster: u32) -> u32 {
96 self.data_start_sector() + (cluster - 2) * self.sectors_per_cluster as u32
97 }
98
99 fn cluster_size(&self) -> usize {
101 self.bytes_per_sector as usize * self.sectors_per_cluster as usize
102 }
103
104 fn fat_sector_for_cluster(&self, cluster: u32) -> u32 {
106 let fat_offset = cluster * 4;
107 self.reserved_sectors as u32 + fat_offset / self.bytes_per_sector as u32
108 }
109
110 fn fat_offset_in_sector(&self, cluster: u32) -> usize {
112 ((cluster * 4) % self.bytes_per_sector as u32) as usize
113 }
114}
115
116struct FatTable {
118 entries: Vec<u32>,
120}
121
122impl FatTable {
123 fn new(num_clusters: usize) -> Self {
124 Self {
125 entries: vec![0u32; num_clusters],
126 }
127 }
128
129 fn get(&self, cluster: u32) -> u32 {
130 if (cluster as usize) < self.entries.len() {
131 self.entries[cluster as usize] & 0x0FFF_FFFF
132 } else {
133 FAT32_EOC
134 }
135 }
136
137 fn set(&mut self, cluster: u32, value: u32) {
138 if (cluster as usize) < self.entries.len() {
139 self.entries[cluster as usize] = value & 0x0FFF_FFFF;
140 }
141 }
142
143 fn alloc_cluster(&mut self, hint: u32) -> Option<u32> {
145 let start = core::cmp::max(hint as usize, 2);
146 for i in start..self.entries.len() {
148 if self.entries[i] == FAT32_FREE {
149 self.entries[i] = FAT32_EOC;
150 return Some(i as u32);
151 }
152 }
153 for i in 2..start {
155 if self.entries[i] == FAT32_FREE {
156 self.entries[i] = FAT32_EOC;
157 return Some(i as u32);
158 }
159 }
160 None
161 }
162
163 fn free_chain(&mut self, start: u32) {
165 let mut current = start;
166 while (2..FAT32_EOC).contains(¤t) {
167 let next = self.get(current);
168 self.entries[current as usize] = FAT32_FREE;
169 if next >= FAT32_EOC {
170 break;
171 }
172 current = next;
173 }
174 }
175
176 fn get_chain(&self, start: u32) -> Vec<u32> {
178 let mut chain = Vec::new();
179 let mut current = start;
180 while (2..FAT32_EOC).contains(¤t) {
181 chain.push(current);
182 let next = self.get(current);
183 if next >= FAT32_EOC || chain.len() > 1_000_000 {
184 break;
185 }
186 current = next;
187 }
188 chain
189 }
190}
191
192#[derive(Debug, Clone, Copy)]
194#[repr(C, packed)]
195struct RawDirEntry {
196 name: [u8; 11],
197 attr: u8,
198 _nt_reserved: u8,
199 create_time_tenth: u8,
200 create_time: u16,
201 create_date: u16,
202 access_date: u16,
203 first_cluster_hi: u16,
204 write_time: u16,
205 write_date: u16,
206 first_cluster_lo: u16,
207 file_size: u32,
208}
209
210impl RawDirEntry {
211 fn first_cluster(&self) -> u32 {
212 ((self.first_cluster_hi as u32) << 16) | self.first_cluster_lo as u32
213 }
214
215 fn is_free(&self) -> bool {
216 self.name[0] == 0xE5 || self.name[0] == 0x00
217 }
218
219 fn is_end(&self) -> bool {
220 self.name[0] == 0x00
221 }
222
223 fn is_long_name(&self) -> bool {
224 self.attr == ATTR_LONG_NAME
225 }
226
227 fn is_directory(&self) -> bool {
228 (self.attr & ATTR_DIRECTORY) != 0
229 }
230
231 fn short_name(&self) -> String {
232 let name_part: Vec<u8> = self.name[..8]
233 .iter()
234 .copied()
235 .take_while(|&b| b != b' ')
236 .collect();
237 let ext_part: Vec<u8> = self.name[8..11]
238 .iter()
239 .copied()
240 .take_while(|&b| b != b' ')
241 .collect();
242
243 let mut result = String::new();
244 for &b in &name_part {
245 result.push(b as char);
246 }
247 if !ext_part.is_empty() {
248 result.push('.');
249 for &b in &ext_part {
250 result.push(b as char);
251 }
252 }
253 result
254 }
255}
256
257#[derive(Debug, Clone, Copy)]
259#[repr(C, packed)]
260struct LfnDirEntry {
261 order: u8,
262 name1: [u16; 5],
263 attr: u8,
264 entry_type: u8,
265 checksum: u8,
266 name2: [u16; 6],
267 _first_cluster_lo: u16,
268 name3: [u16; 2],
269}
270
271impl LfnDirEntry {
272 fn chars(&self) -> Vec<u16> {
275 let mut chars = Vec::new();
276
277 let name1: [u16; 5] = unsafe { core::ptr::read_unaligned(core::ptr::addr_of!(self.name1)) };
281 let name2: [u16; 6] = unsafe { core::ptr::read_unaligned(core::ptr::addr_of!(self.name2)) };
282 let name3: [u16; 2] = unsafe { core::ptr::read_unaligned(core::ptr::addr_of!(self.name3)) };
283
284 for &c in &name1 {
285 if c == 0x0000 || c == 0xFFFF {
286 return chars;
287 }
288 chars.push(c);
289 }
290 for &c in &name2 {
291 if c == 0x0000 || c == 0xFFFF {
292 return chars;
293 }
294 chars.push(c);
295 }
296 for &c in &name3 {
297 if c == 0x0000 || c == 0xFFFF {
298 return chars;
299 }
300 chars.push(c);
301 }
302 chars
303 }
304}
305
306static FAT32_NEXT_INODE: AtomicU64 = AtomicU64::new(1);
308
309struct Fat32Node {
311 node_type: NodeType,
312 data: RwLock<Vec<u8>>,
314 children: RwLock<BTreeMap<String, Arc<Fat32Node>>>,
316 metadata: RwLock<Metadata>,
317 inode: u64,
318 parent_inode: u64,
319 start_cluster: RwLock<u32>,
321 fs_state: Arc<RwLock<Fat32State>>,
323}
324
325struct Fat32State {
327 bpb: Bpb,
328 fat: FatTable,
329 sector_cache: BTreeMap<u64, Vec<u8>>,
331 dirty: bool,
333 next_free_hint: u32,
335}
336
337impl Fat32State {
338 fn read_cluster(&self, cluster: u32) -> Vec<u8> {
340 let sector = self.bpb.cluster_to_sector(cluster);
341 let cluster_size = self.bpb.cluster_size();
342 let mut data = vec![0u8; cluster_size];
343
344 let sectors_per_cluster = self.bpb.sectors_per_cluster as u32;
345 for i in 0..sectors_per_cluster {
346 let sec = (sector + i) as u64;
347 if let Some(cached) = self.sector_cache.get(&sec) {
348 let offset = i as usize * self.bpb.bytes_per_sector as usize;
349 let len = core::cmp::min(cached.len(), self.bpb.bytes_per_sector as usize);
350 data[offset..offset + len].copy_from_slice(&cached[..len]);
351 }
352 }
353 data
354 }
355
356 fn write_cluster(&mut self, cluster: u32, data: &[u8]) {
358 let sector = self.bpb.cluster_to_sector(cluster);
359 let bps = self.bpb.bytes_per_sector as usize;
360 let sectors_per_cluster = self.bpb.sectors_per_cluster as u32;
361
362 for i in 0..sectors_per_cluster {
363 let sec = (sector + i) as u64;
364 let offset = i as usize * bps;
365 let end = core::cmp::min(offset + bps, data.len());
366 if offset < data.len() {
367 self.sector_cache.insert(sec, data[offset..end].to_vec());
368 }
369 }
370 self.dirty = true;
371 }
372
373 fn read_chain_data(&self, start_cluster: u32, size: usize) -> Vec<u8> {
375 let chain = self.fat.get_chain(start_cluster);
376 let mut data = Vec::with_capacity(size);
377
378 for &cluster in &chain {
379 let cluster_data = self.read_cluster(cluster);
380 let remaining = size.saturating_sub(data.len());
381 let take = core::cmp::min(remaining, cluster_data.len());
382 data.extend_from_slice(&cluster_data[..take]);
383 if data.len() >= size {
384 break;
385 }
386 }
387 data
388 }
389
390 fn write_data(&mut self, start_cluster: u32, data: &[u8]) -> Result<u32, KernelError> {
392 let cluster_size = self.bpb.cluster_size();
393 let clusters_needed = if data.is_empty() {
394 0
395 } else {
396 data.len().div_ceil(cluster_size)
397 };
398
399 if start_cluster >= 2 {
401 self.fat.free_chain(start_cluster);
402 }
403
404 if clusters_needed == 0 {
405 return Ok(0);
406 }
407
408 let mut chain = Vec::with_capacity(clusters_needed);
410 for _ in 0..clusters_needed {
411 let cluster = self
412 .fat
413 .alloc_cluster(self.next_free_hint)
414 .ok_or(KernelError::FsError(FsError::NoSpace))?;
415 self.next_free_hint = cluster + 1;
416 chain.push(cluster);
417 }
418
419 for i in 0..chain.len() - 1 {
421 self.fat.set(chain[i], chain[i + 1]);
422 }
423 for (i, &cluster) in chain.iter().enumerate() {
427 let offset = i * cluster_size;
428 let end = core::cmp::min(offset + cluster_size, data.len());
429 let mut cluster_buf = vec![0u8; cluster_size];
430 cluster_buf[..end - offset].copy_from_slice(&data[offset..end]);
431 self.write_cluster(cluster, &cluster_buf);
432 }
433
434 Ok(chain[0])
435 }
436
437 fn parse_dir_entries(&self, dir_data: &[u8]) -> Vec<(String, u32, u32, u8)> {
439 let mut entries = Vec::new();
440 let mut lfn_parts: Vec<(u8, Vec<u16>)> = Vec::new();
441 let entry_count = dir_data.len() / DIR_ENTRY_SIZE;
442
443 for i in 0..entry_count {
444 let offset = i * DIR_ENTRY_SIZE;
445 let entry_bytes = &dir_data[offset..offset + DIR_ENTRY_SIZE];
446
447 if entry_bytes[0] == 0x00 {
448 break; }
450 if entry_bytes[0] == 0xE5 {
451 lfn_parts.clear();
452 continue; }
454
455 let attr = entry_bytes[11];
456
457 if attr == ATTR_LONG_NAME {
458 let lfn = unsafe { &*(entry_bytes.as_ptr() as *const LfnDirEntry) };
461 let order = lfn.order & 0x3F;
462 lfn_parts.push((order, lfn.chars()));
463 continue;
464 }
465
466 let raw = unsafe { &*(entry_bytes.as_ptr() as *const RawDirEntry) };
469
470 let name = if !lfn_parts.is_empty() {
472 lfn_parts.sort_by_key(|(order, _)| *order);
473 let mut chars: Vec<u16> = Vec::new();
474 for (_, part) in &lfn_parts {
475 chars.extend_from_slice(part);
476 }
477 lfn_parts.clear();
478
479 let mut name = String::new();
481 for &c in &chars {
482 if c == 0 {
483 break;
484 }
485 if c < 128 {
486 name.push(c as u8 as char);
487 } else {
488 name.push('?'); }
490 }
491 name
492 } else {
493 lfn_parts.clear();
494 raw.short_name()
495 };
496
497 if name == "." || name == ".." {
499 continue;
500 }
501
502 entries.push((name, raw.first_cluster(), raw.file_size, raw.attr));
503 }
504
505 entries
506 }
507}
508
509impl Fat32Node {
510 fn new_file(
511 inode: u64,
512 parent_inode: u64,
513 start_cluster: u32,
514 size: usize,
515 fs_state: Arc<RwLock<Fat32State>>,
516 ) -> Self {
517 Self {
518 node_type: NodeType::File,
519 data: RwLock::new(Vec::new()),
520 children: RwLock::new(BTreeMap::new()),
521 metadata: RwLock::new(Metadata {
522 node_type: NodeType::File,
523 size,
524 permissions: Permissions::default(),
525 uid: 0,
526 gid: 0,
527 created: 0,
528 modified: 0,
529 accessed: 0,
530 inode,
531 }),
532 inode,
533 parent_inode,
534 start_cluster: RwLock::new(start_cluster),
535 fs_state,
536 }
537 }
538
539 fn new_directory(
540 inode: u64,
541 parent_inode: u64,
542 start_cluster: u32,
543 fs_state: Arc<RwLock<Fat32State>>,
544 ) -> Self {
545 Self {
546 node_type: NodeType::Directory,
547 data: RwLock::new(Vec::new()),
548 children: RwLock::new(BTreeMap::new()),
549 metadata: RwLock::new(Metadata {
550 node_type: NodeType::Directory,
551 size: 0,
552 permissions: Permissions::default(),
553 uid: 0,
554 gid: 0,
555 created: 0,
556 modified: 0,
557 accessed: 0,
558 inode,
559 }),
560 inode,
561 parent_inode,
562 start_cluster: RwLock::new(start_cluster),
563 fs_state,
564 }
565 }
566
567 fn ensure_children_loaded(&self) {
569 if self.node_type != NodeType::Directory {
570 return;
571 }
572
573 {
574 let children = self.children.read();
575 if !children.is_empty() {
578 return;
579 }
580 }
581
582 let start = *self.start_cluster.read();
583 if start < 2 {
584 return;
585 }
586
587 let parsed = {
588 let state = self.fs_state.read();
589 let dir_data = state.read_chain_data(start, 1024 * 1024); state.parse_dir_entries(&dir_data)
591 };
592
593 let mut children = self.children.write();
594 for (name, cluster, size, attr) in parsed {
595 let inode = FAT32_NEXT_INODE.fetch_add(1, Ordering::Relaxed);
596 let node = if (attr & ATTR_DIRECTORY) != 0 {
597 Arc::new(Fat32Node::new_directory(
598 inode,
599 self.inode,
600 cluster,
601 self.fs_state.clone(),
602 ))
603 } else {
604 Arc::new(Fat32Node::new_file(
605 inode,
606 self.inode,
607 cluster,
608 size as usize,
609 self.fs_state.clone(),
610 ))
611 };
612 children.insert(name, node);
613 }
614 }
615}
616
617impl VfsNode for Fat32Node {
618 fn node_type(&self) -> NodeType {
619 self.node_type
620 }
621
622 fn read(&self, offset: usize, buffer: &mut [u8]) -> Result<usize, KernelError> {
623 if self.node_type != NodeType::File {
624 return Err(KernelError::FsError(FsError::NotAFile));
625 }
626
627 let meta = self.metadata.read();
628 if offset >= meta.size {
629 return Ok(0);
630 }
631
632 let start = *self.start_cluster.read();
633 let file_data = {
634 let state = self.fs_state.read();
635 state.read_chain_data(start, meta.size)
636 };
637
638 let bytes_to_read = core::cmp::min(buffer.len(), file_data.len().saturating_sub(offset));
639 buffer[..bytes_to_read].copy_from_slice(&file_data[offset..offset + bytes_to_read]);
640
641 Ok(bytes_to_read)
642 }
643
644 fn write(&self, offset: usize, data: &[u8]) -> Result<usize, KernelError> {
645 if self.node_type != NodeType::File {
646 return Err(KernelError::FsError(FsError::NotAFile));
647 }
648
649 let old_start = *self.start_cluster.read();
651 let old_size = self.metadata.read().size;
652
653 let mut file_data = {
654 let state = self.fs_state.read();
655 if old_start >= 2 && old_size > 0 {
656 state.read_chain_data(old_start, old_size)
657 } else {
658 Vec::new()
659 }
660 };
661
662 if offset > file_data.len() {
664 file_data.resize(offset, 0);
665 }
666 let new_end = offset + data.len();
667 if new_end > file_data.len() {
668 file_data.resize(new_end, 0);
669 }
670 file_data[offset..new_end].copy_from_slice(data);
671
672 let new_cluster = {
674 let mut state = self.fs_state.write();
675 state.write_data(old_start, &file_data)?
676 };
677
678 *self.start_cluster.write() = new_cluster;
679 let mut meta = self.metadata.write();
680 meta.size = file_data.len();
681 meta.modified = crate::arch::timer::get_timestamp_secs();
682
683 Ok(data.len())
684 }
685
686 fn metadata(&self) -> Result<Metadata, KernelError> {
687 Ok(self.metadata.read().clone())
688 }
689
690 fn readdir(&self) -> Result<Vec<DirEntry>, KernelError> {
691 if self.node_type != NodeType::Directory {
692 return Err(KernelError::FsError(FsError::NotADirectory));
693 }
694
695 self.ensure_children_loaded();
696
697 let children = self.children.read();
698 let mut entries = Vec::new();
699
700 entries.push(DirEntry {
701 name: String::from("."),
702 node_type: NodeType::Directory,
703 inode: self.inode,
704 });
705 entries.push(DirEntry {
706 name: String::from(".."),
707 node_type: NodeType::Directory,
708 inode: self.parent_inode,
709 });
710
711 for (name, child) in children.iter() {
712 entries.push(DirEntry {
713 name: name.clone(),
714 node_type: child.node_type,
715 inode: child.inode,
716 });
717 }
718
719 Ok(entries)
720 }
721
722 fn lookup(&self, name: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
723 if self.node_type != NodeType::Directory {
724 return Err(KernelError::FsError(FsError::NotADirectory));
725 }
726
727 self.ensure_children_loaded();
728
729 let children = self.children.read();
730 children
731 .get(name)
732 .map(|node| node.clone() as Arc<dyn VfsNode>)
733 .ok_or(KernelError::FsError(FsError::NotFound))
734 }
735
736 fn create(
737 &self,
738 name: &str,
739 permissions: Permissions,
740 ) -> Result<Arc<dyn VfsNode>, KernelError> {
741 if self.node_type != NodeType::Directory {
742 return Err(KernelError::FsError(FsError::NotADirectory));
743 }
744
745 self.ensure_children_loaded();
746
747 let mut children = self.children.write();
748 if children.contains_key(name) {
749 return Err(KernelError::FsError(FsError::AlreadyExists));
750 }
751
752 let inode = FAT32_NEXT_INODE.fetch_add(1, Ordering::Relaxed);
753 let new_file = Arc::new(Fat32Node::new_file(
754 inode,
755 self.inode,
756 0, 0,
758 self.fs_state.clone(),
759 ));
760 new_file.metadata.write().permissions = permissions;
762 children.insert(String::from(name), new_file.clone());
763
764 Ok(new_file as Arc<dyn VfsNode>)
765 }
766
767 fn mkdir(&self, name: &str, permissions: Permissions) -> Result<Arc<dyn VfsNode>, KernelError> {
768 if self.node_type != NodeType::Directory {
769 return Err(KernelError::FsError(FsError::NotADirectory));
770 }
771
772 self.ensure_children_loaded();
773
774 let mut children = self.children.write();
775 if children.contains_key(name) {
776 return Err(KernelError::FsError(FsError::AlreadyExists));
777 }
778
779 let cluster = {
781 let mut state = self.fs_state.write();
782 let hint = state.next_free_hint;
783 let cluster = state
784 .fat
785 .alloc_cluster(hint)
786 .ok_or(KernelError::FsError(FsError::NoSpace))?;
787 state.next_free_hint = cluster + 1;
788
789 let cluster_size = state.bpb.cluster_size();
791 let empty = vec![0u8; cluster_size];
792 state.write_cluster(cluster, &empty);
793 state.dirty = true;
794 cluster
795 };
796
797 let inode = FAT32_NEXT_INODE.fetch_add(1, Ordering::Relaxed);
798 let new_dir = Arc::new(Fat32Node::new_directory(
799 inode,
800 self.inode,
801 cluster,
802 self.fs_state.clone(),
803 ));
804 new_dir.metadata.write().permissions = permissions;
805 children.insert(String::from(name), new_dir.clone());
806
807 Ok(new_dir as Arc<dyn VfsNode>)
808 }
809
810 fn unlink(&self, name: &str) -> Result<(), KernelError> {
811 if self.node_type != NodeType::Directory {
812 return Err(KernelError::FsError(FsError::NotADirectory));
813 }
814
815 self.ensure_children_loaded();
816
817 let mut children = self.children.write();
818
819 if let Some(node) = children.get(name) {
820 if node.node_type == NodeType::Directory {
821 let node_children = node.children.read();
822 if !node_children.is_empty() {
823 return Err(KernelError::FsError(FsError::DirectoryNotEmpty));
824 }
825 }
826
827 let start = *node.start_cluster.read();
829 if start >= 2 {
830 let mut state = self.fs_state.write();
831 state.fat.free_chain(start);
832 state.dirty = true;
833 }
834
835 children.remove(name);
836 Ok(())
837 } else {
838 Err(KernelError::FsError(FsError::NotFound))
839 }
840 }
841
842 fn truncate(&self, size: usize) -> Result<(), KernelError> {
843 if self.node_type != NodeType::File {
844 return Err(KernelError::FsError(FsError::NotAFile));
845 }
846
847 let old_start = *self.start_cluster.read();
848 let old_size = self.metadata.read().size;
849
850 if size == 0 {
851 if old_start >= 2 {
853 let mut state = self.fs_state.write();
854 state.fat.free_chain(old_start);
855 state.dirty = true;
856 }
857 *self.start_cluster.write() = 0;
858 } else if size != old_size {
859 let mut data = {
861 let state = self.fs_state.read();
862 state.read_chain_data(old_start, old_size)
863 };
864
865 data.resize(size, 0);
866 let new_cluster = {
867 let mut state = self.fs_state.write();
868 state.write_data(old_start, &data)?
869 };
870 *self.start_cluster.write() = new_cluster;
871 }
872
873 let mut meta = self.metadata.write();
874 meta.size = size;
875 meta.modified = crate::arch::timer::get_timestamp_secs();
876
877 Ok(())
878 }
879}
880
881pub struct Fat32Fs {
883 root: Arc<Fat32Node>,
884 state: Arc<RwLock<Fat32State>>,
885 readonly: bool,
886}
887
888impl Fat32Fs {
889 pub fn from_image(image_data: &[u8], readonly: bool) -> Result<Self, KernelError> {
894 if image_data.len() < 512 {
895 return Err(KernelError::FsError(FsError::CorruptedData));
896 }
897
898 let bpb = Bpb::parse(&image_data[..512])?;
899 let bps = bpb.bytes_per_sector as usize;
900
901 let fat_start = bpb.reserved_sectors as usize * bps;
903 let fat_size_bytes = bpb.fat_size_32 as usize * bps;
904 let total_data_sectors = bpb.total_sectors_32 as usize - bpb.data_start_sector() as usize;
905 let total_clusters = total_data_sectors / bpb.sectors_per_cluster as usize + 2;
906
907 let mut fat = FatTable::new(total_clusters);
908 if fat_start + fat_size_bytes <= image_data.len() {
909 let fat_data = &image_data[fat_start..fat_start + fat_size_bytes];
910 for i in 0..core::cmp::min(total_clusters, fat_data.len() / 4) {
911 fat.entries[i] = u32::from_le_bytes([
912 fat_data[i * 4],
913 fat_data[i * 4 + 1],
914 fat_data[i * 4 + 2],
915 fat_data[i * 4 + 3],
916 ]);
917 }
918 }
919
920 let mut sector_cache = BTreeMap::new();
922 let total_sectors = image_data.len() / bps;
923 for s in 0..total_sectors {
924 let offset = s * bps;
925 let end = core::cmp::min(offset + bps, image_data.len());
926 sector_cache.insert(s as u64, image_data[offset..end].to_vec());
927 }
928
929 let state = Arc::new(RwLock::new(Fat32State {
930 bpb: bpb.clone(),
931 fat,
932 sector_cache,
933 dirty: false,
934 next_free_hint: 2,
935 }));
936
937 let root_inode = FAT32_NEXT_INODE.fetch_add(1, Ordering::Relaxed);
938 let root = Arc::new(Fat32Node::new_directory(
939 root_inode,
940 root_inode,
941 bpb.root_cluster,
942 state.clone(),
943 ));
944
945 Ok(Self {
946 root,
947 state,
948 readonly,
949 })
950 }
951}
952
953impl Filesystem for Fat32Fs {
954 fn root(&self) -> Arc<dyn VfsNode> {
955 self.root.clone() as Arc<dyn VfsNode>
956 }
957
958 fn name(&self) -> &str {
959 "fat32"
960 }
961
962 fn is_readonly(&self) -> bool {
963 self.readonly
964 }
965
966 fn sync(&self) -> Result<(), KernelError> {
967 Ok(())
970 }
971}
972
973#[cfg(test)]
974mod tests {
975 use super::*;
976
977 fn make_test_fat32_image() -> Vec<u8> {
979 let bps: usize = 512;
980 let spc: usize = 1;
981 let reserved: usize = 32;
982 let num_fats: usize = 2;
983 let fat_size: usize = 128; let total_sectors: usize = reserved + num_fats * fat_size + 1024; let mut image = vec![0u8; total_sectors * bps];
987
988 image[11] = (bps & 0xFF) as u8;
990 image[12] = ((bps >> 8) & 0xFF) as u8;
991 image[13] = spc as u8;
992 image[14] = (reserved & 0xFF) as u8;
993 image[15] = ((reserved >> 8) & 0xFF) as u8;
994 image[16] = num_fats as u8;
995 let ts = total_sectors as u32;
996 image[32] = (ts & 0xFF) as u8;
997 image[33] = ((ts >> 8) & 0xFF) as u8;
998 image[34] = ((ts >> 16) & 0xFF) as u8;
999 image[35] = ((ts >> 24) & 0xFF) as u8;
1000 let fs = fat_size as u32;
1001 image[36] = (fs & 0xFF) as u8;
1002 image[37] = ((fs >> 8) & 0xFF) as u8;
1003 image[38] = ((fs >> 16) & 0xFF) as u8;
1004 image[39] = ((fs >> 24) & 0xFF) as u8;
1005 image[44] = 2;
1007 image[48] = 1;
1009 image[510] = 0x55;
1011 image[511] = 0xAA;
1012
1013 let fat_start = reserved * bps;
1015 image[fat_start] = 0xF8;
1017 image[fat_start + 1] = 0xFF;
1018 image[fat_start + 2] = 0xFF;
1019 image[fat_start + 3] = 0x0F;
1020 image[fat_start + 4] = 0xFF;
1022 image[fat_start + 5] = 0xFF;
1023 image[fat_start + 6] = 0xFF;
1024 image[fat_start + 7] = 0x0F;
1025 image[fat_start + 8] = 0xFF;
1027 image[fat_start + 9] = 0xFF;
1028 image[fat_start + 10] = 0xFF;
1029 image[fat_start + 11] = 0x0F;
1030
1031 image
1035 }
1036
1037 #[test]
1038 fn test_bpb_parse() {
1039 let image = make_test_fat32_image();
1040 let bpb = Bpb::parse(&image[..512]).unwrap();
1041 assert_eq!(bpb.bytes_per_sector, 512);
1042 assert_eq!(bpb.sectors_per_cluster, 1);
1043 assert_eq!(bpb.reserved_sectors, 32);
1044 assert_eq!(bpb.num_fats, 2);
1045 assert_eq!(bpb.root_cluster, 2);
1046 }
1047
1048 #[test]
1049 fn test_bpb_parse_bad_signature() {
1050 let mut image = vec![0u8; 512];
1051 let result = Bpb::parse(&image);
1052 assert!(result.is_err());
1053 }
1054
1055 #[test]
1056 fn test_fat32_from_image() {
1057 let image = make_test_fat32_image();
1058 let fs = Fat32Fs::from_image(&image, false).unwrap();
1059 assert_eq!(fs.name(), "fat32");
1060 assert!(!fs.is_readonly());
1061
1062 let root = fs.root();
1063 assert_eq!(root.node_type(), NodeType::Directory);
1064 }
1065
1066 #[test]
1067 fn test_fat32_readonly() {
1068 let image = make_test_fat32_image();
1069 let fs = Fat32Fs::from_image(&image, true).unwrap();
1070 assert!(fs.is_readonly());
1071 }
1072
1073 #[test]
1074 fn test_fat32_empty_root_readdir() {
1075 let image = make_test_fat32_image();
1076 let fs = Fat32Fs::from_image(&image, false).unwrap();
1077 let root = fs.root();
1078
1079 let entries = root.readdir().unwrap();
1080 assert_eq!(entries.len(), 2);
1082 }
1083
1084 #[test]
1085 fn test_fat32_create_and_write_file() {
1086 let image = make_test_fat32_image();
1087 let fs = Fat32Fs::from_image(&image, false).unwrap();
1088 let root = fs.root();
1089
1090 let file = root.create("TEST.TXT", Permissions::default()).unwrap();
1091 file.write(0, b"Hello FAT32!").unwrap();
1092
1093 let mut buf = vec![0u8; 20];
1094 let n = file.read(0, &mut buf).unwrap();
1095 assert_eq!(n, 12);
1096 assert_eq!(&buf[..12], b"Hello FAT32!");
1097
1098 let meta = file.metadata().unwrap();
1099 assert_eq!(meta.size, 12);
1100 }
1101
1102 #[test]
1103 fn test_fat32_mkdir() {
1104 let image = make_test_fat32_image();
1105 let fs = Fat32Fs::from_image(&image, false).unwrap();
1106 let root = fs.root();
1107
1108 let dir = root.mkdir("SUBDIR", Permissions::default()).unwrap();
1109 assert_eq!(dir.node_type(), NodeType::Directory);
1110
1111 let found = root.lookup("SUBDIR").unwrap();
1112 assert_eq!(found.node_type(), NodeType::Directory);
1113 }
1114
1115 #[test]
1116 fn test_fat32_unlink_file() {
1117 let image = make_test_fat32_image();
1118 let fs = Fat32Fs::from_image(&image, false).unwrap();
1119 let root = fs.root();
1120
1121 root.create("DEL.TXT", Permissions::default()).unwrap();
1122 assert!(root.lookup("DEL.TXT").is_ok());
1123
1124 root.unlink("DEL.TXT").unwrap();
1125 assert!(root.lookup("DEL.TXT").is_err());
1126 }
1127
1128 #[test]
1129 fn test_fat32_truncate() {
1130 let image = make_test_fat32_image();
1131 let fs = Fat32Fs::from_image(&image, false).unwrap();
1132 let root = fs.root();
1133
1134 let file = root.create("TRUNC.TXT", Permissions::default()).unwrap();
1135 file.write(0, b"0123456789").unwrap();
1136 assert_eq!(file.metadata().unwrap().size, 10);
1137
1138 file.truncate(5).unwrap();
1139 assert_eq!(file.metadata().unwrap().size, 5);
1140
1141 let mut buf = vec![0u8; 10];
1142 let n = file.read(0, &mut buf).unwrap();
1143 assert_eq!(n, 5);
1144 assert_eq!(&buf[..5], b"01234");
1145 }
1146
1147 #[test]
1148 fn test_fat_table_alloc_and_free() {
1149 let mut fat = FatTable::new(100);
1150
1151 let c1 = fat.alloc_cluster(2).unwrap();
1153 assert_eq!(c1, 2);
1154 assert_eq!(fat.get(2), FAT32_EOC & 0x0FFF_FFFF);
1155
1156 let c2 = fat.alloc_cluster(2).unwrap();
1157 assert_eq!(c2, 3);
1158
1159 fat.free_chain(2);
1161 assert_eq!(fat.get(2), FAT32_FREE);
1162 }
1163
1164 #[test]
1165 fn test_fat_table_chain() {
1166 let mut fat = FatTable::new(100);
1167
1168 fat.set(2, 3);
1169 fat.set(3, 4);
1170 fat.set(4, FAT32_EOC);
1171
1172 let chain = fat.get_chain(2);
1173 assert_eq!(chain, vec![2, 3, 4]);
1174 }
1175
1176 #[test]
1177 fn test_short_name_parsing() {
1178 let mut entry = [0u8; 32];
1179 entry[..8].copy_from_slice(b"TEST ");
1180 entry[8..11].copy_from_slice(b"TXT");
1181 entry[11] = 0x20; let raw = unsafe { &*(entry.as_ptr() as *const RawDirEntry) };
1184 assert_eq!(raw.short_name(), "TEST.TXT");
1185 }
1186
1187 #[test]
1188 fn test_short_name_no_extension() {
1189 let mut entry = [0u8; 32];
1190 entry[..8].copy_from_slice(b"README ");
1191 entry[8..11].copy_from_slice(b" ");
1192 entry[11] = 0x10; let raw = unsafe { &*(entry.as_ptr() as *const RawDirEntry) };
1195 assert_eq!(raw.short_name(), "README");
1196 }
1197}