當前位置:編程學習大全網 - 源碼下載 - ext2exploder怎麽修改linux的系統文件

ext2exploder怎麽修改linux的系統文件

1.ext2文件系統整體布局

壹個磁盤可以劃分成多個分區,每個分區必須先用格式化工具(例如某種mkfs命令)格式化成某種格式的文件系統,然後才能存儲文件,格式化的過程會在磁盤上寫壹些管理存儲布局的信息。下圖是壹個磁盤分區格式化成ext2文件系統後的存儲布局。

文件系統中存儲的最小單位是塊(Block),壹個塊究竟多大是在格式化時確定的,例如mke2fs的-b選項可以設定塊大小為1024、2048或4096字節,這些 blocks 被聚在壹起分成幾個大的 block group。每個 block group 中有多少個 block 是固定的。而上圖中啟動塊(Boot Block)的大小是確定的,就是1KB,啟動塊是由PC標準規定的,用來存儲磁盤分區信息和啟動信息,任何文件系統都不能使用啟動塊。啟動塊之後才是ext2文件系統的開始,ext2文件系統將整個分區劃成若幹個同樣大小的塊組(Block Group),每個塊組都由以下部分組成

1).超級塊(Super Block)

描述整個分區的文件系統信息,例如塊大小、文件系統版本號、上次mount的時間等等。超級塊在每個塊組的開頭都有壹份拷貝。

2).塊組描述符表(GDT,Group Descriptor Table)

由很多塊組描述符組成,整個分區分成多少個塊組就對應有多少個塊組描述符。每個塊組描述符(Group Descriptor)存儲壹個塊組的描述信息,例如在這個塊組中從哪裏開始是inode表,從哪裏開始是數據塊,空閑的inode和數據塊還有多少個等等。和超級塊類似,塊組描述符表在每個塊組的開頭也都有壹份拷貝,這些信息是非常重要的,壹旦超級塊意外損壞就會丟失整個分區的數據,壹旦塊組描述符意外損壞就會丟失整個塊組的數據,因此它們都有多份拷貝。通常內核只用到第0個塊組中的拷貝,當執行e2fsck檢查文件系統壹致性時,第0個塊組中的超級塊和塊組描述符表就會拷貝到其它塊組,這樣當第0個塊組的開頭意外損壞時就可以用其它拷貝來恢復,從而減少損失。

3).塊位圖(Block Bitmap)

壹個塊組中的塊是這樣利用的:數據塊存儲所有文件的數據,比如某個分區的塊大小是1024字節,某個文件是2049字節,那麽就需要三個數據塊來存,即使第三個塊只存了壹個字節也需要占用壹個整塊;超級塊、塊組描述符表、塊位圖、inode位圖、inode表這幾部分存儲該塊組的描述信息。那麽如何知道哪些塊已經用來存儲文件數據或其它描述信息,哪些塊仍然空閑可用呢?塊位圖就是用來描述整個塊組中哪些塊已用哪些塊空閑的,它本身占壹個塊,其中的每個bit代表本塊組中的壹個塊,這個bit為1表示該塊已用,這個bit為0表示該塊空閑可用。

為什麽用df命令統計整個磁盤的已用空間非常快呢?因為只需要查看每個塊組的塊位圖即可,而不需要搜遍整個分區。相反,用du命令查看壹個較大目錄的已用空間就非常慢,因為不可避免地要搜遍整個目錄的所有文件。

與此相聯系的另壹個問題是:在格式化壹個分區時究竟會劃出多少個塊組呢?主要的限制在於塊位圖本身必須只占壹個塊。用mke2fs格式化時默認塊大小是1024字節,可以用-b參數指定塊大小,現在設塊大小指定為b字節,那麽壹個塊可以有8b個bit,這樣大小的壹個塊位圖就可以表示8b個塊的占用情況,因此壹個塊組最多可以有8b個塊,如果整個分區有s個塊,那麽就可以有s/(8b)個塊組。格式化時可以用-g參數指定壹個塊組有多少個塊,但是通常不需要手動指定,mke2fs工具會計算出最優的數值。

4).inode位圖(inode Bitmap)

和塊位圖類似,本身占壹個塊,其中每個bit表示壹個inode是否空閑可用

5).inode表(inode Table)

我們知道,壹個文件除了數據需要存儲之外,壹些描述信息也需要存儲,例如文件類型(常規、目錄、符號鏈接等),權限,文件大小,創建/修改/訪問時間等,也就是ls -l命令看到的那些信息,這些信息存在inode中而不是數據塊中。每個文件都有壹個inode,壹個塊組中的所有inode組成了inode表。

inode表占多少個塊在格式化時就要決定並寫入塊組描述符中,mke2fs格式化工具的默認策略是壹個塊組有多少個8KB就分配多少個inode。由於數據塊占了整個塊組的絕大部分,也可以近似認為數據塊有多少個8KB就分配多少個inode,換句話說,如果平均每個文件的大小是8KB,當分區存滿的時候inode表會得到比較充分的利用,數據塊也不浪費。如果這個分區存的都是很大的文件(比如電影),則數據塊用完的時候inode會有壹些浪費,如果這個分區存的都是很小的文件(比如源代碼),則有可能數據塊還沒用完inode就已經用完了,數據塊可能有很大的浪費。如果用戶在格式化時能夠對這個分區以後要存儲的文件大小做壹個預測,也可以用mke2fs的-i參數手動指定每多少個字節分配壹個inode。

6).數據塊(Data Block)

根據不同的文件類型有以下幾種情況

對於常規文件,文件的數據存儲在數據塊中。

對於目錄,該目錄下的所有文件名和目錄名存儲在數據塊中,註意文件名保存在它所在目錄的數據塊中,除文件名之外,ls -l命令看到的其它信息都保存在該文件的inode中。註意這個概念:目錄也是壹種文件,是壹種特殊類型的文件。

對於符號鏈接,如果目標路徑名較短則直接保存在inode中以便更快地查找,如果目標路徑名較長則分配壹個數據塊來保存。

設備文件、FIFO和socket等特殊文件沒有數據塊,設備文件的主設備號和次設備號保存在inode中。

2.數據塊尋址

如果壹個文件有多個數據塊,這些數據塊很可能不是連續存放的,應該如何尋址到每個塊呢?實際上,根目錄的數據塊是通過其inode中的索引項Blocks[0]找到的,事實上,這樣的索引項壹***有15個,從Blocks[0]到Blocks[14],每個索引項占4字節。前12個索引項都表示塊編號,例如上面的例子中Blocks[0]字段保存著24,就表示第24個塊是該文件的數據塊,如果塊大小是1KB,這樣可以表示從0字節到12KB的文件。如果剩下的三個索引項Blocks[12]到Blocks[14]也是這麽用的,就只能表示最大15KB的文件了,這是遠遠不夠的,事實上,剩下的三個索引項都是間接索引。

索引項Blocks[12]所指向的塊並非數據塊,而是稱為間接尋址塊(Indirect Block),其中存放的都是類似Blocks[0]這種索引項,再由索引項指向數據塊。設塊大小是b,那麽壹個間接尋址塊中可以存放b/4個索引項,指向b/4個數據塊。所以如果把Blocks[0]到Blocks[12]都用上,最多可以表示b/4+12個數據塊,對於塊大小是1K的情況,最大可表示268K的文件。如下圖所示,註意文件的數據塊編號是從0開始的,Blocks[0]指向第0個數據塊,Blocks[11]指向第11個數據塊,Blocks[12]所指向的間接尋址塊的第壹個索引項指向第12個數據塊,依此類推。

從上圖可以看出,索引項Blocks[13]指向兩級的間接尋址塊,最多可表示(b/4)2+b/4+12個數據塊,對於1K的塊大小最大可表示64.26MB的文件。索引項Blocks[14]指向三級的間接尋址塊,最多可表示(b/4)3+(b/4)2+b/4+12個數據塊,對於1K的塊大小最大可表示16.06GB的文件。

可見,這種尋址方式對於訪問不超過12個數據塊的小文件是非常快的,訪問文件中的任意數據只需要兩次讀盤操作,壹次讀inode(也就是讀索引項)壹次讀數據塊。而訪問大文件中的數據則需要最多五次讀盤操作:inode、壹級間接尋址塊、二級間接尋址塊、三級間接尋址塊、數據塊。實際上,磁盤中的inode和數據塊往往已經被內核緩存了,讀大文件的效率也不會太低。

3.文件和目錄操作的系統函數(這裏面的"(n)"應該表示參數的個數)

1).stat(2)函數讀取文件的inode,然後把inode中的各種文件屬性填入壹個struct stat結構體傳出給調用者。stat(1)命令是基於stat函數實現的。stat需要根據傳入的文件路徑找到inode,假設壹個路徑是/opt/file,則查找的順序是:

讀出inode表中第2項,也就是根目錄的inode,從中找出根目錄數據塊的位置

從根目錄的數據塊中找出文件名為opt的記錄,從記錄中讀出它的inode號

讀出opt目錄的inode,從中找出它的數據塊的位置

從opt目錄的數據塊中找出文件名為file的記錄,從記錄中讀出它的inode號

讀出file文件的inode

還有另外兩個類似stat的函數:fstat(2)函數傳入壹個已打開的文件描述符,傳出inode信息,lstat(2)函數也是傳入路徑傳出inode信息,但是和stat函數有壹點不同,當文件是壹個符號鏈接時,stat(2)函數傳出的是它所指向的目標文件的inode,而lstat函數傳出的就是符號鏈接文件本身的inode。

2).access(2)函數檢查執行當前進程的用戶是否有權限訪問某個文件,傳入文件路徑和要執行的訪問操作(讀/寫/執行),access函數取出文件inode中的st_mode字段,比較壹下訪問權限,然後返回0表示允許訪問,返回-1表示錯誤或不允許訪問。

3).chmod(2)和fchmod(2)函數改變文件的訪問權限,也就是修改inode中的st_mode字段。這兩個函數的區別類似於stat/fstat。chmod(1)命令是基於chmod函數實現的。

4).chown(2)/fchown(2)/lchown(2)改變文件的所有者和組,也就是修改inode中的User和Group字段,只有超級用戶才能正確調用這幾個函數,這幾個函數之間的區別類似於stat/fstat/lstat。chown(1)命令是基於chown函數實現的。

5).utime(2)函數改變文件的訪問時間和修改時間,也就是修改inode中的atime和mtime字段。touch(1)命令是基於utime函數實現的。

6).truncate(2)和ftruncate(2)函數把文件截斷到某個長度,如果新的長度比原來的長度短,則後面的數據被截掉了,如果新的長度比原來的長度長,則後面多出來的部分用0填充,這需要修改inode中的Blocks索引項以及塊位圖中相應的bit。這兩個函數的區別類似於stat/fstat。

7).link(2)函數創建硬鏈接,其原理是在目錄的數據塊中添加壹條新記錄,其中的inode號字段和原文件相同。symlink(2)函數創建壹個符號鏈接,這需要創建壹個新的inode,其中st_mode字段的文件類型是符號鏈接,原文件的路徑保存在inode中或者分配壹個數據塊來保存。ln(1)命令是基於link和symlink函數實現的。

8).unlink(2)函數刪除壹個鏈接。如果是符號鏈接則釋放這個符號鏈接的inode和數據塊,清除inode位圖和塊位圖中相應的位。如果是硬鏈接則從目錄的數據塊中清除壹條文件名記錄,如果當前文件的硬鏈接數已經是1了還要刪除它,就同時釋放它的inode和數據塊,清除inode位圖和塊位圖中相應的位,這樣就真的刪除文件了。unlink(1)命令和rm(1)命令是基於unlink函數實現的。

9).rename(2)函數改變文件名,需要修改目錄數據塊中的文件名記錄,如果原文件名和新文件名不在壹個目錄下則需要從原目錄數據塊中清除壹條記錄然後添加到新目錄的數據塊中。mv(1)命令是基於rename函數實現的,因此在同壹分區的不同目錄中移動文件並不需要復制和刪除文件的inode和數據塊,只需要壹個改名操作,即使要移動整個目錄,這個目錄下有很多子目錄和文件也要隨著壹起移動,移動操作也只是對頂級目錄的改名操作,很快就能完成。但是,如果在不同的分區之間移動文件就必須復制和刪除inode和數據塊,如果要移動整個目錄,所有子目錄和文件都要復制刪除,這就很慢了。

10)readlink(2)函數讀取壹個符號鏈接所指向的目標路徑,其原理是從符號鏈接的inode或數據塊中讀出保存的數據,這就是目標路徑。

11).mkdir(2)函數創建新的目錄,要做的操作是在它的父目錄數據塊中添加壹條記錄,然後分配新的inode和數據塊,inode的st_mode字段的文件類型是目錄,在數據塊中填兩個記錄,分別是.和..,由於..表示父目錄,因此父目錄的硬鏈接數要加1。mkdir(1)命令是基於mkdir函數實現的。

12).rmdir(2)函數刪除壹個目錄,這個目錄必須是空的(只包含.和..)才能刪除,要做的操作是釋放它的inode和數據塊,清除inode位圖和塊位圖中相應的位,清除父目錄數據塊中的記錄,父目錄的硬鏈接數要減1。rmdir(1)命令是基於rmdir函數實現的。

13).opendir(3)/readdir(3)/closedir(3)用於遍歷目錄數據塊中的記錄。opendir打開壹個目錄,返回壹個DIR *指針代表這個目錄,它是壹個類似FILE *指針的句柄,closedir用於關閉這個句柄,把DIR *指針傳給readdir讀取目錄數據塊中的記錄,每次返回壹個指向struct dirent的指針,反復讀就可以遍歷所有記錄,所有記錄遍歷完之後readdir返回NULL

  • 上一篇:C# 中怎麽把已知網址頁面轉化為字符串
  • 下一篇:關於單片機和串口助手的問題
  • copyright 2024編程學習大全網