日期:2014-05-16  浏览次数:20832 次

Windows上面读磁盘分区表

1. 概述

在 GPT分区表 一文中,讲解了MBR分区表的一些概念。本文进一步给出了Windows系统上读取MBR的示例代码,以及MBR的具体数据,可进一步加深对MBR的理解。


在参考网上一些文章&代码的基础上,本文给出了下面的展示MBR的示例代码;同时最后针对几个典型问题,给出了一些解释和参考文档。


2. 代码

下面是代码:

/**
 * ref: http://noyesno.net/page/it/20100701-172
 * 
 */
#include <stdio.h>
#include <windows.h>

struct CHS {
    unsigned int header;
    unsigned int sector; 
    unsigned int cylinder;
};

struct partition_record {
    unsigned char boot_indicator;
    unsigned char os_type;
    struct CHS starting_chs;
    struct CHS ending_chs;
    unsigned int starting_LBA;
    unsigned int size_in_LBA;
};

void dump_partition_record(const partition_record& record) {
    const double DISK_SECTOR_SIZE = 512.0;
    const size_t GB = 1024 * 1024 * 1024;

    printf(
        "\tboot indicator: 0x%02x\n"
        "\tOS Type: 0x%02x\n"
        "\tStarting CHS: (%d, %d, %d)\n"
        "\tEnding_CHS: (%d, %d, %d)\n"
        "\tSize in LBA: %d\n"
        "\tSize:%.2f\n\n",
        record.boot_indicator, 
        record.os_type, 
        record.starting_chs.cylinder,
        record.starting_chs.header,
        record.starting_chs.sector,
        record.ending_chs.cylinder,
        record.ending_chs.header,
        record.ending_chs.sector,
        record.size_in_LBA,
        record.size_in_LBA * DISK_SECTOR_SIZE / GB);
}

// transform the 16-bytes buffer to partition record
void get_partition_record(unsigned char buffer[], partition_record& record) {
    record.boot_indicator = buffer[0];

    record.starting_chs.header = buffer[1];
    record.starting_chs.sector = buffer[2] & 0x3f;
    record.starting_chs.cylinder = (((buffer[2] & 0xff) >> 6) << 8) + buffer[3];

    record.os_type = buffer[4];

    record.ending_chs.header = buffer[5];
    record.ending_chs.sector = buffer[6] & 0x3f;
    record.ending_chs.cylinder = (((buffer[6] & 0xff) >> 6) << 8) + buffer[7];

    record.size_in_LBA = *(unsigned int*)(buffer + 12);
}

void read_mbr(const char *devname){
  HANDLE hDevice = CreateFile(devname, GENERIC_READ,   
                  FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);  
  if (hDevice == INVALID_HANDLE_VALUE){  
      printf("Open %s failed, the error code is %d.\n", devname, GetLastError());  
      return;  
  }

  DWORD dwRead = 0;  
  const size_t DISK_SECTOR_SIZE = 512;
  unsigned char buffer[DISK_SECTOR_SIZE];  

  BOOL bSuccess = ReadFile(hDevice, buffer, DISK_SECTOR_SIZE, &dwRead, NULL);  
  CloseHandle(hDevice);

  if ( !bSuccess || DISK_SECTOR_SIZE != dwRead)  {  
     printf("Error: read error! Read size = %d\n",  dwRead);  
     return; 
  }  

  size_t i, j;
  printf("%10s 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F \n", " ");  
  for (i = 0; i < 32; i++) {  
      printf("%.8XH: ", i);  
      for (j = 0; j < 16; j++) {
          printf("%.2X ", buffer[i * 16 + j] & 0xFF);  
      }
      printf("\n");  
  }

  printf("====MBR Partition Entries====\n");
  partition_record record = {0};
  for(i = 0x01be; i < 0x01FE; i += 16){
      get_partition_record(buffer + i, record);
      dump_partition_record(record);
  }
}

int main(int argc, char *argv[]){
    const char* LOG_FILE = "./log.txt";
    freopen(LOG_FILE, "a", stdout); 
    setbuf(stdout, NULL);

    read_mbr("\\\\.\\PhysicalDrive0");

    return 0;
}

运行结果如下:

           0  1  2  3  4  5  6  7  8  9