Changeset 9071 in vbox for trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
- Timestamp:
- May 23, 2008 11:51:22 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r9047 r9071 3646 3646 3647 3647 /** 3648 * Allocates a new copy of the given UTF-8 string using RTMemTmpAlloc().3648 * Replaces a fragment of a string with the specified string. 3649 3649 * 3650 3650 * @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. 3652 3654 */ 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; 3655 static 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; 3661 3675 } 3662 3676 … … 3665 3679 { 3666 3680 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)); 3675 3698 3676 3699 /* Check arguments. */ … … 3685 3708 3686 3709 /* 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. 3689 3713 */ 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 { 3701 3719 rc = VERR_NO_MEMORY; 3702 3720 goto out; 3703 3721 } 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); 3799 3781 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); 3824 3802 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 3816 rollback: 3834 3817 /* Roll back all changes in case of failure. */ 3835 3818 if (VBOX_FAILURE(rc)) … … 3844 3827 vmdkFreeImage(pImage, false); 3845 3828 } 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]) 3862 3833 { 3863 rrc = RTFileMove(apszNew ExtentFullNames[i], apszOldExtentFullNames[i], 0);3834 rrc = RTFileMove(apszNewName[i], apszOldName[i], 0); 3864 3835 AssertRC(rrc); 3865 RTStrFree(apszNewExtentFullNames[i]); 3866 RTStrFree(apszOldExtentFullNames[i]); 3836 RTStrFree(apszOldName[i]); 3867 3837 } 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. */ 3869 3860 rrc = vmdkOpenImage(pImage, pImage->uOpenFlags); 3870 3861 AssertRC(rrc); 3871 3862 } 3872 3863 3873 RTMemTmpFree(apszOldExtentBaseNames);3874 RTMemTmpFree(apszOldExtentFullNames);3875 RTMemTmpFree(apszNewExtentFullNames);3876 3877 3864 out: 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); 3878 3874 LogFlowFunc(("returns %Vrc\n", rc)); 3879 3875 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.