- Timestamp:
- Jul 14, 2011 3:01:07 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/doc/manual/en_US/user_VBoxManage.xml
r37929 r37971 1092 1092 <title>VBoxManage clonevm</title> 1093 1093 1094 <para>This command creates a full copy of an existing virtual1094 <para>This command creates a full or linked copy of an existing virtual 1095 1095 machine.</para> 1096 1096 … … 1118 1118 </listitem> 1119 1119 <listitem> 1120 <para><computeroutput>--options keepallmacs|keepnatmacs|keepdisknames</computeroutput>: 1121 Allows additional fine tuning of the clone operation. The first two 1120 <para><computeroutput>--options link|keepallmacs|keepnatmacs|keepdisknames</computeroutput>: 1121 Allows additional fine tuning of the clone operation. The first 1122 option defines that a linked clone should be created, which is 1123 only possible for a machine clone from a snapshot. The next two 1122 1124 options allow to define how the MAC addresses of every virtual 1123 1125 network card should be handled. They can either be reinitialized 1124 (the default), le avedunchanged1125 (<computeroutput>keepallmacs</computeroutput>) or le avedunchanged1126 (the default), left unchanged 1127 (<computeroutput>keepallmacs</computeroutput>) or left unchanged 1126 1128 when the network type is NAT 1127 1129 (<computeroutput>keepnatmacs</computeroutput>). If you add -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
r37929 r37971 336 336 " [--snapshot <uuid>|<name>]\n" 337 337 " [--mode machine|machineandchilds|all]\n" 338 " [--options keepallmacs|keepnatmacs|keepdisknames]\n" 338 " [--options link|keepallmacs|keepnatmacs|\n" 339 " keepdisknames]\n" 339 340 " [--name <name>]\n" 340 341 " [--basefolder <basefolder>]\n" -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
r37900 r37971 311 311 else if (!RTStrNICmp(psz, "KeepDiskNames", len)) 312 312 options->push_back(CloneOptions_KeepDiskNames); 313 // else if (!RTStrNICmp(psz, "Link", len)) 314 // options->push_back(CloneOptions_Link) 313 else if ( !RTStrNICmp(psz, "Link", len) 314 || !RTStrNICmp(psz, "Linked", len)) 315 options->push_back(CloneOptions_Link); 315 316 else 316 317 rc = VERR_PARSE_ERROR; -
trunk/src/VBox/Main/include/MachineImplCloneVM.h
r37533 r37971 34 34 protected: 35 35 HRESULT run(); 36 HRESULT createDiffHelper(const ComObjPtr<Medium> &pParent, 37 const Utf8Str &strSnapshotFolder, 38 RTCList<ComObjPtr<Medium> > *pNewMedia, 39 ComObjPtr<Medium> *ppDiff); 36 40 void destroy(); 37 41 -
trunk/src/VBox/Main/src-server/MachineImpl.cpp
r37932 r37971 6260 6260 optList = com::SafeArray<CloneOptions_T>(ComSafeArrayInArg(options)).toList(); 6261 6261 6262 AssertReturn(!optList.contains(CloneOptions_Link) , E_NOTIMPL);6262 AssertReturn(!optList.contains(CloneOptions_Link) || (isSnapshotMachine() && mode == CloneMode_MachineState), E_INVALIDARG); 6263 6263 AssertReturn(!(optList.contains(CloneOptions_KeepAllMACs) && optList.contains(CloneOptions_KeepNATMACs)), E_INVALIDARG); 6264 6264 6265 6265 AutoCaller autoCaller(this); 6266 6266 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 6267 6267 6268 6268 6269 MachineCloneVM *pWorker = new MachineCloneVM(this, static_cast<Machine*>(pTarget), mode, optList); … … 9455 9456 /** 9456 9457 * Deletes implicit differencing hard disks created either by 9457 * #createImplicitDiffs() or by #Attach Medium() and rolls back mMediaData.9458 * 9459 * Note that to delete hard disks created by #Attach Medium() this method is9458 * #createImplicitDiffs() or by #AttachDevice() and rolls back mMediaData. 9459 * 9460 * Note that to delete hard disks created by #AttachDevice() this method is 9460 9461 * called from #fixupMedia() when the changes are rolled back. 9461 9462 * -
trunk/src/VBox/Main/src-server/MachineImplCloneVM.cpp
r37905 r37971 36 36 ComPtr<IMedium> pMedium; 37 37 ULONG uWeight; 38 } MEDIUMTASK;38 } MEDIUMTASK; 39 39 40 40 typedef struct … … 42 42 RTCList<MEDIUMTASK> chain; 43 43 bool fCreateDiffs; 44 }MEDIUMTASKCHAIN; 44 bool fAttachLinked; 45 } MEDIUMTASKCHAIN; 45 46 46 47 typedef struct … … 49 50 Utf8Str strSaveStateFile; 50 51 ULONG uWeight; 51 } SAVESTATETASK;52 } SAVESTATETASK; 52 53 53 54 // The private class … … 330 331 if (machine == d->pOldMachineState) 331 332 fCreateDiffs = true; 333 /* If we want to create a linked clone just attach the medium 334 * associated with the snapshot. The rest is taken care of by 335 * attach already, so no need to duplicate this. */ 336 bool fAttachLinked = false; 337 if (d->options.contains(CloneOptions_Link)) 338 fAttachLinked = true; 332 339 SafeIfaceArray<IMediumAttachment> sfaAttachments; 333 340 rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments)); … … 358 365 MEDIUMTASKCHAIN mtc; 359 366 mtc.fCreateDiffs = fCreateDiffs; 360 while(!pSrcMedium.isNull()) 367 mtc.fAttachLinked = fAttachLinked; 368 369 if (d->mode == CloneMode_MachineState) 361 370 { 362 371 /* Refresh the state so that the file size get read. */ … … 371 380 MEDIUMTASK mt; 372 381 mt.pMedium = pSrcMedium; 373 mt.uWeight = (lSize + _1M - 1) / _1M; 382 if (fAttachLinked) 383 mt.uWeight = 0; /* dummy */ 384 else 385 mt.uWeight = (lSize + _1M - 1) / _1M; 374 386 mtc.chain.append(mt); 375 376 /* Query next parent. */ 377 rc = pSrcMedium->COMGETTER(Parent)(pSrcMedium.asOutParam()); 378 if (FAILED(rc)) throw rc; 379 }; 380 /* Currently the creation of diff images involves reading at least 381 * the biggest parent in the previous chain. So even if the new 382 * diff image is small in size, it could need some time to create 383 * it. Adding the biggest size in the chain should balance this a 384 * little bit more, i.e. the weight is the sum of the data which 385 * needs to be read and written. */ 386 uint64_t uMaxSize = 0; 387 for (size_t e = mtc.chain.size(); e > 0; --e) 387 } 388 else 388 389 { 389 MEDIUMTASK &mt = mtc.chain.at(e - 1); 390 mt.uWeight += uMaxSize; 391 392 /* Calculate progress data */ 390 /** @todo r=klaus this puts way too many images in the list 391 * when cloning a snapshot (sub)tree, which means that more 392 * images are cloned than necessary. It is just the easiest 393 * way to get a working VM, as getting the image 394 * parent/child relationships right for only the bare 395 * minimum cloning is rather tricky. */ 396 while (!pSrcMedium.isNull()) 397 { 398 /* Refresh the state so that the file size get read. */ 399 MediumState_T e; 400 rc = pSrcMedium->RefreshState(&e); 401 if (FAILED(rc)) throw rc; 402 LONG64 lSize; 403 rc = pSrcMedium->COMGETTER(Size)(&lSize); 404 if (FAILED(rc)) throw rc; 405 406 /* Save the current medium, for later cloning. */ 407 MEDIUMTASK mt; 408 mt.pMedium = pSrcMedium; 409 mt.uWeight = (lSize + _1M - 1) / _1M; 410 mtc.chain.append(mt); 411 412 /* Query next parent. */ 413 rc = pSrcMedium->COMGETTER(Parent)(pSrcMedium.asOutParam()); 414 if (FAILED(rc)) throw rc; 415 } 416 } 417 418 if (fAttachLinked) 419 { 420 /* Implicit diff creation as part of attach is a pretty cheap 421 * operation, and does only need one operation per attachment. */ 393 422 ++uCount; 394 uTotalWeight += mt.uWeight; 395 396 /* Save the max size for better weighting of diff image 397 * creation. */ 398 uMaxSize = RT_MAX(uMaxSize, mt.uWeight); 423 uTotalWeight += 1; /* 1MB per attachment */ 424 } 425 else 426 { 427 /* Currently the copying of diff images involves reading at least 428 * the biggest parent in the previous chain. So even if the new 429 * diff image is small in size, it could need some time to create 430 * it. Adding the biggest size in the chain should balance this a 431 * little bit more, i.e. the weight is the sum of the data which 432 * needs to be read and written. */ 433 uint64_t uMaxSize = 0; 434 for (size_t e = mtc.chain.size(); e > 0; --e) 435 { 436 MEDIUMTASK &mt = mtc.chain.at(e - 1); 437 mt.uWeight += uMaxSize; 438 439 /* Calculate progress data */ 440 ++uCount; 441 uTotalWeight += mt.uWeight; 442 443 /* Save the max size for better weighting of diff image 444 * creation. */ 445 uMaxSize = RT_MAX(uMaxSize, mt.uWeight); 446 } 399 447 } 400 448 d->llMedias.append(mtc); … … 472 520 strTrgMachineFolder.stripFilename(); 473 521 474 RTCList< ComObjPtr<Medium> > newMedias;/* All created images */522 RTCList<ComObjPtr<Medium> > newMedia; /* All created images */ 475 523 RTCList<Utf8Str> newFiles; /* All extra created files (save states, ...) */ 476 524 try … … 499 547 trgMCF.llFirstSnapshot.clear(); 500 548 trgMCF.uuidCurrentSnapshot.clear(); 501 } else502 if ( d->mode == CloneMode_MachineAndChildStates503 && !sn.uuid.isEmpty())549 } 550 else if ( d->mode == CloneMode_MachineAndChildStates 551 && !sn.uuid.isEmpty()) 504 552 { 505 553 /* Copy the snapshot data to the current machine. */ … … 569 617 if (FAILED(rc)) throw rc; 570 618 571 /* Is a clone already there? */ 572 TStrMediumMap::iterator it = map.find(Utf8Str(bstrSrcId)); 573 if (it != map.end()) 574 pNewParent = it->second; 619 if (mtc.fAttachLinked) 620 { 621 IMedium *pTmp = pMedium; 622 ComObjPtr<Medium> pLMedium = static_cast<Medium*>(pTmp); 623 if (pLMedium.isNull()) 624 throw E_POINTER; 625 if (pLMedium->isReadOnly()) 626 { 627 ComObjPtr<Medium> pDiff; 628 /* create the diff under the snapshot medium */ 629 rc = createDiffHelper(pLMedium, strTrgSnapshotFolder, 630 &newMedia, &pDiff); 631 if (FAILED(rc)) throw rc; 632 map.insert(TStrMediumPair(Utf8Str(bstrSrcId), pDiff)); 633 /* diff image has to be used... */ 634 pNewParent = pDiff; 635 } 636 else 637 { 638 /* Attach the medium directly, as its type is not 639 * subject to diff creation. */ 640 newMedia.append(pLMedium); 641 map.insert(TStrMediumPair(Utf8Str(bstrSrcId), pLMedium)); 642 pNewParent = pLMedium; 643 } 644 } 575 645 else 576 646 { 577 ComPtr<IMediumFormat> pSrcFormat; 578 rc = pMedium->COMGETTER(MediumFormat)(pSrcFormat.asOutParam()); 579 ULONG uSrcCaps = 0; 580 rc = pSrcFormat->COMGETTER(Capabilities)(&uSrcCaps); 581 if (FAILED(rc)) throw rc; 582 583 /* Default format? */ 584 Utf8Str strDefaultFormat; 585 p->mParent->getDefaultHardDiskFormat(strDefaultFormat); 586 Bstr bstrSrcFormat(strDefaultFormat); 587 ULONG srcVar = MediumVariant_Standard; 588 /* Is the source file based? */ 589 if ((uSrcCaps & MediumFormatCapabilities_File) == MediumFormatCapabilities_File) 647 /* Is a clone already there? */ 648 TStrMediumMap::iterator it = map.find(Utf8Str(bstrSrcId)); 649 if (it != map.end()) 650 pNewParent = it->second; 651 else 590 652 { 591 /* Yes, just use the source format. Otherwise the defaults 592 * will be used. */ 593 rc = pMedium->COMGETTER(Format)(bstrSrcFormat.asOutParam()); 594 if (FAILED(rc)) throw rc; 595 rc = pMedium->COMGETTER(Variant)(&srcVar); 596 if (FAILED(rc)) throw rc; 653 ComPtr<IMediumFormat> pSrcFormat; 654 rc = pMedium->COMGETTER(MediumFormat)(pSrcFormat.asOutParam()); 655 ULONG uSrcCaps = 0; 656 rc = pSrcFormat->COMGETTER(Capabilities)(&uSrcCaps); 657 if (FAILED(rc)) throw rc; 658 659 /* Default format? */ 660 Utf8Str strDefaultFormat; 661 p->mParent->getDefaultHardDiskFormat(strDefaultFormat); 662 Bstr bstrSrcFormat(strDefaultFormat); 663 ULONG srcVar = MediumVariant_Standard; 664 /* Is the source file based? */ 665 if ((uSrcCaps & MediumFormatCapabilities_File) == MediumFormatCapabilities_File) 666 { 667 /* Yes, just use the source format. Otherwise the defaults 668 * will be used. */ 669 rc = pMedium->COMGETTER(Format)(bstrSrcFormat.asOutParam()); 670 if (FAILED(rc)) throw rc; 671 rc = pMedium->COMGETTER(Variant)(&srcVar); 672 if (FAILED(rc)) throw rc; 673 } 674 675 Guid newId; 676 newId.create(); 677 Utf8Str strNewName(bstrSrcName); 678 if (!fKeepDiskNames) 679 { 680 /* If the old disk name was in {uuid} format we also 681 * want the new name in this format, but with the 682 * updated id of course. If the old disk was called 683 * like the VM name, we change it to the new VM name. 684 * For all other disks we rename them with this 685 * template: "new name-disk1.vdi". */ 686 Utf8Str strSrcTest = Utf8Str(bstrSrcName).stripExt(); 687 if (strSrcTest == strOldVMName) 688 strNewName = Utf8StrFmt("%s%s", trgMCF.machineUserData.strName.c_str(), RTPathExt(Utf8Str(bstrSrcName).c_str())); 689 else if ( strSrcTest.startsWith("{") 690 && strSrcTest.endsWith("}")) 691 { 692 strSrcTest = strSrcTest.substr(1, strSrcTest.length() - 2); 693 if (isValidGuid(strSrcTest)) 694 strNewName = Utf8StrFmt("%s%s", newId.toStringCurly().c_str(), RTPathExt(strNewName.c_str())); 695 } 696 else 697 strNewName = Utf8StrFmt("%s-disk%d%s", trgMCF.machineUserData.strName.c_str(), ++cDisks, RTPathExt(Utf8Str(bstrSrcName).c_str())); 698 } 699 700 /* Check if this medium comes from the snapshot folder, if 701 * so, put it there in the cloned machine as well. 702 * Otherwise it goes to the machine folder. */ 703 Bstr bstrSrcPath; 704 Utf8Str strFile = Utf8StrFmt("%s%c%s", strTrgMachineFolder.c_str(), RTPATH_DELIMITER, strNewName.c_str()); 705 rc = pMedium->COMGETTER(Location)(bstrSrcPath.asOutParam()); 706 if (FAILED(rc)) throw rc; 707 if ( !bstrSrcPath.isEmpty() 708 && RTPathStartsWith(Utf8Str(bstrSrcPath).c_str(), Utf8Str(bstrSrcSnapshotFolder).c_str())) 709 strFile = Utf8StrFmt("%s%c%s", strTrgSnapshotFolder.c_str(), RTPATH_DELIMITER, strNewName.c_str()); 710 else 711 strFile = Utf8StrFmt("%s%c%s", strTrgMachineFolder.c_str(), RTPATH_DELIMITER, strNewName.c_str()); 712 713 /* Start creating the clone. */ 714 ComObjPtr<Medium> pTarget; 715 rc = pTarget.createObject(); 716 if (FAILED(rc)) throw rc; 717 718 rc = pTarget->init(p->mParent, 719 Utf8Str(bstrSrcFormat), 720 strFile, 721 Guid::Empty, /* empty media registry */ 722 NULL /* llRegistriesThatNeedSaving */); 723 if (FAILED(rc)) throw rc; 724 725 /* Update the new uuid. */ 726 pTarget->updateId(newId); 727 728 srcLock.release(); 729 /* Do the disk cloning. */ 730 ComPtr<IProgress> progress2; 731 rc = pMedium->CloneTo(pTarget, 732 srcVar, 733 pNewParent, 734 progress2.asOutParam()); 735 if (FAILED(rc)) throw rc; 736 737 /* Wait until the async process has finished. */ 738 rc = d->pProgress->WaitForAsyncProgressCompletion(progress2); 739 srcLock.acquire(); 740 if (FAILED(rc)) throw rc; 741 742 /* Check the result of the async process. */ 743 LONG iRc; 744 rc = progress2->COMGETTER(ResultCode)(&iRc); 745 if (FAILED(rc)) throw rc; 746 if (FAILED(iRc)) 747 { 748 /* If the thread of the progress object has an error, then 749 * retrieve the error info from there, or it'll be lost. */ 750 ProgressErrorInfo info(progress2); 751 throw p->setError(iRc, Utf8Str(info.getText()).c_str()); 752 } 753 /* Remember created medium. */ 754 newMedia.append(pTarget); 755 /* Get the medium type from the source and set it to the 756 * new medium. */ 757 MediumType_T type; 758 rc = pMedium->COMGETTER(Type)(&type); 759 if (FAILED(rc)) throw rc; 760 rc = pTarget->COMSETTER(Type)(type); 761 if (FAILED(rc)) throw rc; 762 map.insert(TStrMediumPair(Utf8Str(bstrSrcId), pTarget)); 763 /* register the new harddisk */ 764 { 765 AutoWriteLock tlock(p->mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 766 rc = p->mParent->registerHardDisk(pTarget, NULL /* pllRegistriesThatNeedSaving */); 767 if (FAILED(rc)) throw rc; 768 } 769 /* This medium becomes the parent of the next medium in the 770 * chain. */ 771 pNewParent = pTarget; 597 772 } 598 599 Guid newId;600 newId.create();601 Utf8Str strNewName(bstrSrcName);602 if (!fKeepDiskNames)603 {604 /* If the old disk name was in {uuid} format we also605 * want the new name in this format, but with the606 * updated id of course. If the old disk was called607 * like the VM name, we change it to the new VM name.608 * For all other disks we rename them with this609 * template: "new name-disk1.vdi". */610 Utf8Str strSrcTest = Utf8Str(bstrSrcName).stripExt();611 if (strSrcTest == strOldVMName)612 strNewName = Utf8StrFmt("%s%s", trgMCF.machineUserData.strName.c_str(), RTPathExt(Utf8Str(bstrSrcName).c_str()));613 else614 if (strSrcTest.startsWith("{") &&615 strSrcTest.endsWith("}"))616 {617 strSrcTest = strSrcTest.substr(1, strSrcTest.length() - 2);618 if (isValidGuid(strSrcTest))619 strNewName = Utf8StrFmt("%s%s", newId.toStringCurly().c_str(), RTPathExt(strNewName.c_str()));620 }621 else622 strNewName = Utf8StrFmt("%s-disk%d%s", trgMCF.machineUserData.strName.c_str(), ++cDisks, RTPathExt(Utf8Str(bstrSrcName).c_str()));623 }624 625 /* Check if this medium comes from the snapshot folder, if626 * so, put it there in the cloned machine as well.627 * Otherwise it goes to the machine folder. */628 Bstr bstrSrcPath;629 Utf8Str strFile = Utf8StrFmt("%s%c%s", strTrgMachineFolder.c_str(), RTPATH_DELIMITER, strNewName.c_str());630 rc = pMedium->COMGETTER(Location)(bstrSrcPath.asOutParam());631 if (FAILED(rc)) throw rc;632 if ( !bstrSrcPath.isEmpty()633 && RTPathStartsWith(Utf8Str(bstrSrcPath).c_str(), Utf8Str(bstrSrcSnapshotFolder).c_str()))634 strFile = Utf8StrFmt("%s%c%s", strTrgSnapshotFolder.c_str(), RTPATH_DELIMITER, strNewName.c_str());635 else636 strFile = Utf8StrFmt("%s%c%s", strTrgMachineFolder.c_str(), RTPATH_DELIMITER, strNewName.c_str());637 638 /* Start creating the clone. */639 ComObjPtr<Medium> pTarget;640 rc = pTarget.createObject();641 if (FAILED(rc)) throw rc;642 643 rc = pTarget->init(p->mParent,644 Utf8Str(bstrSrcFormat),645 strFile,646 Guid::Empty, /* empty media registry */647 NULL /* llRegistriesThatNeedSaving */);648 if (FAILED(rc)) throw rc;649 650 /* Update the new uuid. */651 pTarget->updateId(newId);652 653 srcLock.release();654 /* Do the disk cloning. */655 ComPtr<IProgress> progress2;656 rc = pMedium->CloneTo(pTarget,657 srcVar,658 pNewParent,659 progress2.asOutParam());660 if (FAILED(rc)) throw rc;661 662 /* Wait until the asynchrony process has finished. */663 rc = d->pProgress->WaitForAsyncProgressCompletion(progress2);664 srcLock.acquire();665 if (FAILED(rc)) throw rc;666 667 /* Check the result of the asynchrony process. */668 LONG iRc;669 rc = progress2->COMGETTER(ResultCode)(&iRc);670 if (FAILED(rc)) throw rc;671 if (FAILED(iRc))672 {673 /* If the thread of the progress object has an error, then674 * retrieve the error info from there, or it'll be lost. */675 ProgressErrorInfo info(progress2);676 throw p->setError(iRc, Utf8Str(info.getText()).c_str());677 }678 /* Remember created medias. */679 newMedias.append(pTarget);680 /* Get the medium type from the source and set it to the681 * new medium. */682 MediumType_T type;683 rc = pMedium->COMGETTER(Type)(&type);684 if (FAILED(rc)) throw rc;685 rc = pTarget->COMSETTER(Type)(type);686 if (FAILED(rc)) throw rc;687 map.insert(TStrMediumPair(Utf8Str(bstrSrcId), pTarget));688 /* Global register the new harddisk */689 {690 AutoWriteLock tlock(p->mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);691 rc = p->mParent->registerHardDisk(pTarget, NULL /* pllRegistriesThatNeedSaving */);692 if (FAILED(rc)) return rc;693 }694 /* This medium becomes the parent of the next medium in the695 * chain. */696 pNewParent = pTarget;697 773 } 698 774 } … … 701 777 if (mtc.fCreateDiffs) 702 778 { 703 Bstr bstrSrcId; 704 rc = pNewParent->COMGETTER(Id)(bstrSrcId.asOutParam()); 705 if (FAILED(rc)) throw rc; 706 ComObjPtr<Medium> diff; 707 diff.createObject(); 708 rc = diff->init(p->mParent, 709 pNewParent->getPreferredDiffFormat(), 710 Utf8StrFmt("%s%c", strTrgSnapshotFolder.c_str(), RTPATH_DELIMITER), 711 Guid::Empty, /* empty media registry */ 712 NULL); /* pllRegistriesThatNeedSaving */ 713 if (FAILED(rc)) throw rc; 714 MediumLockList *pMediumLockList(new MediumLockList()); 715 rc = diff->createMediumLockList(true /* fFailIfInaccessible */, 716 true /* fMediumLockWrite */, 717 pNewParent, 718 *pMediumLockList); 719 if (FAILED(rc)) throw rc; 720 rc = pMediumLockList->Lock(); 721 if (FAILED(rc)) throw rc; 722 rc = pNewParent->createDiffStorage(diff, MediumVariant_Standard, 723 pMediumLockList, 724 NULL /* aProgress */, 725 true /* aWait */, 726 NULL); // pllRegistriesThatNeedSaving 727 delete pMediumLockList; 728 if (FAILED(rc)) throw rc; 729 /* Remember created medias. */ 730 newMedias.append(diff); 731 /* Global register the new harddisk */ 779 if (pNewParent->isReadOnly()) 732 780 { 733 AutoWriteLock tlock(p->mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 734 rc = p->mParent->registerHardDisk(diff, NULL /* pllRegistriesThatNeedSaving */); 735 if (FAILED(rc)) return rc; 781 ComObjPtr<Medium> pDiff; 782 rc = createDiffHelper(pNewParent, strTrgSnapshotFolder, 783 &newMedia, &pDiff); 784 if (FAILED(rc)) throw rc; 785 /* diff image has to be used... */ 786 pNewParent = pDiff; 736 787 } 737 /* This medium becomes the parent of the next medium in the 738 * chain. */ 739 pNewParent = diff; 788 else 789 { 790 /* Attach the medium directly, as its type is not 791 * subject to diff creation. */ 792 newMedia.append(pNewParent); 793 } 740 794 } 741 795 Bstr bstrSrcId; … … 752 806 /* Make sure all disks know of the new machine uuid. We do this last to 753 807 * be able to change the medium type above. */ 754 for (size_t i = newMedia s.size(); i > 0; --i)755 { 756 ComObjPtr<Medium> &pMedium = newMedias.at(i - 1);808 for (size_t i = newMedia.size(); i > 0; --i) 809 { 810 const ComObjPtr<Medium> &pMedium = newMedia.at(i - 1); 757 811 AutoCaller mac(pMedium); 758 812 if (FAILED(mac.rc())) throw mac.rc(); 759 813 AutoWriteLock mlock(pMedium COMMA_LOCKVAL_SRC_POS); 760 pMedium->addRegistry(d-> pTrgMachine->mData->mUuid, false /* fRecursive */);814 pMedium->addRegistry(d->options.contains(CloneOptions_Link) ? d->pSrcMachine->mData->mUuid : d->pTrgMachine->mData->mUuid, false /* fRecurse */); 761 815 } 762 816 /* Check if a snapshot folder is necessary and if so doesn't already … … 812 866 rc = d->pTrgMachine->SaveSettings(); 813 867 if (FAILED(rc)) throw rc; 814 } 815 catch(HRESULT rc2) 868 trgLock.release(); 869 if (d->options.contains(CloneOptions_Link)) 870 { 871 srcLock.release(); 872 GuidList llRegistrySrc; 873 llRegistrySrc.push_back(d->pSrcMachine->mData->mUuid); 874 rc = p->mParent->saveRegistries(llRegistrySrc); 875 if (FAILED(rc)) throw rc; 876 } 877 } 878 catch (HRESULT rc2) 816 879 { 817 880 rc = rc2; … … 836 899 /* Delete all already created medias. (Reverse, cause there could be 837 900 * parent->child relations.) */ 838 for (size_t i = newMedias.size(); i > 0; --i) 839 { 840 bool fFile = false; 841 Utf8Str strLoc; 842 ComObjPtr<Medium> &pMedium = newMedias.at(i - 1); 843 { 844 AutoCaller mac(pMedium); 845 if (FAILED(mac.rc())) { continue; mrc = mac.rc(); } 846 AutoReadLock mlock(pMedium COMMA_LOCKVAL_SRC_POS); 847 fFile = pMedium->isMediumFormatFile(); 848 strLoc = pMedium->getLocationFull(); 849 } 850 if (fFile) 851 { 852 vrc = RTFileDelete(strLoc.c_str()); 853 if (RT_FAILURE(vrc)) 854 mrc = p->setError(VBOX_E_IPRT_ERROR, p->tr("Could not delete file '%s' (%Rrc)"), strLoc.c_str(), vrc); 855 } 901 for (size_t i = newMedia.size(); i > 0; --i) 902 { 903 const ComObjPtr<Medium> &pMedium = newMedia.at(i - 1); 904 mrc = pMedium->deleteStorage(NULL /* aProgress */, 905 true /* aWait */, 906 NULL /* llRegistriesThatNeedSaving */); 907 pMedium->Close(); 856 908 } 857 909 /* Delete the snapshot folder when not empty. */ … … 865 917 } 866 918 919 HRESULT MachineCloneVM::createDiffHelper(const ComObjPtr<Medium> &pParent, 920 const Utf8Str &strSnapshotFolder, 921 RTCList< ComObjPtr<Medium> > *pNewMedia, 922 ComObjPtr<Medium> *ppDiff) 923 { 924 DPTR(MachineCloneVM); 925 ComObjPtr<Machine> &p = d->p; 926 HRESULT rc = S_OK; 927 928 try 929 { 930 Bstr bstrSrcId; 931 rc = pParent->COMGETTER(Id)(bstrSrcId.asOutParam()); 932 if (FAILED(rc)) throw rc; 933 ComObjPtr<Medium> diff; 934 diff.createObject(); 935 rc = diff->init(p->mParent, 936 pParent->getPreferredDiffFormat(), 937 Utf8StrFmt("%s%c", strSnapshotFolder.c_str(), RTPATH_DELIMITER), 938 Guid::Empty, /* empty media registry */ 939 NULL); /* pllRegistriesThatNeedSaving */ 940 if (FAILED(rc)) throw rc; 941 MediumLockList *pMediumLockList(new MediumLockList()); 942 rc = diff->createMediumLockList(true /* fFailIfInaccessible */, 943 true /* fMediumLockWrite */, 944 pParent, 945 *pMediumLockList); 946 if (FAILED(rc)) throw rc; 947 rc = pMediumLockList->Lock(); 948 if (FAILED(rc)) throw rc; 949 /* this already registers the new diff image */ 950 rc = pParent->createDiffStorage(diff, MediumVariant_Standard, 951 pMediumLockList, 952 NULL /* aProgress */, 953 true /* aWait */, 954 NULL); // pllRegistriesThatNeedSaving 955 delete pMediumLockList; 956 if (FAILED(rc)) throw rc; 957 /* Remember created medium. */ 958 pNewMedia->append(diff); 959 *ppDiff = diff; 960 } 961 catch (HRESULT rc2) 962 { 963 rc = rc2; 964 } 965 catch (...) 966 { 967 rc = VirtualBox::handleUnexpectedExceptions(RT_SRC_POS); 968 } 969 970 return rc; 971 } 972 867 973 void MachineCloneVM::destroy() 868 974 {
Note:
See TracChangeset
for help on using the changeset viewer.