VirtualBox

Ignore:
Timestamp:
May 23, 2008 11:51:22 AM (17 years ago)
Author:
vboxsync
Message:

New internal command 'renamevmdk' in VBoxManage with corresponding vmdk backend API.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r9047 r9071  
    36463646
    36473647/**
    3648  * Allocates a new copy of the given UTF-8 string using RTMemTmpAlloc().
     3648 * Replaces a fragment of a string with the specified string.
    36493649 *
    36503650 * @returns Pointer to the allocated UTF-8 string.
    3651  * @param   pszString       UTF-8 string to duplicate.
     3651 * @param   pszWhere        UTF-8 string to search in.
     3652 * @param   pszWhat         UTF-8 string to search for.
     3653 * @param   pszByWhat       UTF-8 string to replace the found string with.
    36523654 */
    3653 static char * vmdkStrTmpDup(const char *pszString)
    3654 {
    3655     Assert(VALID_PTR(pszString));
    3656     size_t cch = strlen(pszString) + 1;
    3657     char *psz = (char *)RTMemTmpAlloc(cch);
    3658     if (psz)
    3659         memcpy(psz, pszString, cch);
    3660     return psz;
     3655static char * vmdkStrReplace(const char *pszWhere, const char *pszWhat, const char *pszByWhat)
     3656{
     3657    Assert(VALID_PTR(pszWhere));
     3658    Assert(VALID_PTR(pszWhat));
     3659    Assert(VALID_PTR(pszByWhat));
     3660    char *pszFoundStr = strstr(pszWhere, pszWhat);
     3661    if (!pszFoundStr)
     3662        return NULL;
     3663    size_t cFinal = strlen(pszWhere) + 1 + strlen(pszByWhat) - strlen(pszWhat);
     3664    char *pszNewStr = (char *)RTMemAlloc(cFinal);
     3665    if (pszNewStr)
     3666    {
     3667        char *pszTmp = pszNewStr;
     3668        memcpy(pszTmp, pszWhere, pszFoundStr - pszWhere);
     3669        pszTmp += pszFoundStr - pszWhere;
     3670        memcpy(pszTmp, pszByWhat, strlen(pszByWhat));
     3671        pszTmp += strlen(pszByWhat);
     3672        strcpy(pszTmp, pszFoundStr + strlen(pszWhat));
     3673    }
     3674    return pszNewStr;
    36613675}
    36623676
     
    36653679{
    36663680    LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
    3667     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3668     int rc = VINF_SUCCESS;
    3669     char **apszOldExtentBaseNames;
    3670     char **apszOldExtentFullNames;
    3671     char **apszNewExtentFullNames;
    3672     char *pszOldImageName;
    3673     char *pszNewImageName;
    3674     bool fImageFreed = false;
     3681
     3682    PVMDKIMAGE  pImage  = (PVMDKIMAGE)pBackendData;
     3683    int               rc = VINF_SUCCESS;
     3684    char   **apszOldName = NULL;
     3685    char   **apszNewName = NULL;
     3686    char  **apszNewLines = NULL;
     3687    char *pszOldDescName = NULL;
     3688    bool     fImageFreed = false;
     3689    bool   fEmbeddedDesc = false;
     3690    unsigned    cExtents = pImage->cExtents;
     3691    char *pszNewBasename;
     3692    char *pszOldBasename;
     3693    unsigned i, line;
     3694    VMDKDESCRIPTOR DescriptorCopy;
     3695    VMDKEXTENT     ExtentCopy;
     3696
     3697    memset(&DescriptorCopy, 0, sizeof(DescriptorCopy));
    36753698
    36763699    /* Check arguments. */
     
    36853708
    36863709    /*
    3687      * Allocate an array to store old extent names in case we have to roll back the changes.
    3688      * Everything is initialized with zeros. We actually save stuff when and if we change it.
     3710     * Allocate an array to store both old and new names of renamed files
     3711     * in case we have to roll back the changes. Arrays are initialized
     3712     * with zeros. We actually save stuff when and if we change it.
    36893713     */
    3690     apszOldExtentBaseNames = (char **)RTMemTmpAllocZ(pImage->cExtents * sizeof(char*));
    3691     apszOldExtentFullNames = (char **)RTMemTmpAllocZ(pImage->cExtents * sizeof(char*));
    3692     apszNewExtentFullNames = (char **)RTMemTmpAllocZ(pImage->cExtents * sizeof(char*));
    3693     if (!apszOldExtentBaseNames || !apszOldExtentFullNames || !apszNewExtentFullNames)
    3694     {
    3695         if (apszOldExtentBaseNames)
    3696             RTMemTmpFree(apszOldExtentBaseNames);
    3697         if (apszOldExtentFullNames)
    3698             RTMemTmpFree(apszOldExtentFullNames);
    3699         if (apszNewExtentFullNames)
    3700             RTMemTmpFree(apszNewExtentFullNames);
     3714    apszOldName  = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
     3715    apszNewName  = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
     3716    apszNewLines = (char **)RTMemTmpAllocZ((cExtents) * sizeof(char*));
     3717    if (!apszOldName || !apszNewName || !apszNewLines)
     3718    {
    37013719        rc = VERR_NO_MEMORY;
    37023720        goto out;
    37033721    }
    3704     pszOldImageName = NULL;
    3705     pszNewImageName = NULL;
    3706 
    3707     do {
    3708         /* Basename strings needed for constructing the extent names. */
    3709         char *pszBasenameSubstr = RTPathFilename(pszFilename);
    3710         Assert(pszBasenameSubstr);
    3711         size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
    3712 
    3713         /* Loop through each VMDKEXTENT in VMDKIMAGE->pExtents using VMDKIMAGE->cExtents. */
    3714         for (unsigned i = 0; i < pImage->cExtents; i++)
    3715         {
    3716             PVMDKEXTENT pExtent = &pImage->pExtents[i];
    3717 
    3718             /* @todo Store pExtent->pszFullname in array for future reference. */
    3719             /* @todo Store pExtent->pszBasename in array for future reference. */
    3720 
    3721             /* @todo This is copy/paste code, move to seperate function. */
    3722             /* Determine the new file name. */
    3723             /* Set up fullname/basename for extent description. Cannot use StrDup
    3724              * for basename, as it is not guaranteed that the memory can be freed
    3725              * with RTMemTmpFree, which must be used as in other code paths
    3726              * StrDup is not usable. */
    3727             if (pImage->cExtents == 1 && pImage->enmImageType != VD_IMAGE_TYPE_FIXED)
    3728             {
    3729                 char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
    3730                 if (!pszBasename)
    3731                 {
    3732                     rc = VERR_NO_MEMORY;
    3733                     break;
    3734                 }
    3735                 memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
    3736                 /* Save the old name in case we need to roll back. */
    3737                 apszOldExtentBaseNames[i] = vmdkStrTmpDup(pExtent->pszBasename);
    3738                 pExtent->pszBasename = pszBasename;
    3739             }
    3740             else
    3741             {
    3742                 char *pszBasenameExt = RTPathExt(pszBasenameSubstr);
    3743                 char *pszBasenameBase = RTStrDup(pszBasenameSubstr);
    3744                 RTPathStripExt(pszBasenameBase);
    3745                 char *pszTmp;
    3746                 size_t cbTmp;
    3747                 if (pImage->enmImageType == VD_IMAGE_TYPE_FIXED)
    3748                 {
    3749                     if (pImage->cExtents == 1)
    3750                         rc = RTStrAPrintf(&pszTmp, "%s-flat%s", pszBasenameBase,
    3751                                           pszBasenameExt);
    3752                     else
    3753                         rc = RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase,
    3754                                           i+1, pszBasenameExt);
    3755                 }
    3756                 else
    3757                     rc = RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, i+1,
    3758                                       pszBasenameExt);
    3759                 RTStrFree(pszBasenameBase);
    3760                 if (VBOX_FAILURE(rc))
    3761                     break;
    3762                 cbTmp = strlen(pszTmp) + 1;
    3763                 char *pszBasename = (char *)RTMemTmpAlloc(cbTmp);
    3764                 if (!pszBasename)
    3765                 {
    3766                     rc = VERR_NO_MEMORY;
    3767                     break;
    3768                 }
    3769                 memcpy(pszBasename, pszTmp, cbTmp);
    3770                 RTStrFree(pszTmp);
    3771                 /* Save the old name in case we need to roll back. */
    3772                 apszOldExtentBaseNames[i] = vmdkStrTmpDup(pExtent->pszBasename);
    3773                 pExtent->pszBasename = pszBasename;
    3774                 /* @todo ??? cbExtent = RT_MIN(cbRemaining, VMDK_2G_SPLIT_SIZE); */
    3775             }
    3776             char *pszBasedirectory = RTStrDup(pImage->pszFilename);
    3777             RTPathStripFilename(pszBasedirectory);
    3778             char *pszFN;
    3779             rc = RTStrAPrintf(&pszFN, "%s%c%s", pszBasedirectory, RTPATH_SLASH,
    3780                               pExtent->pszBasename);
    3781             RTStrFree(pszBasedirectory);
    3782             if (VBOX_FAILURE(rc))
    3783                 break;
    3784 
    3785             /* Close the VMDKEXTENT. */
    3786             vmdkFileClose(pImage, &pExtent->File, false);
    3787 
    3788             /* Rename the file. */
    3789             rc = RTFileMove(pExtent->pszFullname, pszFN, 0);
    3790             if (VBOX_FAILURE(rc))
    3791                 break;
    3792 
    3793             /* Save both names in case we need to roll back. */
    3794             apszOldExtentFullNames[i] = RTStrDup(pExtent->pszFullname);
    3795             apszNewExtentFullNames[i] = RTStrDup(pszFN);
    3796             pExtent->pszFullname = pszFN;
    3797         }
    3798 
     3722
     3723    /* Save the descriptor size and position. */
     3724    if (pImage->pDescData)
     3725    {
     3726        /* Separate descriptor file. */
     3727        fEmbeddedDesc = false;
     3728    }
     3729    else
     3730    {
     3731        /* Embedded descriptor file. */
     3732        ExtentCopy  = pImage->pExtents[0];
     3733        fEmbeddedDesc = true;
     3734    }
     3735    /* Save the descriptor content. */
     3736    DescriptorCopy.cLines = pImage->Descriptor.cLines;
     3737    for (i = 0; i < DescriptorCopy.cLines; i++)
     3738    {
     3739        DescriptorCopy.aLines[i] = RTStrDup(pImage->Descriptor.aLines[i]);
     3740        if (!DescriptorCopy.aLines[i])
     3741        {
     3742            rc = VERR_NO_MEMORY;
     3743            goto out;
     3744        }
     3745    }
     3746
     3747    /* Prepare both old and new base names used for string replacement. */
     3748    pszNewBasename = RTStrDup(RTPathFilename(pszFilename));
     3749    RTPathStripExt(pszNewBasename);
     3750    pszOldBasename = RTStrDup(RTPathFilename(pImage->pszFilename));
     3751    RTPathStripExt(pszOldBasename);
     3752
     3753    /* --- Up to this point we have not done any damage yet. --- */
     3754
     3755    /* Save the old name for easy access to the old descriptor file. */
     3756    pszOldDescName = RTStrDup(pImage->pszFilename);
     3757
     3758    /* Rename the extents. */
     3759    for (i = 0, line = pImage->Descriptor.uFirstExtent;
     3760        i < cExtents;
     3761        i++, line = pImage->Descriptor.aNextLines[line])
     3762    {
     3763        PVMDKEXTENT pExtent = &pImage->pExtents[i];
     3764        /* Assume that vmdkStrReplace will fail. */
     3765        rc = VERR_NO_MEMORY;
     3766        /* Update the descriptor. */
     3767        apszNewLines[i] = vmdkStrReplace(pImage->Descriptor.aLines[line],
     3768            pszOldBasename, pszNewBasename);
     3769        if (!apszNewLines[i])
     3770            goto rollback;
     3771        pImage->Descriptor.aLines[line] = apszNewLines[i];
     3772        /* Compose new name for the extent. */
     3773        apszNewName[i] = vmdkStrReplace(pExtent->pszFullname,
     3774            pszOldBasename, pszNewBasename);
     3775        if (!apszNewName[i])
     3776            goto rollback;
     3777        /* Close the extent file. */
     3778        vmdkFileClose(pImage, &pExtent->File, false);
     3779        /* Rename the extent file. */
     3780        rc = RTFileMove(pExtent->pszFullname, apszNewName[i], 0);
    37993781        if (VBOX_FAILURE(rc))
    3800             break;
    3801 
    3802         /* After looping through all of them close the VMDKIMAGE. */
    3803         vmdkFreeImage(pImage, false);
    3804 
    3805         fImageFreed = true;
    3806 
    3807         /* Rename the descriptor file if it's separate. */
    3808         if (pImage->pDescData)
    3809         {
    3810             rc = RTFileCopy(pImage->pszFilename, pszFilename);
    3811             if (VBOX_FAILURE(rc))
    3812                 break;
    3813             /* Save new name only if we may need to change it back. */
    3814             pszNewImageName = RTStrDup(pszFilename);
    3815         }
    3816 
    3817         /* Save the old name in case we need to roll back. */
    3818         pszOldImageName = RTStrDup(pImage->pszFilename);
    3819         /* Update pImage with the new information. */
    3820         pImage->pszFilename = pszFilename;
    3821 
    3822         /* Open the new image. */
    3823         rc = vmdkOpenImage(pImage, pImage->uOpenFlags);
     3782            goto rollback;
     3783        /* Remember the old name. */
     3784        apszOldName[i] = RTStrDup(pExtent->pszFullname);
     3785    }
     3786
     3787    /* Make sure the descriptor gets written back. */
     3788    pImage->Descriptor.fDirty = true;
     3789    /* Release all old stuff and write back the descriptor. */
     3790    vmdkFreeImage(pImage, false);
     3791
     3792    fImageFreed = true;
     3793
     3794    /* Last elements of new/old name arrays are intended for
     3795     * storing descriptor's names.
     3796     */
     3797    apszNewName[cExtents] = RTPathFilename(pszFilename);
     3798    /* Rename the descriptor file if it's separate. */
     3799    if (!fEmbeddedDesc)
     3800    {
     3801        rc = RTFileMove(pImage->pszFilename, apszNewName[cExtents], 0);
    38243802        if (VBOX_FAILURE(rc))
    3825             break;
    3826         /* Remove the old descriptor file. */
    3827         if (pszNewImageName)
    3828         {
    3829             rc = RTFileDelete(pszOldImageName);
    3830             AssertRC(rc);
    3831         }
    3832     } while (0);
    3833 
     3803            goto rollback;
     3804        /* Save old name only if we may need to change it back. */
     3805        apszOldName[cExtents] = RTStrDup(pszFilename);
     3806    }
     3807
     3808    /* Update pImage with the new information. */
     3809    pImage->pszFilename = pszFilename;
     3810
     3811    /* Open the new image. */
     3812    rc = vmdkOpenImage(pImage, pImage->uOpenFlags);
     3813    if (VBOX_SUCCESS(rc))
     3814        goto out;
     3815
     3816rollback:
    38343817    /* Roll back all changes in case of failure. */
    38353818    if (VBOX_FAILURE(rc))
     
    38443827            vmdkFreeImage(pImage, false);
    38453828        }
    3846         if (pszNewImageName)
    3847         {
    3848             /* The image was actually copied, destroy the copy. */
    3849             rrc = RTFileDelete(pszNewImageName);
    3850             AssertRC(rrc);
    3851             RTStrFree(pszNewImageName);
    3852         }
    3853         if (pszOldImageName)
    3854         {
    3855             /* We end up here only if vmdkOpenImage() has failed, restore the old image name. */
    3856             pImage->pszFilename = pszOldImageName;
    3857         }
    3858         /* Restore renamed extents. */
    3859         for (unsigned i = 0; i < pImage->cExtents; i++)
    3860         {
    3861             if (apszOldExtentFullNames[i])
     3829        /* Rename files back and free the memory. */
     3830        for (i = 0; i < cExtents + 1; i++)
     3831        {
     3832            if (apszOldName[i])
    38623833            {
    3863                 rrc = RTFileMove(apszNewExtentFullNames[i], apszOldExtentFullNames[i], 0);
     3834                rrc = RTFileMove(apszNewName[i], apszOldName[i], 0);
    38643835                AssertRC(rrc);
    3865                 RTStrFree(apszNewExtentFullNames[i]);
    3866                 RTStrFree(apszOldExtentFullNames[i]);
     3836                RTStrFree(apszOldName[i]);
    38673837            }
    3868         }
     3838            if (apszNewName[i])
     3839                RTStrFree(apszNewName[i]);
     3840            if (apszNewLines[i])
     3841                RTStrFree(apszNewLines[i]);
     3842        }
     3843        /* Restore the old descriptor. */
     3844        RTFILE File;
     3845        rrc = RTFileOpen(&File, pszOldDescName,
     3846            RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     3847        AssertRC(rrc);
     3848        if (fEmbeddedDesc)
     3849        {
     3850            ExtentCopy.File   = File;
     3851            pImage->pExtents = &ExtentCopy;
     3852        }
     3853        else
     3854            pImage->File = File;
     3855        pImage->Descriptor = DescriptorCopy;
     3856        vmdkWriteDescriptor(pImage);
     3857        RTFileClose(File);
     3858        RTStrFree(pszOldDescName);
     3859        /* Re-open the image back. */
    38693860        rrc = vmdkOpenImage(pImage, pImage->uOpenFlags);
    38703861        AssertRC(rrc);
    38713862    }
    38723863
    3873     RTMemTmpFree(apszOldExtentBaseNames);
    3874     RTMemTmpFree(apszOldExtentFullNames);
    3875     RTMemTmpFree(apszNewExtentFullNames);
    3876 
    38773864out:
     3865    for (i = 0; i < DescriptorCopy.cLines; i++)
     3866        if (DescriptorCopy.aLines[i])
     3867            RTStrFree(DescriptorCopy.aLines[i]);
     3868    if (apszOldName)
     3869        RTMemTmpFree(apszOldName);
     3870    if (apszNewName)
     3871        RTMemTmpFree(apszNewName);
     3872    if (apszNewLines)
     3873        RTMemTmpFree(apszNewLines);
    38783874    LogFlowFunc(("returns %Vrc\n", rc));
    38793875    return rc;
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