自己動手從零寫桌面作業系統GrapeOS系列教學——22.檔案系統與FAT16

2023-03-24 06:06:07

學習作業系統原理最好的方法是自己寫一個簡單的作業系統。


新買的硬碟和優盤在第一次使用時需要格式化,有時候還需要分割區。這是為什麼呢?分割區和格式化到底是幹啥呢?本講將為大家解開這些疑惑。

一、檔案系統

1.分割區

首先說一下分割區,我們平時看到的C槽、D槽等就是一個個分割區。硬碟第一個磁區的一部分固定空間叫做分割區表,劃分分割區就是在這個分割區表中記錄一下各分割區的資訊,包括各個分割區從哪個磁區開始,到哪個磁區結束等。由於GrapeOS所用虛擬硬碟的空間大小隻有4MB,沒必要分割區,所以我們在MBR中也沒有填寫分割區表。

2.格式化

格式化是在某個分割區上做的。如果一個盤沒有做分割區,那就將整個盤作為一個分割區看待,GrapeOS就是這樣的。大家如果對硬碟或優盤做過格式化就會知道,格式化的時候會讓你選擇一種檔案系統,常見的選項有NTFS、FAT32、exFAT等。所謂格式化就是將某種檔案系統的資訊寫入到這個分割區的一部分磁區上。那什麼是檔案系統呢?下面來簡單介紹一下。

3.檔案系統

計算機一開始是沒有檔案和檔案系統概念的。前面我們學習了對硬碟的讀寫,我們知道對硬碟的讀寫是按磁區為單位進行的。在讀寫硬碟的時候我們有用到檔案的概念嗎?沒有。到目前為止,我們用的虛擬硬碟上並沒有任何檔案系統,就和剛買的新硬碟一樣,但並不影響我們讀寫硬碟。但是在沒有檔案系統的情況下實際使用會非常麻煩。比如你將多個檔案寫入到硬碟上,你需要記錄每個檔案存放在了那些磁區上;如果為一個檔案增加了一些內容,需要多佔用一些磁區,你需要知道哪些磁區是空閒的。這些問題都是需要檔案系統處理的。早期的計算機之所以沒有檔案系統也能用是因為當時的每個外部記憶體上的資料都是為某一件事專用的,有配套的程式做處理,並不能像現在隨意往硬碟裡存放各種檔案。總之,檔案系統是為了方便在硬碟或其它儲存裝置上儲存資料而抽象出來的一種資料管理方式。只說是抽象出來的,這個不好理解,檔案系統有很多種,需要結合一種具體的檔案系統講解才能明白。下面我們介紹一下GrapeOS中用的檔案系統FAT16。

二、FAT16

1.FAT16空間分佈

首先大家需要明白兩個概念,檔案屬性和檔案內容。檔案屬性一般包含檔名稱、大小、修改日期等資訊。檔案內容是指檔案內具體包含的東西,比如一個文字檔案,它的內容就是裡面的文字資訊。
在FAT16檔案系統中,一般會將硬碟或某個分割區劃分為5個部分:引導磁區、FAT1表、FAT2表、根目錄區、資料區。如下圖所示:

  • 引導磁區就是硬碟或分割區的第一個磁區。
  • 根目錄區存放的就是根目錄中檔案和資料夾的屬性資訊。
  • 資料區存放的是所有檔案和資料夾的內容。
  • FAT1表和FAT2表存放的是檔案內容的簇號,也就是記錄每個檔案的內容存放在了哪些磁區中。簇是FAT16資料區中的一個空間單位,每個簇等於若干個磁區,具體等於多少個磁區,需要在引導磁區中設定。在GrapeOS中每個簇設定等於一個磁區。簇是FAT16中用來存放檔案資料的基本單位,不可分割,一個簇內的空間不能一部分屬於一個檔案,而另一部分屬於另一個檔案。比較特殊的一點是資料區中的簇號不是從0開始的,而是從2開始的。
    FAT2表是FAT1表的備份,大小完全相同,正常情況下里面的資料也完全相同。如果發生不正常的情況可以用FAT2表中的資料恢復FAT1表。在GrapeOS中我們不考慮這種不正常的情況,所以捨棄了FAT2表。如下圖所示:

2.FAT16引導磁區

FAT16檔案系統引導磁區結構表:

名稱 偏移 長度 內容 GrapeOS的值
BS_jmpBoot 0 3 一個短跳轉指令 jmp boot_start nop
BS_OEMName 3 8 廠商名稱 GrapeOS
BPB_BytsPerSec 11 2 每磁區位元組數 0x0200
BPB_SecPerClus 13 1 每簇磁區數 0x01
BPB_RsvdSecCnt 14 2 保留磁區數(引導磁區的磁區數) 0x0001
BPB_NumFATs 16 1 FAT表的份數 0x01
BPB_RootEntCnt 17 2 根目錄可容納的目錄項數 0x0200
BPB_TotSec16 19 2 磁區總數 0x2000(4MB)
BPB_Media 21 1 媒介描述符 0xf8
BPB_FATSz16 22 2 每個FAT表磁區數 0x0020
BPB_SecPerTrk 24 2 每磁軌磁區數 0x0020
BPB_NumHeads 26 2 磁頭數 0x0040
BPB_HiddSec 28 4 隱藏磁區數 0x00000000
BPB_TotSec32 32 4 如果BPB_TotSec16是0,由這個值記錄磁區數。 0x00000000
BS_DrvNum 36 1 int 13h的驅動器號 0x80
BS_Reservedl 37 1 未使用 0x00
BS_BootSig 38 1 擴充套件引導標記 0x29
BS_VolID 39 4 卷序列號 0x00000000
BS_VolLab 43 11 卷標 Grape OS
BS_FileSysType 54 8 檔案系統型別 FAT16
引導程式碼及其它 62 448 引導程式碼、資料及其它填充字元等
結束標誌 510 2 0xAA55 0xAA55

從上表中可以看到,FAT16引導磁區中前62個位元組是有固定格式的,FAT16的格式化就是將上表中的格式資料寫入到引導磁區中。上表中的資料並非每一行都有用,我們用到的有:BPB_BytsPerSec、BPB_SecPerClus、BPB_RsvdSecCnt、BPB_NumFATs、BPB_RootEntCnt、BPB_TotSec16、BPB_FATSz16。根據這些資訊就能推斷出GrapeOS的硬碟FAT16磁區分佈:

3.FAT16目錄項

資料夾也叫目錄,檔案和資料夾的屬性都儲存在目錄項中,在根目錄和其它目錄中存放的是一個一個的目錄項,也就是說資料夾的內容就是目錄項列表。每個目錄項有32個位元組,具體結構如下:

名稱 偏移 長度 描述
DIR_Name 0 11 檔名8位元組,擴充套件名3位元組
DIR_Attr 11 1 目錄項屬性(0x10代表資料夾,0x20代表檔案)
保留位 12 10 保留位
DIR_WrtTime 22 2 最後一次寫入時間
DIR_WrtDate 24 2 最後一次寫入日期
DIR_FstClus 26 2 起始簇號
DIR_FileSize 28 4 檔案大小

每個磁區可以存放16個目錄項。

4.FAT表和FAT表項

前面我們講到,在FAT16的資料區中是以簇為單位編號的,簇號從2開始依次遞增。FAT16的簇號是用16位元二進位制數表示的,這也是FAT16中16的含義。除了前2個簇號不用,最後的16個簇號有特殊用途,FAT16最多可以管理216-2-16=65518個簇。
在目錄項中,DIR_FstClus存放的是起始簇號。如果一個檔案或資料夾的內容在一個簇裡放不下,需要多個簇,其它簇號需要記錄到FAT表中。在FAT16的FAT表中,每兩個位元組是一個FAT表項,每個FAT表項代表一個簇,從第一個FAT表項開始依次代表簇0、簇1、簇2、簇3、簇4等等,用來表示每個簇是否已被佔用或下一個簇。對於每個FAT表項,如果它的值是0表示該簇未使用,可以用來存放新資料,對於一個剛格式化完的硬碟,FAT表中除了前2個表項,其它表項應該都是0。如果FAT表項的值不為0,表示該簇已被佔用,而且這個值就是檔案內容下一個簇的簇號,這樣就實現了檔案內容在資料區中的鏈式儲存。從目錄項中拿到檔案的起始簇號,在起始簇號對應的FAT表項中的值就是存放檔案內容的第二個簇號,在第二個簇號對應的FAT表項中的值就是存放檔案內容的第三個簇號……舉個例子,比如一個檔案的起始簇號是5,在第5個FAT表項中存放的是檔案內容的第2個簇號,假設第2個簇號是8,則會在第8個FAT表項中存放第3個簇號,以此類推,就像連結串列一樣,直到下一個簇號大於等於0xfff8,表示檔案內容結束,請見下圖。

上圖中表示這個檔案共佔用3個簇的空間,簇號分別是5、8、9。我們只要把這個簇連結串列中每個簇的資料從資料區裡讀取出來,並按簇連結串列的順序存放在一起就是檔案的完整內容。
FAT表項取值說明:

FAT表項 範例值 描述
0 0xfff8 磁碟表示字(實際無用,設為0即可。)
1 0xffff 第一個簇不可用(實際無用,設為0即可。)
2
3
……
0x0003
0x0004
……
0x0000:可用簇
0x00020xffef:已用簇,標識下一個簇的簇號<br>0xfff00xfff6:保留簇
0xfff7:壞簇
0xfff8~0xffff:檔案的最後一個簇

前面我們已經提到,GrapeOS的FAT表有32個磁區,每個磁區有256個FAT表項,則共有8192個FAT表項。由於資料區簇號是從2開始的,FAT表中的前2個FAT表項不使用,也就是最多能管理8190個簇。我們這裡一個簇等於一個磁區,所以這裡的FAT表最多能管理8190個磁區。而我們這裡的資料區共8127個磁區,FAT表大小夠用了。


視訊版地址:https://space.bilibili.com/1688387238
配套的程式碼與資料在:https://gitee.com/jackchengyujia/grapeos-course
GrapeOS作業系統交流QQ群:643474045