MachineImplCloneVM.cpp revision d1bb48754376874c3cc6b1091a6abec549663c0c
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/* $Id$ */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** @file
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Implementation of MachineCloneVM
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/*
df2a53dee17325742e7464e7f53d3f99dc500f3avboxsync * Copyright (C) 2011-2013 Oracle Corporation
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * available from http://www.virtualbox.org. This file is free software;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * you can redistribute it and/or modify it under the terms of the GNU
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * General Public License (GPL) as published by the Free Software
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include "MachineImplCloneVM.h"
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include "VirtualBoxImpl.h"
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include "MediumImpl.h"
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include "HostImpl.h"
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <iprt/path.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <iprt/dir.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <iprt/cpp/utils.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#ifdef DEBUG_poetzsch
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync# include <iprt/stream.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#endif
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <VBox/com/list.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <VBox/com/MultiResult.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync// typedefs
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/////////////////////////////////////////////////////////////////////////////
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsynctypedef struct
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Utf8Str strBaseName;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComPtr<IMedium> pMedium;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint32_t uIdx;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ULONG uWeight;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync} MEDIUMTASK;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsynctypedef struct
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync RTCList<MEDIUMTASK> chain;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync bool fCreateDiffs;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync bool fAttachLinked;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync} MEDIUMTASKCHAIN;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsynctypedef struct
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync Guid snapshotUuid;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync Utf8Str strSaveStateFile;
6febf3149010855617e4a37e2c49f93d68930d44vboxsync ULONG uWeight;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync} SAVESTATETASK;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync// The private class
80e46f984efd827517661c0e081a36014ca41af8vboxsync/////////////////////////////////////////////////////////////////////////////
80e46f984efd827517661c0e081a36014ca41af8vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncstruct MachineCloneVMPrivate
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MachineCloneVMPrivate(MachineCloneVM *a_q, ComObjPtr<Machine> &a_pSrcMachine, ComObjPtr<Machine> &a_pTrgMachine, CloneMode_T a_mode, const RTCList<CloneOptions_T> &opts)
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync : q_ptr(a_q)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync , p(a_pSrcMachine)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync , pSrcMachine(a_pSrcMachine)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync , pTrgMachine(a_pTrgMachine)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync , mode(a_mode)
48dafba24ef28f07a241e5857a43b327822574a8vboxsync , options(opts)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {}
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Thread management */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync int startWorker()
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
710a6316a22868b04400caf79719f96c18163cd3vboxsync return RTThreadCreate(NULL,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync MachineCloneVMPrivate::workerThread,
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync static_cast<void*>(this),
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync 0,
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync RTTHREADTYPE_MAIN_WORKER,
06782e19f5e2144408396dcec922c423c5ef9da8vboxsync 0,
80e46f984efd827517661c0e081a36014ca41af8vboxsync "MachineClone");
80e46f984efd827517661c0e081a36014ca41af8vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync static int workerThread(RTTHREAD /* Thread */, void *pvUser)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MachineCloneVMPrivate *pTask = static_cast<MachineCloneVMPrivate*>(pvUser);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync AssertReturn(pTask, VERR_INVALID_POINTER);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync HRESULT rc = pTask->q_ptr->run();
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
6febf3149010855617e4a37e2c49f93d68930d44vboxsync pTask->pProgress->notifyComplete(rc);
63b785c3291332a86a9bc473e68f08121368898bvboxsync
80e46f984efd827517661c0e081a36014ca41af8vboxsync pTask->q_ptr->destroy();
80e46f984efd827517661c0e081a36014ca41af8vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync return VINF_SUCCESS;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Private helper methods */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* MachineCloneVM::start helper: */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync HRESULT createMachineList(const ComPtr<ISnapshot> &pSnapshot, RTCList< ComObjPtr<Machine> > &machineList) const;
48dafba24ef28f07a241e5857a43b327822574a8vboxsync inline void updateProgressStats(MEDIUMTASKCHAIN &mtc, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight) const;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync inline HRESULT addSaveState(const ComObjPtr<Machine> &machine, ULONG &uCount, ULONG &uTotalWeight);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync inline HRESULT queryBaseName(const ComPtr<IMedium> &pMedium, Utf8Str &strBaseName) const;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync HRESULT queryMediasForMachineState(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync HRESULT queryMediasForMachineAndChildStates(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync HRESULT queryMediasForAllStates(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync /* MachineCloneVM::run helper: */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync bool findSnapshot(const settings::SnapshotsList &snl, const Guid &id, settings::Snapshot &sn) const;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync void updateMACAddresses(settings::NetworkAdaptersList &nwl) const;
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync void updateMACAddresses(settings::SnapshotsList &sl) const;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync void updateStorageLists(settings::StorageControllersList &sc, const Bstr &bstrOldId, const Bstr &bstrNewId) const;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync void updateSnapshotStorageLists(settings::SnapshotsList &sl, const Bstr &bstrOldId, const Bstr &bstrNewId) const;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync void updateStateFile(settings::SnapshotsList &snl, const Guid &id, const Utf8Str &strFile) const;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync HRESULT createDifferencingMedium(const ComObjPtr<Machine> &pMachine, const ComObjPtr<Medium> &pParent, const Utf8Str &strSnapshotFolder, RTCList<ComObjPtr<Medium> > &newMedia, ComObjPtr<Medium> *ppDiff) const;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync static int copyStateFileProgress(unsigned uPercentage, void *pvUser);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /* Private q and parent pointer */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync MachineCloneVM *q_ptr;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComObjPtr<Machine> p;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Private helper members */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComObjPtr<Machine> pSrcMachine;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComObjPtr<Machine> pTrgMachine;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComPtr<IMachine> pOldMachineState;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComObjPtr<Progress> pProgress;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync Guid snapshotId;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync CloneMode_T mode;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync RTCList<CloneOptions_T> options;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync RTCList<MEDIUMTASKCHAIN> llMedias;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync RTCList<SAVESTATETASK> llSaveStateFiles; /* Snapshot UUID -> File path */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync};
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsyncHRESULT MachineCloneVMPrivate::createMachineList(const ComPtr<ISnapshot> &pSnapshot, RTCList< ComObjPtr<Machine> > &machineList) const
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync HRESULT rc = S_OK;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Bstr name;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pSnapshot->COMGETTER(Name)(name.asOutParam());
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComPtr<IMachine> pMachine;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync rc = pSnapshot->COMGETTER(Machine)(pMachine.asOutParam());
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync machineList.append((Machine*)(IMachine*)pMachine);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SafeIfaceArray<ISnapshot> sfaChilds;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pSnapshot->COMGETTER(Children)(ComSafeArrayAsOutParam(sfaChilds));
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (FAILED(rc)) return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (size_t i = 0; i < sfaChilds.size(); ++i)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = createMachineList(sfaChilds[i], machineList);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncvoid MachineCloneVMPrivate::updateProgressStats(MEDIUMTASKCHAIN &mtc, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight) const
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (fAttachLinked)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /* Implicit diff creation as part of attach is a pretty cheap
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * operation, and does only need one operation per attachment. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ++uCount;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uTotalWeight += 1; /* 1MB per attachment */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /* Currently the copying of diff images involves reading at least
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * the biggest parent in the previous chain. So even if the new
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * diff image is small in size, it could need some time to create
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * it. Adding the biggest size in the chain should balance this a
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * little bit more, i.e. the weight is the sum of the data which
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * needs to be read and written. */
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync ULONG uMaxWeight = 0;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync for (size_t e = mtc.chain.size(); e > 0; --e)
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync {
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync MEDIUMTASK &mt = mtc.chain.at(e - 1);
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync mt.uWeight += uMaxWeight;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync /* Calculate progress data */
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync ++uCount;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync uTotalWeight += mt.uWeight;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync /* Save the max size for better weighting of diff image
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync * creation. */
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync uMaxWeight = RT_MAX(uMaxWeight, mt.uWeight);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync}
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsyncHRESULT MachineCloneVMPrivate::addSaveState(const ComObjPtr<Machine> &machine, ULONG &uCount, ULONG &uTotalWeight)
6febf3149010855617e4a37e2c49f93d68930d44vboxsync{
6febf3149010855617e4a37e2c49f93d68930d44vboxsync Bstr bstrSrcSaveStatePath;
6febf3149010855617e4a37e2c49f93d68930d44vboxsync HRESULT rc = machine->COMGETTER(StateFilePath)(bstrSrcSaveStatePath.asOutParam());
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if (FAILED(rc)) return rc;
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if (!bstrSrcSaveStatePath.isEmpty())
6febf3149010855617e4a37e2c49f93d68930d44vboxsync {
6febf3149010855617e4a37e2c49f93d68930d44vboxsync SAVESTATETASK sst;
6febf3149010855617e4a37e2c49f93d68930d44vboxsync sst.snapshotUuid = machine->getSnapshotId();
6febf3149010855617e4a37e2c49f93d68930d44vboxsync sst.strSaveStateFile = bstrSrcSaveStatePath;
63b785c3291332a86a9bc473e68f08121368898bvboxsync uint64_t cbSize;
63b785c3291332a86a9bc473e68f08121368898bvboxsync int vrc = RTFileQuerySize(sst.strSaveStateFile.c_str(), &cbSize);
63b785c3291332a86a9bc473e68f08121368898bvboxsync if (RT_FAILURE(vrc))
63b785c3291332a86a9bc473e68f08121368898bvboxsync return p->setError(VBOX_E_IPRT_ERROR, p->tr("Could not query file size of '%s' (%Rrc)"), sst.strSaveStateFile.c_str(), vrc);
63b785c3291332a86a9bc473e68f08121368898bvboxsync /* same rule as above: count both the data which needs to
63b785c3291332a86a9bc473e68f08121368898bvboxsync * be read and written */
63b785c3291332a86a9bc473e68f08121368898bvboxsync sst.uWeight = (ULONG)(2 * (cbSize + _1M - 1) / _1M);
63b785c3291332a86a9bc473e68f08121368898bvboxsync llSaveStateFiles.append(sst);
63b785c3291332a86a9bc473e68f08121368898bvboxsync ++uCount;
80626cd34607c5dbf3f0af51b32396ce58bf493bvboxsync uTotalWeight += sst.uWeight;
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync }
80626cd34607c5dbf3f0af51b32396ce58bf493bvboxsync return S_OK;
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync}
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsyncHRESULT MachineCloneVMPrivate::queryBaseName(const ComPtr<IMedium> &pMedium, Utf8Str &strBaseName) const
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync ComPtr<IMedium> pBaseMedium;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync HRESULT rc = pMedium->COMGETTER(Base)(pBaseMedium.asOutParam());
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync Bstr bstrBaseName;
80e46f984efd827517661c0e081a36014ca41af8vboxsync rc = pBaseMedium->COMGETTER(Name)(bstrBaseName.asOutParam());
80e46f984efd827517661c0e081a36014ca41af8vboxsync if (FAILED(rc)) return rc;
80e46f984efd827517661c0e081a36014ca41af8vboxsync strBaseName = bstrBaseName;
80e46f984efd827517661c0e081a36014ca41af8vboxsync return rc;
80e46f984efd827517661c0e081a36014ca41af8vboxsync}
80e46f984efd827517661c0e081a36014ca41af8vboxsync
80e46f984efd827517661c0e081a36014ca41af8vboxsyncHRESULT MachineCloneVMPrivate::queryMediasForMachineState(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight)
80e46f984efd827517661c0e081a36014ca41af8vboxsync{
80e46f984efd827517661c0e081a36014ca41af8vboxsync /* This mode is pretty straightforward. We didn't need to know about any
80e46f984efd827517661c0e081a36014ca41af8vboxsync * parent/children relationship and therefor simply adding all directly
80e46f984efd827517661c0e081a36014ca41af8vboxsync * attached images of the source VM as cloning targets. The IMedium code
80e46f984efd827517661c0e081a36014ca41af8vboxsync * take than care to merge any (possibly) existing parents into the new
80e46f984efd827517661c0e081a36014ca41af8vboxsync * image. */
80e46f984efd827517661c0e081a36014ca41af8vboxsync HRESULT rc = S_OK;
80e46f984efd827517661c0e081a36014ca41af8vboxsync for (size_t i = 0; i < machineList.size(); ++i)
80e46f984efd827517661c0e081a36014ca41af8vboxsync {
80e46f984efd827517661c0e081a36014ca41af8vboxsync const ComObjPtr<Machine> &machine = machineList.at(i);
80e46f984efd827517661c0e081a36014ca41af8vboxsync /* If this is the Snapshot Machine we want to clone, we need to
80e46f984efd827517661c0e081a36014ca41af8vboxsync * create a new diff file for the new "current state". */
80e46f984efd827517661c0e081a36014ca41af8vboxsync const bool fCreateDiffs = (machine == pOldMachineState);
80e46f984efd827517661c0e081a36014ca41af8vboxsync /* Add all attachments of the different machines to a worker list. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync SafeIfaceArray<IMediumAttachment> sfaAttachments;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (size_t a = 0; a < sfaAttachments.size(); ++a)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[a];
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync DeviceType_T type;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pAtt->COMGETTER(Type)(&type);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Only harddisk's are of interest. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (type != DeviceType_HardDisk)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync continue;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Valid medium attached? */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync ComPtr<IMedium> pSrcMedium;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pAtt->COMGETTER(Medium)(pSrcMedium.asOutParam());
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (pSrcMedium.isNull())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync continue;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Create the medium task chain. In this case it will always
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * contain one image only. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MEDIUMTASKCHAIN mtc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.fCreateDiffs = fCreateDiffs;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.fAttachLinked = fAttachLinked;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Refresh the state so that the file size get read. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MediumState_T e;
48dafba24ef28f07a241e5857a43b327822574a8vboxsync rc = pSrcMedium->RefreshState(&e);
48dafba24ef28f07a241e5857a43b327822574a8vboxsync if (FAILED(rc)) return rc;
48dafba24ef28f07a241e5857a43b327822574a8vboxsync LONG64 lSize;
48dafba24ef28f07a241e5857a43b327822574a8vboxsync rc = pSrcMedium->COMGETTER(Size)(&lSize);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MEDIUMTASK mt;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mt.uIdx = UINT32_MAX; /* No read/write optimization possible. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
06782e19f5e2144408396dcec922c423c5ef9da8vboxsync /* Save the base name. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = queryBaseName(pSrcMedium, mt.strBaseName);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Save the current medium, for later cloning. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mt.pMedium = pSrcMedium;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (fAttachLinked)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mt.uWeight = 0; /* dummy */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync mt.uWeight = (ULONG)((lSize + _1M - 1) / _1M);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync mtc.chain.append(mt);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Update the progress info. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync updateProgressStats(mtc, fAttachLinked, uCount, uTotalWeight);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Append the list of images which have to be cloned. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync llMedias.append(mtc);
194a8ad893b721dfc22ac5f955671f09db015a3fvboxsync }
e073b07dcb5c9827f0530a9bfa2643356c5656dbvboxsync /* Add the save state files of this machine if there is one. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = addSaveState(machine, uCount, uTotalWeight);
e073b07dcb5c9827f0530a9bfa2643356c5656dbvboxsync if (FAILED(rc)) return rc;
e073b07dcb5c9827f0530a9bfa2643356c5656dbvboxsync }
e073b07dcb5c9827f0530a9bfa2643356c5656dbvboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return rc;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync}
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsyncHRESULT MachineCloneVMPrivate::queryMediasForMachineAndChildStates(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync /* This is basically a three step approach. First select all medias
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync * directly or indirectly involved in the clone. Second create a histogram
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsync * of the usage of all that medias. Third select the medias which are
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsync * directly attached or have more than one directly/indirectly used child
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsync * in the new clone. Step one and two are done in the first loop.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Example of the histogram counts after going through 3 attachments from
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * bottom to top:
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync *
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * 3
bc04c0fb1382c98fb74fb38ac5dbd3f06ea6a92bvboxsync * |
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * -> 3
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * / \
bc04c0fb1382c98fb74fb38ac5dbd3f06ea6a92bvboxsync * 2 1 <-
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * /
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * -> 2
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * / \
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * -> 1 1
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync * \
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * 1 <-
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync *
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * Whenever the histogram count is changing compared to the previous one we
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * need to include that image in the cloning step (Marked with <-). If we
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * start at zero even the directly attached images are automatically
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * included.
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync *
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync * Note: This still leads to media chains which can have the same medium
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync * included. This case is handled in "run" and therefor not critical, but
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync * it leads to wrong progress infos which isn't nice. */
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync HRESULT rc = S_OK;
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync std::map<ComPtr<IMedium>, uint32_t> mediaHist; /* Our usage histogram for the medias */
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync for (size_t i = 0; i < machineList.size(); ++i)
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync {
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync const ComObjPtr<Machine> &machine = machineList.at(i);
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync /* If this is the Snapshot Machine we want to clone, we need to
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync * create a new diff file for the new "current state". */
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync const bool fCreateDiffs = (machine == pOldMachineState);
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync /* Add all attachments (and their parents) of the different
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync * machines to a worker list. */
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync SafeIfaceArray<IMediumAttachment> sfaAttachments;
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync if (FAILED(rc)) return rc;
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync for (size_t a = 0; a < sfaAttachments.size(); ++a)
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync {
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[a];
174f11bbd5c277153742aa5e6c3bd640bf379547vboxsync DeviceType_T type;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pAtt->COMGETTER(Type)(&type);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Only harddisk's are of interest. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (type != DeviceType_HardDisk)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync continue;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /* Valid medium attached? */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync ComPtr<IMedium> pSrcMedium;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pAtt->COMGETTER(Medium)(pSrcMedium.asOutParam());
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (pSrcMedium.isNull())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync continue;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MEDIUMTASKCHAIN mtc;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync mtc.fCreateDiffs = fCreateDiffs;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.fAttachLinked = fAttachLinked;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync while (!pSrcMedium.isNull())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Build a histogram of used medias and the parent chain. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync ++mediaHist[pSrcMedium];
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Refresh the state so that the file size get read. */
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync MediumState_T e;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pSrcMedium->RefreshState(&e);
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync LONG64 lSize;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pSrcMedium->COMGETTER(Size)(&lSize);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync MEDIUMTASK mt;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync mt.uIdx = UINT32_MAX;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mt.pMedium = pSrcMedium;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync mt.uWeight = (ULONG)((lSize + _1M - 1) / _1M);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.chain.append(mt);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync /* Query next parent. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pSrcMedium->COMGETTER(Parent)(pSrcMedium.asOutParam());
df2a53dee17325742e7464e7f53d3f99dc500f3avboxsync if (FAILED(rc)) return rc;
df2a53dee17325742e7464e7f53d3f99dc500f3avboxsync }
df2a53dee17325742e7464e7f53d3f99dc500f3avboxsync
df2a53dee17325742e7464e7f53d3f99dc500f3avboxsync llMedias.append(mtc);
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync }
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync /* Add the save state files of this machine if there is one. */
9113fcf881235e2b3df9ce4760b299c929ac3a62vboxsync rc = addSaveState(machine, uCount, uTotalWeight);
9113fcf881235e2b3df9ce4760b299c929ac3a62vboxsync if (FAILED(rc)) return rc;
9113fcf881235e2b3df9ce4760b299c929ac3a62vboxsync }
9113fcf881235e2b3df9ce4760b299c929ac3a62vboxsync /* Build up the index list of the image chain. Unfortunately we can't do
9113fcf881235e2b3df9ce4760b299c929ac3a62vboxsync * that in the previous loop, cause there we go from child -> parent and
9113fcf881235e2b3df9ce4760b299c929ac3a62vboxsync * didn't know how many are between. */
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync for (size_t i = 0; i < llMedias.size(); ++i)
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync {
9113fcf881235e2b3df9ce4760b299c929ac3a62vboxsync uint32_t uIdx = 0;
9113fcf881235e2b3df9ce4760b299c929ac3a62vboxsync MEDIUMTASKCHAIN &mtc = llMedias.at(i);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync for (size_t a = mtc.chain.size(); a > 0; --a)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.chain[a - 1].uIdx = uIdx++;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync#ifdef DEBUG_poetzsch
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Print the histogram */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync std::map<ComPtr<IMedium>, uint32_t>::iterator it;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (it = mediaHist.begin(); it != mediaHist.end(); ++it)
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync Bstr bstrSrcName;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = (*it).first->COMGETTER(Name)(bstrSrcName.asOutParam());
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync RTPrintf("%ls: %d\n", bstrSrcName.raw(), (*it).second);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync#endif
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Go over every medium in the list and check if it either a directly
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * attached disk or has more than one children. If so it needs to be
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * replicated. Also we have to make sure that any direct or indirect
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * children knows of the new parent (which doesn't necessarily mean it
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * is a direct children in the source chain). */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (size_t i = 0; i < llMedias.size(); ++i)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync MEDIUMTASKCHAIN &mtc = llMedias.at(i);
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync RTCList<MEDIUMTASK> newChain;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync uint32_t used = 0;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync for (size_t a = 0; a < mtc.chain.size(); ++a)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync const MEDIUMTASK &mt = mtc.chain.at(a);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync uint32_t hist = mediaHist[mt.pMedium];
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync#ifdef DEBUG_poetzsch
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync Bstr bstrSrcName;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = mt.pMedium->COMGETTER(Name)(bstrSrcName.asOutParam());
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync RTPrintf("%ls: %d (%d)\n", bstrSrcName.raw(), hist, used);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync#endif
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync /* Check if there is a "step" in the histogram when going the chain
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync * upwards. If so, we need this image, cause there is another branch
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * from here in the cloned VM. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (hist > used)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync newChain.append(mt);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync used = hist;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Make sure we always using the old base name as new base name, even
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * if the base is a differencing image in the source VM (with the UUID
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * as name). */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = queryBaseName(newChain.last().pMedium, newChain.last().strBaseName);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Update the old medium chain with the updated one. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.chain = newChain;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Update the progress info. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync updateProgressStats(mtc, fAttachLinked, uCount, uTotalWeight);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncHRESULT MachineCloneVMPrivate::queryMediasForAllStates(const RTCList<ComObjPtr<Machine> > &machineList, bool fAttachLinked, ULONG &uCount, ULONG &uTotalWeight)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* In this case we create a exact copy of the original VM. This means just
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * adding all directly and indirectly attached disk images to the worker
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * list. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync HRESULT rc = S_OK;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (size_t i = 0; i < machineList.size(); ++i)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync const ComObjPtr<Machine> &machine = machineList.at(i);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* If this is the Snapshot Machine we want to clone, we need to
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * create a new diff file for the new "current state". */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync const bool fCreateDiffs = (machine == pOldMachineState);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Add all attachments (and their parents) of the different
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync * machines to a worker list. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync SafeIfaceArray<IMediumAttachment> sfaAttachments;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (FAILED(rc)) return rc;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync for (size_t a = 0; a < sfaAttachments.size(); ++a)
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync {
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[a];
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync DeviceType_T type;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync rc = pAtt->COMGETTER(Type)(&type);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (FAILED(rc)) return rc;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync /* Only harddisk's are of interest. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (type != DeviceType_HardDisk)
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync continue;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Valid medium attached? */
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync ComPtr<IMedium> pSrcMedium;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync rc = pAtt->COMGETTER(Medium)(pSrcMedium.asOutParam());
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (pSrcMedium.isNull())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync continue;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Build up a child->parent list of this attachment. (Note: we are
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * not interested of any child's not attached to this VM. So this
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * will not create a full copy of the base/child relationship.) */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync MEDIUMTASKCHAIN mtc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.fCreateDiffs = fCreateDiffs;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync mtc.fAttachLinked = fAttachLinked;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync while (!pSrcMedium.isNull())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Refresh the state so that the file size get read. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MediumState_T e;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pSrcMedium->RefreshState(&e);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync LONG64 lSize;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pSrcMedium->COMGETTER(Size)(&lSize);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Save the current medium, for later cloning. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MEDIUMTASK mt;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mt.uIdx = UINT32_MAX;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mt.pMedium = pSrcMedium;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync mt.uWeight = (ULONG)((lSize + _1M - 1) / _1M);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.chain.append(mt);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Query next parent. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pSrcMedium->COMGETTER(Parent)(pSrcMedium.asOutParam());
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) return rc;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Update the progress info. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync updateProgressStats(mtc, fAttachLinked, uCount, uTotalWeight);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Append the list of images which have to be cloned. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync llMedias.append(mtc);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /* Add the save state files of this machine if there is one. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = addSaveState(machine, uCount, uTotalWeight);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (FAILED(rc)) return rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Build up the index list of the image chain. Unfortunately we can't do
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * that in the previous loop, cause there we go from child -> parent and
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * didn't know how many are between. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (size_t i = 0; i < llMedias.size(); ++i)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint32_t uIdx = 0;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync MEDIUMTASKCHAIN &mtc = llMedias.at(i);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (size_t a = mtc.chain.size(); a > 0; --a)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync mtc.chain[a - 1].uIdx = uIdx++;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return rc;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncbool MachineCloneVMPrivate::findSnapshot(const settings::SnapshotsList &snl, const Guid &id, settings::Snapshot &sn) const
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync settings::SnapshotsList::const_iterator it;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (it = snl.begin(); it != snl.end(); ++it)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (it->uuid == id)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync sn = (*it);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync return true;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync else if (!it->llChildSnapshots.empty())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (findSnapshot(it->llChildSnapshots, id, sn))
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync return true;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync return false;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncvoid MachineCloneVMPrivate::updateMACAddresses(settings::NetworkAdaptersList &nwl) const
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync const bool fNotNAT = options.contains(CloneOptions_KeepNATMACs);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync settings::NetworkAdaptersList::iterator it;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (it = nwl.begin(); it != nwl.end(); ++it)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if ( fNotNAT
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync && it->mode == NetworkAttachmentType_NAT)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync continue;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync Host::generateMACAddress(it->strMACAddress);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncvoid MachineCloneVMPrivate::updateMACAddresses(settings::SnapshotsList &sl) const
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync settings::SnapshotsList::iterator it;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (it = sl.begin(); it != sl.end(); ++it)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync updateMACAddresses(it->hardware.llNetworkAdapters);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (!it->llChildSnapshots.empty())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync updateMACAddresses(it->llChildSnapshots);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncvoid MachineCloneVMPrivate::updateStorageLists(settings::StorageControllersList &sc, const Bstr &bstrOldId, const Bstr &bstrNewId) const
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync settings::StorageControllersList::iterator it3;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for (it3 = sc.begin();
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync it3 != sc.end();
b6eb6140917e0b633bba260f465976326b36aee2vboxsync ++it3)
48dafba24ef28f07a241e5857a43b327822574a8vboxsync {
48dafba24ef28f07a241e5857a43b327822574a8vboxsync settings::AttachedDevicesList &llAttachments = it3->llAttachedDevices;
48dafba24ef28f07a241e5857a43b327822574a8vboxsync settings::AttachedDevicesList::iterator it4;
48dafba24ef28f07a241e5857a43b327822574a8vboxsync for (it4 = llAttachments.begin();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync it4 != llAttachments.end();
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync ++it4)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if ( it4->deviceType == DeviceType_HardDisk
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && it4->uuid == bstrOldId)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync it4->uuid = bstrNewId;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncvoid MachineCloneVMPrivate::updateSnapshotStorageLists(settings::SnapshotsList &sl, const Bstr &bstrOldId, const Bstr &bstrNewId) const
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync{
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync settings::SnapshotsList::iterator it;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync for ( it = sl.begin();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync it != sl.end();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ++it)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync updateStorageLists(it->storage.llStorageControllers, bstrOldId, bstrNewId);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (!it->llChildSnapshots.empty())
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync updateSnapshotStorageLists(it->llChildSnapshots, bstrOldId, bstrNewId);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync}
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsyncvoid MachineCloneVMPrivate::updateStateFile(settings::SnapshotsList &snl, const Guid &id, const Utf8Str &strFile) const
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync{
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync settings::SnapshotsList::iterator it;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync for (it = snl.begin(); it != snl.end(); ++it)
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync {
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (it->uuid == id)
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync it->strStateFile = strFile;
93771df67d4047d8b965665899b6a5bdf06ae277vboxsync else if (!it->llChildSnapshots.empty())
93771df67d4047d8b965665899b6a5bdf06ae277vboxsync updateStateFile(it->llChildSnapshots, id, strFile);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync}
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncHRESULT MachineCloneVMPrivate::createDifferencingMedium(const ComObjPtr<Machine> &pMachine, const ComObjPtr<Medium> &pParent, const Utf8Str &strSnapshotFolder, RTCList<ComObjPtr<Medium> > &newMedia, ComObjPtr<Medium> *ppDiff) const
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
80e46f984efd827517661c0e081a36014ca41af8vboxsync HRESULT rc = S_OK;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync try
80e46f984efd827517661c0e081a36014ca41af8vboxsync {
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync // check validity of parent object
80e46f984efd827517661c0e081a36014ca41af8vboxsync {
80e46f984efd827517661c0e081a36014ca41af8vboxsync AutoReadLock alock(pParent COMMA_LOCKVAL_SRC_POS);
80e46f984efd827517661c0e081a36014ca41af8vboxsync Bstr bstrSrcId;
80e46f984efd827517661c0e081a36014ca41af8vboxsync rc = pParent->COMGETTER(Id)(bstrSrcId.asOutParam());
80e46f984efd827517661c0e081a36014ca41af8vboxsync if (FAILED(rc)) throw rc;
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync }
06782e19f5e2144408396dcec922c423c5ef9da8vboxsync ComObjPtr<Medium> diff;
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync diff.createObject();
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync rc = diff->init(p->getVirtualBox(),
dbfa5765a2a72c30564ef1bd950720e89a06c96avboxsync pParent->getPreferredDiffFormat(),
dbfa5765a2a72c30564ef1bd950720e89a06c96avboxsync Utf8StrFmt("%s%c", strSnapshotFolder.c_str(), RTPATH_DELIMITER),
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync Guid::Empty /* empty media registry */);
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync if (FAILED(rc)) throw rc;
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync MediumLockList *pMediumLockList(new MediumLockList());
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync rc = diff->createMediumLockList(true /* fFailIfInaccessible */,
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync true /* fMediumLockWrite */,
3221176430afca4d1be145b04bf50163fab4fdb1vboxsync pParent,
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync *pMediumLockList);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) throw rc;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync rc = pMediumLockList->Lock();
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (FAILED(rc)) throw rc;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync /* this already registers the new diff image */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pParent->createDiffStorage(diff, MediumVariant_Standard,
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync pMediumLockList,
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync NULL /* aProgress */,
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync true /* aWait */);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync delete pMediumLockList;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (FAILED(rc)) throw rc;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync /* Remember created medium. */
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync newMedia.append(diff);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync *ppDiff = diff;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync catch (HRESULT rc2)
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync {
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync rc = rc2;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync catch (...)
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync {
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync rc = VirtualBoxBase::handleUnexpectedExceptions(pMachine, RT_SRC_POS);
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync }
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync return rc;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync}
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync/* static */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsyncint MachineCloneVMPrivate::copyStateFileProgress(unsigned uPercentage, void *pvUser)
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync{
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync ComObjPtr<Progress> pProgress = *static_cast< ComObjPtr<Progress>* >(pvUser);
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync BOOL fCanceled = false;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync HRESULT rc = pProgress->COMGETTER(Canceled)(&fCanceled);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) return VERR_GENERAL_FAILURE;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync /* If canceled by the user tell it to the copy operation. */
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (fCanceled) return VERR_CANCELLED;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /* Set the new process. */
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync rc = pProgress->SetCurrentOperationProgress(uPercentage);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (FAILED(rc)) return VERR_GENERAL_FAILURE;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync return VINF_SUCCESS;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync// The public class
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync/////////////////////////////////////////////////////////////////////////////
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsyncMachineCloneVM::MachineCloneVM(ComObjPtr<Machine> pSrcMachine, ComObjPtr<Machine> pTrgMachine, CloneMode_T mode, const RTCList<CloneOptions_T> &opts)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync : d_ptr(new MachineCloneVMPrivate(this, pSrcMachine, pTrgMachine, mode, opts))
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync{
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync}
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsyncMachineCloneVM::~MachineCloneVM()
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync{
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync delete d_ptr;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync}
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsyncHRESULT MachineCloneVM::start(IProgress **pProgress)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync DPTR(MachineCloneVM);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync ComObjPtr<Machine> &p = d->p;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync HRESULT rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync try
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync /** @todo r=klaus this code cannot deal with someone crazy specifying
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * IMachine corresponding to a mutable machine as d->pSrcMachine */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (d->pSrcMachine->isSessionMachine())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync throw p->setError(E_INVALIDARG, "The source machine is mutable");
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /* Handle the special case that someone is requesting a _full_ clone
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * with all snapshots (and the current state), but uses a snapshot
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * machine (and not the current one) as source machine. In this case we
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * just replace the source (snapshot) machine with the current machine. */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if ( d->mode == CloneMode_AllStates
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync && d->pSrcMachine->isSnapshotMachine())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync Bstr bstrSrcMachineId;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = d->pSrcMachine->COMGETTER(Id)(bstrSrcMachineId.asOutParam());
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) throw rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync ComPtr<IMachine> newSrcMachine;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = d->pSrcMachine->getVirtualBox()->FindMachine(bstrSrcMachineId.raw(), newSrcMachine.asOutParam());
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) throw rc;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync d->pSrcMachine = (Machine*)(IMachine*)newSrcMachine;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync bool fSubtreeIncludesCurrent = false;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync ComObjPtr<Machine> pCurrState;
63b785c3291332a86a9bc473e68f08121368898bvboxsync if (d->mode == CloneMode_MachineAndChildStates)
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync {
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync if (d->pSrcMachine->isSnapshotMachine())
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync {
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync /* find machine object for current snapshot of current state */
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync Bstr bstrSrcMachineId;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync rc = d->pSrcMachine->COMGETTER(Id)(bstrSrcMachineId.asOutParam());
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync if (FAILED(rc)) throw rc;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync ComPtr<IMachine> pCurr;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync rc = d->pSrcMachine->getVirtualBox()->FindMachine(bstrSrcMachineId.raw(), pCurr.asOutParam());
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync if (FAILED(rc)) throw rc;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync if (pCurr.isNull())
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync throw p->setError(VBOX_E_OBJECT_NOT_FOUND);
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync pCurrState = (Machine *)(IMachine *)pCurr;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync ComPtr<ISnapshot> pSnapshot;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync rc = pCurrState->COMGETTER(CurrentSnapshot)(pSnapshot.asOutParam());
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync if (FAILED(rc)) throw rc;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync if (pSnapshot.isNull())
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync throw p->setError(VBOX_E_OBJECT_NOT_FOUND);
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync ComPtr<IMachine> pCurrSnapMachine;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync rc = pSnapshot->COMGETTER(Machine)(pCurrSnapMachine.asOutParam());
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync if (FAILED(rc)) throw rc;
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync if (pCurrSnapMachine.isNull())
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync throw p->setError(VBOX_E_OBJECT_NOT_FOUND);
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync /* now check if there is a parent chain which leads to the
1e9377d042fa2ea3e2cd78805678f23f64db55f6vboxsync * snapshot machine defining the subtree. */
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync while (!pSnapshot.isNull())
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync {
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync ComPtr<IMachine> pSnapMachine;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync rc = pSnapshot->COMGETTER(Machine)(pSnapMachine.asOutParam());
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (FAILED(rc)) throw rc;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (pSnapMachine.isNull())
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync throw p->setError(VBOX_E_OBJECT_NOT_FOUND);
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (pSnapMachine == d->pSrcMachine)
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync {
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync fSubtreeIncludesCurrent = true;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync break;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync rc = pSnapshot->COMGETTER(Parent)(pSnapshot.asOutParam());
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync if (FAILED(rc)) throw rc;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync else
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync {
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync /* If the subtree is only the Current State simply use the
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync * 'machine' case for cloning. It is easier to understand. */
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync d->mode = CloneMode_MachineState;
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync }
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync /* Lock the target machine early (so nobody mess around with it in the meantime). */
051eba4436f9c682f7873390fb327e8eceb9e0efvboxsync AutoWriteLock trgLock(d->pTrgMachine COMMA_LOCKVAL_SRC_POS);
6b74e8c9c04e1d625ccd055b5a25050a15831b21vboxsync
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if (d->pSrcMachine->isSnapshotMachine())
6febf3149010855617e4a37e2c49f93d68930d44vboxsync d->snapshotId = d->pSrcMachine->getSnapshotId();
6febf3149010855617e4a37e2c49f93d68930d44vboxsync
6febf3149010855617e4a37e2c49f93d68930d44vboxsync /* Add the current machine and all snapshot machines below this machine
6febf3149010855617e4a37e2c49f93d68930d44vboxsync * in a list for further processing. */
6febf3149010855617e4a37e2c49f93d68930d44vboxsync RTCList< ComObjPtr<Machine> > machineList;
6febf3149010855617e4a37e2c49f93d68930d44vboxsync
6febf3149010855617e4a37e2c49f93d68930d44vboxsync /* Include current state? */
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if ( d->mode == CloneMode_MachineState
6febf3149010855617e4a37e2c49f93d68930d44vboxsync || d->mode == CloneMode_AllStates)
dfb2e698385f22ba39053f27fe2711e463acd3a1vboxsync machineList.append(d->pSrcMachine);
dfb2e698385f22ba39053f27fe2711e463acd3a1vboxsync /* Should be done a depth copy with all child snapshots? */
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if ( d->mode == CloneMode_MachineAndChildStates
6febf3149010855617e4a37e2c49f93d68930d44vboxsync || d->mode == CloneMode_AllStates)
6febf3149010855617e4a37e2c49f93d68930d44vboxsync {
dfb2e698385f22ba39053f27fe2711e463acd3a1vboxsync ULONG cSnapshots = 0;
dfb2e698385f22ba39053f27fe2711e463acd3a1vboxsync rc = d->pSrcMachine->COMGETTER(SnapshotCount)(&cSnapshots);
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if (FAILED(rc)) throw rc;
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if (cSnapshots > 0)
515d43bd83e097dbf72b54267e8288b53f13b3a0vboxsync {
6febf3149010855617e4a37e2c49f93d68930d44vboxsync Utf8Str id;
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if (d->mode == CloneMode_MachineAndChildStates)
6febf3149010855617e4a37e2c49f93d68930d44vboxsync id = d->snapshotId.toString();
6febf3149010855617e4a37e2c49f93d68930d44vboxsync ComPtr<ISnapshot> pSnapshot;
6febf3149010855617e4a37e2c49f93d68930d44vboxsync rc = d->pSrcMachine->FindSnapshot(Bstr(id).raw(), pSnapshot.asOutParam());
6febf3149010855617e4a37e2c49f93d68930d44vboxsync if (FAILED(rc)) throw rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = d->createMachineList(pSnapshot, machineList);
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) throw rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (d->mode == CloneMode_MachineAndChildStates)
63b785c3291332a86a9bc473e68f08121368898bvboxsync {
63b785c3291332a86a9bc473e68f08121368898bvboxsync if (fSubtreeIncludesCurrent)
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
63b785c3291332a86a9bc473e68f08121368898bvboxsync if (pCurrState.isNull())
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync throw p->setError(VBOX_E_OBJECT_NOT_FOUND);
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync machineList.append(pCurrState);
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync else
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync {
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync rc = pSnapshot->COMGETTER(Machine)(d->pOldMachineState.asOutParam());
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync if (FAILED(rc)) throw rc;
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync }
63b785c3291332a86a9bc473e68f08121368898bvboxsync
63b785c3291332a86a9bc473e68f08121368898bvboxsync /* We have different approaches for getting the medias which needs to
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * be replicated based on the clone mode the user requested (this is
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * mostly about the full clone mode).
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * MachineState:
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * - Only the images which are directly attached to an source VM will
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * be cloned. Any parent disks in the original chain will be merged
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * into the final cloned disk.
63b785c3291332a86a9bc473e68f08121368898bvboxsync * MachineAndChildStates:
63b785c3291332a86a9bc473e68f08121368898bvboxsync * - In this case we search for images which have more than one
63b785c3291332a86a9bc473e68f08121368898bvboxsync * children in the cloned VM or are directly attached to the new VM.
63b785c3291332a86a9bc473e68f08121368898bvboxsync * All others will be merged into the remaining images which are
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * cloned.
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * This case is the most complicated one and needs several iterations
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * to make sure we are only cloning images which are really
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * necessary.
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * AllStates:
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * - All disks which are directly or indirectly attached to the
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * original VM are cloned.
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync *
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync * Note: If you change something generic in one of the methods its
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * likely that it need to be changed in the others as well! */
aeb9498c4d9854ed42b271541d34c7bad97b4c77vboxsync ULONG uCount = 2; /* One init task and the machine creation. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync ULONG uTotalWeight = 2; /* The init task and the machine creation is worth one. */
825c2485cf84eec495985ffd605a1c9cddee8c32vboxsync bool fAttachLinked = d->options.contains(CloneOptions_Link); /* Linked clones requested? */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync switch (d->mode)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case CloneMode_MachineState: d->queryMediasForMachineState(machineList, fAttachLinked, uCount, uTotalWeight); break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case CloneMode_MachineAndChildStates: d->queryMediasForMachineAndChildStates(machineList, fAttachLinked, uCount, uTotalWeight); break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case CloneMode_AllStates: d->queryMediasForAllStates(machineList, fAttachLinked, uCount, uTotalWeight); break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
2294b1479e3fb6f4e9c9550b3e15f3d3a3f1fc24vboxsync /* Now create the progress project, so the user knows whats going on. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = d->pProgress.createObject();
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (FAILED(rc)) throw rc;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync rc = d->pProgress->init(p->getVirtualBox(),
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync static_cast<IMachine*>(d->pSrcMachine) /* aInitiator */,
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync Bstr(p->tr("Cloning Machine")).raw(),
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync true /* fCancellable */,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uCount,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uTotalWeight,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Bstr(p->tr("Initialize Cloning")).raw(),
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync 1);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) throw rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync int vrc = d->startWorker();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (RT_FAILURE(vrc))
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync p->setError(VBOX_E_IPRT_ERROR, "Could not create machine clone thread (%Rrc)", vrc);
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync catch (HRESULT rc2)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = rc2;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (SUCCEEDED(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync d->pProgress.queryInterfaceTo(pProgress);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync}
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncHRESULT MachineCloneVM::run()
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync DPTR(MachineCloneVM);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComObjPtr<Machine> &p = d->p;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync AutoCaller autoCaller(p);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(autoCaller.rc())) return autoCaller.rc();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
2294b1479e3fb6f4e9c9550b3e15f3d3a3f1fc24vboxsync AutoReadLock srcLock(p COMMA_LOCKVAL_SRC_POS);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync AutoWriteLock trgLock(d->pTrgMachine COMMA_LOCKVAL_SRC_POS);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync HRESULT rc = S_OK;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Todo:
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * - What about log files?
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Where should all the media go? */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Utf8Str strTrgSnapshotFolder;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Utf8Str strTrgMachineFolder = d->pTrgMachine->getSettingsFileFull();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync strTrgMachineFolder.stripFilename();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync RTCList<ComObjPtr<Medium> > newMedia; /* All created images */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync RTCList<Utf8Str> newFiles; /* All extra created files (save states, ...) */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync try
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Copy all the configuration from this machine to an empty
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * configuration dataset. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync settings::MachineConfigFile trgMCF = *d->pSrcMachine->mData->pMachineConfigFile;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Reset media registry. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.mediaRegistry.llHardDisks.clear();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* If we got a valid snapshot id, replace the hardware/storage section
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * with the stuff from the snapshot. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync settings::Snapshot sn;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (d->snapshotId.isValid() && !d->snapshotId.isZero())
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (!d->findSnapshot(trgMCF.llFirstSnapshot, d->snapshotId, sn))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync throw p->setError(E_FAIL,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync p->tr("Could not find data to snapshots '%s'"), d->snapshotId.toString().c_str());
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (d->mode == CloneMode_MachineState)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (sn.uuid.isValid() && !sn.uuid.isZero())
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync {
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync trgMCF.hardwareMachine = sn.hardware;
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync trgMCF.storageMachine = sn.storage;
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync }
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync /* Remove any hint on snapshots. */
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync trgMCF.llFirstSnapshot.clear();
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync trgMCF.uuidCurrentSnapshot.clear();
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync }
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync else if ( d->mode == CloneMode_MachineAndChildStates
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync && sn.uuid.isValid()
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync && !sn.uuid.isZero())
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (!d->pOldMachineState.isNull())
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Copy the snapshot data to the current machine. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.hardwareMachine = sn.hardware;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.storageMachine = sn.storage;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Current state is under root snapshot. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.uuidCurrentSnapshot = sn.uuid;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* There will be created a new differencing image based on this
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * snapshot. So reset the modified state. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.fCurrentStateModified = false;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync /* The snapshot will be the root one. */
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync trgMCF.llFirstSnapshot.clear();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.llFirstSnapshot.push_back(sn);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Generate new MAC addresses for all machines when not forbidden. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (!d->options.contains(CloneOptions_KeepAllMACs))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync d->updateMACAddresses(trgMCF.hardwareMachine.llNetworkAdapters);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync d->updateMACAddresses(trgMCF.llFirstSnapshot);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
825c2485cf84eec495985ffd605a1c9cddee8c32vboxsync /* When the current snapshot folder is absolute we reset it to the
e073b07dcb5c9827f0530a9bfa2643356c5656dbvboxsync * default relative folder. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (RTPathStartsWithRoot(trgMCF.machineUserData.strSnapshotFolder.c_str()))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.machineUserData.strSnapshotFolder = "Snapshots";
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.strStateFile = "";
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Set the new name. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync const Utf8Str strOldVMName = trgMCF.machineUserData.strName;
dad2c11c7cb6ce93d5db9a3266ed2b004d41c917vboxsync trgMCF.machineUserData.strName = d->pTrgMachine->mUserData->s.strName;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgMCF.uuid = d->pTrgMachine->mData->mUuid;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Bstr bstrSrcSnapshotFolder;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = d->pSrcMachine->COMGETTER(SnapshotFolder)(bstrSrcSnapshotFolder.asOutParam());
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) throw rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* The absolute name of the snapshot folder. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync strTrgSnapshotFolder = Utf8StrFmt("%s%c%s", strTrgMachineFolder.c_str(), RTPATH_DELIMITER, trgMCF.machineUserData.strSnapshotFolder.c_str());
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Should we rename the disk names. */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync bool fKeepDiskNames = d->options.contains(CloneOptions_KeepDiskNames);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync /* We need to create a map with the already created medias. This is
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * necessary, cause different snapshots could have the same
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * parents/parent chain. If a medium is in this map already, it isn't
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * cloned a second time, but simply used. */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync typedef std::map<Utf8Str, ComObjPtr<Medium> > TStrMediumMap;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync typedef std::pair<Utf8Str, ComObjPtr<Medium> > TStrMediumPair;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync TStrMediumMap map;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync size_t cDisks = 0;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (size_t i = 0; i < d->llMedias.size(); ++i)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync const MEDIUMTASKCHAIN &mtc = d->llMedias.at(i);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync ComObjPtr<Medium> pNewParent;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync uint32_t uSrcParentIdx = UINT32_MAX;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint32_t uTrgParentIdx = UINT32_MAX;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (size_t a = mtc.chain.size(); a > 0; --a)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync const MEDIUMTASK &mt = mtc.chain.at(a - 1);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync ComPtr<IMedium> pMedium = mt.pMedium;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Bstr bstrSrcName;
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync rc = pMedium->COMGETTER(Name)(bstrSrcName.asOutParam());
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync if (FAILED(rc)) throw rc;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync rc = d->pProgress->SetNextOperation(BstrFmt(p->tr("Cloning Disk '%ls' ..."), bstrSrcName.raw()).raw(), mt.uWeight);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync if (FAILED(rc)) throw rc;
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Bstr bstrSrcId;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pMedium->COMGETTER(Id)(bstrSrcId.asOutParam());
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) throw rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (mtc.fAttachLinked)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync IMedium *pTmp = pMedium;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComObjPtr<Medium> pLMedium = static_cast<Medium*>(pTmp);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pLMedium.isNull())
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync throw p->setError(VBOX_E_OBJECT_NOT_FOUND);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComObjPtr<Medium> pBase = pLMedium->getBase();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pBase->isReadOnly())
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync ComObjPtr<Medium> pDiff;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* create the diff under the snapshot medium */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgLock.release();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync srcLock.release();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = d->createDifferencingMedium(p, pLMedium, strTrgSnapshotFolder,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync newMedia, &pDiff);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync srcLock.acquire();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trgLock.acquire();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) throw rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync map.insert(TStrMediumPair(Utf8Str(bstrSrcId), pDiff));
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /* diff image has to be used... */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pNewParent = pDiff;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Attach the medium directly, as its type is not
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * subject to diff creation. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync newMedia.append(pLMedium);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync map.insert(TStrMediumPair(Utf8Str(bstrSrcId), pLMedium));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pNewParent = pLMedium;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync else
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Is a clone already there? */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync TStrMediumMap::iterator it = map.find(Utf8Str(bstrSrcId));
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync if (it != map.end())
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pNewParent = it->second;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync ComPtr<IMediumFormat> pSrcFormat;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pMedium->COMGETTER(MediumFormat)(pSrcFormat.asOutParam());
40f74699d21578c96f79fa80bd8563a72c7b315cvboxsync ULONG uSrcCaps = 0;
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync rc = pSrcFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap));
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) throw rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (ULONG j = 0; j < mediumFormatCap.size(); j++)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uSrcCaps |= mediumFormatCap[j];
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Default format? */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Utf8Str strDefaultFormat;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync p->mParent->getDefaultHardDiskFormat(strDefaultFormat);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Bstr bstrSrcFormat(strDefaultFormat);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ULONG srcVar = MediumVariant_Standard;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync com::SafeArray <MediumVariant_T> mediumVariant;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Is the source file based? */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if ((uSrcCaps & MediumFormatCapabilities_File) == MediumFormatCapabilities_File)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync /* Yes, just use the source format. Otherwise the defaults
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * will be used. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pMedium->COMGETTER(Format)(bstrSrcFormat.asOutParam());
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) throw rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync rc = pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(mediumVariant));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (FAILED(rc)) throw rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (size_t j = 0; j < mediumVariant.size(); j++)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync srcVar |= mediumVariant[j];
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync Guid newId;
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync newId.create();
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync Utf8Str strNewName(bstrSrcName);
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync if (!fKeepDiskNames)
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync {
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync Utf8Str strSrcTest = bstrSrcName;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync /* Check if we have to use another name. */
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync if (!mt.strBaseName.isEmpty())
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync strSrcTest = mt.strBaseName;
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync strSrcTest.stripSuffix();
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync /* If the old disk name was in {uuid} format we also
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync * want the new name in this format, but with the
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync * updated id of course. If the old disk was called
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync * like the VM name, we change it to the new VM name.
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync * For all other disks we rename them with this
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync * template: "new name-disk1.vdi". */
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync if (strSrcTest == strOldVMName)
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync strNewName = Utf8StrFmt("%s%s", trgMCF.machineUserData.strName.c_str(), RTPathSuffix(Utf8Str(bstrSrcName).c_str()));
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync else if ( strSrcTest.startsWith("{")
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync && strSrcTest.endsWith("}"))
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync {
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync strSrcTest = strSrcTest.substr(1, strSrcTest.length() - 2);
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync Guid temp_guid(strSrcTest);
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync if (temp_guid.isValid() && !temp_guid.isZero())
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync strNewName = Utf8StrFmt("%s%s", newId.toStringCurly().c_str(), RTPathSuffix(strNewName.c_str()));
39fa431e2dbe885a37b126ccd293f8e8255812a6vboxsync }
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync else
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync strNewName = Utf8StrFmt("%s-disk%d%s", trgMCF.machineUserData.strName.c_str(), ++cDisks,
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync RTPathSuffix(Utf8Str(bstrSrcName).c_str()));
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync }
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync /* Check if this medium comes from the snapshot folder, if
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync * so, put it there in the cloned machine as well.
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync * Otherwise it goes to the machine folder. */
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync Bstr bstrSrcPath;
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync Utf8Str strFile = Utf8StrFmt("%s%c%s", strTrgMachineFolder.c_str(), RTPATH_DELIMITER, strNewName.c_str());
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync rc = pMedium->COMGETTER(Location)(bstrSrcPath.asOutParam());
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync if (FAILED(rc)) throw rc;
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync if ( !bstrSrcPath.isEmpty()
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync && RTPathStartsWith(Utf8Str(bstrSrcPath).c_str(), Utf8Str(bstrSrcSnapshotFolder).c_str())
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync && (fKeepDiskNames || mt.strBaseName.isEmpty()))
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync strFile = Utf8StrFmt("%s%c%s", strTrgSnapshotFolder.c_str(), RTPATH_DELIMITER, strNewName.c_str());
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync /* Start creating the clone. */
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync ComObjPtr<Medium> pTarget;
77bbd3327e8130eb01de6c1c1d1ef54e0ab48be8vboxsync rc = pTarget.createObject();
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync if (FAILED(rc)) throw rc;
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync rc = pTarget->init(p->mParent,
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync Utf8Str(bstrSrcFormat),
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync strFile,
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync Guid::Empty /* empty media registry */);
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync if (FAILED(rc)) throw rc;
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync
bf88068260ded16af90b7da4867240fbdd9c8017vboxsync /* Update the new uuid. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pTarget->updateId(newId);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync srcLock.release();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Do the disk cloning. */
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync ComPtr<IProgress> progress2;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ComObjPtr<Medium> pLMedium = static_cast<Medium*>((IMedium*)pMedium);
825c2485cf84eec495985ffd605a1c9cddee8c32vboxsync rc = pLMedium->cloneToEx(pTarget,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync srcVar,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pNewParent,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync progress2.asOutParam(),
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uSrcParentIdx,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uTrgParentIdx);
41c24e185aa1d6b5dc290edbd061c5a3c23a9e2fvboxsync if (FAILED(rc)) throw rc;
/* Wait until the async process has finished. */
rc = d->pProgress->WaitForAsyncProgressCompletion(progress2);
srcLock.acquire();
if (FAILED(rc)) throw rc;
/* Check the result of the async process. */
LONG iRc;
rc = progress2->COMGETTER(ResultCode)(&iRc);
if (FAILED(rc)) throw rc;
/* If the thread of the progress object has an error, then
* retrieve the error info from there, or it'll be lost. */
if (FAILED(iRc))
throw p->setError(ProgressErrorInfo(progress2));
/* Remember created medium. */
newMedia.append(pTarget);
/* Get the medium type from the source and set it to the
* new medium. */
MediumType_T type;
rc = pMedium->COMGETTER(Type)(&type);
if (FAILED(rc)) throw rc;
rc = pTarget->COMSETTER(Type)(type);
if (FAILED(rc)) throw rc;
map.insert(TStrMediumPair(Utf8Str(bstrSrcId), pTarget));
/* register the new harddisk */
{
AutoWriteLock tlock(p->mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
rc = p->mParent->registerMedium(pTarget, &pTarget,
DeviceType_HardDisk);
if (FAILED(rc)) throw rc;
}
/* This medium becomes the parent of the next medium in the
* chain. */
pNewParent = pTarget;
}
}
/* Save the current source medium index as the new parent
* medium index. */
uSrcParentIdx = mt.uIdx;
/* Simply increase the target index. */
++uTrgParentIdx;
}
Bstr bstrSrcId;
rc = mtc.chain.first().pMedium->COMGETTER(Id)(bstrSrcId.asOutParam());
if (FAILED(rc)) throw rc;
Bstr bstrTrgId;
rc = pNewParent->COMGETTER(Id)(bstrTrgId.asOutParam());
if (FAILED(rc)) throw rc;
/* update snapshot configuration */
d->updateSnapshotStorageLists(trgMCF.llFirstSnapshot, bstrSrcId, bstrTrgId);
/* create new 'Current State' diff for caller defined place */
if (mtc.fCreateDiffs)
{
const MEDIUMTASK &mt = mtc.chain.first();
ComObjPtr<Medium> pLMedium = static_cast<Medium*>((IMedium*)mt.pMedium);
if (pLMedium.isNull())
throw p->setError(VBOX_E_OBJECT_NOT_FOUND);
ComObjPtr<Medium> pBase = pLMedium->getBase();
if (pBase->isReadOnly())
{
ComObjPtr<Medium> pDiff;
trgLock.release();
srcLock.release();
rc = d->createDifferencingMedium(p, pNewParent, strTrgSnapshotFolder,
newMedia, &pDiff);
srcLock.acquire();
trgLock.acquire();
if (FAILED(rc)) throw rc;
/* diff image has to be used... */
pNewParent = pDiff;
}
else
{
/* Attach the medium directly, as its type is not
* subject to diff creation. */
newMedia.append(pNewParent);
}
rc = pNewParent->COMGETTER(Id)(bstrTrgId.asOutParam());
if (FAILED(rc)) throw rc;
}
/* update 'Current State' configuration */
d->updateStorageLists(trgMCF.storageMachine.llStorageControllers, bstrSrcId, bstrTrgId);
}
/* Make sure all disks know of the new machine uuid. We do this last to
* be able to change the medium type above. */
for (size_t i = newMedia.size(); i > 0; --i)
{
const ComObjPtr<Medium> &pMedium = newMedia.at(i - 1);
AutoCaller mac(pMedium);
if (FAILED(mac.rc())) throw mac.rc();
AutoWriteLock mlock(pMedium COMMA_LOCKVAL_SRC_POS);
Guid uuid = d->pTrgMachine->mData->mUuid;
if (d->options.contains(CloneOptions_Link))
{
ComObjPtr<Medium> pParent = pMedium->getParent();
mlock.release();
if (!pParent.isNull())
{
AutoCaller mac2(pParent);
if (FAILED(mac2.rc())) throw mac2.rc();
AutoReadLock mlock2(pParent COMMA_LOCKVAL_SRC_POS);
if (pParent->getFirstRegistryMachineId(uuid))
{
mlock2.release();
trgLock.release();
srcLock.release();
p->mParent->markRegistryModified(uuid);
srcLock.acquire();
trgLock.acquire();
mlock2.acquire();
}
}
mlock.acquire();
}
pMedium->addRegistry(uuid, false /* fRecurse */);
}
/* Check if a snapshot folder is necessary and if so doesn't already
* exists. */
if ( !d->llSaveStateFiles.isEmpty()
&& !RTDirExists(strTrgSnapshotFolder.c_str()))
{
int vrc = RTDirCreateFullPath(strTrgSnapshotFolder.c_str(), 0700);
if (RT_FAILURE(vrc))
throw p->setError(VBOX_E_IPRT_ERROR,
p->tr("Could not create snapshots folder '%s' (%Rrc)"), strTrgSnapshotFolder.c_str(), vrc);
}
/* Clone all save state files. */
for (size_t i = 0; i < d->llSaveStateFiles.size(); ++i)
{
SAVESTATETASK sst = d->llSaveStateFiles.at(i);
const Utf8Str &strTrgSaveState = Utf8StrFmt("%s%c%s", strTrgSnapshotFolder.c_str(), RTPATH_DELIMITER, RTPathFilename(sst.strSaveStateFile.c_str()));
/* Move to next sub-operation. */
rc = d->pProgress->SetNextOperation(BstrFmt(p->tr("Copy save state file '%s' ..."), RTPathFilename(sst.strSaveStateFile.c_str())).raw(), sst.uWeight);
if (FAILED(rc)) throw rc;
/* Copy the file only if it was not copied already. */
if (!newFiles.contains(strTrgSaveState.c_str()))
{
int vrc = RTFileCopyEx(sst.strSaveStateFile.c_str(), strTrgSaveState.c_str(), 0, MachineCloneVMPrivate::copyStateFileProgress, &d->pProgress);
if (RT_FAILURE(vrc))
throw p->setError(VBOX_E_IPRT_ERROR,
p->tr("Could not copy state file '%s' to '%s' (%Rrc)"), sst.strSaveStateFile.c_str(), strTrgSaveState.c_str(), vrc);
newFiles.append(strTrgSaveState);
}
/* Update the path in the configuration either for the current
* machine state or the snapshots. */
if (!sst.snapshotUuid.isValid() || sst.snapshotUuid.isZero())
trgMCF.strStateFile = strTrgSaveState;
else
d->updateStateFile(trgMCF.llFirstSnapshot, sst.snapshotUuid, strTrgSaveState);
}
{
rc = d->pProgress->SetNextOperation(BstrFmt(p->tr("Create Machine Clone '%s' ..."), trgMCF.machineUserData.strName.c_str()).raw(), 1);
if (FAILED(rc)) throw rc;
/* After modifying the new machine config, we can copy the stuff
* over to the new machine. The machine have to be mutable for
* this. */
rc = d->pTrgMachine->checkStateDependency(p->MutableStateDep);
if (FAILED(rc)) throw rc;
rc = d->pTrgMachine->loadMachineDataFromSettings(trgMCF,
&d->pTrgMachine->mData->mUuid);
if (FAILED(rc)) throw rc;
/* save all VM data */
bool fNeedsGlobalSaveSettings = false;
rc = d->pTrgMachine->saveSettings(&fNeedsGlobalSaveSettings, Machine::SaveS_Force);
if (FAILED(rc)) throw rc;
/* Release all locks */
trgLock.release();
srcLock.release();
if (fNeedsGlobalSaveSettings)
{
/* save the global settings; for that we should hold only the
* VirtualBox lock */
AutoWriteLock vlock(p->mParent COMMA_LOCKVAL_SRC_POS);
rc = p->mParent->saveSettings();
if (FAILED(rc)) throw rc;
}
}
/* Any additional machines need saving? */
p->mParent->saveModifiedRegistries();
}
catch (HRESULT rc2)
{
rc = rc2;
}
catch (...)
{
rc = VirtualBoxBase::handleUnexpectedExceptions(p, RT_SRC_POS);
}
MultiResult mrc(rc);
/* Cleanup on failure (CANCEL also) */
if (FAILED(rc))
{
int vrc = VINF_SUCCESS;
/* Delete all created files. */
for (size_t i = 0; i < newFiles.size(); ++i)
{
vrc = RTFileDelete(newFiles.at(i).c_str());
if (RT_FAILURE(vrc))
mrc = p->setError(VBOX_E_IPRT_ERROR, p->tr("Could not delete file '%s' (%Rrc)"), newFiles.at(i).c_str(), vrc);
}
/* Delete all already created medias. (Reverse, cause there could be
* parent->child relations.) */
for (size_t i = newMedia.size(); i > 0; --i)
{
const ComObjPtr<Medium> &pMedium = newMedia.at(i - 1);
mrc = pMedium->deleteStorage(NULL /* aProgress */,
true /* aWait */);
pMedium->Close();
}
/* Delete the snapshot folder when not empty. */
if (!strTrgSnapshotFolder.isEmpty())
RTDirRemove(strTrgSnapshotFolder.c_str());
/* Delete the machine folder when not empty. */
RTDirRemove(strTrgMachineFolder.c_str());
/* Must save the modified registries */
p->mParent->saveModifiedRegistries();
}
return mrc;
}
void MachineCloneVM::destroy()
{
delete this;
}