2017-05-22 5 views
3

Meine Anforderung ist Laufwerksvolumen durch Programm zu erweitern. Wenn ich IOCTL_DISK_GROW_PARTITION in DeviceIO verwendete, um es zu erweitern, zeigt die Datenträger-Verwaltung die neue geänderte Größe an, während die Größe des Laufwerks in This PC (Arbeitsplatz) unverändert bleibt.So erweitern Sie ein Volume programmatisch

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 
    ); 

Durch einige Analyse fand ich, dass während der Verwendung dieses API des MBR der Platte geändert wird, aber das Cluster-Bitmap des Laufwerks nicht geändert wird. Ich möchte wissen, wie diese DeviceIO richtig verwendet wird, um ein Volume oder eine andere API für denselben Prozess zu erweitern.

+0

als nächstes mit 'IOCTL_DISK_GROW_PARTITION' Sie nur Partition von Platte Ansicht erstrecken. aber Sie müssen auch das Dateisystem erweitern, das diese Partition gemountet hat. Ich denke, brauchen Sie ['FSCTL_EXTEND_VOLUME'] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa364564 (v = vs.85) .aspx) für diese * nach * erweitern Sie die Partition – RbMm

+0

* Die neue Volume-Größe muss mindestens einen Cluster größer als die vorherige Volume-Größe sein. Die zugrunde liegende Partition muss über genügend Sektoren verfügen, um das erweiterte Volume zu enthalten. Wenn nicht, kann IOCTL_DISK_GROW_PARTITION verwendet werden, wenn das zugrunde liegende Gerät über genügend freien Speicherplatz verfügt. * - Versuchen Sie also 'FSCTL_EXTEND_VOLUME' nach' IOCTL_DISK_GROW_PARTITION' – RbMm

+0

und verwenden Sie ['IOCTL_DISK_UPDATE_DRIVE_SIZE'] (https://msdn.microsoft.com/en-us /library/windows/hardware/ff560419(v=vs.85).aspx) zwischen "IOCTL_DISK_GROW_PARTITION" und "FSCTL_EXTEND_VOLUME" – RbMm

Antwort

2

müssen verstehen, unterscheiden sich zwischen Datenträger Treiber, die Informationen über Datenträger-Layout und Partitionen (Größe, Offset vom Datenträger beginnen, Stil (gpt oder mbr)) und Dateisystem, die diese Partition mounten.

IOCTL_DISK_GROW_PARTITION - Dieses ioctl wird vom Festplattentreiber und der Partitionserweiterung behandelt, aber dies kann keine Auswirkungen auf das Dateisystem haben, die nicht mit ioctl umgehen und überhaupt nicht wissen, dass die Partition erweitert wurde. also brauchst du zusätzlich ioctl FSCTL_EXTEND_VOLUME - dieses ioctl sende schon und handle nach file-system.

so dass, wenn wir die nächsten Schritte

  1. IOCTL_DISK_GROW_PARTITION mit DISK_GROW_PARTITION als Eingangspuffer senden zu tun haben
  2. IOCTL_DISK_UPDATE_DRIVE_SIZE mit DISK_GEOMETRY als Ausgangspuffer tatsächlichen
  3. senden IOCTL_DISK_GET_PARTITION_INFO_EX mit PARTITION_INFORMATION_EX als Ausgabe senden für bekommen Größe von Partition jetzt.
  4. berechnen neue Größe des Volumens, in Sektoren

    LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart/dg.BytesPerSector;

    (dg wir bei Schritt 2 und PartitionEntry in Schritt 3 bekam)

  5. schließlich FSCTL_EXTEND_VOLUME verwenden

voller Code c ein wie

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(); 
} 
Verwandte Themen