Przeglądaj źródła

修正了FAT32判断逻辑,解决了文件系统为FAT12/16时系统无法正常启动的问题。 (#211)

* fix(fat): fix determination of fat type casue crash if fs is fat12/16

* refactor(fat): split BiosParameterBlock.validate() into BiosParameterBlockFAT32.validate() and BiosParameterBlockLegacy.validate()

* 调整“最大允许的簇号”的常量放置的位置。

---------

Co-authored-by: longjin <[email protected]>
WaferJay 1 rok temu
rodzic
commit
2286eda652
2 zmienionych plików z 68 dodań i 53 usunięć
  1. 61 53
      kernel/src/filesystem/fat/bpb.rs
  2. 7 0
      kernel/src/filesystem/fat/fs.rs

+ 61 - 53
kernel/src/filesystem/fat/bpb.rs

@@ -8,7 +8,7 @@ use crate::{
     libs::vec_cursor::VecCursor,
 };
 
-use super::fs::Cluster;
+use super::fs::{Cluster, FATFileSystem};
 
 /// 对于所有的FAT文件系统都适用的Bios Parameter Block结构体
 #[derive(Debug, Clone, Copy, Default)]
@@ -179,6 +179,45 @@ impl FATType {
     }
 }
 
+impl BiosParameterBlockLegacy {
+    /// @brief 验证FAT12/16 BPB的信息是否合法
+    fn validate(&self, _bpb: &BiosParameterBlock) -> Result<(), i32> {
+        return Ok(());
+    }
+}
+
+impl BiosParameterBlockFAT32 {
+    /// @brief 验证BPB32的信息是否合法
+    fn validate(&self, bpb: &BiosParameterBlock) -> Result<(), i32> {
+        if bpb.fat_size_16 != 0 {
+            kerror!("Invalid fat_size_16 value in BPB (should be zero for FAT32)");
+            return Err(-(EINVAL as i32));
+        }
+
+        if bpb.root_entries_cnt != 0 {
+            kerror!("Invalid root_entries value in BPB (should be zero for FAT32)");
+            return Err(-(EINVAL as i32));
+        }
+
+        if bpb.total_sectors_16 != 0 {
+            kerror!("Invalid total_sectors_16 value in BPB (should be zero for FAT32)");
+            return Err(-(EINVAL as i32));
+        }
+
+        if self.fat_size_32 == 0 {
+            kerror!("Invalid fat_size_32 value in BPB (should be non-zero for FAT32)");
+            return Err(-(EINVAL as i32));
+        }
+
+        if self.fs_version != 0 {
+            kerror!("Unknown FAT FS version");
+            return Err(-(EINVAL as i32));
+        }
+
+        return Ok(());
+    }
+}
+
 impl BiosParameterBlock {
     pub fn new(partition: Arc<Partition>) -> Result<BiosParameterBlock, i32> {
         let mut v = Vec::with_capacity(LBA_SIZE);
@@ -230,9 +269,6 @@ impl BiosParameterBlock {
         // 读取尾部的启动扇区标志
         bpb.trail_sig = cursor.read_u16()?;
 
-        // 验证BPB32的信息是否合法
-        bpb.validate(&bpb32)?;
-
         // 计算根目录项占用的空间(单位:字节)
         let root_sectors = ((bpb.root_entries_cnt as u32 * 32) + (bpb.bytes_per_sector as u32 - 1))
             / (bpb.bytes_per_sector as u32);
@@ -258,19 +294,25 @@ impl BiosParameterBlock {
         let count_clusters = data_sectors / (bpb.sector_per_cluster as u32);
 
         // 设置FAT类型
-        bpb.fat_type = if count_clusters < 4085 {
+        bpb.fat_type = if count_clusters < FATFileSystem::FAT12_MAX_CLUSTER {
             FATType::FAT12(BiosParameterBlockLegacy::default())
-        } else if count_clusters < 65525 {
+        } else if count_clusters <= FATFileSystem::FAT16_MAX_CLUSTER {
             FATType::FAT16(BiosParameterBlockLegacy::default())
-        } else {
+        } else if count_clusters < FATFileSystem::FAT32_MAX_CLUSTER {
             FATType::FAT32(bpb32)
+        } else {
+            // 都不符合条件,报错
+            return Err(-(EINVAL as i32));
         };
 
+        // 验证BPB的信息是否合法
+        bpb.validate()?;
+
         return Ok(bpb);
     }
 
-    /// @brief 验证BPB32的信息是否合法
-    pub fn validate(&self, bpb32: &BiosParameterBlockFAT32) -> Result<(), i32> {
+    /// @brief 验证BPB的信息是否合法
+    pub fn validate(&self) -> Result<(), i32> {
         // 校验每扇区字节数是否合法
         if self.bytes_per_sector.count_ones() != 1 {
             kerror!("Invalid bytes per sector(not a power of 2)");
@@ -283,8 +325,6 @@ impl BiosParameterBlock {
             return Err(-(EINVAL as i32));
         }
 
-        let is_fat32 = self.is_fat32();
-
         if self.rsvd_sec_cnt < 1 {
             kerror!("Invalid rsvd_sec_cnt value in BPB");
             return Err(-(EINVAL as i32));
@@ -295,42 +335,26 @@ impl BiosParameterBlock {
             return Err(-(EINVAL as i32));
         }
 
-        if is_fat32 && self.root_entries_cnt != 0 {
-            kerror!("Invalid root_entries value in BPB (should be zero for FAT32)");
-            return Err(-(EINVAL as i32));
-        }
-
-        if is_fat32 && self.total_sectors_16 != 0 {
-            kerror!("Invalid total_sectors_16 value in BPB (should be zero for FAT32)");
-            return Err(-(EINVAL as i32));
-        }
-
         if (self.total_sectors_16 == 0) && (self.total_sectors_32 == 0) {
             kerror!("Invalid BPB (total_sectors_16 or total_sectors_32 should be non-zero)");
             return Err(-(EINVAL as i32));
         }
 
-        if is_fat32 && bpb32.fat_size_32 == 0 {
-            kerror!("Invalid fat_size_32 value in BPB (should be non-zero for FAT32)");
-            return Err(-(EINVAL as i32));
-        }
-
-        if bpb32.fs_version != 0 {
-            kerror!("Unknown FAT FS version");
-            return Err(-(EINVAL as i32));
-        }
+        let fat_size = match self.fat_type {
+            FATType::FAT32(bpb32) => {
+                bpb32.validate(self)?;
+                bpb32.fat_size_32
+            }
+            FATType::FAT16(bpb_legacy) | FATType::FAT12(bpb_legacy) => {
+                bpb_legacy.validate(self)?;
+                self.fat_size_16 as u32
+            }
+        };
 
         let root_sectors = ((self.root_entries_cnt as u32 * 32)
             + (self.bytes_per_sector as u32 - 1))
             / (self.bytes_per_sector as u32);
 
-        // 每FAT扇区数
-        let fat_size = if self.fat_size_16 != 0 {
-            self.fat_size_16 as u32
-        } else {
-            bpb32.fat_size_32
-        };
-
         // 当前分区总扇区数
         let total_sectors = if self.total_sectors_16 != 0 {
             self.total_sectors_16 as u32
@@ -341,31 +365,15 @@ impl BiosParameterBlock {
         let first_data_sector =
             (self.rsvd_sec_cnt as u32) + (self.num_fats as u32) * fat_size + root_sectors;
 
-        // 数据区扇区数
-        let data_sectors = total_sectors - first_data_sector;
-        // 总的数据簇数量(向下对齐)
-        let count_clusters = data_sectors / (self.sector_per_cluster as u32);
-
         // 总扇区数应当大于第一个数据扇区的扇区号
         if total_sectors <= first_data_sector {
             kerror!("Total sectors lesser than first data sector");
             return Err(-(EINVAL as i32));
         }
 
-        // 检查文件系统类型与总的数据簇数量的关系是否合法
-        if (is_fat32 && (count_clusters < 65525)) || ((!is_fat32) && (count_clusters >= 65525)) {
-            kerror!("FAT determination using tot_sec_16 and count_cluster differs");
-            return Err(-(EINVAL as i32));
-        }
         return Ok(());
     }
 
-    /// @brief 判断当前是否为fat32的bpb
-    fn is_fat32(&self) -> bool {
-        // fat32的bpb,这个字段是0
-        return self.total_sectors_16 == 0;
-    }
-
     pub fn get_volume_id(&self) -> u32 {
         match self.fat_type {
             FATType::FAT12(f) | FATType::FAT16(f) => {

+ 7 - 0
kernel/src/filesystem/fat/fs.rs

@@ -244,6 +244,13 @@ impl FileSystem for FATFileSystem {
 }
 
 impl FATFileSystem {
+    /// FAT12允许的最大簇号
+    pub const FAT12_MAX_CLUSTER: u32 = 0xFF5;
+    /// FAT16允许的最大簇号
+    pub const FAT16_MAX_CLUSTER: u32 = 0xFFF5;
+    /// FAT32允许的最大簇号
+    pub const FAT32_MAX_CLUSTER: u32 = 0x0FFFFFF7;
+
     pub fn new(partition: Arc<Partition>) -> Result<Arc<FATFileSystem>, i32> {
         let bpb = BiosParameterBlock::new(partition.clone())?;