(opensource) windows写磁盘镜像(u盘, sdcard, 含分区表)

@vrqq  January 6, 2020

Linux下面直接dd在windows下要绕几个坑。。

先上做法

  • 在target device上新建一个分区,占满整个disk
  • 假设分区代号\\.\W:,整盘代号\\.\PhysicalDrive99,下面开始打开vs写程序(需要windows.h等等)
  • 看磁盘代号打开Powershell 然后`wmic DISKDRIVE

    // 1. get volume
    HANDLE hVolume = CreateFile("\\\\.\\W:", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    
    // 2. lock volume (we cannot lock the whole disk but we can do that)
    DeviceIoControl(hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytesreturned, NULL);
    
    // 3. unmountVolume (we cannot lock the whole disk but we can do that)
    DeviceIoControl(hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &junk, NULL);
    
    // 4. get device
    HANDLE hDev = CreateFile("\\.\PhysicalDrive99", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    
    // 5. write
    WriteFile(......)
    
    // 6. close & unlock
    ......

首先windows不支持lock整个disk,所以我们只能lock volume。
所以会有下面几个坑

坑:没写上面1,2,3步,直接打开device直接写,写时候报lasterror = 2, 32, 87, 5等等??
而且在不知道什么时候比如22% 38% 0.7%...
在写的时候刷新了磁盘分区表,然后系统发现哇,分区变了,并且第一个区如果可读的话,系统会兴高采烈地挂载它。
此时我们丧失了对整个DEVICE的full control权力,即使在上述步骤第四步,fileshare参数设为NULL也不行,因为这不是文件,挂载分区是“驱动程序”做的事情,而不是操作系统。
而我们控制文件独占,是“操作系统”的事情,上述路径是整个驱动器的代号,所以LOCK驱动器行不通啦。。

但是我就不写1,2,3步能行吗?就直接CreateFile后开搞
也是可以的!
先看这个:https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#physical-disks-and-volumes
虽然明确说了"Direct access to the disk or to a volume is restricted. ",但我非要这么做。
那就是:写失败了以后,保留分区表里面的分区位置信息,删掉分配的盘符,并把分区1跳1的删掉(主要删系统认识的分区) or 格式化成系统不认得的格。
1跳1的删掉为了在更新分区表插入分区时,不触发系统抢占整个磁盘。
写失败的时候一般来说分区表是写完了的!(看下面例子)

举例:磁盘从前向后写入,写入分区表->写入第一个分区(fat32)->写入第二个(ext4)
当写完分区表和fat32分区时候,系统哇,发现一个分区,我认识,快给安上!
然后就抢占了,我们的程序就失去了控制权。。
这也说明了如果运气好,写小img可以一次成型,在系统没发现时候就已经写好了!
而上述土办法呢,打这系统一个措手不及,啊你这分区表没变啊,那没有新的,不动了!

Note

下述windd64代码稍作更改 然后

windd64.exe /if:F:\xxx.img /of:\\.\PHYSICALDRIVE2

Refs:

  • Win32DiskImager-1.0.0-src.zip
  • Github: windd64

添加新评论