You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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;
}

关键修正点

  1. 读取逻辑修正:只读取第一块硬盘的MBR(0柱面0磁头1扇区),这是分区表的唯一存储位置。
  2. 分区表位置修正:分区表在MBR的0x1BE偏移处,原代码错误地将读取内容写入buf的前64字节,覆盖了正确的分区表区域。
  3. 有效分区判断:原get_count_partitions()直接计数4个项,现在判断系统代码是否为0,只统计有效分区。
  4. CHS参数解析:原代码直接输出beginSecCyl的原始值,现在正确解析出扇区和柱面的实际数值(扇区是低6位,柱面是高2位+下一字节)。
  5. 错误处理优化:增加错误码输出,方便排查读取失败原因。

内容的提问来源于stack exchange,提问作者Влад

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:04:50