VirtualBox

Changeset 57196 in vbox for trunk/src/VBox/Devices/Storage


Ignore:
Timestamp:
Aug 5, 2015 2:33:52 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
101948
Message:

Storage/HBDMgmt-win: Much easier way to unmount volumes and take them offline. Getting the mount points is not required, finding the appropriate \Device\HarddiskVolume<N> device is enough to be able to unmount the volume from everything.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/HBDMgmt-win.cpp

    r57190 r57196  
    4747    /** The block device name. */
    4848    char              *pszDevice;
    49     /** Number of mountpoint handles in the array below. */
    50     unsigned           cMountpointHandles;
    51     /** Array of mountpoint handles for a particular volume or disk, variable size. */
    52     HANDLE             aMountpointHandles[1];
     49    /** Number of volumes for this block device. */
     50    unsigned           cVolumes;
     51    /** Array of handle to the volumes for unmounting and taking it offline. */
     52    HANDLE             ahVolumes[1];
    5353} HBDMGRDEV;
    5454/** Pointer to a claimed block device. */
     
    8787static void hbdMgrDevUnclaim(PHBDMGRDEV pDev)
    8888{
    89     for (unsigned i = 0; i < pDev->cMountpointHandles; i++)
     89    LogFlowFunc(("pDev=%p{%s} cVolumes=%u\n", pDev, pDev->pszDevice, pDev->cVolumes));
     90
     91    for (unsigned i = 0; i < pDev->cVolumes; i++)
    9092    {
    9193        DWORD dwReturned = 0;
    92         BOOL bRet = DeviceIoControl(pDev->aMountpointHandles[i], IOCTL_VOLUME_ONLINE, NULL, 0, NULL, 0, &dwReturned, NULL);
     94
     95        LogFlowFunc(("Taking volume %u online\n", i));
     96        BOOL bRet = DeviceIoControl(pDev->ahVolumes[i], IOCTL_VOLUME_ONLINE, NULL, 0, NULL, 0, &dwReturned, NULL);
    9397        if (!bRet)
    9498            LogRel(("HBDMgmt: Failed to take claimed volume online during cleanup: %s{%Rrc}\n",
    9599                    pDev->pszDevice, RTErrConvertFromWin32(GetLastError())));
     100
     101        CloseHandle(pDev->ahVolumes[i]);
    96102    }
    97103
     
    205211}
    206212
    207 /**
    208  * Splits the given mount point buffer into individual entries.
    209  *
    210  * @returns VBox status code.
    211  * @param   pwszMountpoints    The buffer holding the list of mountpoints separated by a null terminator,
    212  *                             the end of the list is marked with an extra null terminator.
    213  * @param   ppapwszMountpoints Where to store the array of mount points on success.
    214  * @param   pcMountpoints      Where to store the returned number of mount points on success.
    215  */
    216 static int hbdMgrSplitMountpointBuffer(PRTUTF16 pwszMountpoints, PRTUTF16 **ppapwszMountpoints, unsigned *pcMountpoints)
    217 {
    218     int rc = VINF_SUCCESS;
    219     unsigned cMountpoints = 0;
    220 
    221     *pcMountpoints = 0;
    222     *ppapwszMountpoints = NULL;
    223 
    224     /* First round, count the number of mountpoints. */
    225     PRTUTF16 pwszMountpointCur = pwszMountpoints;
    226     while (*pwszMountpointCur != L'\0')
    227     {
    228         pwszMountpointCur = (PRTUTF16)RTUtf16End(pwszMountpointCur, RTSTR_MAX);
    229         pwszMountpointCur++;
    230         cMountpoints++;
    231     }
    232 
    233     PRTUTF16 *papwszMountpoints = (PRTUTF16 *)RTMemAllocZ(cMountpoints * sizeof(PRTUTF16));
    234     if (RT_LIKELY(papwszMountpoints))
    235     {
    236         unsigned idxMountpoint = 0;
    237 
    238         pwszMountpointCur = pwszMountpoints;
    239 
    240         /* Split the buffer now. */
    241         while (   *pwszMountpointCur != L'\0'
    242                && RT_SUCCESS(rc)
    243                && idxMountpoint < cMountpoints)
    244         {
    245             papwszMountpoints[idxMountpoint] = RTUtf16Dup(pwszMountpointCur);
    246             if (!papwszMountpoints[idxMountpoint])
    247             {
    248                 rc = VERR_NO_STR_MEMORY;
    249                 break;
    250             }
    251 
    252             pwszMountpointCur = (PRTUTF16)RTUtf16End(pwszMountpointCur, RTSTR_MAX);
    253             pwszMountpointCur++;
    254             idxMountpoint++;
    255         }
    256 
    257         if (RT_SUCCESS(rc))
    258         {
    259             *pcMountpoints = cMountpoints;
    260             *ppapwszMountpoints = papwszMountpoints;
    261         }
    262         else
    263         {
    264             /* Undo everything. */
    265             while (idxMountpoint-- > 0)
    266                 RTUtf16Free(papwszMountpoints[idxMountpoint]);
    267             RTMemFree(papwszMountpoints);
    268         }
    269     }
    270     else
    271         rc = VERR_NO_MEMORY;
    272 
    273     return rc;
    274 }
    275 
    276 /**
    277  * Queries all available mount points for a given volume.
    278  *
    279  * @returns VBox status code.
    280  * @param   pwszVolNt          The volume to query the mount points for (NT namespace).
    281  * @param   ppapwszMountpoints Where to store the array of mount points on success.
    282  * @param   pcMountpoints      Where to store the returned number of mount points on success.
    283  */
    284 static int hbdMgrQueryMountpointsForVolume(PRTUTF16 pwszVolNt, PRTUTF16 **ppapwszMountpoints, unsigned *pcMountpoints)
    285 {
    286     int rc = VINF_SUCCESS;
    287     RTUTF16 awszVolume[64];
    288 
    289     /*
    290      * Volume names returned by FindFirstVolume/FindNextVolume have a very strict format looking
    291      * like \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}, so the buffer for the name can be static.
    292      */
    293     RT_ZERO(awszVolume);
    294 
    295     HANDLE hVol = FindFirstVolumeW(&awszVolume[0], RT_ELEMENTS(awszVolume));
    296     if (hVol != INVALID_HANDLE_VALUE)
    297     {
    298         do
    299         {
    300             PRTUTF16 pwszVolNtCur = NULL;
    301             rc = hbdMgrQueryNtName(awszVolume, &pwszVolNtCur);
    302             if (RT_SUCCESS(rc))
    303             {
    304                 /* If both volume names match we found the right one. */
    305                 if (!RTUtf16Cmp(pwszVolNtCur, pwszVolNt))
    306                 {
    307                     DWORD cchBufferLength = 100;
    308                     DWORD cchBufRequired = 0;
    309                     PRTUTF16 pwszVolumeMountpoints = RTUtf16Alloc(cchBufferLength * sizeof(RTUTF16));
    310                     if (pwszVolumeMountpoints)
    311                     {
    312                         BOOL bRet = GetVolumePathNamesForVolumeNameW(awszVolume, pwszVolumeMountpoints,
    313                                                                      cchBufferLength, &cchBufRequired);
    314                         if (   !bRet
    315                             && GetLastError() == ERROR_MORE_DATA)
    316                         {
    317                             /* Realloc and try again. */
    318                             RTUtf16Free(pwszVolumeMountpoints);
    319                             pwszVolumeMountpoints = RTUtf16Alloc(cchBufRequired * sizeof(RTUTF16));
    320                             if (pwszVolumeMountpoints)
    321                             {
    322                                 cchBufferLength = cchBufRequired;
    323                                 bRet = GetVolumePathNamesForVolumeNameW(awszVolume, pwszVolumeMountpoints,
    324                                                                         cchBufferLength, &cchBufRequired);
    325                             }
    326                             else
    327                                 rc = VERR_NO_STR_MEMORY;
    328                         }
    329 
    330                         if (   RT_SUCCESS(rc)
    331                             && bRet)
    332                             rc = hbdMgrSplitMountpointBuffer(pwszVolumeMountpoints, ppapwszMountpoints,
    333                                                              pcMountpoints);
    334                         else if (RT_SUCCESS(rc))
    335                             rc = RTErrConvertFromWin32(GetLastError());
    336 
    337                         RTUtf16Free(pwszVolumeMountpoints);
    338                     }
    339                     else
    340                         rc = VERR_NO_STR_MEMORY;
    341 
    342                     break;
    343                 }
    344                 else
    345                 {
    346                     RTUtf16Free(pwszVolNtCur);
    347                     RT_ZERO(awszVolume);
    348                     BOOL bRet = FindNextVolumeW(hVol, &awszVolume[0], RT_ELEMENTS(awszVolume));
    349                     if (!bRet)
    350                     {
    351                         DWORD dwRet = GetLastError();
    352                         if (dwRet == ERROR_NO_MORE_FILES)
    353                             rc = VERR_NOT_FOUND;
    354                         else
    355                             rc = RTErrConvertFromWin32(dwRet);
    356                         break;
    357                     }
    358                 }
    359             }
    360         } while (RT_SUCCESS(rc));
    361 
    362         FindVolumeClose(hVol);
    363     }
    364     else
    365         rc = RTErrConvertFromWin32(GetLastError());
    366 
    367     return rc;
    368 }
    369 
    370 static int hbdMgrQueryAllMountpointsForDisk(PRTUTF16 pwszDiskNt, PRTUTF16 **ppapwszMountpoints,
    371                                             unsigned *pcMountpoints)
     213static int hbdMgrQueryAllMountpointsForDisk(PRTUTF16 pwszDiskNt, PRTUTF16 **ppapwszVolumes,
     214                                            unsigned *pcVolumes)
    372215{
    373216    /*
     
    381224    int rc = VINF_SUCCESS;
    382225    char *pszDiskNt = NULL;
    383     unsigned cMountpoints = 0;
    384     PRTUTF16 *papwszMountpoints = NULL;
     226    unsigned cVolumes = 0;
     227    unsigned cVolumesMax = 10;
     228    PRTUTF16 *papwszVolumes = (PRTUTF16 *)RTMemAllocZ(cVolumesMax * sizeof(PRTUTF16));
     229
     230    if (!papwszVolumes)
     231        return VERR_NO_MEMORY;
    385232
    386233    rc = RTUtf16ToUtf8(pwszDiskNt, &pszDiskNt);
     
    415262                            if (RT_SUCCESS(rc))
    416263                            {
    417                                 unsigned cMountpointsCur = 0;
    418                                 PRTUTF16 *papwszMountpointsCur = NULL;
    419 
    420                                 rc = hbdMgrQueryMountpointsForVolume(pwszTargetNt, &papwszMountpointsCur,
    421                                                                      &cMountpointsCur);
    422                                 if (RT_SUCCESS(rc))
     264                                if (cVolumes == cVolumesMax)
    423265                                {
    424                                     if (!papwszMountpoints)
     266                                    /* Increase array of volumes. */
     267                                    PRTUTF16 *papwszVolumesNew = (PRTUTF16 *)RTMemAllocZ((cVolumesMax + 10) * sizeof(PRTUTF16));
     268                                    if (papwszVolumesNew)
    425269                                    {
    426                                         papwszMountpoints = papwszMountpointsCur;
    427                                         cMountpoints = cMountpointsCur;
     270                                        cVolumesMax += 10;
     271                                        papwszVolumes = papwszVolumesNew;
    428272                                    }
    429273                                    else
    430274                                    {
    431                                         PRTUTF16 *papwszMountpointsNew = (PRTUTF16 *)RTMemRealloc(papwszMountpoints,
    432                                                                                                   (cMountpoints + cMountpointsCur) * sizeof(PRTUTF16));
    433                                         if (papwszMountpointsNew)
    434                                         {
    435                                             for (unsigned i = cMountpoints; i < cMountpoints + cMountpointsCur; i++)
    436                                                 papwszMountpointsNew[i] = papwszMountpointsCur[i - cMountpoints];
    437 
    438                                             papwszMountpoints = papwszMountpointsNew;
    439                                         }
    440                                         else
    441                                         {
    442                                             for (unsigned i = 0; i < cMountpointsCur; i++)
    443                                                 RTUtf16Free(papwszMountpointsCur[i]);
    444 
    445                                             rc = VERR_NO_MEMORY;
    446                                         }
     275                                        RTUtf16Free(pwszTargetNt);
     276                                        rc = VERR_NO_MEMORY;
    447277                                    }
    448 
    449                                     RTMemFree(papwszMountpointsCur);
    450278                                }
    451279
    452                                 iPart++;
    453                                 RTUtf16Free(pwszTargetNt);
     280                                if (RT_SUCCESS(rc))
     281                                {
     282                                    Assert(cVolumes < cVolumesMax);
     283                                    papwszVolumes[cVolumes++] = pwszTargetNt;
     284                                    iPart++;
     285                                }
    454286                            }
    455287                            else if (rc == VERR_FILE_NOT_FOUND)
     
    477309    if (RT_SUCCESS(rc))
    478310    {
    479         *pcMountpoints = cMountpoints;
    480         *ppapwszMountpoints = papwszMountpoints;
     311        *pcVolumes = cVolumes;
     312        *ppapwszVolumes = papwszVolumes;
     313        LogFlowFunc(("rc=%Rrc cVolumes=%u ppapwszVolumes=%p\n", rc, cVolumes, papwszVolumes));
    481314    }
    482315    else
    483316    {
    484         for (unsigned i = 0; i < cMountpoints; i++)
    485             RTUtf16Free(papwszMountpoints[i]);
    486 
    487         RTMemFree(papwszMountpoints);
     317        for (unsigned i = 0; i < cVolumes; i++)
     318            RTUtf16Free(papwszVolumes[i]);
     319
     320        RTMemFree(papwszVolumes);
    488321    }
    489322
    490323    return rc;
     324}
     325
     326static NTSTATUS hbdMgrNtCreateFileWrapper(PRTUTF16 pwszVolume, HANDLE *phVolume)
     327{
     328    HANDLE          hVolume = RTNT_INVALID_HANDLE_VALUE;
     329    IO_STATUS_BLOCK Ios     = RTNT_IO_STATUS_BLOCK_INITIALIZER;
     330    UNICODE_STRING  NtName;
     331
     332    NtName.Buffer        = (PWSTR)pwszVolume;
     333    NtName.Length        = (USHORT)(RTUtf16Len(pwszVolume) * sizeof(RTUTF16));
     334    NtName.MaximumLength = NtName.Length + sizeof(WCHAR);
     335
     336    OBJECT_ATTRIBUTES ObjAttr;
     337    InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
     338
     339    NTSTATUS rcNt = NtCreateFile(&hVolume,
     340                                 FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
     341                                 &ObjAttr,
     342                                 &Ios,
     343                                 NULL /* Allocation Size*/,
     344                                 FILE_ATTRIBUTE_NORMAL,
     345                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
     346                                 FILE_OPEN,
     347                                 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
     348                                 NULL /*EaBuffer*/,
     349                                 0 /*EaLength*/);
     350    if (NT_SUCCESS(rcNt))
     351        rcNt = Ios.Status;
     352
     353    if (NT_SUCCESS(rcNt))
     354        *phVolume = hVolume;
     355
     356    return rcNt;
    491357}
    492358
     
    536402    if (!fIsBlockDevice)
    537403        fIsBlockDevice = RTStrNICmp(pszFilename, "\\\\.\\Harddisk", sizeof("\\\\.\\Harddisk") - 1) == 0 ? true : false;
     404
     405    LogFlowFunc(("returns %s -> %RTbool\n", pszFilename, fIsBlockDevice));
    538406    return fIsBlockDevice;
    539407}
     
    559427            if (RT_SUCCESS(rc))
    560428            {
    561                 PRTUTF16 *papwszMountpoints = NULL;
    562                 unsigned cMountpoints = 0;
     429                PRTUTF16 *papwszVolumes = NULL;
     430                unsigned cVolumes = 0;
    563431
    564432                /* Complete disks need to be handled differently. */
    565433                if (!RTStrNCmp(pszFilename, "\\\\.\\PhysicalDrive", sizeof("\\\\.\\PhysicalDrive") - 1))
    566                     rc = hbdMgrQueryAllMountpointsForDisk(pwszVolNt, &papwszMountpoints, &cMountpoints);
     434                {
     435                    rc = hbdMgrQueryAllMountpointsForDisk(pwszVolNt, &papwszVolumes, &cVolumes);
     436                    RTUtf16Free(pwszVolNt);
     437                }
    567438                else
    568                     rc = hbdMgrQueryMountpointsForVolume(pwszVolNt, &papwszMountpoints, &cMountpoints);
     439                {
     440                    papwszVolumes = &pwszVolNt;
     441                    cVolumes = 1;
     442                }
    569443
    570444                if (RT_SUCCESS(rc))
    571445                {
    572                     /** @todo: Unmount everything and take volume offline. */
    573 
    574                     for (unsigned i = 0; i < cMountpoints; i++)
    575                         RTUtf16Free(papwszMountpoints[i]);
    576 
    577                     RTMemFree(papwszMountpoints);
     446#ifdef LOG_ENABLED
     447                    for (unsigned i = 0; i < cVolumes; i++)
     448                        LogFlowFunc(("Volume %u: %ls\n", i, papwszVolumes[i]));
     449#endif
     450                    pDev = (PHBDMGRDEV)RTMemAllocZ(RT_OFFSETOF(HBDMGRDEV, ahVolumes[cVolumes]));
     451                    if (pDev)
     452                    {
     453                        pDev->cVolumes = 0;
     454                        pDev->pszDevice = RTStrDup(pszFilename);
     455                        if (pDev->pszDevice)
     456                        {
     457                            for (unsigned i = 0; i < cVolumes; i++)
     458                            {
     459                                HANDLE hVolume;
     460
     461                                NTSTATUS rcNt = hbdMgrNtCreateFileWrapper(papwszVolumes[i], &hVolume);
     462                                if (NT_SUCCESS(rcNt))
     463                                {
     464                                    DWORD dwReturned = 0;
     465
     466                                    Assert(hVolume != INVALID_HANDLE_VALUE);
     467                                    BOOL bRet = DeviceIoControl(hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwReturned, NULL);
     468                                    if (bRet)
     469                                    {
     470                                         bRet = DeviceIoControl(hVolume, IOCTL_VOLUME_OFFLINE, NULL, 0, NULL, 0, &dwReturned, NULL);
     471                                         if (bRet)
     472                                            pDev->ahVolumes[pDev->cVolumes++] = hVolume;
     473                                         else
     474                                            rc = RTErrConvertFromWin32(GetLastError());
     475                                    }
     476                                    else
     477                                        rc = RTErrConvertFromWin32(GetLastError());
     478
     479                                    if (RT_FAILURE(rc))
     480                                        CloseHandle(hVolume);
     481                                }
     482                                else
     483                                    rc = RTErrConvertFromNtStatus(rcNt);
     484                            }
     485                        }
     486                        else
     487                            rc = VERR_NO_STR_MEMORY;
     488
     489                        if (RT_SUCCESS(rc))
     490                        {
     491                            RTSemFastMutexRequest(pThis->hMtxList);
     492                            RTListAppend(&pThis->ListClaimed, &pDev->ListNode);
     493                            RTSemFastMutexRelease(pThis->hMtxList);
     494                        }
     495                        else
     496                        {
     497                            /* Close all open handles and take the volumes online again. */
     498                            for (unsigned i = 0; i < pDev->cVolumes; i++)
     499                            {
     500                                DWORD dwReturned = 0;
     501                                BOOL bRet = DeviceIoControl(pDev->ahVolumes[i], IOCTL_VOLUME_ONLINE, NULL, 0, NULL, 0, &dwReturned, NULL);
     502                                if (!bRet)
     503                                    LogRel(("HBDMgmt: Failed to take claimed volume online during cleanup: %s{%Rrc}\n",
     504                                            pDev->pszDevice, RTErrConvertFromWin32(GetLastError())));
     505
     506                                CloseHandle(pDev->ahVolumes[i]);
     507                            }
     508                            if (pDev->pszDevice)
     509                                RTStrFree(pDev->pszDevice);
     510                            RTMemFree(pDev);
     511                        }
     512                    }
     513                    else
     514                        rc = VERR_NO_MEMORY;
     515
     516                    for (unsigned i = 0; i < cVolumes; i++)
     517                        RTUtf16Free(papwszVolumes[i]);
     518
     519                    RTMemFree(papwszVolumes);
    578520                }
    579 
    580                 RTUtf16Free(pwszVolNt);
    581521            }
    582522
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette