实战DeviceIoControl 之三:制作磁盘镜像文件

转载 2006年06月06日 16:30:00

Q DOS命令DISKCOPY给我很深的印象,现在也有许多“克隆”软件,可以对磁盘进行全盘复制。我想,要制作磁盘镜像文件,DeviceIoControl应该很有用武之地吧?

A 是的。这里举一个制作软盘镜像文件,功能类似于“DISKCOPY”的例子。

本例实现其功能的核心代码如下:

// 打开磁盘
HANDLE OpenDisk(LPCTSTR filename)
{
    HANDLE hDisk;
  
    // 打开设备
    hDisk = ::CreateFile(filename,           // 文件名
        GENERIC_READ | GENERIC_WRITE,        // 读写方式
        FILE_SHARE_READ | FILE_SHARE_WRITE,  // 共享方式
        NULL,                                // 默认的安全描述符
        OPEN_EXISTING,                       // 创建方式
        0,                                   // 不需设置文件属性
        NULL);                               // 不需参照模板文件
  
    return hDisk;
}
  
// 获取磁盘参数
BOOL GetDiskGeometry(HANDLE hDisk, PDISK_GEOMETRY lpGeometry)
{
    DWORD dwOutBytes;
    BOOL bResult;
  
    // 用IOCTL_DISK_GET_DRIVE_GEOMETRY取磁盘参数
    bResult = ::DeviceIoControl(hDisk,        // 设备句柄
        IOCTL_DISK_GET_DRIVE_GEOMETRY,        // 取磁盘参数
        NULL, 0,                              // 不需要输入数据
        lpGeometry, sizeof(DISK_GEOMETRY),    // 输出数据缓冲区
        &dwOutBytes,                          // 输出数据长度
        (LPOVERLAPPED)NULL);                  // 用同步I/O
  
    return bResult;
}
  
// 从指定磁道开始读磁盘
BOOL ReadTracks(HANDLE hDisk, PDISK_GEOMETRY lpGeometry, LPVOID pBuf, DWORD dwStartCylinder, DWORD dwCylinderNumber)
{
    DWORD VirtBufSize;
    DWORD BytesRead;
  
    // 大小
    VirtBufSize =  lpGeometry->TracksPerCylinder * lpGeometry->SectorsPerTrack * lpGeometry->BytesPerSector;
  
    // 偏移
    ::SetFilePointer(hDisk, VirtBufSize*dwStartCylinder, NULL, FILE_BEGIN);
  
    return ::ReadFile(hDisk, pBuf, VirtBufSize*dwCylinderNumber, &BytesRead, NULL);
}
  
// 从指定磁道开始写磁盘
BOOL WriteTracks(HANDLE hDisk, PDISK_GEOMETRY lpGeometry, LPVOID pBuf, DWORD dwStartCylinder, DWORD dwCylinderNumber)
{
    DWORD VirtBufSize;
    DWORD BytesWritten;
  
    // 大小
    VirtBufSize =  lpGeometry->TracksPerCylinder * lpGeometry->SectorsPerTrack * lpGeometry->BytesPerSector;
  
    // 偏移
    ::SetFilePointer(hDisk, VirtBufSize*dwStartCylinder, NULL, FILE_BEGIN);
  
    return ::WriteFile(hDisk, pBuf, VirtBufSize*dwCylinderNumber, &BytesWritten, NULL);
}
  
// 从指定磁道开始格式化磁盘
BOOL LowLevelFormatTracks(HANDLE hDisk, PDISK_GEOMETRY lpGeometry, DWORD dwStartCylinder, DWORD dwCylinderNumber)
{
    FORMAT_PARAMETERS FormatParameters;
    PBAD_TRACK_NUMBER lpBadTrack;
    DWORD dwOutBytes;
    DWORD dwBufSize;
    BOOL bResult;
  
    FormatParameters.MediaType = lpGeometry->MediaType;
    FormatParameters.StartCylinderNumber = dwStartCylinder;
    FormatParameters.EndCylinderNumber = dwStartCylinder + dwCylinderNumber - 1;
    FormatParameters.StartHeadNumber = 0;
    FormatParameters.EndHeadNumber = lpGeometry->TracksPerCylinder - 1;
  
    dwBufSize = lpGeometry->TracksPerCylinder * sizeof(BAD_TRACK_NUMBER);
  
    lpBadTrack = (PBAD_TRACK_NUMBER) new BYTE[dwBufSize];
  
    // 用IOCTL_DISK_FORMAT_TRACKS对连续磁道进行低级格式化
    bResult = ::DeviceIoControl(hDisk,               // 设备句柄
        IOCTL_DISK_FORMAT_TRACKS,                    // 低级格式化
        &FormatParameters, sizeof(FormatParameters), // 输入数据缓冲区
        lpBadTrack, dwBufSize,                       // 输出数据缓冲区
        &dwOutBytes,                                 // 输出数据长度
        (LPOVERLAPPED)NULL);                         // 用同步I/O
  
    delete lpBadTrack;
  
    return bResult;
}
  
// 将卷锁定
BOOL LockVolume(HANDLE hDisk)
{
    DWORD dwOutBytes;
    BOOL bResult;
  
    // 用FSCTL_LOCK_VOLUME锁卷
    bResult = ::DeviceIoControl(hDisk,        // 设备句柄
        FSCTL_LOCK_VOLUME,                    // 锁卷
        NULL, 0,                              // 不需要输入数据
        NULL, 0,                              // 不需要输出数据
        &dwOutBytes,                          // 输出数据长度
        (LPOVERLAPPED)NULL);                  // 用同步I/O
  
    return bResult;
}
  
// 将卷解锁
BOOL UnlockVolume(HANDLE hDisk)
{
    DWORD dwOutBytes;
    BOOL bResult;
  
    // 用FSCTL_UNLOCK_VOLUME开卷锁
    bResult = ::DeviceIoControl(hDisk,        // 设备句柄
        FSCTL_UNLOCK_VOLUME,                  // 开卷锁
        NULL, 0,                              // 不需要输入数据
        NULL, 0,                              // 不需要输出数据
        &dwOutBytes,                          // 输出数据长度
        (LPOVERLAPPED)NULL);                  // 用同步I/O
  
    return bResult;
}
  
// 将卷卸下
// 该操作使系统重新辨识磁盘,等效于重新插盘
BOOL DismountVolume(HANDLE hDisk)
{
    DWORD dwOutBytes;
    BOOL bResult;
  
    // 用FSCTL_DISMOUNT_VOLUME卸卷
    bResult = ::DeviceIoControl(hDisk,        // 设备句柄
        FSCTL_DISMOUNT_VOLUME,                // 卸卷
        NULL, 0,                              // 不需要输入数据
        NULL, 0,                              // 不需要输出数据
        &dwOutBytes,                          // 输出数据长度
        (LPOVERLAPPED)NULL);                  // 用同步I/O
  
    return bResult;
}

将软盘保存成镜像文件的步骤简单描述为:
1、创建空的镜像文件。
2、调用OpenDisk打开软盘。成功转3,失败转8。
3、调用LockVolume将卷锁定。成功转4,失败转7。
4、调用GetDiskGeometry获取参数。成功转5,失败转6。
5、将磁盘参数写入镜像文件作为文件头。调用ReadTracks按柱面读出数据,保存在镜像文件中。循环次数等于柱面数。
6、调用UnlockVolume将卷解锁。
7、调用CloseDisk关闭软盘。
8、关闭镜像文件。

将镜像文件载入软盘的步骤简单描述为:
1、打开镜像文件。
2、调用OpenDisk打开软盘。成功转3,失败转11。
3、调用LockVolume将卷锁定。成功转4,失败转10。
4、调用GetDiskGeometry获取参数。成功转5,失败转9。
5、从镜像文件中读出文件头,判断两个磁盘参数是否一致。不一致转6,否则转7。
6、调用LowLevelFormatTracks按柱面格式化软盘。循环次数等于柱面数。成功转7,失败转8。
7、从镜像文件中读出数据,并调用WriteTracks按柱面写入磁盘。循环次数等于柱面数。
8、调用DismountVolume将卷卸下。
9、调用UnlockVolume将卷解锁。
10、调用CloseDisk关闭软盘。
11、关闭镜像文件。

Q 我注意到,磁盘读写和格式化是按柱面进行的,有什么道理吗?

A 没有特别的原因,只是因为在这个例子中可以方便地显示处理进度。

有一点需要特别提及,按绝对地址读写磁盘数据时,“最小单位”是扇区,地址一定要与扇区对齐,长度也要等于扇区长度的整数倍。比如,每扇区512字节,那么起始地址和数据长度都应能被512整除才行。

Q 我忽然产生了一个伟大的想法,用绝对地址读写的方式使用磁盘,包括U盘啦,MO啦,而不是用现成的文件系统,那不是可以将数据保密了吗?

A 当然,只要你喜欢。可千万别在你的系统盘上做试验,否则......可别怪bhw98没有提醒过你喔!

Q 我知道怎么测试光驱的传输速度了,就用上面的方法,读出一定长度数据,除以所需时间,应该可以吧?

A 可以。但取光盘参数时要用IOCTL_STORAGE_GET_MEDIA_TYPES_EX,我们已经探讨过的。

[相关资源]

本文Demo源码:FloppyImage.zip (16KB) Microsoft的例子:vs6samples.exe (134,518KB) bhw98的专栏:http://www.csdn.net/develop/author/netauthor/bhw98/

首次发布:2003-02-19
最后修订:2003-05-20

 


实战 DeviceIoControl 系列 之三:制作磁盘镜像文件

Q DOS命令 DISKCOPY 给我很深的印象,现在也有许多“克隆”软件,可以对磁盘进行全盘复制。我想,要制作磁盘镜像文件,DeviceIoControl 应该很有用武之地吧?  A 是的。这里举一...
  • cnyfk
  • cnyfk
  • 2011年03月30日 14:15
  • 266

实战DeviceIoControl 之三:制作磁盘镜像文件

Q DOS命令DISKCOPY给我很深的印象,现在也有许多“克隆”软件,可以对磁盘进行全盘复制。我想,要制作磁盘镜像文件,DeviceIoControl应该很有用武之地吧? A 是的。这里举一个...

磁盘镜像文件的制作

为了以防意外情况发生,丢失重要的文件系统、数据,而没有方法恢复,因此想将一个硬盘里的所有数据(包括系统、软件等)到拷贝到另外一个空硬盘里,以作备用。该如何做呢?对于这个很简单,当然是运用到磁盘镜像文件...

win Image制作磁盘镜像

  • 2010年03月08日 22:55
  • 588KB
  • 下载

2台电脑共享硬盘方法 有时候我们需要在两台电脑之间传送大容量的文件,例如系统备份的镜像文件,或者要拷贝整个硬盘里的文件,我们又找不到这么大的移动存储设备,该怎么办,其实在没有网络和大容量移动磁盘的情

2台电脑共享硬盘方法  有时候我们需要在两台电脑之间传送大容量的文件,例如系统备份的镜像文件,或者要拷贝整个硬盘里的文件,我们又找不到这么大的移动存储设备,该怎么办,其实在没有网络和大容量移...

AIX下做磁盘镜像

  • 2015年01月13日 09:56
  • 297KB
  • 下载

磁盘管理,磁盘挂在mount,挂载光盘镜像文件,挂在U盘,umount 卸载命令, dd

1 mount 命令格式: mount[-t vfstype] -o options device dir 其中: *-t vfstype 指定文件系统的类型,通常不必指定。mount会自动...

Zhaoyu的 11GASM磁盘镜像特性

  • 2013年04月03日 09:58
  • 137KB
  • 下载

磁盘镜像创建方法总结

  • 2015年03月04日 22:05
  • 149KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:实战DeviceIoControl 之三:制作磁盘镜像文件
举报原因:
原因补充:

(最多只允许输入30个字)