那系统首先找FAT的002,在002处得到一个值003,表示文件下一个扇区是003号,再接着003表项找,得到006...,表项的值含义如下:000 - 此簇未用;FF8 - FFF 该簇为文件的最后一簇;FF0 - FF7,此簇为坏,不可用;其它值表示文件下一簇的簇号。
下面的图来说明FAT的基本原理:表项编号 值16位 备注000 FF0 lt- 000 项 001项为表头,1字节 0xF0表示存储介质001 FFF lt- 2、3字节为 0xFFFF ,固定值,FAT标志002 003 lt- 文件下一簇为003003 005 lt- 下一簇:005004 FF7 lt- 坏簇,不可用005 011 lt- 下一簇:011........................................011 FF8 lt- 该文件结束012 000 lt- 可用簇.......................................根据上表,我们可以知道,一个文件占用了 002003005011 这4个簇。
簇号 31 逻辑扇区号 //// 31 = 保留扇区数 隐藏扇区数 FAT数×每个FAT所占扇区数 FDT所占扇区数 - 2 1 0 218 14 -2 LBA 逻辑扇区号 - 1 扇区 LBA MOD 每道扇区数 1 磁道 LBA / 每道扇区数 / 磁头数 磁头 LBA / 每道扇区数 MOD 磁头数根据上面的公式,得到以下计算值:002: S 32 MOD 18 1 15002: C 32 / 18 / 2 0002: H 32 / 18 MOD 2 1-----------------011: S 1131-1 MOD 18 1 6011: C 1131-1 / 18 / 2 1011: H 1131-1 / 18 MOD 2 0就此,我们已经可心根据簇号得到物理CHS了,那怎样才能得到一个文件的关系首簇号呢?前面我们提到了FDT。
下面说说FDT的结构:每个FDT项占32字节,分配如下:=======================0 - 7 : 8字节,文件名8 - 10: 3字节,文件扩展名11 :1字节,文件的属性12 - 15:4字节,保留16 - 21:6字节,保留22 - 23:2字节,文件最后修改时间(时分秒,5:6:5)24 - 25:2字节,文件最后修改日期(年月日,7:4:5,年取0-119对应 1980 - 2099)26 - 27:2字节,文件首簇号,我们可以根据这个值在FAT中找到文件的存储位置28 - 31:4字节,文件的长度,以字节为单位===========================0 - 7 文件名含义:0 - 目录项为空,可用;E5 - 此文件已经被删除7 - 10 :文件名和扩展名为8.3格式,如果不够,必需用空格填充,即文件名如果只有6个字节,那剩下的2个字节必须以空格填充。
文件名和扩展名都是大写。
11属性字节含义:00 - 普通文件;01 - 只读;02 - 隐藏;04 - 系统文件;101x - 该文件是目录。
就此,本文已经基本介绍完了软盘的结构,下面介绍如何读一个文件:给出一个文件名,比如“KERNEL.SYS”将文件名扩展为“KERNEL SYS”,即去掉点并为文件名和扩展名补充空格读FDT到内存中(用BIOS INT 13)在FDT中查找到符合的文件名可选,判断在FDT中找到的是否是目录在符合的FDT中取出文件首簇号读入FAT,可以选择读入两个FAT表,以检查是否有效将簇号转换为CHS,将扇区读入内存根据簇号在FAT中查找下一簇,并判断是否是文件最后一簇如果是文件最后一簇,则文件读取完毕;如果不是,则转第8步如果在引导程序中读指定的内核文件,则可以省略1、2步,直接给出内核文件名即可。
如果给出的文件是带目录的,那这里还有必要介绍一下:实际上,目录也是一个文件,只不过这个文件是一个FDT,FDT指出该目录下其它文件或目录。
因此,给出如下路径:/EXOS/KERNEL.BIN ,则先是在根目录中,将“EXOS ”这个“文件”读出来,然后在读出的FDT中找“KERNEL BIN”。
fat12 文件系统 源代码分析/ The FAT file system is difficult to trace through FAT table. // There are two kinds of FATs 12 bit and 16 bit. The 16 bit // FAT is the easiest since it is nothing more than a series // of UWORDs. The 12 bit FAT is difficult because it packs 3 // FAT entries into two BYTEs. These are packed as follows: // // 0x0003 0x0004 0x0005 0x0006 0x0007 0x0008 0x0009 0x0010... // // are packed as // // 0x03 0x40 0x00 0x05 0x60 0x00 0x07 0x80 0x00 0x09 0x00 0x01... //请注意上面的0x0009和0x0010的fat12的表示 // // 12 bytes are compressed to 9 bytes // fat文件系统是很难遍历的,有两种fat,一个是12位的,一个是16位的// 16位的是很简单的,但是12位的是不同的,因为它把3个字节压缩到两个字节里了,)// 而且数据是有交叉的,第二个字节的高4位是下个簇号的低四位,第二个字节的// 第四位是第一个字节的高四位但是仍旧是12个位表达一个文件目录//假设就是fat12文件系统,这时调用为 find_free_fat--gtnext_clusterdpbpidx-gtlink_fatdpbpidxREAD_CLUSTER idx是当前簇索引值,每次都是以一递增是簇号索引。
struct dpb dpbp其实就是内部的驱动器的参数表,就是在每个盘最前扇区 的内容,来对这个驱动盘进行描述的内容结构体。
有个规定:簇是从2开始用的,前两个没有用,保留。
/CLUSTER link_fatstruct dpb FAR dpbp CLUSTER Cluster1 REG CLUSTER Cluster2struct buffer FAR bpunsigned idxunsigned secdivunsigned char wasfree 0CLUSTER clussec Cluster1/这么多簇有多少扇区/CLUSTER max_cluster dpbp-gtdpb_size/最大簇号/ifdef WITHFAT32if ISFAT32dpbp max_cluster dpbp-gtdpb_xsizeendif/当前索引的簇值肯定是要在当前盘的空间内的,如果超过了(包括两边),就返回,并报错/if clussec lt 1 clussec gt max_cluster put_stringquotrun CHKDSK: trying to
access invalid cluster 0xquotifdef WITHFAT32 put_unsignedunsignedclussec gtgt 16 16 4endif/put_unsigned函数是将一个十进制的字符串数转化成为2进制或者是16进制的表示方法,非常巧妙/ put_unsignedunsignedclussec amp 0xffffu 16 4 put_console/n return 1/dpb-gtdpb_secsize是当前驱动盘的扇区大小为什么要用secdiv做变量我还不是很清楚可能是secctor divide因为下面做除法了 /secdiv dpbp-gtdpb_secsizeif ISFAT12dpbp/这好像要看官方文档,看 fat12的簇大小是多少的一个簇=一个扇区=512字节,// 这里一个2,一个3,注意的是1.5=3/2,就是一个fat要占用的字节数, 我突然想到baidu知道上不知道是谁说fat12的簇含有4个扇区 / clussec unsignedclussec 3 secdiv 2/暂且只讨论fat12/else / FAT16 or FAT32 / secdiv / 2ifdef WITHFAT32 if ISFAT32dpbp secdiv / 2endif/ idx is a pointer to an index which is the nibble offset of the FAT entry within the sector for FAT12 or word offset for FAT16 or dword offset for FAT32 //我认为下面的代码就是计算偏移,化整为零/idx unsignedclussec secdiv/没有构成一个扇区/clussec / secdiv/还有多少个整数扇区//曾经做过一个计算题,好像fat表项可以是很大的,可以有几兆的/clussec dpbp-gtdpb_fatstrt/绝对扇区地址/ifdef WITHFAT32if ISFAT32dpbp ampamp dpbp-gtdpb_xflags amp FAT_NO_MIRRORING / we must modify the active fat its number is in the 0-3 bits of dpb_xflags / clussec dpbp-gtdpb_xflags amp 0xf dpbp-gtdpb_xfatsizeendif/ Get the block that this cluster is in //读一个block到一个缓冲区,返回的是缓冲区的首地址但是比较特殊的是/ / 它返回的是一个512字节长度的fat表项 /bp getFATblockdpbp clussec/没有读成功,自然要返回也就是读fat表项没有成功,可能是别的错误之类的/if bp NULL return 1 / the only error code possible here (他是说这是这个函数里面唯一的错误信息不过好像确实是的//针对fat12特别处理,可以看到下面每种文件系统都做了处理,我在想,如果我要加入ntfs怎么办?/if ISFAT12dpbp REG UBYTE FAR fbp0 FAR fbp1 struct buffer FAR bp1 unsigned cluster cluster2 / form an index so that we can read the block as a / / byte array //idx上面操作得到的在簇里面的第几个扇区 fat12文件系统一个簇=一个扇区 第n个fat目录项: n为偶数:低四位3n/2,高四位3n/21 n为奇数:低四位 一个簇=??? 一个扇区=512字节 一个fat表项=12位=1.5位 idx是在原有的簇的基础上还要移动几个扇区的索引 一个buffer的大小就是一个扇区的大小 / idx / 2 / Test to see if the cluster straddles the block. If / / it does get the next block and use both to form the / / the FAT word. Otherwise just point to the next / / block.测试这个簇是否跨越了这个块,如果是这样的话,得到下个块, 用这两个簇形成一个fat字 //sizeofb_buffer512BPRIampgtPRI-gt/ fbp0 ampbp-gtb_bufferidx / pointer to next byte will be overwritten if not valid //如果是跨越的话,就是越界的访问了吧我的意思没有意思的访问/ fbp1 fbp0 1/如果这时候是跨越了的话,那么就要读下一个块,那么fbp1是无效的,而是需要重新赋值//因为是必须要读2个字节的,idx只是开始字节地址/ if idx gt unsigneddpbp-gtdpb_secsize - 1 / blockio.c LRU logic ensures that bp bp1 这话我还没懂,希望懂的人能解释下/ bp1 getFATblockdpbp unsignedclussec 1 if bp1 0 return 1 / the only error code possible here //我看到现在只要看过READ_CLUSTER/ if unsignedCluster2 READ_CLUSTER bp1-gtb_flag BFR_DIRTY BFR_VALID /fbp1指向下个byte/ fbp1 ampbp1-gtb_buffer0 /fbp1只是unsigned char阿?总共也就8位的,左移8位还有吗??//高高低低原则/ cluster fbp0 fbp1 ltlt 8 unsigned res cluster / Now to unpack the contents of the FAT entry. Odd and / / even bytes are packed differently. //如果要寻找的idx是奇数的话,则要/ if Cluster1 amp 0x01 cluster gtgt 4 cluster amp 0x0fff/因为我只要看获取一个空闲fat,所以我就看到了这里 当fat项是0时候,说明是空闲的 / if unsignedCluster2 READ_CLUSTER if cluster gt MASK12 return LONG_LAST_CLUSTER if cluster BAD12 return LONG_BAD return cluster /如果不是在寻找空闲的fat那么可以计算空闲的fat/ if cluster FREE wasfree cluster res / Cluster2 may be set to LONG_LAST_CLUSTER 0x0FFFFFFFUL or 0xFFFF / / -- please dont remove this mask / cluster2 unsignedCluster2 amp 0x0fff / Now pack the value in / if Cluster1 amp 0x01 cluster amp 0x000f cluster2 ltlt 4 else cluster amp 0xf000 cluster cluster2 fbp0 UBYTEcluster fbp1 UBYTEcluster gtgt 8else .
上一篇:
vsftp添加虚拟用户
下一篇:
手机媒体营销分析