C语言读取磁盘分区信息(MBR、DPT、EBR)
文章目录
- 简介
- 使用的函数
- 1.CreateFile()函数打开设备
- 2.DeviceIoControl()函数返回磁盘设备信息
- 3.SetFilePointer()函数设置读取磁盘信息位置
- 4.ReadFile()函数读取磁盘内容
- 源代码
- 结果分析
- MBR部分:
- 第一个EBR的DPT内容为:
- 第2个EBR内容
- 总结
简介
在win8以后,磁盘格式一般是GPT格式的,做实验是在winXP虚拟机上完成的,partition style是MBR。在虚拟机上分配了40GB的硬盘空间。三个主分区盘C、E、F,一个扩展分区里面有三个逻辑盘G、H、I。
使用的函数
1.CreateFile()函数打开设备
HANDLE CreateFile(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
- 第1个参数lpFileName为要创建或打开的文件或设备的名称。磁盘为TEXT("\\.\PhysicalDrive0"),如果有两个盘,第2个为1。
- 第2个参数dwDesiredAccess为请求访问文件或设备,常取值为GENERIC_READ, GENERIC_WRITE或两者(GENERIC_READ | GENERIC_WRITE)
- 第3个参数为dwShareMode,是请求的文件或设备共享模式,可以是读取,写入,两者,删除
- 第4个参数为lpSecurityAttributes,是指向SECURITY_ATTRIBUTES 结构的指针,如果此参数为NULL,则CreateFile返回的句柄不能由应用程序可能创建的任何子进程继承,使用默认安全属性。
- 第5个参数dwCreationDisposition,对存在或不存在的文件或设备执行的操作。对于文件以外的设备,此参数通常设置为OPEN_EXISTING。
- 第6个参数为dwFlagsAndAttributes,是文件或设备属性和标志。
- 第7个参数为hTemplateFile,具有GENERIC_READ访问权限的模板文件的有效句柄。此参数可以为NULL。
- 返回值:如果函数成功,则返回值是指定文件,设备,命名管道或邮件槽的打开句柄。如果函数失败,则返回值为INVALID_HANDLE_VALUE。获取错误码,可以调用GetLastError()函数。
2.DeviceIoControl()函数返回磁盘设备信息
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
- 第1个参数为hDevice,是要对其执行操作的设备的句柄,本实验中是CreateFile()函数的返回的设备句柄。
- 第2个参数dwIoControlCode,是操作的控制代码,该值标识要执行的特定操作以及执行它的设备类型。使用IOCTL_DISK_GET_DRIVE_GEOMETRY,用于获取磁盘信息。
- 第3个参数为lpInBuffer,是指向输入缓冲区的指针,可以为NULL。
- 第4个参数为nInBufferSize,是输入缓冲区大小,以字节为单位。
- 第5个参数为lpOutBuffer,指向输出缓冲区的指针,用于接收操作返回的数据。
- 第6个参数为nOutBufferSize,是输出缓冲区的大小,以字节为单位。
- 第7个参数为lpBytesReturned,是一个指向变量的指针,该变量接收存储在输出缓冲区中的数据大小(以字节为单位)。如果输出缓冲区太小而无法接收任何数据,则调用失败, GetLastError()返回 ERROR_INSUFFICIENT_BUFFER,并且lpBytesReturned为零。
- 第8个参数为lpOverlapped,指向OVERLAPPED结构的指针。如果在未指定FILE_FLAG_OVERLAPPED的情况下打开 hDevice,则忽略lpOverlapped。
- 返回值:如果操作成功完成,则返回值为非零值。
3.SetFilePointer()函数设置读取磁盘信息位置
DWORD SetFilePointer(
HANDLE hFile,
LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod
);
- 第1个参数hFile是文件的句柄。
- 第2个参数为lDistanceToMove,是表示距离的有符号数的低32位,用来指定文件指针的字节偏移。
- 第3个参数lpDistanceToMoveHigh,是距离的高32位。
- 第4个参数dwMoveMethod是文件指针移动的起点。
4.ReadFile()函数读取磁盘内容
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
- 第1个参数hFile,是文件/设备句柄。
- 第2个参数lpBuffer,是指向缓冲区的指针,用于接收读取的数据。
- 第3个参数nNumberOfBytesToRead,是要读取的最大字节数。
- 第4个参数lpNumberOfBytesRead,用于接收读取的字节数。
- 第5个参数lpOverlapped可以为NULL。
源代码
#include <windows.h>
#include <winioctl.h> //DDK驱动开发与控制
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#define BufferLength 1024//将四个连续字节存放的值转为int型
uint32_t transtoint(unsigned char a[])
{uint32_t sum = 0UL;uint32_t temp = 0UL;for (int i = 3; i>=0; i--){temp = a[i];//先赋值 temp = temp <<( 8 * (3-i)); sum = sum | temp;}return sum;
}
//十六进制输出
bool HexOutput(char* buf, size_t len,bool ismbr, ULONGLONG * baseaddr,ULONGLONG * nextaddr,int EBRnum)
{bool mbrflag=1;//在读取MBR的时候判断条目是主分区还是扩展分区条目 unsigned char a = buf[0];if(ismbr)printf("-----------------------------------------------------");elseprintf("--------------------------第%d个EBR------------------",EBRnum);//printf("第一字节是:%x\n\n", a);if(ismbr)printf(" 第一部分(MBR):\n\n");elseprintf(" 第一部分(EBR):\n\n");int flag = 0;for (size_t i = 0; i < len; ++i){unsigned char c = buf[i]; // must use unsigned char to print >128 value flag++;if (c < 16)printf("0%x ", c);elseprintf("%x ", c);if (i == 445){flag = 0;printf("\n\n 第二部分(分区表):\n");}if (i == 509){flag = 0;printf("\n\n 第三部分(结束标志):\n");}if ((flag) % 16 == 0)printf("\n");}printf("\n<-------------------分区表信息解析------------------->\n\n");printf("\n\n分区地址和大小分别为: \n\n"); int limit=ismbr?509:477;//如果已经知道是扩展分区的EBR,不用读取那么多,rank=1是分区表,rank=2是指向下一个的for (int m = 445, rank = 1; m < limit&&rank<=4; m += 16, rank++){unsigned char fifth = buf[m + 5];//取得第五位文件系统标志位,十六进制为05H或者0FH是扩展分区 if(fifth==0x5||fifth==0xf)//是扩展分区条目,不用往后读了 {printf("This is an extend patition!\n");mbrflag=0; rank = 4;}//不是mbr是扩展分区EBR if (fifth < 16) //调整输出格式printf("第%d分区表标志位为: 0%x\n", rank, fifth);elseprintf("第%d分区表标志位为: %x\n", rank, fifth);if (fifth == 0x00)//当第五位(标志位)是00时,代表分区表信息为空,无分区{printf(" 分区表为空\n\n");//也不用往后读了 }else {//分区项 unsigned char offsetadd[4] = { 0 };//倒着读,高字节在高地址处for (int n = m + 12, t = 0; n > m + 8, t < 4; n--, t++){unsigned char temp = buf[n];if (temp < 16)printf(" 0%x ", temp);elseprintf(" %x ", temp);offsetadd[t] = buf[n];}//计算地址,转换为十进制扇区数LBAprintf("\n");uint32_t tempadd = transtoint(offsetadd);printf("\n开始地址为: %I64x", (ULONGLONG)tempadd * (ULONGLONG)512 + *baseaddr);if(ismbr&&!mbrflag)// if in mbr and got a extend entry,the EBR at relsecor+nowbase(0){*baseaddr=(ULONGLONG)tempadd* (ULONGLONG)512 + *baseaddr;//only change once*nextaddr = (ULONGLONG)0UL;} else if (!mbrflag)//if it's the extend entry{*nextaddr = (ULONGLONG)tempadd * (ULONGLONG)512;}printf("\n\n");printf("大小:");for (int p = m + 16, w = 0; p > m + 12, w < 4; p--, w++){unsigned char temp1 = buf[p];if (temp1 < 16)printf(" 0%x ", temp1);elseprintf(" %x ", temp1);offsetadd[w] = buf[p];}//计算大小,转化为GB单位printf("\n");uint32_t tempsize = transtoint(offsetadd);if(ismbr && !mbrflag)printf("\n扩展盘总大小为: %lu 扇区 = %lf GB \n", tempsize, ((double)tempsize / 2.0 / 1024.0 / 1024.0));else if(!ismbr){printf("\n第%d逻辑盘大小为: %lu 扇区 = %lf GB \n",EBRnum, tempsize, ((double)tempsize / 2.0 / 1024.0 / 1024.0));}elseprintf("\n该盘大小为: %lu 扇区 = %lf GB \n", tempsize, ((double)tempsize / 2.0 / 1024.0 / 1024.0));}}printf("\n\n");return (mbrflag);
}//函数:对主分区表进行解析,分别得到每个分区的偏移地址以及分区大小
BOOL GetDriveGeometry(DISK_GEOMETRY *pdg, int addr)
{HANDLE hDevice; // 设备句柄BOOL bResult; // results flagDWORD junk; // discard resultsccchar lpBuffer[BufferLength] = { 0 };//通过CreateFile来获得设备的句柄hDevice = CreateFile(TEXT("\\\\.\\PhysicalDrive0"), // 设备名称,这里指第一块硬盘GENERIC_READ, // no access to the driveFILE_SHARE_READ | FILE_SHARE_WRITE, // share modeNULL, // default security attributesOPEN_EXISTING, // disposition0, // file attributesNULL); // do not copy file attributesif (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive{printf("Creatfile error!May be no permission!ERROR_ACCESS_DENIED!\n");return (FALSE);}//通过DeviceIoControl函数与设备进行IObResult = DeviceIoControl(hDevice, // 设备的句柄IOCTL_DISK_GET_DRIVE_GEOMETRY, // 控制码,指明设备的类型NULL, 0, // no input bufferpdg,sizeof(*pdg), &junk, // # bytes returned(LPOVERLAPPED)NULL); // synchronous I/OLARGE_INTEGER offset;//long long signedoffset.QuadPart = (ULONGLONG)addr * (ULONGLONG)512;//0SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);//从0开始读MBRif(GetLastError())printf("错误类型代号:%ld\n\n", GetLastError());//如果出错了DWORD dwCB;//从这个位置开始读 BOOL bRet = ReadFile(hDevice, lpBuffer, 512, &dwCB, NULL);//如果不是MBR,bool finished=0; int EBRnum=0;ULONGLONG *baseaddr=new ULONGLONG,*nextaddr= new ULONGLONG;//扩展分区起始地址,EBR地址 *baseaddr = (ULONGLONG)0;*nextaddr = (ULONGLONG)0;finished=HexOutput(lpBuffer, 512,true,baseaddr,nextaddr,EBRnum);//先是读取MBRif(finished)CloseHandle(hDevice);else{//继续读do{EBRnum++;memset(lpBuffer, 0, sizeof(lpBuffer));offset.QuadPart = (ULONGLONG)(*baseaddr + *nextaddr);//find the EBRSetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);//读EBRif(GetLastError())printf("错误类型代号:%ld\n\n", GetLastError());//如果出错了ReadFile(hDevice, lpBuffer, 512, &dwCB, NULL);}while(!HexOutput(lpBuffer, 512,false,baseaddr,nextaddr,EBRnum));CloseHandle(hDevice);}delete baseaddr;delete nextaddr;return bResult;
}
extern int add[20];
extern int disknum;
int main()
{DISK_GEOMETRY pdg; // 保存磁盘参数的结构体BOOL bResult; // generic results flagULONGLONG DiskSize; // size of the drive, in bytesprintf("<-----------------欢迎使用分区读取程序----------------->\n\n");bResult = GetDriveGeometry(&pdg, 0);if (bResult){DiskSize = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *(ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;printf("磁盘总大小 = %I64d (Bytes) = %I64d (Gb)\n", DiskSize, DiskSize / (1024 * 1024 * 1024));}else{printf("GetDriveGeometry failed. Error %ld.\n", GetLastError());}return ((int)bResult);
}
结果分析
运行程序解析磁盘信息的结果,与使用Winhex查看计算是一致的。
MBR部分:
分区地址和大小分别为:
第1分区表标志位为: 07
00 00 00 3f
开始地址为: 7e00
大小: 02 7f 8c b2
该盘大小为: 41913522 扇区 = 19.985925 GB第2分区表标志位为: 07
02 7f 8c f1
开始地址为: 4ff19e200
大小: 00 3f fa c5
该盘大小为: 4192965 扇区 = 1.999362 GB第3分区表标志位为: 07
02 bf 87 b6
开始地址为: 57f0f6c00
大小: 00 3f fa c5
该盘大小为: 4192965 扇区 = 1.999362 GBThis is an extend patition!
第4分区表标志位为: 0f
02 ff 82 7b
开始地址为: 5ff04f600
大小: 02 00 53 aa
扩展盘总大小为: 33575850 扇区 = 16.010213 GB
查看C盘信息,开始地址7E00,20G:
查看E盘信息,开始抵制4FF19E200,大小2G:
查看F盘信息,开始地址57F0F6C00,大小2G:
查看第4个DPT对应的扩展分区的EBR,扩展分区的EBR所在地址位5FF04F600:
第一个EBR的DPT内容为:
第一个条目地址信息中3F 00 00 00是63,指向第一个逻辑盘。计算这个逻辑盘开始地址为63*512=7E00H,加上5FF04F600H得到5FF057400H,这就是G盘的起始位置。G盘的大小信息为0E 12 A0 00,也就是10490382个扇区,10490382*512/1024/1024/1024=5GB。
第2个条目是第5个字节内容是05H,表示是扩展分区。(之前MBR中的第4个扇区第5字节是0FH,也表示这是一个扩展分区)。扩展分区的地址信息为A0124DH,也就是相对于扩展分区开始位置5FF04F600H起的第10490445个扇区(换成字节是140249A00H)处存放着下一个扩展分区的MBR。这个位置是140249A00H+5FF04F600H =73F299000H。在这个位置,的确放着下一逻辑盘,也就是H盘的EBR。用同样方式可以计算。
第1分区表标志位为: 07
00 00 00 3f
开始地址为: 5ff057400
大小: 00 a0 12 0e
第1逻辑盘大小为: 10490382 扇区 = 5.002204 GBThis is an extend patition!
第2分区表标志位为: 05
00 a0 12 4d
开始地址为: 73f299000
大小: 00 a0 12 4d
第1逻辑盘大小为: 10490445 扇区 = 5.002234 GB
第2个EBR内容
分区地址和大小分别为:
第1分区表标志位为: 07
00 00 00 3f
开始地址为: 5ff057400
大小: 00 a0 12 0e
第2逻辑盘大小为: 10490382 扇区 = 5.002204 GBThis is an extend patition!
第2分区表标志位为: 05
01 40 24 9a
开始地址为: 87f4e2a00
大小: 00 c0 2f 10
第2逻辑盘大小为: 12594960 扇区 = 6.005745 GB
总结
MBR的四个分区表的组合有两种:全部是主分区;三个主分区+一个扩展分区。在阅读分区表条目的时候,(从第1字节开始)第5字节中存放的信息也比较重要,如果是05H或者是0FH,表示这是一个扩展分区条目,地址信息指向的是EBR,否则如果不是0,就是一个主分区条目,指向的是每个主分区的开始扇区。如果是在EBR中,在扩展分区表部分,只有前两个条目有效,最后两个是全为0的没有用到,第1个条目指向了目前已经发现了的逻辑盘,第2个条目如果不是全0,说明还有下一个逻辑盘,指向的就是下一个EBR。
地址信息Relative在主分区中,是0。在扩展分区中,是主扩展分区的开始位置所在扇区,可以从MBR中获取到。而Sectors指的是分区占的总扇区数,在MBR中,第4个如果是扩展分区的话,表示是整个扩展分区里面所有逻辑盘的大小。
自己电脑的分区逻辑图如图所示:
PS:程序写的时候有的显示BUG这种就没有改了。。。。。
C语言读取磁盘分区信息(MBR、DPT、EBR)相关推荐
- 两种磁盘分区形式MBR(只支持4个主分区)和GPT
两种磁盘分区形式MBR(只支持4个主分区)和GPT: MBR: master boot record(主引导记录),存在于驱动器开始部分的特殊启动扇区,是存在于驱动器开始部分的一个特殊启动扇区,包括已 ...
- linux服务器引导分区,Linux系统的引导过程和磁盘分区信息
Linux系统的引导过程和磁盘分区信息 作者:chinaitlab 佚名 2005-12-07 00:00 评论 分享 [IT168 服务器学院] 系统的引导过程和磁盘分区信息 在PC机上,最初的启动 ...
- 磁盘分区格式(MBR分区和GPT分区)和启动引导模式(Legacy和UEFI)的关系
文章目录 1. 专业名词概览 2. 磁盘分区格式:MBR分区和GPT分区 2.1 简介 2.2 区别 3. 启动引导模式:Legacy BIOS和UEFI BIOS 3.1 Legacy BIOS的启 ...
- 使用partx重读磁盘分区信息及自动挂载分区的方法
在之前的帖子<Linux调整分区后Grub修复>中提到,Linux调整磁盘分区大小后会出现Grub引导损坏的问题,可以参考那篇帖子中的方法,进入grub rescue进行修复. 但是修复后 ...
- Linux 磁盘分区(MBR和GPT,loop详细分区方法介绍)
磁盘分区和格式化操作是比较接近硬件底层的操作,这两个操作也是至关重要的,决定了磁盘的使用效率和磁盘的数据安全.(相信现在应该没有什么特别的需要,一般都已经抛弃了ext2,ext4文件格式了吧~~~~, ...
- 磁盘分区方式——MBR与GPT之学习笔记
大数据时代,硬盘作为数据存储工具,是生产生活中必不可少的工具.在数据日益繁多的情况下,如何让对数据进行有效管理变得愈发重要.磁盘分区,是对数据进行有效管理的重要手段之一. 磁盘分区,就是使用分区编辑器 ...
- linux mbr 分区表修复,磁盘分区中MBR的模拟损坏及修复
目前对于硬盘的分区方式有两种:MBR和GPT.本文只是为了介绍分区中的MBR的备份和恢复,所以不对GPT分区做过多的介绍. 我们先来对MBR的分区方式进行一个简单的介绍: 上图说明: 采用MBR分区的 ...
- linux:查看磁盘分区信息和文件系统格式
查看实例上的数据盘信息(GPT/MBR) 磁盘标签类型对应: dos => MBR gpt => GPT # fdisk -l磁盘 /dev/vda:42.9 GB, 4294967296 ...
- linux分区语言,Linux磁盘分区(9)-Go语言中文社区
分区的基础知识: 模式:mbr分区: 1.最多支持四个主分区 2.系统只能安装主分区 3.扩展分区要占一个主分区 4.MBR最大只支持2TB,但拥有最好的兼容性 gtp分区: 1.支持无限多个主分区( ...
最新文章
- checkstyle安装使用
- 19 java程序员面试宝典视频课程之正则表达式
- 这是自动驾驶的战国时期,也是技术发展的黄金时期
- python软件开发-如何编写Python软件开发文档(7个技巧)
- mongod副本集的安装配置
- 重置npm设置_密码重置用户流程4部曲
- java jdk 序列化_JDK 11:Java序列化的终结开始了吗?
- numpy T、transpose()函数、swapaxes()函数
- day28 java的集合(6)Properties和TreeSet
- 俄罗斯方块-C语言-完整代码
- php smarty入门,smarty教程专题
- coco2d-x 3.0游戏实例学习笔记 《跑酷》 第二步---游戏界面amp;全新的3.0物理世界...
- Redis的持久化操作---RDBAOF
- linux系统可以装access吗,安装华为FusionAccess Linux版本的方法
- 报错:npm ERR code EPERM
- 噪声为什么是高频信号_人类是信号,但科技将我们视为噪音
- 物联网常用协议:MQTT、CoAP、LwM2M、HTTP、LoRaWAN和NB-IoT
- cesium 三维坐标系绘制
- 网络属性里的残留网络服务卸载错误0x8007007e导致卡巴斯基安装到klim6.sys错误27300回滚
- 自学python(mac)----读写文件