codefans

导航

<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

统计

常用链接

留言簿(2)

随笔分类

随笔档案

文章分类

文章档案

程序设计链接

搜索

最新评论

阅读排行榜

评论排行榜

[开发教程]FAT 12 文件系统简介

小谢 发表于 2005-8-26 11:51:06

  有不少朋友在论坛或是发邮件给我,问关于FAT12的问题。对一些开发操作系统的朋友来说,软盘或软盘镜像是不可或缺的系统载体,我们的操作系统要在存储介质上操作就几乎不可能离开文件系统,如果想了解一下FAT12、FAT16、FAT32之类的Windows 用过的文件系统,可以去:http://www.yesky.com/20030313/1656880.shtml 
如果想全面地了解硬盘结构,文件系统原理,下面的一系列文章是很不错的材料:
http://www.sjhf.net/Article/sjhfdoc/200404/1.html
http://www.sjhf.net/Article/sjhfdoc/200404/2.html
http://www.sjhf.net/Article/sjhfdoc/200404/3.html
http://www.sjhf.net/Article/sjhfdoc/200404/4.html
http://www.sjhf.net/Article/Index.html

  本文主要介绍以3.5英寸的1.44M标准格式化的FAT12文件系统的软盘为介绍对象。这里强调那么多是因为:1.44M的软盘格式化可以不是1.44M,可以大于也可以小于;格式化的文件系统也可以不是FAT12。

  为什么会出现正常的1.44M软盘格式化后可大可小的情况呢?从软盘及软盘驱动器原理出发,软盘的寻址方式(可以认为是读取数据的方式)是:CHS,C = Cylinder(柱面),H = Header(磁头),S = Sector(扇区)。标准地格式化后,磁盘将被格式化为 每面80磁道(80个同心圆,柱面),每个磁道有18个扇区,每个扇区是 512字节,那么高密3.5英寸软盘的容量为:2×80×18×512 = 1474560 Byte = 1440 KB = 1.44 MB。然而,软盘可以不格式为80磁道,每个磁道也可以不是18扇区,这是题外话,如果您有兴趣,可以用古老的HDCopy试试。

  文件存储到磁盘上时至少要占用1个扇区,即使这个文件只有1个字节,如果文件有513字节,那就得占用2个扇区,下一个文件就不能用这只使用了一个字节的扇区。即软盘以扇区为单位存储文件。现在用下面的假设来说明本文的目的:
  假设只有18个扇区的磁盘,以 0 - 17 编址,如果一个文件保存在 1 - 6扇区,另一文件保存在 7 - 16扇区,如果我们对第一个文件增加了内容,又需要一个扇区来保存它,但由于文件连续存储, 7号扇区是第二个文件的,我们当然不能用它,只有最后留有一个扇区可用,我们会不会把第二个文件先挪到8-17扇区以腾出一个扇区来给第一个文件使用呢?当只有少数两个文件的时候可以,但有很多文件的时候会变得麻烦起来。如果我们用一个表来表示有一个文件占用了 1-6扇区 和 17扇区,那事情就简单了——我们不必为文件不连续而烦恼。这个表就叫它:文件分配表(File Allocation Table)。那怎样才能知道这个文件存储的文件名和文件存放的起始扇区?再建一个表,用于存放文件名、起始扇区、文件创建时间、文件实际大小等等资料,这个表叫:文件目录表(File Directory Table)。将这两个表放在磁盘指定的位置,以便操作系统使用,磁盘的其它扇区全都用来存放文件的实际内容,这就构成了有文件系统的磁盘。

  磁盘上,0面0磁道第1扇区用于存放引导程序,如果这512字节最后两个字节分别是0x55,0xAA(一个字是0xAA55),称为可引导标志,BIOS会将这512字节读取出来执行,操作系统便是利用这里来实现引导的。标识软盘是不是FAT12并不是没有根据的,在这512字节中,还有一个设备头用于标识这个软盘(设备),例子如下:

;===========================================================================
; 程序执行的第一条指令必须是跳转(如果你想使用FAT12这类文件系统的磁盘)

; 必须占用3字节
;===========================================================================
jmp SHORT main ; 2 bits,跳转到主程序执行
nop            ; 1 bit
;===========================================================================
; FAT12 文件系统头,从NYAOS 借过来的,可以参考相关的文档以获得更多细节
; 这个块会让 Winimage 认出编译后的二进制文件为有效的引导文件
; 如果不使用这个块,Winimage将不会将其作为引导程序处理
; 但我们可以借助其它方法和工具处理,比如DEBUG
;===========================================================================
bsOEM       db "ExOS0.02"               ; OEM String,任意你喜欢的8字节ASCII码
bsSectSize  dw 512                      ; Bytes per sector
bsClustSize db 1                        ; Sectors per cluster
bsRessect   dw 1                        ; # of reserved sectors
bsFatCnt    db 2                        ; # of fat copies
bsRootSize  dw 224                      ; size of root directory
bsTotalSect dw 2880                     ; total # of sectors if < 32 meg
bsMedia     db 0xF0                     ; Media Descriptor
bsFatSize   dw 9                        ; Size of each FAT
bsTrackSect dw 18                       ; Sectors per track
bsHeadCnt   dw 2                        ; number of read-write heads
bsHidenSect dd 0                        ; number of hidden sectors
bsHugeSect  dd 0                        ; if bsTotalSect is 0 this value is
                                        ; the number of sectors
bsBootDrv   db 0                        ; holds drive that the bs came from
bsReserv    db 0                        ; not used for anything
bsBootSign  db 29h                      ; boot signature 29h
bsVolID     dd 0                        ; Disk volume ID also used for temp
                                        ; sector # / # sectors to load
bsVoLabel   db "NO NAME    "            ; Volume Label
bsFSType    db "FAT12   "               ; File System type <- FAT 12文件系统
;===========================================================================
; Main start here
;===========================================================================
main:
#至于如何引导计算机,可以参考我Blog里的more.asp?name=xemean&id=2

  0面0道第2扇区到第10扇区的9个扇区是FAT表的存放位置,为了预防,0面0道的第11扇区到1面0道第1扇区的9个扇区是第2个FAT表的存放位置,这第2个FAT是备用的,当第一个FAT出了问题里,可以用第2个FAT。1面0道的第2扇区起到1面0道的第15扇区(共14个扇区)用于存放 FDT。FDT没有备份,所以没有第二个FDT。这里要注意的是,磁盘为了读写的速度,0面0道的18个扇区接下来的是 1面0道的扇区,而不是0面1道,因为0面0道跟1面0道同在一个柱面上(同心圆),只是用的磁头不同。

  FAT12 中,每个文件分配表项只占12位(bit),即1.5字节(byte),每个表项代表一个扇区,在这里,磁盘只有扇区的概念,磁盘里所有扇区都被类似于上一段提到的磁盘读写方式线性地编址(LBA),不再有CHS。这里还要提一提簇的概念:DOS会把2个扇区作为一簇,那么文件就要以簇为单位读写。簇的大小通常根据磁盘的大小设定,以尽可能少浪费磁盘空间为本。

  FAT12每个表项的值指出文件存放的下一个扇区号,同时也是表项入口。比如如果文件的存放的第一个扇区是002,那系统首先找FAT的002,在002处得到一个值003,表示文件下一个扇区是003号,再接着003表项找,得到006...,表项的值含义如下:
000 - 此簇未用;FF8 - FFF 该簇为文件的最后一簇;FF0 - FF7,此簇为坏,不可用;其它值表示文件下一簇的簇号。
  下面的图来说明FAT的基本原理:
表项编号  值(16位)   备注 
000   | FF0  | <- 000 项 001项为表头,1字节 0xF0表示存储介质
001   | FFF  | <- 2、3字节为 0xFFFF ,固定值,FAT标志
002   | 003  | <- 文件下一簇为003
003   | 005  | <- 下一簇:005
004   | FF7  | <- 坏簇,不可用
005   | 011  | <- 下一簇:011
........................................
011   | FF8  | <- 该文件结束
012   | 000  | <- 可用簇
.......................................
根据上表,我们可以知道,一个文件占用了 002,003,005,011 这4个簇。
  簇号 + 31 = 逻辑扇区号 //// 31 = 保留扇区数 + 隐藏扇区数 + FAT数×每个FAT所占扇区数 + FDT所占扇区数 - 2 = 1 + 0 + 2*18 + 14 -2
  LBA = 逻辑扇区号 - 1
  扇区 = (LBA MOD 每道扇区数) + 1
  磁道 = (LBA / 每道扇区数) / 磁头数
  磁头 = (LBA / 每道扇区数) MOD 磁头数

根据上面的公式,得到以下计算值:
002: S = ( 32 MOD 18 ) + 1 = 15
002: C = ( 32 / 18 ) / 2 = 0
002: H = ( 32 / 18 ) MOD 2 = 1
-----------------
011: S = ( ( 11+31-1) MOD 18) + 1 = 6
011: C = ( ( 11+31-1) / 18) / 2 = 1
011: H = ( ( 11+31-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 - 系统文件;10(1x) - 该文件是目录。

  就此,本文已经基本介绍完了软盘的结构,下面介绍如何读一个文件:

  1. 给出一个文件名,比如“KERNEL.SYS”
  2. 将文件名扩展为“KERNEL  SYS”,即去掉点并为文件名和扩展名补充空格
  3. 读FDT到内存中(用BIOS INT 13)
  4. 在FDT中查找到符合的文件名
  5. 可选,判断在FDT中找到的是否是目录
  6. 在符合的FDT中取出文件首簇号
  7. 读入FAT,可以选择读入两个FAT表,以检查是否有效
  8. 将簇号转换为CHS,将扇区读入内存
  9. 根据簇号在FAT中查找下一簇,并判断是否是文件最后一簇
  10. 如果是文件最后一簇,则文件读取完毕;如果不是,则转第8步

  如果在引导程序中读指定的内核文件,则可以省略1、2步,直接给出内核文件名即可。

  如果给出的文件是带目录的,那这里还有必要介绍一下:实际上,目录也是一个文件,只不过这个文件是一个FDT,FDT指出该目录下其它文件或目录。因此,给出如下路径:/EXOS/KERNEL.BIN ,则先是在根目录中,将“EXOS    ”这个“文件”读出来,然后在读出的FDT中找“KERNEL  BIN”。

  好了,本文至此告一段落,但愿能给大家一定的帮助。近期正在写一个ERP,时间仓促,本文写得也有不尽如人意的地方,更没有代码实例。还请大家见谅。

X.
2005-08-26


阅读全文(73) | 回复(3) | 引用(0)
 


回复:FAT 12 文件系统简介
future0906(游客)发表评论于2005-8-29 11:08:27
以下引用xemean在2005-8-28 16:20:19的评论:

表头的三个字节的值是 0xFFFFF0,即第1个字节是0xF0,第二个字节是0xFF,第三个字节也是 0xFF。按照小拉丁写法,高位在前(左),低位在后(右),所以写成 FF0我认为并没有错。


恩,我明白你的意思了~~,谢

个人主页 | 引用 | 返回
 


回复:FAT 12 文件系统简介
xemean发表评论于2005-8-28 16:20:19

表头的三个字节的值是 0xFFFFF0,即第1个字节是0xF0,第二个字节是0xFF,第三个字节也是 0xFF。按照小拉丁写法,高位在前(左),低位在后(右),所以写成 FF0我认为并没有错。


个人主页 | 引用 | 返回
 

posted on 2005-09-14 16:21 春雷的博客 阅读(1126) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航: