⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat32中文版.txt

📁 FAT32中英文标准及源代码,文档包括英文原版和本人翻译的
💻 TXT
📖 第 1 页 / 共 5 页
字号:

     } 

     Else if (FATType == FAT32) { 

          If (FATContent >= 0x0FFFFFF8) 

               isEOF = TRUE; 

     } 

     注意:包含 EOC 标记的簇属于当前文件并且是当前文件的最后一个簇。Microsoft 的操作系统设置 EOC 

标记时 FAT12 使用 0x0FFF,FAT16 使用 0xFFFF,FAT32 使用 0x0FFFFFFF,但有一些运行于 Microsoft 系统的 

工具并不使用这个值。 

     还有一个特殊的标记就是“坏簇(BAT CLUSTER)”标记,任何包含“坏簇”标记的簇都不应该被列 

到剩余簇的范畴内,这个“坏簇”标记对 FAT12 是 0x0FF7, FAT16 是 0xFFF7, FAT32 是 0x0FFFFFF7。另外, 

这些坏簇看起来也象是丢失的簇——们似乎已经分配出去,因为它们的值不为 0,但同时它们又不属于任 

何文件。磁盘修复程序一定要认出这些被标记坏簇标记的“丢失簇”,并且不去修改它们的内容。 

     NOTE: 对于 FAT12 和 FAT16 而言,坏簇标记不可能是某个已分配簇的簇号,但对于 FAT32 而言, 

0x0FFFFFF7 就有可能是某个簇的簇号,因此 FAT32 文件系统必须避免把 0x0FFFFFF7 这个数字分配出去作 

为某个簇的簇号。 

     FAT 表中剩余簇的列表就是卷中所有内容为 0 的簇的列表。这些数据必须尽早取得并记录下来以表示 

剩余的簇是已经被使用的。这个列表并没有存储在卷中的任何一个地方,他必须在系统挂上(mount)该卷 

时由 FAT 扫描程序获得内容为 0 的簇的列表。FAT32 的 BPB_FSInfo 扇区可能会 包含剩余簇的数量,请参 

阅 FAT32 关于 BPB_FSInfo 扇区的讨论部分。 

     在 FAT 卷起始部分的两个保留扇区到底是做什么用的呢?第一个保留簇 FAT[0],它的低位 8-bit 为 

BPB_Media,剩余的位用 1 填充,比如:BPB_Media 的内容为 0xF8,那么 FAT12 的内容为 0x0FF8,FAT16 为 

0xFFF8,FAT32 的内容为 0x0FFFFFF8.第二个保留簇 FAT[1]在格式化的时候被填充 EOC 标记。FAT12 卷此域 

不用,其值始终为 EOC 标记。FAT16 和 FAT32 此域的高 2-bit 可以被用于标记磁盘是否为“脏”(下面描述), 

剩余的位均用 1 填充。请注意 FAT16 和 FAT32 这两位的位置是不一样的,因为是高位 2-bit. 

     对于 FAT16: 

          ClnShutBitMask = 0x8000; 

          HrdErrBitMask = 0x4000; 

     对于 FAT32: 

          ClnShutBitMask = 0x08000000; 

          HrdErrBitMask = 0x04000000; 


          Bit ClnShutBitMask –    如果此位为 1,那么卷是“干净”的。 如果为 0,那么卷是“脏”的。 

                                     意味着系统在上次卸载(unmount)此卷时没有正常地断开连接,此 

                                     时建议使用 ChkDsk/Scandisk 等工具来检测磁盘是否有错误。 

          Bit HrdErrBitMask -      如果此位为 1,表示没有发生磁盘读/写错误。如果为 0,表示系统在 

                                     上次挂载该卷时有发生过磁盘读/写错误,此时建议运行 

                                     ChkDsk/Scandisk等工具来扫描磁盘表面看看是否有出现新的坏簇。 

     关于 FAT 表这里还有两个重要的问题: 

           1. FAT 表的结束扇区不一定就是 FAT 表的最后一个扇区,FAT 表的结尾扇区位于簇号为 

               CountofClusters + 1(参阅前面关于 CountofClusters 的计算式)的簇中。这个扇区未 

               必在 FAT 表的最后面。FAT 程序不应该尝试着去访问 CountofClusters + 1 以后的簇. FAT 

               格式化程序应该把这个簇号后面的所有簇用 0 填充。 

           2. BPB_FATSz16(对于 FAT32 为 BPB_FATSz32)的值会比它实际需要的大,也就是说,在 FAT 表 

               中可能有部分扇区没有被使用。因此,FAT 表的结束扇区都是由 CountofClusters + 1 来 计 



                                                                                           第 11 页 

                                                            FAT: General Overview of On-Disk Format 



              算得到,而不是使用 BPB_FATSz16/32 来计算。FAT 程序不因该尝试去访问这些“额外”的 

              扇区。FAT 格式化程序因该把这些扇区用 0 来填充。 



初始化 FAT 卷(FAT Volume Initialization) 


     读到这里,细心的读者一定会发现一个有趣的问题。前面说过 FAT 的类型(FAT12, FAT16 或是 FAT32) 

是根据总的簇数来辨别——并且数据区中最大可取得的扇区数由 FAT 表的大小来决定——那么当一个磁盘 

还没有格式化时,我们无法得到这 BPB 数据,这时是如何检测并计算出正确的值来放到 BPB_SecPerClus 和 

BPB_FATSz16或是BPB_FATSz32中呢?Microsoft的操作系统使用一些固定的值和表格配合一个巧妙的算法 

来完成这些工作。 

     Microsoft 只在软盘上使用 FAT12 文件系统,因为软盘的种类很少,并且都有固定的参数,格式化时 

使用的是一张简单的表: 

     “如果这是一张这种格式的软盘,那么它的 BPB 看起来就是这样子。(If it is a floppy of this type, 

then the BPB look like this.)” 

     对于 FAT12 格式的计算相对简单,所有写到 BPB 中的值都可以在一张纸上用手算出来的(当然得小心 

使 cluster 的值始终小于 4085),如果存储介质的容量大于 4M,那就别再麻烦 FAT12 了,只需要把 

BPB_SecPerClus 的值改小一点,这个卷就成为 FAT16 了。 

     本节以下部分描述如何驱动每扇区 512 字节的 FAT 卷。如果扇区大小不是这样的话,你将不能使用这 

个表格和算法。不同的磁盘的扇区大小不一。这里根据磁盘容量的大小选择一个“合适的值”来简单地 

区分 FAT 类型。如果磁盘容量小于该值就是 FAT16;如果大于或等于该值,那么就是 FAT32。Windows 操作 

系统选择该值为 512MB,任何小于 512MB 的卷都是 FAT16 卷,任何大于或等于 512MB 的卷都是 FAT32 卷。 

     这里请特别注意,别过早地下结论。 

     有很多 FAT16 卷的容量都大于 512MB,因为有很多不同的办法可以强制把磁盘格式化成 FAT 16 格式而 

不是象默认的那样格式化成 FAT32 格式,并且不同的 FAT 程序遵循不同的规定来格式化磁盘。这里我们讨 

论的只是 MS-DOS 和 Windows 默认情况下是如何处理未格式化的磁盘。这里有两个表格,一个用于 FAT16, 另 

外一个用于 FAT32。这个表其中的一项是根据每扇区 512 字节的磁盘空间大小计算而来(该数值将写到 

BPB_TotSec16 或是 BPBSec32 中),还有一个值用来设置 BPB_SecPerClus。 


     struct DSKSZTOSECPERCLUS { 

       DWORD         DiskSize; 

       BYTE          SecPerClusVal; 

     }; 

     /* 

     * 这个表使用于 FAT16,注意这个表包含了大于 512MB 的情况,虽然默认 

     * 情况下使用的都是<512MB。通过比较磁盘大小的是否小于或等于表中的 

     * 第一项 DiskSize 来决定采用哪个值。为了能够让这张表能够正确地工作, 

     * BPB_RsvdSecCnt 的值必须为 1, BPB_NumFATs 的值必须为 2,还有 

     * BPB_RootEntCnt 的值必须为 512,如果这些值不符的话,必须改变表中第 

     * 一项 DiskSize 的值否则磁盘的簇数可能会小于 FAT16 所要求的数值。 

     */ 

          DSKSZTOSECPERCLUS DskTableFAT16 [ ] = { 

              {8400,     0}, /* 磁盘容量最大为 4.1 MB, SecPerClusVal 的值为 0 表示这是一个错误*/ 

              { 32680,        2}, /*磁盘容量最大为 16 MB, 1k cluster */ 

              { 262144,       4}, /*磁盘容量最大为 128 MB, 2k cluster */ 


                                                                                          第 12 页 

                                                          FAT: General Overview of On-Disk Format 



              { 524288,8}, /*磁盘容量最大为 256 MB, 4k cluster */ 

              { 1048576, 16}, /*磁盘容量最大为 512 MB, 8k cluster */ 

              /* 除非强制使用 FAT16,否则以下数据不使用 */ 

              { 2097152,     32}, /*磁盘容量最大为 1 GB, 16k cluster */ 

              { 4194304,     64}, /*磁盘容量最大为 2 GB, 32k cluster */ 

              { 0xFFFFFFFF, 0} /*磁盘容量超过 2GB, SecPerClusVal 的值为 0 意味着这是一个错误*/ 

         }; 


    /* 

    * 这个表使用于 FAT32,注意这个表包含了小于 512 的情况,虽然默认 

    * 情况下使用的都是 >= 512MB,通过比较磁盘大小的是否小于或等于 

    * 表中的第一项 DiskSize 来决定采用哪个值。为了使这个表能正确地工作, 

    * BPB_RsvdSecCnt 的值必须为 32,BPB_NumFATs 的值必须为 2,如果这 

    * 些值不符的话,必须改变表中第一项 DiskSize 的值否则磁盘的簇数可能 

    * 会小于 FAT32 所要求的数值。 

    */ 

         DSKSZTOSECPERCLUS DskTableFAT32 [ ] = { 

           { 66600, 0},/*磁盘容量最大为32.5 MB, SecPerClusVal的值为0表示这是一个错误 */ 

           { 532480, 1}, /*磁盘容量最大为260 MB, .5k cluster */ 

           { 16777216, 8}, /*磁盘容量最大为8 GB, 4k cluster */ 

           { 33554432, 16}, /*磁盘容量最大为16 GB, 8k cluster */ 

           { 67108864, 32}, /*磁盘容量最大为32 GB, 16k cluster */ 

           { 0xFFFFFFFF, 64}/* 磁盘容量超过32GB, 32k cluster */ 

         }; 

    这样,只要给出磁盘的大小和 FAT 的类型就可以确定 BPB_SecPerClus 的值,现在我们唯一所缺的就 

是 FATSz16 或 FATSz32 的大小。这里我们假设 BPB_RootEntCnt, BPB_RsvdSecCnt 和 BPB_NumFATs 的值已 

经按照上面的约定正确地设置。同时我们还假设 DiskSize 就是我们要写到 BPB_TotSec32 或是 

BPB_TotSec16 的值。 


         RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec – 1)) / BPB_BytsPerSec; 

         TmpVal1 = DskSize – (BPB_RsvdSecCnt + RootDirSectors); 

         TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs; 

         If(FATType == FAT32) 

              TmpVal2 = TmpVal2 / 2; 

         FATSz = (TMPVal1 + (TmpVal2 – 1)) / TmpVal2; 

         If(FATType == FAT32) { 

              BPB_FATSz16 = 0; 

              BPB_FATSz32 = FATSz; 

         } else { 

              BPB_FATSz16 = LOWORD(FATSz); 

              /* FAT16 的 BPB 没有 BPB_FATSz32 */ 

         } 

    不要花费太多的工夫去琢磨上面的代码是如何工作的,这个算法的原理十分复杂,放在这里的目的只 

是说明 Microsoft 的操作系统是如何实现磁盘初始化的。但是,上面的代码并不完美,在一些偶然的情况 



                                                                                        第 13 页 

                                                            FAT: General Overview of On-Disk Format 



下,它会使 FAT16 的 FATSz 比实际需要的多 2 个扇区,或使 FAT32 的 FATSz 多 8 个扇区,不过它永远不会 

使 FATSz 的值比实际需要的小。因为 FATSz 的值比实际的大并不会影响文件系统正常工作,唯一的缺点就 

是造成很少一部分磁盘空间的浪费。由于以上代码是如此的简单可靠,这在很大程度上弥补了它的不足。 



FAT32 FSInfo 扇区结构和备份启动扇区 

     FAT32 的 FAT 表可能会非常的庞大,而不像 FAT16 的值被限制在 128K 或 FAT12 被限制在 6K 范围内一 

样,因此,在 FAT32 卷中存放着 “最新”的剩余簇的数量,在 API 函数想知道剩余空间时(比如在 DIR 命 

令的最后显示剩余空间)不必马上去计算该数值。FSInfo 的扇区号存放在 BPB_FSInfo 中,对于 Microsoft 

的操作系统此值为 1。下表是 FSInfo 的结构 

                          Offset    大小 
         名称                                                        描述 
                          (byte)    (byte) 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -