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)
    }
}

  

 

代码说明

  1. 常量和结构体定义

    • IOCTL_DISK_GET_DRIVE_LAYOUT_EX: 控制代码,用于获取磁盘的分区布局信息。
    • PARTITION_INFORMATION_EXDRIVE_LAYOUT_INFORMATION_EX: 分别表示单个分区的信息以及整个磁盘的分区布局。
  2. 设备路径

    • 使用 \\.\PhysicalDriveX 表示物理磁盘,X 为磁盘编号(例如 0 表示 \\.\PhysicalDrive0)。
  3. DeviceIoControl 调用

    • 通过 windows.DeviceIoControl 函数调用 IOCTL_DISK_GET_DRIVE_LAYOUT_EX,获取指定物理磁盘的分区布局信息。
  4. 缓冲区大小

    • 由于磁盘可能包含多个分区,所以需要一个足够大的缓冲区来存放所有分区的信息。这里我们假设最多可能有 128 个分区,并为每个分区分配足够的空间。
  5. 解析布局信息

    • 解析返回的布局信息,遍历并打印每个分区的偏移量和长度。

 

 

 

 

 

 参考:

https://www.cnblogs.com/chaikefusibushiji/p/6775773.html

 

posted @   redrobot  阅读(167)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!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 与随机数
点击右上角即可分享
微信分享提示