在STM32上實現NTFS之5:GPT分區表的C語言實現(2)GPT實現以及統一方式讀取磁碟分割

來源:互聯網
上載者:User

標籤:char   代碼結構   合成   資料   結果   div   erp   byte   c語言實現   

  上一節實現了主GPT頭的資訊提取,這一節繼續提取整個的GPT資料,並且將GPT分區表和MBR分區表兩種格式融合成一個模組,使主調函數(也可以說是使用者)不需要關心磁碟的分區表類型:它太底層了,確實不需要過多的關心。

  繼續看上一節的圖1,這裡就不貼圖了,LBA1的主GPT頭給出了分區資訊的總數,還有每一個分區資訊所佔用的位元組數,分區資訊的結構如表1:

表1 分區資訊結構(GPT Entry)

位元組位移量

資料長度(位元組)

範例數值

資料項目說明

0x00

16

28 73 2A C1 1F F8 D2 11 BA 4B 00 A0 C9 3E C9 3B

用GUID表示的分區類型

0x10

16

82 63 7A C8 13 0E F8 46 95 29 E6 31 E9 16 B5 42

用GUID表示的分區唯一標示符

0x20

8

00 08 00 00 00 00 00 00

該分區的起始扇區,用LBA值表示

0x28

8

FF 27 E6 31 E9 16 B5 42

該分區的結束扇區(包含),用LBA值表示,通常是奇數

0x30

8

00 00 00 00 00 00 00 80

該分區的屬性標誌

0x38

72

 

UTF-16LE編碼的人類可讀的分區名稱,最大32個字元

可以看到,這個結構非常之簡潔,只標註了起始扇區,結束扇區,分區類型,GUID,屬性,分區名,而不關心磁頭、磁軌等等資訊。

需要特殊說明的是,整個分區資訊的結構,也就是從LBA2到LBA34(MS總是給劃分128個分區資訊),是完全連續的,不依靠任何扇區等資訊去定位,也就是說,第n個分區資訊的結構起始地址,僅僅根據LBA2的起始地址+分區位元組數*n來確定,最常見的是微軟定義的128個分區資訊,512位元組扇區,128位元組的分區資訊位元組數,所以最常見的是每一個扇區4個分區資訊,密集的排列32個扇區。然而正確的計數方法是每128個位元組一個分區資訊,密集排列128個。當扇區不是512位元組時(注意這裡不要跟簇混淆,目前我還沒見過不是512位元組扇區的儲存空間),每個扇區儲存的分區資訊有可能不是4個,下面的程式規避了這個問題,採用了一個新的磁碟讀寫函數——ReadDiskData而不是ReadSectorData——來防止讀分區資訊出現錯誤。

 1 /******************************************************************************* 2  3 函 數 名:GetVolumeNumberOfGPT 4  5 函數功能:擷取一個GPT格式的磁碟中有效分卷數 6  7 輸入參數: 8  9           hDisk:磁碟控制代碼10 11           DPT:  磁碟DPT12 13 返回參數:int型,返回DPT中包含的有效分區數量(包含未格式化的分卷),如果該DPT不是GPT14 15         分區形式,將會返回-116 17 *******************************************************************************/18 19 int GetVolumeNumberOfGPT(HANDLE hDisk, DPT_Info* DPT)20 21 {22 23     if (DPTDetermination(DPT) == DPT_MBR)24 25         return -1;26 27     GPTEntry_Byte GPTEbuffer;28 29     GPTEntry_Info GPTEinfo;30 31     PGPTH_Info PGPTH;32 33     GetPGPTH(hDisk, &PGPTH);34 35     int ValidPartitions = 0;36 37     for (int i = 0; i < PGPTH.PartitionTables; i++)38 39     {40 41         ReadDiskData(42 43             hDisk, //讀取磁碟控制代碼44 45             SECTOR_SIZE * PGPTH.PartitionStart + i * PGPTH.BytesPerPartitionTable, //計算讀取的GPTE位置46 47             (uint8_t*)(void*)&GPTEbuffer, //緩衝區地址48 49             sizeof(GPTEntry_Byte)); //位元組數50 51         GetGPTEInfo(&GPTEbuffer, &GPTEinfo);52 53         if (GUIDcmp(&(GPTEinfo.TypeGUID), (GUID_Info*)&GUID_ptUnuse))54 55             break;56 57         else58 59             ValidPartitions++;60 61     }62 63     return ValidPartitions;64 65 }

分區類型是有規定的,一般有表2的幾種GUID;屬性標誌也是有規定的,見表3。

 

表2:分區類型的16Byte GUID

數值

類型說明

00000000-0000-0000-0000-000000000000

未使用

024DEE41-33E7-11D3-9D69-0008C781F39F

MBR分區表

C12A7328-F81F-11D2-BA4B-00A0C93EC93B

EFI系統磁碟分割[EFI System partition (ESP)],必須是VFAT格式

BC13C2FF-59E6-4262-A352-B275FD6F7172

擴充boot分區,必須是VFAT格式

21686148-6449-6E6F-744E-656564454649

BIOS引導分區,其對應的ASCII字串是"Hah!IdontNeedEFI"。

D3BFE2DE-3DAF-11DF-BA40-E3A556D89593

Intel Fast Flash (iFFS) partition (for Intel Rapid Start technology)

E3C9E316-0B5C-4DB8-817D-F92DF00215AE

微軟保留分區

EBD0A0A2-B9E5-4433-87C0-68B6B72699C7

基本資料分區

DE94BBA4-06D1-4D40-A16A-BFD50179D6AC

Windows恢複環境

0FC63DAF-8483-4772-8E79-3D69D8477DE4

資料分區。Linux曾經使用和Windows基本資料分區相同的GUID。
這個新的GUID是由 GPT fdisk 和 GNU Parted 開發人員根據Linux傳統的"8300"分區代碼發明的。

44479540-F297-41B2-9AF7-D131D5F0458A

x86根分區 (/) 這是systemd的發明,可用於無fstab時的自動掛載

4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709

x86-64根分區 (/) 這是systemd的發明,可用於無fstab時的自動掛載

69DAD710-2CE4-4E3C-B16C-21A1D49ABED3

ARM32根分區 (/) 這是systemd的發明,可用於無fstab時的自動掛載

B921B045-1DF0-41C3-AF44-4C6F280D3FAE

AArch64根分區 (/) 這是systemd的發明,可用於無fstab時的自動掛載

3B8F8425-20E0-4F3B-907F-1A25A76F98E8

伺服器資料分區(/srv) 這是systemd的發明,可用於無fstab時的自動掛載

933AC7E1-2EB4-4F13-B844-0E14E2AEF915

HOME分區 (/home) 這是systemd的發明,可用於無fstab時的自動掛載

0657FD6D-A4AB-43C4-84E5-0933C84B4F4F

交換分區(swap) 不是systemd的發明,但同樣可用於無fstab時的自動掛載

A19D880F-05FC-4D3B-A006-743F0F84911E

RAID分區

E6D6D379-F507-44C2-A23C-238F2A3DF928

邏輯卷管理器(LVM)分區

8DA63339-0007-60C0-C436-083AC8230908

保留

    上面的GUID數值比較有意思,根據winHex得到的扇區資料,它將16位元組的GUID分成了5部分,在很多編譯器中已經有GUID結構體的定義不過是4部分的,在這裡無法使用,所以我們另外定義一個結構

 1 typedef struct 2  3 { 4  5     uint32_t Part1;                 //GUID第1部分 6 
 7     uint16_t Part2;                 //GUID第2部分 8  9     uint16_t Part3;                 //GUID第3部分10 11     uint16_t Part4;                 //GUID第4部分12 13     uint48_t Part5;                 //GUID第5部分14 15 }GUID_Info;

 

來表示GUID。而有意思的地方在於,這5部分並不是單純的完全大端或者小端模式,它是混合著來的,前三個部分是小端,後兩個部分是大端,我們在讀取結構的時候一定要注意這點。

    表3:分區屬性

數值

類型說明

0

系統磁碟分割

1

EFI隱藏式磁碟分割(EFI不可見分區)

2

傳統的BIOS的可引導分區標誌

60

唯讀

62

隱藏

63

不自動掛載,也就是不自動分配盤符

    以上的屬性列表並不完全,至少我的硬碟分區之後,類型就是0x80。因為只有一個位元組有用的資訊,一個枚舉類型就足以解決問題。

    現在我們實際看一個擁有4個分區資訊的LBA,1:

 

圖1 LBA分區

    ,紅框框起來的部分就是一個分區資訊結構,比較精髓的部分是粉色框裡的72位元組,它是以UTF16的小端模式編碼的,因為涉及到了中文問題,UTF16LE解碼比較複雜,在這裡我們直接用wchar_t來擷取這個結構:

 1 typedef struct 2  3 { 4  5     uint8_t TypeGUID[16];           //用GUID表示的分區類型 6  7     uint8_t UniqueGUID[16];         //用GUID表示的分區唯一標示符 8  9     uint8_t SectorStart[8];         //該分區的起始扇區,用LBA值表示10 11     uint8_t SectorEnd[8];           //該分區的結束扇區(包含),用LBA值表示,通常是奇數12 13     uint8_t PartitionAttrib[8];     //該分區的屬性標誌14 15     WCHAR   PartitionName[36];      //UTF-16LE編碼的人類可讀的分區名稱,最大32個字元。16 17 }GPTEntry_Byte;

 

 

    現在GPT結構已經可以完整的讀取,由於博文實在實驗階段性完成後做的,所以沒有(=_=尷尬)。

接下來的步驟是整合GPT和MBR。由於DPT引導到GPT和MBR的部分可以直接整合,所以原DPT部分代碼可以不動,但不同的是GPT是通過讀取LBA直接得到每個分區的起始扇區、終止扇區、分區類型等等,而MBR方式是先通過DPT得到小於等於4個開機磁區的位置,然後對這幾個開機磁區進行解析,每個開機磁區對應一個分區資訊。

在使用其他的一些庫的時候,筆者受到困擾的地方就是,API函數太多,有很多的庫有不同的API功能是接近的,同時又有很多API名字相近但功能截然不同,所以為了避免這種情況,在這裡盡量縮減API。根據這個思想,可以構建大致的流程如下:首先由使用者提取分區總數,然後使用者來進行malloc操作來根據分區數建立分區列表,然後根據分區列表可以找到每個分區的開機磁區位置。在本節中,所謂的“分區資訊”是針對於分區表的分區資訊,事實上根據前幾節的介紹,分卷容量並不一定等於分區容量,所以目前的代碼中都是以Partition代表分區,而以Volume代表分卷。

詳細的代碼結構這裡不進行更多的截取,有關代碼的調用方式在main.cpp中很容易的看到。在壓縮包裡有基於VS2015community環境的完整工程。

最後貼上一張完整的分區列表運行結果(磁碟3是我的移動硬碟,磁碟4是我的64GB SD卡)。

 

圖2 代碼運行結果

 工程:https://files.cnblogs.com/files/Coder-Ku/NTFS5.rar

在STM32上實現NTFS之5:GPT分區表的C語言實現(2)GPT實現以及統一方式讀取磁碟分割

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.