65.9K
CodeProject 正在变化。 阅读更多。
Home

分区表详解

starIconstarIconstarIconstarIconstarIcon

5.00/5 (13投票s)

2012 年 11 月 2 日

CPOL

14分钟阅读

viewsIcon

72436

downloadIcon

3809

分区表格式及图形化演示工具

引言

我一直对磁盘如何分区以及分区表的样子感到好奇。本文将解释分区表的格式,并提供一个小型工具(分区查看器)来演示我们解释的内容。

本文信息适用于 x86 系统,我不了解其他系统的磁盘分区。
您无需具备磁盘分区方面的先验知识。本文的目的是提供理解磁盘分区所需的知识,因此许多细节留给读者自行探索。

请注意,本文不包含 GPT(GUID 分区表)。

背景

在本节中,我将介绍一些理解本文所需的概念。

当您购买一块具有给定容量的新硬盘时,您能做的就是从第一个地址到最后一个地址读取/写入原始数据。您可以使用可以读取未格式化/未分区磁盘的特殊工具来实现。您读取/写入的数据没有标准的结构,只有您自己设计的结构。

当我们对磁盘进行分区时,我们只是将磁盘空间划分为分区(逻辑边界)。例如,一个 10GB 的磁盘可以(理论上)划分为任意数量的分区,例如 3GB、4GB 和 3GB 的分区。

[======10 GB============] (分区前)
[(3GB===)(4GB====)(3GB===)] (分区后)

实际上,磁盘分区不仅仅是将磁盘空间划分为更小的分区,还为每个分区附加给定的结构。
这些结构被称为“文件系统”。您可能听说过 FAT 和 NTFS 文件系统(由 Microsoft 操作系统支持)。

文件系统是一种允许您以有组织的方式存储数据(可由主机操作系统管理)的方法。这就是为什么磁盘分区有规则和限制(稍后讨论)。例如,您可以创建一个 10GB 的分区,但不能为其附加 FAT16 文件系统,因为 FAT16 只能管理高达 2GB 的磁盘空间。每种文件系统都有其优缺点,本文档不予讨论。

为了最终确定磁盘分区和文件系统的关系,您可以想象一个原始的、未分区的磁盘可以与一个没有隔间的大房间进行比较,每个员工在这里随意放置物品,但当我们用隔间划分(分区)空间时,我们就有了有组织的办公室和房间(文件系统)。

磁盘寻址和容量限制

在本节中,我们将尝试解释磁盘寻址的概念。

柱面/磁头/扇区 (CHS) 寻址

CHS 代表(C)ylinder/(H)ead/(S)ector 寻址模式。这三个组件共同指定目标磁盘地址。

逻辑块寻址 (LBA)

LBA 是线性寻址模式,从地址 0 开始,直到磁盘中可寻址的最大位置。
与 CHS 寻址相比,LBA 更简单易懂,并且被现代操作系统使用。

MBR 和分区表格式

在本节中,我们将解释 MBR(主引导记录)以及分区表的格式及其在物理磁盘上的位置。

主引导记录 (MBR) 是一个包含引导加载程序和分区表的结构。MBR 始终位于磁盘的最开始处,在 CHS 寻址中是 LBA 0 或 0,0,1。

MBR 结构的大小为 512 字节。

偏移量(十六进制) 大小(字节) 项目
0x0-0x1BD 446 引导加载程序
0x1BE-0x1FD 64 分区表
0x1FE-0x1FF 2 签名(应为 0x55,0xAA)

通常,MBR 的作用是找到哪个分区表是活动的,加载其引导扇区并执行它。

MBR 加载程序可能感染 **MBR 病毒**(有时称为启动程序),该病毒甚至在操作系统启动(或引导扇区执行)之前运行。

引导加载程序

引导加载程序是一个程序,其唯一目的是解释分区表并决定应从哪个分区启动。

引导加载程序可能感染 **引导扇区病毒**,该病毒甚至在操作系统启动之前运行。

以下是引导加载程序通常执行的步骤

  1. 加载分区表。
  2. 遍历其条目,查找标记为活动的哪个分区条目。
  3. 找到活动分区后,加载该分区的相应引导扇区。
  4. 如果没有找到活动分区,则停止。
  5. 找到活动分区并加载其相应的引导扇区后,MBR 会执行 MBR 代码。

引导扇区

在上一节中,我们介绍了“引导扇区”一词,这不应与 MBR 的“引导加载程序”混淆。引导扇区和 MBR 是两件不同的事情。

引导扇区是另一个结构,大小为 512 字节,特定于文件系统。其功能是初始化操作系统并从磁盘加载它。由于 MBR 会加载并执行引导扇区,因此引导扇区的最低要求是

  1. 偏移量 0 应包含有效的 x86 指令,以便当 MBR 执行它时,代码不会导致系统崩溃
  2. 偏移量 0x1FE 应具有签名 0x55 0xAA(类似于 MBR)

对于 MS-DOS,引导扇区程序负责加载 *IO.SYS* 和 *MS-DOS.SYS*,它们又会加载 *COMMAND.COM*。

分区表

分区表长 64 字节,位于 MBR 的扇区 0x1BE 内。

分区表是 4 个分区表条目的数组,每个条目 16 字节,即:16x4 = 64。

每个分区表条目的格式如下

偏移量 大小 项目
0x00 1 引导指示符;0x80 = 活动分区 / 0x00 非活动分区(*boot_indicator*)
0x01 1 分区开始:磁头(*chs_start.head*)
0x02 1 分区开始:扇区(*chs_start.sect*)
0x03 1 分区开始:柱面(*chs_start.cyl*)
0x04 1 分区 ID(例如 ID=1 表示 FAT12)(*system_indicator*)
0x05 1 分区结束:磁头(*chs_end.head*)
0x06 1 分区结束:扇区(*chs_end.sector*)
0x07 1 分区结束:柱面(*chs_end.cyl*)
0x08 4 此分区开始之前的扇区数(*sectors_before*)
0x0C 4 此分区中的扇区数(*number_of_sectors*)

您应该注意,开始和结束 CHS 值并非其存储时的值,而是我们需要从位中提取其值。

实际柱面值 = ((chs.sector >> 6) << 8) | (chs.cyl)。我们从 `chs_sector` 中取出位 6-7,它们是 `real_cyl_value` 的高位,然后与 `chs_cyl`(`real_cyl_value` 的低位)结合。

它们被编码成这种方式的原因是,BIOS INT 0x13/AH=0x02 函数(读取扇区)需要这种编码。

INT 13 - DISK - READ SECTOR(S) INTO MEMORY
	AH = 02h
	AL = number of sectors to read (must be nonzero)
	CH = low eight bits of cylinder number
	CL = sector number 1-63 (bits 0-5)
	     high two bits of cylinder (bits 6-7, hard disk only)
	DH = head number
	DL = drive number (bit 7 set for hard disk)
	ES:BX -> data buffer

`number_of_sectors` 字段描述了这个分区中有多少个扇区。此字段可用于确定分区的长度。类似地,我们可以使用(`CHS_END - CHS_START`)来确定分区的长度。

之前的扇区数(偏移量 8 处)指定了从分区表定义开始,分区数据在哪里开始。如果 MBR 中,一个条目的 `sectors_before` 等于 63,则表示该分区的引导扇区位于扇区 63。

主分区和扩展分区

主分区是 ID 不同于 5 和 15 的分区条目,可以关联文件系统。

与主分区不同,扩展分区具有 ID 5 或 15,不能关联文件系统,而是指向另一个分区表,该表最多包含 **两个分区表** 条目。第二个可以是扩展分区,从而在其内部嵌套更多分区)。扩展分区可以被视为其他分区的容器。接下来我们将演示分区表嵌套。

分区表规则

以下分区表规则摘自其他来源,我只列出最相关的(在本文的上下文中)

  • 一次只能有一个活动分区。
  • 在 MBR 分区表中:最多可以创建 4 个主分区,或者 3 个主分区和 1 个扩展分区。
  • 在扩展分区表中:可以有 0 或 1 个扩展分区链接和 0 或 1 个非扩展分区(总共两个)。
  • 分区表条目可以按任意顺序(我们可以交换条目 1 和 2 等)。

嵌套分区

由于 MBR 中分区表的结构,我们意识到每个分区表最多只能有 4 个分区表条目。为了克服此限制,引入了特殊的分区表条目,允许我们拥有无限数量的链接分区。

在 MBR 中,扩展分区条目描述了其内部包含的所有分区的总大小(使用 `nb_of_sectors` 字段),而 `NbSectorsBefore` 或 `CHS_START` 将用于计算指向下一个分区表的链接,该表最多可以包含 2 个分区表条目。

这两个条目是

  • 一个普通分区条目
  • 另一个指向下一个链接分区的扩展分区条目

使用十六进制编辑器手动解释分区表

在本节中,我们将演示如何使用可以显示磁盘扇区的十六进制编辑器手动解释分区表。

此屏幕截图显示了磁盘的第一个扇区。黄色标记的字节是引导加载程序代码。红色标记的字节是 MBR 的签名,应始终为 0x55 0xAA。

绿色区域显示了一个完整的(16 字节)分区表条目

  • 00:引导指示符 -> 非活动
  • 01 01 00:`CHS_START` -> 磁头 = 1,扇区 = 1,柱面 = 0
  • 06:系统指示符 -> FAT16B (>= 32 MB)
  • FE 3F 0B:`CHS_END` -> 磁头=254,扇区=63,柱面=11
  • 3F 00 00 00:之前的扇区 -> 63
  • CD F0 02 00:扇区数 -> 192717

这意味着这是一个大约 96MB 的 FAT16 分区。同样,我们可以解释表的结果并将其读取为

条目 # 引导指示符 CHS_START 系统 ID CHS_END 之前的扇区 扇区数
1 0 0,1,1 6:FAT16B (>= 32 MB) 11,254,63 63 192717
2 0 166,0,1 15:Win95 扩展 (LBA) 12543,254,63 2666790 26748225
3 0 13,0,1 23:隐藏的 IFS (HPFS/NTFS) 154,254,63 208845 2281230
4 0 12543,0,1 28:隐藏的 Win95 FAT32 (LBA) 12543,254,63 29415015 4128705

请注意,条目 #2 是一个扩展分区(sysid = 15),大小为:(26748225 * 512) = 13695091200 字节 = 13060 GB。
此分区从扇区 2666790 (`sectors_before`) 开始,让我们去那里看看它指向的分区表

条目# 引导指示符 CHS_START 系统 ID CHS_END 之前的扇区 扇区数
1 0 166,1,1 11:Win95 FAT32 178,254,63 63 208782
2 0 184,0,1 5:扩展 209,254,63 289170 417690

正如我们所说,现在从初始扩展分区表条目指向的每个分区表最多有两个条目。第一个条目是普通条目,第二个条目(类型 = 扩展)是另一个分区表的链接。要计算第二个条目的 LBA,我们将 MBR 中扩展分区表条目的“之前的扇区”值添加到“之前的扇区”值中,即:2666790+289170 = 扇区 2955960。

现在我们去那里读取分区表

条目# 引导指示符 CHS_START 系统 ID CHS_END 之前的扇区 扇区数
1 0 184,1,1 6:FAT16B (>= 32 MB) 209,254,63 63 417627
2 0 240,0,1 5:扩展 255,254,255 1188810 17462655

下一个分区表位于:2666790+1188810 = 扇区 3855600。

条目# 引导指示符 CHS_START 系统 ID CHS_END 之前的扇区 扇区数
1 0 240,1,1 7:可安装文件系统 (NTFS, HPFS) 255,254,255 63 17462592
2 0 255,0,193 5:扩展 255,254,255 19069155 3919860

下一个分区表位于:2666790+19069155 = 扇区 21735945。

条目# 引导指示符 CHS_START 系统 ID CHS_END 之前的扇区 扇区数
1 0 255,1,193 6:FAT16B (>= 32 MB) 255,254,255 63 3919797
2 0 255,0,193 5:扩展 255,254,255 23246055 433755

下一个分区表位于:2666790+23246055 = 扇区 25912845。

条目# 引导指示符 CHS_START 系统 ID CHS_END 之前的扇区 扇区数
1 0 255,1,193 130:Linux 交换 / Solaris 255,254,255 63 433692
2 0 255,0,193 5:扩展 255,254,255 23679810 3068415

下一个分区表位于:2666790+23679810 = 扇区 26346600。

条目# 引导指示符 CHS_START 系统 ID CHS_END 之前的扇区 扇区数
1 0 255,1,193 11:Win95 FAT32 255,254,255 63 3068352
0 0 0,0,0 0 0,0,0 0 0

没有下一个条目;分区嵌套结束。

一些分区表系统 ID

下表列出了一些已知的系统 ID(或文件系统 ID)。

ID 名称
0x00 Empty
0x01 FAT12
0x02 XENIX root
0x03 XENIX usr
0x04 FAT16 <32MB
0x05 扩展
0x06 FAT16B (>= 32 MB)
0x07 可安装文件系统 (NTFS HPFS)
0x08 AIX
0x09 AIX 可启动
0x0A OS/2 引导管理器
0x0B Win95 FAT32
0x0C Win95 FAT32 (LBA)
0x0E Win95 FAT16 (LBA)
0x0F Win95 扩展 (LBA)
0x10 OPUS
0x11 隐藏的 FAT12
0x12 Compaq diagnostic
0x14 隐藏的 FAT16 <32MB
0x16 隐藏的 FAT16
0x17 隐藏的 IFS (HPFS/NTFS)
0x18 AST SmartSleep
0x1B 隐藏的 Win95 FAT32
0x1C 隐藏的 Win95 FAT32 (LBA)
0x1E 隐藏的 Win95 FAT16 (LBA)
0x24 NEC DOS
0x2C WildFile/Adaptec GOBack
0x39 计划 9
0x3C PowerQuest 可恢复分区
0x40 Venix 80286
0x41 PPC PReP 引导
0x42 Veritas 逻辑磁盘管理器
0x4d QNX4.x
0x4e QNX4.x 2nd part
0x4f QNX4.x 3rd part
0x50 OnTrack DM
0x51 OnTrack DM6 Aux1
0x52 CP/M
0x53 OnTrack DM6 Aux3
0x54 OnTrackDM6
0x55 EZ-Drive
0x56 Golden Bow
0x5c Priam Edisk
0x61 SpeedStor
0x63 GNU HURD 或 SysV
0x64 Novell Netware 286
0x65 Novell Netware (3.11 和 4.1)
0x66 Novell Netware 386
0x70 DiskSecure Multi-Boot
0x75 PC/IX
0x78 XOSL
0x80 Old Minix
0x81 Linux/Minix v1.4b+
0x82 Linux 交换 / Solaris
0x83 Linux 原生文件系统 (Ext2/3)
0x84 OS/2 隐藏类型 04h 分区
0x85 Linux 扩展
0x86 NT FAT 卷集
0x87 NT IFS 卷集
0x8e Linux LVM
0x93 Amoeba/隐藏 Linux 原生文件系统 (Ext2/3)
0x94 Amoeba BBT
0x9f BSD/OS
0xA0 IBM Thinkpad 휴면
0xA5 FreeBSD
0xA6 OpenBSD
0xA7 NeXTSTEP
0xA9 NetBSD
0xB7 BSDI fs
0xb8 BSDI swap
0xbb Boot Wizard 隐藏
0xc1 DRDOS / sec (FAT-12)
0xc4 DRDOS / sec (FAT-16 < 32M)
0xc6 禁用 NT FAT (FAT-16) 卷集/DRDOS
0xc7 Syrinx / 禁用 NT IFS 卷集
0xda 非 FS 数据
0xdb CP/M / CTOS / ...
0xde Dell Corporation 诊断分区
0xdf BootIt
0xe1 DOS 访问
0xe3 DOS R/O
0xe4 SpeedStor
0xeb BeOS fs
0xee EFI GPT
0xef EFI (FAT-12/16/32)
0xf0 Linux/PA-RISC 引导
0xf1 SpeedStor
0xf4 SpeedStor
0xf2 DOS secondary
0xfd Linux raid autodetect
0xfe LANstep
0xff 坏道表

分区查看器工具

为了演示,我编写了一个附带以下组件的工具

  • *DiskSector.cpp*/.h - 用于读写原始磁盘扇区的类
  • *partitionmanager.cpp*/.h - 用于解析分区表的类
  • *MyDrawBar.cpp*/.h - 用于绘制分区表的 MFC 静态组件
  • *MyHistory.cpp*/.h - 用于绘制分区表的 MFC 静态组件
  • *PartitionViewer[Dlg].cpp*/.h - 使用上述辅助类的 UI

`PartitionViewer` 工具仅硬编码了一小部分系统 ID 和颜色

static const MYHISTORYBARTYPECOLOR part_colors[] = 
{
  {0x0,  RGB(255,255,255), "Free space"},
  {0x6,  RGB(100,10,0), "FAT16B (>= 32 MB)"},
  {0xC,  RGB(255,0,128), "Win95 FAT32 (LBA)"},
  {0xE,  RGB(0,110,110), "Win95 FAT16 (LBA)"},
  {0x7,  RGB(200,0,20), "Installable File System (NTFS, HPFS)"},
  {0x0B, RGB(10,100,0), "Win95 FAT32"},
  {0x83, RGB(20,200,0), "Linux native file system (Ext2/3)"},
  {0x17, RGB(10,0,100), "Hidden IFS (HPFS/NTFS)"},
  {0x82, RGB(101, 12, 130), "Linux swap / Solaris"},
  {0x1C, RGB(90, 127, 30), "Hidden Win95 FAT32 (LBA)"},
  {0x1E, RGB(0, 0, 255), "Hidden Win95 FAT16 (LBA)"},
  {0x04, RGB(101, 12, 130), "FAT16 <32MB"}
};

欢迎您扩展此列表。

此程序需要管理员权限才能运行,因为它会访问磁盘扇区。

执行后

分区将被可视化

  • 使用下拉列表选择另一个驱动器,然后按“**表示**”按钮。
  • 将鼠标悬停在绘制的区域上,即可在驱动器下拉列表下方的面板中显示分区信息。

结论

希望您觉得这篇文章有用。将来,可以写另一篇文章来介绍 GPT。请在下方留下您的评论或建议,我将尽力在我(有限的)时间和知识范围内回答问题或修复代码。

参考文献

我想感谢所有撰写了使本文成为可能的文章、开源程序和参考资料的人。

历史

  • 2012 年 11 月 2 日:初始版本
© . All rights reserved.