VirtualBox

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

Last change on this file since 70825 was 70825, checked in by vboxsync, 7 years ago

bugref:8345. Removed unused variable.

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

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