windows的磁盘操作之五——获取物理磁盘上的所有逻辑分区号
引用:https://www.cnblogs.com/chaikefusibushiji/p/6775773.html
本节讨论与上一节相反的操作,根据物理驱动器号获取该磁盘上的所有分区号。DeviceIoControl函数并没有提供操作码来直接完成此操作,所以需要稍微绕个圈子来实现这项功能。
大体思路为,先通过GetLogicalDrives函数获得系统中所有分区号,然后过滤掉非硬盘分区(例如软驱、光驱),再过滤掉不属于指定物理磁盘的分区,最后剩下的就是我们所需要的分区号了。
代码如下
/******************************************************************************
* Function: get disk's drive letters from physical number
* e.g. 0-->{C, D, E} (disk0 has 3 drives, C:, D: and E:)
* input: phyDriveNumber, disk's physical number
* output: letters, letters array
* return: Succeed, the amount of letters
* Fail, -1
******************************************************************************/
DWORD GetPartitionLetterFromPhysicalDrive(DWORD phyDriveNumber, CHAR **letters)
{
DWORD mask;
DWORD driveType;
DWORD bmLetters;
DWORD diskNumber;
CHAR path[DISK_PATH_LEN];
CHAR letter;
DWORD letterNum;
WORD i;
CHAR *p;
bmLetters = GetLogicalDrives();
if (0 == bmLetters)
{
return (DWORD)-1;
}
letterNum = 0;
for (i = 0; i < sizeof(DWORD) * 8; i++)
{
mask = 0x1u << i;
if ((mask & bmLetters) == 0) //get one letter
{
continue;
}
letter = (CHAR)(0x41 + i); //ASCII change
sprintf(path, "%c:\\", letter);
driveType = GetDriveType(path);
if (driveType != DRIVE_FIXED)
{
bmLetters &= ~mask; //clear this bit
continue;
}
diskNumber = GetPhysicalDriveFromPartitionLetter(letter);
if (diskNumber != phyDriveNumber)
{
bmLetters &= ~mask; //clear this bit
continue;
}
letterNum++;
}
//build the result
*letters = (CHAR *)malloc(letterNum);
if (NULL == *letters)
{
return (DWORD)-1;
}
p = *letters;
for (i = 0; i < sizeof(DWORD) * 8; i++)
{
mask = 0x1u << i;
if ((mask & bmLetters) == 0)
{
continue;
}
letter = (CHAR)(0x41 + i); //ASCII change
*p = letter;
p++;
}
return letterNum;
}
代码分析
函数输入参数DWORD phyDriveNumber为物理磁盘号,例如0,1,2……。
函数输出参数CHAR **letters为获得的逻辑分区号数组指针。由于一块物理盘上可能有多个分区,所以用数组存放求得的多个分区号。
函数返回值为分区数量。
1. 调用函数GetLogicalDrives获得所有分区号。注意函数GetLogicalDrives返回值为位图形时,例如第0位代表A:,第2位代表C: 等等。
2. 对获得的逻辑分区逐个检测。
调用函数GetDriveType获得分区类型,如果类型不为硬盘(driveType != DRIVE_FIXED),将此位清0。
调用函数GetPhysicalDriveFromPartitionLetter查询该逻辑分区所属的物理分区号,如果不为phyDriveNumber,将此位清0。
经过上两项条件过滤后的位图存储了我们所需的逻辑分区号。
3. 为*letters分配空间,并将位图转换为盘符字母存储在数组中。
使用vs c++ 实现,然后打印其中宏的数值。然后用go实现。
https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-ioctl_disk_get_drive_geometry
https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ns-winioctl-disk_geometry
参考结构体,与宏 值。
chatGPT:
在 Windows 系统中,要获取指定物理磁盘上的所有分区信息,你可以使用 DeviceIoControl
API 与 IOCTL_DISK_GET_DRIVE_LAYOUT_EX
控制代码来获取分区布局。以下是一个在 Go 中实现该功能的示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | package main import ( "fmt" "golang.org/x/sys/windows" "unsafe" ) // 定义所需的常量和结构体 const ( IOCTL_DISK_GET_DRIVE_LAYOUT_EX = 0x00070050 ) type PARTITION_INFORMATION_EX struct { PartitionStyle uint32 StartingOffset int64 PartitionLength int64 PartitionNumber uint32 RewritePartition bool IsRecognizedPartition bool IsPrimaryPartition bool } type DRIVE_LAYOUT_INFORMATION_EX struct { PartitionStyle uint32 PartitionCount uint32 Partitions [1]PARTITION_INFORMATION_EX } func main() { diskNumber := 0 // 这里指定你要检查的物理磁盘号,0 对应 \\.\PhysicalDrive0 // 构建设备路径,例如 \\.\PhysicalDrive0 devicePath := fmt.Sprintf( "\\\\.\\PhysicalDrive%d" , diskNumber) // 打开设备 handle, err := windows.CreateFile( windows.StringToUTF16Ptr(devicePath), windows.GENERIC_READ, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0, ) if err != nil { fmt.Printf( "Failed to open %s: %v\n" , devicePath, err) return } defer windows.CloseHandle(handle) // 获取磁盘分区布局信息 var layout DRIVE_LAYOUT_INFORMATION_EX var bytesReturned uint32 // 设置缓冲区大小,以便足够容纳所有分区信息 layoutSize := uint32( unsafe .Sizeof(layout) + unsafe .Sizeof(layout.Partitions)*(127)) // 最大支持128个分区 buffer := make([] byte , layoutSize) err = windows.DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, nil, 0, &buffer[0], layoutSize, &bytesReturned, nil) if err != nil { fmt.Printf( "Failed to get drive layout for %s: %v\n" , devicePath, err) return } // 解释返回的布局信息 layout = *(*DRIVE_LAYOUT_INFORMATION_EX)( unsafe .Pointer(&buffer[0])) fmt.Printf( "Found %d partitions on disk %s:\n" , layout.PartitionCount, devicePath) for i := uint32(0); i < layout.PartitionCount; i++ { partition := layout.Partitions[i] fmt.Printf( "Partition %d: Offset = %d, Length = %d bytes\n" , partition.PartitionNumber, partition.StartingOffset, partition.PartitionLength) } } |
代码说明
-
常量和结构体定义:
IOCTL_DISK_GET_DRIVE_LAYOUT_EX
: 控制代码,用于获取磁盘的分区布局信息。PARTITION_INFORMATION_EX
和DRIVE_LAYOUT_INFORMATION_EX
: 分别表示单个分区的信息以及整个磁盘的分区布局。
-
设备路径:
- 使用
\\.\PhysicalDriveX
表示物理磁盘,X
为磁盘编号(例如0
表示\\.\PhysicalDrive0
)。
- 使用
-
DeviceIoControl 调用:
- 通过
windows.DeviceIoControl
函数调用IOCTL_DISK_GET_DRIVE_LAYOUT_EX
,获取指定物理磁盘的分区布局信息。
- 通过
-
缓冲区大小:
- 由于磁盘可能包含多个分区,所以需要一个足够大的缓冲区来存放所有分区的信息。这里我们假设最多可能有 128 个分区,并为每个分区分配足够的空间。
-
解析布局信息:
- 解析返回的布局信息,遍历并打印每个分区的偏移量和长度。
参考:
https://www.cnblogs.com/chaikefusibushiji/p/6775773.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2023-09-04 go init
2023-09-04 go实现ping
2023-09-04 go 生成uuid 与随机数