1. 程式人生 > 其它 >資訊安全系統設計與實現:第十一章學習筆記

資訊安全系統設計與實現:第十一章學習筆記

資訊安全系統設計與實現:第十一章學習筆記

20191331 lyx

教材學習內容總結

第十一章 EXT2檔案系統

學習目標

充分理解一個檔案系統,掌握EXT2檔案系統的資料結構,通過簡單程式設計實現EXT2檔案系統的功能,瞭解如何實現支援linux核心檔案的操作的EXT2檔案系統,瞭解檔案系統的三個級別。

什麼是EXT2檔案系統

EXT2第二代擴充套件檔案系統second extended filesystem,縮寫為ext2,是LINUX核心所用的檔案系統。它開始由Rémy Card設計,用以代替ext,於1993年1月加入linux核心支援之中。ext2 的經典實現為LINUX核心中的ext2fs檔案系統驅動,最大可支援2TB的檔案系統,至linux核心2.6版時,擴充套件到可支援32TB。其他的實現包括GNU Hurd,Mac OS X ,Darwin ,BSD。ext2為數個LINUX發行版的預設檔案系統,如Debian、Red Hat Linux等。

其單一檔案大小與檔案系統本身的容量上限與檔案系統本身的簇大小有關,在一般常見的 x86 電腦系統中,簇最大為 4KB, 則單一檔案大小上限為 2048GB, 而檔案系統的容量上限為 16384GB。

但由於目前核心 2.4 所能使用的單一分割區最大隻有 2048GB,實際上能使用的檔案系統容量最多也只有 2048GB。

至於Ext3檔案系統,它屬於一種日誌檔案系統,是對ext2系統的擴充套件。它相容ext2,並且從ext2轉換成ext3並不複雜。

EXT2檔案系統的結構和佈局

檔案系統中儲存的最小單元是塊(block),一個塊的大小是在格式化時確定的。啟動塊(Boot Block)的大小為1KB,由PC標準規定,用來儲存磁碟分割槽資訊和啟動資訊,任何檔案系統都不能修改啟動塊。

啟動塊之後才是ext2檔案系統的開始,ext2檔案系統將整個分區劃分成若干個同樣大小的塊組(Block Group)。

在整體的規劃當中,檔案系統最前面有一個啟動扇區(boot sector),這個啟動扇區可以安裝啟動管理程式, 這是個非常重要的設計,因為如此一來我們就能夠將不同的啟動管理程式安裝到個別的檔案系統最前端,而不用覆蓋整顆硬碟唯一的 MBR 。

每個塊組的組成:

  • 超級塊(Super Block)描述整個分割槽的檔案系統資訊,如inode/block的大小、總量、使用量、剩餘量,以及檔案系統的格式與相關資訊。超級塊在每個塊組的開頭都有一份拷貝(第一個塊組必須有,後面的塊組可以沒有)。 為了保證檔案系統在磁碟部分扇區出現物理問題的情況下還能正常工作,就必須保證檔案系統的super block資訊在這種情況下也能正常訪問。所以一個檔案系統的super block會在多個block group中進行備份,這些super block區域的資料保持一致。

    • 超級塊記錄的資訊有:

    • 1、block 與 inode 的總量(分割槽內所有Block Group的block和inode總量);

    • 2、未使用與已使用的 inode / block 數量;

    • 3、block 與 inode 的大小 (block 為 1, 2, 4K,inode 為 128 bytes);

    • 4、filesystem 的掛載時間、最近一次寫入資料的時間、最近一次檢驗磁碟 (fsck) 的時間等檔案系統的相關資訊;

    • 5、一個 valid bit 數值,若此檔案系統已被掛載,則 valid bit 為 0 ,若未被掛載,則 valid bit 為 1 。

每個區段與 superblock 的資訊都可以使用 dumpe2fs 這個命令查詢

  • 塊組描述符表(GDT,Group Descriptor Table)由很多塊組描述符組成,整個分割槽分成多個塊組就對應有多少個塊組描述符。

每個塊組描述符儲存一個塊組的描述資訊,如在這個塊組中從哪裡開始是inode Table,從哪裡開始是Data Blocks,空閒的inode和資料塊還有多少個等等。塊組描述符在每個塊組的開頭都有一份拷貝。

  • 塊點陣圖(Block Bitmap)用來描述整個塊組中哪些塊已用哪些塊空閒。塊點陣圖本身佔一個塊,其中的每個bit代表本塊組的一個block,這個bit為1代表該塊已用,為0表示空閒可用。假設格式化時block大小為1KB,這樣大小的一個塊點陣圖就可以表示1024*8個塊的佔用情況,因此一個塊組最多可以有10248個塊。

  • inode點陣圖(inode Bitmap)和塊點陣圖類似,本身佔一個塊,其中每個bit表示一個inode是否空閒可用。 Inode bitmap的作用是記錄block group中Inode區域的使用情況,Ext檔案系統中一個block group中可以有16384個Inode,代表著這個Ext檔案系統中一個block group最多可以描述16384個檔案。

  • inode表(inode Table)由一個塊組中的所有inode組成。一個檔案除了資料需要儲存之外,一些描述資訊也需要儲存,如檔案型別,許可權,檔案大小,建立、修改、訪問時間等,這些資訊存在inode中而不是資料塊中。inode表佔多少個塊在格式化時就要寫入塊組描述符中。

在Ext2/Ext3檔案系統中,每個檔案在磁碟上的位置都由檔案系統block group中的一個Inode指標進行索引,Inode將會把具體的位置指向一些真正記錄檔案資料的block塊,需要注意的是這些block可能和Inode同屬於一個block group也可能分屬於不同的block group。我們把檔案系統上這些真實記錄檔案資料的block稱為Data blocks。

  • 資料塊(Data Block)是用來放置檔案內容資料的地方。

注意到OpenEuler作業系統核心也使用EXT2作為檔案系統

其結構為

檔案描述符與開啟檔案之間的關係

在Linux系統中一切皆可以看成是檔案,檔案又可分為:普通檔案、目錄檔案、連結檔案和裝置檔案。檔案描述符(file descriptor)是核心為了高效管理已被開啟的檔案所建立的索引,其是一個非負整數(通常是小整數),用於指代被開啟的檔案,所有執行I/O操作的系統呼叫都通過檔案描述符。程式剛剛啟動的時候,0是標準輸入,1是標準輸出,2是標準錯誤。如果此時去開啟一個新的檔案,它的檔案描述符會是3。

每一個檔案描述符會與一個開啟檔案相對應,同時,不同的檔案描述符也會指向同一個檔案。相同的檔案可以被不同的程序開啟也可以在同一個程序中被多次開啟。系統為每一個程序維護了一個檔案描述符表,該表的值都是從0開始的,所以在不同的程序中你會看到相同的檔案描述符,這種情況下相同檔案描述符有可能指向同一個檔案,也有可能指向不同的檔案。具體情況要具體分析,要理解具體其概況如何,需要檢視由核心維護的3個數據結構。

    1. 程序級的檔案描述符表
    1. 系統級的開啟檔案描述符表
    1. 檔案系統的i-node表

檔案描述符、開啟的檔案控制代碼以及i-node之間的關係

例如要查詢"/home/ealtieri/hello.txt"這個檔案,先從inode2找到root inode,然後從i_block中找到home的ext2_dir_entry_2,然後得到home的inode編號,再遞迴尋找。

EXT2檔案系統在OpenEuler中的實踐

ext2分區劃分的基本單位是block,磁碟上前1024byte是boot block,記錄作業系統在分割槽中的位置。

之後的空間劃分為多個block group(一般代表柱面組)。每個block group的第一個block為super block每個block group的super block都相同,是為了增加冗餘,提高可靠性。

通過 mkfs 建立虛擬磁碟

mke2fs -b blkesize -N ninodes device nblocks
在裝置上建立一個帶有nblocks個塊(每個塊大小為blksize位元組)和ninodes個索引節點的EXT2檔案系統。裝置可以是真實裝置,也可以是虛擬磁碟檔案。如果未指定blksize,則預設塊大小為1KB。如果未指定ninoides,mke2fs將根據 nblocks 計算一個預設的ninodes數。

檢視現有磁碟資訊

使用命令
dd if=/dev/zero of=20191331d bs=1024 count=1440
建立名為20191331d的虛擬磁碟

格式化為EXT2檔案系統
mke2fs 20191331d 1440

EXT2檔案系統的的一些資料結構

一個ext2檔案系統的檔案或目錄包括索引結點和資料塊兩個部分,索引結點存放檔案的屬性、存取許可權、修改時間以及其他的一些資訊,而資料塊存放檔案的內容。

目錄:
當我們在 Linux 下的 ext2 檔案系統建立一個目錄時, ext2 會分配一個 inode 與至少一塊Block 給該目錄。其中,inode 記錄該目錄的相關屬性,並指向分配到的那塊 Block ;而 Block則是記錄在這個目錄下的相關連的目錄的關連性!

檔案:
當我們在 Linux 下的 ext2 建立一個一般檔案時, ext2 會分配至少一個 inode 與相對於該檔案大小的 Block 數量給該檔案。例如:假設我的一個 Block 為 4 Kbytes ,而我要建立一個 100KBytes 的檔案,那麼 linux 將分配一個 inode 與 25 個 Block 來儲存該檔案。

Block#0:
引導塊,檔案系統不會使用它。它用於容納從磁碟引導作業系統的載入程式。

Block#1:
超級塊(在硬碟分割槽中位元組偏移量為1024)。用於容納關於整個檔案系統的資訊。
超級塊中一些重要欄位。

1.SuperBlock超級塊

記錄了block的總數量,inode的數量,block的size等等。

struct ext2_super_block {
    __u32   s_inodes_count;     /* Inodes count */
    __u32   s_blocks_count;     /* Blocks count */
    ...
    __u32   s_free_blocks_count;    /* Free blocks count */
    __u32   s_free_inodes_count;    /* Free inodes count */
    __u32   s_first_data_block; /* First Data Block */
    __u32   s_log_block_size;   /* Block size */
    ...
    __u32   s_blocks_per_group; /* # Blocks per group */
    ...
    __u16   s_magic;        /* Magic signature */
    ...

2.Group Description塊組描述符

記錄了磁碟上所有block group的資訊(為了冗餘),當然包含本block group的資訊:block bitmap的位置,inode bitmap的位置,inode table的位置

struct ext2_group_desc
{
    __u32   bg_block_bitmap;    /* Blocks bitmap block */
    __u32   bg_inode_bitmap;    /* Inodes bitmap block */
    __u32   bg_inode_table;     /* Inodes table block */
    __u16   bg_free_blocks_count;   /* Free blocks count */
    __u16   bg_free_inodes_count;   /* Free inodes count */
    __u16   bg_used_dirs_count; /* Directories count */
    __u16   bg_pad;
    __u32   bg_reserved[3];
};

3.block bitmap,inode bitmap

0表示block是free,1表示block被佔用

4.Inode table索引節點

儲存ext2_inode資料結構的地方,每個ext2_inode有個編號,編號從1開始,root inode的編號為2

struct ext2_inode {
        __u16   i_mode;         /* File type and access rights */
        __u16   i_uid;          /* Low 16 bits of Owner Uid */
        __u32   i_size;         /* Size in bytes */
        __u32   i_atime;        /* Access time */
        __u32   i_ctime;        /* Creation time */
        __u32   i_mtime;        /* Modification time */
        __u32   i_dtime;        /* Deletion Time */
        __u16   i_gid;          /* Low 16 bits of Group Id */
        __u16   i_links_count;  /* Links count */
        __u32   i_blocks;       /* Blocks count */
        __u32   i_flags;        /* File flags */
    ...
    __u32   i_block[EXT2_N_BLOCKS];  /* Pointers to blocks */
    ...
};

i_mode儲存檔案型別和讀取許可權

當i_mode為檔案時,i_blocks表示data block的指標。

當i_mode為資料夾時,i_blocks表示ext2_dir_entry_2的指標。

每個ext2_dir_entry_2的大小都不一樣,所以查詢ext2_dir_entry_2時要線性搜尋,這是時間換空間。

使用df命令檢視各個分割槽掛在情況

檢視超級塊

郵差演算法

郵差演算法:在計算機系統中, 經常出現下面這個問題。 一個城市有M 個街區, 編號從 0到M-1。 每個街區有N座房子, 編號從0 到 N-1。每座房子有一個唯一的街區地址, 用(街區, 房子)表示, 其中0<=街區<M, 0<=房子<N。 來自外太空的外星人可能不熟悉地球上的街區定址方案, 傾向於採用線性方法將這些房子地址編為 0, 1, ···, N-1, N, N+1 等。 已知某個街區地址 BA= (街區, 房子), 怎麼把它轉換為線性地址 LA, 反過來,已知線性地址,怎麼把它轉換為街區地址?如果都從0開始計數,轉換就會非常簡單。

Linear_addraaa LA=N*block + house;
Blook_address BA=(LA/N, LA % N);

EXT2檔案系統樹的遍歷


(1)讀取超級塊。檢查幻數s_magic(0xEF53),驗證它確實是 EXT2 FS。
(2)讀取塊組描述符塊(1 + s_first_data_block),以訪問組0描述符。從塊組描述符的bg_inode_table條目中找到索引節點的起始塊編號,並將其稱為InodesBeginBlock。
(3)讀取 InodeBeginBlock,獲取/的索引節點,即 INODE#2。
(4)將路徑名標記為元件字串,假設元件數量為n。例如,如果路徑名 =/a/b/c,則元件字串是"a""b""c",其中n=3。用name[0],name[1],…,name[n-1]來表示元件。
(5)從(3)中的根索引節點開始,在其資料塊中搜索 name[0]。為簡單起見,我們可以假設某個目錄中的條目數量很少,因此一個目錄索引節點只有12個直接資料塊。有了這個假設,就可以在12個(非零)直接塊中搜索 name[0]。目錄索引節點的每個資料塊都包含以下形式的 dir entry 結構體;
[ino rec_len name_len NAME] [ino rec_len name_len NAME]....
其中NAME是一系列nlen字元,不含終止NUL。對於每個資料塊,將該塊讀入記憶體並使用 dir_entry *dp指向載入的資料塊。然後使用 name_len將NAME提取為字串,並與name[0]進行比較。如果它們不匹配,則通過以下程式碼轉到下一個dir_entry:
dp =(dir_entry*)((char *)dp + dp->rec_len);
繼續搜尋。如果存在 name[0],則可以找到它的 dir_entry,從而找到它的索引節點號。
(6)使用索引節點號ino來定位相應的索引節點。回想前面的內容,ino 從1開始計數。使用郵差演算法計算包含索引節點的磁碟塊及其在該塊中的偏移量。

blk =(ino - 1) / INODE8_PER_BLOCK + InodesBeginBlock;
offset = (ino - 1) % INODES_PER_BLOCK;
然後在索引節點中讀取/a,從中確定它是否是一個目錄(DIR)。如果/a不是目錄,則不能有/a/b,因此搜尋失敗。如果它是目錄,並且有更多需要搜尋的元件,那麼繼續搜尋下一個元件 name[1]。現在的問題是∶在索引節點中搜索/a的 name[1],與第(5)步完全相同。
(7)由於(5)~(6)步將會重複n次,所以最好編寫一個搜尋函式∶

u32 search (INODE *inodePtr, char *name)
{
  // search for name in the data blocks of current DIR inode 
  // if found, return its ino; else return 0 )
}
然後我們只需呼叫 search()n次,如下所示。

Assume:n,name[0],....,name[n-1] are globals 
INODE *ip points at INODE of   /
for(i=0; i<n; i++)
{
  ino = search(ip, name[4])
  if(!ino){ // can't find name[i], exit;}
  use ino to zead in INODE and let ip point to INODE
}

如果搜尋迴圈成功結束,ip必須指向路徑名的索引節點。遍歷有多個組的大型 EXT2/3 檔案系統也是類似操作。

檔案系統的級別

檔案系統的實現分為三個級別。每個級別處理檔案系統的不同部分。這使得實現過程模組化,更容易理解。在檔案系統的實現過程中,FS目錄包含實現EXT2檔案系統的檔案。

使用第1級別FS 函式的使用者命令程式有:
mkdir、creat.mknod. rmdir.link.unlink.symlink, rm、ls、cd和 pwd等。

  • 第1級別實現了基本檔案系統樹。它包含以下檔案,實現了指定函式。
mkdir_creat.c      : make directory, create regular file
ls_cd_pwd.c        : list directory, change directory, get CWD path
rmdir.c            : remove directory
link_unlink.c      : hard link and unlink files
symlink_readlink.c : symbolic link files
stat.c             : return file information
misc1.c            : access,chmod, chown, utime, etc.
  • 第2級別實現了檔案內容讀/寫函式。
open_close_lseek.c :  open file for RBAD | WRITE|APPEND,close file and lseek
read.c             :  read from file descriptor of an opened regular file
write.c            :  write to file descriptor of an opened regular file
opendir_readdir.c  :  open and read directory
  • 第3級別實現了檔案系統的掛載、解除安裝和檔案保護。
mount__umount.c    : mount/umount file systems
file_protection    : access permission checking
file-locking       : lock/unlock files

檔案系統掛載

1.系統呼叫處理

使用者執行掛載是通過系統呼叫路徑進入核心處理,拷貝使用者空間傳遞引數到核心,掛載委託do_mount。

2.掛載點路徑查詢

掛載點路徑查詢,掛載委託path_mount.

3.引數合法性檢查

引數合法性檢查, 新掛載委託do_new_mount

4.呼叫具體檔案系統掛載方法

5.掛載例項新增到全域性檔案系統樹

程式設計實現ls-l命令

程式碼託管:https://gitee.com/DKY2019/xxaqxt/blob/master/myls_l.c

參考資料

詳解EXT2 https://blog.csdn.net/gongjiwei/article/details/82025142

ext2檔案系統結構 https://www.jianshu.com/p/18c74734911b

檔案系統掛載 https://zhuanlan.zhihu.com/p/378011720

ext2檔案系統學習 https://blog.csdn.net/weixin_30415801/article/details/95911807





20191331lyx
2021/10/17