VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/MachineImplMoveVM.cpp@ 70692

最後變更 在這個檔案從70692是 70692,由 vboxsync 提交於 7 年 前

bugref:8345. The unused variables were removed.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 50.9 KB
 
1/* $Id: MachineImplMoveVM.cpp 70692 2018-01-22 20:55:41Z vboxsync $ */
2/** @file
3 * Implementation of MachineMoveVM
4 */
5
6/*
7 * Copyright (C) 2011-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#include <iprt/fs.h>
18#include <iprt/dir.h>
19#include <iprt/file.h>
20#include <iprt/path.h>
21#include <iprt/cpp/utils.h>
22#include <iprt/stream.h>
23
24#include "MachineImplMoveVM.h"
25#include "VirtualBoxImpl.h"
26#include "Logging.h"
27
28typedef std::multimap<Utf8Str, Utf8Str> list_t;
29typedef std::multimap<Utf8Str, Utf8Str>::const_iterator cit_t;
30typedef std::multimap<Utf8Str, Utf8Str>::iterator it_t;
31typedef std::pair <std::multimap<Utf8Str, Utf8Str>::iterator, std::multimap<Utf8Str, Utf8Str>::iterator> rangeRes_t;
32
33struct fileList_t
34{
35 HRESULT add(const Utf8Str& folder, const Utf8Str& file)
36 {
37 HRESULT rc = S_OK;
38 m_list.insert(std::make_pair(folder, file));
39 return rc;
40 }
41
42 HRESULT add(const Utf8Str& fullPath)
43 {
44 HRESULT rc = S_OK;
45 Utf8Str folder = fullPath;
46 folder.stripFilename();
47 Utf8Str filename = fullPath;
48 filename.stripPath();
49 m_list.insert(std::make_pair(folder, filename));
50 return rc;
51 }
52
53 HRESULT removeFileFromList(const Utf8Str& fullPath)
54 {
55 HRESULT rc = S_OK;
56 Utf8Str folder = fullPath;
57 folder.stripFilename();
58 Utf8Str filename = fullPath;
59 filename.stripPath();
60 rangeRes_t res = m_list.equal_range(folder);
61 for (it_t it=res.first; it!=res.second; ++it)
62 {
63 if (it->second.equals(filename))
64 m_list.erase(it);
65 }
66 return rc;
67 }
68
69 HRESULT removeFileFromList(const Utf8Str& path, const Utf8Str& fileName)
70 {
71 HRESULT rc = S_OK;
72 rangeRes_t res = m_list.equal_range(path);
73 for (it_t it=res.first; it!=res.second; ++it)
74 {
75 if (it->second.equals(fileName))
76 m_list.erase(it);
77 }
78 return rc;
79 }
80
81 HRESULT removeFolderFromList(const Utf8Str& path)
82 {
83 HRESULT rc = S_OK;
84 m_list.erase(path);
85 return rc;
86 }
87
88 rangeRes_t getFilesInRange(const Utf8Str& path)
89 {
90 rangeRes_t res;
91 res = m_list.equal_range(path);
92 return res;
93 }
94
95 std::list<Utf8Str> getFilesInList(const Utf8Str& path)
96 {
97 std::list<Utf8Str> list_;
98 rangeRes_t res = m_list.equal_range(path);
99 for (it_t it=res.first; it!=res.second; ++it)
100 list_.push_back(it->second);
101 return list_;
102 }
103
104
105 list_t m_list;
106
107};
108
109HRESULT MachineMoveVM::init()
110{
111 HRESULT rc = S_OK;
112 Utf8Str strTargetFolder = m_targetPath;
113
114 /*
115 * We have a mode which user is able to request
116 * basic mode:
117 * - The images which are solely attached to the VM
118 * and located in the original VM folder will be moved.
119 *
120 * Comment: in the future some other modes can be added.
121 */
122
123 try
124 {
125 Utf8Str info;
126 int vrc = 0;
127
128 RTFOFF cbTotal = 0;
129 RTFOFF cbFree = 0;
130 uint32_t cbBlock = 0;
131 uint32_t cbSector = 0;
132
133 vrc = RTFsQuerySizes(strTargetFolder.c_str(), &cbTotal, &cbFree, &cbBlock, &cbSector);
134 if (FAILED(vrc)) throw vrc;
135 long long totalFreeSpace = cbFree;
136 long long totalSpace = cbTotal;
137 info = Utf8StrFmt("blocks: total %lld, free %u ", cbTotal, cbFree);
138 RTPrintf("%s \n", info.c_str());
139 RTPrintf("total space (Kb) %lld (Mb) %lld (Gb) %lld\n",
140 totalSpace/1024, totalSpace/(1024*1024), totalSpace/(1024*1024*1024));
141 RTPrintf("total free space (Kb) %lld (Mb) %lld (Gb) %lld\n",
142 totalFreeSpace/1024, totalFreeSpace/(1024*1024), totalFreeSpace/(1024*1024*1024));
143
144 RTFSPROPERTIES properties;
145 vrc = RTFsQueryProperties(strTargetFolder.c_str(), &properties);
146 if (FAILED(vrc)) throw vrc;
147 info = Utf8StrFmt("disk properties:\n"
148 "remote: %s \n"
149 "read only: %s \n"
150 "compressed: %s \n",
151 properties.fRemote == true ? "true":"false",
152 properties.fReadOnly == true ? "true":"false",
153 properties.fCompressed == true ? "true":"false");
154
155 RTPrintf("%s \n", info.c_str());
156
157 /* Get the original VM path */
158 Utf8Str strSettingsFilePath;
159 Bstr bstr_settingsFilePath;
160 m_pMachine->COMGETTER(SettingsFilePath)(bstr_settingsFilePath.asOutParam());
161 strSettingsFilePath = bstr_settingsFilePath;
162 strSettingsFilePath.stripFilename();
163
164 vmFolders.insert(std::make_pair(VBox_SettingFolder, strSettingsFilePath));
165
166 /* Collect all files from the VM's folder */
167 fileList_t fullFileList;
168 rc = getFilesList(strSettingsFilePath, fullFileList);
169 if (FAILED(rc)) throw rc;
170
171 /*
172 * Collect all known folders used by the VM:
173 * - log folder;
174 * - state folder;
175 * - snapshot folder.
176 */
177 Utf8Str strLogFolder;
178 Bstr bstr_logFolder;
179 m_pMachine->COMGETTER(LogFolder)(bstr_logFolder.asOutParam());
180 strLogFolder = bstr_logFolder;
181 if ( m_type.equals("full")
182 && strLogFolder.contains(strSettingsFilePath))
183 {
184 vmFolders.insert(std::make_pair(VBox_LogFolder, strLogFolder));
185 }
186
187 Utf8Str strStateFilePath;
188 Bstr bstr_stateFilePath;
189 MachineState_T machineState;
190 rc = m_pMachine->COMGETTER(State)(&machineState);
191 if (FAILED(rc)) throw rc;
192 else if (machineState == MachineState_Saved)
193 {
194 m_pMachine->COMGETTER(StateFilePath)(bstr_stateFilePath.asOutParam());
195 strStateFilePath = bstr_stateFilePath;
196 strStateFilePath.stripFilename();
197 if ( m_type.equals("full")
198 && strStateFilePath.contains(strSettingsFilePath))
199 vmFolders.insert(std::make_pair(VBox_StateFolder, strStateFilePath));//Utf8Str(bstr_stateFilePath)));
200 }
201
202 Utf8Str strSnapshotFolder;
203 Bstr bstr_snapshotFolder;
204 m_pMachine->COMGETTER(SnapshotFolder)(bstr_snapshotFolder.asOutParam());
205 strSnapshotFolder = bstr_snapshotFolder;
206 if ( m_type.equals("full")
207 && strSnapshotFolder.contains(strSettingsFilePath))
208 vmFolders.insert(std::make_pair(VBox_SnapshotFolder, strSnapshotFolder));
209
210 if (m_pMachine->i_isSnapshotMachine())
211 {
212 Bstr bstrSrcMachineId;
213 rc = m_pMachine->COMGETTER(Id)(bstrSrcMachineId.asOutParam());
214 if (FAILED(rc)) throw rc;
215 ComPtr<IMachine> newSrcMachine;
216 rc = m_pMachine->i_getVirtualBox()->FindMachine(bstrSrcMachineId.raw(), newSrcMachine.asOutParam());
217 if (FAILED(rc)) throw rc;
218 }
219
220 /* Add the current machine and all snapshot machines below this machine
221 * in a list for further processing.
222 */
223
224 long long neededFreeSpace = 0;
225
226 /* Actual file list */
227 fileList_t actualFileList;
228 Utf8Str strTargetImageName;
229 std::vector< ComObjPtr<Machine> > machineList;
230
231// if (m_pMachine->i_isSnapshotMachine())
232// Guid snapshotId = m_pMachine->i_getSnapshotId();
233
234 /* Include current state? */
235 machineList.push_back(m_pMachine);
236
237 {
238 ULONG cSnapshots = 0;
239 rc = m_pMachine->COMGETTER(SnapshotCount)(&cSnapshots);
240 if (FAILED(rc)) throw rc;
241 if (cSnapshots > 0)
242 {
243 Utf8Str id;
244 if (m_pMachine->i_isSnapshotMachine())
245 id = m_pMachine->i_getSnapshotId().toString();
246 ComPtr<ISnapshot> pSnapshot;
247 rc = m_pMachine->FindSnapshot(Bstr(id).raw(), pSnapshot.asOutParam());
248 if (FAILED(rc)) throw rc;
249 rc = createMachineList(pSnapshot, machineList);
250 if (FAILED(rc)) throw rc;
251 }
252 }
253
254 ULONG uCount = 2; /* One init task and the machine creation. */
255 ULONG uTotalWeight = 2; /* The init task and the machine creation is worth one. */
256
257 queryMediasForAllStates(machineList, uCount, uTotalWeight);
258
259 {
260 uint64_t totalMediumsSize = 0;
261
262 for (size_t i = 0; i < llMedias.size(); ++i)
263 {
264 LONG64 cbSize = 0;
265 MEDIUMTASKCHAIN &mtc = llMedias.at(i);
266 for (size_t a = mtc.chain.size(); a > 0; --a)
267 {
268 Bstr bstrLocation;
269 Utf8Str strLocation;
270 Utf8Str name = mtc.chain[a - 1].strBaseName;
271 ComPtr<IMedium> plMedium = mtc.chain[a - 1].pMedium;
272 rc = plMedium->COMGETTER(Location)(bstrLocation.asOutParam());
273 if (FAILED(rc)) throw rc;
274 strLocation = bstrLocation;
275
276 /*if an image is located in the actual VM folder it will be added to the actual list */
277 if (strLocation.contains(strSettingsFilePath))
278 {
279 rc = plMedium->COMGETTER(Size)(&cbSize);
280 if (FAILED(rc)) throw rc;
281
282 totalMediumsSize += cbSize;
283
284 std::pair<std::map<Utf8Str, MEDIUMTASK>::iterator,bool> ret;
285 ret = finalMediumsMap.insert(std::make_pair(name, mtc.chain[a - 1]));
286 if (ret.second == true)
287 RTPrintf("Image %s was added into the moved list\n", name.c_str());
288 }
289 }
290 }
291 neededFreeSpace += totalMediumsSize;
292 }
293
294 /* Prepare data for moving ".sav" files */
295 {
296 uint64_t totalStateSize = 0;
297
298 for (size_t i = 0; i < llSaveStateFiles.size(); ++i)
299 {
300 uint64_t cbFile = 0;
301 SAVESTATETASK &sst = llSaveStateFiles.at(i);
302
303 Utf8Str name = sst.strSaveStateFile;
304 /*if a state file is located in the actual VM folder it will be added to the actual list */
305 if (name.contains(strSettingsFilePath))
306 {
307 vrc = RTFileQuerySize(name.c_str(), &cbFile);
308 if (RT_SUCCESS(vrc))
309 {
310 totalStateSize += cbFile;
311 }
312
313 std::pair<std::map<Utf8Str, SAVESTATETASK>::iterator,bool> ret;
314 ret = finalSaveStateFilesMap.insert(std::make_pair(name, sst));
315 if (ret.second == true)
316 {
317 uCount += 1;
318 uTotalWeight += 1;//just for now (should be correctly evaluated according its size)
319 RTPrintf("State file %s was added into the moved list\n", name.c_str());
320 }
321 }
322 }
323 neededFreeSpace += totalStateSize;
324 }
325
326 /* Prepare data for moving the log files */
327 {
328 Utf8Str strFolder = vmFolders[VBox_LogFolder];
329 if (strFolder.isNotEmpty())
330 {
331 uint64_t totalLogSize = 0;
332 rc = getFolderSize(strFolder, totalLogSize);
333 if (SUCCEEDED(rc))
334 {
335 neededFreeSpace += totalLogSize;
336 if (totalFreeSpace - neededFreeSpace <= 1024*1024)
337 {
338 throw VERR_OUT_OF_RESOURCES;//less than 1Mb free space on the target location
339 }
340
341 fileList_t filesList;
342 getFilesList(strFolder, filesList);
343 cit_t it = filesList.m_list.begin();
344 while(it != filesList.m_list.end())
345 {
346 Utf8Str strFile = it->first.c_str();
347 strFile.append(RTPATH_DELIMITER).append(it->second.c_str());
348 RTPrintf("%s\n", strFile.c_str());
349 actualFileList.add(strFile);
350
351 uCount += 1;
352 uTotalWeight += 1;//just for now (should be correctly evaluated according its size)
353
354 RTPrintf("The log file %s added into the moved list\n", strFile.c_str());
355 ++it;
356 }
357 }
358 }
359 }
360
361 /* Check a target location on enough room */
362 if (totalFreeSpace - neededFreeSpace <= 1024*1024)
363 {
364 throw VERR_OUT_OF_RESOURCES;//less than 1Mb free space on the target location
365 }
366
367 /* Init both Progress instances */
368 {
369 rc = m_pProgress->init(m_pMachine->i_getVirtualBox(),
370 static_cast<IMachine*>(m_pMachine) /* aInitiator */,
371 Bstr(m_pMachine->tr("Moving Machine")).raw(),
372 true /* fCancellable */,
373 uCount,
374 uTotalWeight,
375 Bstr(m_pMachine->tr("Initialize Moving")).raw(),
376 1);
377 if (FAILED(rc))
378 {
379 throw m_pMachine->setError(VBOX_E_IPRT_ERROR,
380 m_pMachine->tr("Couldn't correctly setup the progress object "
381 "for moving VM operation (%Rrc)"),
382 rc);
383 }
384
385 m_pRollBackProgress.createObject();
386 rc = m_pRollBackProgress->init(m_pMachine->i_getVirtualBox(),
387 static_cast<IMachine*>(m_pMachine) /* aInitiator */,
388 Bstr(m_pMachine->tr("Moving back Machine")).raw(),
389 true /* fCancellable */,
390 uCount,
391 uTotalWeight,
392 Bstr(m_pMachine->tr("Initialize Moving back")).raw(),
393 1);
394 if (FAILED(rc))
395 {
396 throw m_pMachine->setError(VBOX_E_IPRT_ERROR,
397 m_pMachine->tr("Couldn't correctly setup the progress object "
398 "for possible rollback operation during moving VM (%Rrc)"),
399 rc);
400 }
401 }
402
403 /* save all VM data */
404 m_pMachine->i_setModified(Machine::IsModified_MachineData);
405 rc = m_pMachine->SaveSettings();
406 }
407 catch(HRESULT hrc)
408 {
409 rc = hrc;
410 }
411
412 LogFlowFuncLeave();
413
414 return rc;
415}
416
417void MachineMoveVM::updateStateFile(settings::MachineConfigFile *snl, const Guid &id, const Utf8Str &strFile)
418{
419 settings::SnapshotsList::iterator it;
420 for (it = (*snl).llFirstSnapshot.begin(); it != (*snl).llFirstSnapshot.end(); ++it)
421 {
422 settings::Snapshot snap = (settings::Snapshot)(*it);
423 RTPrintf("it->uuid = %s , id = %s\n", snap.uuid.toStringCurly().c_str(), id.toStringCurly().c_str());
424 RTPrintf("it->strStateFile = %s , strFile = %s\n", it->strStateFile.c_str(), strFile.c_str());
425 if (it->uuid == id)
426 {
427 it->strStateFile = strFile;
428 RTPrintf("Modified it->strStateFile = %s\n", it->strStateFile.c_str());
429 }
430 else if (!it->llChildSnapshots.empty())
431 updateStateFile(it->llChildSnapshots, id, strFile);
432 }
433}
434
435void MachineMoveVM::updateStateFile(settings::SnapshotsList &snl, const Guid &id, const Utf8Str &strFile)
436{
437 settings::SnapshotsList::iterator it;
438 for (it = snl.begin(); it != snl.end(); ++it)
439 {
440 if (it->uuid == id)
441 {
442 settings::Snapshot snap = (settings::Snapshot)(*it);
443 RTPrintf("it->uuid = %s , id = %s\n", snap.uuid.toStringCurly().c_str(), id.toStringCurly().c_str());
444 RTPrintf("it->strStateFile = %s , strFile = %s\n", snap.strStateFile.c_str(), strFile.c_str());
445 it->strStateFile = strFile;
446
447 RTPrintf("Modified it->strStateFile = %s\n", it->strStateFile.c_str());
448 m_pMachine->mSSData->strStateFilePath = strFile;
449 RTPrintf("Modified m_pMachine->mSSData->strStateFilePath = %s\n",
450 m_pMachine->mSSData->strStateFilePath.c_str());
451 }
452 else if (!it->llChildSnapshots.empty())
453 updateStateFile(it->llChildSnapshots, id, strFile);
454 }
455}
456
457void MachineMoveVM::printStateFile(settings::SnapshotsList &snl)
458{
459 settings::SnapshotsList::iterator it;
460 for (it = snl.begin(); it != snl.end(); ++it)
461 {
462 if (!it->strStateFile.isEmpty())
463 {
464 settings::Snapshot snap = (settings::Snapshot)(*it);
465 RTPrintf("snap.uuid = %s\n", snap.uuid.toStringCurly().c_str());
466 RTPrintf("snap.strStateFile = %s\n", snap.strStateFile.c_str());
467 }
468
469 if (!it->llChildSnapshots.empty())
470 printStateFile(it->llChildSnapshots);
471 }
472}
473
474/* static */
475DECLCALLBACK(int) MachineMoveVM::updateProgress(unsigned uPercent, void *pvUser)
476{
477 MachineMoveVM* pTask = *(MachineMoveVM**)pvUser;
478
479 if ( pTask
480 && !pTask->m_pProgress.isNull())
481 {
482 BOOL fCanceled;
483 pTask->m_pProgress->COMGETTER(Canceled)(&fCanceled);
484 if (fCanceled)
485 return -1;
486 pTask->m_pProgress->SetCurrentOperationProgress(uPercent);
487 }
488 return VINF_SUCCESS;
489}
490
491/* static */
492DECLCALLBACK(int) MachineMoveVM::copyFileProgress(unsigned uPercentage, void *pvUser)
493{
494 ComObjPtr<Progress> pProgress = *static_cast< ComObjPtr<Progress>* >(pvUser);
495
496 BOOL fCanceled = false;
497 HRESULT rc = pProgress->COMGETTER(Canceled)(&fCanceled);
498 if (FAILED(rc)) return VERR_GENERAL_FAILURE;
499 /* If canceled by the user tell it to the copy operation. */
500 if (fCanceled) return VERR_CANCELLED;
501 /* Set the new process. */
502 rc = pProgress->SetCurrentOperationProgress(uPercentage);
503 if (FAILED(rc)) return VERR_GENERAL_FAILURE;
504
505 return VINF_SUCCESS;
506}
507
508
509/* static */
510void MachineMoveVM::i_MoveVMThreadTask(MachineMoveVM* task)
511{
512 LogFlowFuncEnter();
513 HRESULT rc = S_OK;
514
515 MachineMoveVM* taskMoveVM = task;
516 ComObjPtr<Machine> &machine = taskMoveVM->m_pMachine;
517
518 AutoCaller autoCaller(machine);
519// if (FAILED(autoCaller.rc())) return;//Should we return something here?
520
521 Utf8Str strTargetFolder = taskMoveVM->m_targetPath;
522 {
523 Bstr bstrMachineName;
524 taskMoveVM->m_pMachine->COMGETTER(Name)(bstrMachineName.asOutParam());
525 strTargetFolder.append(Utf8Str(bstrMachineName));
526 }
527
528 RTCList<Utf8Str> newFiles; /* All extra created files (save states, ...) */
529 RTCList<Utf8Str> originalFiles; /* All original files except images */
530 typedef std::map<Utf8Str, ComObjPtr<Medium> > MediumMap;
531 MediumMap mapOriginalMedium;
532
533 /*
534 * We have the couple modes which user is able to request
535 * basic mode:
536 * - The images which are solely attached to the VM
537 * and located in the original VM folder will be moved.
538 *
539 * full mode:
540 * - All disks which are directly attached to the VM
541 * will be moved.
542 *
543 * Apart from that all other files located in the original VM
544 * folder will be moved.
545 */
546 /* Collect the shareable disks.
547 * Get the machines whom the shareable disks attach to.
548 * Return an error if the state of any VM doesn't allow to move a shareable disk.
549 * Check new destination whether enough room for the VM or not. if "not" return an error.
550 * Make a copy of VM settings and a list with all files which are moved. Save the list on the disk.
551 * Start "move" operation.
552 * Check the result of operation.
553 * if the operation was successful:
554 * - delete all files in the original VM folder;
555 * - update VM disks info with new location;
556 * - update all other VM if it's needed;
557 * - update global settings
558 */
559
560 try
561 {
562 /* Move all disks */
563 rc = taskMoveVM->moveAllDisks(taskMoveVM->finalMediumsMap, &strTargetFolder);
564 if (FAILED(rc))
565 throw rc;
566
567 {
568 RTPrintf("0 Print all state files\n");
569 taskMoveVM->printStateFile(taskMoveVM->m_pMachine->mData->pMachineConfigFile->llFirstSnapshot);
570 }
571
572 /* Copy all save state files. */
573 Utf8Str strTrgSnapshotFolder;
574 {
575 Machine::Data *machineData = taskMoveVM->m_pMachine->mData.data();
576 settings::MachineConfigFile *machineConfFile = machineData->pMachineConfigFile;
577
578 /* When the current snapshot folder is absolute we reset it to the
579 * default relative folder. */
580 if (RTPathStartsWithRoot((*machineConfFile).machineUserData.strSnapshotFolder.c_str()))
581 (*machineConfFile).machineUserData.strSnapshotFolder = "Snapshots";
582 (*machineConfFile).strStateFile = "";
583
584 /* The absolute name of the snapshot folder. */
585 strTrgSnapshotFolder = Utf8StrFmt("%s%c%s", strTargetFolder.c_str(), RTPATH_DELIMITER,
586 (*machineConfFile).machineUserData.strSnapshotFolder.c_str());
587
588 /* Check if a snapshot folder is necessary and if so doesn't already
589 * exists. */
590 if ( taskMoveVM->finalSaveStateFilesMap.size() != 0
591 && !RTDirExists(strTrgSnapshotFolder.c_str()))
592 {
593 int vrc = RTDirCreateFullPath(strTrgSnapshotFolder.c_str(), 0700);
594 if (RT_FAILURE(vrc))
595 throw machine->setError(VBOX_E_IPRT_ERROR,
596 machine->tr("Could not create snapshots folder '%s' (%Rrc)"),
597 strTrgSnapshotFolder.c_str(), vrc);
598 }
599
600 std::map<Utf8Str, SAVESTATETASK>::iterator itState = taskMoveVM->finalSaveStateFilesMap.begin();
601 while (itState != taskMoveVM->finalSaveStateFilesMap.end())
602 {
603 const SAVESTATETASK &sst = itState->second;
604 const Utf8Str &strTrgSaveState = Utf8StrFmt("%s%c%s", strTrgSnapshotFolder.c_str(), RTPATH_DELIMITER,
605 RTPathFilename(sst.strSaveStateFile.c_str()));
606
607 /* Move to next sub-operation. */
608 rc = taskMoveVM->m_pProgress->SetNextOperation(BstrFmt(machine->tr("Move save state file '%s' ..."),
609 RTPathFilename(sst.strSaveStateFile.c_str())).raw(), sst.uWeight);
610 if (FAILED(rc)) throw rc;
611
612 int vrc = RTFileCopyEx(sst.strSaveStateFile.c_str(), strTrgSaveState.c_str(), 0,
613 MachineMoveVM::copyFileProgress, &taskMoveVM->m_pProgress);
614 if (RT_FAILURE(vrc))
615 throw machine->setError(VBOX_E_IPRT_ERROR,
616 machine->tr("Could not move state file '%s' to '%s' (%Rrc)"),
617 sst.strSaveStateFile.c_str(), strTrgSaveState.c_str(), vrc);
618
619 /* save new file in case of restoring */
620 newFiles.append(strTrgSaveState);
621 /* save original file for deletion in the end */
622 originalFiles.append(sst.strSaveStateFile);
623 ++itState;
624 }
625 }
626
627 /* Update XML settings. */
628 rc = taskMoveVM->updateStateFilesXMLSettings(taskMoveVM->finalSaveStateFilesMap, strTrgSnapshotFolder);
629 if (FAILED(rc))
630 throw rc;
631
632 {
633 RTPrintf("\n1 Print all state files\n");
634 taskMoveVM->printStateFile(taskMoveVM->m_pMachine->mData->pMachineConfigFile->llFirstSnapshot);
635 }
636
637 /* Moving Machine settings file */
638 {
639 RTPrintf("\nMoving Machine settings file \n");
640 Machine::Data *machineData = taskMoveVM->m_pMachine->mData.data();
641 settings::MachineConfigFile *machineConfFile = machineData->pMachineConfigFile;
642
643 rc = taskMoveVM->m_pProgress->SetNextOperation(BstrFmt(machine->tr("Moving Machine settings '%s' ..."),
644 (*machineConfFile).machineUserData.strName.c_str()).raw(), 1);
645 if (FAILED(rc)) throw rc;
646
647 Utf8Str strTargetSettingsFilePath = strTargetFolder;
648 Bstr bstrMachineName;
649 taskMoveVM->m_pMachine->COMGETTER(Name)(bstrMachineName.asOutParam());
650 strTargetSettingsFilePath.append(RTPATH_DELIMITER).append(Utf8Str(bstrMachineName)).append(".vbox");
651
652 Utf8Str strSettingsFilePath;
653 Bstr bstr_settingsFilePath;
654 taskMoveVM->m_pMachine->COMGETTER(SettingsFilePath)(bstr_settingsFilePath.asOutParam());
655 strSettingsFilePath = bstr_settingsFilePath;
656
657 int vrc = RTFileCopyEx(strSettingsFilePath.c_str(), strTargetSettingsFilePath.c_str(), 0,
658 MachineMoveVM::copyFileProgress, &taskMoveVM->m_pProgress);
659 if (RT_FAILURE(vrc))
660 throw machine->setError(VBOX_E_IPRT_ERROR,
661 machine->tr("Could not move setting file '%s' to '%s' (%Rrc)"),
662 strSettingsFilePath.c_str(), strTargetSettingsFilePath.c_str(), vrc);
663
664 /* save new file in case of restoring */
665 newFiles.append(strTargetSettingsFilePath);
666 /* save original file for deletion in the end */
667 originalFiles.append(strSettingsFilePath);
668 }
669
670 {
671 RTPrintf("\n2 Print all state files\n");
672 Machine::Data *machineData = taskMoveVM->m_pMachine->mData.data();
673 RTPrintf("\nmachineData->m_strConfigFileFull = %s\n", machineData->m_strConfigFileFull.c_str());
674 RTPrintf("\nmachineData->m_strConfigFile = %s\n", machineData->m_strConfigFile.c_str());
675 taskMoveVM->printStateFile(taskMoveVM->m_pMachine->mData->pMachineConfigFile->llFirstSnapshot);
676 }
677
678 /* Moving Machine log files */
679 {
680 RTPrintf("\nMoving Machine log files \n");
681
682 Utf8Str strTargetLogFolderPath = strTargetFolder;
683
684 if (taskMoveVM->vmFolders[VBox_LogFolder].isNotEmpty())
685 {
686 Bstr bstrMachineName;
687 taskMoveVM->m_pMachine->COMGETTER(Name)(bstrMachineName.asOutParam());
688 strTargetLogFolderPath.append(RTPATH_DELIMITER).append("Logs");
689
690 /* Check a log folder existing and create one if it's not */
691 if (!RTDirExists(strTargetLogFolderPath.c_str()))
692 {
693 int vrc = RTDirCreateFullPath(strTargetLogFolderPath.c_str(), 0700);
694 if (RT_FAILURE(vrc))
695 throw machine->setError(VBOX_E_IPRT_ERROR,
696 machine->tr("Could not create log folder '%s' (%Rrc)"),
697 strTargetLogFolderPath.c_str(), vrc);
698 }
699
700 fileList_t filesList;
701 taskMoveVM->getFilesList(taskMoveVM->vmFolders[VBox_LogFolder], filesList);
702 cit_t it = filesList.m_list.begin();
703 while(it != filesList.m_list.end())
704 {
705 Utf8Str strFullSourceFilePath = it->first.c_str();
706 strFullSourceFilePath.append(RTPATH_DELIMITER).append(it->second.c_str());
707
708 Utf8Str strFullTargetFilePath = strTargetLogFolderPath;
709 strFullTargetFilePath.append(RTPATH_DELIMITER).append(it->second.c_str());
710
711 /* Move to next sub-operation. */
712 rc = taskMoveVM->m_pProgress->SetNextOperation(BstrFmt(machine->tr("Moving Machine log file '%s' ..."),
713 RTPathFilename(strFullSourceFilePath.c_str())).raw(), 1);
714 if (FAILED(rc)) throw rc;
715
716 int vrc = RTFileCopyEx(strFullSourceFilePath.c_str(), strFullTargetFilePath.c_str(), 0,
717 MachineMoveVM::copyFileProgress, &taskMoveVM->m_pProgress);
718 if (RT_FAILURE(vrc))
719 throw machine->setError(VBOX_E_IPRT_ERROR,
720 machine->tr("Could not move log file '%s' to '%s' (%Rrc)"),
721 strFullSourceFilePath.c_str(), strFullTargetFilePath.c_str(), vrc);
722
723 RTPrintf("The log file %s moved into the folder %s\n", strFullSourceFilePath.c_str(),
724 strFullTargetFilePath.c_str());
725
726 /* save new file in case of restoring */
727 newFiles.append(strFullTargetFilePath);
728 /* save original file for deletion in the end */
729 originalFiles.append(strFullSourceFilePath);
730
731 ++it;
732 }
733 }
734 }
735
736 /* save all VM data */
737 {
738 RTPrintf("\nCall Machine::SaveSettings()\n");
739 rc = taskMoveVM->m_pMachine->SaveSettings();
740 }
741
742 {
743 RTPrintf("\n3 Print all state files\n");
744 Machine::Data *machineData = taskMoveVM->m_pMachine->mData.data();
745
746 Utf8Str strTargetSettingsFilePath = strTargetFolder;
747 Bstr bstrMachineName;
748 taskMoveVM->m_pMachine->COMGETTER(Name)(bstrMachineName.asOutParam());
749 strTargetSettingsFilePath.append(RTPATH_DELIMITER).append(Utf8Str(bstrMachineName)).append(".vbox");
750 machineData->m_strConfigFileFull = strTargetSettingsFilePath;
751 taskMoveVM->m_pMachine->mParent->i_copyPathRelativeToConfig(strTargetSettingsFilePath, machineData->m_strConfigFile);
752// machineData->m_strConfigFile = strTargetSettingsFilePath;
753 RTPrintf("\nmachineData->m_strConfigFileFull = %s\n", machineData->m_strConfigFileFull.c_str());
754 RTPrintf("\nmachineData->m_strConfigFile = %s\n", machineData->m_strConfigFile.c_str());
755 taskMoveVM->printStateFile(taskMoveVM->m_pMachine->mData->pMachineConfigFile->llFirstSnapshot);
756 }
757
758 /* Marks the global registry for uuid as modified */
759 {
760 Guid uuid = taskMoveVM->m_pMachine->mData->mUuid;
761 taskMoveVM->m_pMachine->mParent->i_markRegistryModified(uuid);
762
763 // save the global settings; for that we should hold only the VirtualBox lock
764 AutoWriteLock vboxLock(taskMoveVM->m_pMachine->mParent COMMA_LOCKVAL_SRC_POS);
765 RTPrintf("\nCall global VirtualBox i_saveSettings()\n");
766 rc = taskMoveVM->m_pMachine->mParent->i_saveSettings();
767 }
768
769 {
770 RTPrintf("\n4 Print all state files\n");
771 taskMoveVM->printStateFile(taskMoveVM->m_pMachine->mData->pMachineConfigFile->llFirstSnapshot);
772 }
773
774 }
775 catch(HRESULT hrc)
776 {
777 RTPrintf("\nHRESULT exception\n");
778 rc = hrc;
779 taskMoveVM->result = rc;
780 }
781 catch (...)
782 {
783 RTPrintf("\nUnknown exception\n");
784 rc = VirtualBoxBase::handleUnexpectedExceptions(taskMoveVM->m_pMachine, RT_SRC_POS);
785 taskMoveVM->result = rc;
786 }
787
788 /* Cleanup on failure */
789 if (FAILED(rc))
790 {
791 /* ! Apparently we should update the Progress object !*/
792
793 /* Restore the original XML settings. */
794 rc = taskMoveVM->updateStateFilesXMLSettings(taskMoveVM->finalSaveStateFilesMap,
795 taskMoveVM->vmFolders[VBox_StateFolder]);
796 if (FAILED(rc))
797 throw rc;
798
799 {
800 RTPrintf("\nFailed: Print all state files\n");
801 Machine::Data *machineData = taskMoveVM->m_pMachine->mData.data();
802 RTPrintf("\nmachineData->m_strConfigFileFull = %s\n", machineData->m_strConfigFileFull.c_str());
803 RTPrintf("\nmachineData->m_strConfigFile = %s\n", machineData->m_strConfigFile.c_str());
804 taskMoveVM->printStateFile(taskMoveVM->m_pMachine->mData->pMachineConfigFile->llFirstSnapshot);
805 }
806
807 /* Delete all created files. */
808 rc = taskMoveVM->deleteFiles(newFiles);
809 if (FAILED(rc))
810 RTPrintf("Can't delete all new files.");
811
812 RTDirRemove(strTargetFolder.c_str());
813
814 /* Restoring the original mediums */
815 try
816 {
817 rc = taskMoveVM->moveAllDisks(taskMoveVM->finalMediumsMap);
818 if (FAILED(rc))
819 throw rc;
820 }
821 catch(HRESULT hrc)
822 {
823 RTPrintf("\nFailed: HRESULT exception\n");
824 taskMoveVM->result = hrc;
825 }
826 catch (...)
827 {
828 RTPrintf("\nFailed: Unknown exception\n");
829 rc = VirtualBoxBase::handleUnexpectedExceptions(taskMoveVM->m_pMachine, RT_SRC_POS);
830 taskMoveVM->result = rc;
831 }
832
833 /* save all VM data */
834 {
835 AutoWriteLock srcLock(machine COMMA_LOCKVAL_SRC_POS);
836 srcLock.release();
837 RTPrintf("\nFailed: Call SaveSettings()\n");
838 rc = taskMoveVM->m_pMachine->SaveSettings();
839 srcLock.acquire();
840 }
841
842 /* Restore an original path to XML setting file */
843 {
844 RTPrintf("\nFailed: Print all state files\n");
845 Machine::Data *machineData = taskMoveVM->m_pMachine->mData.data();
846
847 Utf8Str strOriginalSettingsFilePath = taskMoveVM->vmFolders[VBox_SettingFolder];
848 Bstr bstrMachineName;
849 taskMoveVM->m_pMachine->COMGETTER(Name)(bstrMachineName.asOutParam());
850 strOriginalSettingsFilePath.append(RTPATH_DELIMITER).append(Utf8Str(bstrMachineName)).append(".vbox");
851
852 machineData->m_strConfigFileFull = strOriginalSettingsFilePath;
853
854 taskMoveVM->m_pMachine->mParent->i_copyPathRelativeToConfig(strOriginalSettingsFilePath,
855 machineData->m_strConfigFile);
856
857 RTPrintf("\nmachineData->m_strConfigFileFull = %s\n", machineData->m_strConfigFileFull.c_str());
858 RTPrintf("\nmachineData->m_strConfigFile = %s\n", machineData->m_strConfigFile.c_str());
859
860 taskMoveVM->printStateFile(taskMoveVM->m_pMachine->mData->pMachineConfigFile->llFirstSnapshot);
861 }
862
863 /* Marks the global registry for uuid as modified */
864 {
865 AutoWriteLock srcLock(machine COMMA_LOCKVAL_SRC_POS);
866 srcLock.release();
867 Guid uuid = taskMoveVM->m_pMachine->mData->mUuid;
868 taskMoveVM->m_pMachine->mParent->i_markRegistryModified(uuid);
869 srcLock.acquire();
870
871 // save the global settings; for that we should hold only the VirtualBox lock
872 AutoWriteLock vboxLock(taskMoveVM->m_pMachine->mParent COMMA_LOCKVAL_SRC_POS);
873 RTPrintf("\nFailed: Call global VirtualBox i_saveSettings()\n");
874 rc = taskMoveVM->m_pMachine->mParent->i_saveSettings();
875 }
876 }
877 else /*Operation was successful and now we can delete the original files like the state files, XML setting, log files */
878 {
879 rc = taskMoveVM->deleteFiles(originalFiles);
880 if (FAILED(rc))
881 RTPrintf("Can't delete all original files.");
882 }
883
884 if (!taskMoveVM->m_pProgress.isNull())
885 taskMoveVM->m_pProgress->i_notifyComplete(taskMoveVM->result);
886
887 LogFlowFuncLeave();
888}
889
890HRESULT MachineMoveVM::moveAllDisks(const std::map<Utf8Str, MEDIUMTASK>& listOfDisks,
891 const Utf8Str* strTargetFolder)
892{
893 HRESULT rc = S_OK;
894 ComObjPtr<Machine> &machine = m_pMachine;
895
896 AutoWriteLock machineLock(machine COMMA_LOCKVAL_SRC_POS);
897
898 try{
899 std::map<Utf8Str, MEDIUMTASK>::const_iterator itMedium = listOfDisks.begin();
900 while(itMedium != listOfDisks.end())
901 {
902 const MEDIUMTASK &mt = itMedium->second;
903 ComPtr<IMedium> pMedium = mt.pMedium;
904 Utf8Str strTargetImageName;
905 Utf8Str strLocation;
906 Bstr bstrLocation;
907 Bstr bstrSrcName;
908
909 rc = pMedium->COMGETTER(Name)(bstrSrcName.asOutParam());
910 if (FAILED(rc)) throw rc;
911
912 if (strTargetFolder != NULL && !strTargetFolder->isEmpty())
913 {
914 strTargetImageName = *strTargetFolder;
915 rc = pMedium->COMGETTER(Location)(bstrLocation.asOutParam());
916 if (FAILED(rc)) throw rc;
917 strLocation = bstrLocation;
918
919 if (mt.fSnapshot == true)
920 {
921 strLocation.stripFilename().stripPath().append(RTPATH_DELIMITER).append(Utf8Str(bstrSrcName));
922 }
923 else
924 {
925 strLocation.stripPath();
926 }
927
928 strTargetImageName.append(RTPATH_DELIMITER).append(strLocation);
929 rc = m_pProgress->SetNextOperation(BstrFmt(machine->tr("Moving Disk '%ls' ..."),
930 bstrSrcName.raw()).raw(),
931 mt.uWeight);
932 if (FAILED(rc)) throw rc;
933 }
934 else
935 {
936 strTargetImageName = mt.strBaseName;//Should contain full path to the image
937 rc = m_pRollBackProgress->SetNextOperation(BstrFmt(machine->tr("Moving back Disk '%ls' ..."),
938 bstrSrcName.raw()).raw(),
939 mt.uWeight);
940 if (FAILED(rc)) throw rc;
941 }
942
943
944
945 /* consistency: use \ if appropriate on the platform */
946 RTPathChangeToDosSlashes(strTargetImageName.mutableRaw(), false);
947 RTPrintf("\nTarget disk %s \n", strTargetImageName.c_str());
948
949 ComPtr<IProgress> moveDiskProgress;
950 bstrLocation = strTargetImageName.c_str();
951 rc = pMedium->SetLocation(bstrLocation.raw(), moveDiskProgress.asOutParam());
952
953 /* Wait until the async process has finished. */
954 machineLock.release();
955 if (strTargetFolder != NULL && !strTargetFolder->isEmpty())
956 {
957 rc = m_pProgress->WaitForAsyncProgressCompletion(moveDiskProgress);
958 }
959 else
960 {
961 rc = m_pRollBackProgress->WaitForAsyncProgressCompletion(moveDiskProgress);
962 }
963
964 machineLock.acquire();
965 if (FAILED(rc)) throw rc;
966
967 RTPrintf("\nMoving %s has finished\n", strTargetImageName.c_str());
968
969 /* Check the result of the async process. */
970 LONG iRc;
971 rc = moveDiskProgress->COMGETTER(ResultCode)(&iRc);
972 if (FAILED(rc)) throw rc;
973 /* If the thread of the progress object has an error, then
974 * retrieve the error info from there, or it'll be lost. */
975 if (FAILED(iRc))
976 throw machine->setError(ProgressErrorInfo(moveDiskProgress));
977
978 ++itMedium;
979 }
980
981 machineLock.release();
982 }
983 catch(HRESULT hrc)
984 {
985 RTPrintf("\nHRESULT exception\n");
986 rc = hrc;
987 machineLock.release();
988 }
989 catch (...)
990 {
991 RTPrintf("\nUnknown exception\n");
992 rc = VirtualBoxBase::handleUnexpectedExceptions(m_pMachine, RT_SRC_POS);
993 machineLock.release();
994 }
995
996 return rc;
997}
998
999HRESULT MachineMoveVM::updateStateFilesXMLSettings(const std::map<Utf8Str, SAVESTATETASK>& listOfFiles,
1000 const Utf8Str& targetPath)
1001{
1002 HRESULT rc = S_OK;
1003 Machine::Data *machineData = m_pMachine->mData.data();
1004 settings::MachineConfigFile *machineConfFile = machineData->pMachineConfigFile;
1005
1006 std::map<Utf8Str, SAVESTATETASK>::const_iterator itState = listOfFiles.begin();
1007 while (itState != listOfFiles.end())
1008 {
1009 const SAVESTATETASK &sst = itState->second;
1010 const Utf8Str &strTargetSaveStateFilePath = Utf8StrFmt("%s%c%s", targetPath.c_str(),
1011 RTPATH_DELIMITER,
1012 RTPathFilename(sst.strSaveStateFile.c_str()));
1013
1014 /* Update the path in the configuration either for the current
1015 * machine state or the snapshots. */
1016 if (!sst.snapshotUuid.isValid() || sst.snapshotUuid.isZero())
1017 {
1018 (*machineConfFile).strStateFile = strTargetSaveStateFilePath;
1019 }
1020 else
1021 {
1022 updateStateFile(m_pMachine->mData->pMachineConfigFile->llFirstSnapshot,
1023 sst.snapshotUuid, strTargetSaveStateFilePath);
1024 }
1025
1026 ++itState;
1027 }
1028
1029 return rc;
1030}
1031
1032HRESULT MachineMoveVM::getFilesList(const Utf8Str& strRootFolder, fileList_t &filesList)
1033{
1034 RTDIR hDir;
1035 HRESULT rc = S_OK;
1036 int vrc = RTDirOpen(&hDir, strRootFolder.c_str());
1037 if (RT_SUCCESS(vrc))
1038 {
1039 RTDIRENTRY DirEntry;
1040 while (RT_SUCCESS(RTDirRead(hDir, &DirEntry, NULL)))
1041 {
1042 if (RTDirEntryIsStdDotLink(&DirEntry))
1043 continue;
1044
1045 if (DirEntry.enmType == RTDIRENTRYTYPE_FILE)
1046 {
1047 Utf8Str fullPath(strRootFolder);
1048 filesList.add(strRootFolder, DirEntry.szName);
1049 }
1050 else if (DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY)
1051 {
1052 Utf8Str strNextFolder(strRootFolder);
1053 strNextFolder.append(RTPATH_DELIMITER).append(DirEntry.szName);
1054 rc = getFilesList(strNextFolder, filesList);
1055 if (FAILED(rc))
1056 break;
1057 }
1058 }
1059
1060 vrc = RTDirClose(hDir);
1061 }
1062 else if (vrc == VERR_FILE_NOT_FOUND)
1063 {
1064 m_pMachine->setError(VBOX_E_IPRT_ERROR,
1065 m_pMachine->tr("Folder '%s' doesn't exist (%Rrc)"),
1066 strRootFolder.c_str(), vrc);
1067 rc = vrc;
1068 }
1069 else
1070 throw m_pMachine->setError(VBOX_E_IPRT_ERROR,
1071 m_pMachine->tr("Could not open folder '%s' (%Rrc)"),
1072 strRootFolder.c_str(), vrc);
1073 return rc;
1074}
1075
1076HRESULT MachineMoveVM::deleteFiles(const RTCList<Utf8Str>& listOfFiles)
1077{
1078 HRESULT rc = S_OK;
1079 /* Delete all created files. */
1080 try
1081 {
1082 for (size_t i = 0; i < listOfFiles.size(); ++i)
1083 {
1084 int vrc = RTFileDelete(listOfFiles.at(i).c_str());
1085 if (RT_FAILURE(vrc))
1086 rc = m_pMachine->setError(VBOX_E_IPRT_ERROR,
1087 m_pMachine->tr("Could not delete file '%s' (%Rrc)"),
1088 listOfFiles.at(i).c_str(), rc);
1089 else
1090 RTPrintf("\nFile %s has been deleted\n", listOfFiles.at(i).c_str());
1091 }
1092 }
1093 catch(HRESULT hrc)
1094 {
1095 rc = hrc;
1096 }
1097 catch (...)
1098 {
1099 rc = VirtualBoxBase::handleUnexpectedExceptions(m_pMachine, RT_SRC_POS);
1100 }
1101
1102 return rc;
1103}
1104
1105HRESULT MachineMoveVM::getFolderSize(const Utf8Str& strRootFolder, uint64_t& size)
1106{
1107 int vrc = 0;
1108 uint64_t totalFolderSize = 0;
1109 fileList_t filesList;
1110
1111 HRESULT rc = getFilesList(strRootFolder, filesList);
1112 if (SUCCEEDED(rc))
1113 {
1114 cit_t it = filesList.m_list.begin();
1115 while(it != filesList.m_list.end())
1116 {
1117 uint64_t cbFile = 0;
1118 Utf8Str fullPath = it->first;
1119 fullPath.append(RTPATH_DELIMITER).append(it->second);
1120 vrc = RTFileQuerySize(fullPath.c_str(), &cbFile);
1121 if (RT_SUCCESS(vrc))
1122 {
1123 totalFolderSize += cbFile;
1124 }
1125 else
1126 throw m_pMachine->setError(VBOX_E_IPRT_ERROR,
1127 m_pMachine->tr("Could not get the size of file '%s' (%Rrc)"),
1128 fullPath.c_str(), vrc);
1129 ++it;
1130 }
1131// RTPrintf("Total folder %s size %llu\n", strRootFolder.c_str(), totalFolderSize);
1132 size = totalFolderSize;
1133 }
1134 else
1135 m_pMachine->setError(VBOX_E_IPRT_ERROR,
1136 m_pMachine->tr("Could not calculate the size of folder '%s' (%Rrc)"),
1137 strRootFolder.c_str(), vrc);
1138 return rc;
1139}
1140
1141HRESULT MachineMoveVM::queryBaseName(const ComPtr<IMedium> &pMedium, Utf8Str &strBaseName) const
1142{
1143 ComPtr<IMedium> pBaseMedium;
1144 HRESULT rc = pMedium->COMGETTER(Base)(pBaseMedium.asOutParam());
1145 if (FAILED(rc)) return rc;
1146 Bstr bstrBaseName;
1147 rc = pBaseMedium->COMGETTER(Name)(bstrBaseName.asOutParam());
1148 if (FAILED(rc)) return rc;
1149 strBaseName = bstrBaseName;
1150 return rc;
1151}
1152
1153HRESULT MachineMoveVM::createMachineList(const ComPtr<ISnapshot> &pSnapshot,
1154 std::vector< ComObjPtr<Machine> > &aMachineList) const
1155{
1156 HRESULT rc = S_OK;
1157 Bstr name;
1158 rc = pSnapshot->COMGETTER(Name)(name.asOutParam());
1159 if (FAILED(rc)) return rc;
1160
1161 ComPtr<IMachine> l_pMachine;
1162 rc = pSnapshot->COMGETTER(Machine)(l_pMachine.asOutParam());
1163 if (FAILED(rc)) return rc;
1164 aMachineList.push_back((Machine*)(IMachine*)l_pMachine);
1165
1166 SafeIfaceArray<ISnapshot> sfaChilds;
1167 rc = pSnapshot->COMGETTER(Children)(ComSafeArrayAsOutParam(sfaChilds));
1168 if (FAILED(rc)) return rc;
1169 for (size_t i = 0; i < sfaChilds.size(); ++i)
1170 {
1171 rc = createMachineList(sfaChilds[i], aMachineList);
1172 if (FAILED(rc)) return rc;
1173 }
1174
1175 return rc;
1176}
1177
1178HRESULT MachineMoveVM::queryMediasForAllStates(const std::vector<ComObjPtr<Machine> > &aMachineList,
1179 ULONG &uCount, ULONG &uTotalWeight)
1180{
1181 /* In this case we create a exact copy of the original VM. This means just
1182 * adding all directly and indirectly attached disk images to the worker
1183 * list. */
1184 HRESULT rc = S_OK;
1185 for (size_t i = 0; i < aMachineList.size(); ++i)
1186 {
1187 const ComObjPtr<Machine> &machine = aMachineList.at(i);
1188
1189 /* Add all attachments (and their parents) of the different
1190 * machines to a worker list. */
1191 SafeIfaceArray<IMediumAttachment> sfaAttachments;
1192 rc = machine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
1193 if (FAILED(rc)) return rc;
1194 for (size_t a = 0; a < sfaAttachments.size(); ++a)
1195 {
1196 const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[a];
1197 DeviceType_T type;
1198 rc = pAtt->COMGETTER(Type)(&type);
1199 if (FAILED(rc)) return rc;
1200
1201 /* Only harddisks and floppies are of interest. */
1202 if ( type != DeviceType_HardDisk
1203 && type != DeviceType_Floppy)
1204 continue;
1205
1206 /* Valid medium attached? */
1207 ComPtr<IMedium> pSrcMedium;
1208 rc = pAtt->COMGETTER(Medium)(pSrcMedium.asOutParam());
1209 if (FAILED(rc)) return rc;
1210
1211 if (pSrcMedium.isNull())
1212 continue;
1213
1214 MEDIUMTASKCHAIN mtc;
1215 mtc.devType = type;
1216
1217 while (!pSrcMedium.isNull())
1218 {
1219 /* Refresh the state so that the file size get read. */
1220 MediumState_T e;
1221 rc = pSrcMedium->RefreshState(&e);
1222 if (FAILED(rc)) return rc;
1223 LONG64 lSize;
1224 rc = pSrcMedium->COMGETTER(Size)(&lSize);
1225 if (FAILED(rc)) return rc;
1226
1227 Bstr bstrLocation;
1228 rc = pSrcMedium->COMGETTER(Location)(bstrLocation.asOutParam());
1229 if (FAILED(rc)) throw rc;
1230
1231 /* Save the current medium, for later cloning. */
1232 MEDIUMTASK mt;
1233 mt.strBaseName = bstrLocation;
1234 Utf8Str strFolder = vmFolders[VBox_SnapshotFolder];
1235 if (strFolder.isNotEmpty() && mt.strBaseName.contains(strFolder))
1236 {
1237 mt.fSnapshot = true;
1238 }
1239 else
1240 mt.fSnapshot = false;
1241
1242 mt.uIdx = UINT32_MAX;
1243 mt.pMedium = pSrcMedium;
1244 mt.uWeight = (ULONG)((lSize + _1M - 1) / _1M);
1245 mtc.chain.append(mt);
1246
1247 /* Query next parent. */
1248 rc = pSrcMedium->COMGETTER(Parent)(pSrcMedium.asOutParam());
1249 if (FAILED(rc)) return rc;
1250 }
1251 /* Update the progress info. */
1252 updateProgressStats(mtc, uCount, uTotalWeight);
1253 /* Append the list of images which have to be moved. */
1254 llMedias.append(mtc);
1255 }
1256 /* Add the save state files of this machine if there is one. */
1257 rc = addSaveState(machine, uCount, uTotalWeight);
1258 if (FAILED(rc)) return rc;
1259
1260 }
1261 /* Build up the index list of the image chain. Unfortunately we can't do
1262 * that in the previous loop, cause there we go from child -> parent and
1263 * didn't know how many are between. */
1264 for (size_t i = 0; i < llMedias.size(); ++i)
1265 {
1266 uint32_t uIdx = 0;
1267 MEDIUMTASKCHAIN &mtc = llMedias.at(i);
1268 for (size_t a = mtc.chain.size(); a > 0; --a)
1269 mtc.chain[a - 1].uIdx = uIdx++;
1270 }
1271
1272 return rc;
1273}
1274
1275HRESULT MachineMoveVM::addSaveState(const ComObjPtr<Machine> &machine, ULONG &uCount, ULONG &uTotalWeight)
1276{
1277 Bstr bstrSrcSaveStatePath;
1278 HRESULT rc = machine->COMGETTER(StateFilePath)(bstrSrcSaveStatePath.asOutParam());
1279 if (FAILED(rc)) return rc;
1280 if (!bstrSrcSaveStatePath.isEmpty())
1281 {
1282 SAVESTATETASK sst;
1283
1284 sst.snapshotUuid = machine->i_getSnapshotId();
1285 sst.strSaveStateFile = bstrSrcSaveStatePath;
1286 uint64_t cbSize;
1287 int vrc = RTFileQuerySize(sst.strSaveStateFile.c_str(), &cbSize);
1288 if (RT_FAILURE(vrc))
1289 return m_pMachine->setError(VBOX_E_IPRT_ERROR, m_pMachine->tr("Could not query file size of '%s' (%Rrc)"),
1290 sst.strSaveStateFile.c_str(), vrc);
1291 /* same rule as above: count both the data which needs to
1292 * be read and written */
1293 sst.uWeight = (ULONG)(2 * (cbSize + _1M - 1) / _1M);
1294 llSaveStateFiles.append(sst);
1295 RTPrintf("Added state file %s into the llSaveStateFiles.\n", sst.strSaveStateFile.c_str());
1296 ++uCount;
1297 uTotalWeight += sst.uWeight;
1298 }
1299 return S_OK;
1300}
1301
1302void MachineMoveVM::updateProgressStats(MEDIUMTASKCHAIN &mtc, ULONG &uCount, ULONG &uTotalWeight) const
1303{
1304
1305 /* Currently the copying of diff images involves reading at least
1306 * the biggest parent in the previous chain. So even if the new
1307 * diff image is small in size, it could need some time to create
1308 * it. Adding the biggest size in the chain should balance this a
1309 * little bit more, i.e. the weight is the sum of the data which
1310 * needs to be read and written. */
1311 ULONG uMaxWeight = 0;
1312 for (size_t e = mtc.chain.size(); e > 0; --e)
1313 {
1314 MEDIUMTASK &mt = mtc.chain.at(e - 1);
1315 mt.uWeight += uMaxWeight;
1316
1317 /* Calculate progress data */
1318 ++uCount;
1319 uTotalWeight += mt.uWeight;
1320
1321 /* Save the max size for better weighting of diff image
1322 * creation. */
1323 uMaxWeight = RT_MAX(uMaxWeight, mt.uWeight);
1324 }
1325}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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