VirtualBox

source: vbox/trunk/src/VBox/Main/ApplianceImpl.cpp@ 29984

Last change on this file since 29984 was 29984, checked in by vboxsync, 15 years ago

OVF: almost

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.6 KB
Line 
1/* $Id: ApplianceImpl.cpp 29984 2010-06-02 12:22:39Z vboxsync $ */
2/** @file
3 *
4 * IAppliance and IVirtualSystem COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2008-2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <iprt/path.h>
20
21#include <VBox/com/array.h>
22
23#include "ApplianceImpl.h"
24#include "VFSExplorerImpl.h"
25#include "VirtualBoxImpl.h"
26#include "GuestOSTypeImpl.h"
27#include "ProgressImpl.h"
28#include "MachineImpl.h"
29
30#include "AutoCaller.h"
31#include "Logging.h"
32
33#include "ApplianceImplPrivate.h"
34
35using namespace std;
36
37////////////////////////////////////////////////////////////////////////////////
38//
39// Internal helpers
40//
41////////////////////////////////////////////////////////////////////////////////
42
43static const struct
44{
45 ovf::CIMOSType_T cim;
46 const char *pcszVbox;
47}
48g_osTypes[] =
49{
50 { ovf::CIMOSType_CIMOS_Unknown, SchemaDefs_OSTypeId_Other },
51 { ovf::CIMOSType_CIMOS_OS2, SchemaDefs_OSTypeId_OS2 },
52 { ovf::CIMOSType_CIMOS_MSDOS, SchemaDefs_OSTypeId_DOS },
53 { ovf::CIMOSType_CIMOS_WIN3x, SchemaDefs_OSTypeId_Windows31 },
54 { ovf::CIMOSType_CIMOS_WIN95, SchemaDefs_OSTypeId_Windows95 },
55 { ovf::CIMOSType_CIMOS_WIN98, SchemaDefs_OSTypeId_Windows98 },
56 { ovf::CIMOSType_CIMOS_WINNT, SchemaDefs_OSTypeId_WindowsNT4 },
57 { ovf::CIMOSType_CIMOS_NetWare, SchemaDefs_OSTypeId_Netware },
58 { ovf::CIMOSType_CIMOS_NovellOES, SchemaDefs_OSTypeId_Netware },
59 { ovf::CIMOSType_CIMOS_Solaris, SchemaDefs_OSTypeId_OpenSolaris },
60 { ovf::CIMOSType_CIMOS_SunOS, SchemaDefs_OSTypeId_OpenSolaris },
61 { ovf::CIMOSType_CIMOS_FreeBSD, SchemaDefs_OSTypeId_FreeBSD },
62 { ovf::CIMOSType_CIMOS_NetBSD, SchemaDefs_OSTypeId_NetBSD },
63 { ovf::CIMOSType_CIMOS_QNX, SchemaDefs_OSTypeId_QNX },
64 { ovf::CIMOSType_CIMOS_Windows2000, SchemaDefs_OSTypeId_Windows2000 },
65 { ovf::CIMOSType_CIMOS_WindowsMe, SchemaDefs_OSTypeId_WindowsMe },
66 { ovf::CIMOSType_CIMOS_OpenBSD, SchemaDefs_OSTypeId_OpenBSD },
67 { ovf::CIMOSType_CIMOS_WindowsXP, SchemaDefs_OSTypeId_WindowsXP },
68 { ovf::CIMOSType_CIMOS_WindowsXPEmbedded, SchemaDefs_OSTypeId_WindowsXP },
69 { ovf::CIMOSType_CIMOS_WindowsEmbeddedforPointofService, SchemaDefs_OSTypeId_WindowsXP },
70 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003, SchemaDefs_OSTypeId_Windows2003 },
71 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003_64, SchemaDefs_OSTypeId_Windows2003_64 },
72 { ovf::CIMOSType_CIMOS_WindowsXP_64, SchemaDefs_OSTypeId_WindowsXP_64 },
73 { ovf::CIMOSType_CIMOS_WindowsVista, SchemaDefs_OSTypeId_WindowsVista },
74 { ovf::CIMOSType_CIMOS_WindowsVista_64, SchemaDefs_OSTypeId_WindowsVista_64 },
75 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008, SchemaDefs_OSTypeId_Windows2008 },
76 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008_64, SchemaDefs_OSTypeId_Windows2008_64 },
77 { ovf::CIMOSType_CIMOS_FreeBSD_64, SchemaDefs_OSTypeId_FreeBSD_64 },
78 { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, SchemaDefs_OSTypeId_RedHat },
79 { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, SchemaDefs_OSTypeId_RedHat_64 },
80 { ovf::CIMOSType_CIMOS_Solaris_64, SchemaDefs_OSTypeId_OpenSolaris_64 },
81 { ovf::CIMOSType_CIMOS_SUSE, SchemaDefs_OSTypeId_OpenSUSE },
82 { ovf::CIMOSType_CIMOS_SLES, SchemaDefs_OSTypeId_OpenSUSE },
83 { ovf::CIMOSType_CIMOS_NovellLinuxDesktop, SchemaDefs_OSTypeId_OpenSUSE },
84 { ovf::CIMOSType_CIMOS_SUSE_64, SchemaDefs_OSTypeId_OpenSUSE_64 },
85 { ovf::CIMOSType_CIMOS_SLES_64, SchemaDefs_OSTypeId_OpenSUSE_64 },
86 { ovf::CIMOSType_CIMOS_LINUX, SchemaDefs_OSTypeId_Linux },
87 { ovf::CIMOSType_CIMOS_SunJavaDesktopSystem, SchemaDefs_OSTypeId_Linux },
88 { ovf::CIMOSType_CIMOS_TurboLinux, SchemaDefs_OSTypeId_Linux},
89
90 // { ovf::CIMOSType_CIMOS_TurboLinux_64, },
91
92 { ovf::CIMOSType_CIMOS_Mandriva, SchemaDefs_OSTypeId_Mandriva },
93 { ovf::CIMOSType_CIMOS_Mandriva_64, SchemaDefs_OSTypeId_Mandriva_64 },
94 { ovf::CIMOSType_CIMOS_Ubuntu, SchemaDefs_OSTypeId_Ubuntu },
95 { ovf::CIMOSType_CIMOS_Ubuntu_64, SchemaDefs_OSTypeId_Ubuntu_64 },
96 { ovf::CIMOSType_CIMOS_Debian, SchemaDefs_OSTypeId_Debian },
97 { ovf::CIMOSType_CIMOS_Debian_64, SchemaDefs_OSTypeId_Debian_64 },
98 { ovf::CIMOSType_CIMOS_Linux_2_4_x, SchemaDefs_OSTypeId_Linux24 },
99 { ovf::CIMOSType_CIMOS_Linux_2_4_x_64, SchemaDefs_OSTypeId_Linux24_64 },
100 { ovf::CIMOSType_CIMOS_Linux_2_6_x, SchemaDefs_OSTypeId_Linux26 },
101 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, SchemaDefs_OSTypeId_Linux26_64 },
102 { ovf::CIMOSType_CIMOS_Linux_64, SchemaDefs_OSTypeId_Linux26_64 }
103};
104
105/* Pattern structure for matching the OS type description field */
106struct osTypePattern
107{
108 const char *pcszPattern;
109 const char *pcszVbox;
110};
111
112/* These are the 32-Bit ones. They are sorted by priority. */
113static const osTypePattern g_osTypesPattern[] =
114{
115 {"Windows NT", SchemaDefs_OSTypeId_WindowsNT4},
116 {"Windows XP", SchemaDefs_OSTypeId_WindowsXP},
117 {"Windows 2000", SchemaDefs_OSTypeId_Windows2000},
118 {"Windows 2003", SchemaDefs_OSTypeId_Windows2003},
119 {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista},
120 {"Windows 2008", SchemaDefs_OSTypeId_Windows2008},
121 {"SUSE", SchemaDefs_OSTypeId_OpenSUSE},
122 {"Novell", SchemaDefs_OSTypeId_OpenSUSE},
123 {"Red Hat", SchemaDefs_OSTypeId_RedHat},
124 {"Mandriva", SchemaDefs_OSTypeId_Mandriva},
125 {"Ubuntu", SchemaDefs_OSTypeId_Ubuntu},
126 {"Debian", SchemaDefs_OSTypeId_Debian},
127 {"QNX", SchemaDefs_OSTypeId_QNX},
128 {"Linux 2.4", SchemaDefs_OSTypeId_Linux24},
129 {"Linux 2.6", SchemaDefs_OSTypeId_Linux26},
130 {"Linux", SchemaDefs_OSTypeId_Linux},
131 {"OpenSolaris", SchemaDefs_OSTypeId_OpenSolaris},
132 {"Solaris", SchemaDefs_OSTypeId_OpenSolaris},
133 {"FreeBSD", SchemaDefs_OSTypeId_FreeBSD},
134 {"NetBSD", SchemaDefs_OSTypeId_NetBSD},
135 {"Windows 95", SchemaDefs_OSTypeId_Windows95},
136 {"Windows 98", SchemaDefs_OSTypeId_Windows98},
137 {"Windows Me", SchemaDefs_OSTypeId_WindowsMe},
138 {"Windows 3.", SchemaDefs_OSTypeId_Windows31},
139 {"DOS", SchemaDefs_OSTypeId_DOS},
140 {"OS2", SchemaDefs_OSTypeId_OS2}
141};
142
143/* These are the 64-Bit ones. They are sorted by priority. */
144static const osTypePattern g_osTypesPattern64[] =
145{
146 {"Windows XP", SchemaDefs_OSTypeId_WindowsXP_64},
147 {"Windows 2003", SchemaDefs_OSTypeId_Windows2003_64},
148 {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista_64},
149 {"Windows 2008", SchemaDefs_OSTypeId_Windows2008_64},
150 {"SUSE", SchemaDefs_OSTypeId_OpenSUSE_64},
151 {"Novell", SchemaDefs_OSTypeId_OpenSUSE_64},
152 {"Red Hat", SchemaDefs_OSTypeId_RedHat_64},
153 {"Mandriva", SchemaDefs_OSTypeId_Mandriva_64},
154 {"Ubuntu", SchemaDefs_OSTypeId_Ubuntu_64},
155 {"Debian", SchemaDefs_OSTypeId_Debian_64},
156 {"Linux 2.4", SchemaDefs_OSTypeId_Linux24_64},
157 {"Linux 2.6", SchemaDefs_OSTypeId_Linux26_64},
158 {"Linux", SchemaDefs_OSTypeId_Linux26_64},
159 {"OpenSolaris", SchemaDefs_OSTypeId_OpenSolaris_64},
160 {"Solaris", SchemaDefs_OSTypeId_OpenSolaris_64},
161 {"FreeBSD", SchemaDefs_OSTypeId_FreeBSD_64},
162};
163
164/**
165 * Private helper func that suggests a VirtualBox guest OS type
166 * for the given OVF operating system type.
167 * @param osTypeVBox
168 * @param c
169 * @param cStr
170 */
171void convertCIMOSType2VBoxOSType(Utf8Str &strType, ovf::CIMOSType_T c, const Utf8Str &cStr)
172{
173 /* First check if the type is other/other_64 */
174 if (c == ovf::CIMOSType_CIMOS_Other)
175 {
176 for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern); ++i)
177 if (cStr.contains (g_osTypesPattern[i].pcszPattern, Utf8Str::CaseInsensitive))
178 {
179 strType = g_osTypesPattern[i].pcszVbox;
180 return;
181 }
182 }
183 else if (c == ovf::CIMOSType_CIMOS_Other_64)
184 {
185 for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern64); ++i)
186 if (cStr.contains (g_osTypesPattern64[i].pcszPattern, Utf8Str::CaseInsensitive))
187 {
188 strType = g_osTypesPattern64[i].pcszVbox;
189 return;
190 }
191 }
192
193 for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
194 {
195 if (c == g_osTypes[i].cim)
196 {
197 strType = g_osTypes[i].pcszVbox;
198 return;
199 }
200 }
201
202 strType = SchemaDefs_OSTypeId_Other;
203}
204
205/**
206 * Private helper func that suggests a VirtualBox guest OS type
207 * for the given OVF operating system type.
208 * @param osTypeVBox
209 * @param c
210 */
211ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox)
212{
213 for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
214 {
215 if (!RTStrICmp(pcszVbox, g_osTypes[i].pcszVbox))
216 return g_osTypes[i].cim;
217 }
218
219 return ovf::CIMOSType_CIMOS_Other;
220}
221
222////////////////////////////////////////////////////////////////////////////////
223//
224// IVirtualBox public methods
225//
226////////////////////////////////////////////////////////////////////////////////
227
228// This code is here so we won't have to include the appliance headers in the
229// IVirtualBox implementation.
230
231/**
232 * Implementation for IVirtualBox::createAppliance.
233 *
234 * @param anAppliance IAppliance object created if S_OK is returned.
235 * @return S_OK or error.
236 */
237STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
238{
239 HRESULT rc;
240
241 ComObjPtr<Appliance> appliance;
242 appliance.createObject();
243 rc = appliance->init(this);
244
245 if (SUCCEEDED(rc))
246 appliance.queryInterfaceTo(anAppliance);
247
248 return rc;
249}
250
251////////////////////////////////////////////////////////////////////////////////
252//
253// Appliance constructor / destructor
254//
255////////////////////////////////////////////////////////////////////////////////
256
257Appliance::Appliance()
258 : mVirtualBox(NULL)
259{
260}
261
262Appliance::~Appliance()
263{
264}
265
266/**
267 * Appliance COM initializer.
268 * @param
269 * @return
270 */
271HRESULT Appliance::init(VirtualBox *aVirtualBox)
272{
273 /* Enclose the state transition NotReady->InInit->Ready */
274 AutoInitSpan autoInitSpan(this);
275 AssertReturn(autoInitSpan.isOk(), E_FAIL);
276
277 /* Weak reference to a VirtualBox object */
278 unconst(mVirtualBox) = aVirtualBox;
279
280 // initialize data
281 m = new Data;
282
283 /* Confirm a successful initialization */
284 autoInitSpan.setSucceeded();
285
286 return S_OK;
287}
288
289/**
290 * Appliance COM uninitializer.
291 * @return
292 */
293void Appliance::uninit()
294{
295 /* Enclose the state transition Ready->InUninit->NotReady */
296 AutoUninitSpan autoUninitSpan(this);
297 if (autoUninitSpan.uninitDone())
298 return;
299
300 delete m;
301 m = NULL;
302}
303
304////////////////////////////////////////////////////////////////////////////////
305//
306// IAppliance public methods
307//
308////////////////////////////////////////////////////////////////////////////////
309
310/**
311 * Public method implementation.
312 * @param
313 * @return
314 */
315STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
316{
317 if (!aPath)
318 return E_POINTER;
319
320 AutoCaller autoCaller(this);
321 if (FAILED(autoCaller.rc())) return autoCaller.rc();
322
323 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
324
325 if (!isApplianceIdle())
326 return E_ACCESSDENIED;
327
328 Bstr bstrPath(m->locInfo.strPath);
329 bstrPath.cloneTo(aPath);
330
331 return S_OK;
332}
333
334/**
335 * Public method implementation.
336 * @param
337 * @return
338 */
339STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
340{
341 CheckComArgOutSafeArrayPointerValid(aDisks);
342
343 AutoCaller autoCaller(this);
344 if (FAILED(autoCaller.rc())) return autoCaller.rc();
345
346 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
347
348 if (!isApplianceIdle())
349 return E_ACCESSDENIED;
350
351 if (m->pReader) // OVFReader instantiated?
352 {
353 size_t c = m->pReader->m_mapDisks.size();
354 com::SafeArray<BSTR> sfaDisks(c);
355
356 ovf::DiskImagesMap::const_iterator it;
357 size_t i = 0;
358 for (it = m->pReader->m_mapDisks.begin();
359 it != m->pReader->m_mapDisks.end();
360 ++it, ++i)
361 {
362 // create a string representing this disk
363 const ovf::DiskImage &d = it->second;
364 char *psz = NULL;
365 RTStrAPrintf(&psz,
366 "%s\t"
367 "%RI64\t"
368 "%RI64\t"
369 "%s\t"
370 "%s\t"
371 "%RI64\t"
372 "%RI64\t"
373 "%s",
374 d.strDiskId.c_str(),
375 d.iCapacity,
376 d.iPopulatedSize,
377 d.strFormat.c_str(),
378 d.strHref.c_str(),
379 d.iSize,
380 d.iChunkSize,
381 d.strCompression.c_str());
382 Utf8Str utf(psz);
383 Bstr bstr(utf);
384 // push to safearray
385 bstr.cloneTo(&sfaDisks[i]);
386 RTStrFree(psz);
387 }
388
389 sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
390 }
391
392 return S_OK;
393}
394
395/**
396 * Public method implementation.
397 * @param
398 * @return
399 */
400STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
401{
402 CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
403
404 AutoCaller autoCaller(this);
405 if (FAILED(autoCaller.rc())) return autoCaller.rc();
406
407 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
408
409 if (!isApplianceIdle())
410 return E_ACCESSDENIED;
411
412 SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
413 sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
414
415 return S_OK;
416}
417
418STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
419{
420 CheckComArgOutPointerValid(aExplorer);
421
422 AutoCaller autoCaller(this);
423 if (FAILED(autoCaller.rc())) return autoCaller.rc();
424
425 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
426
427 ComObjPtr<VFSExplorer> explorer;
428 HRESULT rc = S_OK;
429 try
430 {
431 Utf8Str uri(aURI);
432 /* Check which kind of export the user has requested */
433 LocationInfo li;
434 parseURI(uri, li);
435 /* Create the explorer object */
436 explorer.createObject();
437 rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
438 }
439 catch (HRESULT aRC)
440 {
441 rc = aRC;
442 }
443
444 if (SUCCEEDED(rc))
445 /* Return explorer to the caller */
446 explorer.queryInterfaceTo(aExplorer);
447
448 return rc;
449}
450
451/**
452* Public method implementation.
453 * @return
454 */
455STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
456{
457 if (ComSafeArrayOutIsNull(aWarnings))
458 return E_POINTER;
459
460 AutoCaller autoCaller(this);
461 if (FAILED(autoCaller.rc())) return autoCaller.rc();
462
463 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
464
465 com::SafeArray<BSTR> sfaWarnings(m->llWarnings.size());
466
467 list<Utf8Str>::const_iterator it;
468 size_t i = 0;
469 for (it = m->llWarnings.begin();
470 it != m->llWarnings.end();
471 ++it, ++i)
472 {
473 Bstr bstr = *it;
474 bstr.cloneTo(&sfaWarnings[i]);
475 }
476
477 sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
478
479 return S_OK;
480}
481
482////////////////////////////////////////////////////////////////////////////////
483//
484// Appliance private methods
485//
486////////////////////////////////////////////////////////////////////////////////
487
488/**
489 * Returns true if the appliance is in "idle" state. This should always be the
490 * case unless an import or export is currently in progress. Similar to machine
491 * states, this permits the Appliance implementation code to let go of the
492 * Appliance object lock while a time-consuming disk conversion is in progress
493 * without exposing the appliance to conflicting calls.
494 *
495 * This sets an error on "this" (the appliance) and returns false if the appliance
496 * is busy. The caller should then return E_ACCESSDENIED.
497 *
498 * Must be called from under the object lock!
499 *
500 * @return
501 */
502bool Appliance::isApplianceIdle() const
503{
504 if (m->state == Data::ApplianceImporting)
505 setError(VBOX_E_INVALID_OBJECT_STATE, "The appliance is busy importing files");
506 else if (m->state == Data::ApplianceExporting)
507 setError(VBOX_E_INVALID_OBJECT_STATE, "The appliance is busy exporting files");
508 else
509 return true;
510
511 return false;
512}
513
514HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
515{
516 IMachine *machine = NULL;
517 char *tmpName = RTStrDup(aName.c_str());
518 int i = 1;
519 /* @todo: Maybe too cost-intensive; try to find a lighter way */
520 while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
521 {
522 RTStrFree(tmpName);
523 RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
524 ++i;
525 }
526 aName = tmpName;
527 RTStrFree(tmpName);
528
529 return S_OK;
530}
531
532HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
533{
534 IMedium *harddisk = NULL;
535 char *tmpName = RTStrDup(aName.c_str());
536 int i = 1;
537 /* Check if the file exists or if a file with this path is registered
538 * already */
539 /* @todo: Maybe too cost-intensive; try to find a lighter way */
540 while ( RTPathExists(tmpName)
541 || mVirtualBox->FindHardDisk(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND
542 )
543 {
544 RTStrFree(tmpName);
545 char *tmpDir = RTStrDup(aName.c_str());
546 RTPathStripFilename(tmpDir);;
547 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
548 RTPathStripExt(tmpFile);
549 const char *tmpExt = RTPathExt(aName.c_str());
550 RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
551 RTStrFree(tmpFile);
552 RTStrFree(tmpDir);
553 ++i;
554 }
555 aName = tmpName;
556 RTStrFree(tmpName);
557
558 return S_OK;
559}
560
561/**
562 * Little shortcut to SystemProperties::DefaultHardDiskFolder.
563 * @param str
564 * @return
565 */
566HRESULT Appliance::getDefaultHardDiskFolder(Utf8Str &str) const
567{
568 /* We need the default path for storing disk images */
569 ComPtr<ISystemProperties> systemProps;
570 HRESULT rc = mVirtualBox->COMGETTER(SystemProperties)(systemProps.asOutParam());
571 if (FAILED(rc)) return rc;
572 Bstr bstrDefaultHardDiskFolder;
573 rc = systemProps->COMGETTER(DefaultHardDiskFolder)(bstrDefaultHardDiskFolder.asOutParam());
574 if (FAILED(rc)) return rc;
575 str = bstrDefaultHardDiskFolder;
576
577 return S_OK;
578}
579
580/**
581 * Called from the import and export background threads to synchronize the second
582 * background disk thread's progress object with the current progress object so
583 * that the user interface sees progress correctly and that cancel signals are
584 * passed on to the second thread.
585 * @param pProgressThis Progress object of the current thread.
586 * @param pProgressAsync Progress object of asynchronous task running in background.
587 */
588void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
589 ComPtr<IProgress> &pProgressAsync)
590{
591 HRESULT rc;
592
593 // now loop until the asynchronous operation completes and then report its result
594 BOOL fCompleted;
595 BOOL fCanceled;
596 ULONG currentPercent;
597 while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
598 {
599 rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
600 if (FAILED(rc)) throw rc;
601 if (fCanceled)
602 {
603 pProgressAsync->Cancel();
604 break;
605 }
606
607 rc = pProgressAsync->COMGETTER(Percent(&currentPercent));
608 if (FAILED(rc)) throw rc;
609 if (!pProgressThis.isNull())
610 pProgressThis->SetCurrentOperationProgress(currentPercent);
611 if (fCompleted)
612 break;
613
614 /* Make sure the loop is not too tight */
615 rc = pProgressAsync->WaitForCompletion(100);
616 if (FAILED(rc)) throw rc;
617 }
618 // report result of asynchronous operation
619 LONG iRc;
620 rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
621 if (FAILED(rc)) throw rc;
622
623
624 // if the thread of the progress object has an error, then
625 // retrieve the error info from there, or it'll be lost
626 if (FAILED(iRc))
627 {
628 ProgressErrorInfo info(pProgressAsync);
629 Utf8Str str(info.getText());
630 const char *pcsz = str.c_str();
631 HRESULT rc2 = setError(iRc, pcsz);
632 throw rc2;
633 }
634}
635
636void Appliance::addWarning(const char* aWarning, ...)
637{
638 va_list args;
639 va_start(args, aWarning);
640 Utf8StrFmtVA str(aWarning, args);
641 va_end(args);
642 m->llWarnings.push_back(str);
643}
644
645/**
646 * Refreshes the cDisks and ulTotalDisksMB members in the instance data.
647 * Requires that virtual system descriptions are present.
648 */
649void Appliance::disksWeight()
650{
651 m->ulTotalDisksMB = 0;
652 m->cDisks = 0;
653 // weigh the disk images according to their sizes
654 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
655 for (it = m->virtualSystemDescriptions.begin();
656 it != m->virtualSystemDescriptions.end();
657 ++it)
658 {
659 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
660 /* One for every hard disk of the Virtual System */
661 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
662 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
663 for (itH = avsdeHDs.begin();
664 itH != avsdeHDs.end();
665 ++itH)
666 {
667 const VirtualSystemDescriptionEntry *pHD = *itH;
668 m->ulTotalDisksMB += pHD->ulSizeMB;
669 ++m->cDisks;
670 }
671 }
672
673}
674
675/**
676 * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a
677 * progress object with the proper weights and maximum progress values.
678 *
679 * @param pProgress
680 * @param bstrDescription
681 * @param mode
682 * @return
683 */
684HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress,
685 const Bstr &bstrDescription,
686 SetUpProgressMode mode)
687{
688 HRESULT rc;
689
690 /* Create the progress object */
691 pProgress.createObject();
692
693 // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data)
694 disksWeight();
695
696 m->ulWeightForManifestOperation = 0;
697
698 ULONG cOperations;
699 ULONG ulTotalOperationsWeight;
700
701 cOperations = 1 // one for XML setup
702 + m->cDisks; // plus one per disk
703 if (m->ulTotalDisksMB)
704 {
705 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML
706 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
707 }
708 else
709 {
710 // no disks to export:
711 m->ulWeightForXmlOperation = 1;
712 ulTotalOperationsWeight = 1;
713 }
714
715 switch (mode)
716 {
717 case ImportFileNoManifest:
718 break;
719
720 case ImportFileWithManifest:
721 case WriteFile:
722 ++cOperations; // another one for creating the manifest
723
724 // assume that checking or creating the manifest will take 10% of the time it takes to export the disks
725 m->ulWeightForManifestOperation = m->ulTotalDisksMB / 10;
726 ulTotalOperationsWeight += m->ulWeightForManifestOperation;
727 break;
728
729 case ImportS3:
730 {
731 cOperations += 1 + 1; // another one for the manifest file & another one for the import
732 ulTotalOperationsWeight = m->ulTotalDisksMB;
733 if (!m->ulTotalDisksMB)
734 // no disks to export:
735 ulTotalOperationsWeight = 1;
736
737 ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import
738 ulTotalOperationsWeight += ulImportWeight;
739
740 m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */
741
742 ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init
743 ulTotalOperationsWeight += ulInitWeight;
744 }
745 break;
746
747 case WriteS3:
748 {
749 cOperations += 1 + 1; // another one for the mf & another one for temporary creation
750
751 if (m->ulTotalDisksMB)
752 {
753 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for OVF file upload (we didn't know the size at this point)
754 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
755 }
756 else
757 {
758 // no disks to export:
759 ulTotalOperationsWeight = 1;
760 m->ulWeightForXmlOperation = 1;
761 }
762 ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
763 ulTotalOperationsWeight += ulOVFCreationWeight;
764 }
765 break;
766 }
767
768 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n",
769 m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation));
770
771 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
772 bstrDescription,
773 TRUE /* aCancelable */,
774 cOperations, // ULONG cOperations,
775 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
776 bstrDescription, // CBSTR bstrFirstOperationDescription,
777 m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight,
778 return rc;
779}
780
781void Appliance::parseURI(Utf8Str strUri, LocationInfo &locInfo) const
782{
783 /* Check the URI for the protocol */
784 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
785 {
786 locInfo.storageType = VFSType_File;
787 strUri = strUri.substr(sizeof("file://") - 1);
788 }
789 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
790 {
791 locInfo.storageType = VFSType_S3;
792 strUri = strUri.substr(sizeof("SunCloud://") - 1);
793 }
794 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
795 {
796 locInfo.storageType = VFSType_S3;
797 strUri = strUri.substr(sizeof("S3://") - 1);
798 }
799 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
800 throw E_NOTIMPL;
801
802 /* Not necessary on a file based URI */
803 if (locInfo.storageType != VFSType_File)
804 {
805 size_t uppos = strUri.find("@"); /* username:password combo */
806 if (uppos != Utf8Str::npos)
807 {
808 locInfo.strUsername = strUri.substr(0, uppos);
809 strUri = strUri.substr(uppos + 1);
810 size_t upos = locInfo.strUsername.find(":");
811 if (upos != Utf8Str::npos)
812 {
813 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
814 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
815 }
816 }
817 size_t hpos = strUri.find("/"); /* hostname part */
818 if (hpos != Utf8Str::npos)
819 {
820 locInfo.strHostname = strUri.substr(0, hpos);
821 strUri = strUri.substr(hpos);
822 }
823 }
824
825 locInfo.strPath = strUri;
826}
827
828void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket) const
829{
830 /* Buckets are S3 specific. So parse the bucket out of the file path */
831 if (!aPath.startsWith("/"))
832 throw setError(E_INVALIDARG,
833 tr("The path '%s' must start with /"), aPath.c_str());
834 size_t bpos = aPath.find("/", 1);
835 if (bpos != Utf8Str::npos)
836 {
837 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
838 aPath = aPath.substr(bpos); /* The rest of the file path */
839 }
840 /* If there is no bucket name provided reject it */
841 if (aBucket.isEmpty())
842 throw setError(E_INVALIDARG,
843 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
844}
845
846Utf8Str Appliance::manifestFileName(Utf8Str aPath) const
847{
848 /* Get the name part */
849 char *pszMfName = RTStrDup(RTPathFilename(aPath.c_str()));
850 /* Strip any extensions */
851 RTPathStripExt(pszMfName);
852 /* Path without the filename */
853 aPath.stripFilename();
854 /* Format the manifest path */
855 Utf8StrFmt strMfFile("%s/%s.mf", aPath.c_str(), pszMfName);
856 RTStrFree(pszMfName);
857 return strMfFile;
858}
859
860/**
861 *
862 * @return
863 */
864int Appliance::TaskOVF::startThread()
865{
866 int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOrExport, this,
867 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
868 "Appliance::Task");
869
870 ComAssertMsgRCRet(vrc,
871 ("Could not create OVF task thread (%Rrc)\n", vrc), E_FAIL);
872
873 return S_OK;
874}
875
876/**
877 * Thread function for the thread started in Appliance::readImpl() and Appliance::importImpl()
878 * and Appliance::writeImpl().
879 * This will in turn call Appliance::readFS() or Appliance::readS3() or Appliance::importFS()
880 * or Appliance::importS3() or Appliance::writeFS() or Appliance::writeS3().
881 *
882 * @param aThread
883 * @param pvUser
884 */
885/* static */
886DECLCALLBACK(int) Appliance::taskThreadImportOrExport(RTTHREAD /* aThread */, void *pvUser)
887{
888 std::auto_ptr<TaskOVF> task(static_cast<TaskOVF*>(pvUser));
889 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
890
891 Appliance *pAppliance = task->pAppliance;
892
893 LogFlowFuncEnter();
894 LogFlowFunc(("Appliance %p\n", pAppliance));
895
896 HRESULT taskrc = S_OK;
897
898 switch (task->taskType)
899 {
900 case TaskOVF::Read:
901 if (task->locInfo.storageType == VFSType_File)
902 taskrc = pAppliance->readFS(task->locInfo);
903 else if (task->locInfo.storageType == VFSType_S3)
904 taskrc = pAppliance->readS3(task.get());
905 break;
906
907 case TaskOVF::Import:
908 if (task->locInfo.storageType == VFSType_File)
909 taskrc = pAppliance->importFS(task->locInfo, task->pProgress);
910 else if (task->locInfo.storageType == VFSType_S3)
911 taskrc = pAppliance->importS3(task.get());
912 break;
913
914 case TaskOVF::Write:
915 if (task->locInfo.storageType == VFSType_File)
916 taskrc = pAppliance->writeFS(task->locInfo, task->enFormat, task->pProgress);
917 else if (task->locInfo.storageType == VFSType_S3)
918 taskrc = pAppliance->writeS3(task.get());
919 break;
920 }
921
922 task->rc = taskrc;
923
924 if (!task->pProgress.isNull())
925 task->pProgress->notifyComplete(taskrc);
926
927 LogFlowFuncLeave();
928
929 return VINF_SUCCESS;
930}
931
932/* static */
933int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
934{
935 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
936
937 if ( pTask
938 && !pTask->pProgress.isNull())
939 {
940 BOOL fCanceled;
941 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
942 if (fCanceled)
943 return -1;
944 pTask->pProgress->SetCurrentOperationProgress(uPercent);
945 }
946 return VINF_SUCCESS;
947}
948
949////////////////////////////////////////////////////////////////////////////////
950//
951// IVirtualSystemDescription constructor / destructor
952//
953////////////////////////////////////////////////////////////////////////////////
954
955DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
956
957/**
958 * COM initializer.
959 * @return
960 */
961HRESULT VirtualSystemDescription::init()
962{
963 /* Enclose the state transition NotReady->InInit->Ready */
964 AutoInitSpan autoInitSpan(this);
965 AssertReturn(autoInitSpan.isOk(), E_FAIL);
966
967 /* Initialize data */
968 m = new Data();
969 m->pConfig = NULL;
970
971 /* Confirm a successful initialization */
972 autoInitSpan.setSucceeded();
973 return S_OK;
974}
975
976/**
977* COM uninitializer.
978*/
979
980void VirtualSystemDescription::uninit()
981{
982 if (m->pConfig)
983 delete m->pConfig;
984 delete m;
985 m = NULL;
986}
987
988////////////////////////////////////////////////////////////////////////////////
989//
990// IVirtualSystemDescription public methods
991//
992////////////////////////////////////////////////////////////////////////////////
993
994/**
995 * Public method implementation.
996 * @param
997 * @return
998 */
999STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
1000{
1001 if (!aCount)
1002 return E_POINTER;
1003
1004 AutoCaller autoCaller(this);
1005 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1006
1007 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1008
1009 *aCount = (ULONG)m->llDescriptions.size();
1010
1011 return S_OK;
1012}
1013
1014/**
1015 * Public method implementation.
1016 * @return
1017 */
1018STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1019 ComSafeArrayOut(BSTR, aRefs),
1020 ComSafeArrayOut(BSTR, aOrigValues),
1021 ComSafeArrayOut(BSTR, aVboxValues),
1022 ComSafeArrayOut(BSTR, aExtraConfigValues))
1023{
1024 if (ComSafeArrayOutIsNull(aTypes) ||
1025 ComSafeArrayOutIsNull(aRefs) ||
1026 ComSafeArrayOutIsNull(aOrigValues) ||
1027 ComSafeArrayOutIsNull(aVboxValues) ||
1028 ComSafeArrayOutIsNull(aExtraConfigValues))
1029 return E_POINTER;
1030
1031 AutoCaller autoCaller(this);
1032 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1033
1034 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1035
1036 ULONG c = (ULONG)m->llDescriptions.size();
1037 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1038 com::SafeArray<BSTR> sfaRefs(c);
1039 com::SafeArray<BSTR> sfaOrigValues(c);
1040 com::SafeArray<BSTR> sfaVboxValues(c);
1041 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1042
1043 list<VirtualSystemDescriptionEntry>::const_iterator it;
1044 size_t i = 0;
1045 for (it = m->llDescriptions.begin();
1046 it != m->llDescriptions.end();
1047 ++it, ++i)
1048 {
1049 const VirtualSystemDescriptionEntry &vsde = (*it);
1050
1051 sfaTypes[i] = vsde.type;
1052
1053 Bstr bstr = vsde.strRef;
1054 bstr.cloneTo(&sfaRefs[i]);
1055
1056 bstr = vsde.strOvf;
1057 bstr.cloneTo(&sfaOrigValues[i]);
1058
1059 bstr = vsde.strVboxCurrent;
1060 bstr.cloneTo(&sfaVboxValues[i]);
1061
1062 bstr = vsde.strExtraConfigCurrent;
1063 bstr.cloneTo(&sfaExtraConfigValues[i]);
1064 }
1065
1066 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1067 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1068 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1069 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1070 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1071
1072 return S_OK;
1073}
1074
1075/**
1076 * Public method implementation.
1077 * @return
1078 */
1079STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescriptionType_T aType,
1080 ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1081 ComSafeArrayOut(BSTR, aRefs),
1082 ComSafeArrayOut(BSTR, aOrigValues),
1083 ComSafeArrayOut(BSTR, aVboxValues),
1084 ComSafeArrayOut(BSTR, aExtraConfigValues))
1085{
1086 if (ComSafeArrayOutIsNull(aTypes) ||
1087 ComSafeArrayOutIsNull(aRefs) ||
1088 ComSafeArrayOutIsNull(aOrigValues) ||
1089 ComSafeArrayOutIsNull(aVboxValues) ||
1090 ComSafeArrayOutIsNull(aExtraConfigValues))
1091 return E_POINTER;
1092
1093 AutoCaller autoCaller(this);
1094 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1095
1096 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1097
1098 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1099 ULONG c = (ULONG)vsd.size();
1100 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1101 com::SafeArray<BSTR> sfaRefs(c);
1102 com::SafeArray<BSTR> sfaOrigValues(c);
1103 com::SafeArray<BSTR> sfaVboxValues(c);
1104 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1105
1106 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1107 size_t i = 0;
1108 for (it = vsd.begin();
1109 it != vsd.end();
1110 ++it, ++i)
1111 {
1112 const VirtualSystemDescriptionEntry *vsde = (*it);
1113
1114 sfaTypes[i] = vsde->type;
1115
1116 Bstr bstr = vsde->strRef;
1117 bstr.cloneTo(&sfaRefs[i]);
1118
1119 bstr = vsde->strOvf;
1120 bstr.cloneTo(&sfaOrigValues[i]);
1121
1122 bstr = vsde->strVboxCurrent;
1123 bstr.cloneTo(&sfaVboxValues[i]);
1124
1125 bstr = vsde->strExtraConfigCurrent;
1126 bstr.cloneTo(&sfaExtraConfigValues[i]);
1127 }
1128
1129 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1130 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1131 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1132 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1133 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1134
1135 return S_OK;
1136}
1137
1138/**
1139 * Public method implementation.
1140 * @return
1141 */
1142STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionType_T aType,
1143 VirtualSystemDescriptionValueType_T aWhich,
1144 ComSafeArrayOut(BSTR, aValues))
1145{
1146 if (ComSafeArrayOutIsNull(aValues))
1147 return E_POINTER;
1148
1149 AutoCaller autoCaller(this);
1150 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1151
1152 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1153
1154 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1155 com::SafeArray<BSTR> sfaValues((ULONG)vsd.size());
1156
1157 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1158 size_t i = 0;
1159 for (it = vsd.begin();
1160 it != vsd.end();
1161 ++it, ++i)
1162 {
1163 const VirtualSystemDescriptionEntry *vsde = (*it);
1164
1165 Bstr bstr;
1166 switch (aWhich)
1167 {
1168 case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
1169 case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
1170 case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVboxCurrent; break;
1171 case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfigCurrent; break;
1172 }
1173
1174 bstr.cloneTo(&sfaValues[i]);
1175 }
1176
1177 sfaValues.detachTo(ComSafeArrayOutArg(aValues));
1178
1179 return S_OK;
1180}
1181
1182/**
1183 * Public method implementation.
1184 * @return
1185 */
1186STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
1187 ComSafeArrayIn(IN_BSTR, argVboxValues),
1188 ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
1189{
1190#ifndef RT_OS_WINDOWS
1191 NOREF(aEnabledSize);
1192#endif /* RT_OS_WINDOWS */
1193
1194 CheckComArgSafeArrayNotNull(aEnabled);
1195 CheckComArgSafeArrayNotNull(argVboxValues);
1196 CheckComArgSafeArrayNotNull(argExtraConfigValues);
1197
1198 AutoCaller autoCaller(this);
1199 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1200
1201 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1202
1203 com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
1204 com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
1205 com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
1206
1207 if ( (sfaEnabled.size() != m->llDescriptions.size())
1208 || (sfaVboxValues.size() != m->llDescriptions.size())
1209 || (sfaExtraConfigValues.size() != m->llDescriptions.size())
1210 )
1211 return E_INVALIDARG;
1212
1213 list<VirtualSystemDescriptionEntry>::iterator it;
1214 size_t i = 0;
1215 for (it = m->llDescriptions.begin();
1216 it != m->llDescriptions.end();
1217 ++it, ++i)
1218 {
1219 VirtualSystemDescriptionEntry& vsde = *it;
1220
1221 if (sfaEnabled[i])
1222 {
1223 vsde.strVboxCurrent = sfaVboxValues[i];
1224 vsde.strExtraConfigCurrent = sfaExtraConfigValues[i];
1225 }
1226 else
1227 vsde.type = VirtualSystemDescriptionType_Ignore;
1228 }
1229
1230 return S_OK;
1231}
1232
1233/**
1234 * Public method implementation.
1235 * @return
1236 */
1237STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
1238 IN_BSTR aVboxValue,
1239 IN_BSTR aExtraConfigValue)
1240{
1241 AutoCaller autoCaller(this);
1242 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1243
1244 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1245
1246 addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
1247
1248 return S_OK;
1249}
1250
1251/**
1252 * Internal method; adds a new description item to the member list.
1253 * @param aType Type of description for the new item.
1254 * @param strRef Reference item; only used with hard disk controllers.
1255 * @param aOrigValue Corresponding original value from OVF.
1256 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
1257 * @param ulSizeMB Weight for IProgress
1258 * @param strExtraConfig Extra configuration; meaning dependent on type.
1259 */
1260void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
1261 const Utf8Str &strRef,
1262 const Utf8Str &aOvfValue,
1263 const Utf8Str &aVboxValue,
1264 uint32_t ulSizeMB,
1265 const Utf8Str &strExtraConfig /*= ""*/)
1266{
1267 VirtualSystemDescriptionEntry vsde;
1268 vsde.ulIndex = (uint32_t)m->llDescriptions.size(); // each entry gets an index so the client side can reference them
1269 vsde.type = aType;
1270 vsde.strRef = strRef;
1271 vsde.strOvf = aOvfValue;
1272 vsde.strVboxSuggested // remember original value
1273 = vsde.strVboxCurrent // and set current value which can be overridden by setFinalValues()
1274 = aVboxValue;
1275 vsde.strExtraConfigSuggested
1276 = vsde.strExtraConfigCurrent
1277 = strExtraConfig;
1278 vsde.ulSizeMB = ulSizeMB;
1279
1280 m->llDescriptions.push_back(vsde);
1281}
1282
1283/**
1284 * Private method; returns a list of description items containing all the items from the member
1285 * description items of this virtual system that match the given type.
1286 * @param aType
1287 * @return
1288 */
1289std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
1290{
1291 std::list<VirtualSystemDescriptionEntry*> vsd;
1292
1293 list<VirtualSystemDescriptionEntry>::iterator it;
1294 for (it = m->llDescriptions.begin();
1295 it != m->llDescriptions.end();
1296 ++it)
1297 {
1298 if (it->type == aType)
1299 vsd.push_back(&(*it));
1300 }
1301
1302 return vsd;
1303}
1304
1305/**
1306 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1307 * the given reference ID. Useful when needing the controller for a particular
1308 * virtual disk.
1309 * @param id
1310 * @return
1311 */
1312const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
1313{
1314 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1315 list<VirtualSystemDescriptionEntry>::const_iterator it;
1316 for (it = m->llDescriptions.begin();
1317 it != m->llDescriptions.end();
1318 ++it)
1319 {
1320 const VirtualSystemDescriptionEntry &d = *it;
1321 switch (d.type)
1322 {
1323 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1324 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1325 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1326 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1327 if (d.strRef == strRef)
1328 return &d;
1329 break;
1330 }
1331 }
1332
1333 return NULL;
1334}
1335
1336/**
1337 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1338 * contains a <vbox:Machine> element. This method then attempts to parse that and
1339 * create a MachineConfigFile instance from it which is stored in this instance data
1340 * and can then be used to create a machine.
1341 *
1342 * This must only be called once per instance.
1343 *
1344 * This rethrows all XML and logic errors from MachineConfigFile.
1345 *
1346 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1347 * DOM tree.
1348 */
1349void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmMachine)
1350{
1351 settings::MachineConfigFile *pConfig = NULL;
1352
1353 Assert(m->pConfig == NULL);
1354
1355 try
1356 {
1357 pConfig = new settings::MachineConfigFile(NULL);
1358 pConfig->importMachineXML(elmMachine);
1359
1360 m->pConfig = pConfig;
1361 }
1362 catch (...)
1363 {
1364 if (pConfig)
1365 delete pConfig;
1366 throw;
1367 }
1368}
1369
1370/**
1371 * Returns the machine config created by importVboxMachineXML() or NULL if there's none.
1372 * @return
1373 */
1374const settings::MachineConfigFile* VirtualSystemDescription::getMachineConfig() const
1375{
1376 return m->pConfig;
1377}
1378
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