Как записать образ, содержащий несколько разделов, на USB-накопитель в Windows с помощью C ++

В Windows вы можете увидеть только первый раздел на съемном носителе. Я хочу написать программу на C ++, которая может записывать образ, содержащий MBR и 2 раздела данных, на USB-накопитель. Мне не нужно, чтобы второй раздел был доступен для просмотра в Windows - мне просто нужно иметь возможность записать это необработанное изображение на USB-накопитель из Windows / C ++, чтобы позже, при запуске в Linux, можно было увидеть 2 раздела.

Я читал об установке драйвера фильтра, который в конечном итоге будет рассматривать съемный носитель как фиксированный, что было бы неплохо для чтения, но я просто хочу записать этот образ с минимальным вмешательством в компьютер пользователя. Могу ли я получить доступ к необработанному USB-накопителю, начиная с первого сектора, и просто записать MBR, а затем два раздела данных?


person Corey Velan    schedule 21.02.2013    source источник


Ответы (1)


Если у вас есть для этого достаточные права, вы можете открыть дескриптор для записи непосредственно на USB-накопитель, используя _ 1_ с именем файла, например \\.\PhysicalDrive2.

Вам нужно будет выяснить номер физического диска. Если у вас есть буква диска, вы можете открыть дескриптор тома, используя имя файла, например \\?\D:, а затем использовать _ 4_, чтобы определить номера физических дисков, связанных с томом.

Вам может потребоваться сначала размонтировать существующий том (если есть). Я не уверен, что лучше всего, но вы можете попробовать использовать _ 5_.

Изменить: вот код, который я использую для создания образа диска, хотя я не припомню, пробовал ли я когда-нибудь его на USB-диске. Общественное достояние, но без гарантий, явных или подразумеваемых и т. Д. (Просматривая код, я замечаю, что я явно не проверял размер сектора, чтобы убедиться, что буфер и операции чтения / записи правильно выровнены. Это не должно '' На практике это может быть проблемой, потому что самый большой размер сектора, который обычно используется, составляет 4 КБ, и это также размер страницы памяти в 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;
  }
}
person Harry Johnston    schedule 21.02.2013
comment
Я просто пробовал это (на Win7 под управлением администратора). Вызов WriteFile сначала выполняется успешно (я пишу кусками), но кажется, что в какой-то момент вскоре после записи MBR я получаю код возврата ERROR_ACCESS_DENIED из WriteFile. Я заметил, что проводник смонтировал первый раздел. То же самое происходит, даже если я начинаю с USB-накопителя с 0 разделами. Вот звонок, где я открываю USB для записи. HANDLE hHandleUSB = CreateFile (_T (\\\\. \\ PhysicalDrive1), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); <код> - person Corey Velan; 24.02.2013
comment
Возможно, вам придется использовать FSCTL_LOCK_VOLUME, а не IOCTL_VOLUME_OFFLINE, как я изначально предлагал. Кроме того, вы помните требования к выравниванию секторов? Операции должны быть выровнены по секторам, а длина операции должна быть кратной размеру сектора; кроме того, адрес буфера в памяти должен быть кратным размеру сектора. Я добавил копию рабочего кода (не тестировался на USB, но в этом отношении он не должен сильно отличаться от жесткого диска), так что, надеюсь, это поможет. - person Harry Johnston; 25.02.2013
comment
Ага, я сделал FSCTL_DISMOUNT_VOLUME, а затем FSCTL_LOCK_VOLUME (не уверен на 100%, требуются ли оба), и это работает! Спасибо. - person Corey Velan; 01.03.2013
comment
Я попробовал приведенный выше код, как администратор, на 64-битной Windows 7. Устройство (второй жесткий диск) для файла /save работало нормально. Ошибка передачи файла на устройство /write из-за ошибки 5 при запуске записи на выходной диск. Это также привело к появлению всплывающего окна Microsoft Security Essentials, предлагающего сообщить о исполняемом файле в Microsoft! - person fadedbee; 25.11.2014
comment
Когда я вручную удалил том перед выполнением /write. Думаю, мне просто нужно поиграть с FSCTL_DISMOUNT_VOLUME. - person fadedbee; 25.11.2014
comment
Использование FSCTL_DISMOUNT_VOLUME перед FSCTL_LOCK_VOLUME не помогает. FSCTL_DISMOUNT_VOLUME возвращает успех, но запись по-прежнему не выполняется с ошибкой 5, как и раньше. - person fadedbee; 25.11.2014
comment
Может быть проблема в том, что я пытаюсь размонтировать весь диск, когда я хочу размонтировать на нем разделы / файловые системы / тома? (umount /dev/sdb против umount /dev/sdb1 в Linux.) - person fadedbee; 25.11.2014
comment
Оно работает! Мне пришлось FSCTL_DISMOUNT_VOLUME на L"\\\\?\\E:", а не на L"\\\\.\\PhysicalDrive2". - person fadedbee; 25.11.2014