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. 【Thinkphp 5】auth权限设置以及实现

    1.将auth类下载好 放置目录: extend\auth\auth.php 2.将类中的SQL语句执行,可以在数据库中创建3张表 auth_group(用户组表)           auth_ru ...

  2. struts2--实现自定义拦截器

    前言: 本篇文章,我想说清实现拦截器的办法,还有为什么要这样做: 目录: 1.需求目的 2.实现步骤及原理(文字怕描述不清,画图描述) 3.代码 4.总结 一.需求目的 规范或限制越级访问(例如:一个 ...

  3. 编程岗位电话面试问答Top 50[转]

    原文链接:http://blog.jobbole.com/84618/ 1. 从哈希表,二叉树和链表中取元素的时间复杂度?如果你有数百万记录呢? 哈希表的时间复杂度为O(1),二叉树为O(logN) ...

  4. 洛谷 [p1196] 银河英雄传说

    所谓带权并查集 本题所求的不止是两个编号之间是否有关系,还要求两个编号之间有什么关系,这就要求我们维护多个数组,fa[]数组维护两个编号之间的连通性,dis[]维护编号为i的战舰到fa[i]之间的距离 ...

  5. SDOI2017 Round1

    SDOI2017 Round1 在回去的车上写的 cnblog的markdown貌似有bug,空行都没有了 Day -several [清明节] 没想到在省选之前还会有一次放假 放假前一天晚上走到校门 ...

  6. BZOJ 3786: 星系探索 [伪ETT]

    传送门 数据,标程 题意: 一颗有根树,支持询问点到根路径权值和,子树加,换父亲 欧拉序列怎么求路径权值和? 一个点的权值只会给自己的子树中的点贡献,入栈权值正出栈权值负,求前缀和就行了! 和上题一样 ...

  7. PHP判断SQL语句是否合法:mysqli_error()

    假设现在有条update语句,有时候update语句正确,但是受影响的行数是0. 那么怎么判断这条SQL语句到底是否正确?使用 mysqli_error($Conn); create table us ...

  8. 解决java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext这个问题

    今天在运行别人的SSH项目时,遇到了这个问题 严重: Exception sending context initialized event to listener instance of class ...

  9. 工作中代码笔记 -- adb命令篇

    1.抓log方法 (bat文件) mkdir D:\logcatset /p miaoshu=请描述操作:adb logcat -v threadtime > D:\logcat\%miaosh ...

  10. springboot入门_模板

    springboot中已经不推荐使用jsp,而是推荐使用模板,如freemarker,thymeleaf等,本文记录在sprigboot中使用模板. 创建一个maven的springboot工程, f ...