【问题标题】:How to write an image containing multiple partitions to a USB flash drive on Windows using C++如何使用 C++ 在 Windows 上将包含多个分区的图像写入 USB 闪存驱动器
【发布时间】:2013-02-21 14:39:25
【问题描述】:

在 Windows 上,您只能看到可移动媒体上的第一个分区。我想编写一个 C++ 程序,该程序可以将包含 MBR 和 2 个数据分区的图像写入 USB 闪存驱动器。我不需要在 Windows 中查看第二个分区——我只需要能够将这个原始图像从 Windows/C++ 写入 USB 闪存驱动器,以便稍后在 Linux 上运行时,可以看到这两个分区。

我已经阅读了有关安装过滤器驱动程序的信息,该驱动程序最终会将可移动媒体视为固定的,这很适合阅读,但我只想在对用户 PC 的干扰最小的情况下编写此图像。我可以从第一个扇区开始访问原始 USB 驱动器,然后只写入 MBR,然后写入两个数据分区吗?

【问题讨论】:

    标签: c++ windows partitioning usb-flash-drive


    【解决方案1】:

    如果您有足够的权限执行此操作,您可以使用 CreateFile 和类似 \\.\PhysicalDrive2 的文件名打开一个句柄以直接写入 USB 驱动器。

    您需要找出物理驱动器号。如果您有驱动器号,则可以使用 \\?\D: 之类的文件名打开卷句柄,然后使用 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 确定与该卷关联的物理驱动器号。

    您可能需要先卸载现有卷(如果有)。我不确定最好的方法是什么,但您可以尝试使用IOCTL_VOLUME_OFFLINE

    编辑:这是我用于磁盘映像的一些代码,尽管我不记得我是否曾在 USB 磁盘上尝试过它。公共领域,但没有明示或暗示的保证等。(查看代码我注意到我没有明确检查扇区大小以确保缓冲区和读/写操作正确对齐。这应该'在实践中不是问题,因为常用的最大扇区大小是 4K,这也是 Windows 上的内存页面大小。但是,在生产代码中,您应该始终明确确定相关设备的扇区大小并确保正确对齐相应地。)

    #define _WIN32_WINNT 0x0501
    
    #include <windows.h>
    
    #include <stdio.h>
    
    #define dump_buffersize_megs 16
    #define dump_buffersize (dump_buffersize_megs * 1024 * 1024)
    #define dump_workingsetsize ((dump_buffersize_megs + 1) * 1024 * 1024)
    
    DWORD save(const wchar_t * source_device_name, const wchar_t * filename) {
    
      DWORD err;
    
      HANDLE hdevice, houtput;
    
      DWORD bytes_to_transfer, byte_count;
    
      GET_LENGTH_INFORMATION source_disklength;
    
      DISK_GEOMETRY source_diskgeometry;
    
      LARGE_INTEGER offset;
    
      OVERLAPPED overlapped;
    
      BYTE * buffer;
    
      if (!SetProcessWorkingSetSize(GetCurrentProcess(), dump_workingsetsize, dump_workingsetsize)) 
      {
        err = GetLastError();
        printf("Error %u trying to expand working set.\n", err);
        return err;
      }
    
      buffer = VirtualAlloc(NULL, dump_buffersize, MEM_COMMIT, PAGE_READWRITE);
    
      if (buffer == NULL)
      {
        err = GetLastError();
        printf("Error %u trying to allocate buffer.\n", err);
        return err;
      }
    
      if (!VirtualLock(buffer, dump_buffersize))
      {
        err = GetLastError();
        printf("Error %u trying to lock buffer.\n", err);
        return err;
      }
    
      hdevice = CreateFile
        (
        source_device_name,
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_NO_BUFFERING,
        NULL
        );
    
      if (hdevice == INVALID_HANDLE_VALUE) {
        err = GetLastError();
        fprintf(stderr, "Error %u opening input device.\n", err);
        return err;
      }
    
      if (!DeviceIoControl
        (
        hdevice,
        FSCTL_LOCK_VOLUME,
        NULL,
        0,
        NULL,
        0,
        &byte_count,
        NULL
        ))
      {
        err = GetLastError();
        fprintf(stderr, "Error %u locking input volume.\n", err);
        return err;
      }
    
      if (!DeviceIoControl
        (
        hdevice,
        IOCTL_DISK_GET_DRIVE_GEOMETRY,
        NULL,
        0,
        &source_diskgeometry,
        sizeof(source_diskgeometry),
        &byte_count,
        NULL
        ))
      {
        err = GetLastError();
        fprintf(stderr, "Error %u getting device geometry.\n", err);
        return err;
      }
    
      switch (source_diskgeometry.MediaType)
      {
      case Unknown:
      case RemovableMedia:
      case FixedMedia:
    
        if (!DeviceIoControl
          (
          hdevice,
          IOCTL_DISK_GET_LENGTH_INFO,
          NULL,
          0,
          &source_disklength,
          sizeof(source_disklength),
          &byte_count,
          NULL
          ))
        {
          err = GetLastError();
          fprintf(stderr, "Error %u getting input device length.\n", err);
          return err;
        }
    
        fprintf(stderr, "\nInput disk has %I64i bytes.\n\n", source_disklength.Length.QuadPart);
        break;
    
      default:
    
        source_disklength.Length.QuadPart = 
          source_diskgeometry.Cylinders.QuadPart *
          source_diskgeometry.TracksPerCylinder *
          source_diskgeometry.SectorsPerTrack *
          source_diskgeometry.BytesPerSector;
    
        fprintf(stderr, 
          "\n"
          "Input device appears to be a floppy disk.  WARNING: if this is not a\n"
          "floppy disk the calculated size will probably be incorrect, resulting\n"
          "in an incomplete copy.\n"
          "\n"
          "Input disk has %I64i bytes.\n"
          "\n", 
          source_disklength.Length.QuadPart);
    
        break;
      }
    
      houtput = CreateFile
        (
        filename,
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
        NULL
        );
    
      if (houtput == INVALID_HANDLE_VALUE)
      {
        err = GetLastError();
        fprintf(stderr, "Error %u creating output file.\n", err);
        return err;
      }
    
      offset.QuadPart = 0;
      overlapped.hEvent = 0;
    
      for (;;) 
      {
        overlapped.Offset = offset.LowPart;
        overlapped.OffsetHigh = offset.HighPart;
    
        if (source_disklength.Length.QuadPart - offset.QuadPart < dump_buffersize) 
        {
          bytes_to_transfer = (DWORD)(source_disklength.Length.QuadPart - offset.QuadPart);
          if (bytes_to_transfer == 0) break;
        }
        else
        {
          bytes_to_transfer = dump_buffersize;
        }
    
        if (!ReadFile(hdevice, buffer, bytes_to_transfer, NULL, &overlapped)) 
        {
          err = GetLastError();
          printf("Error %u initiating read from input disk.\n", err);
          return err;
        }
    
        if (!GetOverlappedResult(hdevice, &overlapped, &byte_count, TRUE)) 
        {
          err = GetLastError();
          printf("Error %u reading from input disk.\n", err);
          return err;
        }
    
        if (byte_count != bytes_to_transfer)
        {
          err = GetLastError();
          printf("Internal error - partial read.  Last error code %u.\n", err);
          printf("bytes_to_transfer = %u; byte_count = %u.\n", bytes_to_transfer, byte_count);
          if (byte_count == 0) return ERROR_INVALID_FUNCTION;
          bytes_to_transfer = byte_count;
        }
    
        if (!WriteFile(houtput, buffer, bytes_to_transfer, NULL, &overlapped)) 
        {
          err = GetLastError();
          if (err != ERROR_IO_PENDING)
          {
            printf("Error %u initiating write to output file.\n", err);
            return err;
          }
        }
    
        if (!GetOverlappedResult(houtput, &overlapped, &byte_count, TRUE)) 
        {
          err = GetLastError();
          printf("Error %u writing to output file.\n", err);
          return err;
        }
    
        if (byte_count != bytes_to_transfer)
        {
          printf("Internal error - partial write.\n");
          printf("bytes_to_transfer = %u; byte_count = %u.\n", bytes_to_transfer, byte_count);
          return ERROR_INVALID_FUNCTION;
        }
    
        offset.QuadPart += bytes_to_transfer;
      }
    
      overlapped.Offset = offset.LowPart;
      overlapped.OffsetHigh = offset.HighPart;
    
      if (!ReadFile(hdevice, buffer, source_diskgeometry.BytesPerSector, NULL, &overlapped)) 
      {
        err = GetLastError();
        if (err == ERROR_HANDLE_EOF)
        {
          printf("Save successfully completed.\n");      
          return 0;
        }
        printf("Error %u initiating read from input disk past end of file.\n", err);
        return err;
      }
    
      if (!GetOverlappedResult(hdevice, &overlapped, &byte_count, TRUE)) 
      {
        err = GetLastError();
        if (err == ERROR_HANDLE_EOF)
        {
          printf("Save successfully completed.\n");      
          return 0;
        }
        printf("Error %u reading from input disk past end of file.\n", err);
        return err;
      }
    
      if (byte_count == 0)
      {
        printf("Save successfully completed.\n"); 
        return 0;
      }
    
      printf("WARNING: the expected amount of data was successfully copied,\n"
             "but end of file not detected on input disk.  The copy might\n"
             "not be complete.");
    
      return ERROR_MORE_DATA;
    
    }
    
    DWORD write(const wchar_t * filename, const wchar_t * target_device_name) {
    
      DWORD err;
    
      HANDLE hinput, houtput;
    
      WIN32_FILE_ATTRIBUTE_DATA fad;
    
      DWORD bytes_to_transfer, byte_count;
    
      LARGE_INTEGER filelength;
    
      GET_LENGTH_INFORMATION target_disklength;
    
      DISK_GEOMETRY target_diskgeometry;
    
      LARGE_INTEGER transfer_length;
    
      LARGE_INTEGER offset;
    
      OVERLAPPED overlapped;
    
      BYTE * buffer;
    
      if (!SetProcessWorkingSetSize(GetCurrentProcess(), dump_workingsetsize, dump_workingsetsize)) 
      {
        err = GetLastError();
        printf("Error %u trying to expand working set.\n", err);
        return err;
      }
    
      buffer = VirtualAlloc(NULL, dump_buffersize, MEM_COMMIT, PAGE_READWRITE);
    
      if (buffer == NULL)
      {
        err = GetLastError();
        printf("Error %u trying to allocate buffer.\n", err);
        return err;
      }
    
      if (!VirtualLock(buffer, dump_buffersize))
      {
        err = GetLastError();
        printf("Error %u trying to lock buffer.\n", err);
        return err;
      }
    
      if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad)) 
      {
        err = GetLastError();
        fprintf(stderr, "Error %u reading input file attributes.\n", err);
        return err;
      }
    
      filelength.HighPart = fad.nFileSizeHigh;
      filelength.LowPart = fad.nFileSizeLow;
    
      fprintf(stderr, "\nInput file has %I64i bytes.\n", filelength.QuadPart);
    
      hinput = CreateFile
        (
        filename,
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
        NULL
        );
    
      if (hinput == INVALID_HANDLE_VALUE)
      {
        err = GetLastError();
        fprintf(stderr, "Error %u opening input file.\n", err);
        return err;
      }
    
      houtput = CreateFile
        (
        target_device_name,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_NO_BUFFERING,
        NULL
        );
    
      if (houtput == INVALID_HANDLE_VALUE) {
        err = GetLastError();
        fprintf(stderr, "Error %u opening output device.\n", err);
        return err;
      }
    
      if (!DeviceIoControl
        (
        houtput,
        FSCTL_LOCK_VOLUME,
        NULL,
        0,
        NULL,
        0,
        &byte_count,
        NULL
        ))
      {
        err = GetLastError();
        fprintf(stderr, "Error %u locking volume.\n", err);
        return err;
      }
    
      if (!DeviceIoControl
        (
        houtput,
        IOCTL_DISK_GET_DRIVE_GEOMETRY,
        NULL,
        0,
        &target_diskgeometry,
        sizeof(target_diskgeometry),
        &byte_count,
        NULL
        ))
      {
        err = GetLastError();
        fprintf(stderr, "Error %u getting output device geometry.\n", err);
        return err;
      }
    
      switch (target_diskgeometry.MediaType)
      {
      case Unknown:
      case RemovableMedia:
      case FixedMedia:
    
        if (!DeviceIoControl
          (
          houtput,
          IOCTL_DISK_GET_LENGTH_INFO,
          NULL,
          0,
          &target_disklength,
          sizeof(target_disklength),
          &byte_count,
          NULL
          ))
        {
          err = GetLastError();
          fprintf(stderr, "Error %u getting output device length.\n", err);
          return err;
        }
    
        fprintf(stderr, "Output disk has %I64i bytes.\n\n", target_disklength.Length.QuadPart);
        break;
    
      default:
    
        target_disklength.Length.QuadPart = 
          target_diskgeometry.Cylinders.QuadPart *
          target_diskgeometry.TracksPerCylinder *
          target_diskgeometry.SectorsPerTrack *
          target_diskgeometry.BytesPerSector;
    
        fprintf(stderr, 
          "\n"
          "Output device appears to be a floppy disk.  WARNING: if this is not a\n"
          "floppy disk the calculated output device size is probably incorrect,\n"
          "which might result in an incomplete copy.\n"
          "\n"
          "Output disk has %I64i bytes.\n"
          "\n", 
          target_disklength.Length.QuadPart);
    
        break;
      }
    
      if (filelength.QuadPart == target_disklength.Length.QuadPart)
      {
        transfer_length.QuadPart = filelength.QuadPart;
      }
      else if (filelength.QuadPart < target_disklength.Length.QuadPart)
      {
        fprintf(stderr, "Image is smaller than target.  Part of the target will not be written to.\n\n");
        transfer_length.QuadPart = filelength.QuadPart;
      }
      else
      {
        fprintf(stderr, "Image is larger than target.  Part of the image will not be copied.\n\n");
        transfer_length.QuadPart = target_disklength.Length.QuadPart;
      }
    
      offset.QuadPart = 0;
      overlapped.hEvent = 0;
    
      for (;;) 
      {
        overlapped.Offset = offset.LowPart;
        overlapped.OffsetHigh = offset.HighPart;
    
        if (transfer_length.QuadPart - offset.QuadPart < dump_buffersize) 
        {
          bytes_to_transfer = (DWORD)(transfer_length.QuadPart - offset.QuadPart);
          if (bytes_to_transfer == 0) break;
        }
        else
        {
          bytes_to_transfer = dump_buffersize;
        }
    
        if (!ReadFile(hinput, buffer, bytes_to_transfer, NULL, &overlapped)) 
        {
          err = GetLastError();
          if (err != ERROR_IO_PENDING)
          {
            printf("Error %u initiating read from input file.\n", err);
            return err;
          }
        }
    
        if (!GetOverlappedResult(hinput, &overlapped, &byte_count, TRUE)) 
        {
          err = GetLastError();
          printf("Error %u reading from input file.\n", err);
          return err;
        }
    
        if (byte_count != bytes_to_transfer)
        {
          err = GetLastError();
          printf("Internal error - partial read.  Last error code %u.\n", err);
          printf("bytes_to_transfer = %u; byte_count = %u.\n", bytes_to_transfer, byte_count);
          if (byte_count == 0) return ERROR_INVALID_FUNCTION;
          bytes_to_transfer = byte_count;
        }
    
        if (!WriteFile(houtput, buffer, bytes_to_transfer, NULL, &overlapped)) 
        {
          err = GetLastError();
          if (err != ERROR_IO_PENDING)
          {
            printf("Error %u initiating write to output disk.\n", err);
            return err;
          }
        }
    
        if (!GetOverlappedResult(houtput, &overlapped, &byte_count, TRUE)) 
        {
          err = GetLastError();
          printf("Error %u writing to output disk.\n", err);
          return err;
        }
    
        if (byte_count != bytes_to_transfer)
        {
          printf("Internal error - partial write.\n");
          printf("bytes_to_transfer = %u; byte_count = %u.\n", bytes_to_transfer, byte_count);
          return ERROR_INVALID_FUNCTION;
        }
    
        offset.QuadPart += bytes_to_transfer;
      }
    
      printf("Write successfully completed.\n");
      return 0;
    }
    
    DWORD clone(const wchar_t * source_device_name, const wchar_t * target_device_name) {
    
      DWORD err;
    
      HANDLE hinput, houtput;
    
      DWORD bytes_to_transfer, byte_count;
    
      GET_LENGTH_INFORMATION source_disklength;
    
      DISK_GEOMETRY source_diskgeometry;
    
      GET_LENGTH_INFORMATION target_disklength;
    
      DISK_GEOMETRY target_diskgeometry;
    
      LARGE_INTEGER transfer_length;
    
      LARGE_INTEGER offset;
    
      OVERLAPPED overlapped;
    
      BYTE * buffer;
    
      DWORD result;
    
      if (!SetProcessWorkingSetSize(GetCurrentProcess(), dump_workingsetsize, dump_workingsetsize)) 
      {
        err = GetLastError();
        printf("Error %u trying to expand working set.\n", err);
        return err;
      }
    
      buffer = VirtualAlloc(NULL, dump_buffersize, MEM_COMMIT, PAGE_READWRITE);
    
      if (buffer == NULL)
      {
        err = GetLastError();
        printf("Error %u trying to allocate buffer.\n", err);
        return err;
      }
    
      if (!VirtualLock(buffer, dump_buffersize))
      {
        err = GetLastError();
        printf("Error %u trying to lock buffer.\n", err);
        return err;
      }
    
      hinput = CreateFile
        (
        source_device_name,
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_NO_BUFFERING,
        NULL
        );
    
      if (hinput == INVALID_HANDLE_VALUE) {
        err = GetLastError();
        fprintf(stderr, "Error %u opening input device.\n", err);
        return err;
      }
    
      if (!DeviceIoControl
        (
        hinput,
        FSCTL_LOCK_VOLUME,
        NULL,
        0,
        NULL,
        0,
        &byte_count,
        NULL
        ))
      {
        err = GetLastError();
        fprintf(stderr, "Error %u locking input volume.\n", err);
        return err;
      }
    
      if (!DeviceIoControl
        (
        hinput,
        IOCTL_DISK_GET_DRIVE_GEOMETRY,
        NULL,
        0,
        &source_diskgeometry,
        sizeof(source_diskgeometry),
        &byte_count,
        NULL
        ))
      {
        err = GetLastError();
        fprintf(stderr, "Error %u getting device geometry.\n", err);
        return err;
      }
    
      switch (source_diskgeometry.MediaType)
      {
      case Unknown:
      case RemovableMedia:
      case FixedMedia:
    
        if (!DeviceIoControl
          (
          hinput,
          IOCTL_DISK_GET_LENGTH_INFO,
          NULL,
          0,
          &source_disklength,
          sizeof(source_disklength),
          &byte_count,
          NULL
          ))
        {
          err = GetLastError();
          fprintf(stderr, "Error %u getting input device length.\n", err);
          return err;
        }
    
        fprintf(stderr, "\nInput disk has %I64i bytes.\n", source_disklength.Length.QuadPart);
        break;
    
      default:
    
        source_disklength.Length.QuadPart = 
          source_diskgeometry.Cylinders.QuadPart *
          source_diskgeometry.TracksPerCylinder *
          source_diskgeometry.SectorsPerTrack *
          source_diskgeometry.BytesPerSector;
    
        fprintf(stderr, 
          "\n"
          "Input device appears to be a floppy disk.  WARNING: if this is not a\n"
          "floppy disk the calculated disk size is probably incorrect, resulting\n"
          "in an incomplete copy.\n"
          "\n"
          "Input disk has %I64i bytes.\n",
          source_disklength.Length.QuadPart);
    
        break;
      }
    
      houtput = CreateFile
        (
        target_device_name,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_NO_BUFFERING,
        NULL
        );
    
      if (houtput == INVALID_HANDLE_VALUE) {
        err = GetLastError();
        fprintf(stderr, "Error %u opening output device.\n", err);
        return err;
      }
    
      if (!DeviceIoControl
        (
        houtput,
        FSCTL_LOCK_VOLUME,
        NULL,
        0,
        NULL,
        0,
        &byte_count,
        NULL
        ))
      {
        err = GetLastError();
        fprintf(stderr, "Error %u locking output volume.\n", err);
        return err;
      }
    
      if (!DeviceIoControl
        (
        houtput,
        IOCTL_DISK_GET_DRIVE_GEOMETRY,
        NULL,
        0,
        &target_diskgeometry,
        sizeof(target_diskgeometry),
        &byte_count,
        NULL
        ))
      {
        err = GetLastError();
        fprintf(stderr, "Error %u getting output device geometry.\n", err);
        return err;
      }
    
      switch (target_diskgeometry.MediaType)
      {
      case Unknown:
      case RemovableMedia:
      case FixedMedia:
    
        if (!DeviceIoControl
          (
          houtput,
          IOCTL_DISK_GET_LENGTH_INFO,
          NULL,
          0,
          &target_disklength,
          sizeof(target_disklength),
          &byte_count,
          NULL
          ))
        {
          err = GetLastError();
          fprintf(stderr, "Error %u getting output device length.\n", err);
          return err;
        }
    
        fprintf(stderr, "Output disk has %I64i bytes.\n\n", target_disklength.Length.QuadPart);
        break;
    
      default:
    
        target_disklength.Length.QuadPart = 
          target_diskgeometry.Cylinders.QuadPart *
          target_diskgeometry.TracksPerCylinder *
          target_diskgeometry.SectorsPerTrack *
          target_diskgeometry.BytesPerSector;
    
        fprintf(stderr, 
          "\n"
          "Output device appears to be a floppy disk.  WARNING: if this is not a\n"
          "floppy disk the calculated output device size is probably incorrect,\n"
          "which might result in an incomplete copy.\n"
          "\n"
          "Output disk has %I64i bytes.\n"
          "\n", 
          target_disklength.Length.QuadPart);
    
        break;
      }
    
      if (source_disklength.Length.QuadPart == target_disklength.Length.QuadPart)
      {
        transfer_length.QuadPart = source_disklength.Length.QuadPart;
      }
      else if (source_disklength.Length.QuadPart < target_disklength.Length.QuadPart)
      {
        printf("Input shorter than output.  Part of the output disk will not be written to.\n\n");
        transfer_length.QuadPart = source_disklength.Length.QuadPart;
      }
      else
      {
        printf("Output shorter than input.  Copy will be truncated to output length.\n\n");
        transfer_length.QuadPart = target_disklength.Length.QuadPart;
      }
    
      offset.QuadPart = 0;
      overlapped.hEvent = 0;
    
      for (;;) 
      {
        overlapped.Offset = offset.LowPart;
        overlapped.OffsetHigh = offset.HighPart;
    
        if (transfer_length.QuadPart - offset.QuadPart < dump_buffersize) 
        {
          bytes_to_transfer = (DWORD)(transfer_length.QuadPart - offset.QuadPart);
          if (bytes_to_transfer == 0) break;
        }
        else
        {
          bytes_to_transfer = dump_buffersize;
        }
    
        if (!ReadFile(hinput, buffer, bytes_to_transfer, NULL, &overlapped)) 
        {
          err = GetLastError();
          printf("Error %u initiating read from input file.\n", err);
          return err;
        }
    
        if (!GetOverlappedResult(hinput, &overlapped, &byte_count, TRUE)) 
        {
          err = GetLastError();
          printf("Error %u reading from input file.\n", err);
          return err;
        }
    
        if (byte_count != bytes_to_transfer)
        {
          err = GetLastError();
          printf("Internal error - partial read.  Last error code %u.\n", err);
          printf("bytes_to_transfer = %u; byte_count = %u.\n", bytes_to_transfer, byte_count);
          if (byte_count == 0) return ERROR_INVALID_FUNCTION;
          bytes_to_transfer = byte_count;
        }
    
        if (!WriteFile(houtput, buffer, bytes_to_transfer, NULL, &overlapped)) 
        {
          err = GetLastError();
          if (err != ERROR_IO_PENDING)
          {
            printf("Error %u initiating write to output disk.\n", err);
            return err;
          }
        }
    
        if (!GetOverlappedResult(houtput, &overlapped, &byte_count, TRUE)) 
        {
          err = GetLastError();
          printf("Error %u writing to output disk.\n", err);
          return err;
        }
    
        if (byte_count != bytes_to_transfer)
        {
          printf("Internal error - partial write.\n");
          printf("bytes_to_transfer = %u; byte_count = %u.\n", bytes_to_transfer, byte_count);
          return ERROR_INVALID_FUNCTION;
        }
    
        offset.QuadPart += bytes_to_transfer;
      }
    
      if (transfer_length.QuadPart == source_disklength.Length.QuadPart)
      {
        overlapped.Offset = offset.LowPart;
        overlapped.OffsetHigh = offset.HighPart;
    
        if (!ReadFile(hinput, buffer, source_diskgeometry.BytesPerSector, NULL, &overlapped)) 
        {
          err = GetLastError();
          if (err == ERROR_HANDLE_EOF)
          {
            printf("Copy successfully completed.\n");      
            return 0;
          }
          printf("Error %u initiating read from input disk past end of file.\n", err);
          return err;
        }
    
        if (!GetOverlappedResult(hinput, &overlapped, &byte_count, TRUE)) 
        {
          err = GetLastError();
          if (err == ERROR_HANDLE_EOF)
          {
            printf("Copy successfully completed.\n");
            return 0;
          }
          printf("Error %u reading from input disk past end of file.\n", err);
          return err;
        }
    
        if (byte_count == 0)
        {
          printf("Copy successfully completed.\n"); 
          return 0;
        }
    
        printf("WARNING: the expected amount of data was successfully copied,\n"
               "but end of file not detected on input disk.  The copy might\n"
               "not be complete.");
    
        result = ERROR_MORE_DATA;
        return 0;
      }
    
      printf("Copy successfully completed.\n");
      return 0;
    }
    
    int wmain(int argc, wchar_t ** argv)
    {
      if (argc < 4)
      {
        printf("Syntax: \n"
          "To save an image of a physical drive:\n"
          "diskimage /save \\\\.\\PhysicalDrive0 file.img\n"
          "diskimage /save \\\\.\\A: file.img\n"
          "To write from an image file to a physical drive:\n"
          "diskimage /write file.img \\\\.\\PhysicalDrive0\n"
          "diskimage /write file.img \\\\.\\A:\n"
          "To clone input drive 0 to output drive 1:\n"
          "diskimage /clone \\\\.\\PhysicalDrive0 \\\\.\\PhysicalDrive1\n"
          );
        return 1;
      }
      if (_wcsicmp(argv[1], L"/save") == 0)
      {
        return save(argv[2], argv[3]);
      }
      else if (_wcsicmp(argv[1], L"/write") == 0)
      {
        return write(argv[2], argv[3]);
      }
      else if (_wcsicmp(argv[1], L"/clone") == 0)
      {
        return clone(argv[2], argv[3]);
      }
      else
      {
        printf("Invalid argument.  Use /? for syntax help.\n");
        return 1;
      }
    }
    

    【讨论】:

    • 我刚试过这个(在 Win7 上以管理员身份运行)。对 WriteFile 的调用一开始是成功的(我正在分块写入),但似乎在写入 MBR 后不久的某个时间点,我从 WriteFile 获得了 ERROR_ACCESS_DENIED 返回码。我注意到资源管理器已经安装了第一个分区。即使我从具有 0 个分区的 USB 驱动器开始,也会发生同样的事情。这是我打开 USB 进行写入的调用。 HANDLE hHandleUSB = CreateFile(_T("\\\\.\\PhysicalDrive1"), GENERIC_READ|GENERIC_WRITE,0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    • 您可能需要使用 FSCTL_LOCK_VOLUME 而不是我最初建议的 IOCTL_VOLUME_OFFLINE。另外,您还记得扇区对齐要求吗?操作必须是扇区对齐的,操作长度必须是扇区大小的倍数;此外,内存中缓冲区的地址必须是扇区大小的倍数。我添加了一份工作代码的副本(未在 USB 上测试,但在这方面它与硬盘应该没有太大区别)所以希望这会有所帮助。
    • 是的-我先做了 FSCTL_DISMOUNT_VOLUME,然后是 FSCTL_LOCK_VOLUME(不是 100% 确定是否都需要),而且它有效!谢谢。
    • 我以管理员身份在 64 位 Windows 7 上尝试了上述代码。文件/save 的设备(第二个硬盘)运行良好。到设备/write 的文件失败,出现“错误 5 开始写入输出磁盘。”。它还导致“Microsoft Security Essentials”弹出,提供向 Microsoft 报告可执行文件!
    • 当我在执行/write 之前手动删除了卷时,它确实工作正常。我想我只需要玩 FSCTL_DISMOUNT_VOLUME。
    猜你喜欢
    • 2011-03-24
    • 2023-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 2017-01-27
    • 2019-10-25
    • 1970-01-01
    相关资源
    最近更新 更多