linux系统下对硬盘自定义分区格式化的分析与实现
前言:在这个数据爆炸的时代,数据存储也显得尤为的重要。存储形式从原来的U盘,SD卡硬盘发展到现在的网络存储,云存储。存储空间也是从原来的M大小到现在动辄T为单位的大容量存储。因为工作关系有接触数据存储方案,这里就对我们常用的磁盘分区、磁盘格式化做一个介绍。磁盘分区格式化以及硬盘的结构特性这些内容网上已经有一大堆,这里不做常规介绍。本文是想从一个程序员的角度来分析分区格式化,从而可以在不......
前言:
在这个数据爆炸的时代,数据存储也显得尤为的重要。存储形式从原来的U盘,SD卡硬盘发展到现在的网络存储,云存储。存储空间也是从原来的M大小到现在动辄T为单位的大容量存储。因为工作关系有接触数据存储方案,这里就对我们常用的磁盘分区、磁盘格式化做一个介绍。磁盘分区格式化以及硬盘的结构特性这些内容网上已经有一大堆,这里不做常规介绍。本文是想从一个程序员的角度来分析分区格式化,从而可以在不借助第三方工具或是命令的情况下自己用代码实现分区格式化,最后可以进一步实现自定义的一些功能。
Table of Contents
说明:
本人使用的是一张32G的SD卡,信息如下,在开始之前已经将SD卡低级格式化过,所有的扇区写入的数据是0x00
- 接口类型: USB
- 序列号: 2012090114345300
- 型号: Generic-SD/MMC
- 分区表类型: MBR
- MBR签名: 00000000
- 属性: 可移动磁盘
- 柱面数: 3828
- 磁头数: 255
- 每道扇区数: 63
- 总容量: 29.3GB
- 总字节数: 31486640128
- 总扇区数: 61497344
- 扇区大小: 512
- 附加扇区数: 524
- 物理扇区大小: 512
缩写介绍:
国内的很多资料是翻译的国外的,但是对于很多缩写没有给出英文原意,导致很多人理解困难,对于很多资料,还是建议看英文原版。
- MBR:Master Boot Record 主引导记录
- GPT: GUID Partition Table 全局唯一标识磁盘分区表
- CHS: Cylinder,Heads,Sector 柱面、磁头、扇区
- LBA: Logical Block Addressing 逻辑块寻址
- FAT: File Allocation Table Windows的一种文件系统
- exFAT: extended File Allocation Table
- NTFS: New Technology File System Windows的一种文件系统
- EXT: Linux extended file system, extfs,即Linux扩展文件系统
- UFS: Unix File System
- GFS: Google File System
- HFS: Hierarchical File System 分层文件系统苹果系统使用
- CDFS: Compact Disc File System
- DBR: Dos Boot Record 分区的引导记录扇区
计算方式:
一个柱面大小(字节) = 磁头数 * 每道扇区数 * 每扇区字节数
硬盘分区格式化介绍:
Windows上的分区方式有两种:MBR分区和GPT分区。
MBR分区有的资料介绍最大只能支持分区到2.1T,有些介绍只能支持到2.2T,不管实际准确值是多少,大于2T的硬盘多不建议使用MBR这种分区方式。因为它只能用4字节也就是32位来表示一个扇区的容量以及一个扇区的偏移位置。分区是一扇区为单位,假如一个扇区为512字节,32位能够表示的表示的最大值也就是2T。 其他还有:Apple分区;BSD分区,主要用于BSD Unix服务器;Sun Solaris
格式化是指将文件系统安装到分区中去,文件系统也就是操作系统中负责管理和存储文件信息的软件机构。常见的文件系统有:FAT32,NTFS, exFAT, EXT2,EXT3,UFS,GFS,HFS,CDFS,RAW。
在Windows系统中,分区方式主要有MBR和GPT两种,现在还在使用的比较多的格式化文件系统是:NTFS和FAT32文件系统。
本文主要分析将一个32GSD卡分区成3个分区,格式化成FAT32文件系统,它在分区和格式化的时候都主要做了些什么内容,以及MBR,FAT32各参数的位置及功能。
MBR分区方案:
MBR是传统的分区表,主要特点有:
- 1、MBR分区方案使用硬盘的第一个物理扇区中的64个字节作为分区表的空间保存硬盘分区信息,每个分区的信息要占16个字节。所以,MBR分区表最多只能保存4个分区的分区信息。
- 2、MBR分区方案中,有三种类型的分区:主分区、扩展分区和逻辑分区。扩展分区与逻辑分区是为了突破分区表中只能保存4个分区的限制而出现的。
- 3、MBR分区表中保存的分区信息都是主分区与扩展分区的分区信息,扩展分区不能直接使用,需要在扩展分区内划分一个或多个逻辑分区后才能使用。逻辑分区的分区信息保存在扩展分区内而不是保存在MBR分区表内,这样,就可以突破MBR分区表只能保存4个分区的限制。
- 4、16个字节的分区信息保存有分区活动状态标志、文件系统标识、起止柱面号、磁头号、扇区号、起始扇区位置(4个字节)、分区总扇区数目(4个字节)等内容。这里最重要的是:分区的起始扇区位置与分区的总扇区数,都是用4个字节表示的。
- 5、一般每个扇区的容量是512字节,4个字节的扇区能表示的最大容量是2TB,由4可知,在MBR分区表中,分区的起始位置不能大于2TB,分区的最大容量,也不能大于2TB。所以,对2TB以上容量的物理硬盘,不适合使用MBR分区方案。
关键的特性主要有两点:
- 1、本来MBR分区表只能保存四个分区的信息,但通过扩展分区与逻辑分区的使用,MBR突破了这个限制。
- 2、由于MBR分区表中,表示地址的参数是只有4个字节,所以导致MBR分区方案中,分区的起始位置不能大于2TB,分区的最大容量,也不能大于2TB。所以,对2TB以上容量的物理硬盘,不适合使用MBR分区方案。
如果要使用MBR分区,同时又需要支持大于2T的设备,那么需要的是使用大扇区的设备,比如一个扇区1024字节或是2048字节,扇区的大小这个是由硬盘生产商确定的,用户并不能修改。但扩大扇区的大小,又会带来很多其他的问题,特别是会严重影响硬盘的速度,所以这种方法,没有被广泛接受。
MBR的分区示意图如下:
我把我的的SD卡分成3个分区,如下图,下面就这张SD卡为例进行分析,这里不涉及到扩展分区
磁盘引导是在磁盘的第一个扇区,MBR格式的分区,主分区的分区表也是在第一分区,第一分区的内容如下:
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
000000000 33 C0 8E D0 BC 00 7C FB 50 07 50 1F FC 50 BE 00 3.....|.P.P..P..
000000010 7C BF 00 06 B9 00 02 F3 A4 BF 1E 06 57 CB 33 DB |...........W.3.
000000020 33 D2 BD 00 06 BE BE 07 B1 04 F6 04 80 75 0E 83 3............u..
000000030 C6 10 E2 F6 BE 74 01 B9 17 00 E9 25 01 8B D6 52 .....t.....%...R
000000040 BE 74 01 89 12 B8 00 42 BE 7B 01 03 F5 56 B1 10 .t.....B.{...V..
000000050 C6 04 00 46 E2 FA 5E 8B FA C6 04 10 FE 44 02 C6 ...F..^......D..
000000060 44 05 7C 8B 5D 08 89 5C 08 8B 5D 0A 89 5C 0A B2 D.|.]..\..]..\..
000000070 80 CD 13 BE FE 7D 81 3C 55 AA 74 09 BE 8B 01 B9 .....}.<U.t.....
000000080 18 00 E9 DD 00 60 B8 00 08 B2 80 CD 13 80 E1 3F .....`.........?
000000090 8A D1 FE C6 33 DB BE 03 7C BF A6 01 03 FD B9 04 ....3...|.......
0000000A0 00 F3 A6 74 1C BE 52 7C BF A3 01 03 FD B1 03 F3 ...t..R|........
0000000B0 A6 74 0E BE 36 7C BF A3 01 03 FD B1 03 F3 A6 75 .t..6|.........u
0000000C0 4F BE 18 7C 3A 14 74 03 88 14 43 BE 1A 7C 3A 34 O..|:.t...C..|:4
0000000D0 74 03 88 34 43 83 FB 00 74 36 BE 74 01 8B 12 B8 t..4C...t6.t....
0000000E0 00 42 BE 7B 01 03 F5 56 B1 10 C6 04 00 46 E2 FA .B.{...V.....F..
0000000F0 5E 8B FA C6 04 10 FE 44 02 C7 44 05 7C 00 8B 5D ^......D..D.|..]
000000100 08 89 5C 08 8B 5D 0A 89 5C 0A FE C4 B2 80 CD 13 ..\..]..\.......
000000110 BE AA 01 80 3A 00 74 41 8A 1A B8 00 42 BE 7B 01 ....:.tA....B.{.
000000120 03 F5 56 B1 10 88 04 46 E2 FB 5E C6 04 10 FE 44 ..V....F..^....D
000000130 02 C6 44 05 7E 88 5C 08 B2 80 CD 13 B8 00 42 56 ..D.~.\.......BV
000000140 57 BE B8 07 BF B8 7F B9 46 00 F3 A4 5F 5E 32 DB W.......F..._^2.
000000150 88 5C 08 FE C4 B2 80 CD 13 61 33 C0 50 B8 00 7C .\.......a3.P..|
000000160 50 CB 81 C6 00 06 AC BB 07 00 B4 0E CD 10 E2 F6 P...............
000000170 B1 0F E2 FC 49 6E 76 61 6C 69 64 20 50 61 72 74 ....Invalid Part
000000180 69 74 69 6F 6E 20 54 61 62 6C 65 4D 69 73 73 69 ition TableMissi
000000190 6E 67 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 ng operating sys
0000001A0 74 65 6D 46 41 54 4E 54 46 53 01 00 00 00 00 00 temFATNTFS......
0000001B0 00 00 00 00 00 00 00 00 3A 57 EB A5 00 00 80 01 ........:W......
0000001C0 01 00 0C FE FF FF 3F 00 00 00 9A E5 3F 01 00 FE ......?.....?...
0000001D0 FF FF 0C FE FF FF D9 E5 3F 01 D9 E5 3F 01 00 FE ........?...?...
0000001E0 FF FF 0C FE FF FF B2 CB 7F 02 4E 94 2A 01 00 00 ..........N.*...
0000001F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............U.
MBR分区表的分析:
分区表在0x1be 到0x1fc,这里可以记录四个分区,如果分区超过了四个分区,那就需要使用逻辑分区。
引导指示符 开始磁头 开始扇区 开始柱面 系统ID 结束磁头 结束扇区 结束柱面 相对扇区数 总扇区数
80 01 01 00 0C FE FF FF 3F 00 00 00 9A E5 3F 01
00 FE FF FF 0C FE FF FF D9 E5 3F 01 D9 E5 3F 01
00 FE FF FF 0C FE FF FF B2 CB 7F 02 4E 94 2A 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
由上面分区表可以知道各分区开始位置:
第一分区开始位置:Part1_pos = 0x3f = 63 扇区 = 0x7E00 地址
第二分区开始位置:Part2_pos = 0x013fe5d9 = 20964825 扇区 = 0x27FCBB200 地址
第三分区开始位置:Part3_pos = 0x027ecbb2 = 41864114 扇区 = 0x4FD976400 地址
各分区的大小计算如下:
第一分区大小:Part1_size = 0x13fe59a 扇区 = 20964762 扇区 * 512 字节 = 10733958144 字节 = 10236.7001953125 M = 9.996777534484863 G
第二分区大小:Part2_size = 0x13fe5d9 扇区 = 20964825 扇区 * 512 字节 = 10733990400 字节 = 10236.73095703125 M = 9.99680757522583 G
第三分区大小:Part3_size = 0x12a944e 扇区 = 19567694 扇区 * 512 字节 = 10018659328 字节 = 9554.5380859375 M = 9.33060359954834 G
GPT分区方案:
相比较于MBR,GPT是新一代的分区方案,个人认为GPT比MBR要简单些。GPT磁盘分区结构解决了MBR只能分4个主分区的的缺点,理论上说,GPT磁盘分区结构对分区的数量好像是没有限制的。但某些操作系统可能会对此有限制。
GPT磁盘分区结构由6部分组成,示意图如下:
GPT分区方案的硬盘结构如下图:
首先,你会注意到,这张用LBA 0、LBA 1这样的方法来表明硬盘上的地址,这是因为以前一般都是用chs方式对硬盘寻址的,chs 是指柱面磁头扇区寻址,LBA是指逻辑快寻址。现在一般都用LBA方式对硬盘寻址,对上面这张图来说,LBA 0指的是物理序号为0的第一个扇区,LBA 1指的是物理序号为1的第二个扇区,依次类推。
下面比照着上面这张图,解释GPT分区方案:
- 1、保留MBR,GPT的分区方案,硬盘的第一个物理扇区,仍然是一个前面讲过的MBR,这个MBR主要是出于软件兼容性的考虑,对GPT分区方案本身来讲,其实没有啥意义。
- 2、GPT分区表头,这个在保留MBR之后,也就是占用第二个物理扇区,GPT分区表头中,定义了分区的数量,基本上,你可以认为GPT分区的数量是没有限制的;
- 3、GPT分区表,从第三个扇区开始,是实际的分区表。请注意:每个扇区可以保存4个分区信息,说明每个分区的分区信息占用的空间是128个字节。
- 4、从3中,我们知道每个分区的信息占用了四分之一个扇区,也就是128字节的空间,对比一下MBR分区方案中,每个分区的信息只有16个字节,所以GPT分区方案,有充足的空间去存储分区的开始位置及总的容量等,基本上,不用考虑对分区容量的限制。
- 5、从3中,我们知道,GPT分区方案,分了多少个区,就在分区表中有多少个分区信息。然而实际情形并不是这样,事实上,如图中所示:如果你使用windows操作系统,通常GPT分区表占用32个扇区的空间,可以保存128个分区信息,用不到的空间会被保留,实际使用了多少分区信息与保留了多少分区信息,在2中的GPT分区表头中设置。我们的电脑,通常不会有超过10个的分区,所以GPT分区表中的空间,90%以上都是保留空间,其实就是被浪费了。
- 6、接下来的两个部分,很简单,分别是GPT分区表,及GPT分区表头的备份。
下面介绍GPT分区的各个组成部分:
(1)保护MBR
保护MBR位于GPT磁盘的第一扇区,也就是0号扇区,有磁盘签名,MBR磁盘分区表和结束标志组成,没有引导代码。而且分区表内只有一个分区表项,这个表项GPT根本不用,只是为了让系统认为这个磁盘是合法的。
(2)GPT头
GPT头位于GPT磁盘的第二个磁盘,也就是1号扇区,该扇区是在创建GPT磁盘时生成,GPT头会定义分区表的起始位置,分区表的结束位置、每个分区表项的大小、分区表项的个数及分区表的校验和等信息。
GPT头中参数的含义解释如下表:
(3)分区表
分区表位于GPT磁盘的2-33号磁盘,一共占用32个扇区,能够容纳128个分区表项。每个分区表项大小为128字节。因为每个分区表项管理一共分区,所以Windows系统允许GPT磁盘创建128个分区。
每个分区表项中记录着分区的起始,结束地址,分区类型的GUID,分区的名字,分区属性和分区GUID。
分区表项中各参数的含义解释如下表:
(4)分区区域
GPT分区区域就是用户使用的分区,也是用户进行数据存储的区域。分区区域的起始地址和结束地址由GPT头定义。
(5)GPT头备份
GPT头有一个备份,放在GPT磁盘的最后一个扇区,但这个GPT头备份并非完全GPT头备份,某些参数有些不一样。复制的时候根据实际情况更改一下即可。
(6)分区表备份
分区区域结束后就是分区表备份,其地址在GPT头备份扇区中有描述。分区表备份是对分区表32个扇区的完整备份。如果分区表被破坏,系统会自动读取分区表备份,也能够保证正常识别分区。
FAT32文件系统
FAT32文件系统由DBR及其保留扇区,FAT1,FAT2和DATA四个部分组成,其机构如下图:
- DBR及其保留扇区:DBR的含义是DOS引导记录,也称为操作系统引导记录,在DBR之后往往会有一些保留扇区。
- FAT1:FAT的含义是文件分配表,FAT32一般有两份FAT,FAT1是第一份,也是主FAT。
- FAT2:FAT2是FAT32的第二份文件分配表,也是FAT1的备份。
- DATA:DATA也就是数据区,是FAT32文件系统的主要区域,其中包含目录区域。
(一)分析FAT32文件系统的DBR
FAT32文件系统的DBR有5部分组成,分别为跳转指令,OEM代号,BPB,引导程序和结束标志。如下是我SD卡第一分区中一个完整的FAT32文件系统的DBR,它所在的位置也就是在第一分区的第一个扇区,就是Part1_pos = 0x3f = 63 扇区 = 0x7E00 地址。查看里面的数据:
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
000007E00 EB 58 90 4D 53 44 4F 53 35 2E 30 00 02 10 22 00 .X.MSDOS5.0...".
000007E10 02 00 00 00 00 F8 00 00 3F 00 FF 00 3F 00 00 00 ........?...?...
000007E20 9A E5 3F 01 F3 27 00 00 00 00 00 00 02 00 00 00 ..?..'..........
000007E30 01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000007E40 80 00 29 61 D6 9A 0A 20 20 20 20 20 20 20 20 20 ..)a...
000007E50 20 20 46 41 54 33 32 20 20 20 33 C9 8E D1 BC F4 FAT32 3.....
000007E60 7B 8E C1 8E D9 BD 00 7C 88 56 40 88 4E 02 8A 56 {......|.V@.N..V
000007E70 40 B4 41 BB AA 55 CD 13 72 10 81 FB 55 AA 75 0A @.A..U..r...U.u.
000007E80 F6 C1 01 74 05 FE 46 02 EB 2D 8A 56 40 B4 08 CD ...t..F..-.V@...
000007E90 13 73 05 B9 FF FF 8A F1 66 0F B6 C6 40 66 0F B6 .s......f...@f..
000007EA0 D1 80 E2 3F F7 E2 86 CD C0 ED 06 41 66 0F B7 C9 ...?.......Af...
000007EB0 66 F7 E1 66 89 46 F8 83 7E 16 00 75 39 83 7E 2A f..f.F..~..u9.~*
000007EC0 00 77 33 66 8B 46 1C 66 83 C0 0C BB 00 80 B9 01 .w3f.F.f........
000007ED0 00 E8 2C 00 E9 A8 03 A1 F8 7D 80 C4 7C 8B F0 AC ..,......}..|...
000007EE0 84 C0 74 17 3C FF 74 09 B4 0E BB 07 00 CD 10 EB ..t.<.t.........
000007EF0 EE A1 FA 7D EB E4 A1 7D 80 EB DF 98 CD 16 CD 19 ...}...}........
000007F00 66 60 80 7E 02 00 0F 84 20 00 66 6A 00 66 50 06 f`.~.... .fj.fP.
000007F10 53 66 68 10 00 01 00 B4 42 8A 56 40 8B F4 CD 13 Sfh.....B.V@....
000007F20 66 58 66 58 66 58 66 58 EB 33 66 3B 46 F8 72 03 fXfXfXfX.3f;F.r.
000007F30 F9 EB 2A 66 33 D2 66 0F B7 4E 18 66 F7 F1 FE C2 ..*f3.f..N.f....
000007F40 8A CA 66 8B D0 66 C1 EA 10 F7 76 1A 86 D6 8A 56 ..f..f....v....V
000007F50 40 8A E8 C0 E4 06 0A CC B8 01 02 CD 13 66 61 0F @............fa.
000007F60 82 74 FF 81 C3 00 02 66 40 49 75 94 C3 42 4F 4F .t.....f@Iu..BOO
000007F70 54 4D 47 52 20 20 20 20 00 00 00 00 00 00 00 00 TMGR ........
000007F80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000007F90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000007FA0 00 00 00 00 00 00 00 00 00 00 00 00 0D 0A 44 69 ..............Di
000007FB0 73 6B 20 65 72 72 6F 72 FF 0D 0A 50 72 65 73 73 sk error...Press
000007FC0 20 61 6E 79 20 6B 65 79 20 74 6F 20 72 65 73 74 any key to rest
000007FD0 61 72 74 0D 0A 00 00 00 00 00 00 00 00 00 00 00 art.............
000007FE0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000007FF0 00 00 00 00 00 00 00 00 AC 01 B9 01 00 00 55 AA ..............U.
- 0x00~0x02:3字节,跳转指令。
- 0x03~0x0A:8字节,文件系统标志和版本号
- 0x0B~0x0C:2字节,每扇区字节数
- 0x0D~0x0D:1字节,每簇扇区数
- 0x0E~0x0F:2字节,保留扇区数
- 0x10~0x10:1字节,FAT表个数,0x02。
- 0x11~0x12:2字节,FAT32必须等于0,FAT12/FAT16为根目录中目录的个数;
- 0x13~0x14:2字节,FAT32必须等于0,FAT12/FAT16为扇区总数。
- 0x15~0x15:1字节,哪种存储介质,0xF8标准值,可移动存储介质。
- 0x16~0x17:2字节,FAT32必须为0,FAT12/FAT16为一个FAT 表所占的扇区数。
- 0x18~0x19:2字节,每磁道扇区数,只对于“特殊形状”(由磁头和柱面分割为若干磁道)的存储介质有效,0x003F=63。
- 0x1A~0x1B:2字节,磁头数,只对特殊的介质才有效,0x00FF=255。
- 0x1C~0x1F:4字节,EBR分区之前所隐藏的扇区数,分区表至FAT32_DBR之间的扇区,对应MBR中的相对扇区数
- 0x20~0x23:4字节,文件系统总扇区数
- 0x24~0x27:4字节,每个FAT表占用扇区数
- 0x28~0x29:2字节,标记,此域FAT32 特有。
- 0x2A~0x2B:2字节,FAT32版本号0.0,FAT32特有。
- 0x2C~0x2F:4字节,根目录所在第一个簇的簇号,0x02。(虽然在FAT32文件系统下,根目录可以存放在数据区的任何位置,但是通常情况下还是起始于2号簇)
- 0x30~0x31:2字节,FSINFO(文件系统信息扇区)扇区号0x01,该扇区为操作系统提供关于空簇总数及下一可用簇的信息。
- 0x32~0x33:2字节,备份引导扇区的位置。备份引导扇区总是位于文件系统的6号扇区。
- 0x34~0x3F:12字节,用于以后FAT 扩展使用。
- 0x40~0x40:1字节,与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已。
- 0x41~0x41:1字节,与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已 。
- 0x42~0x42:1字节,扩展引导标志,0x29。与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已
- 0x43~0x46:4字节,卷序列号。通常为一个随机值。
- 0x47~0x51:11字节,卷标(ASCII码),如果建立文件系统的时候指定了卷标,会保存在此。
- 0x52~0x59:8字节,文件系统格式的ASCII码,FAT32。
- 0x5A~0x1FD:共410字节,引导代码。
- 0x1FE~0x1FF:签名标志“55 AA”。
- FAT文件系统将引导代码与文件形同数据结构融合在FAT32文件系统引导扇区的512字节中,90~509字节为引导代码,而FAT12/16则是62~509字节为引导代码。同时,FAT32还可以利用引导扇区后的扇区空间存放附加的引导代码。一个FAT卷即使不是可引导文件系统,也会存在引导代码。
(a)分区引导扇区数据分析:
跳转指令 空操作指令 OEM ID BPB参数 扩展BPB参数 分区引导记录
EB 58 90 4D 53 44 4F 53 35 2E 30 00 02 10 22 00
02 00 00 00 00 F8 00 00 3F 00 FF 00 3F 00 00 00
9A E5 3F 01 F3 27 00 00 00 00 00 00 02 00 00 00
01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00
80 00 29 61 D6 9A 0A 20 20 20 20 20 20 20 20 20
20 20 46 41 54 33 32 20 20 20 33 C9 8E D1 BC F4
(b)BPB参数分析:
字节数/扇区 扇区数/簇 保留扇区数(FAT1表至FAT32_DBR之间的扇区) FAT表个数 未用 未用 媒体描述符 未用 扇区数/磁道 磁头数 隐藏扇区数(分区表至FAT32_DBR之间的扇区)
00 02 10 22 00 02 00 00 00 00 F8 00 00 3F 00 FF 00 3F 00 00 00
FAT32文件系统的总扇区数 每个FAT表占用的扇区数 扩展标志 文件系统版本 根目录开始簇号 文件系统信息扇区号 FAT32_DBR备份扇区所在的扇区号 保留(12字节)
9A E5 3F 01 F3 27 00 00 00 00 00 00 02 00 00 00 01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00
(c)扩展BPB参数分析:
物理驱动号 保留 扩展引导标签(必须是0x28或0x29) 卷标序号 FAT32的卷标 系统ID(一般是"FAT32")
80 00 29 61 D6 9A 0A 20 20 20 20 20 20 20 20 20 20 20 46 41 54 33 32 20 20 20
FSINFO 信息扇区分析
该扇区在在分区引导扇区之后的一个扇区
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
000008000 52 52 61 41 00 00 00 00 00 00 00 00 00 00 00 00 RRaA............
000008010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000080A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000080B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000080C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000080D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000080E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000080F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000008190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000081A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000081B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000081C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000081D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000081E0 00 00 00 00 72 72 41 61 58 F9 13 00 06 00 00 00 ....rrAaX.......
0000081F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............U.
参数内容分析如下:
扩展引导标志"RRaA" 未使用(480字节)
52 52 61 41 00 00 00 00 00 00 00 00 00 00 00 00 .....
FSINFO 签名标志"rrAa" 空闲簇 下一个可用簇(该值不一定准) 未使用(14字节) 标志"55 AA"
00 00 00 00 72 72 41 61 58 F9 13 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
第一分区 备份分区引导扇区
在分区引导之后的第6个扇区,从DBR中可以知道备份备份DBR的位置,内容与分区引导中的数据一样
FSINFO 备份信息扇区分区
在分区引导之后的第7个扇区,内容与信息扇区分区的数据相同
(二)分析FAT32文件系统的FAT表
FAT文件系统之所以有12,16,32不同的版本之分,其根本在于FAT表用来记录任意一簇链接的二进制位数。以FAT16为例,每一簇在FAT表中占据2字节(二进制16位)。所以,FAT16最大可以表示的簇号为0xFFFF(十进制的65535),以32K(最多只支持64个扇区)为簇的大小的话,FAT16可以管理的最大磁盘空间为:32KB×65535=2048MB,这就是为什么FAT16不支持超过2GB分区的原因。
FAT表结构及作用:
- 1、FAT32文件一般有两份FAT,他们由格式化程序在对分区进行格式化时创建,FAT1是主,FAT2是备份。
- 2、FAT1跟在DBR之后,其具体地址由DBR的BPB参数中指定,FAT2跟在FAT1的后面。
- 3、FAT表由FAT表项构成,我们把FAT表项简称FAT项,每个FAT项占用4字节。
- 4、每个FAT项都有一个固定的编号,这个编号从0开始。
- 5、FAT表项的前两个FAT项为文件系统保留使用,0号FAT为介质类型,1号FAT为文件系统错误标志。
- 6、分区的数据区中每个簇都会映射到FAT表中的唯一一个FAT项,因为0号FAT和1号FAT被系统占用,用户的数据从2号FAT开始记录。
- 7、如果某个文件占用很多个簇,则第一个FAT项记录下一个FAT项的编号(既簇号),如果这个文件结束了,则用“0F FF FF FF”表示。
- 8、分区格式化后,用户文件以簇为单位存放在数据区中,一个文件至少占用一个簇。
- 9、FAT的主要作用是标明分区存储的介质以及簇的使用情况。
定位FAT绝对位置的方法如下:
- 1、首先从MBR的分区表中得知分区的起始扇区,偏移到此扇区。
- 2、从DBR的BPB中得知DBR的保留扇区数,FAT表的个数,FAT表的大小。
- 3、因此FAT1=分区起始扇区+DBR保留扇区,FAT2=分区起始扇区+DBR保留扇区+FAT1。
下面为FAT1的第一个扇区:(该SD卡被低级格式化过,没有任何的用户数据)
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
00000C200 F8 FF FF 0F FF FF FF 0F FF FF FF 0F 00 00 00 00 ................
00000C210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C230 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C250 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C280 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C290 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C2A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C2B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C2C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C2D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C2E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C2F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C320 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C370 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C380 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C390 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C3A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C3B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C3C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C3D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C3E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000C3F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
添加文件之后的FAT1第一个扇区
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
00000C200 F8 FF FF 0F FF FF FF FF E3 1F 00 00 04 00 00 00 ................
00000C210 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 ................
00000C220 09 00 00 00 0A 00 00 00 0B 00 00 00 0C 00 00 00 ................
00000C230 0D 00 00 00 0E 00 00 00 0F 00 00 00 10 00 00 00 ................
00000C240 11 00 00 00 12 00 00 00 13 00 00 00 14 00 00 00 ................
00000C250 15 00 00 00 16 00 00 00 17 00 00 00 18 00 00 00 ................
00000C260 19 00 00 00 1A 00 00 00 1B 00 00 00 1C 00 00 00 ................
00000C270 1D 00 00 00 1E 00 00 00 1F 00 00 00 20 00 00 00 ............ ...
00000C280 21 00 00 00 22 00 00 00 FF FF FF 0F 24 00 00 00 !...".......$...
00000C290 25 00 00 00 26 00 00 00 27 00 00 00 28 00 00 00 %...&...'...(...
00000C2A0 29 00 00 00 2A 00 00 00 2B 00 00 00 2C 00 00 00 )...*...+...,...
00000C2B0 2D 00 00 00 2E 00 00 00 2F 00 00 00 30 00 00 00 -......./...0...
00000C2C0 31 00 00 00 32 00 00 00 33 00 00 00 34 00 00 00 1...2...3...4...
00000C2D0 35 00 00 00 36 00 00 00 37 00 00 00 38 00 00 00 5...6...7...8...
00000C2E0 39 00 00 00 3A 00 00 00 3B 00 00 00 3C 00 00 00 9...:...;...<...
00000C2F0 3D 00 00 00 3E 00 00 00 3F 00 00 00 40 00 00 00 =...>...?...@...
00000C300 41 00 00 00 42 00 00 00 FF FF FF 0F 44 00 00 00 A...B.......D...
00000C310 45 00 00 00 46 00 00 00 47 00 00 00 48 00 00 00 E...F...G...H...
00000C320 49 00 00 00 4A 00 00 00 4B 00 00 00 4C 00 00 00 I...J...K...L...
00000C330 4D 00 00 00 4E 00 00 00 4F 00 00 00 50 00 00 00 M...N...O...P...
00000C340 51 00 00 00 52 00 00 00 53 00 00 00 54 00 00 00 Q...R...S...T...
00000C350 55 00 00 00 56 00 00 00 57 00 00 00 58 00 00 00 U...V...W...X...
00000C360 59 00 00 00 5A 00 00 00 5B 00 00 00 5C 00 00 00 Y...Z...[...\...
00000C370 5D 00 00 00 5E 00 00 00 5F 00 00 00 60 00 00 00 ]...^..._...`...
00000C380 61 00 00 00 62 00 00 00 FF FF FF 0F 64 00 00 00 a...b.......d...
00000C390 65 00 00 00 66 00 00 00 67 00 00 00 68 00 00 00 e...f...g...h...
00000C3A0 69 00 00 00 6A 00 00 00 6B 00 00 00 6C 00 00 00 i...j...k...l...
00000C3B0 6D 00 00 00 6E 00 00 00 6F 00 00 00 70 00 00 00 m...n...o...p...
00000C3C0 71 00 00 00 72 00 00 00 73 00 00 00 74 00 00 00 q...r...s...t...
00000C3D0 75 00 00 00 76 00 00 00 77 00 00 00 78 00 00 00 u...v...w...x...
00000C3E0 79 00 00 00 7A 00 00 00 7B 00 00 00 7C 00 00 00 y...z...{...|...
00000C3F0 7D 00 00 00 7E 00 00 00 7F 00 00 00 80 00 00 00 }...~...........
FAT项分析:
第0项 F8 FF FF 0F 磁盘标识字,第一项FF FF FF FF 第一簇被占用 FF FF FF 0F 文件开始簇, 04 00 00 00 ~ 22 00 00 00 大文件的连续簇,FF FF FF 0F 结束簇,第一个文件到这里结束了。下面的簇也可以一样的分析。
(三)分析FAT32文件系统的数据区(data)
数据区的位置在FAT2的后面,具体定位方式如下;
1、通过MBR中的分区表信息得知分区的起始位置。
2、通过分区中DBR得知DBR的保留扇区数以及FAT表的大小,FAT表的个数。
3、通过上面的信息就可以找到数据区的起始位置,数据区 = 隐藏扇区数+DBR保留扇区+(每个FAT表扇区数*2)。
数据区的类容主要由三部分组成:根目录,子目录和文件内容。在数据区中是以“簇”为单位进行存储的,2号簇被分配给根目录使用。
根据簇号得到在FAT中的扇区号和偏移:
扇区号 = 簇号*4/每个扇区的字节数 + 隐藏扇区数 + 保留扇区数
扇区偏移 = 簇号*4%每个扇区的字节数
根据簇号得到起始扇区号:
簇号起始扇区 = (簇号-2)* 每个簇的扇区数 + 隐藏扇区数 + 保留扇区数 + FAT数*每个FAT占扇区数
下面为根目录的第一个扇区:
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
000A08E00 CF B5 CD B3 20 20 20 20 20 20 20 08 00 00 00 00 .... .....
000A08E10 00 00 00 00 00 00 6A 86 BF 4E 00 00 00 00 00 00 ......j..N......
000A08E20 4A 50 5F 30 30 37 30 30 57 53 44 20 10 07 22 92 JP_00700WSD ..".
000A08E30 BF 4E BF 4E 00 00 37 7D AF 4E 03 00 00 00 04 00 .N.N..7}.N......
000A08E40 4A 50 5F 30 30 30 30 30 57 53 44 20 10 29 22 92 JP_00000WSD .)".
000A08E50 BF 4E BF 4E 00 00 00 00 21 00 23 00 00 00 04 00 .N.N....!.#.....
000A08E60 4A 50 5F 30 30 30 30 31 57 53 44 20 10 2B 22 92 JP_00001WSD .+".
000A08E70 BF 4E BF 4E 00 00 00 00 21 00 43 00 00 00 04 00 .N.N....!.C.....
000A08E80 4A 50 5F 30 30 30 30 32 57 53 44 20 10 37 22 92 JP_00002WSD .7".
000A08E90 BF 4E BF 4E 00 00 00 00 21 00 63 00 00 00 04 00 .N.N....!.c.....
000A08EA0 4A 50 5F 30 30 30 30 33 57 53 44 20 10 39 22 92 JP_00003WSD .9".
000A08EB0 BF 4E BF 4E 00 00 00 00 21 00 83 00 00 00 04 00 .N.N....!.......
000A08EC0 4A 50 5F 30 30 30 30 34 57 53 44 20 10 3C 22 92 JP_00004WSD .<".
000A08ED0 BF 4E BF 4E 00 00 AD 2E B0 4E A3 00 00 00 04 00 .N.N.....N......
000A08EE0 4A 50 5F 30 30 30 30 35 57 53 44 20 10 3E 22 92 JP_00005WSD .>".
000A08EF0 BF 4E BF 4E 00 00 D7 1B BC 4E C3 00 00 00 04 00 .N.N.....N......
000A08F00 4A 50 5F 30 30 30 30 36 57 53 44 20 10 40 22 92 JP_00006WSD .@".
000A08F10 BF 4E BF 4E 00 00 70 20 BC 4E E3 00 00 00 04 00 .N.N..p .N......
000A08F20 4A 50 5F 30 30 30 30 37 57 53 44 20 10 5B 22 92 JP_00007WSD .[".
000A08F30 BF 4E BF 4E 00 00 B4 20 BC 4E 03 01 00 00 04 00 .N.N... .N......
000A08F40 4A 50 5F 30 30 30 30 38 57 53 44 20 10 65 22 92 JP_00008WSD .e".
000A08F50 BF 4E BF 4E 00 00 71 21 BC 4E 23 01 00 00 04 00 .N.N..q!.N#.....
000A08F60 4A 50 5F 30 30 30 30 39 57 53 44 20 10 69 22 92 JP_00009WSD .i".
000A08F70 BF 4E BF 4E 00 00 4F 24 BC 4E 43 01 00 00 04 00 .N.N..O$.NC.....
000A08F80 4A 50 5F 30 30 30 31 30 57 53 44 20 10 6D 22 92 JP_00010WSD .m".
000A08F90 BF 4E BF 4E 00 00 61 24 BC 4E 63 01 00 00 04 00 .N.N..a$.Nc.....
000A08FA0 4A 50 5F 30 30 30 31 31 57 53 44 20 10 71 22 92 JP_00011WSD .q".
000A08FB0 BF 4E BF 4E 00 00 35 7D AF 4E 83 01 00 00 04 00 .N.N..5}.N......
000A08FC0 4A 50 5F 30 30 30 31 32 57 53 44 20 10 75 22 92 JP_00012WSD .u".
000A08FD0 BF 4E BF 4E 00 00 35 7D AF 4E A3 01 00 00 04 00 .N.N..5}.N......
000A08FE0 4A 50 5F 30 30 30 31 33 57 53 44 20 10 79 22 92 JP_00013WSD .y".
000A08FF0 BF 4E BF 4E 00 00 35 7D AF 4E C3 01 00 00 04 00 .N.N..5}.N......
FAT32文件系统中,分区根目录下的文件和目录都放在根目录区中,子目录中的文件和目录都放在子目录区中,并且每32个字节为一个目录项(FDT),每个目录项纪录着一个目录或文件(也可能是多个目录项记录一个文件或目录),如下面所示就是一个目录项。
4A 50 5F 30 30 37 30 30 57 53 44 20 10 07 22 92
BF 4E BF 4E 00 00 37 7D AF 4E 03 00 00 00 04 00
在FAT32文件系统中,目录项可以分为四类:
卷标目录项、“.”和“..”目录项、短文件名目录项、长文件名目录项。
卷标目录项:
卷标就是分区的名字,可以在格式化分区时创建,也可以随意修改,长度为11字节。
“.”和“..”目录项:
“.”表示当前目录,“..”表示上一层目录。这两个目录项多存在子目录中。
短文件名目录项:
所谓短文件名既文件名的“8.3”格式,此格式支持主文件名不能超过8字节,扩展名不能超过3字节。短文件名目录始终存放在一个目录项中。
长文件名目录项:
由于短文件名“8.3”的格式远远不能满足现实中的需求,所以就出现了长文件名。
1.1. 何为短文件名
短文件名是DOS+FAT12/FAT16时代的产物,命名规则为8.3
8是指文件名,3是指扩展名(完整文件=文件名.扩展名)
文件名不能超过8个字节,如果多于8个字节,在DOS里不会被识别
扩展名不能超过3个字节,如果多于3个字节,在DOS里不会被识别
1.2. 何为长文件名
文件名超出8个字节或扩展名超出3个字节都是长文件名
FAT32文件系统完全支持长文件名,长文件名记录在目录项中,可能一个文件名占据多个目录项
1.3. FAT32中短文件目录项
1.3.1. 短文件目录项特点
1.如果文件名不足8个则用0x20进行填充
2.如果是子目录,则将扩展名部分用“0x20”进行填充
3.每个文件或子目录都分配有一个大小为 32 字节的短文件目录项,用以描述文件或目录的属性
4.要找到一个目录项的位置只能用分配给文件或子目录的全名进行是搜索
5.一个目录项是否被分配使用由它的第一个字节来描述。对于已经分配使用的目录项,它的第一个字节是文件名的第一个字符,而文件或目录被删除后,它所对应的目录项的第一个字节将被置为0xE5,这就是为什么有的 FAT数据恢复工具需要用户自己输入文件名的第一个字符的原因
FAT32短文件目录项32个字节的表示定义如下:
- 0x0-0x7:文件名,如果该目录项正在使用中0x0位置的值为文件名或子目录名的第一个字符,如果该目录项未被使用0x0位置的值为0x00,如果该目录项曾经被使用过但是现在已经被删除则0x0位置的值为0xE5
- 0x8-0xA:扩展名
- 0xB:描述文件的属性,该字段在短文件中不可取值0x0F,如果设置为0x0F则标志是长文件
- 0xC:1字节,保留 (这个位默认为0,只有短文件名时才有用.当为0x00时为文件名全大写,当为0x08时为文件名全小写;0x10时扩展名全大写,0x00扩展名全小写;当为0x18时为文件名全小写,扩展名全大写)
- 0xD:文件创建的时间-精确到十分之一秒
- 0xE-0xF:文件创建的时间-时分秒,16bit 被划分为 3个部分
- 0~4bit 为秒,以 2秒为单位,有效值为 0~29,可以表示的时刻为 0~58
- 5~10bit 为分,有效值为 0~59
- 11~15bit 为时,有效值为 0~23
- 0x10-0x11:文件创建日期,16bit 也划分为三个部分
- 0~4bit 为日,有效值为 1~31
- 5~8bit 为月,有效值为 1~12
- 9~15bit 为年,有效值为 0~127,这是一个相对于 1980 年的年数值,也就是说该值加上 1980即为文件创建的日期值。
- 0x12~0x13:2 个字节,最后访问日期。
- 0x14~0x15:2 个字节,文件起始簇号的高两个字节。
- 0x16~0x17:2 个字节,文件最后修改的时间。
- 0x18~0x19:2 个字节,文件最后被修改时的日期。
- 0x1A~0x1B:文件内容起始簇号的低两个字节,与 0x14~0x15 字节处的高两个字节组成文件内容起始簇号。
- 0x1C~0x1F:文件内容大小字节数,只对文件有效,子目录的目录项此处全部设置为 0。
注意这里:最后面的文件长度,它占用4个字节,也就是说它最大只能表示4G大小的文件,如果文件大于4G,FAT32文件系统将会支持不了。
上面根目录的数据可以分析出第一和第二段目录项的内容:
文件名 文件扩展名 属性字节 系统保留 创建的时间10毫秒位 文件创建时间 文件创建日期 文件最后访问日期 文件起始簇号高16位 文件的最后修改时间 文件的最后修改日期 文件起始簇号的低16位 文件的长度
目录项1 CF B5 CD B3 20 20 20 20 20 20 20 08 00 00 00 00 00 00 00 00 00 00 6A 86 BF 4E 00 00 00 00 00 00
目录项2 4A 50 5F 30 30 37 30 30 57 53 44 20 10 07 22 92 BF 4E BF 4E 00 00 37 7D AF 4E 03 00 00 00 04 00
可以看出目录项1是卷标,其属性字节为0x08,目录项2 是 归档,也就是文件:
目录项1文件名为:该目录项为卷,不是正常的文件名
目录项1最后修改时间 :
0x866A = 1000011001101010 = 10000(时) 110011(分) 01010(秒) = 10000(16时) 110011(51分) 01010(10秒)
目录项1最后修改日期 :
0x4EBF = 100111010111111 = 100111(年) 0101(月) 11111(日) = 100111(1980+39年) 0101(5月) 11111(31日)
目录项2文件名为:JP_00700.WSD
目录项2的时间日期与目录项1的时间日期计算相同
1.4. FAT32中长文件目录项
1.4.1. 长文件目录项特点
为了低版本的OS或程序能正确读取长文件名文件,系统自动为所有长文件名文件创建了一个对应的短文件名,使对应数据既可以用长文件名寻址,也可以用短文件名寻址。不支持长文件名的OS或程序会忽略它认为不合法的长文件名字段,而支持长文件名的OS或程序则会以长文件名为显式项来记录和编辑,并隐藏起短文件名。
长文件名的实现有赖于目录项偏移为0xB的属性字节,当此字节的属性为:只读、隐藏、系统、卷标,即其值为0FH时,DOS和WIN32会认为其不合法而忽略其存在。这正是长文件名存在的依据。
系统将长文件名以13个字符为单位进行切割,每一组占据一个目录项。所以可能一个文件需要多个目录项,这时长文件名的各个目录项按倒序排列在目录表中,以防与其他文件名混淆。长文件名的第一部分距离短文件名目录项是最近的。
系统在存储长文件名时,总是先按倒序填充长文件名目录项,然后紧跟其对应的短文件名。长文件名中并不存储对应文件的文件开始簇、文件大小、各种时间和日期属性。文件的这些属性还是存放在短文件名目录项中,一个长文件名总是和其相应的短文件名一一对应,短文件名没有了长文件名还可以读,但长文件名如果没有对应的短文件名,不管什么系统都将忽略其存在。所以短文件名是至关重要的。在不支持长文件名的环境中对短文件名中的文件名和扩展名字段作更改(包括删除,因为删除是对首字符改写E5H),都会使长文件名形同虚设。
1.4.2. 长转短文件名规则
当创建一个长文件名文件时,系统会自动加上对应的短文件名,其一般有的原则:
(1)、取长文件名的前6个字符加上”~1”形成短文件名,扩展名不变。
(2)、如果已存在这个文件名,则符号”~”后的数字递增,直到5。
(3)、如果文件名中”~”后面的数字达到5,则短文件名只使用长文件名的前两个字母。通过数学操纵长文件名的剩余字母生成短文件名的后四个字母,然后加后缀”~1”直到最后(如果有必要,或是其他数字以避免重复的文件名)。
(4)、如果存在老OS或程序无法读取的字符,换以”_”
1.4.3. 长文件目录名定义
长文件名中的字符采用unicode形式编码,每个字符占据2字节的空间。其目录项定义如下:
- 0x00~0x00:1 个字节,长文件名目录项的序列号,一个文件的第一个目录项序列号为 1,然后依次递增。如果是该文件的最后一个长文件名目录项,则将该目录项的序号与 0x40 进行“或(OR)运算”的结果写入该位置。如果该长文件名目录项对应的文件或子目录被删除,则将该字节设置成删除标志0xE5。
- 0x01~0x0A:10 个字节,长文件名的第 1~5 个字符。长文件名使用 Unicode 码,每个字符需要两个字节的空间。如果文件名结束但还有未使用的字节,则会在文件名后先填充两个字节的“00”,然后开始使用 0xFF 填充。
- 0x0B~0x0B:1 个字节,长目录项的属性标志,一定是 0x0F。
- 0x0C~0x0C:保留。
- 0x0D~0x0D:1 个字节,校验和。如果一个文件的长文件名需要几个长文件名目录项进行存储,则这些长文件名目录项具有相同的校验和。
- 0x0E~0x19:12 个字节,文件名的第 6~11 个字符,未使用的字节用 0xFF 填充。
- 0x1A~0x1B:2 个字节,保留。
- 0x1C~0x1F:4 个字节,文件名的第 12~13 个字符,未使用的字节用 0xFF 填充。
1.5. 长短文件名如何配对
长文件名和短文件名之间的联系光靠他们之间的位置关系维系显然远远不够。其实,长文件名的0xD字节的校验和起很重要的作用,此校验和是用短文件名的11个字符通过一种运算方式来得到的。系统根据相应的算法来确定相应的长文件名和短文件名是否匹配
如果通过短文件名计算出来的校验和与长文件名中的0xD偏移处数据不相等。系统无论如何都不会将它们配对的。
依据长文件名和短文件名对目录项的定义,加上对簇的编号和链接,FAT32上数据的读取便游刃有余了。
1.6. .与..
1.6.1. “.”目录项和“..”目录项
“.”表示当前目录(下文中的子)
“..”表示上级目录(下文中的父)
一个子目录的起始簇,前两个目录项为“.”目录项和“..”目录项,子目录通过这两个目录项及它在父目录中的目录项建立起父子目录的联系。
“.”目录项位于子目录起始簇的第一个目录项位置,它用以表明该簇是一个子目录的起始簇。另外,该目录项实际上是对目录自身的描述,它记录了该子目录时间信息、起始簇号等。需要注意的是,它所记录的起始簇号也就是该子目录目前所处的位置。
“..”目录项位于子目录起始簇的第二个目录项位置,用于描述该子目录的父目录的相关信息。
1.6.2. 卷标目录项
卷标名使用11个字节描述(目录项还是32字节咯),不足 11 个字节,则用 0x20 填充。(由于每个汉字占用 2 个字节空间,而卷标最多允许 11 个字节,所以用汉字命名卷标时,卷标的长度不能超过 5 个汉字)。
卷标目录项结构与普通短文件名目录项结构完全相同,但没有创建时间和访问时间,只有一个最后修改时间。
另外,卷标目录项也没有起始簇号和大小值,这些字节位置全部这只为 0
0x0B 字节处的属性值为 0x08.
如果创建文件系统时指定了卷标,则会在根目录下第一个目录项的位置建立一个卷标目录项
卷标名最多允许占用长度为 11 个字节,也就是为短文件名分配的 11 个文件名区域
代码实现:
1.最简GPT分区功能实现:
/************************************************************
*Copyright (C),lcb0281at163.com lcb0281atgmail.com
*FileName: GPT_DiskPart.cpp
*BlogAddr: caibiao-lee.blog.csdn.net
*Description:磁盘分区类成员的实现,其集中了磁盘分区的所有功能
*Date: 2019-10-12
*Author: Caibiao Lee
*Version: V1.0
*Others:
*History:
***********************************************************/
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <sys/mount.h>
#include <linux/fd.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include "GPT_DiskPart.h"
#define SIGNATURE "EFI PART"
const unsigned char s8ArrBootCode[] = {
0x33,0xC0,0x8E,0xD0,0xBC,0x00,0x7C,0x8E,0xC0,0x8E,0xD8,0xBE,\
0x00,0x7C,0xBF,0x00,0x06,0xB9,0x00,0x02,0xFC,0xF3,0xA4,0x50,0x68,0x1C,0x06,\
0xCB,0xFB,0xB9,0x04,0x00,0xBD,0xBE,0x07,0x80,0x7E,0x00,0x00,0x7C,0x0B,0x0F,\
0x85,0x0E,0x01,0x83,0xC5,0x10,0xE2,0xF1,0xCD,0x18,0x88,0x56,0x00,0x55,0xC6,\
0x46,0x11,0x05,0xC6,0x46,0x10,0x00,0xB4,0x41,0xBB,0xAA,0x55,0xCD,0x13,0x5D,\
0x72,0x0F,0x81,0xFB,0x55,0xAA,0x75,0x09,0xF7,0xC1,0x01,0x00,0x74,0x03,0xFE,\
0x46,0x10,0x66,0x60,0x80,0x7E,0x10,0x00,0x74,0x26,0x66,0x68,0x00,0x00,0x00,\
0x00,0x66,0xFF,0x76,0x08,0x68,0x00,0x00,0x68,0x00,0x7C,0x68,0x01,0x00,0x68,\
0x10,0x00,0xB4,0x42,0x8A,0x56,0x00,0x8B,0xF4,0xCD,0x13,0x9F,0x83,0xC4,0x10,\
0x9E,0xEB,0x14,0xB8,0x01,0x02,0xBB,0x00,0x7C,0x8A,0x56,0x00,0x8A,0x76,0x01,\
0x8A,0x4E,0x02,0x8A,0x6E,0x03,0xCD,0x13,0x66,0x61,0x73,0x1C,0xFE,0x4E,0x11,\
0x75,0x0C,0x80,0x7E,0x00,0x80,0x0F,0x84,0x8A,0x00,0xB2,0x80,0xEB,0x84,0x55,\
0x32,0xE4,0x8A,0x56,0x00,0xCD,0x13,0x5D,0xEB,0x9E,0x81,0x3E,0xFE,0x7D,0x55,\
0xAA,0x75,0x6E,0xFF,0x76,0x00,0xE8,0x8D,0x00,0x75,0x17,0xFA,0xB0,0xD1,0xE6,\
0x64,0xE8,0x83,0x00,0xB0,0xDF,0xE6,0x60,0xE8,0x7C,0x00,0xB0,0xFF,0xE6,0x64,\
0xE8,0x75,0x00,0xFB,0xB8,0x00,0xBB,0xCD,0x1A,0x66,0x23,0xC0,0x75,0x3B,0x66,\
0x81,0xFB,0x54,0x43,0x50,0x41,0x75,0x32,0x81,0xF9,0x02,0x01,0x72,0x2C,0x66,\
0x68,0x07,0xBB,0x00,0x00,0x66,0x68,0x00,0x02,0x00,0x00,0x66,0x68,0x08,0x00,\
0x00,0x00,0x66,0x53,0x66,0x53,0x66,0x55,0x66,0x68,0x00,0x00,0x00,0x00,0x66,\
0x68,0x00,0x7C,0x00,0x00,0x66,0x61,0x68,0x00,0x00,0x07,0xCD,0x1A,0x5A,0x32,\
0xF6,0xEA,0x00,0x7C,0x00,0x00,0xCD,0x18,0xA0,0xB7,0x07,0xEB,0x08,0xA0,0xB6,\
0x07,0xEB,0x03,0xA0,0xB5,0x07,0x32,0xE4,0x05,0x00,0x07,0x8B,0xF0,0xAC,0x3C,\
0x00,0x74,0x09,0xBB,0x07,0x00,0xB4,0x0E,0xCD,0x10,0xEB,0xF2,0xF4,0xEB,0xFD,\
0x2B,0xC9,0xE4,0x64,0xEB,0x00,0x24,0x02,0xE0,0xF8,0x24,0x02,0xC3,0x49,0x6E,\
0x76,0x61,0x6C,0x69,0x64,0x20,0x70,0x61,0x72,0x74,0x69,0x74,0x69,0x6F,0x6E,\
0x20,0x74,0x61,0x62,0x6C,0x65,0x00,0x45,0x72,0x72,0x6F,0x72,0x20,0x6C,0x6F,\
0x61,0x64,0x69,0x6E,0x67,0x20,0x6F,0x70,0x65,0x72,0x61,0x74,0x69,0x6E,0x67,\
0x20,0x73,0x79,0x73,0x74,0x65,0x6D,0x00,0x4D,0x69,0x73,0x73,0x69,0x6E,0x67,\
0x20,0x6F,0x70,0x65,0x72,0x61,0x74,0x69,0x6E,0x67,0x20,0x73,0x79,0x73,0x74,\
0x65,0x6D,0x00,0x00,0x00,0x63,0x7B,0x9A,0xD7,0x26,0x7E,0x7F,0x00,0x00
};
unsigned int const g_u8arrcrc32tab[] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
};
static unsigned int GPT_CRC32(unsigned char *pu8buf,unsigned int u32size)
{
unsigned int i, l_u32crc;
l_u32crc = 0xFFFFFFFF;
for (i = 0; i < u32size; i++)
{
l_u32crc = g_u8arrcrc32tab[(l_u32crc ^ pu8buf[i]) & 0xff] ^ (l_u32crc >> 8);
}
return l_u32crc^0xFFFFFFFF;
}
GPTDiskPart::GPTDiskPart()
{
m_u32SecPerTrac = SECTOR_BYTE_NUM;
m_u32HeadNum = DISK_HEAD_NUM;
m_u32SecSize = SECTOR_BYTE_NUM;
m_u64SecCount = 0;
}
GPTDiskPart::~GPTDiskPart()
{
}
GPTDiskPart *GPTDiskPart::GPTDiskPartInstance()
{
static GPTDiskPart *l_clsGptDP = NULL;
if(NULL == l_clsGptDP)
{
l_clsGptDP = new GPTDiskPart();
}
return l_clsGptDP;
}
int GPTDiskPart::GPTDP_Access(char *const ps8Path)
{
if(NULL == ps8Path)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
return access(ps8Path,F_OK);
}
int GPTDiskPart::GPTDP_Open(char *const ps8Path,int s32Flag)
{
if(NULL == ps8Path)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
return open(ps8Path,s32Flag);
}
int GPTDiskPart::GPTDP_Close(int s32Fd)
{
close(s32Fd);
return 0;
}
int GPTDiskPart::GPTDP_Ioctl(int s32Fd,int s32Cmd,void *pArg)
{
if(s32Fd < 0 || NULL == pArg)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
return ioctl(s32Fd,s32Cmd,pArg); /*用法很简单*/
}
int GPTDiskPart::GPTDP_Select(int s32Fd,unsigned int u32TimeOut)
{
struct timeval l_stTimeOut = {0};
int l_s32Ret = 0;
fd_set l_stReadFdSet;
fd_set l_stWriteFdSet;
l_stTimeOut.tv_sec = u32TimeOut; /*超时3秒*/
FD_ZERO(&l_stReadFdSet);
FD_ZERO(&l_stWriteFdSet);
FD_SET(s32Fd,&l_stReadFdSet);
FD_SET(s32Fd,&l_stWriteFdSet);
l_s32Ret = select(s32Fd + 1,&l_stReadFdSet,&l_stWriteFdSet,NULL,&l_stTimeOut);
if(l_s32Ret <= 0)
{
GPTP_LOG("[%s,%d] select error\n",__FILE__,__LINE__);
return SELECT_ERROR;
}
if(FD_ISSET(s32Fd,&l_stReadFdSet) && FD_ISSET(s32Fd,&l_stWriteFdSet))
{
return 0;
}
return SELECT_ERROR;
}
int GPTDiskPart::GPTDP_Read(int s32Fd,unsigned char *pu8DateBuf,int s32Size)
{
if(NULL == pu8DateBuf || s32Size < 0 || s32Fd < 0)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
return read(s32Fd,pu8DateBuf,s32Size);
}
int GPTDiskPart::GPTDP_Write(int s32Fd,unsigned char *pu8DateBuf,int s32Size)
{
if(NULL == pu8DateBuf || s32Size < 0 || s32Fd < 0)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
return write(s32Fd,pu8DateBuf,s32Size);
}
long long GPTDiskPart::GPTDP_Lseek64(int s32Fd,long long s64Offset,int s32Whence)
{
if(s32Fd < 0)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
GPTP_LOG("[%s,%d] ====lseek64==%lld=\n",__FILE__,__LINE__,s64Offset);
return lseek64(s32Fd,s64Offset,s32Whence);
}
int GPTDiskPart::GPTDP_WriteMBRHandle(int s32Fd,MBR_INFO_S *pstMBRInfo)
{
PART_INFO_S l_starrPartInfo[4] = {0};
int l_s32Ret = 0;
long long l_s64Ret = 0;
if(s32Fd < 0 || NULL == pstMBRInfo)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
l_starrPartInfo[0].u8PartSelfFlag = 0;
l_starrPartInfo[0].u8PartStartHead = 0;
l_starrPartInfo[0].u8PartStartSec = 2;
l_starrPartInfo[0].u8PartStartCylLow = 0;
l_starrPartInfo[0].u8PartStartCylHig8 = 0;
l_starrPartInfo[0].u8PartFlag = 0xEE;
l_starrPartInfo[0].u8PartStopHead = 0xFF;
l_starrPartInfo[0].u8PartStopSec = 0x3F;
l_starrPartInfo[0].u8PartStopCylLow = 0x3;
l_starrPartInfo[0].u8PartStopCylHig8 = 0xFF;
l_starrPartInfo[0].u32StartSec = GPT_HEAD_SECNO;
l_starrPartInfo[0].u32SizeSec = 0xFFFFFFFF;
bzero(pstMBRInfo,sizeof(MBR_INFO_S));
pstMBRInfo->s8ArrTag[0] = 0x55;
pstMBRInfo->s8ArrTag[1] = 0xAA;
memcpy(pstMBRInfo->u8arrBoot ,s8ArrBootCode,sizeof(s8ArrBootCode));
memcpy(pstMBRInfo->starrPartInfo,l_starrPartInfo,sizeof(PART_INFO_S) * 4);
GPTP_LOG("[%s,%d] 开始偏移到0扇区写MBR\n",__FILE__,__LINE__);
l_s32Ret = GPTDP_Lseek64(s32Fd,0,SEEK_SET);
if(0 != l_s64Ret)
{
GPTP_LOG("[%s,%d] %d is lseek64 error\n",__FILE__,__LINE__,s32Fd);
return LSEEK_ERROR;
}
l_s32Ret = GPTDP_Write(s32Fd,(unsigned char *)pstMBRInfo,sizeof(MBR_INFO_S));
if(sizeof(MBR_INFO_S) != l_s32Ret)
{
GPTP_LOG("[%s,%d] %d is read error\n",__FILE__,__LINE__,s32Fd);
return WRITE_ERROR;
}
return 0;
}
int GPTDiskPart::GPTDP_WriteGPTHead(int s32Fd,GPT_HEAD_INFO_S *pstGPTHeadInfo)
{
unsigned int l_u32Len = 0;
unsigned int l_u32Size = 0;
int l_s32Ret = 0;
long long l_s64offset = 0;
long long l_s64Ret = 0;
unsigned char l_u8arrBuf[17] = {
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,\
0x11,0x12,0x13,0x14,0x15,0x16};
if(s32Fd < 0 || NULL == pstGPTHeadInfo)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
l_u32Size = sizeof(GPT_HEAD_INFO_S);
bzero(pstGPTHeadInfo,l_u32Size);
/*GPT头签名*/
memcpy(pstGPTHeadInfo->u8arrSignature,"EFI PART",8);
/*版本号*/
pstGPTHeadInfo->u8arrVersion[0] = 0x00;
pstGPTHeadInfo->u8arrVersion[1] = 0x00;
pstGPTHeadInfo->u8arrVersion[2] = 0x01;
pstGPTHeadInfo->u8arrVersion[3] = 0x00;
/*GPT头的总字节数*/
pstGPTHeadInfo->u32HeadLen = sizeof(GPT_HEAD_INFO_S) - GPT_HEAD_RESERVED;
/*GPT头的CRC32校验和*/
pstGPTHeadInfo->u32GPTHeadCRC32 = 0;
/*预留*/
pstGPTHeadInfo->u32Reserved = 0;
/*GPT头所在扇区号*/
pstGPTHeadInfo->u64GPTHeadPositSec = GPT_HEAD_SECNO;
/*GPT头备份所在的扇区号*/
pstGPTHeadInfo->u64GPTHeadBackupPositSec = GPT_HEAD_BACKUP_SECNO(m_u64SecCount);
/*分区区域开始的扇区号*/
pstGPTHeadInfo->u64GPTDataStartSec = GPT_DATA_START_SECNO;
/*GPT分区区域结束的扇区号*/
pstGPTHeadInfo->u64GPTDataEndSec = GPT_DATA_END_SECNO(m_u64SecCount);
/*这个结构体是关键*/
struct hd_driveid l_stHD;
l_s32Ret = GPTDP_Ioctl(s32Fd,HDIO_GET_IDENTITY,&l_stHD);
if(l_s32Ret < 0)
{
perror("error:");
GPTP_LOG("[%s,%d]ioctl error\n",__FILE__,__LINE__);
memcpy(pstGPTHeadInfo->u8arrDiskGUID,l_u8arrBuf,16);
}
else
{
GPTP_LOG("Serial No = %s\n",l_stHD.serial_no);
l_u32Len = sizeof(l_stHD.serial_no);
l_u32Len = l_u32Len > 16 ? 16 : l_u32Len;
memcpy(pstGPTHeadInfo->u8arrDiskGUID,l_stHD.serial_no,l_u32Len);
}
/*GPT分区表开始扇区号*/
pstGPTHeadInfo->u64GPTStartSec = GPT_TABLE_SECNO;
/*最多容纳分区表的数量*/
pstGPTHeadInfo->u32MaxNumPartTable = GPT_MAX_PART_NUM;
/*每个分区表项的字节数*/
pstGPTHeadInfo->u32TableItemLen = GPT_PART_ITEMS;
/*分区表CRC32校验和*/
pstGPTHeadInfo->u32GPTCRC32 = 0;
/**写扇区头**/
l_s64offset = GPT_HEAD_SECNO;
l_s64offset *= m_u32SecSize;
GPTP_LOG("[%s,%d] 开始偏移到扇区:%llu写GPT head\n",__FILE__,__LINE__,pstGPTHeadInfo->u64GPTHeadPositSec);
l_s64Ret = GPTDP_Lseek64(s32Fd,l_s64offset,SEEK_SET);
if(l_s64Ret != l_s64offset)
{
GPTP_LOG("[%s,%d] %d is lseek64 error\n",__FILE__,__LINE__,s32Fd);
return LSEEK_ERROR;
}
l_u32Size = sizeof(GPT_HEAD_INFO_S);
l_s32Ret = GPTDP_Write(s32Fd,(unsigned char *)pstGPTHeadInfo,l_u32Size);
if(l_u32Size != (unsigned int)l_s32Ret)
{
GPTP_LOG("[%s,%d] %d is write error\n",__FILE__,__LINE__,s32Fd);
return WRITE_ERROR;
}
/**写备份扇区头**/
l_s64offset = GPT_HEAD_BACKUP_SECNO(m_u64SecCount);
l_s64offset *= m_u32SecSize;
GPTP_LOG("[%s,%d] 开始偏移到扇区:%llu写备份GPT head\n",__FILE__,__LINE__,pstGPTHeadInfo->u64GPTHeadPositSec);
l_s64Ret = GPTDP_Lseek64(s32Fd,l_s64offset,SEEK_SET);
if(l_s64Ret != l_s64offset)
{
GPTP_LOG("[%s,%d] %d is lseek64 error\n",__FILE__,__LINE__,s32Fd);
return LSEEK_ERROR;
}
l_u32Size = sizeof(GPT_HEAD_INFO_S);
l_s32Ret = GPTDP_Write(s32Fd,(unsigned char *)pstGPTHeadInfo,l_u32Size);
if(l_u32Size != (unsigned int)l_s32Ret)
{
GPTP_LOG("[%s,%d] %d is write error\n",__FILE__,__LINE__,s32Fd);
return WRITE_ERROR;
}
return 0;
}
int GPTDiskPart::GPTDP_WritePartTable(int s32Fd,unsigned char u8PartCount,GPT_HEAD_INFO_S *pstGPTHeadInfo)
{
unsigned int l_u32Size = 0;
unsigned char l_u8PartIndex = 0;
unsigned int l_u32PartNum =0;
unsigned int l_u32SecperCly = 0;
int l_s32Ret = 0;
long long l_s64Ret = 0;
long long l_s64offset = 0;
unsigned long long l_u64DataSec = 0;
unsigned long long l_u64EachDataPartSec = 0;
unsigned long long l_u64StartSec = 0;
unsigned long long l_u64EndSec = 0;
unsigned long long l_u64Stmp = 0;
GPT_INFO_S l_starrGPTInfo[GPT_MAX_PART_NUM] = {0};
unsigned char l_u8arrMainPartGUID[17] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
if((s32Fd < 0)||(0==m_u64SecCount)||(0==u8PartCount))
{
GPTP_LOG("[%s,%d] input para error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
if(0 == m_u32SecPerTrac || 0 == m_u32HeadNum || 0 == m_u32SecSize)
{
m_u32SecPerTrac = SECTOR_BYTE_NUM;
m_u32HeadNum = DISK_HEAD_NUM;
m_u32SecSize = SECTOR_BYTE_NUM;
}
l_s64offset = GPT_TABLE_SECNO;
l_s64offset *= m_u32SecSize;
GPTP_LOG("[%s,%d] 开始偏移到扇区:%llu写GPT 表头\n",__FILE__,__LINE__,l_s64offset);
l_s64Ret = GPTDP_Lseek64(s32Fd,l_s64offset,SEEK_SET);
if(l_s64Ret != l_s64offset)
{
GPTP_LOG("[%s,%d] %d is lseek64 error\n",__FILE__,__LINE__,s32Fd);
return LSEEK_ERROR;
}
l_u64DataSec = GPT_HEAD_BACKUP_SECNO(m_u64SecCount) - GPT_DATA_START_SECNO;
l_u64EachDataPartSec = l_u64DataSec/u8PartCount;
/**扇区对齐**/
l_u32SecperCly = m_u32SecPerTrac * m_u32HeadNum;
if(0!=(l_u64EachDataPartSec%l_u32SecperCly))
{
l_u64EachDataPartSec = l_u64EachDataPartSec - (l_u64EachDataPartSec%l_u32SecperCly);
}
l_u64StartSec = GPT_DATA_START_SECNO;
l_u64EndSec = l_u64StartSec + l_u64EachDataPartSec;
for(int i=0;i<u8PartCount;i++)
{
if(l_u64EndSec>=GPT_TABLE_BACKUP_SECNO(m_u64SecCount))
{
break;
}
/**分区类型GUID,使用微软公司的主分区类型**/
memcpy(l_starrGPTInfo[i].u8arrPartType,l_u8arrMainPartGUID,16);
/**分区GUID**/
for(int j=0;j<16;j++)
{
l_starrGPTInfo[i].u8arrGUID[j] = (rand()/255) & 0xFF;
}
/**开始扇区号**/
l_starrGPTInfo[i].u64PartStartSec = l_u64StartSec;
/**结束扇区号,每个分区预留一些空闲空间**/
l_starrGPTInfo[i].u64PartStopSec = l_u64EndSec - l_u32SecperCly;
/**扇区属性**/
l_starrGPTInfo[i].u64PartAttrFlag = 0;
/**扇区名字**/
snprintf(l_starrGPTInfo[i].s8arrPartName,sizeof(l_starrGPTInfo[i]),"Disk_Part_%d\n",i);
l_u64StartSec = l_u64EndSec + 1;
l_u64EndSec = l_u64EndSec + l_u64EachDataPartSec;
}
/**写分区表**/
l_s64offset = GPT_TABLE_SECNO;
GPTP_LOG("[%s,%d] s64offset:%lld\n",__FILE__,__LINE__,l_s64offset);
l_s64offset *= m_u32SecSize;
GPTP_LOG("[%s,%d] 开始偏移到扇区开始位置:%lld,%lld写GPT Table\n",__FILE__,__LINE__,l_s64offset/m_u32SecSize,l_s64offset);
l_s64Ret = GPTDP_Lseek64(s32Fd,l_s64offset,SEEK_SET);
if(l_s64offset != l_s64Ret)
{
GPTP_LOG("[%s,%d] lseek64 offset:%lld error\n",__FILE__,__LINE__,l_s64offset);
return LSEEK_ERROR;
}
l_s32Ret = GPTDP_Write(s32Fd,(unsigned char *)l_starrGPTInfo,sizeof(l_starrGPTInfo));
if(sizeof(l_starrGPTInfo) != (unsigned int)l_s32Ret)
{
GPTP_LOG("[%s,%d] %d is read error\n",__FILE__,__LINE__,s32Fd);
return WRITE_ERROR;
}
/*写备份分区表*/
l_s64offset = GPT_TABLE_BACKUP_SECNO(m_u64SecCount);
GPTP_LOG("[%s,%d] s64offset:%lld\n",__FILE__,__LINE__,l_s64offset);
l_s64offset *= m_u32SecSize;
GPTP_LOG("[%s,%d] 开始偏移到备份扇区开始位置:%lld,%lld写GPT Table\n",__FILE__,__LINE__,l_s64offset/m_u32SecSize,l_s64offset);
l_s64Ret = GPTDP_Lseek64(s32Fd,l_s64offset,SEEK_SET);
if(l_s64offset != l_s64Ret)
{
GPTP_LOG("[%s,%d] lseek64 offset:%lld error\n",__FILE__,__LINE__,l_s64offset);
return LSEEK_ERROR;
}
l_s32Ret = GPTDP_Write(s32Fd,(unsigned char *)l_starrGPTInfo,sizeof(l_starrGPTInfo));
if(sizeof(l_starrGPTInfo) != (unsigned int)l_s32Ret)
{
GPTP_LOG("[%s,%d] %d is read error\n",__FILE__,__LINE__,s32Fd);
return WRITE_ERROR;
}
/**更新GPT头中的CRC校验信息**/
l_s64offset =GPT_HEAD_SECNO ;
GPTP_LOG("[%s,%d] s64offset:%lld\n",__FILE__,__LINE__,l_s64offset);
l_s64offset *= m_u32SecSize;
GPTP_LOG("[%s,%d] 开始偏移到GPT头开始位置:%lld,%lld写GPT Table\n",__FILE__,__LINE__,l_s64offset/m_u32SecSize,l_s64offset);
l_s64Ret = GPTDP_Lseek64(s32Fd,l_s64offset,SEEK_SET);
if(l_s64offset != l_s64Ret)
{
GPTP_LOG("[%s,%d] lseek64 offset:%lld error\n",__FILE__,__LINE__,l_s64offset);
return LSEEK_ERROR;
}
pstGPTHeadInfo->u32GPTCRC32 = GPT_CRC32((unsigned char *)l_starrGPTInfo,sizeof(l_starrGPTInfo));
pstGPTHeadInfo->u32GPTHeadCRC32 = GPT_CRC32((unsigned char *)pstGPTHeadInfo,pstGPTHeadInfo->u32HeadLen);
l_s32Ret = GPTDP_Write(s32Fd,(unsigned char *)pstGPTHeadInfo,sizeof(GPT_HEAD_INFO_S));
if(sizeof(GPT_HEAD_INFO_S) != (unsigned int)l_s32Ret)
{
GPTP_LOG("[%s,%d] %d is read error\n",__FILE__,__LINE__,s32Fd);
return WRITE_ERROR;
}
/**更新备份GPT头中的CRC校验信息**/
l_s64offset =GPT_HEAD_BACKUP_SECNO(m_u64SecCount) ;
GPTP_LOG("[%s,%d] s64offset:%lld\n",__FILE__,__LINE__,l_s64offset);
l_s64offset *= m_u32SecSize;
GPTP_LOG("[%s,%d] 开始偏移到备份GPT头开始位置:%lld,%lld写GPT Table\n",__FILE__,__LINE__,l_s64offset/m_u32SecSize,l_s64offset);
l_s64Ret = GPTDP_Lseek64(s32Fd,l_s64offset,SEEK_SET);
if(l_s64offset != l_s64Ret)
{
GPTP_LOG("[%s,%d] lseek64 offset:%lld error\n",__FILE__,__LINE__,l_s64offset);
return LSEEK_ERROR;
}
/**注意备份分区头的位置信息与正常分区头的位置参数不同**/
l_u64Stmp = pstGPTHeadInfo->u64GPTHeadBackupPositSec;
pstGPTHeadInfo->u64GPTHeadBackupPositSec = pstGPTHeadInfo->u64GPTHeadPositSec;
pstGPTHeadInfo->u64GPTHeadPositSec = l_u64Stmp;
pstGPTHeadInfo->u64GPTStartSec = GPT_TABLE_BACKUP_SECNO(m_u64SecCount);
/**注意GPT头CRC校验不包括它自己,所以应该将它赋值为0后再计算CRC值**/
pstGPTHeadInfo->u32GPTHeadCRC32 = 0;
pstGPTHeadInfo->u32GPTHeadCRC32 = GPT_CRC32((unsigned char *)pstGPTHeadInfo,pstGPTHeadInfo->u32HeadLen);
l_s32Ret = GPTDP_Write(s32Fd,(unsigned char *)pstGPTHeadInfo,sizeof(GPT_HEAD_INFO_S));
if(sizeof(GPT_HEAD_INFO_S) != (unsigned int)l_s32Ret)
{
GPTP_LOG("[%s,%d] write error l_s32Ret = %d , len = %d \n",__FILE__,__LINE__,l_s32Ret,sizeof(GPT_HEAD_INFO_S));
return WRITE_ERROR;
}
return 0;
}
int GPTDiskPart::GPTDP_CreateGPTDiskPart(char *const ps8Path, unsigned char u8PartCount)
{
int l_s32Ret = 0;
int l_s32Fd = 0;
MBR_INFO_S l_stMBRInfo = {0};
GPT_HEAD_INFO_S l_stGPTHeadInfo = {0};
GPT_INFO_S l_starrGPTInfo[GPT_PART_ITEMS] = {0};
if(NULL == ps8Path)
{
GPTP_LOG("[%s,%d] Para Point is NULL error\n",__FILE__,__LINE__);
return PARA_ERROR;
}
if(0 != GPTDP_Access(ps8Path))
{
GPTP_LOG("[%s,%d] Dev noexit error\n",__FILE__,__LINE__);
return FILE_NO_ERROR;
}
GPTP_LOG("[%s,%d] 创建磁盘%s\n",__FILE__,__LINE__,ps8Path);
l_s32Fd = GPTDP_Open(ps8Path,O_RDWR);
if(l_s32Fd < 0)
{
GPTP_LOG("[%s,%d] open error\n",__FILE__,__LINE__);
return FILE_OP_ERROR;
}
/**这里获取的是磁盘的大小,单位为byte**/
l_s32Ret = GPTDP_Ioctl(l_s32Fd,BLKGETSIZE64,&m_u64SecCount);
if(-1 == l_s32Ret)
{
GPTP_LOG("[%s,%d],l_s32Ret=%d\n",__FILE__,__LINE__,l_s32Ret);
perror("error");
close(l_s32Fd);
return IOCTL_ERROR;
}
if(0 != m_u32SecSize)
{
m_u64SecCount = m_u64SecCount/m_u32SecSize;
}
m_u32SecPerTrac = SECTORS_PER_TRACK;
m_u32HeadNum = DISK_HEAD_NUM;
m_u32SecSize = SECTOR_BYTE_NUM;
GPTP_LOG("[%s,%d] %u,%u,%u,\n",__FILE__,__LINE__,m_u32HeadNum,m_u32SecPerTrac,m_u32SecSize);
GPTP_LOG("[%s,%d] 磁盘总扇区数:%llu\n",__FILE__,__LINE__,m_u64SecCount);
l_s32Ret = GPTDP_WriteMBRHandle(l_s32Fd,&l_stMBRInfo);
if(0 != l_s32Ret)
{
GPTP_LOG("[%s,%d] MBR Write error\n",__FILE__,__LINE__);
close(l_s32Fd);
return l_s32Ret;
}
l_s32Ret = GPTDP_WriteGPTHead(l_s32Fd,&l_stGPTHeadInfo);
if(0 != l_s32Ret)
{
GPTP_LOG("[%s,%d] GPT Head Handle error\n",__FILE__,__LINE__);
close(l_s32Fd);
return l_s32Ret;
}
GPTP_LOG("[%s,%d] %llu\n",__FILE__,__LINE__,l_stGPTHeadInfo.u64GPTHeadBackupPositSec);
l_s32Ret = GPTDP_WritePartTable(l_s32Fd,u8PartCount,&l_stGPTHeadInfo);
if(0 != l_s32Ret)
{
GPTP_LOG("[%s,%d] GPT Table Handle error\n",__FILE__,__LINE__);
close(l_s32Fd);
return l_s32Ret;
}
if(l_s32Fd>0)
{
close(l_s32Fd);
l_s32Fd = -1;
}
}
GPT分区的时候需要注意几点:
1.GPT头结构中的参数,正常头结构和备份头结构的位置信息是有差异的。
2.GPT头结构的校验是不包括它自己本身的,也就是在做GPT头CRC32校验的时候,应该将u32GPTHeadCRC32这个变量赋值为0,否则检验会出错。
文章引用下面文章内容:
FAT32长文件名短文件名目录项_DarrylQuinn-CSDN博客_fat32长文件名
http://www.blogfshare.com/detail-fat32-filesys.html
全是干货:MBR分区结构以及GPT分区结构【图文】_宋国建_51CTO博客
更多推荐
所有评论(0)