如何在Windows 98下用Turbo C正确读取硬盘分区信息
硬盘MBR分区信息读取问题修正(Borland C++/Windows 98环境)
我需要读取硬盘全部4个分区并显示信息,目前输出功能正常,但读取分区的逻辑存在问题。不清楚该修改磁头(head)、柱面(cylinder)还是扇区(sector)参数,修改这些值后都能读到数据,但无法确认是否正确读取了所有内容。程序基于Borland C++(TurboC)编写,运行环境为Windows 98。
分区表项格式(每个项16字节)
Offset Length Contents +0 1 引导标志:0=非活动,0x80=活动 +1 1 起始磁头号 +2 2 起始扇区/柱面(低6位是扇区,高10位是柱面) +4 1 文件系统代码 +5 1 结束磁头号 +6 2 结束扇区/柱面(低6位是扇区,高10位是柱面) +8 4 分区起始扇区号(LBA) +0Ch 4 分区总扇区数
原程序代码
#include <dos.h> #include <stdio.h> #include <conio.h> //#define NUM_PARTITIONS 4 unsigned char buf[512]; int read_mbr() { union REGS in, out; struct SREGS sr; int i = 0; int j = 0; for (; i < 64; i += 16, j++) { sr.es = FP_SEG(buf + i); in.x.bx = FP_OFF(buf + i); in.h.ah = 0x02; in.h.al = 1; in.h.dl = 0x80 + j; in.h.dh = 0; in.h.cl = 1; in.h.ch = 0; int86x(0x13, &in, &out, &sr); if (out.x.cflag || out.h.ah) return 1; printf("%d", j); } return 0; } int get_count_partitions() { int numPartitions = 0; int i = 0x1BE; for (; i <= 0x1EE; i += 16) { numPartitions++; } return numPartitions; } void extract_partition_info(int partition_number) { unsigned char beginHd = buf[1]; unsigned short beginSecCyl = *((unsigned short*)(buf + 2)); // Print the extracted partition information printf("Partition %d:\n", partition_number); printf("Begin Hd: %u\n", beginHd); printf("Begin Sec/Cyl: %u\n", beginSecCyl); } void print_partition_info(unsigned char* partition_entry, int partition_number) { unsigned char bootFlag = partition_entry[0]; unsigned char beginHd = partition_entry[1]; unsigned short beginSecCyl = *((unsigned short*)(partition_entry + 2)); unsigned char systemCode = partition_entry[4]; unsigned char endingHd = partition_entry[5]; unsigned short endingSecCyl = *((unsigned short*)(partition_entry + 6)); unsigned int startingSector = *((unsigned int*)(partition_entry + 8)); unsigned int numSectors = *((unsigned int*)(partition_entry + 0x0C)); printf("Partition %d:\n", partition_number); printf("Boot Flag: 0x%02X\n", bootFlag); printf("Begin Hd: %u\n", beginHd); printf("Begin Sec/Cyl: %u\n", beginSecCyl); printf("System Code: 0x%02X\n", systemCode); printf("Ending Hd: %u\n", endingHd); printf("Ending Sec/Cyl: %u\n", endingSecCyl); printf("Starting Sector (LBA): %u\n", startingSector); printf("Number of Sectors: %u\n", numSectors); printf("Root Boot Sector Address (LBA): %u\n", startingSector); } int main() { int i = 0; int j = 0; clrscr(); if (read_mbr()) printf("Error reading sector\n"); else printf("Sector read successfully\n"); printf("Number of sections: %d\n", get_count_partitions()); extract_partition_info(1); getch(); clrscr(); for(;j < 512; j++) printf("%d",(int)buf[j]); getch(); for (; i < 64; i += 16){ clrscr(); print_partition_info(&buf[i], (i/16 + 1)); getch(); } return 0; }
问题分析
原read_mbr()函数逻辑完全错误:
- 循环中
j从0到3,每次把dl设为0x80+j,这是读取第j+1块物理硬盘的MBR,而不是同一硬盘的4个分区。 - 分区表就在第一块硬盘的MBR(0柱面0磁头1扇区)的0x1BE到0x1FF位置,不需要读取4个不同的扇区,只需要读取一次MBR即可获取全部4个分区表项。
- 原函数把读取到的内容写入
buf的0-15、16-31、32-47、48-63位置,完全覆盖了后续要处理的分区表区域(正确分区表在buf的0x1BE=446开始)。
修正后的代码
#include <dos.h> #include <stdio.h> #include <conio.h> #define NUM_PARTITIONS 4 #define MBR_OFFSET 0x1BE // 分区表在MBR中的起始偏移 unsigned char buf[512]; int read_mbr() { union REGS in, out; struct SREGS sr; // 设置读取参数:读取第一块硬盘(dl=0x80)的0柱面0磁头1扇区,1个扇区 sr.es = FP_SEG(buf); in.x.bx = FP_OFF(buf); in.h.ah = 0x02; // INT13H功能号:读取扇区 in.h.al = 1; // 读取扇区数量 in.h.dl = 0x80; // 第一块物理硬盘(0x80=主盘,0x81=从盘) in.h.dh = 0; // 磁头0 in.h.cl = 1; // 扇区1(低6位),柱面高2位在cl的高2位(这里柱面0,所以高2位为0) in.h.ch = 0; // 柱面低8位 int86x(0x13, &in, &out, &sr); // 检查错误:CF置位或AH返回非0值表示读取失败 if (out.x.cflag || out.h.ah != 0) { printf("读取错误,错误码:0x%02X\n", out.h.ah); return 1; } return 0; } int get_count_partitions() { int numPartitions = 0; // 遍历MBR中的4个分区表项(从0x1BE到0x1BE+16*3=0x1EE) for (int i = MBR_OFFSET; i <= MBR_OFFSET + 16*(NUM_PARTITIONS-1); i += 16) { // 只有系统代码不为0的项才是有效分区 if (buf[i+4] != 0) { numPartitions++; } } return numPartitions; } void print_partition_info(unsigned char* partition_entry, int partition_number) { unsigned char bootFlag = partition_entry[0]; unsigned char beginHd = partition_entry[1]; // 解析起始扇区和柱面:cl低6位是扇区,高2位+ch是柱面 unsigned char beginSec = partition_entry[2] & 0x3F; unsigned int beginCyl = ((partition_entry[2] >> 6) & 0x03) | (partition_entry[3] << 2); unsigned char systemCode = partition_entry[4]; unsigned char endingHd = partition_entry[5]; unsigned char endSec = partition_entry[6] & 0x3F; unsigned int endCyl = ((partition_entry[6] >> 6) & 0x03) | (partition_entry[7] << 2); // LBA地址是小端模式,直接读取即可 unsigned int startingSector = *((unsigned int*)(partition_entry + 8)); unsigned int numSectors = *((unsigned int*)(partition_entry + 0x0C)); printf("=== 分区 %d 信息 ===\n", partition_number); printf("引导标志: %s (0x%02X)\n", (bootFlag == 0x80) ? "活动" : "非活动", bootFlag); printf("起始磁头: %u\n", beginHd); printf("起始柱面: %u\n", beginCyl); printf("起始扇区: %u\n", beginSec); printf("文件系统代码: 0x%02X\n", systemCode); printf("结束磁头: %u\n", endingHd); printf("结束柱面: %u\n", endCyl); printf("结束扇区: %u\n", endSec); printf("起始扇区(LBA): %u\n", startingSector); printf("分区总扇区数: %u\n", numSectors); printf("分区大小(约): %.2f MB\n", (float)numSectors * 512 / 1024 / 1024); } int main() { clrscr(); if (read_mbr()) { printf("读取MBR失败!\n"); getch(); return 1; } printf("MBR读取成功!\n"); printf("有效分区数量: %d\n\n", get_count_partitions()); getch(); clrscr(); // 遍历4个分区表项 for (int i = 0; i < NUM_PARTITIONS; i++) { unsigned char* entry = &buf[MBR_OFFSET + i*16]; // 跳过系统代码为0的空项 if (entry[4] == 0) continue; print_partition_info(entry, i+1); printf("\n按任意键查看下一个分区...\n"); getch(); clrscr(); } printf("所有分区信息已显示完毕!\n"); getch(); return 0; }
关键修正点
- 读取逻辑修正:只读取第一块硬盘的MBR(0柱面0磁头1扇区),这是分区表的唯一存储位置。
- 分区表位置修正:分区表在MBR的0x1BE偏移处,原代码错误地将读取内容写入buf的前64字节,覆盖了正确的分区表区域。
- 有效分区判断:原
get_count_partitions()直接计数4个项,现在判断系统代码是否为0,只统计有效分区。 - CHS参数解析:原代码直接输出
beginSecCyl的原始值,现在正确解析出扇区和柱面的实际数值(扇区是低6位,柱面是高2位+下一字节)。 - 错误处理优化:增加错误码输出,方便排查读取失败原因。
内容的提问来源于stack exchange,提问作者Влад
相关产品推荐
相关产品推荐

