ext2 檔案系統解析

今夕何兮發表於2024-08-11

ext2檔案系統整體佈局

每個塊組內部都有相關的後設資料對該塊組進行管理。如圖所示,第一個塊組中的後設資料包括引導塊、超級塊、塊組描述符、預留GDT塊、資料塊點陣圖、inode點陣圖、inode表和其它資料塊。後續塊組中有些是對超級塊的備份,有些則沒有第一個塊組這麼完整的後設資料資訊,而只有資料塊點陣圖、inode點陣圖和inode表等後設資料資訊。也就是說塊組其實分為兩種,一種是有超級塊的,比較複雜的塊組(如圖3下面淡棕色所示),另外一種是沒有超級塊的,比較簡單的塊組(如圖3上面淡綠色所示)。
image
image

本次實驗用1G大小檔案模擬磁碟,對齊進行格式化ext2檔案系統,然後檢視其物理儲存結構資訊。

dd if=/dev/zero of=/tmp/bk bs=1024k count=1024
mkfs.ext2 /tmp/bk
dumpe2fs /dev/bk
hexdump -s 1024 -n 4096 /tmp/bk -C # 檢視超級塊資訊,磁碟偏移量為1024,儲存在第1個4k塊中

1. 超級塊super block

每個ext2檔案系統都必須包含一個超級塊,其中儲存了該檔案系統的大量基本資訊,包括塊的大小、每塊組中包含的塊數等。同時,系統會對超級塊進行備份,備份被存放在其他塊組的第一個塊中,備份數量不確定,也就是其他塊組可能沒有超級塊,也可能有。超級塊的起始位置為其所在分割槽的第1024個位元組,佔用1KB的空間,如果初始化指定塊大小1k,那麼超級塊在第二個塊內,如果塊大小為4k,超級塊則儲存在第一個塊內,偏移量1024位元組,內容佔用長度1024位元組。原因是:
image
超級塊結構如下:
image
image

下圖展示了超級塊資訊:
image

2. 塊組描述符表BGT

磁碟分割槽格式化為ext2時,會將分割槽劃分為多個塊組block group,一個塊組描述符用以描述一個塊組的屬性。塊組描述符組由若干塊組描述符組成,描述了檔案系統中所有塊組的屬性,存放於超級塊所在塊的下一個塊中。一個塊組描述符的結構如下,單個描述符佔用32位元組,本次實驗1G空間共劃分8個bg:
image
核心屬性介紹:

__le32 bg_block_bitmap; // 塊點陣圖所在的第一個塊的塊ID(地址資訊)
__le32 bg_inode_bitmap; // inode點陣圖所在的第一個塊的塊ID(地址資訊)
__le32 bg_inode_table; // inode表所在的第一個塊的塊ID(地址資訊)
__le16 bg_free_blocks_count; // 塊組中未使用的塊數
__le16 bg_free_inodes_count; // 塊組中未使用的inode數
__le16 bg_used_dirs_count; // 塊組分配的目錄的inode數

下圖展示了塊組描述符部分GDT資訊:
image

3. 塊點陣圖block bitmap和索引節點點陣圖inode bitmap

塊點陣圖和inode點陣圖的每一位分別指出塊組中對應的那個塊或inode是否被使用,在點陣圖中,0位表示對應項處於FREE狀態,1位表示對應項處於IN_USE狀態。塊點陣圖是一個點陣圖,一個二進位制位代表一個塊,記錄塊組中每個塊的使用情況,標記哪些塊已被分配,哪些是空閒的,幫助檔案系統管理塊的分配和釋放,維護塊的空閒狀態。Inode點陣圖是一個點陣圖,記錄塊組中每個inode的使用情況,標記已分配和空閒的inode。 幫助檔案系統管理inode的分配和釋放,維護inode的空閒狀態。
根據塊組描述符找到對應的block點陣圖:
image
inode點陣圖:
image

4. inode表

inode表一列表的形式儲存了檔案的後設資料資訊,包括檔案大小、擴充套件屬性和時間等內容。由於inode結構的大小根據格式化檔案系統的屬性而有差異,因此該表佔用的磁碟空間不定,大概若干個邏輯塊的大小。關於檔名稱與inode資料結構的關係是透過inode的id確定的,在資料夾中的檔案儲存包含檔名和inode的id資訊,而透過該id可以計算出inode資料結構位於的塊組位置和inode表位置。

/*
 * Structure of an inode on the disk
 */
struct ext2_inode {
  __le16  i_mode;   /* File mode */
  __le16  i_uid;    /* Low 16 bits of Owner Uid */
  __le32  i_size;   /* Size in bytes */
  __le32  i_atime;  /* Access time */
  __le32  i_ctime;  /* Creation time */
  __le32  i_mtime;  /* Modification time */
  __le32  i_dtime;  /* Deletion Time */
  __le16  i_gid;    /* Low 16 bits of Group Id */
  __le16  i_links_count;  /* Links count */
  __le32  i_blocks; /* Blocks count */
  __le32  i_flags;  /* File flags */
  union {
    struct {
      __le32  l_i_reserved1;
    } linux1;
    struct {
      __le32  h_i_translator;
    } hurd1;
    struct {
      __le32  m_i_reserved1;
    } masix1;
  } osd1;       /* OS dependent 1 */
  __le32  i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
  __le32  i_generation; /* File version (for NFS) */
  __le32  i_file_acl; /* File ACL */
  __le32  i_dir_acl;  /* Directory ACL */
  __le32  i_faddr;  /* Fragment address */
  union {
    struct {
      __u8  l_i_frag; /* Fragment number */
      __u8  l_i_fsize;  /* Fragment size */
      __u16 i_pad1;
      __le16  l_i_uid_high; /* these 2 fields    */
      __le16  l_i_gid_high; /* were reserved2[0] */
      __u32 l_i_reserved2;
    } linux2;
    struct {
      __u8  h_i_frag; /* Fragment number */
      __u8  h_i_fsize;  /* Fragment size */
      __le16  h_i_mode_high;
      __le16  h_i_uid_high;
      __le16  h_i_gid_high;
      __le32  h_i_author;
    } hurd2;
    struct {
      __u8  m_i_frag; /* Fragment number */
      __u8  m_i_fsize;  /* Fragment size */
      __u16 m_pad1;
      __u32 m_i_reserved2[2];
    } masix2;
  } osd2;       /* OS dependent 2 */
};

5. 資料塊

對於普通檔案,資料塊中存放檔案的內容。對於目錄檔案,資料塊存放目錄項。

測試檔案寫入:

mkdir /t
mount /tmp/bk /t

image
image
找到對應磁碟位置,二進位制列印13號的inode資訊:
image
根據對應欄位關係,找到inode裡面儲存檔案對應資料塊的陣列,由於檔案較小,分配了一個塊,找到第一個4位元組整數,解析得到檔案塊號為1598.然後二進位制列印1598塊內容,得到該檔案儲存內容與寫入一致:
image
image

關於目錄

在ext2檔案系統中,目錄是作為檔案儲存的。根目錄總是在inode表的第二項,而其子目錄則在根目錄檔案的內容中定義.目錄不過是一種特殊的檔案。每個目錄也有一個inode,會對其分配資料塊。資料塊中儲存的是用於描述目錄下檔案的目錄項,目錄下每個檔案或目錄對應一個目錄項,記錄了該檔案的檔名和inode對應關係,檔案型別。rec_len域是目錄項的長度,把它與目錄項的起始地址相加就得到下一個目錄項的起始地址,因此說,rec_len可以被解釋為指向下一個有效目錄項的指標。為了刪除一個目錄項,把ext2_dir_entry_2的inode域置為0並適當增加前一個有效目錄項rec_len域的值就可以了.

image
struct ext2_dir_entry_2 {
__le32 inode; // 檔案入口的inode號,0表示該項未使用
__le16 rec_len; // 目錄項長度,檔名是字元陣列,不定長
__u8 name_len; // 檔名包含的字元數
__u8 file_type; // 檔案型別
char name[255]; // 檔名
};
請注意:由上可知,以下情形可以改變目錄內容:新增檔案,刪除檔案,修改檔名,修改檔案型別,修改目錄下檔案大小是不會修改目錄的內容,也就是系統看到目錄的修改時間不會變。修改目錄內部目錄裡面的內容,也不會導致外層目錄發生變化

參考:https://www.bilibili.com/read/cv1891885/
https://baike.baidu.com/item/Ext2/822106?fr=ge_ala
https://blog.csdn.net/m0_73898917/article/details/136033920
https://blog.51cto.com/u_15346415/5170913
https://www.jianshu.com/p/9b81daa0adcb
https://blog.csdn.net/YoungMLet/article/details/135604457

相關文章