1. 程式人生 > 其它 >《Unix/Linux系統程式設計》第十一章學習筆記-20191304商蘇赫

《Unix/Linux系統程式設計》第十一章學習筆記-20191304商蘇赫

EXT2檔案系統

  • EXT2檔案系統資料結構
  • 郵差演算法
  • 教材程式設計例項
  • 超級塊
  • 索引節點
  • 塊組描述符
  • 檔案系統專案的擴充套件

超級塊重要欄位:

__u32 s_inodes_count://檔案系統中節點總數
__u32 s_blocks_count://檔案系統中塊總數
__u32 s_r_blocks_count//為超級使用者保留的塊數
__u32 s_free_blocks_count//檔案系統中空閒塊總數
__u32 s_mtime://檔案系統的掛接時間
__u32 s_wtime://最後一次對該超級塊進行寫操作的時間
__u32 s_magic://魔數簽名,用於確定檔案系統版本的標誌
__u32 s_inodes_per_group:表示每個組塊的inode數目,查詢檔案inode所在塊的位置很重要
__u32 s_mnt_count://檔案系統掛接計數
__u32 s_max_mnt_count://檔案系統最大掛接計數
__u32 s_state://檔案系統的狀態

檔案系統專案的擴充套件:

簡單的EXT2檔案系統使用IKB塊大小,只有一個磁碟塊組。它可以輕鬆進行以下擴充套件。

1.多個組:組描述符的大小為32位元組”對於1KB大小的塊,一個塊可能包含 1024/32 = 32組描述符。32個組的檔案系統大小可以擴充套件為32*8 = 256MB.
2.4KB大小的塊:對於4KB大小的塊和一個組,檔案系統大小應為48 = 32MB。對於一個組描述符塊,檔案系統可能有128個組,可將檔案系統大小擴充套件到12832 = 4GB。 對於2個組描述符塊,檔案系統大小為8GB等。大多數擴充套件都很簡單,適合用於程式設計專案。
3.管道檔案:管道可實現為普通檔案,這些檔案遵循管道的讀/寫協議。此方案的優點是:它統一了管道和檔案索引節點,並允許可被不相關程序使用的命名管道。為支援快速讀/寫操作,管道內容應在記憶體中,比如在RAMdisk中。必要時,讀者可將命名管道實現為FIFO檔案.
4.I/O緩衝:在程式設計專案中,每個磁碟塊都是直接讀寫的。這會產生過多的物理磁碟I/O操作。為提髙效率,實際檔案系統通常使用一系列I/O緩衝區作為磁碟塊的快取記憶體。

遍歷EXT2系統檔案樹:

演算法

1.讀取超級塊;
2.讀取塊組描述符塊(1 + s_first_data_block),以訪問組0描述符。並從塊組描述符的bg_inode_table條目中找到索引節點的起始塊編號,將其成為InodesBeginBlock;
3.讀取InodesBeginBlock,獲取/的索引節點,即INODE#2;
4.將路徑名標記為元件字串,假設元件數量為恥例如,如果路徑名=/a/b/c,則組 件字串是“a”“b”“c”,其中n = 3。用name[0], namefl],…,name[n-l]來表示元件
5.從(3)中的根索引節點開始,在其資料塊中搜索name[0]。(5)。目錄索引節點的每個資料塊都包含 以下形式的dir entry結構體:
(ino rec_len name_len NAME] [ino rec_len name_len NAME)
其中NAME是一系列nlen字元,不含終止NULLO對於每個資料塊,將該塊讀入記憶體 並使用dir_entry *dp指向載入的資料塊。然後使用name」en將NAME提取為字串,並與 namefO]進行比較。如果它們不匹配,貝U通過以下程式碼轉到下一個dir_entry:
dp * (dir_entry *)((char *)dp + dp->rec_len))


繼續搜尋。如果存在name[0],則可以找到它的dir_entry,從而找到它的索引節點號。
6.使用索引節點號ino來定位相應的索引節點。回想前面的內容,ino從1開始計數。 使用郵差演算法計算包含索引節點的磁碟塊及其在該塊中的偏移量。

blk = (ino - 1) * INODES_PER_BLOCK + InodesBeginBlock;
offset = (ino - 1) % INODES_PER_BLOCK;

然後在索引節點中讀取/a,從中確定它是否是一個目錄(DIR)。如果/a不是目錄,則 不能有/a/b,因此搜尋失敗。如果它是目錄,並且有更多需要搜尋的元件,那麼繼續搜尋 下一個元件name[l]o現在的問題是:在索引節點中搜索/a的name[l],與第(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
)

8.呼叫search()n次,n為元件數量。

實踐內容:教材例項程式設計superblock.c:

程式碼:

/*********** superblock.c program ************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/io.h>
#include <ext2fs/ext2_fs.h>
// Cypedef u8, ul6, u32 SUPER for convenience typedef typedef typedef
typedef unsigned char u8;
typedef unsigned short ul6;
typedef unsigned int u32;
typedef struct ext2_super_block SUPER;
SUPER *sp;
char buf[1024];
int fd, blksize, inodesize;
int print(char *s, u32 x)
{
    printf("%-30s = %8d\n", s, x);
}
int super(char *device)
{
    fd = open(device, O_RDONLY);
    if (fd < 0) 
    {
        printf("open %s failed\n", device); 
        exit(1);
    }
    lseek(fd, (long)1024*1, 0);	// block 1 or offset 1024
    read(fd, buf, 1024);
    sp = (SUPER *)buf;	// as a super block structure
    // check for EXT2 FS magic number
    printf("%-30s = %8x ", "s_magic", sp->s_magic);
    if (sp->s_magic != 0xEF53)
    {
        printf("NOT an EXT2 FS\n"); exit(2);
    }
    printf("EXT2 FS OK\n"); 
    print("s_inodes_count",  sp->s_inodes_count);
    print("s_blocks _count", sp->s_blocks_count); 
    print("s_r_blocks_count", sp->s_r_blocks_count);
    print("s_free_inodes_count", sp->s_free_inodes_count);
    print("s_free_blocks_count", sp->s_free_blocks_count);
    print("s_first_data_blcok", sp->s_first_data_block); 
    print("s_log_block_s i z e", sp->s_log_block_size);
    print("s_blocks_per_group", sp->s_blocks_per_group); 
    print("s_inodes_per_group", sp-> s_inodes_per_group); 
    print("s_mnt_count", sp->s_mnt_count);
    print("s_max_mnt_count", sp-> s_max_mnt_count);
 
    printf("%-30s = %8x\n", "s_magic", sp->s_magic); 
    
    printf ("s_mtime = %s\n", ctime ((const time_t *)&sp->s_mtime)); 
    printf ("s_wtime = %s", ctime ((const time_t *)&sp->s_wtime)); 
    blksize = 1024 * (1 << sp->s_log_block_size);
    printf("block size = %d\n", blksize);
    printf("inode size = %d\n", sp->s_inode_size);
}

char *device = "vdisk";	// default device name
int main(int argc, char *argv[])
{
    if (argc>1)
        device = argv[1];
    super(device);
}