2017-05-22 19 views
3

내 요구 사항은 프로그램을 통해 드라이브 볼륨을 확장하는 것입니다. DeviceIO에서 IOCTL_DISK_GROW_PARTITION을 사용하여 확장 한 경우이 PC (내 컴퓨터)의 드라이브 크기가 변경되지 않은 상태에서 디스크 관리에 새로운 수정 된 크기가 표시됩니다. 나는 디스크의 MBR이 수정이 API하지만 드라이브의 클러스터 비트 맵을 사용하는 동안하는 것은 변경되지 않습니다 발견 몇 가지 분석을 통해프로그래밍 방식으로 볼륨을 확장하는 방법

BOOL DeviceIoControl(
     (HANDLE) hDevice,   // handle to device 
     IOCTL_DISK_GROW_PARTITION, // dwIoControlCode 
     (LPVOID) lpInBuffer,   // input buffer 
     (DWORD) nInBufferSize,  // size of the input buffer 
     NULL,      // lpOutBuffer 
     0,       // nOutBufferSize 
     (LPDWORD) lpBytesReturned, // number of bytes returned 
     (LPOVERLAPPED) lpOverlapped // OVERLAPPED structure 
    ); 

. 이 DeviceIO를 사용하여 볼륨이나 다른 API를 확장하여 동일한 프로세스를 수행하는 올바른 방법을 알고 싶습니다.

+0

'IOCTL_DISK_GROW_PARTITION'을 사용하면 디스크 드라이브보기에서 파티션 만 확장 할 수 있습니다. 하지만이 파티션을 마운트 한 파일 시스템도 확장해야합니다. 이 * * 후에 파티션을 확장하려면 [F2STL_EXTEND_VOLUME'] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa364564(v=vs.85).aspx)을 사용해야한다고 생각합니다. – RbMm

+0

* 새 볼륨 크기는 이전 볼륨 크기보다 적어도 하나 큰 클러스터 여야합니다. 기본 파티션에는 확장 볼륨을 포함 할 수있는 충분한 섹터가 있어야합니다. IOCTL_DISK_GROW_PARTITION은 기본 장치에 충분한 공간이있는 경우 사용할 수 있습니다. * - 따라서 IOCTL_DISK_GROW_PARTITION 뒤에 'FSCTL_EXTEND_VOLUME'을 시도하십시오. – RbMm

+0

['IOCTL_DISK_UPDATE_DRIVE_SIZE'] (https://msdn.microsoft.com/en-us)를 사용해야합니다. /library/windows/hardware/ff560419(v=vs.85).aspx)'IOCTL_DISK_GROW_PARTITION'과'FSCTL_EXTEND_VOLUME' 사이 – RbMm

답변

2

은 디스크 레이아웃과 파티션 (디스크 크기, 디스크 시작 오프셋, 스타일 (gpt 또는 mbr))에 대한 정보를 유지하는 디스크 드라이버와이 파티션을 마운트하는 파일 시스템간에 다른 점을 이해해야합니다.

IOCTL_DISK_GROW_PARTITION -이 ioctl은 디스크 드라이버와 확장 파티션에 의해 처리되지만이 ioctl을 처리하지 않고 파일 시스템에 영향을 줄 수는 없으며 파티션이 확장되었습니다. 그래서 ioctl을 추가적으로 사용해야한다. FSCTL_EXTEND_VOLUME -이 ioctl은 이미 파일 시스템에 보내고 처리한다.

우리는 다음 단계

  1. 실제 얻을 수에 대한 출력으로 PARTITION_INFORMATION_EXIOCTL_DISK_GET_PARTITION_INFO_EX을 보내 출력 버퍼로 DISK_GEOMETRYIOCTL_DISK_UPDATE_DRIVE_SIZE을 보내 입력 버퍼로 DISK_GROW_PARTITIONIOCTL_DISK_GROW_PARTITION를 전송을 할 필요가 그렇다면 이제 파티션의 크기.
  2. LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart/dg.BytesPerSector;

    (우리가 3 단계에서 2 단계 및 PartitionEntry에있어 DG)

  3. 마지막으로 사용하는 분야에서, 볼륨의 새 크기를 계산 FSCTL_EXTEND_VOLUME

전체 코드 c 다음과 같음

int __cdecl SortPartitions(PPARTITION_INFORMATION_EX PartitionEntry1, PPARTITION_INFORMATION_EX PartitionEntry2) 
{ 
    if (!PartitionEntry1->PartitionNumber) return PartitionEntry2->PartitionNumber ? -1 : 0; 
    if (!PartitionEntry2->PartitionNumber) return +1; 
    if (PartitionEntry1->StartingOffset.QuadPart < PartitionEntry2->StartingOffset.QuadPart) return -1; 
    if (PartitionEntry1->StartingOffset.QuadPart > PartitionEntry2->StartingOffset.QuadPart) return +1; 
    return 0; 
} 

DWORD ExtendTest(HANDLE hDisk) 
{ 
    STORAGE_DEVICE_NUMBER sdn; 

    ULONG dwBytesRet; 

    if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL)) 
    { 
     return GetLastError(); 
    } 

    if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0) 
    { 
     return ERROR_GEN_FAILURE; 
    } 

    GET_LENGTH_INFORMATION gli; 

    if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), &dwBytesRet, NULL)) 
    { 
     return GetLastError(); 
    } 

    DbgPrint("Disk Length %I64x (%I64u)\n", gli.Length.QuadPart, gli.Length.QuadPart); 

    PVOID stack = alloca(guz); 

    union { 
     PVOID buf; 
     PDRIVE_LAYOUT_INFORMATION_EX pdli; 
    }; 

    ULONG cb = 0, rcb, PartitionCount = 4; 

    for (;;) 
    { 
     if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount]))) 
     { 
      cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack); 
     } 

     if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL)) 
     { 
      if (PartitionCount = pdli->PartitionCount) 
      { 
       PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry; 

       qsort(PartitionEntry, PartitionCount, sizeof(PARTITION_INFORMATION_EX), 
        (int (__cdecl *)(const void *, const void *))SortPartitions); 

       do 
       { 
        if (!PartitionEntry->PartitionNumber) 
        { 
         continue; 
        } 

        LARGE_INTEGER EndOffset; 
        LARGE_INTEGER MaximumOffset = PartitionCount != 1 ? (PartitionEntry + 1)->StartingOffset : gli.Length; 

        EndOffset.QuadPart = PartitionEntry->StartingOffset.QuadPart + PartitionEntry->PartitionLength.QuadPart; 

        if (EndOffset.QuadPart > MaximumOffset.QuadPart) 
        { 
         //?? 
         __debugbreak(); 
        } 
        else if (EndOffset.QuadPart < MaximumOffset.QuadPart) 
        { 
         DISK_GROW_PARTITION dgp; 
         dgp.PartitionNumber = PartitionEntry->PartitionNumber; 
         dgp.BytesToGrow.QuadPart = MaximumOffset.QuadPart - EndOffset.QuadPart; 

         WCHAR sz[128]; 

         swprintf(sz, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition%u", sdn.DeviceNumber, dgp.PartitionNumber); 

         HANDLE hPartition = CreateFile(sz, FILE_READ_ACCESS|FILE_WRITE_ACCESS, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0); 

         if (hPartition != INVALID_HANDLE_VALUE) 
         { 
          // +++ begin extend 
          BOOL fOk = FALSE; 

          DISK_GEOMETRY dg; 
          if (DeviceIoControl(hPartition, IOCTL_DISK_GROW_PARTITION, &dgp, sizeof(dgp), 0, 0, &dwBytesRet, 0) && 
           DeviceIoControl(hPartition, IOCTL_DISK_UPDATE_DRIVE_SIZE, 0, 0, &dg, sizeof(dg), &dwBytesRet, 0) && 
           DeviceIoControl(hPartition, IOCTL_DISK_GET_PARTITION_INFO_EX, 0, 0, PartitionEntry, sizeof(*PartitionEntry), &dwBytesRet, 0) 
           ) 
          { 
           LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart/dg.BytesPerSector; 

           fOk = DeviceIoControl(hPartition, FSCTL_EXTEND_VOLUME, &SectorsPerPartition, 
            sizeof(SectorsPerPartition), 0, 0, &dwBytesRet, 0); 

          } 

          if (!fOk) 
          { 
           GetLastError(); 
          } 

          //--- end extend 
          CloseHandle(hPartition); 
         } 
        } 
        // else EndOffset.QuadPart == MaximumOffset.QuadPart - partition can not be extended 

       } while (PartitionEntry++, --PartitionCount); 
      } 

      return NOERROR; 
     } 

     switch (ULONG err = GetLastError()) 
     { 
     case ERROR_MORE_DATA: 
      PartitionCount = pdli->PartitionCount; 
      continue; 
     case ERROR_BAD_LENGTH: 
     case ERROR_INSUFFICIENT_BUFFER: 
      PartitionCount <<= 1; 
      continue; 
     default: 
      return err; 
     } 
    } 

} 
DWORD ExtendTest() 
{ 
    HANDLE hDisk = CreateFileW(L"\\\\?\\PhysicalDrive0", FILE_GENERIC_READ|FILE_GENERIC_WRITE, 
     FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0); 

    if (hDisk != INVALID_HANDLE_VALUE) 
    { 
     DWORD err = ExtendTest(hDisk); 
     CloseHandle(hDisk); 

     return err; 
    } 

    return GetLastError(); 
}