VirtualBox

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

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

scm police

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

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