VirtualBox

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

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

Main/OVF: sort import code into separate file as well

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

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