文件系統(tǒng)已經(jīng)經(jīng)歷了很多年的發(fā)展,很難用一篇文章把文件系統(tǒng)完整的講清楚。
本篇定位科普貼,涵蓋文件系統(tǒng)中大多數(shù)概念與特性。
0x01 什么是文件系統(tǒng)?
計算機的文件系統(tǒng)是一種存儲和組織計算機數(shù)據(jù)的方法,它使得對其訪問和查找變得容易,文件系統(tǒng)使用文件和樹形目錄的抽象邏輯概念代替了硬盤和光盤等物理設(shè)備使用數(shù)據(jù)塊的概念,用戶使用文件系統(tǒng)來保存數(shù)據(jù)不必關(guān)心數(shù)據(jù)實際保存在硬盤(或者光盤)的地址為多少的數(shù)據(jù)塊上,只需要記住這個文件的所屬目錄和文件名。在寫入新數(shù)據(jù)之前,用戶不必關(guān)心硬盤上的那個塊地址沒有被使用,硬盤上的存儲空間管理(分配和釋放)功能由文件系統(tǒng)自動完成,用戶只需要記住數(shù)據(jù)被寫入到了哪個文件中。
上面這段話來自維基百科對文件系統(tǒng)的介紹,真是晦澀難懂??偨Y(jié)成一句大白話就是方便用戶存和取文件的東西。
下面我們會基于這個重點從多個維度了解文件系統(tǒng)。
0x02 常見的文件系統(tǒng)有哪些?
FAT16: 采用16bit記錄長度信息實屬硬傷,導(dǎo)致磁盤分區(qū)最大只能到2GB。這里特別寫出FAT16是因為UEFI引導(dǎo)中ESP分區(qū)默認采用的是FAT16文件系統(tǒng)。
exFAT:FAT家族的文件系統(tǒng)發(fā)展到FAT32居然還有單文件不能大于4G的硬傷,這個問題在exFat里得以解決。exFat是windows,linux,macOS都支持的較好的文件系統(tǒng)。
NTFS:NTFS是一個跟我同齡(93年出生)的文件系統(tǒng)。最新版本是NTFS3.1,從windows xp一直用到win10。三大操作系統(tǒng)也只有windows自己能夠完美支持NTFS的讀寫操作。在macOS和linux上面使用三方庫對NTFS執(zhí)行大量寫操作都有丟數(shù)據(jù)的風(fēng)險。
Ext4:廣泛運用于各大linux發(fā)行版和android的文件系統(tǒng)。
APFS:蘋果于2016年在WWDC宣布的新一代文件系統(tǒng)用以代替年老的HFS+。從macOS10.13,ios10.3版本開始均已默認使用macOS文件系統(tǒng)。參考之前寫過一篇macOS文件系統(tǒng)(http://m.itdecent.cn/p/c401d546cebf)
0x03 扇區(qū)(Sector)和簇(Cluster)基本概念
最大的區(qū)別是:扇區(qū)是物理硬盤層面的容量單位,而簇是文件系統(tǒng)層面的容量單位。
機械硬盤是由多個盤片組成,每個盤片包含兩個面,每個盤面都對應(yīng)地有一個讀/寫磁頭。磁頭走過的路就是磁道,磁盤的磁道是一個個同心圓。磁盤上的每個磁道被等分為若干個弧段,這些弧段便是磁盤的扇區(qū)。硬盤的讀寫以扇區(qū)為基本單位。具體參考下圖:

因為扇區(qū)的單位太小,因此把它捆在一起,組成一個更大的單位更方便進行靈活管理就形成了簇。簇是文件系統(tǒng)存儲管理的的最小單位,在分區(qū)被格式化為文件系統(tǒng)時就將簇大小定了下來。每個文件系統(tǒng)對簇大小有自己的喜好,比如NTFS和Ext4喜歡用4096(8個扇區(qū))作為簇大小,f2fs則默認用2M作為塊大小。
文件系統(tǒng)中文件的存取是以簇為基本單位。以簇大小是4K為例,無論文件大小是1K還是3K文件系統(tǒng)都會分配4K大小給它,分配了但是未被使用的空間稱為slack空間,slack空間的使用信息隱藏技術(shù)慣用手段。(參考信息隱藏第一課:https://www.computersecuritystudent.com/FORENSICS/HIDING/lesson1/index.html)
不同的文件系統(tǒng)喜歡用不同的名稱,比如NTFS中喜歡叫
Cluster,其他別名包括Block,Page,Fragment,Chunk。其實是同一個東西。
0x04 文件系統(tǒng)的最小模型:tar
tar和zip的數(shù)據(jù)結(jié)構(gòu)已經(jīng)在我的文章中多次提及了,這也是特別常用的數(shù)據(jù)結(jié)構(gòu)。
tar的數(shù)據(jù)結(jié)構(gòu)十分簡單:文件元數(shù)據(jù)與數(shù)據(jù)部分。再感受下tar的元數(shù)據(jù)部分數(shù)據(jù)結(jié)構(gòu):
| Field offset | Field size | Field |
|---|---|---|
| 0 | 100 | File name |
| 100 | 8 | File mode |
| 108 | 8 | Owner's numeric user ID |
| 116 | 8 | Group's numeric user ID |
| 124 | 12 | File size in bytes (octal base) |
| 136 | 12 | Last modification time in numeric Unix time format (octal) |
| 148 | 8 | Checksum for header record |
| 156 | 1 | Link indicator (file type) |
| 157 | 100 | Name of linked file |
對比于ls -l命令的返回值,你會發(fā)現(xiàn)一個文件的核心要素都在這里了。
在一個文件系統(tǒng)中,文件的元數(shù)據(jù)信息至少包括文件名,文件權(quán)限,文件類型,文件大小,所屬用戶與所屬組,存儲文件元數(shù)據(jù)信息的結(jié)構(gòu)體叫inode。
0x05 tar的升級版zip
相比于tar,zip提供了與真正文件系統(tǒng)更接近的特性:
- 有magic number作為自身標志
判斷一個文件是否是zip文件首先看前4個字節(jié)十六進制是否是0x50 0x4b 0x03 0x04。如同判斷是否是F2FS文件系統(tǒng)時首先檢查1024起始的4個字節(jié)是否是0x10 0x20 0xF5 0xF2。 - 文件元數(shù)據(jù)與文件數(shù)據(jù)分離
zip文件格式由文件數(shù)據(jù)區(qū)、中央目錄結(jié)構(gòu),中央目錄結(jié)束標志組成。在中央目錄結(jié)構(gòu)區(qū)記錄了大量文件的元數(shù)據(jù)信息,通過deHeaderOffset偏移獲得該文件在文件數(shù)據(jù)區(qū)的偏移。這個行為更貼近于文件系統(tǒng)的存儲方式,在文件元數(shù)據(jù)中存放一個指向真正數(shù)據(jù)的偏移。文件系統(tǒng)中的文件數(shù)據(jù)在磁盤上不一定是連續(xù)存放的,所以文件元數(shù)據(jù)區(qū)會存放多個數(shù)據(jù)偏移和長度的組合,這種組合在NTFS中叫data run,在其他文件系統(tǒng)中叫extent。 - 壓縮數(shù)據(jù)以節(jié)省空間
文件會先經(jīng)過deflat壓縮然后進入zip的文件數(shù)據(jù)區(qū),這是一種節(jié)省空間的方案。
文件系統(tǒng)中節(jié)省空間有2種方案:sparse文件和文件內(nèi)容壓縮。
sparse(稀疏)文件是各大文件系統(tǒng)都會比較喜歡的高效利用磁盤空間的方案,除了最差勁的HFS不支持sparse特性。當文件中部分(至少一個簇)內(nèi)容或者全部內(nèi)容為空(全0)時,則在文件系統(tǒng)中不為空數(shù)據(jù)分配空間。
文件內(nèi)容壓縮Apple文件系統(tǒng)(HFS/HFS+/APFS)的特色,而且這些文件中并不是所有文件數(shù)據(jù)都會被壓縮。因為數(shù)據(jù)的壓縮意味著讀取和修改時都需要經(jīng)歷解壓再壓縮的操作,很明顯這個過程是很耗時間的。只有不被頻繁修改的文件才適合啟用壓縮選項,比如庫文件,可執(zhí)行的二進制文件。 - 擴展域
相比于tar,zip有一個很大的優(yōu)點是提供了擴展域的支持。擴展域用于存儲數(shù)據(jù)結(jié)構(gòu)未規(guī)定的信息。比如zip標準數(shù)據(jù)結(jié)構(gòu)中只有文件最后修改時間這個字段,但是文件創(chuàng)建時間和最后訪問時間也很重要?。〈藭r就用到了擴展域。
文件不僅僅包含元數(shù)據(jù)和文件內(nèi)容。部分文件系統(tǒng)還提供了attribute這個概念,類似于zip的擴展域用以記錄文件更多的信息。比如NTFS允許自行追加命名的$DATA屬性內(nèi)容,就形成了ADS流。APFS文件系統(tǒng)中"com.apple.decmpfs"記錄了文件內(nèi)容被壓縮后的數(shù)據(jù),類似的還有"com.apple.FinderInfo","com.apple.ResourceFork"等其他擴展屬性。 - 數(shù)據(jù)加密
文件打包為zip時允許輸入密碼以加密文件內(nèi)容?,F(xiàn)代部分文件系統(tǒng)也在逐漸帶入加密特性支持,比如新出生的APFS和依然在發(fā)展的F2FS。老文件系統(tǒng)想加密數(shù)據(jù)只能依靠操作系統(tǒng)或者三方軟件幫忙了,比如NTFS,HFS+。
macOS10.13版本之前采用的文件系統(tǒng)是HFS和HFS+,因為HFS和HFS+文件系統(tǒng)本身不具備加密特性,所以macOS中FileVault功能采用的邏輯卷管理方案(Core Storage)。因為Core Storage是在操作系統(tǒng)層面做的加密,所以數(shù)據(jù)可以落到任意文件系統(tǒng)上面(對文件系統(tǒng)透明),并且生成一個未加密的邏輯設(shè)備對上層文件讀寫操作隱藏加密這個細節(jié)。在這種情況下如果對邏輯設(shè)備打鏡像是未加密的,對原始磁盤打鏡像則是加密的。
macOS10.13中引入APFS文件系統(tǒng)后,操作系統(tǒng)事情變得簡單了。因為直接采用文件系統(tǒng)層面的加密,所以也省去了Core Storage這個中間層。對上層文件讀寫操作而言依然感受不到數(shù)據(jù)被加密解密的過程。在這種情況下只能在操作系統(tǒng)層面關(guān)閉FileVault功能(會將磁盤上所有加密文件解密)再打未加密磁盤鏡像,或者直接打磁盤鏡像在取證軟件中解密。
0x06 文件的inum
inum(index number)概念廣泛存在于所有文件系統(tǒng),用于唯一標識某個文件,存儲在每個文件的元數(shù)據(jù)數(shù)據(jù)結(jié)構(gòu)中。注意與上面提到的inode概念區(qū)分,inode是一個結(jié)構(gòu)體保存文件元數(shù)據(jù)信息,inum是存儲在inode中的一個序號。
每個文件的inum可以通過ls命令查看,下面是針對ls命令的-i參數(shù)官方文檔解釋(來自man ls):
-i, --inode
print the index number of each file
ls -li命令返回值示例(inum在第一列):
3407873 drwxr-xr-x 2 root root 4.0K Sep 12 14:48 bin
4718593 drwxr-xr-x 3 root root 4.0K Oct 8 14:05 boot
4849665 drwxr-xr-x 4 root root 4.0K May 5 11:19 data
2 drwxr-xr-x 19 root root 3.9K Oct 7 12:48 dev
6029313 drwxr-xr-x 111 root root 4.0K Oct 7 12:48 etc
5505025 drwxr-xr-x 4 root root 4.0K Jan 11 2019 home
22 lrwxrwxrwx 1 root root 33 Oct 7 12:48 initrd.img -> boot/initrd.img-4.15.0-65-generic
12 lrwxrwxrwx 1 root root 33 Oct 7 12:48 initrd.img.old -> boot/initrd.img-4.15.0-64-generic
當理解inum這個概念后,就很容易的理解linux命令中很多命令。比如ls -l展示出來的硬鏈接數(shù),軟鏈接與硬鏈接的本質(zhì)區(qū)別,find命令中-inum參數(shù)如何使用。
文件系統(tǒng)很多,但每個幾近相同。編程語言很多,但基本概念是共通的。三大操作系統(tǒng)本質(zhì)上也沒有區(qū)別。