实战DeviceIoControl 之三:制作磁盘镜像文件
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 之三:制作磁盘镜像文件的更多相关文章
- Docker系列(24)- 实战:DockerFile制作tomcat镜像
实战:DockerFile制作tomcat镜像 step-1 准备镜像文件 tomcat压缩包,jdk压缩包! step-2 编写dockerfile文件,官方命名Dockerfile,build会自 ...
- 3种方法快速制作tpk文件 [转]
tpk是ArcGIS10.1推出的一种新的数据文件类型,主要是用于将切片文件打包形成离线地图包,tpk可以在ArcGIS Runtime或者ArcGIS for Android/iOS中作为切片底图被 ...
- NSIS使用教程(安装包制作安装文件教程,如何封装打包文件) 中文版
nsis中文版(Nullsoft Scriptable Install System)是一个专业的开源的可以用来封闭Windows程序的实用工具,是一个开源的 Windows 系统下安装程序制作程序. ...
- Ubuntu下制作ISO文件
利用Ubuntu自带的命令mkisofs就可以制作iso文件,具体方法如下: 1. 如果你是直接从cd压制iso文件的,执行 sudo umount /dev/cdromdd if=/dev/cd ...
- 如何制作CSR文件?
如何制作CSR文件? 在申请数字证书之前,您必须先生成证书私钥和证书请求文件(CSR,Cerificate Signing Request),CSR是您的公钥证书原始文件,包含了您的服务器信息和您的单 ...
- 用C#制作PDF文件全攻略
用C#制作PDF文件全攻略 目 录 前 言... 3 第一部分 iText的简单应用... 4 第一章 创建一个Document 4 第一步 创建一个Document实例:... 5 第二步 ...
- 制作BibTex文件
上一篇日志中讲到了在LaTeX中使用BibTex管理参考文献,这篇日志具体总结下如何制作BibTex文件. 制作BibTex文件,主要有以下几种方法: 手工制作: 直接从期刊数据库中下载: 借助Goo ...
- 如何制作iso文件
UltraISO 9.6.2.3059中文完美破解安装版 http://www.upantool.com/qidong/2011/UltraISO_v9.5.0.2800.html 软碟通v9.6.2 ...
- 使用和制作patch文件
使用和制作patch文件 发表时间: 2007-2-13 20:57 作者: superuser 来源: 迷茫人 字体: 小 中 大 | 打印 原文http://www.linuxsir. ...
随机推荐
- Object对象和function对象
Obejct对象 1.ECMAScript 中的 Object 对象与 Java 中的 java.lang.Object 相似. 2.ECMAScript中的所有对象都由Object对象继承而来,Ob ...
- PHP正则匹配与文件编码关系
虽然多数高手认为正则会影响程序效率,但是做数据采集的时候,却很难避免使用正则, 强大的正则表达式用起来很舒服,但是在匹配中文的时候,会出现,明明正则表达式没问题,字符数据里包含符合正则表达式的数据,可 ...
- DevExtreme 学习应用[3]
DevExtreme dxSelectBox 联动查询案例 //数据获取 lookupDataSource = new DevExpress.data.DataSource({ store: stor ...
- JDBC为什么要使用PreparedStatement而不是Statement
PreparedStatement是什么? PreparedStatement是java.sql包下面的一个接口,用来执行SQL语句查询,通过调用connection.preparedStatemen ...
- 51Nod 欢乐手速场1 C 开心的小Q[莫比乌斯函数]
开心的小Q tangjz (命题人) quailty (测试) 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 如果一个数字存在一个约数是完全平方数,那么小Q就认为这个数是有趣的 ...
- IT连创业系列:年终回顾录!
一年不过一转眼,一光阴的青春又逝去了! 还有不到几天,就要进入新年快乐的祝福包围圈了. 在这归家之际,留文一篇,为这忙碌的一年创业留点回忆! IT连创业这一年走来: 大大小小的深坑,小小大大的困难,一 ...
- Windows下快速建立cocos2d-x项目
准备工作 1.根据当前系统版本,下载对应版本的Python 32位下载地址:http://www.python.org/ftp/python/2.7.5/python-2.7. ...
- srand()和rand()函数的使用
rand()函数不接受参数,默认以1为种子(即起始值). 随机数生成器总是以相同的种子开始,所以形成的伪随机数列也相同,失去了随机意义.(但这样便于程序调试) srand()函数就是指明种子的大小:只 ...
- Linux 虚拟IP
虚拟IP Linux网卡上绑定另一个虚拟ip,即网卡上一个真实ip一个虚拟ip.当然通过这2个ip都可以连接到该主机. 实现原理主要是靠TCP/IP的ARP协议.因为ip地址只是一个逻辑 地址,在以太 ...
- [Python Study Notes]CS架构远程访问获取信息--Client端v1.0
更新内容: 1.添加entry栏默认ip和port口 2.修正退出功能 3.添加退出自动关闭窗口功能 4.优化cpu显示为固定保留两位小数 '''''''''''''''''''''''''''''' ...