設計一個文件系統,需要考慮哪些因素?

  • 2020 年 3 月 18 日
  • 筆記

文件系統的實現

在對文件有了基本認識之後,現在是時候把目光轉移到文件系統的實現上了。之前用戶關心的一直都是文件是怎樣命名的、可以進行哪些操作、目錄樹是什麼,如何找到正確的文件路徑等問題。而設計人員關心的是文件和目錄是怎樣存儲的、磁盤空間是如何管理的、如何使文件系統得以流暢運行的問題,下面我們就來一起討論一下這些問題。

文件系統布局

文件系統存儲在磁盤中。大部分的磁盤能夠劃分出一到多個分區,叫做磁盤分區(disk partitioning) 或者是磁盤分片(disk slicing)。每個分區都有獨立的文件系統,每塊分區的文件系統可以不同。磁盤的 0 號分區稱為 主引導記錄(Master Boot Record, MBR),用來引導(boot) 計算機。在 MBR 的結尾是分區表(partition table)。每個分區表給出每個分區由開始到結束的地址。系統管理員使用一個稱為分區編輯器的程序來創建,調整大小,刪除和操作分區。這種方式的一個缺點是很難適當調整分區的大小,導致一個分區具有很多可用空間,而另一個分區幾乎完全被分配。

MBR 可以用在 DOS 、Microsoft Windows 和 Linux 操作系統中。從 2010 年代中期開始,大多數新計算機都改用 GUID 分區表(GPT)分區方案。

下面是一個用 GParted 進行分區的磁盤,表中的分區都被認為是 活動的(active)

當計算機開始引 boot 時,BIOS 讀入並執行 MBR。

引導塊

MBR 做的第一件事就是確定活動分區,讀入它的第一個塊,稱為引導塊(boot block) 並執行。引導塊中的程序將加載分區中的操作系統。為了一致性,每個分區都會從引導塊開始,即使引導塊不包含操作系統。引導塊佔據文件系統的前 4096 個位元組,從磁盤上的位元組偏移量 0 開始。引導塊可用於啟動操作系統。

在計算機中,引導就是啟動計算機的過程,它可以通過硬件(例如按下電源按鈕)或者軟件命令的方式來啟動。開機後,電腦的 CPU 還不能執行指令,因為此時沒有軟件在主存中,所以一些軟件必須先被加載到內存中,然後才能讓 CPU 開始執行。也就是計算機開機後,首先會進行軟件的裝載過程。

重啟電腦的過程稱為重新引導(rebooting),從休眠或睡眠狀態返回計算機的過程不涉及啟動。

除了從引導塊開始之外,磁盤分區的布局是隨着文件系統的不同而變化的。通常文件系統會包含一些屬性,如下

超級塊

緊跟在引導塊後面的是 超級塊(Superblock),超級塊 的大小為 4096 位元組,從磁盤上的位元組偏移 4096 開始。超級塊包含文件系統的所有關鍵參數

  • 文件系統的大小
  • 文件系統中的數據塊數
  • 指示文件系統狀態的標誌
  • 分配組大小

在計算機啟動或者文件系統首次使用時,超級塊會被讀入內存。

空閑空間塊

接着是文件系統中空閑塊的信息,例如,可以用位圖或者指針列表的形式給出。

BitMap 位圖或者 Bit vector 位向量

位圖或位向量是一系列位或位的集合,其中每個位對應一個磁盤塊,該位可以採用兩個值:0和1,0表示已分配該塊,而1表示一個空閑塊。下圖中的磁盤上給定的磁盤塊實例(分配了綠色塊)可以用16位的位圖表示為:0000111000000110。

使用鏈表進行管理

在這種方法中,空閑磁盤塊鏈接在一起,即一個空閑塊包含指向下一個空閑塊的指針。第一個磁盤塊的塊號存儲在磁盤上的單獨位置,也緩存在內存中。

碎片

這裡不得不提一個叫做碎片(fragment)的概念,也稱為片段。一般零散的單個數據通常稱為片段。 磁盤塊可以進一步分為固定大小的分配單元,片段只是在驅動器上彼此不相鄰的文件片段。如果你不理解這個概念就給你舉個例子。比如你用 Windows 電腦創建了一個文件,你會發現這個文件可以存儲在任何地方,比如存在桌面上,存在磁盤中的文件夾中或者其他地方。你可以打開文件,編輯文件,刪除文件等等。你可能以為這些都在一個地方發生,但是實際上並不是,你的硬盤驅動器可能會將文件中的一部分存儲在一個區域內,另一部分存儲在另外一個區域,在你打開文件時,硬盤驅動器會迅速的將文件的所有部分匯總在一起,以便其他計算機系統可以使用它。

inode

然後在後面是一個 inode(index node),也稱作索引節點。它是一個數組的結構,每個文件有一個 inode,inode 非常重要,它說明了文件的方方面面。每個索引節點都存儲對象數據的屬性和磁盤塊位置

有一種簡單的方法可以找到它們 ls -lai 命令。讓我們看一下根文件系統:

inode 節點主要包括了以下信息

  • 模式/權限(保護)
  • 所有者 ID
  • 組 ID
  • 文件大小
  • 文件的硬鏈接數
  • 上次訪問時間
  • 最後修改時間
  • inode 上次修改時間

文件分為兩部分,索引節點和塊。一旦創建後,每種類型的塊數是固定的。你不能增加分區上 inode 的數量,也不能增加磁盤塊的數量。

緊跟在 inode 後面的是根目錄,它存放的是文件系統目錄樹的根部。最後,磁盤的其他部分存放了其他所有的目錄和文件。

文件的實現

最重要的問題是記錄各個文件分別用到了哪些磁盤塊。不同的系統採用了不同的方法。下面我們會探討一下這些方式。分配背後的主要思想是有效利用文件空間快速訪問文件 ,主要有三種分配方案

  • 連續分配
  • 鏈表分配
  • 索引分配

連續分配

最簡單的分配方案是把每個文件作為一連串連續數據塊存儲在磁盤上。因此,在具有 1KB 塊的磁盤上,將為 50 KB 文件分配 50 個連續塊。

上面展示了 40 個連續的內存塊。從最左側的 0 塊開始。初始狀態下,還沒有裝載文件,因此磁盤是空的。接着,從磁盤開始處(塊 0 )處開始寫入佔用 4 塊長度的內存 A 。然後是一個佔用 6 塊長度的內存 B,會直接在 A 的末尾開始寫。

注意每個文件都會在新的文件塊開始寫,所以如果文件 A 只佔用了 3 又 1/2 個塊,那麼最後一個塊的部分內存會被浪費。在上面這幅圖中,總共展示了 7 個文件,每個文件都會從上個文件的末尾塊開始寫新的文件塊。

連續的磁盤空間分配有兩個優點。

  • 第一,連續文件存儲實現起來比較簡單,只需要記住兩個數字就可以:一個是第一個塊的文件地址和文件的塊數量。給定第一個塊的編號,可以通過簡單的加法找到任何其他塊的編號。

  • 第二點是讀取性能比較強,可以通過一次操作從文件中讀取整個文件。只需要一次尋找第一個塊。後面就不再需要尋道時間和旋轉延遲,所以數據會以全帶寬進入磁盤。

因此,連續的空間分配具有實現簡單高性能的特點。

不幸的是,連續空間分配也有很明顯的不足。隨着時間的推移,磁盤會變得很零碎。下圖解釋了這種現象

這裡有兩個文件 D 和 F 被刪除了。當刪除一個文件時,此文件所佔用的塊也隨之釋放,就會在磁盤空間中留下一些空閑塊。磁盤並不會在這個位置擠壓掉空閑塊,因為這會複製空閑塊之後的所有文件,可能會有上百萬的塊,這個量級就太大了。

剛開始的時候,這個碎片不是問題,因為每個新文件都會在之前文件的結尾處進行寫入。然而,磁盤最終會被填滿,因此要麼壓縮磁盤、要麼重新使用空閑塊的空間。壓縮磁盤的開銷太大,因此不可行;後者會維護一個空閑列表,這個是可行的。但是這種情況又存在一個問題,為空閑塊匹配合適大小的文件,需要知道該文件的最終大小

想像一下這種設計的結果會是怎樣的。用戶啟動 word 進程創建文檔。應用程序首先會詢問最終創建的文檔會有多大。這個問題必須回答,否則應用程序就不會繼續執行。如果空閑塊的大小要比文件的大小小,程序就會終止。因為所使用的磁盤空間已經滿了。那麼現實生活中,有沒有使用連續分配內存的介質出現呢?

CD-ROM 就廣泛的使用了連續分配方式。

CD-ROM(Compact Disc Read-Only Memory)即只讀光盤,也稱作只讀存儲器。是一種在電腦上使用的光碟。這種光碟只能寫入數據一次,信息將永久保存在光碟上,使用時通過光碟驅動器讀出信息。

然而 DVD 的情況會更加複雜一些。原則上,一個 90分鐘 的電影能夠被編碼成一個獨立的、大約 4.5 GB 的文件。但是文件系統所使用的 UDF(Universal Disk Format) 格式,使用一個 30 位的數來代表文件長度,從而把文件大小限制在 1 GB。所以,DVD 電影一般存儲在 3、4個連續的 1 GB 空間內。這些構成單個電影中的文件塊稱為擴展區(extends)

就像我們反覆提到的,歷史總是驚人的相似,許多年前,連續分配由於其簡單高性能被實際使用在磁盤文件系統中。後來由於用戶不希望在創建文件時指定文件的大小,於是放棄了這種想法。但是隨着 CD-ROM 、DVD、藍光光盤等光學介質的出現,連續分配又流行起來。從而得出結論,技術永遠沒有過時性,現在看似很老的技術,在未來某個階段可能又會流行起來。

鏈表分配

第二種存儲文件的方式是為每個文件構造磁盤塊鏈表,每個文件都是磁盤塊的鏈接列表,就像下面所示

每個塊的第一個字作為指向下一塊的指針,塊的其他部分存放數據。如果上面這張圖你看的不是很清楚的話,可以看看整個的鏈表分配方案

與連續分配方案不同,這一方法可以充分利用每個磁盤塊。除了最後一個磁盤塊外,不會因為磁盤碎片而浪費存儲空間。同樣,在目錄項中,只要存儲了第一個文件塊,那麼其他文件塊也能夠被找到。

另一方面,在鏈表的分配方案中,儘管順序讀取非常方便,但是隨機訪問卻很困難(這也是數組和鏈表數據結構的一大區別)。

還有一個問題是,由於指針會佔用一些位元組,每個磁盤塊實際存儲數據的位元組數並不再是 2 的整數次冪。雖然這個問題並不會很嚴重,但是這種方式降低了程序運行效率。許多程序都是以長度為 2 的整數次冪來讀寫磁盤,由於每個塊的前幾個位元組被指針所使用,所以要讀出一個完成的塊大小信息,就需要當前塊的信息和下一塊的信息拼湊而成,因此就引發了查找和拼接的開銷。

使用內存表進行鏈表分配

由於連續分配和鏈表分配都有其不可忽視的缺點。所以提出了使用內存中的表來解決分配問題。取出每個磁盤塊的指針字,把它們放在內存的一個表中,就可以解決上述鏈表的兩個不足之處。下面是一個例子

上圖表示了鏈表形成的磁盤塊的內容。這兩個圖中都有兩個文件,文件 A 依次使用了磁盤塊地址 4、7、 2、 10、 12,文件 B 使用了6、3、11 和 14。也就是說,文件 A 從地址 4 處開始,順着鏈表走就能找到文件 A 的全部磁盤塊。同樣,從第 6 塊開始,順着鏈走到最後,也能夠找到文件 B 的全部磁盤塊。你會發現,這兩個鏈表都以不屬於有效磁盤編號的特殊標記(-1)結束。內存中的這種表格稱為 文件分配表(File Application Table,FAT)

使用這種組織方式,整個塊都可以存放數據。進而,隨機訪問也容易很多。雖然仍要順着鏈在內存中查找給定的偏移量,但是整個鏈都存放在內存中,所以不需要任何磁盤引用。與前面的方法相同,不管文件有多大,在目錄項中只需記錄一個整數(起始塊號),按照它就可以找到文件的全部塊。

這種方式存在缺點,那就是必須要把整個鏈表放在內存中。對於 1TB 的磁盤和 1KB 的大小的塊,那麼這張表需要有 10 億項。。。每一項對應於這 10 億個磁盤塊中的一塊。每項至少 3 個位元組,為了提高查找速度,有時需要 4 個位元組。根據系統對空間或時間的優化方案,這張表要佔用 3GB 或 2.4GB 的內存。FAT 的管理方式不能較好地擴展並應用於大型磁盤中。而這正是最初 MS-DOS 文件比較實用,並仍被各個 Windows 版本所安全支持。

inode

最後一個記錄各個文件分別包含哪些磁盤塊的方法是給每個文件賦予一個稱為 inode(索引節點) 的數據結構,每個文件都與一個 inode 進行關聯,inode 由整數進行標識。

下面是一個簡單例子的描述。

給出 inode 的長度,就能夠找到文件中的所有塊。

相對於在內存中使用表的方式而言,這種機制具有很大的優勢。即只有在文件打開時,其 inode 才會在內存中。如果每個 inode 需要 n 個位元組,最多 k 個文件同時打開,那麼 inode 佔有總共打開的文件是 kn 位元組。僅需預留這麼多空間。

這個數組要比我們上面描述的 FAT(文件分配表) 佔用的空間小的多。原因是用於保存所有磁盤塊的鏈接列表的表的大小與磁盤本身成正比。如果磁盤有 n 個塊,那麼這個表也需要 n 項。隨着磁盤空間的變大,那麼該表也隨之線性增長。相反,inode 需要節點中的數組,其大小和可能需要打開的最大文件個數成正比。它與磁盤是 100GB、4000GB 還是 10000GB 無關。

inode 的一個問題是如果每個節點都會有固定大小的磁盤地址,那麼文件增長到所能允許的最大容量外會發生什麼?一個解決方案是最後一個磁盤地址不指向數據塊,而是指向一個包含額外磁盤塊地址的地址,如上圖所示。一個更高級的解決方案是:有兩個或者更多包含磁盤地址的塊,或者指向其他存放地址的磁盤塊的磁盤塊。Windows 的 NTFS 文件系統採用了相似的方法,所不同的僅僅是大的 inode 也可以表示小的文件。

NTFS 的全稱是 New Technology File System,是微軟公司開發的專用系統文件,NTFS 取代 FAT(文件分配表) 和 HPFS(高性能文件系統) ,並在此基礎上進一步改進。例如增強對元數據的支持,使用更高級的數據結構以提升性能、可靠性和磁盤空間利用率等。

目錄的實現

文件只有打開後才能夠被讀取。在文件打開後,操作系統會使用用戶提供的路徑名來定位磁盤中的目錄。目錄項提供了查找文件磁盤塊所需要的信息。根據系統的不同,提供的信息也不同,可能提供的信息是整個文件的磁盤地址,或者是第一個塊的數量(兩個鏈表方案)或 inode的數量。不過不管用那種情況,目錄系統的主要功能就是 將文件的 ASCII 碼的名稱映射到定位數據所需的信息上

與此關係密切的問題是屬性應該存放在哪裡。每個文件系統包含不同的文件屬性,例如文件的所有者和創建時間,需要存儲的位置。一種顯而易見的方法是直接把文件屬性存放在目錄中。有一些系統恰好是這麼做的,如下。

在這種簡單的設計中,目錄有一個固定大小的目錄項列表,每個文件對應一項,其中包含一個固定長度的文件名,文件屬性的結構體以及用以說明磁盤塊位置的一個或多個磁盤地址。

對於採用 inode 的系統,會把 inode 存儲在屬性中而不是目錄項中。在這種情況下,目錄項會更短:僅僅只有文件名稱和 inode 數量。這種方式如下所示

到目前為止,我們已經假設文件具有較短的、固定長度的名字。在 MS-DOS 中,具有 1 – 8 個字符的基本名稱和 1 – 3 個字符的可拓展名稱。在 UNIX 版本 7 中,文件有 1 – 14 個字符,包括任何拓展。然而,幾乎所有的現代操作系統都支持可變長度的擴展名。這是如何實現的呢?

最簡單的方式是給予文件名一個長度限制,比如 255 個字符,然後使用上圖中的設計,並為每個文件名保留 255 個字符空間。這種處理很簡單,但是浪費了大量的目錄空間,因為只有很少的文件會有那麼長的文件名稱。所以,需要一種其他的結構來處理。

一種可選擇的方式是放棄所有目錄項大小相同的想法。在這種方法中,每個目錄項都包含一個固定部分,這個固定部分通常以目錄項的長度開始,後面是固定格式的數據,通常包括所有者、創建時間、保護信息和其他屬性。這個固定長度的頭的後面是一個任意長度的實際文件名,如下圖所示

上圖是 SPARC 機器使用正序放置。

處理機中的一串字符存放的順序有正序(big-endian)逆序(little-endian) 之分。正序存放的就是高位元組在前低位元組在後,而逆序存放的就是低位元組在前高位元組在後。

這個例子中,有三個文件,分別是 project-budgetpersonnelfoo。每個文件名以一個特殊字符(通常是 0 )結束,用矩形中的叉進行表示。為了使每個目錄項從字的邊界開始,每個文件名被填充成整數個字,如下圖所示

這個方法的缺點是當文件被移除後,就會留下一塊固定長度的空間,而新添加進來的文件大小不一定和空閑空間大小一致。

這個問題與我們上面探討的連續磁盤文件的問題是一樣的,由於整個目錄在內存中,所以只有對目錄進行緊湊拼接操作才可節省空間。另一個問題是,一個目錄項可能會分佈在多個頁上,在讀取文件名時可能發生缺頁中斷

處理可變長度文件名字的另外一種方法是,使目錄項自身具有固定長度,而將文件名放在目錄末尾的堆棧中。如上圖所示的這種方式。這種方法的優點是當目錄項被移除後,下一個文件將能夠正常匹配移除文件的空間。當然,必須要對進行管理,因為在處理文件名的時候也會發生缺頁異常。

到目前為止的所有設計中,在需要查找文件名時,所有的方案都是線性的從頭到尾對目錄進行搜索。對於特別長的目錄,線性搜索的效率很低。提高文件檢索效率的一種方式是在每個目錄上使用哈希表(hash table),也叫做散列表。我們假設表的大小為 n,在輸入文件名時,文件名被散列在 0 和 n – 1 之間,例如,它被 n 除,並取餘數。或者對構成文件名字的字求和或類似某種方法。

無論採用哪種方式,在添加一個文件時都要對與散列值相對應的散列表進行檢查。如果沒有使用過,就會將一個指向目錄項的指針指向這裡。文件目錄項緊跟着哈希表後面。如果已經使用過,就會構造一個鏈表(這種構造方式是不是和 HashMap 使用的數據結構一樣?),鏈表的表頭指針存放在表項中,並通過哈希值將所有的表項相連。

查找文件的過程和添加類似,首先對文件名進行哈希處理,在哈希表中查找是否有這個哈希值,如果有的話,就檢查這條鏈上所有的哈希項,查看文件名是否存在。如果哈希不在鏈上,那麼文件就不在目錄中。

使用哈希表的優勢是查找非常迅速,缺點是管理起來非常複雜。只有在系統中會有成千上萬個目錄項存在時,才會考慮使用散列表作為解決方案。

另外一種在大量目錄中加快查找指令目錄的方法是使用緩存,緩存查找的結果。在開始查找之前,會首先檢查文件名是否在緩存中。如果在緩存中,那麼文件就能立刻定位。當然,只有在較少的文件下進行多次查找,緩存才會發揮最大功效。

共享文件

當多個用戶在同一個項目中工作時,他們通常需要共享文件。如果這個共享文件同時出現在多個用戶目錄下,那麼他們協同工作起來就很方便。下面的這張圖我們在上面提到過,但是有一個更改的地方,就是 C 的一個文件也出現在了 B 的目錄下

如果按照如上圖的這種組織方式而言,那麼 B 的目錄與該共享文件的聯繫稱為 鏈接(link)。那麼文件系統現在就是一個 有向無環圖(Directed Acyclic Graph, 簡稱 DAG),而不是一棵樹了。

在圖論中,如果一個有向圖從任意頂點出發無法經過若干條邊回到該點,則這個圖是一個有向無環圖,我們不會在此着重探討關於圖論的東西,大家可以自行 google。

將文件系統組織成為有向無環圖會使得維護複雜化,但也是必須要付出的代價。

共享文件很方便,但這也會帶來一些問題。如果目錄中包含磁盤地址,則當鏈接文件時,必須把 C 目錄中的磁盤地址複製到 B 目錄中。如果 B 或者 C 隨後又向文件中添加內容,則僅在執行追加的用戶的目錄中顯示新寫入的數據塊。這種變更將會對其他用戶不可見,從而破壞了共享的目的。

有兩種方案可以解決這種問題。

  • 第一種解決方案,磁盤塊不列入目錄中,而是會把磁盤塊放在與文件本身相關聯的小型數據結構中。目錄將指向這個小型數據結構。這是 UNIX 中使用的方式(小型數據結構就是 inode)。

  • 在第二種解決方案中,通過讓系統建立一個類型為 LINK 的新文件,並把該文件放在 B 的目錄下,使得 B 與 C 建立鏈接。新的文件中只包含了它所鏈接的文件的路徑名。當 B 想要讀取文件時,操作系統會檢查 B 的目錄下存在一個類型為 LINK 的文件,進而找到該鏈接的文件和路徑名,然後再去讀文件,這種方式稱為 符號鏈接(symbolic linking)

上面的每一種方法都有各自的缺點,在第一種方式中,B 鏈接到共享文件時,inode 記錄文件的所有者為 C。建立一個鏈接並不改變所有關係,如下圖所示。

第一開始的情況如圖 a 所示,此時 C 的目錄的所有者是 C ,當目錄 B 鏈接到共享文件時,並不會改變 C 的所有者關係,只是把計數 + 1,所以此時 系統知道目前有多少個目錄指向這個文件。然後 C 嘗試刪除這個文件,這個時候有個問題,如果 C 把文件移除並清除了 inode 的話,那麼 B 會有一個目錄項指向無效的節點。如果 inode 以後分配給另一個文件,則 B 的鏈接指向一個錯誤的文件。系統通過 inode 可知文件仍在被引用,但是沒有辦法找到該文件的全部目錄項以刪除它們。指向目錄的指針不能存儲在 inode 中,原因是有可能有無數個這樣的目錄。

所以我們能做的就是刪除 C 的目錄項,但是將 inode 保留下來,並將計數設置為 1 ,如上圖 c 所示。c 表示的是只有 B 有指向該文件的目錄項,而該文件的前者是 C 。如果系統進行記賬操作的話,那麼 C 將繼續為該文件付賬直到 B 決定刪除它,如果是這樣的話,只有到計數變為 0 的時刻,才會刪除該文件。

對於符號鏈接,以上問題不會發生,只有真正的文件所有者才有一個指向 inode 的指針。鏈接到該文件上的用戶只有路徑名,沒有指向 inode 的指針。當文件所有者刪除文件時,該文件被銷毀。以後若試圖通過符號鏈接訪問該文件將會失敗,因為系統不能找到該文件。刪除符號鏈接不會影響該文件。

符號鏈接的問題是需要額外的開銷。必須讀取包含路徑的文件,然後要一個部分接一個部分地掃描路徑,直到找到 inode 。這些操作也許需要很多次額外的磁盤訪問。此外,每個符號鏈接都需要額外的 inode ,以及額外的一個磁盤塊用於存儲路徑,雖然如果路徑名很短,作為一種優化,系統可以將它存儲在 inode 中。符號鏈接有一個優勢,即只要簡單地提供一個機器的網絡地址以及文件在該機器上駐留的路徑,就可以連接全球任何地方機器上的文件。

還有另一個由鏈接帶來的問題,在符號鏈接和其他方式中都存在。如果允許鏈接,文件有兩個或多個路徑。查找一指定目錄及其子目錄下的全部文件的程序將多次定位到被鏈接的文件。例如,一個將某一目錄及其子目錄下的文件轉存到磁帶上的程序有可能多次複製一個被鏈接的文件。進而,如果接着把磁帶讀入另一台機器,除非轉出程序具有智能,否則被鏈接的文件將被兩次複製到磁盤上,而不是只是被鏈接起來。

相關參考:

https://zhuanlan.zhihu.com/p/41358013

https://www.linuxtoday.com/blog/what-is-an-inode.html

https://www.lifewire.com/what-is-fragmentation-defragmentation-2625884

https://www.geeksforgeeks.org/free-space-management-in-operating-system/

https://sites.ualberta.ca/dept/chemeng/AIX-43/share/man/info/C/a_doc_lib/aixprggd/genprogc/fsyslayout.htm

https://en.wikipedia.org/wiki/Disk_partitioning

https://en.wikipedia.org/wiki/Master_boot_record

https://en.wikipedia.org/wiki/Booting

https://www.computerhope.com/jargon/f/fileprot.htm

https://en.wikipedia.org/wiki/File_attribute

https://en.wikipedia.org/wiki/Make_(software)

https://unix.stackexchange.com/questions/60034/what-are-character-special-and-block-special-files-in-a-unix-system

https://www.computerhope.com/jargon/d/director.htm

https://www.computerhope.com/jargon/r/regular-file.htm

https://baike.baidu.com/item/固態硬盤/453510?fr=aladdin

《現代操作系統》第四版

《Modern Operation System》fourth