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,我们已经探讨过的。

实战DeviceIoControl 之三:制作磁盘镜像文件的更多相关文章

  1. Docker系列(24)- 实战:DockerFile制作tomcat镜像

    实战:DockerFile制作tomcat镜像 step-1 准备镜像文件 tomcat压缩包,jdk压缩包! step-2 编写dockerfile文件,官方命名Dockerfile,build会自 ...

  2. 3种方法快速制作tpk文件 [转]

    tpk是ArcGIS10.1推出的一种新的数据文件类型,主要是用于将切片文件打包形成离线地图包,tpk可以在ArcGIS Runtime或者ArcGIS for Android/iOS中作为切片底图被 ...

  3. NSIS使用教程(安装包制作安装文件教程,如何封装打包文件) 中文版

    nsis中文版(Nullsoft Scriptable Install System)是一个专业的开源的可以用来封闭Windows程序的实用工具,是一个开源的 Windows 系统下安装程序制作程序. ...

  4. Ubuntu下制作ISO文件

    利用Ubuntu自带的命令mkisofs就可以制作iso文件,具体方法如下: 1.   如果你是直接从cd压制iso文件的,执行 sudo umount /dev/cdromdd if=/dev/cd ...

  5. 如何制作CSR文件?

    如何制作CSR文件? 在申请数字证书之前,您必须先生成证书私钥和证书请求文件(CSR,Cerificate Signing Request),CSR是您的公钥证书原始文件,包含了您的服务器信息和您的单 ...

  6. 用C#制作PDF文件全攻略

    用C#制作PDF文件全攻略 目  录 前    言... 3 第一部分 iText的简单应用... 4 第一章 创建一个Document 4 第一步 创建一个Document实例:... 5 第二步 ...

  7. 制作BibTex文件

    上一篇日志中讲到了在LaTeX中使用BibTex管理参考文献,这篇日志具体总结下如何制作BibTex文件. 制作BibTex文件,主要有以下几种方法: 手工制作: 直接从期刊数据库中下载: 借助Goo ...

  8. 如何制作iso文件

    UltraISO 9.6.2.3059中文完美破解安装版 http://www.upantool.com/qidong/2011/UltraISO_v9.5.0.2800.html 软碟通v9.6.2 ...

  9. 使用和制作patch文件

    使用和制作patch文件 发表时间: 2007-2-13 20:57    作者: superuser    来源: 迷茫人 字体: 小 中 大 | 打印 原文http://www.linuxsir. ...

随机推荐

  1. Elasticsearch 全教程--入门

    1.1 初识 Elasticsearch 是一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎,可以说 Lucene 是当今最先进,最高效的全功能开源搜索引擎框架. 但是 L ...

  2. Array.prototype鲜为人知的事实

    // constructor 属性是每个具有原型的对象的原型成员. // 这包括除 Global 和 Math 对象之外的所有内部 JavaScript 对象. // constructor 属性包含 ...

  3. H5 Canvas图像模糊解决办法

    1.最近在用h5的canvas画动画,发现图像特别模糊.后来终于找到罪魁祸首是<meta name="viewport" content="width=device ...

  4. js的内置对象

    转载: https://www.cnblogs.com/liuluteresa/p/6413988.html   在js里,一切皆为或者皆可以被用作对象.可通过new一个对象或者直接以字面量形式创建变 ...

  5. ABP官方文档翻译 4.2 数据传输对象

    数据传输对象 DTOs的必要性 领域层的抽象 数据隐藏 序列化和懒加载问题 DTO转换和验证 示例 DTOs和实体间的自动映射 辅助接口和类 数据传输对象用来在应用层和展示层之间传输数据. 展示层调用 ...

  6. xBIM 多个IFC文件合并

    目录 xBIM 应用与学习 (一) xBIM 应用与学习 (二) xBIM 基本的模型操作 xBIM 日志操作 XBIM 3D 墙壁案例 xBIM 格式之间转换 xBIM 使用Linq 来优化查询 x ...

  7. 数据提交成功后如何避免alert被window.location.reload()影响

    数据提交成功用alert提示,但页面立马就重载了 alert("提交成功!"); window.location.reload(); 如何避免? 方法一: setTimeout 延 ...

  8. windows搭建web服务器

    1.安装web管理工具 控制面板--->程序和功能--->打开或关闭功能 2.将internet信息服务中的所有选项全部勾上,并点击确定. 3.打开浏览器,输入http://localho ...

  9. Git团队协作之GitFlow & SoucceTree

    GitFlow 定义了一个围绕项目发布的严格的分支模型,仍然使用中央仓库作为开发者的交互中心 GitFlow分支 Master分支 Hotfix紧急修改 Release分支 Develop开发分支 F ...

  10. win7(windows 7)系统下安装SQL2005(SQL Server 2005)图文教程

    操作系统:Microsoft Windows 7 旗舰版(32位) 数据库版本:SQL Server 2005 简体中文开发板 数据库下载链接: https://pan.baidu.com/s/1cq ...