diff options
Diffstat (limited to 'src/VBox/Main/src-server/ApplianceImpl.cpp')
-rw-r--r-- | src/VBox/Main/src-server/ApplianceImpl.cpp | 1943 |
1 files changed, 1943 insertions, 0 deletions
diff --git a/src/VBox/Main/src-server/ApplianceImpl.cpp b/src/VBox/Main/src-server/ApplianceImpl.cpp new file mode 100644 index 00000000..333ffc61 --- /dev/null +++ b/src/VBox/Main/src-server/ApplianceImpl.cpp @@ -0,0 +1,1943 @@ +/* $Id: ApplianceImpl.cpp $ */ +/** @file + * IAppliance and IVirtualSystem COM class implementations. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_MAIN_APPLIANCE +#include <iprt/path.h> +#include <iprt/cpp/path.h> +#include <iprt/cpp/utils.h> +#include <VBox/com/array.h> +#include <map> + +#include "ApplianceImpl.h" +#include "VFSExplorerImpl.h" +#include "VirtualBoxImpl.h" +#include "GuestOSTypeImpl.h" +#include "Global.h" +#include "ProgressImpl.h" +#include "MachineImpl.h" +#include "SystemPropertiesImpl.h" +#include "AutoCaller.h" +#include "LoggingNew.h" +#include "CertificateImpl.h" + +#include "ApplianceImplPrivate.h" + +using namespace std; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const char * const g_pszISOURI = "http://www.ecma-international.org/publications/standards/Ecma-119.htm"; +static const char * const g_pszVMDKStreamURI = "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"; +static const char * const g_pszVMDKSparseURI = "http://www.vmware.com/specifications/vmdk.html#sparse"; +static const char * const g_pszVMDKCompressedURI = "http://www.vmware.com/specifications/vmdk.html#compressed"; +static const char * const g_pszVMDKCompressedURI2 = "http://www.vmware.com/interfaces/specifications/vmdk.html#compressed"; +static const char * const g_pszrVHDURI = "http://go.microsoft.com/fwlink/?LinkId=137171"; +static char g_szIsoBackend[128]; +static char g_szVmdkBackend[128]; +static char g_szVhdBackend[128]; +/** Set after the g_szXxxxBackend variables has been initialized. */ +static bool volatile g_fInitializedBackendNames = false; + +static struct +{ + const char *pszUri, *pszBackend; +} const g_aUriToBackend[] = +{ + { g_pszISOURI, g_szIsoBackend }, + { g_pszVMDKStreamURI, g_szVmdkBackend }, + { g_pszVMDKSparseURI, g_szVmdkBackend }, + { g_pszVMDKCompressedURI, g_szVmdkBackend }, + { g_pszVMDKCompressedURI2, g_szVmdkBackend }, + { g_pszrVHDURI, g_szVhdBackend }, +}; + +static std::map<Utf8Str, Utf8Str> supportedStandardsURI; + +static struct +{ + ovf::CIMOSType_T cim; + VBOXOSTYPE osType; +} const g_aOsTypes[] = +{ + { ovf::CIMOSType_CIMOS_Unknown, VBOXOSTYPE_Unknown }, + { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS2 }, + { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS2Warp3 }, + { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS2Warp4 }, + { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS2Warp45 }, + { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS21x }, + { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_ECS }, + { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_ArcaOS }, + { ovf::CIMOSType_CIMOS_MSDOS, VBOXOSTYPE_DOS }, + { ovf::CIMOSType_CIMOS_WIN3x, VBOXOSTYPE_Win31 }, + { ovf::CIMOSType_CIMOS_WIN95, VBOXOSTYPE_Win95 }, + { ovf::CIMOSType_CIMOS_WIN98, VBOXOSTYPE_Win98 }, + { ovf::CIMOSType_CIMOS_WINNT, VBOXOSTYPE_WinNT }, + { ovf::CIMOSType_CIMOS_WINNT, VBOXOSTYPE_WinNT4 }, + { ovf::CIMOSType_CIMOS_WINNT, VBOXOSTYPE_WinNT3x }, + { ovf::CIMOSType_CIMOS_NetWare, VBOXOSTYPE_Netware }, + { ovf::CIMOSType_CIMOS_NovellOES, VBOXOSTYPE_Netware }, + { ovf::CIMOSType_CIMOS_Solaris, VBOXOSTYPE_Solaris }, + { ovf::CIMOSType_CIMOS_Solaris_64, VBOXOSTYPE_Solaris_x64 }, + { ovf::CIMOSType_CIMOS_Solaris, VBOXOSTYPE_Solaris10U8_or_later }, + { ovf::CIMOSType_CIMOS_Solaris_64, VBOXOSTYPE_Solaris10U8_or_later_x64 }, + { ovf::CIMOSType_CIMOS_SunOS, VBOXOSTYPE_Solaris }, + { ovf::CIMOSType_CIMOS_FreeBSD, VBOXOSTYPE_FreeBSD }, + { ovf::CIMOSType_CIMOS_NetBSD, VBOXOSTYPE_NetBSD }, + { ovf::CIMOSType_CIMOS_QNX, VBOXOSTYPE_QNX }, + { ovf::CIMOSType_CIMOS_Windows2000, VBOXOSTYPE_Win2k }, + { ovf::CIMOSType_CIMOS_WindowsMe, VBOXOSTYPE_WinMe }, + { ovf::CIMOSType_CIMOS_OpenBSD, VBOXOSTYPE_OpenBSD }, + { ovf::CIMOSType_CIMOS_WindowsXP, VBOXOSTYPE_WinXP }, + { ovf::CIMOSType_CIMOS_WindowsXPEmbedded, VBOXOSTYPE_WinXP }, + { ovf::CIMOSType_CIMOS_WindowsEmbeddedforPointofService, VBOXOSTYPE_WinXP }, + { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003, VBOXOSTYPE_Win2k3 }, + { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003_64, VBOXOSTYPE_Win2k3_x64 }, + { ovf::CIMOSType_CIMOS_WindowsXP_64, VBOXOSTYPE_WinXP_x64 }, + { ovf::CIMOSType_CIMOS_WindowsVista, VBOXOSTYPE_WinVista }, + { ovf::CIMOSType_CIMOS_WindowsVista_64, VBOXOSTYPE_WinVista_x64 }, + { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008, VBOXOSTYPE_Win2k8 }, + { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008_64, VBOXOSTYPE_Win2k8_x64 }, + { ovf::CIMOSType_CIMOS_FreeBSD_64, VBOXOSTYPE_FreeBSD_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS_x64 }, // there is no CIM 64-bit type for this + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS106 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS106_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS107_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS108_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS109_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS1010_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS1011_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS1012_x64 }, + { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS1013_x64 }, + + // Linuxes + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, VBOXOSTYPE_RedHat }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, VBOXOSTYPE_RedHat_x64 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, VBOXOSTYPE_RedHat3 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, VBOXOSTYPE_RedHat3_x64 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, VBOXOSTYPE_RedHat4 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, VBOXOSTYPE_RedHat4_x64 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, VBOXOSTYPE_RedHat5 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, VBOXOSTYPE_RedHat5_x64 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, VBOXOSTYPE_RedHat6 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, VBOXOSTYPE_RedHat6_x64 }, + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, VBOXOSTYPE_RedHat7_x64 }, // 64-bit only + { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, VBOXOSTYPE_RedHat8_x64 }, // 64-bit only + { ovf::CIMOSType_CIMOS_SUSE, VBOXOSTYPE_OpenSUSE }, + { ovf::CIMOSType_CIMOS_SLES, VBOXOSTYPE_SUSE_LE }, + { ovf::CIMOSType_CIMOS_NovellLinuxDesktop, VBOXOSTYPE_OpenSUSE }, + { ovf::CIMOSType_CIMOS_SUSE_64, VBOXOSTYPE_OpenSUSE_x64 }, + { ovf::CIMOSType_CIMOS_SLES_64, VBOXOSTYPE_SUSE_LE_x64 }, + { ovf::CIMOSType_CIMOS_SUSE_64, VBOXOSTYPE_OpenSUSE_Leap_x64 }, // 64-bit only + { ovf::CIMOSType_CIMOS_SUSE, VBOXOSTYPE_OpenSUSE_Tumbleweed }, + { ovf::CIMOSType_CIMOS_SUSE_64, VBOXOSTYPE_OpenSUSE_Tumbleweed_x64 }, + { ovf::CIMOSType_CIMOS_LINUX, VBOXOSTYPE_Linux }, + { ovf::CIMOSType_CIMOS_LINUX, VBOXOSTYPE_Linux22 }, + { ovf::CIMOSType_CIMOS_SunJavaDesktopSystem, VBOXOSTYPE_Linux }, + { ovf::CIMOSType_CIMOS_TurboLinux, VBOXOSTYPE_Turbolinux }, + { ovf::CIMOSType_CIMOS_TurboLinux_64, VBOXOSTYPE_Turbolinux_x64 }, + { ovf::CIMOSType_CIMOS_Mandriva, VBOXOSTYPE_Mandriva }, + { ovf::CIMOSType_CIMOS_Mandriva_64, VBOXOSTYPE_Mandriva_x64 }, + { ovf::CIMOSType_CIMOS_Mandriva, VBOXOSTYPE_OpenMandriva_Lx }, + { ovf::CIMOSType_CIMOS_Mandriva_64, VBOXOSTYPE_OpenMandriva_Lx_x64 }, + { ovf::CIMOSType_CIMOS_Mandriva, VBOXOSTYPE_PCLinuxOS }, + { ovf::CIMOSType_CIMOS_Mandriva_64, VBOXOSTYPE_PCLinuxOS_x64 }, + { ovf::CIMOSType_CIMOS_Mandriva, VBOXOSTYPE_Mageia }, + { ovf::CIMOSType_CIMOS_Mandriva_64, VBOXOSTYPE_Mageia_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu10_LTS }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu10_LTS_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu10 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu10_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu11 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu11_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu12_LTS }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu12_LTS_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu12 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu12_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu13 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu13_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu14_LTS }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu14_LTS_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu14 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu14_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu15 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu15_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu16_LTS }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu16_LTS_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu16 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu16_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu17 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu17_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu18_LTS }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu18_LTS_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu18 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu18_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu19 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu19_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu20_LTS_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu20_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu21_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu22_LTS_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu22_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Lubuntu }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Lubuntu_x64 }, + { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Xubuntu }, + { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Xubuntu_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian31 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian4 }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian4_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian5 }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian5_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian6 }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian6_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian7 }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian7_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian8 }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian8_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian9 }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian9_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian10 }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian10_x64 }, + { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian11 }, + { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian11_x64 }, + { ovf::CIMOSType_CIMOS_Linux_2_4_x, VBOXOSTYPE_Linux24 }, + { ovf::CIMOSType_CIMOS_Linux_2_4_x_64, VBOXOSTYPE_Linux24_x64 }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_Linux26 }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_Linux26_x64 }, + { ovf::CIMOSType_CIMOS_Linux_64, VBOXOSTYPE_Linux26_x64 }, + + // types that we have support for but CIM doesn't + { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_ArchLinux }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_ArchLinux_x64 }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_FedoraCore }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_FedoraCore_x64 }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_Gentoo }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_Gentoo_x64 }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_Xandros }, + { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_Xandros_x64 }, + { ovf::CIMOSType_CIMOS_Solaris, VBOXOSTYPE_OpenSolaris }, + { ovf::CIMOSType_CIMOS_Solaris_64, VBOXOSTYPE_OpenSolaris_x64 }, + + // types added with CIM 2.25.0 follow: + { ovf::CIMOSType_CIMOS_WindowsServer2008R2, VBOXOSTYPE_Win2k8 }, // duplicate, see above +// { ovf::CIMOSType_CIMOS_VMwareESXi = 104, // we can't run ESX in a VM + { ovf::CIMOSType_CIMOS_Windows7, VBOXOSTYPE_Win7 }, + { ovf::CIMOSType_CIMOS_Windows7, VBOXOSTYPE_Win7_x64 }, // there is no + // CIM 64-bit type for this + { ovf::CIMOSType_CIMOS_CentOS, VBOXOSTYPE_RedHat }, + { ovf::CIMOSType_CIMOS_CentOS_64, VBOXOSTYPE_RedHat_x64 }, + { ovf::CIMOSType_CIMOS_OracleLinux, VBOXOSTYPE_Oracle }, + { ovf::CIMOSType_CIMOS_OracleLinux_64, VBOXOSTYPE_Oracle_x64 }, + { ovf::CIMOSType_CIMOS_OracleLinux, VBOXOSTYPE_Oracle4 }, + { ovf::CIMOSType_CIMOS_OracleLinux_64, VBOXOSTYPE_Oracle4_x64 }, + { ovf::CIMOSType_CIMOS_OracleLinux, VBOXOSTYPE_Oracle5 }, + { ovf::CIMOSType_CIMOS_OracleLinux_64, VBOXOSTYPE_Oracle5_x64 }, + { ovf::CIMOSType_CIMOS_OracleLinux, VBOXOSTYPE_Oracle6 }, + { ovf::CIMOSType_CIMOS_OracleLinux_64, VBOXOSTYPE_Oracle6_x64 }, + { ovf::CIMOSType_CIMOS_OracleLinux_64, VBOXOSTYPE_Oracle7_x64 }, // 64-bit only + { ovf::CIMOSType_CIMOS_OracleLinux_64, VBOXOSTYPE_Oracle8_x64 }, // 64-bit only + { ovf::CIMOSType_CIMOS_eComStation, VBOXOSTYPE_ECS }, + + { ovf::CIMOSType_CIMOS_WindowsServer2011, VBOXOSTYPE_Win2k8_x64 }, // no 1:1 match on the VBox side + { ovf::CIMOSType_CIMOS_WindowsServer2012, VBOXOSTYPE_Win2k12_x64 }, + { ovf::CIMOSType_CIMOS_Windows8, VBOXOSTYPE_Win8 }, + { ovf::CIMOSType_CIMOS_Windows8_64, VBOXOSTYPE_Win8_x64 }, + { ovf::CIMOSType_CIMOS_WindowsServer2012R2, VBOXOSTYPE_Win2k12_x64 }, + { ovf::CIMOSType_CIMOS_Windows8_1, VBOXOSTYPE_Win81 }, + { ovf::CIMOSType_CIMOS_Windows8_1_64, VBOXOSTYPE_Win81_x64 }, + { ovf::CIMOSType_CIMOS_WindowsServer2016, VBOXOSTYPE_Win2k16_x64 }, + { ovf::CIMOSType_CIMOS_Windows10, VBOXOSTYPE_Win10 }, + { ovf::CIMOSType_CIMOS_Windows10_64, VBOXOSTYPE_Win10_x64 }, + { ovf::CIMOSType_CIMOS_Windows10_64, VBOXOSTYPE_Win10_x64 }, + { ovf::CIMOSType_CIMOS_WindowsServer2016, VBOXOSTYPE_Win2k19_x64 }, // no CIM type for this yet + + // there are no CIM types for these, so these turn to "other" on export: + // VBOXOSTYPE_OpenBSD + // VBOXOSTYPE_OpenBSD_x64 + // VBOXOSTYPE_NetBSD + // VBOXOSTYPE_NetBSD_x64 + +}; + +/* Pattern structure for matching the OS type description field */ +struct osTypePattern +{ + const char *pcszPattern; + VBOXOSTYPE osType; +}; + +/* These are the 32-Bit ones. They are sorted by priority. */ +static const osTypePattern g_aOsTypesPattern[] = +{ + {"Windows NT", VBOXOSTYPE_WinNT4}, + {"Windows XP", VBOXOSTYPE_WinXP}, + {"Windows 2000", VBOXOSTYPE_Win2k}, + {"Windows 2003", VBOXOSTYPE_Win2k3}, + {"Windows Vista", VBOXOSTYPE_WinVista}, + {"Windows 2008", VBOXOSTYPE_Win2k8}, + {"Windows 7", VBOXOSTYPE_Win7}, + {"Windows 8.1", VBOXOSTYPE_Win81}, + {"Windows 8", VBOXOSTYPE_Win8}, + {"Windows 10", VBOXOSTYPE_Win10}, + {"SUSE", VBOXOSTYPE_OpenSUSE}, + {"Novell", VBOXOSTYPE_OpenSUSE}, + {"Red Hat", VBOXOSTYPE_RedHat}, + {"Mandriva", VBOXOSTYPE_Mandriva}, + {"Ubuntu", VBOXOSTYPE_Ubuntu}, + {"Debian", VBOXOSTYPE_Debian}, + {"QNX", VBOXOSTYPE_QNX}, + {"Linux 2.4", VBOXOSTYPE_Linux24}, + {"Linux 2.6", VBOXOSTYPE_Linux26}, + {"Linux", VBOXOSTYPE_Linux}, + {"OpenSolaris", VBOXOSTYPE_OpenSolaris}, + {"Solaris", VBOXOSTYPE_OpenSolaris}, + {"FreeBSD", VBOXOSTYPE_FreeBSD}, + {"NetBSD", VBOXOSTYPE_NetBSD}, + {"Windows 95", VBOXOSTYPE_Win95}, + {"Windows 98", VBOXOSTYPE_Win98}, + {"Windows Me", VBOXOSTYPE_WinMe}, + {"Windows 3.", VBOXOSTYPE_Win31}, + {"DOS", VBOXOSTYPE_DOS}, + {"OS2", VBOXOSTYPE_OS2} +}; + +/* These are the 64-Bit ones. They are sorted by priority. */ +static const osTypePattern g_aOsTypesPattern64[] = +{ + {"Windows XP", VBOXOSTYPE_WinXP_x64}, + {"Windows 2003", VBOXOSTYPE_Win2k3_x64}, + {"Windows Vista", VBOXOSTYPE_WinVista_x64}, + {"Windows 2008", VBOXOSTYPE_Win2k8_x64}, + {"Windows 7", VBOXOSTYPE_Win7_x64}, + {"Windows 8.1", VBOXOSTYPE_Win81_x64}, + {"Windows 8", VBOXOSTYPE_Win8_x64}, + {"Windows 2012", VBOXOSTYPE_Win2k12_x64}, + {"Windows 10", VBOXOSTYPE_Win10_x64}, + {"Windows 2016", VBOXOSTYPE_Win2k16_x64}, + {"Windows 2019", VBOXOSTYPE_Win2k19_x64}, + {"SUSE", VBOXOSTYPE_OpenSUSE_x64}, + {"Novell", VBOXOSTYPE_OpenSUSE_x64}, + {"Red Hat", VBOXOSTYPE_RedHat_x64}, + {"Mandriva", VBOXOSTYPE_Mandriva_x64}, + {"Ubuntu", VBOXOSTYPE_Ubuntu_x64}, + {"Debian", VBOXOSTYPE_Debian_x64}, + {"Linux 2.4", VBOXOSTYPE_Linux24_x64}, + {"Linux 2.6", VBOXOSTYPE_Linux26_x64}, + {"Linux", VBOXOSTYPE_Linux26_x64}, + {"OpenSolaris", VBOXOSTYPE_OpenSolaris_x64}, + {"Solaris", VBOXOSTYPE_OpenSolaris_x64}, + {"FreeBSD", VBOXOSTYPE_FreeBSD_x64}, +}; + +/** + * Private helper func that suggests a VirtualBox guest OS type + * for the given OVF operating system type. + */ +void convertCIMOSType2VBoxOSType(Utf8Str &strType, ovf::CIMOSType_T c, const Utf8Str &cStr) +{ + /* First check if the type is other/other_64 */ + if (c == ovf::CIMOSType_CIMOS_Other) + { + for (size_t i = 0; i < RT_ELEMENTS(g_aOsTypesPattern); ++i) + if (cStr.contains(g_aOsTypesPattern[i].pcszPattern, Utf8Str::CaseInsensitive)) + { + strType = Global::OSTypeId(g_aOsTypesPattern[i].osType); + return; + } + } + else if (c == ovf::CIMOSType_CIMOS_Other_64) + { + for (size_t i = 0; i < RT_ELEMENTS(g_aOsTypesPattern64); ++i) + if (cStr.contains(g_aOsTypesPattern64[i].pcszPattern, Utf8Str::CaseInsensitive)) + { + strType = Global::OSTypeId(g_aOsTypesPattern64[i].osType); + return; + } + } + + for (size_t i = 0; i < RT_ELEMENTS(g_aOsTypes); ++i) + { + if (c == g_aOsTypes[i].cim) + { + strType = Global::OSTypeId(g_aOsTypes[i].osType); + return; + } + } + + if (c == ovf::CIMOSType_CIMOS_Other_64) + strType = Global::OSTypeId(VBOXOSTYPE_Unknown_x64); + else + strType = Global::OSTypeId(VBOXOSTYPE_Unknown); +} + +/** + * Private helper func that suggests a VirtualBox guest OS type + * for the given OVF operating system type. + * @returns CIM OS type. + * @param pcszVBox Our guest OS type identifier string. + * @param fLongMode Whether long mode is enabled and a 64-bit CIM type is + * preferred even if the VBox guest type isn't 64-bit. + */ +ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVBox, BOOL fLongMode) +{ + for (size_t i = 0; i < RT_ELEMENTS(g_aOsTypes); ++i) + { + if (!RTStrICmp(pcszVBox, Global::OSTypeId(g_aOsTypes[i].osType))) + { + if (fLongMode && !(g_aOsTypes[i].osType & VBOXOSTYPE_x64)) + { + VBOXOSTYPE enmDesiredOsType = (VBOXOSTYPE)((int)g_aOsTypes[i].osType | (int)VBOXOSTYPE_x64); + for (size_t j = i+1; j < RT_ELEMENTS(g_aOsTypes); j++) + if (g_aOsTypes[j].osType == enmDesiredOsType) + return g_aOsTypes[j].cim; + if (i > 0) + { + for (size_t j = i-1; j > 0; j++) + if (g_aOsTypes[j].osType == enmDesiredOsType) + return g_aOsTypes[j].cim; + } + /* Not all OSes have 64-bit versions, so just return the 32-bit variant. */ + } + return g_aOsTypes[i].cim; + } + } + + return fLongMode ? ovf::CIMOSType_CIMOS_Other_64 : ovf::CIMOSType_CIMOS_Other; +} + +Utf8Str convertNetworkAttachmentTypeToString(NetworkAttachmentType_T type) +{ + Utf8Str strType; + switch (type) + { + case NetworkAttachmentType_NAT: strType = "NAT"; break; + case NetworkAttachmentType_Bridged: strType = "Bridged"; break; + case NetworkAttachmentType_Internal: strType = "Internal"; break; + case NetworkAttachmentType_HostOnly: strType = "HostOnly"; break; + case NetworkAttachmentType_HostOnlyNetwork: strType = "HostOnlyNetwork"; break; + case NetworkAttachmentType_Generic: strType = "Generic"; break; + case NetworkAttachmentType_NATNetwork: strType = "NATNetwork"; break; + case NetworkAttachmentType_Null: strType = "Null"; break; + case NetworkAttachmentType_Cloud: strType = "Cloud"; break; +#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK + case NetworkAttachmentType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */ +#endif + } + return strType; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Appliance constructor / destructor +// +// //////////////////////////////////////////////////////////////////////////////// + +DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription) + +HRESULT VirtualSystemDescription::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void VirtualSystemDescription::FinalRelease() +{ + uninit(); + + BaseFinalRelease(); +} + +Appliance::Appliance() + : mVirtualBox(NULL) +{ +} + +Appliance::~Appliance() +{ +} + + +HRESULT Appliance::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void Appliance::FinalRelease() +{ + uninit(); + + BaseFinalRelease(); +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Internal helpers +// +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +// +// IVirtualBox public methods +// +//////////////////////////////////////////////////////////////////////////////// + +// This code is here so we won't have to include the appliance headers in the +// IVirtualBox implementation. + +/** + * Implementation for IVirtualBox::createAppliance. + * + * @param aAppliance IAppliance object created if S_OK is returned. + * @return S_OK or error. + */ +HRESULT VirtualBox::createAppliance(ComPtr<IAppliance> &aAppliance) +{ + ComObjPtr<Appliance> appliance; + HRESULT hrc = appliance.createObject(); + if (SUCCEEDED(hrc)) + { + hrc = appliance->init(this); + if (SUCCEEDED(hrc)) + hrc = appliance.queryInterfaceTo(aAppliance.asOutParam()); + } + return hrc; +} + +/** + * Appliance COM initializer. + * @param aVirtualBox The VirtualBox object. + */ +HRESULT Appliance::init(VirtualBox *aVirtualBox) +{ + HRESULT rc = S_OK; + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + /* Weak reference to a VirtualBox object */ + unconst(mVirtualBox) = aVirtualBox; + + // initialize data + m = new Data; + m->m_pSecretKeyStore = new SecretKeyStore(false /* fRequireNonPageable*/); + AssertReturn(m->m_pSecretKeyStore, E_FAIL); + + rc = i_initBackendNames(); + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + + return rc; +} + +/** + * Appliance COM uninitializer. + */ +void Appliance::uninit() +{ + /* Enclose the state transition Ready->InUninit->NotReady */ + AutoUninitSpan autoUninitSpan(this); + if (autoUninitSpan.uninitDone()) + return; + + if (m->m_pSecretKeyStore) + delete m->m_pSecretKeyStore; + + delete m; + m = NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// IAppliance public methods +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Public method implementation. + */ +HRESULT Appliance::getPath(com::Utf8Str &aPath) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + aPath = m->locInfo.strPath; + + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT Appliance::getDisks(std::vector<com::Utf8Str> &aDisks) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + aDisks.resize(0); + + if (m->pReader) // OVFReader instantiated? + { + aDisks.resize(m->pReader->m_mapDisks.size()); + + ovf::DiskImagesMap::const_iterator it; + size_t i = 0; + for (it = m->pReader->m_mapDisks.begin(); + it != m->pReader->m_mapDisks.end(); + ++it, ++i) + { + // create a string representing this disk + const ovf::DiskImage &d = it->second; + char *psz = NULL; + RTStrAPrintf(&psz, + "%s\t" + "%RI64\t" + "%RI64\t" + "%s\t" + "%s\t" + "%RI64\t" + "%RI64\t" + "%s", + d.strDiskId.c_str(), + d.iCapacity, + d.iPopulatedSize, + d.strFormat.c_str(), + d.strHref.c_str(), + d.iSize, + d.iChunkSize, + d.strCompression.c_str()); + Utf8Str utf(psz); + aDisks[i] = utf; + RTStrFree(psz); + } + } + + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT Appliance::getCertificate(ComPtr<ICertificate> &aCertificateInfo) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + /* Can be NULL at this point, queryInterfaceto handles that. */ + m->ptrCertificateInfo.queryInterfaceTo(aCertificateInfo.asOutParam()); + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT Appliance::getVirtualSystemDescriptions(std::vector<ComPtr<IVirtualSystemDescription> > &aVirtualSystemDescriptions) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + aVirtualSystemDescriptions.resize(m->virtualSystemDescriptions.size()); + std::list< ComObjPtr<VirtualSystemDescription> > vsds(m->virtualSystemDescriptions); + size_t i = 0; + for (std::list< ComObjPtr<VirtualSystemDescription> >::iterator it = vsds.begin(); it != vsds.end(); ++it, ++i) + { + (*it).queryInterfaceTo(aVirtualSystemDescriptions[i].asOutParam()); + } + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT Appliance::getMachines(std::vector<com::Utf8Str> &aMachines) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + aMachines.resize(m->llGuidsMachinesCreated.size()); + size_t i = 0; + for (std::list<Guid>::const_iterator it = m->llGuidsMachinesCreated.begin(); + it != m->llGuidsMachinesCreated.end(); + ++it, ++i) + { + const Guid &uuid = *it; + aMachines[i] = uuid.toUtf16(); + } + return S_OK; +} + +HRESULT Appliance::createVFSExplorer(const com::Utf8Str &aURI, ComPtr<IVFSExplorer> &aExplorer) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + ComObjPtr<VFSExplorer> explorer; + HRESULT rc = S_OK; + try + { + Utf8Str uri(aURI); + /* Check which kind of export the user has requested */ + LocationInfo li; + i_parseURI(aURI, li); + /* Create the explorer object */ + explorer.createObject(); + rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox); + } + catch (HRESULT aRC) + { + rc = aRC; + } + + if (SUCCEEDED(rc)) + /* Return explorer to the caller */ + explorer.queryInterfaceTo(aExplorer.asOutParam()); + + return rc; +} + + +/** + * Public method implementation. + * Add the "aRequested" numbers of new empty objects of VSD into the list + * "virtualSystemDescriptions". + * The parameter "aCreated" keeps the actual number of the added objects. + * In case of exception all added objects are removed from the list. + */ +HRESULT Appliance::createVirtualSystemDescriptions(ULONG aRequested, ULONG *aCreated) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + HRESULT rc = S_OK; + uint32_t lQuantity = aRequested; + uint32_t i=0; + + if (lQuantity < 1) + return setError(E_FAIL, tr("The number of VirtualSystemDescription objects must be at least 1 or more.")); + try + { + for (; i<lQuantity; ++i) + { + ComObjPtr<VirtualSystemDescription> opVSD; + rc = opVSD.createObject(); + if (SUCCEEDED(rc)) + { + rc = opVSD->init(); + if (SUCCEEDED(rc)) + m->virtualSystemDescriptions.push_back(opVSD); + else + break; + } + else + break; + } + + if (i<lQuantity) + LogRel(("Number of created VirtualSystemDescription objects is less than requested" + "(Requested %d, Created %d)",lQuantity, i)); + + *aCreated = i; + } + catch (HRESULT aRC) + { + for (; i>0; --i) + { + if (!m->virtualSystemDescriptions.empty()) + m->virtualSystemDescriptions.pop_back(); + else + break; + } + rc = aRC; + } + + return rc; +} + +/** + * Public method implementation. + */ +HRESULT Appliance::getWarnings(std::vector<com::Utf8Str> &aWarnings) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + aWarnings.resize(m->llWarnings.size()); + + list<Utf8Str>::const_iterator it; + size_t i = 0; + for (it = m->llWarnings.begin(); + it != m->llWarnings.end(); + ++it, ++i) + { + aWarnings[i] = *it; + } + + return S_OK; +} + +HRESULT Appliance::getPasswordIds(std::vector<com::Utf8Str> &aIdentifiers) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + aIdentifiers = m->m_vecPasswordIdentifiers; + return S_OK; +} + +HRESULT Appliance::getMediumIdsForPasswordId(const com::Utf8Str &aPasswordId, std::vector<com::Guid> &aIdentifiers) +{ + HRESULT hrc = S_OK; + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + std::map<com::Utf8Str, GUIDVEC>::const_iterator it = m->m_mapPwIdToMediumIds.find(aPasswordId); + if (it != m->m_mapPwIdToMediumIds.end()) + aIdentifiers = it->second; + else + hrc = setError(E_FAIL, tr("The given password identifier is not associated with any medium")); + + return hrc; +} + +HRESULT Appliance::addPasswords(const std::vector<com::Utf8Str> &aIdentifiers, + const std::vector<com::Utf8Str> &aPasswords) +{ + HRESULT hrc = S_OK; + + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + /* Check that the IDs do not exist already before changing anything. */ + for (unsigned i = 0; i < aIdentifiers.size(); i++) + { + SecretKey *pKey = NULL; + int rc = m->m_pSecretKeyStore->retainSecretKey(aIdentifiers[i], &pKey); + if (rc != VERR_NOT_FOUND) + { + AssertPtr(pKey); + if (pKey) + pKey->release(); + return setError(VBOX_E_OBJECT_IN_USE, tr("A password with the given ID already exists")); + } + } + + for (unsigned i = 0; i < aIdentifiers.size() && SUCCEEDED(hrc); i++) + { + size_t cbKey = aPasswords[i].length() + 1; /* Include terminator */ + const uint8_t *pbKey = (const uint8_t *)aPasswords[i].c_str(); + + int rc = m->m_pSecretKeyStore->addSecretKey(aIdentifiers[i], pbKey, cbKey); + if (RT_SUCCESS(rc)) + m->m_cPwProvided++; + else if (rc == VERR_NO_MEMORY) + hrc = setError(E_OUTOFMEMORY, tr("Failed to allocate enough secure memory for the key")); + else + hrc = setError(E_FAIL, tr("Unknown error happened while adding a password (%Rrc)"), rc); + } + + return hrc; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Appliance private methods +// +//////////////////////////////////////////////////////////////////////////////// + +HRESULT Appliance::i_initBackendNames() +{ + HRESULT hrc = S_OK; + if (!g_fInitializedBackendNames) + { + /* + * Use the system properties to translate file extensions into + * storage backend names. + */ + static struct + { + const char *pszExt; /**< extension */ + char *pszBackendName; + size_t cbBackendName; + } const s_aFormats[] = + { + { "iso", g_szIsoBackend, sizeof(g_szIsoBackend) }, + { "vmdk", g_szVmdkBackend, sizeof(g_szVmdkBackend) }, + { "vhd", g_szVhdBackend, sizeof(g_szVhdBackend) }, + }; + SystemProperties *pSysProps = mVirtualBox->i_getSystemProperties(); + for (unsigned i = 0; i < RT_ELEMENTS(s_aFormats); i++) + { + ComObjPtr<MediumFormat> trgFormat = pSysProps->i_mediumFormatFromExtension(s_aFormats[i].pszExt); + if (trgFormat.isNotNull()) + { + const char *pszName = trgFormat->i_getName().c_str(); + int vrc = RTStrCopy(s_aFormats[i].pszBackendName, s_aFormats[i].cbBackendName, pszName); + AssertRCStmt(vrc, hrc = setError(E_FAIL, "Unexpected storage backend name copy error %Rrc for %s.", vrc, pszName)); + } + else + hrc = setError(E_FAIL, tr("Can't find appropriate medium format for ISO type of a virtual disk.")); + } + + if (SUCCEEDED(hrc)) + g_fInitializedBackendNames = true; + } + + return hrc; +} + +Utf8Str Appliance::i_typeOfVirtualDiskFormatFromURI(Utf8Str uri) const +{ + Assert(g_fInitializedBackendNames); + + unsigned i = RT_ELEMENTS(g_aUriToBackend); + while (i-- > 0) + if (RTStrICmp(g_aUriToBackend[i].pszUri, uri.c_str()) == 0) + return Utf8Str(g_aUriToBackend[i].pszBackend); + return Utf8Str(); +} + +#if 0 /* unused */ +std::set<Utf8Str> Appliance::i_URIFromTypeOfVirtualDiskFormat(Utf8Str type) +{ + Assert(g_fInitializedBackendNames); + + std::set<Utf8Str> UriSet; + unsigned i = RT_ELEMENTS(g_aUriToBackend); + while (i-- > 0) + if (RTStrICmp(g_aUriToBackend[i].pszBackend, type.c_str()) == 0) + UriSet.insert(g_aUriToBackend[i].pszUri); + return UriSet; +} +#endif + +/** + * Returns a medium format object corresponding to the given + * disk image or null if no such format. + * + * @param di Disk Image + * @param mf Medium Format + * + * @return ComObjPtr<MediumFormat> + */ +HRESULT Appliance::i_findMediumFormatFromDiskImage(const ovf::DiskImage &di, ComObjPtr<MediumFormat>& mf) +{ + HRESULT rc = S_OK; + + /* Get the system properties. */ + SystemProperties *pSysProps = mVirtualBox->i_getSystemProperties(); + + /* We need a proper source format description */ + /* Which format to use? */ + Utf8Str strSrcFormat = i_typeOfVirtualDiskFormatFromURI(di.strFormat); + + /* + * fallback, if we can't determine virtual disk format using URI from the attribute ovf:format + * in the corresponding section <Disk> in the OVF file. + */ + if (strSrcFormat.isEmpty()) + { + strSrcFormat = di.strHref; + + /* check either file gzipped or not + * if "yes" then remove last extension, + * i.e. "image.vmdk.gz"->"image.vmdk" + */ + if (di.strCompression == "gzip") + { + if (RTPathHasSuffix(strSrcFormat.c_str())) + { + strSrcFormat.stripSuffix(); + } + else + { + mf.setNull(); + rc = setError(E_FAIL, + tr("Internal inconsistency looking up medium format for the disk image '%s'"), + di.strHref.c_str()); + return rc; + } + } + /* Figure out from extension which format the image of disk has. */ + if (RTPathHasSuffix(strSrcFormat.c_str())) + { + const char *pszExt = RTPathSuffix(strSrcFormat.c_str()); + if (pszExt) + pszExt++; + mf = pSysProps->i_mediumFormatFromExtension(pszExt); + } + else + mf.setNull(); + } + else + mf = pSysProps->i_mediumFormat(strSrcFormat); + + if (mf.isNull()) + rc = setError(E_FAIL, tr("Internal inconsistency looking up medium format for the disk image '%s'"), + di.strHref.c_str()); + + return rc; +} + +/** + * Setup automatic I/O stream digest calculation, adding it to hOurManifest. + * + * @returns Passthru I/O stream, of @a hVfsIos if no digest calc needed. + * @param hVfsIos The stream to wrap. Always consumed. + * @param pszManifestEntry The manifest entry. + * @param fRead Set if read stream, clear if write. + * @throws Nothing. + */ +RTVFSIOSTREAM Appliance::i_manifestSetupDigestCalculationForGivenIoStream(RTVFSIOSTREAM hVfsIos, const char *pszManifestEntry, + bool fRead /*= true */) +{ + int vrc; + Assert(!RTManifestPtIosIsInstanceOf(hVfsIos)); + + if (m->fDigestTypes == 0) + return hVfsIos; + + /* Create the manifest if necessary. */ + if (m->hOurManifest == NIL_RTMANIFEST) + { + vrc = RTManifestCreate(0 /*fFlags*/, &m->hOurManifest); + AssertRCReturnStmt(vrc, RTVfsIoStrmRelease(hVfsIos), NIL_RTVFSIOSTREAM); + } + + /* Setup the stream. */ + RTVFSIOSTREAM hVfsIosPt; + vrc = RTManifestEntryAddPassthruIoStream(m->hOurManifest, hVfsIos, pszManifestEntry, m->fDigestTypes, fRead, &hVfsIosPt); + + RTVfsIoStrmRelease(hVfsIos); /* always consumed! */ + if (RT_SUCCESS(vrc)) + return hVfsIosPt; + + setErrorVrc(vrc, tr("RTManifestEntryAddPassthruIoStream failed with rc=%Rrc"), vrc); + return NIL_RTVFSIOSTREAM; +} + +/** + * Returns true if the appliance is in "idle" state. This should always be the + * case unless an import or export is currently in progress. Similar to machine + * states, this permits the Appliance implementation code to let go of the + * Appliance object lock while a time-consuming disk conversion is in progress + * without exposing the appliance to conflicting calls. + * + * This sets an error on "this" (the appliance) and returns false if the appliance + * is busy. The caller should then return E_ACCESSDENIED. + * + * Must be called from under the object lock! + */ +bool Appliance::i_isApplianceIdle() +{ + if (m->state == ApplianceImporting) + setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy importing files")); + else if (m->state == ApplianceExporting) + setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy exporting files")); + else + return true; + + return false; +} + +HRESULT Appliance::i_searchUniqueVMName(Utf8Str &aName) const +{ + ComPtr<IMachine> ptrMachine; + char *tmpName = RTStrDup(aName.c_str()); + int i = 1; + while (mVirtualBox->FindMachine(Bstr(tmpName).raw(), ptrMachine.asOutParam()) != VBOX_E_OBJECT_NOT_FOUND) + { + RTStrFree(tmpName); + RTStrAPrintf(&tmpName, "%s %d", aName.c_str(), i); + ++i; + } + aName = tmpName; + RTStrFree(tmpName); + + return S_OK; +} + +HRESULT Appliance::i_ensureUniqueImageFilePath(const Utf8Str &aMachineFolder, DeviceType_T aDeviceType, Utf8Str &aName) const +{ + /* + * Check if the file exists or if a medium with this path is registered already + */ + Utf8Str strAbsName; + size_t offDashNum = ~(size_t)0; + size_t cchDashNum = 0; + for (unsigned i = 1;; i++) + { + /* Complete the path (could be relative to machine folder). */ + int rc = RTPathAbsExCxx(strAbsName, aMachineFolder, aName); + AssertRCReturn(rc, Global::vboxStatusCodeToCOM(rc)); /** @todo stupid caller ignores this */ + + /* Check that the file does not exist and that there is no media somehow matching the name. */ + if (!RTPathExists(strAbsName.c_str())) + { + ComPtr<IMedium> ptrMedium; + HRESULT hrc = mVirtualBox->OpenMedium(Bstr(strAbsName).raw(), aDeviceType, AccessMode_ReadWrite, + FALSE /* fForceNewUuid */, ptrMedium.asOutParam()); + if (hrc == VBOX_E_OBJECT_NOT_FOUND) + return S_OK; + } + + /* Insert '_%i' before the suffix and try again. */ + if (offDashNum == ~(size_t)0) + { + const char *pszSuffix = RTPathSuffix(aName.c_str()); + offDashNum = pszSuffix ? (size_t)(pszSuffix - aName.c_str()) : aName.length(); + } + char szTmp[32]; + size_t cchTmp = RTStrPrintf(szTmp, sizeof(szTmp), "_%u", i); + aName.replace(offDashNum, cchDashNum, szTmp, cchTmp); + cchDashNum = cchTmp; + } +} + +/** + * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a + * progress object with the proper weights and maximum progress values. + */ +HRESULT Appliance::i_setUpProgress(ComObjPtr<Progress> &pProgress, + const Utf8Str &strDescription, + SetUpProgressMode mode) +{ + HRESULT rc; + + /* Create the progress object */ + try + { + rc = pProgress.createObject(); + if (FAILED(rc)) + return rc; + } + catch (std::bad_alloc &) + { + return E_OUTOFMEMORY; + } + + // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data) + i_disksWeight(); + + m->ulWeightForManifestOperation = 0; + + ULONG cOperations = 1 // one for XML setup + + m->cDisks; // plus one per disk + ULONG ulTotalOperationsWeight; + if (m->ulTotalDisksMB) + { + m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML + ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation; + } + else + { + // no disks to export: + m->ulWeightForXmlOperation = 1; + ulTotalOperationsWeight = 1; + } + + switch (mode) + { + case ImportFile: + { + break; + } + case WriteFile: + { + // assume that creating the manifest will take .1% of the time it takes to export the disks + if (m->fManifest) + { + ++cOperations; // another one for creating the manifest + + m->ulWeightForManifestOperation = (ULONG)((double)m->ulTotalDisksMB * .1 / 100); // use .5% of the + // progress for the manifest + ulTotalOperationsWeight += m->ulWeightForManifestOperation; + } + break; + } + case ImportS3: + { + cOperations += 1 + 1; // another one for the manifest file & another one for the import + ulTotalOperationsWeight = m->ulTotalDisksMB; + if (!m->ulTotalDisksMB) + // no disks to export: + ulTotalOperationsWeight = 1; + + ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import + ulTotalOperationsWeight += ulImportWeight; + + m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */ + + ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init + ulTotalOperationsWeight += ulInitWeight; + break; + } + case WriteS3: + { + cOperations += 1 + 1; // another one for the mf & another one for temporary creation + + if (m->ulTotalDisksMB) + { + 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) + ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation; + } + else + { + // no disks to export: + ulTotalOperationsWeight = 1; + m->ulWeightForXmlOperation = 1; + } + ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the + creation of the OVF + & the disks */ + ulTotalOperationsWeight += ulOVFCreationWeight; + break; + } + case ExportCloud: + case ImportCloud: + break; + } + Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n", + m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation)); + + return pProgress->init(mVirtualBox, static_cast<IAppliance*>(this), + strDescription, + TRUE /* aCancelable */, + cOperations, // ULONG cOperations, + ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight, + strDescription, // CBSTR bstrFirstOperationDescription, + m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight, +} + +void Appliance::i_addWarning(const char* aWarning, ...) +{ + try + { + va_list args; + va_start(args, aWarning); + Utf8Str str(aWarning, args); + va_end(args); + m->llWarnings.push_back(str); + } + catch (...) + { + AssertFailed(); + } +} + +/** + * Refreshes the cDisks and ulTotalDisksMB members in the instance data. + * Requires that virtual system descriptions are present. + */ +void Appliance::i_disksWeight() +{ + m->ulTotalDisksMB = 0; + m->cDisks = 0; + // weigh the disk images according to their sizes + list< ComObjPtr<VirtualSystemDescription> >::const_iterator it; + for (it = m->virtualSystemDescriptions.begin(); + it != m->virtualSystemDescriptions.end(); + ++it) + { + ComObjPtr<VirtualSystemDescription> vsdescThis = (*it); + /* One for every medium of the Virtual System */ + std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->i_findByType(VirtualSystemDescriptionType_HardDiskImage); + std::list<VirtualSystemDescriptionEntry*>::const_iterator itH; + for (itH = avsdeHDs.begin(); + itH != avsdeHDs.end(); + ++itH) + { + const VirtualSystemDescriptionEntry *pHD = *itH; + m->ulTotalDisksMB += pHD->ulSizeMB; + ++m->cDisks; + } + + avsdeHDs = vsdescThis->i_findByType(VirtualSystemDescriptionType_CDROM); + for (itH = avsdeHDs.begin(); + itH != avsdeHDs.end(); + ++itH) + { + const VirtualSystemDescriptionEntry *pHD = *itH; + m->ulTotalDisksMB += pHD->ulSizeMB; + ++m->cDisks; + } + } + +} + +void Appliance::i_parseBucket(Utf8Str &aPath, Utf8Str &aBucket) +{ + /* Buckets are S3 specific. So parse the bucket out of the file path */ + if (!aPath.startsWith("/")) + throw setError(E_INVALIDARG, + tr("The path '%s' must start with /"), aPath.c_str()); + size_t bpos = aPath.find("/", 1); + if (bpos != Utf8Str::npos) + { + aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */ + aPath = aPath.substr(bpos); /* The rest of the file path */ + } + /* If there is no bucket name provided reject it */ + if (aBucket.isEmpty()) + throw setError(E_INVALIDARG, + tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str()); +} + +/** + * Worker for TaskOVF::handler. + * + * The TaskOVF is started in Appliance::readImpl() and Appliance::importImpl() + * and Appliance::writeImpl(). + * + * This will in turn call Appliance::readFS() or Appliance::importFS() or + * Appliance::writeFS(). + * + * @thread pTask The task. + */ +/* static */ void Appliance::i_importOrExportThreadTask(TaskOVF *pTask) +{ + LogFlowFuncEnter(); + AssertReturnVoid(pTask); + + Appliance *pAppliance = pTask->pAppliance; + LogFlowFunc(("Appliance %p taskType=%d\n", pAppliance, pTask->taskType)); + + switch (pTask->taskType) + { + case TaskOVF::Read: + pAppliance->m->resetReadData(); + if (pTask->locInfo.storageType == VFSType_File) + pTask->rc = pAppliance->i_readFS(pTask); + else + pTask->rc = E_NOTIMPL; + break; + + case TaskOVF::Import: + /** @todo allow overriding these? */ + if (!pAppliance->m->fSignatureValid && pAppliance->m->pbSignedDigest) + pTask->rc = pAppliance->setError(E_FAIL, tr("The manifest signature for '%s' is not valid"), + pTask->locInfo.strPath.c_str()); + else if (!pAppliance->m->fCertificateValid && pAppliance->m->pbSignedDigest) + { + if (pAppliance->m->strCertError.isNotEmpty()) + pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is not valid: %s"), + pTask->locInfo.strPath.c_str(), pAppliance->m->strCertError.c_str()); + else + pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is not valid"), + pTask->locInfo.strPath.c_str()); + } + // fusion does not consider this a show stopper (we've filed a warning during read). + //else if (pAppliance->m->fCertificateMissingPath && pAppliance->m->pbSignedDigest) + // pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is does not have a valid CA path"), + // pTask->locInfo.strPath.c_str()); + else + { + if (pTask->locInfo.storageType == VFSType_File) + pTask->rc = pAppliance->i_importFS(pTask); + else + pTask->rc = E_NOTIMPL; + } + break; + + case TaskOVF::Write: + if (pTask->locInfo.storageType == VFSType_File) + pTask->rc = pAppliance->i_writeFS(pTask); + else + pTask->rc = E_NOTIMPL; + break; + + default: + AssertFailed(); + pTask->rc = E_FAIL; + break; + } + + if (!pTask->pProgress.isNull()) + pTask->pProgress->i_notifyComplete(pTask->rc); + + LogFlowFuncLeave(); +} + +/* static */ DECLCALLBACK(int) Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser) +{ + Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser; + + if ( pTask + && !pTask->pProgress.isNull()) + { + BOOL fCanceled; + pTask->pProgress->COMGETTER(Canceled)(&fCanceled); + if (fCanceled) + return -1; + pTask->pProgress->SetCurrentOperationProgress(uPercent); + } + return VINF_SUCCESS; +} + +/** + * Worker for TaskOPC::handler. + * @thread pTask The task. + */ +/* static */ +void Appliance::i_exportOPCThreadTask(TaskOPC *pTask) +{ + LogFlowFuncEnter(); + AssertReturnVoid(pTask); + + Appliance *pAppliance = pTask->pAppliance; + LogFlowFunc(("Appliance %p taskType=%d\n", pAppliance, pTask->taskType)); + + switch (pTask->taskType) + { + case TaskOPC::Export: + pTask->rc = pAppliance->i_writeFSOPC(pTask); + break; + + default: + AssertFailed(); + pTask->rc = E_FAIL; + break; + } + + if (!pTask->pProgress.isNull()) + pTask->pProgress->i_notifyComplete(pTask->rc); + + LogFlowFuncLeave(); +} + +/* static */ +DECLCALLBACK(int) Appliance::TaskOPC::updateProgress(unsigned uPercent, void *pvUser) +{ + Appliance::TaskOPC* pTask = *(Appliance::TaskOPC**)pvUser; + + if ( pTask + && !pTask->pProgress.isNull()) + { + BOOL fCanceled; + pTask->pProgress->COMGETTER(Canceled)(&fCanceled); + if (fCanceled) + return -1; + pTask->pProgress->SetCurrentOperationProgress(uPercent); + } + return VINF_SUCCESS; +} + +/** + * Worker for TaskCloud::handler. + * @thread pTask The task. + */ +/* static */ +void Appliance::i_importOrExportCloudThreadTask(TaskCloud *pTask) +{ + LogFlowFuncEnter(); + AssertReturnVoid(pTask); + + Appliance *pAppliance = pTask->pAppliance; + LogFlowFunc(("Appliance %p taskType=%d\n", pAppliance, pTask->taskType)); + + switch (pTask->taskType) + { + case TaskCloud::Export: + pAppliance->i_setApplianceState(ApplianceExporting); + pTask->rc = pAppliance->i_exportCloudImpl(pTask); + break; + case TaskCloud::Import: + pAppliance->i_setApplianceState(ApplianceImporting); + pTask->rc = pAppliance->i_importCloudImpl(pTask); + break; + case TaskCloud::ReadData: + pAppliance->i_setApplianceState(ApplianceImporting); + pTask->rc = pAppliance->i_gettingCloudData(pTask); + break; + default: + AssertFailed(); + pTask->rc = E_FAIL; + break; + } + + pAppliance->i_setApplianceState(ApplianceIdle); + + if (!pTask->pProgress.isNull()) + pTask->pProgress->i_notifyComplete(pTask->rc); + + LogFlowFuncLeave(); +} + +/* static */ +DECLCALLBACK(int) Appliance::TaskCloud::updateProgress(unsigned uPercent, void *pvUser) +{ + Appliance::TaskCloud* pTask = *(Appliance::TaskCloud**)pvUser; + + if ( pTask + && !pTask->pProgress.isNull()) + { + BOOL fCanceled; + pTask->pProgress->COMGETTER(Canceled)(&fCanceled); + if (fCanceled) + return -1; + pTask->pProgress->SetCurrentOperationProgress(uPercent); + } + return VINF_SUCCESS; +} + +void i_parseURI(Utf8Str strUri, LocationInfo &locInfo) +{ + /* Check the URI for the protocol */ + if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */ + { + locInfo.storageType = VFSType_File; + strUri = strUri.substr(sizeof("file://") - 1); + } + else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */ + { + locInfo.storageType = VFSType_S3; + strUri = strUri.substr(sizeof("SunCloud://") - 1); + } + else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */ + { + locInfo.storageType = VFSType_S3; + strUri = strUri.substr(sizeof("S3://") - 1); + } + else if (strUri.startsWith("OCI://", Utf8Str::CaseInsensitive)) /* OCI service (storage or compute) */ + { + locInfo.storageType = VFSType_Cloud; + locInfo.strProvider = "OCI"; + strUri = strUri.substr(sizeof("OCI://") - 1); + } + else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */ + throw E_NOTIMPL; + + /* Not necessary on a file based URI */ +// if (locInfo.storageType != VFSType_File) +// { +// size_t uppos = strUri.find("@"); /* username:password combo */ +// if (uppos != Utf8Str::npos) +// { +// locInfo.strUsername = strUri.substr(0, uppos); +// strUri = strUri.substr(uppos + 1); +// size_t upos = locInfo.strUsername.find(":"); +// if (upos != Utf8Str::npos) +// { +// locInfo.strPassword = locInfo.strUsername.substr(upos + 1); +// locInfo.strUsername = locInfo.strUsername.substr(0, upos); +// } +// } +// size_t hpos = strUri.find("/"); /* hostname part */ +// if (hpos != Utf8Str::npos) +// { +// locInfo.strHostname = strUri.substr(0, hpos); +// strUri = strUri.substr(hpos); +// } +// } + + locInfo.strPath = strUri; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// IVirtualSystemDescription constructor / destructor +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * COM initializer. + * @return + */ +HRESULT VirtualSystemDescription::init() +{ + /* Enclose the state transition NotReady->InInit->Ready */ + AutoInitSpan autoInitSpan(this); + AssertReturn(autoInitSpan.isOk(), E_FAIL); + + /* Initialize data */ + m = new Data(); + m->pConfig = NULL; + + /* Confirm a successful initialization */ + autoInitSpan.setSucceeded(); + return S_OK; +} + +/** +* COM uninitializer. +*/ + +void VirtualSystemDescription::uninit() +{ + if (m->pConfig) + delete m->pConfig; + delete m; + m = NULL; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// IVirtualSystemDescription public methods +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Public method implementation. + */ +HRESULT VirtualSystemDescription::getCount(ULONG *aCount) +{ + if (!aCount) + return E_POINTER; + + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + *aCount = (ULONG)m->maDescriptions.size(); + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT VirtualSystemDescription::getDescription(std::vector<VirtualSystemDescriptionType_T> &aTypes, + std::vector<com::Utf8Str> &aRefs, + std::vector<com::Utf8Str> &aOVFValues, + std::vector<com::Utf8Str> &aVBoxValues, + std::vector<com::Utf8Str> &aExtraConfigValues) + +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + size_t c = m->maDescriptions.size(); + aTypes.resize(c); + aRefs.resize(c); + aOVFValues.resize(c); + aVBoxValues.resize(c); + aExtraConfigValues.resize(c); + + for (size_t i = 0; i < c; i++) + { + const VirtualSystemDescriptionEntry &vsde = m->maDescriptions[i]; + aTypes[i] = vsde.type; + aRefs[i] = vsde.strRef; + aOVFValues[i] = vsde.strOvf; + aVBoxValues[i] = vsde.strVBoxCurrent; + aExtraConfigValues[i] = vsde.strExtraConfigCurrent; + } + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT VirtualSystemDescription::getDescriptionByType(VirtualSystemDescriptionType_T aType, + std::vector<VirtualSystemDescriptionType_T> &aTypes, + std::vector<com::Utf8Str> &aRefs, + std::vector<com::Utf8Str> &aOVFValues, + std::vector<com::Utf8Str> &aVBoxValues, + std::vector<com::Utf8Str> &aExtraConfigValues) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType(aType); + + size_t c = vsd.size(); + aTypes.resize(c); + aRefs.resize(c); + aOVFValues.resize(c); + aVBoxValues.resize(c); + aExtraConfigValues.resize(c); + + size_t i = 0; + for (list<VirtualSystemDescriptionEntry*>::const_iterator it = vsd.begin(); it != vsd.end(); ++it, ++i) + { + const VirtualSystemDescriptionEntry *vsde = (*it); + aTypes[i] = vsde->type; + aRefs[i] = vsde->strRef; + aOVFValues[i] = vsde->strOvf; + aVBoxValues[i] = vsde->strVBoxCurrent; + aExtraConfigValues[i] = vsde->strExtraConfigCurrent; + } + + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT VirtualSystemDescription::getValuesByType(VirtualSystemDescriptionType_T aType, + VirtualSystemDescriptionValueType_T aWhich, + std::vector<com::Utf8Str> &aValues) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + + std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType (aType); + aValues.resize((ULONG)vsd.size()); + + list<VirtualSystemDescriptionEntry*>::const_iterator it; + size_t i = 0; + for (it = vsd.begin(); + it != vsd.end(); + ++it, ++i) + { + const VirtualSystemDescriptionEntry *vsde = (*it); + + Bstr bstr; + switch (aWhich) + { + case VirtualSystemDescriptionValueType_Reference: aValues[i] = vsde->strRef; break; + case VirtualSystemDescriptionValueType_Original: aValues[i] = vsde->strOvf; break; + case VirtualSystemDescriptionValueType_Auto: aValues[i] = vsde->strVBoxCurrent; break; + case VirtualSystemDescriptionValueType_ExtraConfig: aValues[i] = vsde->strExtraConfigCurrent; break; +#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK + case VirtualSystemDescriptionValueType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */ +#endif + } + } + + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT VirtualSystemDescription::setFinalValues(const std::vector<BOOL> &aEnabled, + const std::vector<com::Utf8Str> &aVBoxValues, + const std::vector<com::Utf8Str> &aExtraConfigValues) +{ +#ifndef RT_OS_WINDOWS + // NOREF(aEnabledSize); +#endif /* RT_OS_WINDOWS */ + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + + if ( (aEnabled.size() != m->maDescriptions.size()) + || (aVBoxValues.size() != m->maDescriptions.size()) + || (aExtraConfigValues.size() != m->maDescriptions.size()) + ) + return E_INVALIDARG; + + size_t i = 0; + for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin(); + it != m->maDescriptions.end(); + ++it, ++i) + { + VirtualSystemDescriptionEntry& vsde = *it; + + if (aEnabled[i]) + { + vsde.strVBoxCurrent = aVBoxValues[i]; + vsde.strExtraConfigCurrent = aExtraConfigValues[i]; + } + else + vsde.type = VirtualSystemDescriptionType_Ignore; + } + + return S_OK; +} + +/** + * Public method implementation. + */ +HRESULT VirtualSystemDescription::addDescription(VirtualSystemDescriptionType_T aType, + const com::Utf8Str &aVBoxValue, + const com::Utf8Str &aExtraConfigValue) + +{ + AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); + i_addEntry(aType, "", aVBoxValue, aVBoxValue, 0, aExtraConfigValue); + return S_OK; +} + +/** + * Internal method; adds a new description item to the member list. + * @param aType Type of description for the new item. + * @param strRef Reference item; only used with storage controllers. + * @param aOvfValue Corresponding original value from OVF. + * @param aVBoxValue Initial configuration value (can be overridden by caller with setFinalValues). + * @param ulSizeMB Weight for IProgress + * @param strExtraConfig Extra configuration; meaning dependent on type. + */ +void VirtualSystemDescription::i_addEntry(VirtualSystemDescriptionType_T aType, + const Utf8Str &strRef, + const Utf8Str &aOvfValue, + const Utf8Str &aVBoxValue, + uint32_t ulSizeMB, + const Utf8Str &strExtraConfig /*= ""*/) +{ + VirtualSystemDescriptionEntry vsde; + vsde.ulIndex = (uint32_t)m->maDescriptions.size(); // each entry gets an index so the client side can reference them + vsde.type = aType; + vsde.strRef = strRef; + vsde.strOvf = aOvfValue; + vsde.strVBoxSuggested /* remember original value */ + = vsde.strVBoxCurrent /* and set current value which can be overridden by setFinalValues() */ + = aVBoxValue; + vsde.strExtraConfigSuggested + = vsde.strExtraConfigCurrent + = strExtraConfig; + vsde.ulSizeMB = ulSizeMB; + + vsde.skipIt = false; + + m->maDescriptions.push_back(vsde); +} + +/** + * Private method; returns a list of description items containing all the items from the member + * description items of this virtual system that match the given type. + */ +std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::i_findByType(VirtualSystemDescriptionType_T aType) +{ + std::list<VirtualSystemDescriptionEntry*> vsd; + for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin(); + it != m->maDescriptions.end(); + ++it) + { + if (it->type == aType) + vsd.push_back(&(*it)); + } + + return vsd; +} + +HRESULT VirtualSystemDescription::removeDescriptionByType(VirtualSystemDescriptionType_T aType) +{ + std::vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin(); + while (it != m->maDescriptions.end()) + { + if (it->type == aType) + it = m->maDescriptions.erase(it); + else + ++it; + } + + return S_OK; +} + +/* Private method; delete all records from the list + * m->llDescriptions that match the given type. + */ +void VirtualSystemDescription::i_removeByType(VirtualSystemDescriptionType_T aType) +{ + std::vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin(); + while (it != m->maDescriptions.end()) + { + if (it->type == aType) + it = m->maDescriptions.erase(it); + else + ++it; + } +} + +/** + * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with + * the given reference ID. Useful when needing the controller for a particular + * virtual disk. + */ +const VirtualSystemDescriptionEntry* VirtualSystemDescription::i_findControllerFromID(const Utf8Str &id) +{ + vector<VirtualSystemDescriptionEntry>::const_iterator it; + for (it = m->maDescriptions.begin(); + it != m->maDescriptions.end(); + ++it) + { + const VirtualSystemDescriptionEntry &d = *it; + switch (d.type) + { + case VirtualSystemDescriptionType_HardDiskControllerIDE: + case VirtualSystemDescriptionType_HardDiskControllerSATA: + case VirtualSystemDescriptionType_HardDiskControllerSCSI: + case VirtualSystemDescriptionType_HardDiskControllerVirtioSCSI: + case VirtualSystemDescriptionType_HardDiskControllerSAS: + if (d.strRef == id) + return &d; + break; + default: break; /* Shut up MSC. */ + } + } + + return NULL; +} + +/** + * Method called from Appliance::Interpret() if the source OVF for a virtual system + * contains a <vbox:Machine> element. This method then attempts to parse that and + * create a MachineConfigFile instance from it which is stored in this instance data + * and can then be used to create a machine. + * + * This must only be called once per instance. + * + * This rethrows all XML and logic errors from MachineConfigFile. + * + * @param elmMachine <vbox:Machine> element with attributes and subelements from some + * DOM tree. + */ +void VirtualSystemDescription::i_importVBoxMachineXML(const xml::ElementNode &elmMachine) +{ + settings::MachineConfigFile *pConfig = NULL; + + Assert(m->pConfig == NULL); + + try + { + pConfig = new settings::MachineConfigFile(NULL); + pConfig->importMachineXML(elmMachine); + + m->pConfig = pConfig; + } + catch (...) + { + if (pConfig) + delete pConfig; + throw; + } +} + +/** + * Returns the machine config created by importVBoxMachineXML() or NULL if there's none. + */ +const settings::MachineConfigFile* VirtualSystemDescription::i_getMachineConfig() const +{ + return m->pConfig; +} + +/** + * Private method; walks through the array of VirtualSystemDescriptionEntry entries + * and returns the one matching the given index. + */ +const VirtualSystemDescriptionEntry* VirtualSystemDescription::i_findByIndex(const uint32_t aIndex) +{ + vector<VirtualSystemDescriptionEntry>::const_iterator it; + for (it = m->maDescriptions.begin(); + it != m->maDescriptions.end(); + ++it) + { + const VirtualSystemDescriptionEntry &d = *it; + if (d.ulIndex == aIndex) + return &d; + } + + return NULL; +} + |