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

📄 fat32中文版.txt

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

     FirstSectorofCluster = ((N – 2) * BPB_SecPerClust) + FirstDataSector; 

     NOTE: 因为 BPB_SecPerClus 总是 2 的整数次方(1,2,4,8,……)这意味这 BPB_SecPerClus 的 

乘除法运算可以通过移位(SHIFT)来进行。在当前 Intel x86 架构 2 进制的机器上乘法(MULT)和除法 

(DIV)的机器指令非常的繁杂和庞大,而使用移位来运算则会相对的快许多。 




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



FAT 类型辨别(FAT Type Determination) 



     这是一个经常产生错误的地方,并且常常会出现诸如 “off by 1”, “off by 2”, “off by 10” 

和 “massively off”的错误,事实上,FAT 类型的检测非常简单,FAT 的类型 ——FAT12,或是 FAT16 或 

是 FAT32 —— 只能通过 FAT 卷中簇的数量来判定,没有其他办法。 

     请仔细阅读本段的每一个细节,每个词都很关键。比如“簇数(count of cluster)”并不是指“最大 

可取得的簇的数量(maximum valid cluster number)”,因为数据区的第一个簇是簇 2 而不是 0 或 1。 

     首先我们讨论这个“簇数”是如何计算的,它完全根据 BPB 的内容来确定,我们先计算根目录所占的 

扇区数(前面已经有叙述)。 

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

     FAT32 的 RootDirSectors 为 0。 

     接下来我们检测数据区中扇区数: 

     If (BPB_FATSz16 != 0) 

         FATSz = BPB_FATSz16; 

     Else 

         FATSz = BPB_FATSz32; 

     If (BPB_TotSec16 != 0) 

         TotSec = BPB_TotSec16; 

     Else 

         TotSec = BPB_TotSec32; 

     DataSec = TotSec – (BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors); 

     计算簇数: 

     CountofClusters = DataSec / BPB_SecPerClus; 

     请记住计算结果四舍五入。 

     现在我们就可以判定 FAT 的类型了,这部分请仔细阅读,否则会导致 off-by-one 的错误 

     在下面的程序中, “<”和 “<=”是不一样的,另外请注意数字不要弄错。 

     If (CountofCluster < 4085) { 

         /* FAT 类型是 FAT12 */ 

     } 

     Else if (CountofCluster < 65525) { 

         /* FAT 类型是 FAT16 */ 

     } 

     Else { 

         /* FAT 类型是 FAT32*/ 

     } 

     这是检测 FAT 类型的唯一办法。世上不存在簇数大于 4084 的 FAT12 卷,也不存在簇数小于 4085 或是 

大于 65524 的 FAT16 卷,同样没有哪个 FAT32 卷的簇数小于 65525。如果你坚持要违背这个规则来创建一 

个 FAT 卷那么 Microsoft 的操作系统将无法对此卷进行操作,因为它不认为这是 FAT 文件系统。 

     NOTE: 如前面所说,目前有很多 FAT 的代码有一些错误,常常会出现 off by 1,2,8,10 或是 off 

by 16 的错误 。因此,为和现存的所有代码取得最好的兼容性,强烈建议在格式化 FAT 文件系统时,尽量 

使簇数的取值不要接近 4085 或 65525,最好能和这分割点的值相差 16 或更多。 

     同时请注意这里的簇数(Count of Cluster)是指数据区所占簇的数量(the count of data clusters) 

从簇 2 开始算起,而“最大可用的簇数”(Maximum valid cluster number for the volume)是簇数 + 1, 

“包括保留簇的簇数”(count of cluster including the two reserved cluster)则为 簇数 + 2。 


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



     FAT 的另一个重要计算公式:给一个簇号 N,它位于 FAT 表的什么位置呢?对于 FAT16 和 FAT32 都比 

较容易计算,而 FAT12 则会复杂一点: 

     If (BPB_FATSz16 != 0) 

         FATSz = BPB_FATSz16; 

     Else 

         FATSz = BPB_FATSz32; 

     If (FATType == FAT16) 

         FATOffset = N * 2; 

     Else if (FATType == FAT32) 

         FATOffset = N * 4; 

     ThisFATSecNum = BPB_RsvdSecCnt + (FATOffset / BPB_BytsPerSec); 

     ThisFATEntOffset = REM (FATOffset / BPB_BytsPerSec); 

     REM(…)为求余操作符,就是求 FATOffset 除以 BPB_BytsPerSec 的余数。ThisFATSecNum 是 FAT 表中 

包含簇 N 的扇区数,如果你想得到第二个 FAT 表中的扇区数,只要加上 FATSz 就是,如果想的到第三个 FAT 

表中的扇区数,只需要加上 FATSz * 2,依次类推。 

     现在你得到扇区数 ThisFATSecNum(记住这是针对 FAT 卷扇区 0 的偏移量),假设把该值读入到一个指 

定的 8-bit SecBuff,同时假定数据类型 WORD 是一个 16-bit 的不无符号类型,而 DWORD 是一个 32-bit 的 

无符号类型。 

     If (FATType == TAF16) 

         FAT16ClusEntryVal = *((WORD *) & SecBuff[ThisFATEntOffset]); 

     Else 

         FAT32ClusEntryVal = (*((DWORD *) & SecBuff[ThisFATEntOffset]) & 0x0FFFFFF; 

     取得该扇区的内容。 

     设置该扇区的值使用如下算式: 

     If (FATType == FAT16) 

         *((WORD *) &SecBuff[ThisFATEntOffset]) = FAT16ClusEntryVal; 

     Else { 

         FAT32ClusEntryVal = FAT32ClusEntryVal & 0x0FFFFFFF; 

         *((DWORD *) & SecBuff[ThisFATEntOffset]) = 

              (*((DWORD *) & SecBuff[ThisFATEntOffset])) & 0xF0000000; 

         *((DWORD *) & SecBuff[ThisFATEntOffset]) = 

              (*((DWORD *) & SecBuff[ThisFATEntOffset])) | FAT32ClusEntryVal; 

     } 

     我们看看上述FAT 代码是如何工作的,实际上每个FAT32的FAT表项只有28-bit可以使用,它的高4位 

保留,这4位只有在被格式化的时候会被使用到,在格式化时整个FAT32单元的32-bit都被设为0,包括高位 

的4-bit。 

     另外要说明的一点,这也是经常被混淆的地方,因为FAT32表项实际上被使用的只有28-bit而不是 

32-bit。比如,以下几个FAT32簇的值为0x10000000,0xF0000000和0x00000000都表示该簇为空,因为程序 

忽略了高位4-bit的值。如果当前簇的值为0x30000000,你想要把数值0x0FFFFFF7写入当前簇来标记坏簇, 

那么当你的操作结束后该簇的值实际上是0x3FFFFFF7,因为你必须舍去0x0FFFFFF7这个坏簇标记高位的 

4-bit. 

     因为BPB_BytsPerSec的值一定能够被2和4整除,对于FAT16/FAT32来说,你不必担心元素会超越扇区 

的边界,但对于FAT12,你就必须小心了。 

     FAT12的代码会显得复杂一点,因为它每个元素占1.5个字节(12-bit)。 



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



    If (FATType == FAT12) 

        FATOffset = N + (N / 2); 

    /* 注意算式并没有乘以浮点数1.5。除以2的值四舍五入 */ 

        ThisFATSecNum = BPB_RsvdSecCnt + (FATOffset / BPB_BytsPerSec); 

        ThisFATEntOffset = REM(FATOffset / BPB_BytsPerSec); 

    现在我们必须考虑扇区边界的情况。 

    If (ThisFATEntOffset == (BPB_BytsPerSec – 1)) { 

        /* 这个簇跨越了FAT的扇区边界,处理这个问题有很多方法, */ 

        /* 其中最简单的一种就是当FAT类型为FAT12则同时读取两个 */ 

        /* 扇区的内容到内存中(如果你想读取扇区N,同时你把扇区 */ 

        /* N+1的内容也读入内存中来,除非扇区N是FAT的最后一个扇 */ 

        /* 区)这样做实际上是避免扇区的边界检测 */ 

    } 

    现在我们可以象FAT16一样使用WORD数据类型来对FAT12的数据进行读取,但仍需要注意,如果簇号为 

偶数,我们取16-bit中的低12-bit,如果是奇数则取高12-bit, 

    FAT12ClusEntryVal = *((WORD *) & SecBuff[ThisFATEntOffset]); 

    If (N & 0x0001) { 

        FAT12ClusEntryVal = FAT12ClusEntryVal >> 4         /* 簇号为偶数 */ 

        *((WORD *) & SecBuff[ThisFATEntOffset]) = 

              (*((WORD *) & SecBuff[ThisFATEntOffset])) & 0x000F; 

    } 

    Else { 

        FAT12ClusEntryVal = FAT12ClusEntryVal & 0x0FFF;        /* 簇号为奇数 */ 

        *((WORD *) &SecBuff[ThisFATEntOffset]) = 

        (*((WORD *) &SecBuff[ThisFATEntOffset])) & 0xF000; 

    } 

    *((WORD *) &SecBuff[ThisFATEntOffset]) = 

    (*((WORD *) &SecBuff[ThisFATEntOffset])) | FAT12ClusEntryVal; 

    NOTE: 这里的 >>为右移操作符,并往高 4 位填充 0; <<为左移操作符,同时低 4 位用 0 填充。 

    数据区中的文件是按以下方式与 FAT 表相对应的:数据区中文件存放的第一个簇的簇号被记录在目录 

项中,文件就是根据这个簇号和 FAT 表相关联,数据区中文件的位置由前面讨论的 FirstSectorofCluster 

来计算。 

    对于一个文件大小为 0 —— 一个没有数据的文件 —— 在目录项中分配的第一个簇的簇号为 0,此 

簇(参见前面讨论的 ThisFATSecNum 和 ThisFATEntOffset)的内容要么是一个 EOC 标记(End of Cluster 

chain 簇链表结束标记)要么就是该文件下一个簇的簇号。EOC 的值和 FAT 类型有关(假设 FATContent 是 

需要检测看是否包含 EOC 标记的簇的内容) 

    isEOF = FALSE; 

    if (FATType == FAT12) { 

        if (FATContent >= 0x0FF8) 

              isEOF = TRUE; 

    } 

    Else if (FATType == FAT16) { 

        If (FATContent >= 0xFFF8) 

              isEOF = TRUE; 



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


⌨️ 快捷键说明

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