实战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. ...
随机推荐
- centos配置单网卡为Trunk模式
单网卡配置多IP(trunk模式)操作标准 1.linux的单网卡配置多IP的操作 下面为linux系统单网卡配置多IP(trunk模式)的操作步骤,系统平台为centos5.5.全部操作完成后,将实 ...
- C语言的格式符
转至:http://blog.csdn.net/zhanzheng520/article/details/10434791 一.格式符含义 1.d格式符:按十进制格式输出. %d ...
- Html5五子棋
1.效果图 2.代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...
- Python CRM项目三
1.分页: 分页使用Django内置的分页模块来实现 官方的分页案例 from django.core.paginator import Paginator, EmptyPage, PageNotAn ...
- c#实现自然排序效果,按1,2,11而不是1,11,12,区分字母文字和数字
排序有时候要考虑后缀.这样看起来比较自然. 参考了codeproject上一篇文章:http://www.codeproject.com/Articles/22978/Implementing-the ...
- ABP官方文档翻译 3.2 值对象
值对象 介绍 值对象基类 最佳实践 介绍 "展现领域描述性层面且没有概念性身份的对象称之为值对象."(Eric Evans). 和实体相反,实体有身份标示(Id),值对象没有身份标 ...
- 读Ghost博客源码与自定义Ghost博客主题
我使用的Ghost博客一直使用者默认的Casper主题.我向来没怎么打理过自己博客,一方面认为自己不够专业,很难写出质量比较高的文字:另一方面认为博客太耗时间,很容易影响正常的工作内容.最近公司即将搬 ...
- java对象表示方式--XStream
对象表示有各种各样的方式,序列化只是其中的一种而已.表示一个对象的目的无非就是为了对象<---->IO之间相互认识,至于怎么认识,那就有很多选择了.除了之前讲过的序列化,还可以选择将数据J ...
- JVM基础篇(一)
JVM简介 JVM(Java虚拟机)是一个虚拟的机器,在实际的计算机上通过软件模拟来实现.JVM有自己的硬件,如处理器.堆栈.寄存器等,还具有相应的指令系统. JVM包括一套字节码指令集.一组寄存器. ...
- JS高级程序设计第3章读书笔记
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...