天天看點

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

1. FAT12 檔案系統

說起來

FAT12

檔案系統的曆史相當久遠,早在

DOS

系統的時代就使用

FAT12

作為檔案系統使用,一直沿用至今仍會在軟碟的結構上使用

FAT12

格式。

當軟碟以

FAT12

格式組織格式化後将會以如下标準設定:

  • 兩個磁頭;
  • 每個磁頭有

    80

    個磁道;
  • 每個磁道有

    18

    個扇區;
  • 每個扇區大小為

    512

    位元組。

标準

FAT12

軟碟空間:

2 * 80 * 18 * 512

=

1474560B

=

1440KB

=

1.44MB

是以一個标準的

1.44MB

大小的

FAT12

格式軟碟共有

2 * 80 * 18

=

2880

個扇區。這

2880

個扇區被分為

5

個部分,如下:

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

2. MBR (Main Boot Record)

MBR (Main Boot Record)

主引導記錄占用大小為

1

個扇區,即

512 B

。在這個扇區裡記錄了整個檔案系統的組織結構資訊和引導程式兩部分内容。

辨別 偏移量 類型 大小 預設值 描述
BS_JmpBoot db 3 - 跳轉指令
BS_OEMName 3 db 8 MSWIN4.1 OEM字元串,必須為 8 個字元,不足會以空格填充
BPB_BytePerSec 11 dw 2 0x200 每個扇區位元組數
BPB_SecPerClus 12 db 1 1 每簇占用的扇區數
BPB_RsvdSecCnt 14 dw 2 1 Boot占用的扇區數
BPB_NumFATs 16 db 1 2 FAT表的數量
BPB_RootEntCnt 17 dw 2 0xE0 根目錄可容納的目錄項數
BPB_TotSec16 19 dw 2 0xB40 邏輯扇區總數
BPB_Media 21 db 1 0xF0 媒體描述符
BPB_FATSz16 22 dw 2 9 每個FAT占用扇區數
BPB_SecPerTrk 24 dw 2 0x12 每個磁道扇區數
BPB_NumHeads 26 dw 2 2 磁頭數
BPB_HiddSec 28 dd 4 隐藏扇區數
BPB_TotSec32 32 dd 4 若BPB_TotSec16是0,則在這裡記錄扇區總數
BS_DrvNum 36 db 1 中斷 13(int 13h)的驅動器号
BS_Reserved1 37 db 1 未使用
BS_Bootsig 38 db 1 0x29 擴充引導标志
BS_VolID 39 dd 4 卷序列号
BS_VolLab 43 db 11 - 卷标,必須為11個字元,不足會以空格填充
BS_FileSysType 54 db 8 FAT12 檔案系統類型,必須是8個字元,不足以空格填充
BOOT_Code 62 db 448 0x00 引導代碼,由偏移0位元組(BS_JmpBoot)跳轉過來
END 510 db 2 0x55, 0xAA 系統引導辨別,引導扇區結束辨別

BPB_NumFATs: 描述在存儲媒體中

FAT

表的數量。此處雖然規定最小設定的值為

1

,但是為了能夠起到恢複檔案的作用,一般建議設定為

2

,即表示擁有兩份

FAT

表。

BPB_Media: 描述存儲媒體類型,對于不可移動的存儲媒體,标準值為

0xF8

,對于可移動的存儲媒體,常用值為

0xF0

。該字段的合法值有

0xF0

0xF8

0xF9

0xFA

0xFB

0xFC

0xFD

0xFE

0xFF

。此處寫入的值也必須向

FAT

的第

項的最後一個位元組寫入同樣的值。

3. FAT 表

本文采用兩個

FAT

表格式的

FAT12

檔案系統,由于

FAT2

是用于資料恢複作用,是以

FAT2

的内容與

FAT1

表的内容完全相同,即是拷貝了

FAT1

一份。

FAT12

檔案系統以簇 (

Cluster

) 為機關配置設定資料區(管理扇區),每個簇大小為

BPB_NumFATs * BPB_RootEntCnt

個位元組。

FAT

表中的表項位寬與

FAT

類型有關,

FAT12

檔案系統的表項位寬為

12bit

FAT16

的表項位寬為

16bit

,而

FAT32

的表項位寬為

32bit

FAT

表中的表項與資料區的簇是一一對應的關系,即一個表項對應資料區的一個簇大小的記憶體單元。

FAT

表項的取值如下:

FAT 項 可取值 描述
BPB_Media 磁盤辨別字,低位元組需與 BPB_Media 數值保持一緻
1 FFFh 表示第一個簇已占用
2 ~ N 000h 可用簇
002h~FEFh 已用簇
FF0h~FF6h 保留簇
FF7h 壞簇
FF8h~FFFh 檔案的最後一個簇

[注]:FAT[0] 和 FAT[1] 始終不作為資料區的索引使用。

4. 根目錄和資料區

根目錄區隻儲存目錄項 (

BootEntry

) 資訊,資料區的不僅可以儲存目錄項資訊,也可以儲存檔案資料。目錄項是由一個

32B

組成的結構體,目錄項本身可以表示一個目錄,也可以表示一個檔案,其中記錄着名字、長度 以及資料起始簇号等資訊。其完整結構如下:

名稱 偏移 長度 描述
DIR_Name 0x00 11 檔案名 8B,擴充名 3B
DIR_Attr 0x0B 1 檔案屬性
保留 0x0C 10 保留位
DIR_WrtTime 0x16 2 最後一次寫入時間
DIR_WrtDate 0x18 2 最後一次寫入日期
DIR_FstCtus 0x1A 2 起始簇号
DIR_FileSize 0x1C 4 檔案大小

其中

DIR_FstClus

字段描述的是檔案在磁盤中存放的具體位置,由于

FAT[0]

FAT[1]

已明确其作用不能用于資料區的簇索引,是以這裡的值不能取

1

,有效值将從

2

開始。

根目錄占用扇區數的計算方法為:

(BPB_RootEntCnt * 32 + BPB_BytesPerSec - 1) / BPB_BytesPerSec = (224 * 32 + 512 - 1) / 512 = 14

,根目錄區的扇區起始号為

MBR + FAT[0] + FAT[1] = 1+ 9 + 9 = 19

,資料區的扇區起始号為

Root + Sizeof( Root ) = 19 + 14 = 33

5. 用執行個體說明

聽了上面這麼多的概念性東西,總覺得講的很虛,讓我們用實際的例子來認識這個

FAT12

結構。

5.1. 建立 1.44MB 軟碟

需要用到的工具:WinImagne

打開

WinImage

軟體,選擇 檔案 > 建立,選擇

1.44MB

大小。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結
【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

5.2. 準備好要放置的檔案

需要事先準備好需要放置進去的檔案,這裡筆者準備了兩個。一個名為

imboot.txt

,其中可以看到隻有簡單的一句話,這段内容長度隻有

32 KB

,在檔案系統中會占據一個簇的大小。

另一個名為

BPB.txt

的檔案,這裡的内容是摘抄一篇有關

FAT

檔案系統中

BPB

介紹的内容,該檔案總長度為

2488 KB

,按照

FAT12

中規定的每簇中僅包含

1

個扇區,即每個簇為

512 KB

,是以按照道理該檔案将會在檔案系統中為其配置設定

5

個簇來存儲,即

5 * 512 = 2560KB

。這裡讀者需要自己做實驗的話,随便填充檔案内容,隻要超過

1024KB

即可,目的是為了檢視

FAT

表項的索引簇号的原理,是以需要必須超過一個簇大小的檔案。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

5.3. 放置檔案進根目錄

依次選擇 鏡像 > 加入,找到提前準備好的檔案,選擇即可。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

5.4. 導出為軟碟格式

可以看到我們準備好的檔案已經放置進來。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

依次選擇 檔案 > 另存為,這裡的格式選擇

vfd

或者

ima

格式均可。(其它格式筆者并未嘗試,可以自行選擇嘗試,記得留言告訴筆者哦❤️)

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

5.5. 打開輸出的鏡像檔案

這裡筆者選擇的使用

VSCode

軟體,當然還有很多其它文本檢視工具可以以

Hex

格式閱讀文本,根據個人習慣選擇即可。

首先簡單看一下這裡的内容,第一個扇區就不用看了,第一個扇區主要記錄檔案系統的結構資訊以及引導程式,這裡直接定位到了第二個扇區的起始位置

200h

,雖然暫時還不明白這串内容是什麼,但至少我們已經發現了,第一個扇區的最後兩個位元組為

0x55

0xAA

,這起碼說明我們的檔案格式是沒問題的。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

5.6. 檢視根目錄區

根據

FAT12

檔案系統的結構,

MBR

FAT[1]

FAT[2]

分别占用

1

個扇區、

9

個扇區、

9

個扇區,即根目錄的起始扇區号應該為

1 + 9 + 9 = 19

。十六進制的位址為

19 * 512 = 2600h

。OK,我們直接定位到檔案的

2600h

的位置。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

其實你已經從檔案右側的

ASCII

碼解碼器顯示的文本中看到了剛才我們放入的兩個檔案名。由于

Inter x86

采用的小端存儲,即低位元組存儲在地位,高位位元組存儲在高位,是以這裡看到的字母是順序的。

我們已經知道了根目錄是由一個個目錄項組成的,而在

FAT12

結構中,一個目錄項長度為

32 bit

,在這裡剛好占兩行。這裡筆者以

C

語言結構體的形式來解讀這裡的根目錄項内容。

将根目錄項視為一個

C

語言的結構體:

struct RootEntry {
char DIR_Name[11];			// 前 8B 為檔案名,後 3B 為擴充名
char DIR_Attr[1];			// 檔案屬性
char DIR_Save[10];			// 未使用,保留
char DIR_WrtTime[2];		// 最後一次寫入時間
char DIR_WrtDate[2];		// 最後一次寫入日期
char DIR_FstClus[2];		// 起始簇号
char DIR_FileSize[4];		// 檔案大小
};
           

先來看第一個目錄項:

struct RootEntry Entry_01 = {
	.DIR_Name = {0x49, 0x4D, 0x42, 0x4F, 0x4F, 0x54, 0x20, 0x20, 0x54, 0x58, 0x54},	// IMBOOT  TXT
	.DIR_Attr = 0x00,	
	.DIR_Save = {0x18, 0x2A, 0x92, 0x7B, 0x0F, 0x55, 0x00, 0x00, 0x00, 0x00},
	.DIR_WrtTime = {0xC3, 0x7B},	// 0x7BC3
	.DIR_WrtDate = {0x0F, 0x55},	// 0x550F
	.DIR_FstClus = {0x07, 0x00},	// 0x0007
	.DIR_FileSize = {0x20, 0x00, 0x00, 0x00}	// 0x00000020 = 32
};
           

從這裡我們可以看出這個目錄項是對

imboot.txt

檔案的描述,檔案屬性為

0x00

表示普通檔案,可任意讀寫。

DIR_FstClus

的值為

0x0007

,表示該檔案在資料區的起始簇号為

7

DIR_FileSize

的值為

0x20

,表示該檔案大小為

32 B

再看第二個目錄項:

struct RootEntry Entry_02 = {
	.DIR_Name = {0x42, 0x50, 0x42, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x58, 0x54},	// BPB     TXT
	.DIR_Attr = 0x00,	
	.DIR_Save = {0x10, 0x1B, 0x9D, 0x7B, 0x0F, 0x55, 0x00, 0x00, 0x00, 0x00},
	.DIR_WrtTime = {0x7A, 0x7C},	// 0x7C7A
	.DIR_WrtDate = {0x0F, 0x55},	// 0x550F
	.DIR_FstClus = {0x02, 0x00},	// 0x0002
	.DIR_FileSize = {0xB8, 0x09, 0x00, 0x00}	// 0x000009B8 = 2488
};
           

從檔案名可以看出,該目錄項是對

BPB.txt

檔案,同樣屬性是普通檔案。

DIR_FstClus

的值為

0x0002

,表示該檔案在資料區的起始簇号為

2

DIR_FileSize

的值為

0x09B8

,表示該檔案大小為

2488 B

,可以對比 上圖 中檔案大小,是一樣的。

5.7. 如何根據根目錄項檢視檔案内容

當我們找到一個目錄項後,最重要關心的是該檔案儲存在資料區的起始簇号,根據這裡的簇索引便可以在資料區找到該檔案對應的第一個簇,緊接着再去查

FAT[1]

表中的對應表項(例,檔案起始簇号為

20

,需要檢視

FAT

表中的第

20

項),根據表項内容知道需要繼續找下一個簇還是已經找完所有簇到了檔案結束位置。具體流程大概如下圖這樣:

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

5.8. FAT 表的檢視方式

FAT12

FAT

表的每個表項長度為

12 bit

,加上小端存儲的緣故,這裡閱讀起來并不會那麼直覺。筆者來解讀一下這裡應該如何閱讀。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

上圖正是以文中的

FAT

表為例,可以了解為一個

FAT

表項是由一個位元組和另一個位元組的一半拼接而成,上圖僅是為了容易了解畫的示意圖。而實際上上圖中的這幾個位元組内容從記憶體中完全拿出來并排序後會變成這樣:

0x00_40_03_FF_FF_F0

,然後再以

12 bit

斷之後就會得到這樣的效果:

0x004_003_FFF_FF0

,這樣正好會與

FAT

表中的資料對應起來,

FAT[0]

0xFF0

表示可移動存儲媒體,

FAT[1]

0xFFF

表示第

1

個簇已經被占用。

5.9. 檢視 IMBOOT.TXT 檔案

根據上文分析,

imboot.txt

檔案在資料區的起始簇号為

7

,那麼首先需要去資料區找到第

7

号簇,根據上文分析,我們知道資料區的起始扇區号為

33

,那麼資料區的起始簇的位址為

33 * 512 = 4200h

,這個位址對于資料區來講是第一個簇,但根目錄項中的起始簇有效值是從

2

開始,即根目錄中的

2

号簇對應的即為資料區的起始簇,這個内容在上文也提到過,為了避免翻來翻去,筆者将上文截圖貼在這裡。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

那麼這樣計算的話,第

7

簇就應該在第

2

簇的基礎上再加上

5

個簇的大小,即得到

imboot.txt

在資料區存儲位置,

(33 + 5) * 512 = 4C00h

,讓我們直接定位到檔案的

4C00h

的位置。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

雖然這裡我們很直覺的看到,該檔案的所有内容都被儲存在這裡,但對于整套檢索流程并沒有結束,在查閱完第

7

号簇後,應立馬去

FAT

表檢視第

7

個表項,這裡我們隻用看

FAT1

表即可,定位到

FAT1

表的位置

200h

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

通過上文我們已經會檢視

FAT

表項了,這裡的

FAT[7]

的值為

FFFh

,表示該簇為最後一個簇,到這裡将不會繼續索引下去,檔案内容結束。

5.10. 檢視 BPB.TXT 檔案

已經分析過

imboot.txt

檔案,再來看

BPB.txt

将會非常的快了。根據上文分析,

BPB.txt

檔案在資料區的起始簇号為

2

,也就是資料區的第一個簇單元,直接定位到資料區的第一個簇位置

4200h

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

每個簇大小為

512 B

,當讀完

2

号簇後,将會去

FAT

表中查詢第

2

号表項。

【實作作業系統 02】FAT12 檔案系統(擺脫術語用實際例子介紹)1. FAT12 檔案系統2. MBR (Main Boot Record)3. FAT 表4. 根目錄和資料區5. 用執行個體說明#小結#參考連結

FAT[2]

的值為

003h

,那麼這時候表示下一個簇号為

3

号簇,再讀完數區的第

3

簇後又會回來查詢

FAT[3]

表項,接下來的

4

5

簇以及

FAT[4]

FAT[5]

3

相同,

FAT[5]

中的值為

006h

,在讀完資料區的

6

号簇後,來查詢

FAT[6]

,發現

FAT[6]

的值為

FFFh

,表示檔案結束。

#小結

到這裡,相信各位讀者已經對

FAT12

檔案系統有了清楚的認識,本來是要在接下來介紹使用

FAT12

檔案系統實作

Boot

加載

Loader

程式到記憶體中的内容,但忽然看了一下本文已經超出

8500

字了,閱讀到這裡顯然大家已經累了,那麼請休息一會,然後請繼續接着看筆者的下一篇文章《使用 FAT12 檔案系統實作簡單的 Boot 加載 Loader 到記憶體》

#參考連結

[1] FAT12/16/32 Media Boot Record: https://docs.microsoft.com/en-us/azure/rtos/filex/chapter3#fat121632-media-boot-record

[2] FAT Filesystem: http://elm-chan.org/docs/fat_e.html

[3] exFAT file system specification: https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification

覺得這篇文章對你有幫助的話,就留下一個贊吧^v^*

請尊重作者,轉載還請注明出處!感謝配合~

[作者]: Imagine Miracle

[版權]: 本作品采用「署名-非商業性使用-相同方式共享 4.0 國際」許可協定進行許可。

[本文連結]: https://blog.csdn.net/qq_36393978/article/details/126305288