diff options
| author | Felix Geyer <debfx-pkg@fobos.de> | 2011-01-02 10:58:34 +0100 |
|---|---|---|
| committer | Felix Geyer <debfx-pkg@fobos.de> | 2011-01-02 10:58:34 +0100 |
| commit | 361589e3ae692db27161410309b92c6b89e1ec6c (patch) | |
| tree | f58702fae95e097c1a03bd37c1df44963a5b316f /src/VBox/Main/xml | |
| parent | d4835ef8bf2b0196ae1887c04e3d57cce840904c (diff) | |
| download | virtualbox-361589e3ae692db27161410309b92c6b89e1ec6c.tar.gz | |
Imported Upstream version 4.0.0-dfsgupstream/4.0.0-dfsg
Diffstat (limited to 'src/VBox/Main/xml')
| -rw-r--r-- | src/VBox/Main/xml/Settings.cpp | 1698 | ||||
| -rw-r--r-- | src/VBox/Main/xml/VirtualBox-settings-common.xsd | 13 | ||||
| -rw-r--r-- | src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd | 2 | ||||
| -rw-r--r-- | src/VBox/Main/xml/VirtualBox-settings-linux.xsd | 2 | ||||
| -rw-r--r-- | src/VBox/Main/xml/VirtualBox-settings-macosx.xsd | 2 | ||||
| -rw-r--r-- | src/VBox/Main/xml/VirtualBox-settings-os2.xsd | 2 | ||||
| -rw-r--r-- | src/VBox/Main/xml/VirtualBox-settings-solaris.xsd | 2 | ||||
| -rw-r--r-- | src/VBox/Main/xml/VirtualBox-settings-windows.xsd | 2 | ||||
| -rw-r--r-- | src/VBox/Main/xml/ovfreader.cpp | 32 |
9 files changed, 1143 insertions, 612 deletions
diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp index 817fee7d2..697048ef8 100644 --- a/src/VBox/Main/xml/Settings.cpp +++ b/src/VBox/Main/xml/Settings.cpp @@ -1,4 +1,4 @@ -/* $Id: Settings.cpp $ */ +/* $Id: Settings.cpp 35151 2010-12-15 16:42:08Z vboxsync $ */ /** @file * Settings File Manipulation API. * @@ -8,37 +8,46 @@ * * The code can read all VirtualBox settings files version 1.3 and higher. That version was * written by VirtualBox 2.0. It can write settings version 1.7 (used by VirtualBox 2.2 and - * 3.0) and 1.9 (used by VirtualBox 3.1). + * 3.0) and 1.9 (used by VirtualBox 3.1) and newer ones obviously. * - * Rules for introducing new settings: If an element or attribute is introduced that was not - * present before VirtualBox 3.1, then settings version checks need to be introduced. The - * settings version for VirtualBox 3.1 is 1.9; see the SettingsVersion enumeration in - * src/VBox/Main/idl/VirtualBox.xidl for details about which version was used when. + * The settings versions enum is defined in src/VBox/Main/idl/VirtualBox.xidl. To introduce + * a new settings version (should be necessary at most once per VirtualBox major release, + * if at all), add a new SettingsVersion value to that enum and grep for the previously + * highest value to see which code in here needs adjusting. * - * The settings versions checks are necessary because VirtualBox 3.1 no longer automatically - * converts XML settings files but only if necessary, that is, if settings are present that - * the old format does not support. If we write an element or attribute to a settings file - * of an older version, then an old VirtualBox (before 3.1) will attempt to validate it - * with XML schema, and that will certainly fail. + * Certainly ConfigFileBase::ConfigFileBase() will. Change VBOX_XML_VERSION below as well. + * + * Once a new settings version has been added, these are the rules for introducing a new + * setting: If an XML element or attribute or value is introduced that was not present in + * previous versions, then settings version checks need to be introduced. See the + * SettingsVersion enumeration in src/VBox/Main/idl/VirtualBox.xidl for details about which + * version was used when. + * + * The settings versions checks are necessary because since version 3.1, VirtualBox no longer + * automatically converts XML settings files but only if necessary, that is, if settings are + * present that the old format does not support. If we write an element or attribute to a + * settings file of an older version, then an old VirtualBox (before 3.1) will attempt to + * validate it with XML schema, and that will certainly fail. * * So, to introduce a new setting: * * 1) Make sure the constructor of corresponding settings structure has a proper default. * * 2) In the settings reader method, try to read the setting; if it's there, great, if not, - * the default value will have been set by the constructor. + * the default value will have been set by the constructor. The rule is to be tolerant + * here. * - * 3) In the settings writer method, write the setting _only_ if the current settings - * version (stored in m->sv) is high enough. That is, for VirtualBox 3.2, write it - * only if (m->sv >= SettingsVersion_v1_10). - * - * 4) In MachineConfigFile::bumpSettingsVersionIfNeeded(), check if the new setting has + * 3) In MachineConfigFile::bumpSettingsVersionIfNeeded(), check if the new setting has * a non-default value (i.e. that differs from the constructor). If so, bump the - * settings version to the current version so the settings writer (3) can write out + * settings version to the current version so the settings writer (4) can write out * the non-default value properly. * * So far a corresponding method for MainConfigFile has not been necessary since there * have been no incompatible changes yet. + * + * 4) In the settings writer method, write the setting _only_ if the current settings + * version (stored in m->sv) is high enough. That is, for VirtualBox 4.0, write it + * only if (m->sv >= SettingsVersion_v1_11). */ /* @@ -81,7 +90,7 @@ using namespace settings; #define VBOX_XML_NAMESPACE "http://www.innotek.de/VirtualBox-settings" /** VirtualBox XML settings version number substring ("x.y") */ -#define VBOX_XML_VERSION "1.10" +#define VBOX_XML_VERSION "1.11" /** VirtualBox XML settings version platform substring */ #if defined (RT_OS_DARWIN) @@ -179,7 +188,7 @@ public: { va_list args; va_start(args, pcszFormat); - Utf8StrFmtVA strWhat(pcszFormat, args); + Utf8Str strWhat(pcszFormat, args); va_end(args); Utf8Str strLine; @@ -198,12 +207,38 @@ public: //////////////////////////////////////////////////////////////////////////////// // +// MediaRegistry +// +//////////////////////////////////////////////////////////////////////////////// + +bool Medium::operator==(const Medium &m) const +{ + return (uuid == m.uuid) + && (strLocation == m.strLocation) + && (strDescription == m.strDescription) + && (strFormat == m.strFormat) + && (fAutoReset == m.fAutoReset) + && (properties == m.properties) + && (hdType == m.hdType) + && (llChildren== m.llChildren); // this is deep and recurses +} + +bool MediaRegistry::operator==(const MediaRegistry &m) const +{ + return llHardDisks == m.llHardDisks + && llDvdImages == m.llDvdImages + && llFloppyImages == m.llFloppyImages; +} + +//////////////////////////////////////////////////////////////////////////////// +// // ConfigFileBase // //////////////////////////////////////////////////////////////////////////////// /** - * Constructor. Allocates the XML internals. + * Constructor. Allocates the XML internals, parses the XML file if + * pstrFilename is != NULL and reads the settings version from it. * @param strFilename */ ConfigFileBase::ConfigFileBase(const com::Utf8Str *pstrFilename) @@ -282,7 +317,9 @@ ConfigFileBase::ConfigFileBase(const com::Utf8Str *pstrFilename) m->sv = SettingsVersion_v1_9; else if (ulMinor == 10) m->sv = SettingsVersion_v1_10; - else if (ulMinor > 10) + else if (ulMinor == 11) + m->sv = SettingsVersion_v1_11; + else if (ulMinor > 11) m->sv = SettingsVersion_Future; } else if (ulMajor > 1) @@ -302,7 +339,7 @@ ConfigFileBase::ConfigFileBase(const com::Utf8Str *pstrFilename) { // creating new settings file: m->strSettingsVersionFull = VBOX_XML_VERSION_FULL; - m->sv = SettingsVersion_v1_10; + m->sv = SettingsVersion_v1_11; } } @@ -320,25 +357,15 @@ ConfigFileBase::~ConfigFileBase() /** * Helper function that parses a UUID in string form into - * a com::Guid item. Since that uses an IPRT function which - * does not accept "{}" characters around the UUID string, - * we handle that here. Throws on errors. + * a com::Guid item. Accepts UUIDs both with and without + * "{}" brackets. Throws on errors. * @param guid * @param strUUID */ void ConfigFileBase::parseUUID(Guid &guid, const Utf8Str &strUUID) const { - // {5f102a55-a51b-48e3-b45a-b28d33469488} - // 01234567890123456789012345678901234567 - // 1 2 3 - if ( (strUUID[0] == '{') - && (strUUID[37] == '}') - ) - guid = strUUID.substr(1, 36).c_str(); - else - guid = strUUID.c_str(); - + guid = strUUID.c_str(); if (guid.isEmpty()) throw ConfigFileError(this, NULL, N_("UUID \"%s\" has invalid format"), strUUID.c_str()); } @@ -439,7 +466,7 @@ com::Utf8Str ConfigFileBase::makeString(const RTTIMESPEC &stamp) * @param map */ void ConfigFileBase::readExtraData(const xml::ElementNode &elmExtraData, - ExtraDataItemsMap &map) + StringsMap &map) { xml::NodesLoop nlLevel4(elmExtraData); const xml::ElementNode *pelmExtraDataItem; @@ -513,6 +540,256 @@ void ConfigFileBase::readUSBDeviceFilters(const xml::ElementNode &elmDeviceFilte } /** + * Reads a media registry entry from the main VirtualBox.xml file. + * + * Whereas the current media registry code is fairly straightforward, it was quite a mess + * with settings format before 1.4 (VirtualBox 2.0 used settings format 1.3). The elements + * in the media registry were much more inconsistent, and different elements were used + * depending on the type of device and image. + * + * @param t + * @param elmMedium + * @param llMedia + */ +void ConfigFileBase::readMedium(MediaType t, + const xml::ElementNode &elmMedium, // HardDisk node if root; if recursing, + // child HardDisk node or DiffHardDisk node for pre-1.4 + MediaList &llMedia) // list to append medium to (root disk or child list) +{ + // <HardDisk uuid="{5471ecdb-1ddb-4012-a801-6d98e226868b}" location="/mnt/innotek-unix/vdis/Windows XP.vdi" format="VDI" type="Normal"> + settings::Medium med; + Utf8Str strUUID; + if (!(elmMedium.getAttributeValue("uuid", strUUID))) + throw ConfigFileError(this, &elmMedium, N_("Required %s/@uuid attribute is missing"), elmMedium.getName()); + + parseUUID(med.uuid, strUUID); + + bool fNeedsLocation = true; + + if (t == HardDisk) + { + if (m->sv < SettingsVersion_v1_4) + { + // here the system is: + // <HardDisk uuid="{....}" type="normal"> + // <VirtualDiskImage filePath="/path/to/xxx.vdi"/> + // </HardDisk> + + fNeedsLocation = false; + bool fNeedsFilePath = true; + const xml::ElementNode *pelmImage; + if ((pelmImage = elmMedium.findChildElement("VirtualDiskImage"))) + med.strFormat = "VDI"; + else if ((pelmImage = elmMedium.findChildElement("VMDKImage"))) + med.strFormat = "VMDK"; + else if ((pelmImage = elmMedium.findChildElement("VHDImage"))) + med.strFormat = "VHD"; + else if ((pelmImage = elmMedium.findChildElement("ISCSIHardDisk"))) + { + med.strFormat = "iSCSI"; + + fNeedsFilePath = false; + // location is special here: current settings specify an "iscsi://user@server:port/target/lun" + // string for the location and also have several disk properties for these, whereas this used + // to be hidden in several sub-elements before 1.4, so compose a location string and set up + // the properties: + med.strLocation = "iscsi://"; + Utf8Str strUser, strServer, strPort, strTarget, strLun; + if (pelmImage->getAttributeValue("userName", strUser)) + { + med.strLocation.append(strUser); + med.strLocation.append("@"); + } + Utf8Str strServerAndPort; + if (pelmImage->getAttributeValue("server", strServer)) + { + strServerAndPort = strServer; + } + if (pelmImage->getAttributeValue("port", strPort)) + { + if (strServerAndPort.length()) + strServerAndPort.append(":"); + strServerAndPort.append(strPort); + } + med.strLocation.append(strServerAndPort); + if (pelmImage->getAttributeValue("target", strTarget)) + { + med.strLocation.append("/"); + med.strLocation.append(strTarget); + } + if (pelmImage->getAttributeValue("lun", strLun)) + { + med.strLocation.append("/"); + med.strLocation.append(strLun); + } + + if (strServer.length() && strPort.length()) + med.properties["TargetAddress"] = strServerAndPort; + if (strTarget.length()) + med.properties["TargetName"] = strTarget; + if (strUser.length()) + med.properties["InitiatorUsername"] = strUser; + Utf8Str strPassword; + if (pelmImage->getAttributeValue("password", strPassword)) + med.properties["InitiatorSecret"] = strPassword; + if (strLun.length()) + med.properties["LUN"] = strLun; + } + else if ((pelmImage = elmMedium.findChildElement("CustomHardDisk"))) + { + fNeedsFilePath = false; + fNeedsLocation = true; + // also requires @format attribute, which will be queried below + } + else + throw ConfigFileError(this, &elmMedium, N_("Required %s/VirtualDiskImage element is missing"), elmMedium.getName()); + + if (fNeedsFilePath) + { + if (!(pelmImage->getAttributeValuePath("filePath", med.strLocation))) + throw ConfigFileError(this, &elmMedium, N_("Required %s/@filePath attribute is missing"), elmMedium.getName()); + } + } + + if (med.strFormat.isEmpty()) // not set with 1.4 format above, or 1.4 Custom format? + if (!(elmMedium.getAttributeValue("format", med.strFormat))) + throw ConfigFileError(this, &elmMedium, N_("Required %s/@format attribute is missing"), elmMedium.getName()); + + if (!(elmMedium.getAttributeValue("autoReset", med.fAutoReset))) + med.fAutoReset = false; + + Utf8Str strType; + if ((elmMedium.getAttributeValue("type", strType))) + { + // pre-1.4 used lower case, so make this case-insensitive + strType.toUpper(); + if (strType == "NORMAL") + med.hdType = MediumType_Normal; + else if (strType == "IMMUTABLE") + med.hdType = MediumType_Immutable; + else if (strType == "WRITETHROUGH") + med.hdType = MediumType_Writethrough; + else if (strType == "SHAREABLE") + med.hdType = MediumType_Shareable; + else if (strType == "READONLY") + med.hdType = MediumType_Readonly; + else if (strType == "MULTIATTACH") + med.hdType = MediumType_MultiAttach; + else + throw ConfigFileError(this, &elmMedium, N_("HardDisk/@type attribute must be one of Normal, Immutable, Writethrough, Shareable, Readonly or MultiAttach")); + } + } + else + { + if (m->sv < SettingsVersion_v1_4) + { + // DVD and floppy images before 1.4 had "src" attribute instead of "location" + if (!(elmMedium.getAttributeValue("src", med.strLocation))) + throw ConfigFileError(this, &elmMedium, N_("Required %s/@src attribute is missing"), elmMedium.getName()); + + fNeedsLocation = false; + } + + if (!(elmMedium.getAttributeValue("format", med.strFormat))) + { + // DVD and floppy images before 1.11 had no format attribute. assign the default. + med.strFormat = "RAW"; + } + } + + if (fNeedsLocation) + // current files and 1.4 CustomHardDisk elements must have a location attribute + if (!(elmMedium.getAttributeValue("location", med.strLocation))) + throw ConfigFileError(this, &elmMedium, N_("Required %s/@location attribute is missing"), elmMedium.getName()); + + elmMedium.getAttributeValue("Description", med.strDescription); // optional + + // recurse to handle children + xml::NodesLoop nl2(elmMedium); + const xml::ElementNode *pelmHDChild; + while ((pelmHDChild = nl2.forAllNodes())) + { + if ( t == HardDisk + && ( pelmHDChild->nameEquals("HardDisk") + || ( (m->sv < SettingsVersion_v1_4) + && (pelmHDChild->nameEquals("DiffHardDisk")) + ) + ) + ) + // recurse with this element and push the child onto our current children list + readMedium(t, + *pelmHDChild, + med.llChildren); + else if (pelmHDChild->nameEquals("Property")) + { + Utf8Str strPropName, strPropValue; + if ( (pelmHDChild->getAttributeValue("name", strPropName)) + && (pelmHDChild->getAttributeValue("value", strPropValue)) + ) + med.properties[strPropName] = strPropValue; + else + throw ConfigFileError(this, pelmHDChild, N_("Required HardDisk/Property/@name or @value attribute is missing")); + } + } + + llMedia.push_back(med); +} + +/** + * Reads in the entire <MediaRegistry> chunk and stores its media in the lists + * of the given MediaRegistry structure. + * + * This is used in both MainConfigFile and MachineConfigFile since starting with + * VirtualBox 4.0, we can have media registries in both. + * + * For pre-1.4 files, this gets called with the <DiskRegistry> chunk instead. + * + * @param elmMediaRegistry + */ +void ConfigFileBase::readMediaRegistry(const xml::ElementNode &elmMediaRegistry, + MediaRegistry &mr) +{ + xml::NodesLoop nl1(elmMediaRegistry); + const xml::ElementNode *pelmChild1; + while ((pelmChild1 = nl1.forAllNodes())) + { + MediaType t = Error; + if (pelmChild1->nameEquals("HardDisks")) + t = HardDisk; + else if (pelmChild1->nameEquals("DVDImages")) + t = DVDImage; + else if (pelmChild1->nameEquals("FloppyImages")) + t = FloppyImage; + else + continue; + + xml::NodesLoop nl2(*pelmChild1); + const xml::ElementNode *pelmMedium; + while ((pelmMedium = nl2.forAllNodes())) + { + if ( t == HardDisk + && (pelmMedium->nameEquals("HardDisk")) + ) + readMedium(t, + *pelmMedium, + mr.llHardDisks); // list to append hard disk data to: the root list + else if ( t == DVDImage + && (pelmMedium->nameEquals("Image")) + ) + readMedium(t, + *pelmMedium, + mr.llDvdImages); // list to append dvd images to: the root list + else if ( t == FloppyImage + && (pelmMedium->nameEquals("Image")) + ) + readMedium(t, + *pelmMedium, + mr.llFloppyImages); // list to append floppy images to: the root list + } + } +} + +/** * Adds a "version" attribute to the given XML element with the * VirtualBox settings version (e.g. "1.10-linux"). Used by * the XML format for the root element and by the OVF export @@ -526,16 +803,24 @@ void ConfigFileBase::setVersionAttribute(xml::ElementNode &elm) { case SettingsVersion_v1_8: pcszVersion = "1.8"; - break; + break; case SettingsVersion_v1_9: pcszVersion = "1.9"; - break; + break; case SettingsVersion_v1_10: - case SettingsVersion_Future: // can be set if this code runs on XML files that were created by a future version of VBox; - // in that case, downgrade to current version when writing since we can't write future versions... pcszVersion = "1.10"; + break; + + case SettingsVersion_v1_11: + pcszVersion = "1.11"; + break; + + case SettingsVersion_Future: + // can be set if this code runs on XML files that were created by a future version of VBox; + // in that case, downgrade to current version when writing since we can't write future versions... + pcszVersion = "1.11"; m->sv = SettingsVersion_v1_10; break; @@ -560,7 +845,7 @@ void ConfigFileBase::setVersionAttribute(xml::ElementNode &elm) * Before calling this, it is the responsibility of the caller to * set the "sv" member to the required settings version that is to * be written. For newly created files, the settings version will be - * the latest (1.9); for files read in from disk earlier, it will be + * the latest (1.11); for files read in from disk earlier, it will be * the settings version indicated in the file. However, this method * will silently make sure that the settings version is always * at least 1.7 and change it if necessary, since there is no write @@ -585,12 +870,21 @@ void ConfigFileBase::createStubDocument() && (m->svRead < m->sv) // we're upgrading? ) { - // compose new filename: strip off trailing ".xml" - Utf8Str strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 4); - // and append something likd "-1.3-linux.xml" + // compose new filename: strip off trailing ".xml"/".vbox" + Utf8Str strFilenameNew; + Utf8Str strExt = ".xml"; + if (m->strFilename.endsWith(".xml")) + strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 4); + else if (m->strFilename.endsWith(".vbox")) + { + strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 5); + strExt = ".vbox"; + } + + // and append something like "-1.3-linux.xml" strFilenameNew.append("-"); strFilenameNew.append(m->strSettingsVersionFull); // e.g. "1.3-linux" - strFilenameNew.append(".xml"); + strFilenameNew.append(strExt); // .xml for main config, .vbox for machine config RTFileMove(m->strFilename.c_str(), strFilenameNew.c_str(), @@ -605,19 +899,20 @@ void ConfigFileBase::createStubDocument() * Creates an <ExtraData> node under the given parent element with * <ExtraDataItem> childern according to the contents of the given * map. + * * This is in ConfigFileBase because it's used in both MainConfigFile - * MachineConfigFile, which both can have extradata. + * and MachineConfigFile, which both can have extradata. * * @param elmParent * @param me */ -void ConfigFileBase::writeExtraData(xml::ElementNode &elmParent, - const ExtraDataItemsMap &me) +void ConfigFileBase::buildExtraData(xml::ElementNode &elmParent, + const StringsMap &me) { if (me.size()) { xml::ElementNode *pelmExtraData = elmParent.createChild("ExtraData"); - for (ExtraDataItemsMap::const_iterator it = me.begin(); + for (StringsMap::const_iterator it = me.begin(); it != me.end(); ++it) { @@ -644,7 +939,7 @@ void ConfigFileBase::writeExtraData(xml::ElementNode &elmParent, * @param ll * @param fHostMode */ -void ConfigFileBase::writeUSBDeviceFilters(xml::ElementNode &elmParent, +void ConfigFileBase::buildUSBDeviceFilters(xml::ElementNode &elmParent, const USBDeviceFiltersList &ll, bool fHostMode) { @@ -689,6 +984,120 @@ void ConfigFileBase::writeUSBDeviceFilters(xml::ElementNode &elmParent, } /** + * Creates a single <HardDisk> element for the given Medium structure + * and recurses to write the child hard disks underneath. Called from + * MainConfigFile::write(). + * + * @param elmMedium + * @param m + * @param level + */ +void ConfigFileBase::buildMedium(xml::ElementNode &elmMedium, + DeviceType_T devType, + const Medium &mdm, + uint32_t level) // 0 for "root" call, incremented with each recursion +{ + xml::ElementNode *pelmMedium; + + if (devType == DeviceType_HardDisk) + pelmMedium = elmMedium.createChild("HardDisk"); + else + pelmMedium = elmMedium.createChild("Image"); + + pelmMedium->setAttribute("uuid", mdm.uuid.toStringCurly()); + + pelmMedium->setAttributePath("location", mdm.strLocation); + + if (devType == DeviceType_HardDisk || RTStrICmp(mdm.strFormat.c_str(), "RAW")) + pelmMedium->setAttribute("format", mdm.strFormat); + if (mdm.fAutoReset) + pelmMedium->setAttribute("autoReset", mdm.fAutoReset); + if (mdm.strDescription.length()) + pelmMedium->setAttribute("Description", mdm.strDescription); + + for (StringsMap::const_iterator it = mdm.properties.begin(); + it != mdm.properties.end(); + ++it) + { + xml::ElementNode *pelmProp = pelmMedium->createChild("Property"); + pelmProp->setAttribute("name", it->first); + pelmProp->setAttribute("value", it->second); + } + + // only for base hard disks, save the type + if (level == 0) + { + const char *pcszType = + mdm.hdType == MediumType_Normal ? "Normal" : + mdm.hdType == MediumType_Immutable ? "Immutable" : + mdm.hdType == MediumType_Writethrough ? "Writethrough" : + mdm.hdType == MediumType_Shareable ? "Shareable" : + mdm.hdType == MediumType_Readonly ? "Readonly" : + mdm.hdType == MediumType_MultiAttach ? "MultiAttach" : + "INVALID"; + // no need to save the usual DVD/floppy medium types + if ( ( devType != DeviceType_DVD + || ( mdm.hdType != MediumType_Writethrough // shouldn't happen + && mdm.hdType != MediumType_Readonly)) + && ( devType != DeviceType_Floppy + || mdm.hdType != MediumType_Writethrough)) + pelmMedium->setAttribute("type", pcszType); + } + + for (MediaList::const_iterator it = mdm.llChildren.begin(); + it != mdm.llChildren.end(); + ++it) + { + // recurse for children + buildMedium(*pelmMedium, // parent + devType, // device type + *it, // settings::Medium + ++level); // recursion level + } +} + +/** + * Creates a <MediaRegistry> node under the given parent and writes out all + * hard disks and DVD and floppy images from the lists in the given MediaRegistry + * structure under it. + * + * This is used in both MainConfigFile and MachineConfigFile since starting with + * VirtualBox 4.0, we can have media registries in both. + * + * @param elmParent + * @param mr + */ +void ConfigFileBase::buildMediaRegistry(xml::ElementNode &elmParent, + const MediaRegistry &mr) +{ + xml::ElementNode *pelmMediaRegistry = elmParent.createChild("MediaRegistry"); + + xml::ElementNode *pelmHardDisks = pelmMediaRegistry->createChild("HardDisks"); + for (MediaList::const_iterator it = mr.llHardDisks.begin(); + it != mr.llHardDisks.end(); + ++it) + { + buildMedium(*pelmHardDisks, DeviceType_HardDisk, *it, 0); + } + + xml::ElementNode *pelmDVDImages = pelmMediaRegistry->createChild("DVDImages"); + for (MediaList::const_iterator it = mr.llDvdImages.begin(); + it != mr.llDvdImages.end(); + ++it) + { + buildMedium(*pelmDVDImages, DeviceType_DVD, *it, 0); + } + + xml::ElementNode *pelmFloppyImages = pelmMediaRegistry->createChild("FloppyImages"); + for (MediaList::const_iterator it = mr.llFloppyImages.begin(); + it != mr.llFloppyImages.end(); + ++it) + { + buildMedium(*pelmFloppyImages, DeviceType_Floppy, *it, 0); + } +} + +/** * Cleans up memory allocated by the internal XML parser. To be called by * descendant classes when they're done analyzing the DOM tree to discard it. */ @@ -784,234 +1193,6 @@ void MainConfigFile::readMachineRegistry(const xml::ElementNode &elmMachineRegis } /** - * Reads a media registry entry from the main VirtualBox.xml file. - * - * Whereas the current media registry code is fairly straightforward, it was quite a mess - * with settings format before 1.4 (VirtualBox 2.0 used settings format 1.3). The elements - * in the media registry were much more inconsistent, and different elements were used - * depending on the type of device and image. - * - * @param t - * @param elmMedium - * @param llMedia - */ -void MainConfigFile::readMedium(MediaType t, - const xml::ElementNode &elmMedium, // HardDisk node if root; if recursing, - // child HardDisk node or DiffHardDisk node for pre-1.4 - MediaList &llMedia) // list to append medium to (root disk or child list) -{ - // <HardDisk uuid="{5471ecdb-1ddb-4012-a801-6d98e226868b}" location="/mnt/innotek-unix/vdis/Windows XP.vdi" format="VDI" type="Normal"> - settings::Medium med; - Utf8Str strUUID; - if (!(elmMedium.getAttributeValue("uuid", strUUID))) - throw ConfigFileError(this, &elmMedium, N_("Required %s/@uuid attribute is missing"), elmMedium.getName()); - - parseUUID(med.uuid, strUUID); - - bool fNeedsLocation = true; - - if (t == HardDisk) - { - if (m->sv < SettingsVersion_v1_4) - { - // here the system is: - // <HardDisk uuid="{....}" type="normal"> - // <VirtualDiskImage filePath="/path/to/xxx.vdi"/> - // </HardDisk> - - fNeedsLocation = false; - bool fNeedsFilePath = true; - const xml::ElementNode *pelmImage; - if ((pelmImage = elmMedium.findChildElement("VirtualDiskImage"))) - med.strFormat = "VDI"; - else if ((pelmImage = elmMedium.findChildElement("VMDKImage"))) - med.strFormat = "VMDK"; - else if ((pelmImage = elmMedium.findChildElement("VHDImage"))) - med.strFormat = "VHD"; - else if ((pelmImage = elmMedium.findChildElement("ISCSIHardDisk"))) - { - med.strFormat = "iSCSI"; - - fNeedsFilePath = false; - // location is special here: current settings specify an "iscsi://user@server:port/target/lun" - // string for the location and also have several disk properties for these, whereas this used - // to be hidden in several sub-elements before 1.4, so compose a location string and set up - // the properties: - med.strLocation = "iscsi://"; - Utf8Str strUser, strServer, strPort, strTarget, strLun; - if (pelmImage->getAttributeValue("userName", strUser)) - { - med.strLocation.append(strUser); - med.strLocation.append("@"); - } - Utf8Str strServerAndPort; - if (pelmImage->getAttributeValue("server", strServer)) - { - strServerAndPort = strServer; - } - if (pelmImage->getAttributeValue("port", strPort)) - { - if (strServerAndPort.length()) - strServerAndPort.append(":"); - strServerAndPort.append(strPort); - } - med.strLocation.append(strServerAndPort); - if (pelmImage->getAttributeValue("target", strTarget)) - { - med.strLocation.append("/"); - med.strLocation.append(strTarget); - } - if (pelmImage->getAttributeValue("lun", strLun)) - { - med.strLocation.append("/"); - med.strLocation.append(strLun); - } - - if (strServer.length() && strPort.length()) - med.properties["TargetAddress"] = strServerAndPort; - if (strTarget.length()) - med.properties["TargetName"] = strTarget; - if (strUser.length()) - med.properties["InitiatorUsername"] = strUser; - Utf8Str strPassword; - if (pelmImage->getAttributeValue("password", strPassword)) - med.properties["InitiatorSecret"] = strPassword; - if (strLun.length()) - med.properties["LUN"] = strLun; - } - else if ((pelmImage = elmMedium.findChildElement("CustomHardDisk"))) - { - fNeedsFilePath = false; - fNeedsLocation = true; - // also requires @format attribute, which will be queried below - } - else - throw ConfigFileError(this, &elmMedium, N_("Required %s/VirtualDiskImage element is missing"), elmMedium.getName()); - - if (fNeedsFilePath) - if (!(pelmImage->getAttributeValue("filePath", med.strLocation))) - throw ConfigFileError(this, &elmMedium, N_("Required %s/@filePath attribute is missing"), elmMedium.getName()); - } - - if (med.strFormat.isEmpty()) // not set with 1.4 format above, or 1.4 Custom format? - if (!(elmMedium.getAttributeValue("format", med.strFormat))) - throw ConfigFileError(this, &elmMedium, N_("Required %s/@format attribute is missing"), elmMedium.getName()); - - if (!(elmMedium.getAttributeValue("autoReset", med.fAutoReset))) - med.fAutoReset = false; - - Utf8Str strType; - if ((elmMedium.getAttributeValue("type", strType))) - { - // pre-1.4 used lower case, so make this case-insensitive - strType.toUpper(); - if (strType == "NORMAL") - med.hdType = MediumType_Normal; - else if (strType == "IMMUTABLE") - med.hdType = MediumType_Immutable; - else if (strType == "WRITETHROUGH") - med.hdType = MediumType_Writethrough; - else if (strType == "SHAREABLE") - med.hdType = MediumType_Shareable; - else - throw ConfigFileError(this, &elmMedium, N_("HardDisk/@type attribute must be one of Normal, Immutable or Writethrough")); - } - } - else if (m->sv < SettingsVersion_v1_4) - { - // DVD and floppy images before 1.4 had "src" attribute instead of "location" - if (!(elmMedium.getAttributeValue("src", med.strLocation))) - throw ConfigFileError(this, &elmMedium, N_("Required %s/@src attribute is missing"), elmMedium.getName()); - - fNeedsLocation = false; - } - - if (fNeedsLocation) - // current files and 1.4 CustomHardDisk elements must have a location attribute - if (!(elmMedium.getAttributeValue("location", med.strLocation))) - throw ConfigFileError(this, &elmMedium, N_("Required %s/@location attribute is missing"), elmMedium.getName()); - - elmMedium.getAttributeValue("Description", med.strDescription); // optional - - // recurse to handle children - xml::NodesLoop nl2(elmMedium); - const xml::ElementNode *pelmHDChild; - while ((pelmHDChild = nl2.forAllNodes())) - { - if ( t == HardDisk - && ( pelmHDChild->nameEquals("HardDisk") - || ( (m->sv < SettingsVersion_v1_4) - && (pelmHDChild->nameEquals("DiffHardDisk")) - ) - ) - ) - // recurse with this element and push the child onto our current children list - readMedium(t, - *pelmHDChild, - med.llChildren); - else if (pelmHDChild->nameEquals("Property")) - { - Utf8Str strPropName, strPropValue; - if ( (pelmHDChild->getAttributeValue("name", strPropName)) - && (pelmHDChild->getAttributeValue("value", strPropValue)) - ) - med.properties[strPropName] = strPropValue; - else - throw ConfigFileError(this, pelmHDChild, N_("Required HardDisk/Property/@name or @value attribute is missing")); - } - } - - llMedia.push_back(med); -} - -/** - * Reads in the entire <MediaRegistry> chunk. For pre-1.4 files, this gets called - * with the <DiskRegistry> chunk instead. - * @param elmMediaRegistry - */ -void MainConfigFile::readMediaRegistry(const xml::ElementNode &elmMediaRegistry) -{ - xml::NodesLoop nl1(elmMediaRegistry); - const xml::ElementNode *pelmChild1; - while ((pelmChild1 = nl1.forAllNodes())) - { - MediaType t = Error; - if (pelmChild1->nameEquals("HardDisks")) - t = HardDisk; - else if (pelmChild1->nameEquals("DVDImages")) - t = DVDImage; - else if (pelmChild1->nameEquals("FloppyImages")) - t = FloppyImage; - else - continue; - - xml::NodesLoop nl2(*pelmChild1); - const xml::ElementNode *pelmMedium; - while ((pelmMedium = nl2.forAllNodes())) - { - if ( t == HardDisk - && (pelmMedium->nameEquals("HardDisk")) - ) - readMedium(t, - *pelmMedium, - llHardDisks); // list to append hard disk data to: the root list - else if ( t == DVDImage - && (pelmMedium->nameEquals("Image")) - ) - readMedium(t, - *pelmMedium, - llDvdImages); // list to append dvd images to: the root list - else if ( t == FloppyImage - && (pelmMedium->nameEquals("Image")) - ) - readMedium(t, - *pelmMedium, - llFloppyImages); // list to append floppy images to: the root list - } - } -} - -/** * Reads in the <DHCPServers> chunk. * @param elmDHCPServers */ @@ -1071,12 +1252,12 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename) if (pelmGlobalChild->nameEquals("SystemProperties")) { pelmGlobalChild->getAttributeValue("defaultMachineFolder", systemProperties.strDefaultMachineFolder); - if (!pelmGlobalChild->getAttributeValue("defaultHardDiskFolder", systemProperties.strDefaultHardDiskFolder)) - // pre-1.4 used @defaultVDIFolder instead - pelmGlobalChild->getAttributeValue("defaultVDIFolder", systemProperties.strDefaultHardDiskFolder); pelmGlobalChild->getAttributeValue("defaultHardDiskFormat", systemProperties.strDefaultHardDiskFormat); - pelmGlobalChild->getAttributeValue("remoteDisplayAuthLibrary", systemProperties.strRemoteDisplayAuthLibrary); + if (!pelmGlobalChild->getAttributeValue("VRDEAuthLibrary", systemProperties.strVRDEAuthLibrary)) + // pre-1.11 used @remoteDisplayAuthLibrary instead + pelmGlobalChild->getAttributeValue("remoteDisplayAuthLibrary", systemProperties.strVRDEAuthLibrary); pelmGlobalChild->getAttributeValue("webServiceAuthLibrary", systemProperties.strWebServiceAuthLibrary); + pelmGlobalChild->getAttributeValue("defaultVRDEExtPack", systemProperties.strDefaultVRDEExtPack); pelmGlobalChild->getAttributeValue("LogHistoryCount", systemProperties.ulLogHistoryCount); } else if (pelmGlobalChild->nameEquals("ExtraData")) @@ -1088,7 +1269,7 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename) && (pelmGlobalChild->nameEquals("DiskRegistry")) ) ) - readMediaRegistry(*pelmGlobalChild); + readMediaRegistry(*pelmGlobalChild, mediaRegistry); else if (pelmGlobalChild->nameEquals("NetserviceRegistry")) { xml::NodesLoop nlLevel4(*pelmGlobalChild); @@ -1134,59 +1315,6 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename) } /** - * Creates a single <HardDisk> element for the given Medium structure - * and recurses to write the child hard disks underneath. Called from - * MainConfigFile::write(). - * - * @param elmMedium - * @param m - * @param level - */ -void MainConfigFile::writeHardDisk(xml::ElementNode &elmMedium, - const Medium &mdm, - uint32_t level) // 0 for "root" call, incremented with each recursion -{ - xml::ElementNode *pelmHardDisk = elmMedium.createChild("HardDisk"); - pelmHardDisk->setAttribute("uuid", mdm.uuid.toStringCurly()); - pelmHardDisk->setAttribute("location", mdm.strLocation); - pelmHardDisk->setAttribute("format", mdm.strFormat); - if (mdm.fAutoReset) - pelmHardDisk->setAttribute("autoReset", mdm.fAutoReset); - if (mdm.strDescription.length()) - pelmHardDisk->setAttribute("Description", mdm.strDescription); - - for (PropertiesMap::const_iterator it = mdm.properties.begin(); - it != mdm.properties.end(); - ++it) - { - xml::ElementNode *pelmProp = pelmHardDisk->createChild("Property"); - pelmProp->setAttribute("name", it->first); - pelmProp->setAttribute("value", it->second); - } - - // only for base hard disks, save the type - if (level == 0) - { - const char *pcszType = - mdm.hdType == MediumType_Normal ? "Normal" : - mdm.hdType == MediumType_Immutable ? "Immutable" : - mdm.hdType == MediumType_Writethrough ? "Writethrough" : - mdm.hdType == MediumType_Shareable ? "Shareable" : "INVALID"; - pelmHardDisk->setAttribute("type", pcszType); - } - - for (MediaList::const_iterator it = mdm.llChildren.begin(); - it != mdm.llChildren.end(); - ++it) - { - // recurse for children - writeHardDisk(*pelmHardDisk, // parent - *it, // settings::Medium - ++level); // recursion level - } -} - -/** * Called from the IVirtualBox interface to write out VirtualBox.xml. This * builds an XML DOM tree and writes it out to disk. */ @@ -1197,7 +1325,7 @@ void MainConfigFile::write(const com::Utf8Str strFilename) xml::ElementNode *pelmGlobal = m->pelmRoot->createChild("Global"); - writeExtraData(*pelmGlobal, mapExtraDataItems); + buildExtraData(*pelmGlobal, mapExtraDataItems); xml::ElementNode *pelmMachineRegistry = pelmGlobal->createChild("MachineRegistry"); for (MachinesRegistry::const_iterator it = llMachines.begin(); @@ -1211,41 +1339,7 @@ void MainConfigFile::write(const com::Utf8Str strFilename) pelmMachineEntry->setAttribute("src", mre.strSettingsFile); } - xml::ElementNode *pelmMediaRegistry = pelmGlobal->createChild("MediaRegistry"); - - xml::ElementNode *pelmHardDisks = pelmMediaRegistry->createChild("HardDisks"); - for (MediaList::const_iterator it = llHardDisks.begin(); - it != llHardDisks.end(); - ++it) - { - writeHardDisk(*pelmHardDisks, *it, 0); - } - - xml::ElementNode *pelmDVDImages = pelmMediaRegistry->createChild("DVDImages"); - for (MediaList::const_iterator it = llDvdImages.begin(); - it != llDvdImages.end(); - ++it) - { - const Medium &mdm = *it; - xml::ElementNode *pelmMedium = pelmDVDImages->createChild("Image"); - pelmMedium->setAttribute("uuid", mdm.uuid.toStringCurly()); - pelmMedium->setAttribute("location", mdm.strLocation); - if (mdm.strDescription.length()) - pelmMedium->setAttribute("Description", mdm.strDescription); - } - - xml::ElementNode *pelmFloppyImages = pelmMediaRegistry->createChild("FloppyImages"); - for (MediaList::const_iterator it = llFloppyImages.begin(); - it != llFloppyImages.end(); - ++it) - { - const Medium &mdm = *it; - xml::ElementNode *pelmMedium = pelmFloppyImages->createChild("Image"); - pelmMedium->setAttribute("uuid", mdm.uuid.toStringCurly()); - pelmMedium->setAttribute("location", mdm.strLocation); - if (mdm.strDescription.length()) - pelmMedium->setAttribute("Description", mdm.strDescription); - } + buildMediaRegistry(*pelmGlobal, mediaRegistry); xml::ElementNode *pelmNetserviceRegistry = pelmGlobal->createChild("NetserviceRegistry"); xml::ElementNode *pelmDHCPServers = pelmNetserviceRegistry->createChild("DHCPServers"); @@ -1266,17 +1360,17 @@ void MainConfigFile::write(const com::Utf8Str strFilename) xml::ElementNode *pelmSysProps = pelmGlobal->createChild("SystemProperties"); if (systemProperties.strDefaultMachineFolder.length()) pelmSysProps->setAttribute("defaultMachineFolder", systemProperties.strDefaultMachineFolder); - if (systemProperties.strDefaultHardDiskFolder.length()) - pelmSysProps->setAttribute("defaultHardDiskFolder", systemProperties.strDefaultHardDiskFolder); if (systemProperties.strDefaultHardDiskFormat.length()) pelmSysProps->setAttribute("defaultHardDiskFormat", systemProperties.strDefaultHardDiskFormat); - if (systemProperties.strRemoteDisplayAuthLibrary.length()) - pelmSysProps->setAttribute("remoteDisplayAuthLibrary", systemProperties.strRemoteDisplayAuthLibrary); + if (systemProperties.strVRDEAuthLibrary.length()) + pelmSysProps->setAttribute("VRDEAuthLibrary", systemProperties.strVRDEAuthLibrary); if (systemProperties.strWebServiceAuthLibrary.length()) pelmSysProps->setAttribute("webServiceAuthLibrary", systemProperties.strWebServiceAuthLibrary); + if (systemProperties.strDefaultVRDEExtPack.length()) + pelmSysProps->setAttribute("defaultVRDEExtPack", systemProperties.strDefaultVRDEExtPack); pelmSysProps->setAttribute("LogHistoryCount", systemProperties.ulLogHistoryCount); - writeUSBDeviceFilters(*pelmGlobal->createChild("USBDeviceFilters"), + buildUSBDeviceFilters(*pelmGlobal->createChild("USBDeviceFilters"), host.llUSBDeviceFilters, true); // fHostMode @@ -1300,18 +1394,17 @@ void MainConfigFile::write(const com::Utf8Str strFilename) * which in turn gets called from Machine::saveSettings to figure out whether * machine settings have really changed and thus need to be written out to disk. */ -bool VRDPSettings::operator==(const VRDPSettings& v) const +bool VRDESettings::operator==(const VRDESettings& v) const { return ( (this == &v) || ( (fEnabled == v.fEnabled) - && (strPort == v.strPort) - && (strNetAddress == v.strNetAddress) && (authType == v.authType) && (ulAuthTimeout == v.ulAuthTimeout) + && (strAuthLibrary == v.strAuthLibrary) && (fAllowMultiConnection == v.fAllowMultiConnection) && (fReuseSingleConnection == v.fReuseSingleConnection) - && (fVideoChannel == v.fVideoChannel) - && (ulVideoChannelQuality == v.ulVideoChannelQuality) + && (strVrdeExtPack == v.strVrdeExtPack) + && (mapProperties == v.mapProperties) ) ); } @@ -1423,6 +1516,7 @@ bool SharedFolder::operator==(const SharedFolder &g) const || ( (strName == g.strName) && (strHostPath == g.strHostPath) && (fWritable == g.fWritable) + && (fAutoMount == g.fAutoMount) ) ); } @@ -1460,7 +1554,6 @@ Hardware::Hardware() fHardwareVirt(true), fHardwareVirtExclusive(HWVIRTEXCLUSIVEDEFAULT), fNestedPaging(true), - fLargePages(false), fVPID(true), fHardwareVirtForce(false), fSyntheticCpu(false), @@ -1468,6 +1561,7 @@ Hardware::Hardware() cCPUs(1), fCpuHotPlug(false), fHpetEnabled(false), + ulCpuExecutionCap(100), ulMemorySizeMB((uint32_t)-1), ulVRAMSizeMB(8), cMonitors(1), @@ -1476,6 +1570,7 @@ Hardware::Hardware() firmwareType(FirmwareType_BIOS), pointingHidType(PointingHidType_PS2Mouse), keyboardHidType(KeyboardHidType_PS2Keyboard), + chipsetType(ChipsetType_PIIX3), clipboardMode(ClipboardMode_Bidirectional), ulMemoryBalloonSize(0), fPageFusionEnabled(false) @@ -1491,6 +1586,17 @@ Hardware::Hardware() #if HC_ARCH_BITS == 64 || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN) fPAE = true; #endif + + /* The default value of large page supports depends on the host: + * - 64 bits host -> true, unless it's Linux (pending further prediction work due to excessively expensive large page allocations) + * - 32 bits host -> false + */ +#if HC_ARCH_BITS == 64 && !defined(RT_OS_LINUX) + fLargePages = true; +#else + /* Not supported on 32 bits hosts. */ + fLargePages = false; +#endif } /** @@ -1513,6 +1619,7 @@ bool Hardware::operator==(const Hardware& h) const && (fPAE == h.fPAE) && (cCPUs == h.cCPUs) && (fCpuHotPlug == h.fCpuHotPlug) + && (ulCpuExecutionCap == h.ulCpuExecutionCap) && (fHpetEnabled == h.fHpetEnabled) && (llCpus == h.llCpus) && (llCpuIdLeafs == h.llCpuIdLeafs) @@ -1525,7 +1632,8 @@ bool Hardware::operator==(const Hardware& h) const && (firmwareType == h.firmwareType) && (pointingHidType == h.pointingHidType) && (keyboardHidType == h.keyboardHidType) - && (vrdpSettings == h.vrdpSettings) + && (chipsetType == h.chipsetType) + && (vrdeSettings == h.vrdeSettings) && (biosSettings == h.biosSettings) && (usbController == h.usbController) && (llNetworkAdapters == h.llNetworkAdapters) @@ -1538,6 +1646,7 @@ bool Hardware::operator==(const Hardware& h) const && (fPageFusionEnabled == h.fPageFusionEnabled) && (llGuestProperties == h.llGuestProperties) && (strNotificationPatterns == h.strNotificationPatterns) + && (ioSettings == h.ioSettings) ) ); } @@ -1556,6 +1665,7 @@ bool AttachedDevice::operator==(const AttachedDevice &a) const && (lDevice == a.lDevice) && (uuid == a.uuid) && (strHostDriveSrc == a.strHostDriveSrc) + && (strBwGroup == a.strBwGroup) ) ); } @@ -1622,7 +1732,6 @@ IoSettings::IoSettings() { fIoCacheEnabled = true; ulIoCacheSize = 5; - ulIoBandwidthMax = 0; } //////////////////////////////////////////////////////////////////////////////// @@ -1646,10 +1755,6 @@ IoSettings::IoSettings() */ MachineConfigFile::MachineConfigFile(const Utf8Str *pstrFilename) : ConfigFileBase(pstrFilename), - fNameSync(true), - fTeleporterEnabled(false), - uTeleporterPort(0), - fRTCUseUTC(false), fCurrentStateModified(true), fAborted(false) { @@ -1674,6 +1779,17 @@ MachineConfigFile::MachineConfigFile(const Utf8Str *pstrFilename) } /** + * Public routine which returns true if this machine config file can have its + * own media registry (which is true for settings version v1.11 and higher, + * i.e. files created by VirtualBox 4.0 and higher). + * @return + */ +bool MachineConfigFile::canHaveOwnMediaRegistry() const +{ + return (m->sv >= SettingsVersion_v1_11); +} + +/** * Public routine which allows for importing machine XML from an external DOM tree. * Use this after having called the constructor with a NULL argument. * @@ -1706,23 +1822,15 @@ bool MachineConfigFile::operator==(const MachineConfigFile &c) const { return ( (this == &c) || ( (uuid == c.uuid) - && (strName == c.strName) - && (fNameSync == c.fNameSync) - && (strDescription == c.strDescription) - && (strOsType == c.strOsType) + && (machineUserData == c.machineUserData) && (strStateFile == c.strStateFile) && (uuidCurrentSnapshot == c.uuidCurrentSnapshot) - && (strSnapshotFolder == c.strSnapshotFolder) - && (fTeleporterEnabled == c.fTeleporterEnabled) - && (uTeleporterPort == c.uTeleporterPort) - && (strTeleporterAddress == c.strTeleporterAddress) - && (strTeleporterPassword == c.strTeleporterPassword) - && (fRTCUseUTC == c.fRTCUseUTC) // skip fCurrentStateModified! && (RTTimeSpecIsEqual(&timeLastStateChange, &c.timeLastStateChange)) && (fAborted == c.fAborted) && (hardwareMachine == c.hardwareMachine) // this one's deep && (storageMachine == c.storageMachine) // this one's deep + && (mediaRegistry == c.mediaRegistry) // this one's deep && (mapExtraDataItems == c.mapExtraDataItems) // this one's deep && (llFirstSnapshot == c.llFirstSnapshot) // this one's deep ) @@ -1819,6 +1927,7 @@ void MachineConfigFile::readNetworkAdapters(const xml::ElementNode &elmNetwork, pelmAdapter->getAttributeValue("trace", nic.fTraceEnabled); pelmAdapter->getAttributeValue("tracefile", nic.strTraceFile); pelmAdapter->getAttributeValue("bootPriority", nic.ulBootPriority); + pelmAdapter->getAttributeValue("bandwidthLimit", nic.ulBandwidthLimit); xml::ElementNodesList llNetworkModes; pelmAdapter->getChildElements(llNetworkModes); @@ -1896,7 +2005,7 @@ void MachineConfigFile::readAttachedNetworkMode(const xml::ElementNode &elmMode, NATRule rule; uint32_t port = 0; (*pf)->getAttributeValue("name", rule.strName); - (*pf)->getAttributeValue("proto", rule.u32Proto); + (*pf)->getAttributeValue("proto", (uint32_t&)rule.proto); (*pf)->getAttributeValue("hostip", rule.strHostIP); (*pf)->getAttributeValue("hostport", port); rule.u16HostPort = port; @@ -2044,6 +2153,8 @@ void MachineConfigFile::readAudioAdapter(const xml::ElementNode &elmAudioAdapter aa.controllerType = AudioControllerType_SB16; else if (strTemp == "AC97") aa.controllerType = AudioControllerType_AC97; + else if (strTemp == "HDA") + aa.controllerType = AudioControllerType_HDA; else throw ConfigFileError(this, &elmAudioAdapter, N_("Invalid value '%s' in AudioAdapter/@controller attribute"), strTemp.c_str()); } @@ -2171,6 +2282,7 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, } pelmHwChild->getAttributeValue("hotplug", hw.fCpuHotPlug); + pelmHwChild->getAttributeValue("executionCap", hw.ulCpuExecutionCap); const xml::ElementNode *pelmCPUChild; if (hw.fCpuHotPlug) @@ -2191,7 +2303,7 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExVPID"))) pelmCPUChild->getAttributeValue("enabled", hw.fVPID); if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtForce"))) - pelmCPUChild->getAttributeValue("enabled", hw.fHardwareVirtForce); + pelmCPUChild->getAttributeValue("enabled", hw.fHardwareVirtForce); if (!(pelmCPUChild = pelmHwChild->findChildElement("PAE"))) { @@ -2276,6 +2388,22 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, strHidType.c_str()); } } + else if (pelmHwChild->nameEquals("Chipset")) + { + Utf8Str strChipsetType; + if (pelmHwChild->getAttributeValue("type", strChipsetType)) + { + if (strChipsetType == "PIIX3") + hw.chipsetType = ChipsetType_PIIX3; + else if (strChipsetType == "ICH9") + hw.chipsetType = ChipsetType_ICH9; + else + throw ConfigFileError(this, + pelmHwChild, + N_("Invalid value '%s' in Chipset/@type"), + strChipsetType.c_str()); + } + } else if (pelmHwChild->nameEquals("HPET")) { pelmHwChild->getAttributeValue("enabled", hw.fHpetEnabled); @@ -2337,9 +2465,13 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, } else if (pelmHwChild->nameEquals("RemoteDisplay")) { - pelmHwChild->getAttributeValue("enabled", hw.vrdpSettings.fEnabled); - pelmHwChild->getAttributeValue("port", hw.vrdpSettings.strPort); - pelmHwChild->getAttributeValue("netAddress", hw.vrdpSettings.strNetAddress); + pelmHwChild->getAttributeValue("enabled", hw.vrdeSettings.fEnabled); + + Utf8Str str; + if (pelmHwChild->getAttributeValue("port", str)) + hw.vrdeSettings.mapProperties["TCP/Ports"] = str; + if (pelmHwChild->getAttributeValue("netAddress", str)) + hw.vrdeSettings.mapProperties["TCP/Address"] = str; Utf8Str strAuthType; if (pelmHwChild->getAttributeValue("authType", strAuthType)) @@ -2347,25 +2479,61 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, // settings before 1.3 used lower case so make sure this is case-insensitive strAuthType.toUpper(); if (strAuthType == "NULL") - hw.vrdpSettings.authType = VRDPAuthType_Null; + hw.vrdeSettings.authType = AuthType_Null; else if (strAuthType == "GUEST") - hw.vrdpSettings.authType = VRDPAuthType_Guest; + hw.vrdeSettings.authType = AuthType_Guest; else if (strAuthType == "EXTERNAL") - hw.vrdpSettings.authType = VRDPAuthType_External; + hw.vrdeSettings.authType = AuthType_External; else throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in RemoteDisplay/@authType attribute"), strAuthType.c_str()); } - pelmHwChild->getAttributeValue("authTimeout", hw.vrdpSettings.ulAuthTimeout); - pelmHwChild->getAttributeValue("allowMultiConnection", hw.vrdpSettings.fAllowMultiConnection); - pelmHwChild->getAttributeValue("reuseSingleConnection", hw.vrdpSettings.fReuseSingleConnection); + pelmHwChild->getAttributeValue("authLibrary", hw.vrdeSettings.strAuthLibrary); + pelmHwChild->getAttributeValue("authTimeout", hw.vrdeSettings.ulAuthTimeout); + pelmHwChild->getAttributeValue("allowMultiConnection", hw.vrdeSettings.fAllowMultiConnection); + pelmHwChild->getAttributeValue("reuseSingleConnection", hw.vrdeSettings.fReuseSingleConnection); + /* 3.2 and 4.0 betas, 4.0 has this information in VRDEProperties. */ const xml::ElementNode *pelmVideoChannel; if ((pelmVideoChannel = pelmHwChild->findChildElement("VideoChannel"))) { - pelmVideoChannel->getAttributeValue("enabled", hw.vrdpSettings.fVideoChannel); - pelmVideoChannel->getAttributeValue("quality", hw.vrdpSettings.ulVideoChannelQuality); - hw.vrdpSettings.ulVideoChannelQuality = RT_CLAMP(hw.vrdpSettings.ulVideoChannelQuality, 10, 100); + bool fVideoChannel = false; + pelmVideoChannel->getAttributeValue("enabled", fVideoChannel); + hw.vrdeSettings.mapProperties["VideoChannel/Enabled"] = fVideoChannel? "true": "false"; + + uint32_t ulVideoChannelQuality = 75; + pelmVideoChannel->getAttributeValue("quality", ulVideoChannelQuality); + ulVideoChannelQuality = RT_CLAMP(ulVideoChannelQuality, 10, 100); + char *pszBuffer = NULL; + if (RTStrAPrintf(&pszBuffer, "%d", ulVideoChannelQuality) >= 0) + { + hw.vrdeSettings.mapProperties["VideoChannel/Quality"] = pszBuffer; + RTStrFree(pszBuffer); + } + else + hw.vrdeSettings.mapProperties["VideoChannel/Quality"] = "75"; + } + pelmHwChild->getAttributeValue("VRDEExtPack", hw.vrdeSettings.strVrdeExtPack); + + const xml::ElementNode *pelmProperties = pelmHwChild->findChildElement("VRDEProperties"); + if (pelmProperties != NULL) + { + xml::NodesLoop nl(*pelmProperties); + const xml::ElementNode *pelmProperty; + while ((pelmProperty = nl.forAllNodes())) + { + if (pelmProperty->nameEquals("Property")) + { + /* <Property name="TCP/Ports" value="3000-3002"/> */ + Utf8Str strName, strValue; + if ( ((pelmProperty->getAttributeValue("name", strName))) + && ((pelmProperty->getAttributeValue("value", strValue))) + ) + hw.vrdeSettings.mapProperties[strName] = strValue; + else + throw ConfigFileError(this, pelmProperty, N_("Required VRDE Property/@name or @value attribute is missing")); + } + } } } else if (pelmHwChild->nameEquals("BIOS")) @@ -2461,8 +2629,8 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, else if (pelmHwChild->nameEquals("RTC")) { Utf8Str strLocalOrUTC; - fRTCUseUTC = pelmHwChild->getAttributeValue("localOrUTC", strLocalOrUTC) - && strLocalOrUTC == "UTC"; + machineUserData.fRTCUseUTC = pelmHwChild->getAttributeValue("localOrUTC", strLocalOrUTC) + && strLocalOrUTC == "UTC"; } else if ( (pelmHwChild->nameEquals("UART")) || (pelmHwChild->nameEquals("Uart")) // used before 1.3 @@ -2484,6 +2652,7 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, pelmFolder->getAttributeValue("name", sf.strName); pelmFolder->getAttributeValue("hostPath", sf.strHostPath); pelmFolder->getAttributeValue("writable", sf.fWritable); + pelmFolder->getAttributeValue("autoMount", sf.fAutoMount); hw.llSharedFolders.push_back(sf); } } @@ -2513,6 +2682,7 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, readGuestProperties(*pelmHwChild, hw); else if (pelmHwChild->nameEquals("IO")) { + const xml::ElementNode *pelmBwGroups; const xml::ElementNode *pelmIoChild; if ((pelmIoChild = pelmHwChild->findChildElement("IoCache"))) @@ -2520,9 +2690,33 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware, pelmIoChild->getAttributeValue("enabled", hw.ioSettings.fIoCacheEnabled); pelmIoChild->getAttributeValue("size", hw.ioSettings.ulIoCacheSize); } - if ((pelmIoChild = pelmHwChild->findChildElement("IoBandwidth"))) + + if ((pelmBwGroups = pelmHwChild->findChildElement("BandwidthGroups"))) { - pelmIoChild->getAttributeValue("max", hw.ioSettings.ulIoBandwidthMax); + xml::NodesLoop nl2(*pelmBwGroups, "BandwidthGroup"); + const xml::ElementNode *pelmBandwidthGroup; + while ((pelmBandwidthGroup = nl2.forAllNodes())) + { + BandwidthGroup gr; + Utf8Str strTemp; + + pelmBandwidthGroup->getAttributeValue("name", gr.strName); + + if (pelmBandwidthGroup->getAttributeValue("type", strTemp)) + { + if (strTemp == "Disk") + gr.enmType = BandwidthGroupType_Disk; + else if (strTemp == "Network") + gr.enmType = BandwidthGroupType_Network; + else + throw ConfigFileError(this, pelmBandwidthGroup, N_("Invalid value '%s' in BandwidthGroup/@type attribute"), strTemp.c_str()); + } + else + throw ConfigFileError(this, pelmBandwidthGroup, N_("Missing BandwidthGroup/@type attribute")); + + pelmBandwidthGroup->getAttributeValue("maxMbPerSec", gr.cMaxMbPerSec); + hw.ioSettings.llBandwidthGroups.push_back(gr); + } } } } @@ -2632,6 +2826,11 @@ void MachineConfigFile::readStorageControllers(const xml::ElementNode &elmStorag pelmController->getAttributeValue("Instance", sctl.ulInstance); // default from constructor is 0 + pelmController->getAttributeValue("Bootable", sctl.fBootable); + // default from constructor is true which is true + // for settings below version 1.11 because they allowed only + // one controller per type. + Utf8Str strType; if (!pelmController->getAttributeValue("type", strType)) throw ConfigFileError(this, pelmController, N_("Required StorageController/@type attribute is missing")); @@ -2734,6 +2933,7 @@ void MachineConfigFile::readStorageControllers(const xml::ElementNode &elmStorag if (!pelmAttached->getAttributeValue("device", att.lDevice)) throw ConfigFileError(this, pelmImage, N_("Required AttachedDevice/@device attribute is missing")); + pelmAttached->getAttributeValue("bandwidthGroup", att.strBwGroup); sctl.llAttachedDevices.push_back(att); } } @@ -2867,7 +3067,7 @@ void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot, throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@timeStamp attribute is missing")); parseTimestamp(snap.timestamp, strTemp); - elmSnapshot.getAttributeValue("stateFile", snap.strStateFile); // online snapshots only + elmSnapshot.getAttributeValuePath("stateFile", snap.strStateFile); // online snapshots only // parse Hardware before the other elements because other things depend on it const xml::ElementNode *pelmHardware; @@ -2976,25 +3176,27 @@ void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine) { Utf8Str strUUID; if ( (elmMachine.getAttributeValue("uuid", strUUID)) - && (elmMachine.getAttributeValue("name", strName)) + && (elmMachine.getAttributeValue("name", machineUserData.strName)) ) { parseUUID(uuid, strUUID); - if (!elmMachine.getAttributeValue("nameSync", fNameSync)) - fNameSync = true; + elmMachine.getAttributeValue("nameSync", machineUserData.fNameSync); Utf8Str str; - elmMachine.getAttributeValue("Description", strDescription); + elmMachine.getAttributeValue("Description", machineUserData.strDescription); - elmMachine.getAttributeValue("OSType", strOsType); + elmMachine.getAttributeValue("OSType", machineUserData.strOsType); if (m->sv < SettingsVersion_v1_5) - convertOldOSType_pre1_5(strOsType); + convertOldOSType_pre1_5(machineUserData.strOsType); + + elmMachine.getAttributeValuePath("stateFile", strStateFile); - elmMachine.getAttributeValue("stateFile", strStateFile); if (elmMachine.getAttributeValue("currentSnapshot", str)) parseUUID(uuidCurrentSnapshot, str); - elmMachine.getAttributeValue("snapshotFolder", strSnapshotFolder); + + elmMachine.getAttributeValuePath("snapshotFolder", machineUserData.strSnapshotFolder); + if (!elmMachine.getAttributeValue("currentStateModified", fCurrentStateModified)) fCurrentStateModified = true; if (elmMachine.getAttributeValue("lastStateChange", str)) @@ -3030,18 +3232,34 @@ void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine) llFirstSnapshot.push_back(snap); } else if (pelmMachineChild->nameEquals("Description")) - strDescription = pelmMachineChild->getValue(); + machineUserData.strDescription = pelmMachineChild->getValue(); else if (pelmMachineChild->nameEquals("Teleporter")) { - if (!pelmMachineChild->getAttributeValue("enabled", fTeleporterEnabled)) - fTeleporterEnabled = false; - if (!pelmMachineChild->getAttributeValue("port", uTeleporterPort)) - uTeleporterPort = 0; - if (!pelmMachineChild->getAttributeValue("address", strTeleporterAddress)) - strTeleporterAddress = ""; - if (!pelmMachineChild->getAttributeValue("password", strTeleporterPassword)) - strTeleporterPassword = ""; + pelmMachineChild->getAttributeValue("enabled", machineUserData.fTeleporterEnabled); + pelmMachineChild->getAttributeValue("port", machineUserData.uTeleporterPort); + pelmMachineChild->getAttributeValue("address", machineUserData.strTeleporterAddress); + pelmMachineChild->getAttributeValue("password", machineUserData.strTeleporterPassword); } + else if (pelmMachineChild->nameEquals("FaultTolerance")) + { + Utf8Str strFaultToleranceSate; + if (pelmMachineChild->getAttributeValue("state", strFaultToleranceSate)) + { + if (strFaultToleranceSate == "master") + machineUserData.enmFaultToleranceState = FaultToleranceState_Master; + else + if (strFaultToleranceSate == "standby") + machineUserData.enmFaultToleranceState = FaultToleranceState_Standby; + else + machineUserData.enmFaultToleranceState = FaultToleranceState_Inactive; + } + pelmMachineChild->getAttributeValue("port", machineUserData.uFaultTolerancePort); + pelmMachineChild->getAttributeValue("address", machineUserData.strFaultToleranceAddress); + pelmMachineChild->getAttributeValue("interval", machineUserData.uFaultToleranceInterval); + pelmMachineChild->getAttributeValue("password", machineUserData.strFaultTolerancePassword); + } + else if (pelmMachineChild->nameEquals("MediaRegistry")) + readMediaRegistry(*pelmMachineChild, mediaRegistry); } if (m->sv < SettingsVersion_v1_9) @@ -3086,12 +3304,14 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, if (hw.fSyntheticCpu) pelmCPU->createChild("SyntheticCpu")->setAttribute("enabled", hw.fSyntheticCpu); pelmCPU->setAttribute("count", hw.cCPUs); + if (hw.ulCpuExecutionCap != 100) + pelmCPU->setAttribute("executionCap", hw.ulCpuExecutionCap); + + /* Always save this setting as we have changed the default in 4.0 (on for large memory 64-bit systems). */ + pelmCPU->createChild("HardwareVirtExLargePages")->setAttribute("enabled", hw.fLargePages); - if (hw.fLargePages) - pelmCPU->createChild("HardwareVirtExLargePages")->setAttribute("enabled", hw.fLargePages); - if (m->sv >= SettingsVersion_v1_9) - pelmCPU->createChild("HardwareVirtForce")->setAttribute("enabled", hw.fHardwareVirtForce); + pelmCPU->createChild("HardwareVirtForce")->setAttribute("enabled", hw.fHardwareVirtForce); if (m->sv >= SettingsVersion_v1_10) { @@ -3190,6 +3410,21 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, pelmHpet->setAttribute("enabled", hw.fHpetEnabled); } + if ( (m->sv >= SettingsVersion_v1_11) + ) + { + xml::ElementNode *pelmChipset = pelmHardware->createChild("Chipset"); + const char *pcszChipset; + + switch (hw.chipsetType) + { + case ChipsetType_PIIX3: pcszChipset = "PIIX3"; break; + case ChipsetType_ICH9: pcszChipset = "ICH9"; break; + default: Assert(false); pcszChipset = "PIIX3"; break; + } + pelmChipset->setAttribute("type", pcszChipset); + } + xml::ElementNode *pelmBoot = pelmHardware->createChild("Boot"); for (BootOrderMap::const_iterator it = hw.mapBootOrder.begin(); it != hw.mapBootOrder.end(); @@ -3222,35 +3457,85 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, if (m->sv >= SettingsVersion_v1_8) pelmDisplay->setAttribute("accelerate2DVideo", hw.fAccelerate2DVideo); - xml::ElementNode *pelmVRDP = pelmHardware->createChild("RemoteDisplay"); - pelmVRDP->setAttribute("enabled", hw.vrdpSettings.fEnabled); - Utf8Str strPort = hw.vrdpSettings.strPort; - if (!strPort.length()) - strPort = "3389"; - pelmVRDP->setAttribute("port", strPort); - if (hw.vrdpSettings.strNetAddress.length()) - pelmVRDP->setAttribute("netAddress", hw.vrdpSettings.strNetAddress); + xml::ElementNode *pelmVRDE = pelmHardware->createChild("RemoteDisplay"); + pelmVRDE->setAttribute("enabled", hw.vrdeSettings.fEnabled); + if (m->sv < SettingsVersion_v1_11) + { + /* In VBox 4.0 these attributes are replaced with "Properties". */ + Utf8Str strPort; + StringsMap::const_iterator it = hw.vrdeSettings.mapProperties.find("TCP/Ports"); + if (it != hw.vrdeSettings.mapProperties.end()) + strPort = it->second; + if (!strPort.length()) + strPort = "3389"; + pelmVRDE->setAttribute("port", strPort); + + Utf8Str strAddress; + it = hw.vrdeSettings.mapProperties.find("TCP/Address"); + if (it != hw.vrdeSettings.mapProperties.end()) + strAddress = it->second; + if (strAddress.length()) + pelmVRDE->setAttribute("netAddress", strAddress); + } const char *pcszAuthType; - switch (hw.vrdpSettings.authType) + switch (hw.vrdeSettings.authType) { - case VRDPAuthType_Guest: pcszAuthType = "Guest"; break; - case VRDPAuthType_External: pcszAuthType = "External"; break; - default: /*case VRDPAuthType_Null:*/ pcszAuthType = "Null"; break; + case AuthType_Guest: pcszAuthType = "Guest"; break; + case AuthType_External: pcszAuthType = "External"; break; + default: /*case AuthType_Null:*/ pcszAuthType = "Null"; break; } - pelmVRDP->setAttribute("authType", pcszAuthType); + pelmVRDE->setAttribute("authType", pcszAuthType); - if (hw.vrdpSettings.ulAuthTimeout != 0) - pelmVRDP->setAttribute("authTimeout", hw.vrdpSettings.ulAuthTimeout); - if (hw.vrdpSettings.fAllowMultiConnection) - pelmVRDP->setAttribute("allowMultiConnection", hw.vrdpSettings.fAllowMultiConnection); - if (hw.vrdpSettings.fReuseSingleConnection) - pelmVRDP->setAttribute("reuseSingleConnection", hw.vrdpSettings.fReuseSingleConnection); + if (hw.vrdeSettings.ulAuthTimeout != 0) + pelmVRDE->setAttribute("authTimeout", hw.vrdeSettings.ulAuthTimeout); + if (hw.vrdeSettings.fAllowMultiConnection) + pelmVRDE->setAttribute("allowMultiConnection", hw.vrdeSettings.fAllowMultiConnection); + if (hw.vrdeSettings.fReuseSingleConnection) + pelmVRDE->setAttribute("reuseSingleConnection", hw.vrdeSettings.fReuseSingleConnection); - if (m->sv >= SettingsVersion_v1_10) + if (m->sv == SettingsVersion_v1_10) + { + xml::ElementNode *pelmVideoChannel = pelmVRDE->createChild("VideoChannel"); + + /* In 4.0 videochannel settings were replaced with properties, so look at properties. */ + Utf8Str str; + StringsMap::const_iterator it = hw.vrdeSettings.mapProperties.find("VideoChannel/Enabled"); + if (it != hw.vrdeSettings.mapProperties.end()) + str = it->second; + bool fVideoChannel = RTStrICmp(str.c_str(), "true") == 0 + || RTStrCmp(str.c_str(), "1") == 0; + pelmVideoChannel->setAttribute("enabled", fVideoChannel); + + it = hw.vrdeSettings.mapProperties.find("VideoChannel/Quality"); + if (it != hw.vrdeSettings.mapProperties.end()) + str = it->second; + uint32_t ulVideoChannelQuality = RTStrToUInt32(str.c_str()); /* This returns 0 on invalid string which is ok. */ + if (ulVideoChannelQuality == 0) + ulVideoChannelQuality = 75; + else + ulVideoChannelQuality = RT_CLAMP(ulVideoChannelQuality, 10, 100); + pelmVideoChannel->setAttribute("quality", ulVideoChannelQuality); + } + if (m->sv >= SettingsVersion_v1_11) { - xml::ElementNode *pelmVideoChannel = pelmVRDP->createChild("VideoChannel"); - pelmVideoChannel->setAttribute("enabled", hw.vrdpSettings.fVideoChannel); - pelmVideoChannel->setAttribute("quality", hw.vrdpSettings.ulVideoChannelQuality); + if (hw.vrdeSettings.strAuthLibrary.length()) + pelmVRDE->setAttribute("authLibrary", hw.vrdeSettings.strAuthLibrary); + if (hw.vrdeSettings.strVrdeExtPack.isNotEmpty()) + pelmVRDE->setAttribute("VRDEExtPack", hw.vrdeSettings.strVrdeExtPack); + if (hw.vrdeSettings.mapProperties.size() > 0) + { + xml::ElementNode *pelmProperties = pelmVRDE->createChild("VRDEProperties"); + for (StringsMap::const_iterator it = hw.vrdeSettings.mapProperties.begin(); + it != hw.vrdeSettings.mapProperties.end(); + ++it) + { + const Utf8Str &strName = it->first; + const Utf8Str &strValue = it->second; + xml::ElementNode *pelm = pelmProperties->createChild("Property"); + pelm->setAttribute("name", strName); + pelm->setAttribute("value", strValue); + } + } } xml::ElementNode *pelmBIOS = pelmHardware->createChild("BIOS"); @@ -3342,7 +3627,7 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, pelmUSB->setAttribute("enabled", hw.usbController.fEnabled); pelmUSB->setAttribute("enabledEhci", hw.usbController.fEnabledEHCI); - writeUSBDeviceFilters(*pelmUSB, + buildUSBDeviceFilters(*pelmUSB, hw.usbController.llDeviceFilters, false); // fHostMode @@ -3368,6 +3653,8 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, pelmAdapter->setAttribute("trace", nic.fTraceEnabled); pelmAdapter->setAttribute("tracefile", nic.strTraceFile); } + if (nic.ulBandwidthLimit) + pelmAdapter->setAttribute("bandwidthLimit", nic.ulBandwidthLimit); const char *pcszType; switch (nic.type) @@ -3417,7 +3704,7 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, else { /* m->sv >= SettingsVersion_v1_10 */ - xml::ElementNode *pelmDisabledNode; + xml::ElementNode *pelmDisabledNode= NULL; if (nic.fHasDisabledNAT) pelmDisabledNode = pelmAdapter->createChild("DisabledModes"); if (nic.fHasDisabledNAT) @@ -3478,12 +3765,29 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, } xml::ElementNode *pelmAudio = pelmHardware->createChild("AudioAdapter"); - pelmAudio->setAttribute("controller", (hw.audioAdapter.controllerType == AudioControllerType_SB16) ? "SB16" : "AC97"); + const char *pcszController; + switch (hw.audioAdapter.controllerType) + { + case AudioControllerType_SB16: + pcszController = "SB16"; + break; + case AudioControllerType_HDA: + if (m->sv >= SettingsVersion_v1_11) + { + pcszController = "HDA"; + break; + } + /* fall through */ + case AudioControllerType_AC97: + default: + pcszController = "AC97"; break; + } + pelmAudio->setAttribute("controller", pcszController); - if ( m->sv >= SettingsVersion_v1_10) + if (m->sv >= SettingsVersion_v1_10) { xml::ElementNode *pelmRTC = pelmHardware->createChild("RTC"); - pelmRTC->setAttribute("localOrUTC", fRTCUseUTC ? "UTC" : "local"); + pelmRTC->setAttribute("localOrUTC", machineUserData.fRTCUseUTC ? "UTC" : "local"); } const char *pcszDriver; @@ -3513,6 +3817,7 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, pelmThis->setAttribute("name", sf.strName); pelmThis->setAttribute("hostPath", sf.strHostPath); pelmThis->setAttribute("writable", sf.fWritable); + pelmThis->setAttribute("autoMount", sf.fAutoMount); } xml::ElementNode *pelmClip = pelmHardware->createChild("Clipboard"); @@ -3530,13 +3835,31 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent, { xml::ElementNode *pelmIo = pelmHardware->createChild("IO"); xml::ElementNode *pelmIoCache; - xml::ElementNode *pelmIoBandwidth; pelmIoCache = pelmIo->createChild("IoCache"); pelmIoCache->setAttribute("enabled", hw.ioSettings.fIoCacheEnabled); pelmIoCache->setAttribute("size", hw.ioSettings.ulIoCacheSize); - pelmIoBandwidth = pelmIo->createChild("IoBandwidth"); - pelmIoBandwidth->setAttribute("max", hw.ioSettings.ulIoBandwidthMax); + + if (m->sv >= SettingsVersion_v1_11) + { + xml::ElementNode *pelmBandwidthGroups = pelmIo->createChild("BandwidthGroups"); + for (BandwidthGroupList::const_iterator it = hw.ioSettings.llBandwidthGroups.begin(); + it != hw.ioSettings.llBandwidthGroups.end(); + ++it) + { + const BandwidthGroup &gr = *it; + const char *pcszType; + xml::ElementNode *pelmThis = pelmBandwidthGroups->createChild("BandwidthGroup"); + pelmThis->setAttribute("name", gr.strName); + switch (gr.enmType) + { + case BandwidthGroupType_Network: pcszType = "Network"; break; + default: /* BandwidthGrouptype_Disk */ pcszType = "Disk"; break; + } + pelmThis->setAttribute("type", pcszType); + pelmThis->setAttribute("maxMbPerSec", gr.cMaxMbPerSec); + } + } } xml::ElementNode *pelmGuest = pelmHardware->createChild("Guest"); @@ -3621,7 +3944,7 @@ void MachineConfigFile::buildNetworkXML(NetworkAttachmentType_T mode, pelmPF = pelmNAT->createChild("Forwarding"); if ((*rule).strName.length()) pelmPF->setAttribute("name", (*rule).strName); - pelmPF->setAttribute("proto", (*rule).u32Proto); + pelmPF->setAttribute("proto", (*rule).proto); if ((*rule).strHostIP.length()) pelmPF->setAttribute("hostip", (*rule).strHostIP); if ((*rule).u16HostPort) @@ -3666,7 +3989,7 @@ void MachineConfigFile::buildNetworkXML(NetworkAttachmentType_T mode, * This parameter is ignored unless the settings version is at least v1.9, which * is always the case when this gets called for OVF export. * @param pllElementsWithUuidAttributes If not NULL, must point to a list of element node - * pointers to which we will append all allements that we created here that contain + * pointers to which we will append all elements that we created here that contain * UUID attributes. This allows the OVF export code to quickly replace the internal * media UUIDs with the UUIDs of the media that were exported. */ @@ -3691,8 +4014,7 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent, continue; xml::ElementNode *pelmController = pelmStorageControllers->createChild("StorageController"); - com::Utf8Str name = sc.strName.raw(); - // + com::Utf8Str name = sc.strName; if (m->sv < SettingsVersion_v1_8) { // pre-1.8 settings use shorter controller names, they are @@ -3729,6 +4051,9 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent, if (m->sv >= SettingsVersion_v1_10) pelmController->setAttribute("useHostIOCache", sc.fUseHostIOCache); + if (m->sv >= SettingsVersion_v1_11) + pelmController->setAttribute("Bootable", sc.fBootable); + if (sc.controllerType == StorageControllerType_IntelAhci) { pelmController->setAttribute("IDE0MasterEmulationPort", sc.lIDE0MasterEmulationPort); @@ -3776,6 +4101,9 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent, pelmDevice->setAttribute("port", att.lPort); pelmDevice->setAttribute("device", att.lDevice); + if (att.strBwGroup.length()) + pelmDevice->setAttribute("bandwidthGroup", att.strBwGroup); + // attached image, if any if ( !att.uuid.isEmpty() && ( att.deviceType == DeviceType_HardDisk @@ -3815,7 +4143,7 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, pelmSnapshot->setAttribute("timeStamp", makeString(snap.timestamp)); if (snap.strStateFile.length()) - pelmSnapshot->setAttribute("stateFile", snap.strStateFile); + pelmSnapshot->setAttributePath("stateFile", snap.strStateFile); if (snap.strDescription.length()) pelmSnapshot->createChild("Description")->addContent(snap.strDescription); @@ -3855,9 +4183,15 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, * * In fl, the following flag bits are recognized: * + * -- BuildMachineXML_MediaRegistry: If set, the machine's media registry will + * be written, if present. This is not set when called from OVF because OVF + * has its own variant of a media registry. This flag is ignored unless the + * settings version is at least v1.11 (VirtualBox 4.0). + * * -- BuildMachineXML_IncludeSnapshots: If set, descend into the snapshots tree * of the machine and write out <Snapshot> and possibly more snapshots under - * that, if snapshots are present. Otherwise all snapshots are suppressed. + * that, if snapshots are present. Otherwise all snapshots are suppressed + * (when called from OVF). * * -- BuildMachineXML_WriteVboxVersionAttribute: If set, add a settingsVersion * attribute to the machine tag with the vbox settings version. This is for @@ -3866,10 +4200,14 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent, * * -- BuildMachineXML_SkipRemovableMedia: If set, removable media attachments * (DVDs, floppies) are silently skipped. This is for the OVF export case - * until we support copying ISO and RAW media as well. This flas is ignored + * until we support copying ISO and RAW media as well. This flag is ignored * unless the settings version is at least v1.9, which is always the case * when this gets called for OVF export. * + * -- BuildMachineXML_SuppressSavedState: If set, the Machine/@stateFile + * attribute is never set. This is also for the OVF export case because we + * cannot save states with OVF. + * * @param elmMachine XML <Machine> element to add attributes and elements to. * @param fl Flags. * @param pllElementsWithUuidAttributes pointer to list that should receive UUID elements or NULL; @@ -3884,40 +4222,76 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine, setVersionAttribute(elmMachine); elmMachine.setAttribute("uuid", uuid.toStringCurly()); - elmMachine.setAttribute("name", strName); - if (!fNameSync) - elmMachine.setAttribute("nameSync", fNameSync); - if (strDescription.length()) - elmMachine.createChild("Description")->addContent(strDescription); - elmMachine.setAttribute("OSType", strOsType); - if (strStateFile.length()) - elmMachine.setAttribute("stateFile", strStateFile); + elmMachine.setAttribute("name", machineUserData.strName); + if (!machineUserData.fNameSync) + elmMachine.setAttribute("nameSync", machineUserData.fNameSync); + if (machineUserData.strDescription.length()) + elmMachine.createChild("Description")->addContent(machineUserData.strDescription); + elmMachine.setAttribute("OSType", machineUserData.strOsType); + if ( strStateFile.length() + && !(fl & BuildMachineXML_SuppressSavedState) + ) + elmMachine.setAttributePath("stateFile", strStateFile); if ( (fl & BuildMachineXML_IncludeSnapshots) && !uuidCurrentSnapshot.isEmpty()) elmMachine.setAttribute("currentSnapshot", uuidCurrentSnapshot.toStringCurly()); - if (strSnapshotFolder.length()) - elmMachine.setAttribute("snapshotFolder", strSnapshotFolder); + + if (machineUserData.strSnapshotFolder.length()) + elmMachine.setAttributePath("snapshotFolder", machineUserData.strSnapshotFolder); if (!fCurrentStateModified) elmMachine.setAttribute("currentStateModified", fCurrentStateModified); elmMachine.setAttribute("lastStateChange", makeString(timeLastStateChange)); if (fAborted) elmMachine.setAttribute("aborted", fAborted); if ( m->sv >= SettingsVersion_v1_9 - && ( fTeleporterEnabled - || uTeleporterPort - || !strTeleporterAddress.isEmpty() - || !strTeleporterPassword.isEmpty() + && ( machineUserData.fTeleporterEnabled + || machineUserData.uTeleporterPort + || !machineUserData.strTeleporterAddress.isEmpty() + || !machineUserData.strTeleporterPassword.isEmpty() ) ) { xml::ElementNode *pelmTeleporter = elmMachine.createChild("Teleporter"); - pelmTeleporter->setAttribute("enabled", fTeleporterEnabled); - pelmTeleporter->setAttribute("port", uTeleporterPort); - pelmTeleporter->setAttribute("address", strTeleporterAddress); - pelmTeleporter->setAttribute("password", strTeleporterPassword); + pelmTeleporter->setAttribute("enabled", machineUserData.fTeleporterEnabled); + pelmTeleporter->setAttribute("port", machineUserData.uTeleporterPort); + pelmTeleporter->setAttribute("address", machineUserData.strTeleporterAddress); + pelmTeleporter->setAttribute("password", machineUserData.strTeleporterPassword); } - writeExtraData(elmMachine, mapExtraDataItems); + if ( m->sv >= SettingsVersion_v1_11 + && ( machineUserData.enmFaultToleranceState != FaultToleranceState_Inactive + || machineUserData.uFaultTolerancePort + || machineUserData.uFaultToleranceInterval + || !machineUserData.strFaultToleranceAddress.isEmpty() + ) + ) + { + xml::ElementNode *pelmFaultTolerance = elmMachine.createChild("FaultTolerance"); + switch (machineUserData.enmFaultToleranceState) + { + case FaultToleranceState_Inactive: + pelmFaultTolerance->setAttribute("state", "inactive"); + break; + case FaultToleranceState_Master: + pelmFaultTolerance->setAttribute("state", "master"); + break; + case FaultToleranceState_Standby: + pelmFaultTolerance->setAttribute("state", "standby"); + break; + } + + pelmFaultTolerance->setAttribute("port", machineUserData.uFaultTolerancePort); + pelmFaultTolerance->setAttribute("address", machineUserData.strFaultToleranceAddress); + pelmFaultTolerance->setAttribute("interval", machineUserData.uFaultToleranceInterval); + pelmFaultTolerance->setAttribute("password", machineUserData.strFaultTolerancePassword); + } + + if ( (fl & BuildMachineXML_MediaRegistry) + && (m->sv >= SettingsVersion_v1_11) + ) + buildMediaRegistry(elmMachine, mediaRegistry); + + buildExtraData(elmMachine, mapExtraDataItems); if ( (fl & BuildMachineXML_IncludeSnapshots) && llFirstSnapshot.size()) @@ -4024,7 +4398,7 @@ AudioDriverType_T MachineConfigFile::getHostDefaultAudioDriver() #elif defined(RT_OS_DARWIN) return AudioDriverType_CoreAudio; #elif defined(RT_OS_OS2) - return AudioDriverType_MMP; + return AudioDriverType_MMPM; #elif defined(RT_OS_FREEBSD) return AudioDriverType_OSS; #else @@ -4037,85 +4411,189 @@ AudioDriverType_T MachineConfigFile::getHostDefaultAudioDriver() * This adjusts the settings version in m->sv if incompatible settings require * a settings bump, whereas otherwise we try to preserve the settings version * to avoid breaking compatibility with older versions. + * + * We do the checks in here in reverse order: newest first, oldest last, so + * that we avoid unnecessary checks since some of these are expensive. */ void MachineConfigFile::bumpSettingsVersionIfNeeded() { - // The hardware versions other than "1" requires settings version 1.4 (2.1+). - if ( m->sv < SettingsVersion_v1_4 - && hardwareMachine.strVersion != "1" - ) - m->sv = SettingsVersion_v1_4; + if (m->sv < SettingsVersion_v1_11) + { + // VirtualBox 4.0 adds HD audio, CPU priorities, fault tolerance, + // per-machine media registries, VRDE, JRockitVE and bandwidth gorups. + if ( hardwareMachine.audioAdapter.controllerType == AudioControllerType_HDA + || hardwareMachine.ulCpuExecutionCap != 100 + || machineUserData.enmFaultToleranceState != FaultToleranceState_Inactive + || machineUserData.uFaultTolerancePort + || machineUserData.uFaultToleranceInterval + || !machineUserData.strFaultToleranceAddress.isEmpty() + || mediaRegistry.llHardDisks.size() + || mediaRegistry.llDvdImages.size() + || mediaRegistry.llFloppyImages.size() + || !hardwareMachine.vrdeSettings.strVrdeExtPack.isEmpty() + || !hardwareMachine.vrdeSettings.strAuthLibrary.isEmpty() + || machineUserData.strOsType == "JRockitVE" + || hardwareMachine.ioSettings.llBandwidthGroups.size() + ) + m->sv = SettingsVersion_v1_11; + } - // "accelerate 2d video" requires settings version 1.8 - if ( (m->sv < SettingsVersion_v1_8) - && (hardwareMachine.fAccelerate2DVideo) - ) - m->sv = SettingsVersion_v1_8; + if (m->sv < SettingsVersion_v1_10) + { + /* If the properties contain elements other than "TCP/Ports" and "TCP/Address", + * then increase the version to at least VBox 3.2, which can have video channel properties. + */ + unsigned cOldProperties = 0; + + StringsMap::const_iterator it = hardwareMachine.vrdeSettings.mapProperties.find("TCP/Ports"); + if (it != hardwareMachine.vrdeSettings.mapProperties.end()) + cOldProperties++; + it = hardwareMachine.vrdeSettings.mapProperties.find("TCP/Address"); + if (it != hardwareMachine.vrdeSettings.mapProperties.end()) + cOldProperties++; + + if (hardwareMachine.vrdeSettings.mapProperties.size() != cOldProperties) + m->sv = SettingsVersion_v1_10; + } - // all the following require settings version 1.9 - if ( (m->sv < SettingsVersion_v1_9) - && ( (hardwareMachine.firmwareType >= FirmwareType_EFI) - || (hardwareMachine.fHardwareVirtExclusive != HWVIRTEXCLUSIVEDEFAULT) - || fTeleporterEnabled - || uTeleporterPort - || !strTeleporterAddress.isEmpty() - || !strTeleporterPassword.isEmpty() - || !hardwareMachine.uuid.isEmpty() - ) - ) - m->sv = SettingsVersion_v1_9; + if (m->sv < SettingsVersion_v1_11) + { + /* If the properties contain elements other than "TCP/Ports", "TCP/Address", + * "VideoChannel/Enabled" and "VideoChannel/Quality" then increase the version to VBox 4.0. + */ + unsigned cOldProperties = 0; + + StringsMap::const_iterator it = hardwareMachine.vrdeSettings.mapProperties.find("TCP/Ports"); + if (it != hardwareMachine.vrdeSettings.mapProperties.end()) + cOldProperties++; + it = hardwareMachine.vrdeSettings.mapProperties.find("TCP/Address"); + if (it != hardwareMachine.vrdeSettings.mapProperties.end()) + cOldProperties++; + it = hardwareMachine.vrdeSettings.mapProperties.find("VideoChannel/Enabled"); + if (it != hardwareMachine.vrdeSettings.mapProperties.end()) + cOldProperties++; + it = hardwareMachine.vrdeSettings.mapProperties.find("VideoChannel/Quality"); + if (it != hardwareMachine.vrdeSettings.mapProperties.end()) + cOldProperties++; + + if (hardwareMachine.vrdeSettings.mapProperties.size() != cOldProperties) + m->sv = SettingsVersion_v1_11; + } - // settings version 1.9 is also required if there is not exactly one DVD + // settings version 1.9 is required if there is not exactly one DVD // or more than one floppy drive present or the DVD is not at the secondary // master; this check is a bit more complicated // // settings version 1.10 is required if the host cache should be disabled - if (m->sv < SettingsVersion_v1_10) + // + // settings version 1.11 is required for bandwidth limits and if more than + // one controller of each type is present. + if (m->sv < SettingsVersion_v1_11) { + // count attached DVDs and floppies (only if < v1.9) size_t cDVDs = 0; size_t cFloppies = 0; - // need to run thru all the storage controllers to figure this out + // count storage controllers (if < v1.11) + size_t cSata = 0; + size_t cScsiLsi = 0; + size_t cScsiBuslogic = 0; + size_t cSas = 0; + size_t cIde = 0; + size_t cFloppy = 0; + + // need to run thru all the storage controllers and attached devices to figure this out for (StorageControllersList::const_iterator it = storageMachine.llStorageControllers.begin(); it != storageMachine.llStorageControllers.end(); ++it) { const StorageController &sctl = *it; + + // count storage controllers of each type; 1.11 is required if more than one + // controller of one type is present + switch (sctl.storageBus) + { + case StorageBus_IDE: + cIde++; + break; + case StorageBus_SATA: + cSata++; + break; + case StorageBus_SAS: + cSas++; + break; + case StorageBus_SCSI: + if (sctl.controllerType == StorageControllerType_LsiLogic) + cScsiLsi++; + else + cScsiBuslogic++; + break; + case StorageBus_Floppy: + cFloppy++; + break; + default: + // Do nothing + break; + } + + if ( cSata > 1 + || cScsiLsi > 1 + || cScsiBuslogic > 1 + || cSas > 1 + || cIde > 1 + || cFloppy > 1) + { + m->sv = SettingsVersion_v1_11; + break; // abort the loop -- we will not raise the version further + } + for (AttachedDevicesList::const_iterator it2 = sctl.llAttachedDevices.begin(); it2 != sctl.llAttachedDevices.end(); ++it2) { - // we can only write the StorageController/@Instance attribute with v1.9 - if (sctl.ulInstance != 0) - { - if (m->sv < SettingsVersion_v1_9) - m->sv = SettingsVersion_v1_9; - } - const AttachedDevice &att = *it2; - if (att.deviceType == DeviceType_DVD) + + // Bandwidth limitations are new in VirtualBox 4.0 (1.11) + if (m->sv < SettingsVersion_v1_11) { - if ( (sctl.storageBus != StorageBus_IDE) // DVD at bus other than DVD? - || (att.lPort != 1) // DVDs not at secondary master? - || (att.lDevice != 0) - ) + if (att.strBwGroup.length() != 0) { - if (m->sv < SettingsVersion_v1_9) - m->sv = SettingsVersion_v1_9; + m->sv = SettingsVersion_v1_11; + break; // abort the loop -- we will not raise the version further } - - ++cDVDs; } - else if (att.deviceType == DeviceType_Floppy) - ++cFloppies; - // Disabling the host IO cache requires settings version 1.10 - if (!sctl.fUseHostIOCache) - { + // disabling the host IO cache requires settings version 1.10 + if ( (m->sv < SettingsVersion_v1_10) + && (!sctl.fUseHostIOCache) + ) m->sv = SettingsVersion_v1_10; - break; /* abort the loop -- we will not raise the version further */ + + // we can only write the StorageController/@Instance attribute with v1.9 + if ( (m->sv < SettingsVersion_v1_9) + && (sctl.ulInstance != 0) + ) + m->sv = SettingsVersion_v1_9; + + if (m->sv < SettingsVersion_v1_9) + { + if (att.deviceType == DeviceType_DVD) + { + if ( (sctl.storageBus != StorageBus_IDE) // DVD at bus other than DVD? + || (att.lPort != 1) // DVDs not at secondary master? + || (att.lDevice != 0) + ) + m->sv = SettingsVersion_v1_9; + + ++cDVDs; + } + else if (att.deviceType == DeviceType_Floppy) + ++cFloppies; } } + + if (m->sv >= SettingsVersion_v1_11) + break; // abort the loop -- we will not raise the version further } // VirtualBox before 3.1 had zero or one floppy and exactly one DVD, @@ -4128,76 +4606,98 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded() m->sv = SettingsVersion_v1_9; } - // VirtualBox 3.2 adds support for CPU hotplug, RTC timezone control, HID type and HPET - if ( m->sv < SettingsVersion_v1_10 - && ( fRTCUseUTC - || hardwareMachine.fCpuHotPlug - || hardwareMachine.pointingHidType != PointingHidType_PS2Mouse - || hardwareMachine.keyboardHidType != KeyboardHidType_PS2Keyboard - || hardwareMachine.fHpetEnabled - ) - ) - m->sv = SettingsVersion_v1_10; - - // VirtualBox 3.2 adds support for page fusion - if ( m->sv < SettingsVersion_v1_10 - && hardwareMachine.fPageFusionEnabled - ) - m->sv = SettingsVersion_v1_10; + // VirtualBox 3.2: Check for non default I/O settings + if (m->sv < SettingsVersion_v1_10) + { + if ( (hardwareMachine.ioSettings.fIoCacheEnabled != true) + || (hardwareMachine.ioSettings.ulIoCacheSize != 5) + // and page fusion + || (hardwareMachine.fPageFusionEnabled) + // and CPU hotplug, RTC timezone control, HID type and HPET + || machineUserData.fRTCUseUTC + || hardwareMachine.fCpuHotPlug + || hardwareMachine.pointingHidType != PointingHidType_PS2Mouse + || hardwareMachine.keyboardHidType != KeyboardHidType_PS2Keyboard + || hardwareMachine.fHpetEnabled + ) + m->sv = SettingsVersion_v1_10; + } - // VirtualBox 3.2 adds NAT and boot priority to the NIC config in Main. + // VirtualBox 3.2 adds NAT and boot priority to the NIC config in Main if (m->sv < SettingsVersion_v1_10) { NetworkAdaptersList::const_iterator netit; for (netit = hardwareMachine.llNetworkAdapters.begin(); - netit != hardwareMachine.llNetworkAdapters.end(); ++netit) + netit != hardwareMachine.llNetworkAdapters.end(); + ++netit) { - if ( netit->fEnabled - && netit->mode == NetworkAttachmentType_NAT - && ( netit->nat.u32Mtu != 0 - || netit->nat.u32SockRcv != 0 - || netit->nat.u32SockSnd != 0 - || netit->nat.u32TcpRcv != 0 - || netit->nat.u32TcpSnd != 0 - || !netit->nat.fDnsPassDomain - || netit->nat.fDnsProxy - || netit->nat.fDnsUseHostResolver - || netit->nat.fAliasLog - || netit->nat.fAliasProxyOnly - || netit->nat.fAliasUseSamePorts - || netit->nat.strTftpPrefix.length() - || netit->nat.strTftpBootFile.length() - || netit->nat.strTftpNextServer.length() - || netit->nat.llRules.size()) - ) + if ( (m->sv < SettingsVersion_v1_11) + && (netit->ulBandwidthLimit) + ) { - m->sv = SettingsVersion_v1_10; + /* New in VirtualBox 4.0 */ + m->sv = SettingsVersion_v1_11; break; } - if ( netit->fEnabled - && netit->ulBootPriority != 0) + else if ( (m->sv < SettingsVersion_v1_10) + && (netit->fEnabled) + && (netit->mode == NetworkAttachmentType_NAT) + && ( netit->nat.u32Mtu != 0 + || netit->nat.u32SockRcv != 0 + || netit->nat.u32SockSnd != 0 + || netit->nat.u32TcpRcv != 0 + || netit->nat.u32TcpSnd != 0 + || !netit->nat.fDnsPassDomain + || netit->nat.fDnsProxy + || netit->nat.fDnsUseHostResolver + || netit->nat.fAliasLog + || netit->nat.fAliasProxyOnly + || netit->nat.fAliasUseSamePorts + || netit->nat.strTftpPrefix.length() + || netit->nat.strTftpBootFile.length() + || netit->nat.strTftpNextServer.length() + || netit->nat.llRules.size() + ) + ) { m->sv = SettingsVersion_v1_10; - break; + // no break because we still might need v1.11 above + } + else if ( (m->sv < SettingsVersion_v1_10) + && (netit->fEnabled) + && (netit->ulBootPriority != 0) + ) + { + m->sv = SettingsVersion_v1_10; + // no break because we still might need v1.11 above } } } - // Check for non default I/O settings and bump the settings version. - if (m->sv < SettingsVersion_v1_10) - { - if ( hardwareMachine.ioSettings.fIoCacheEnabled != true - || hardwareMachine.ioSettings.ulIoCacheSize != 5 - || hardwareMachine.ioSettings.ulIoBandwidthMax != 0) - m->sv = SettingsVersion_v1_10; - } - // VirtualBox 3.2 adds support for VRDP video channel - if ( m->sv < SettingsVersion_v1_10 - && ( hardwareMachine.vrdpSettings.fVideoChannel + // all the following require settings version 1.9 + if ( (m->sv < SettingsVersion_v1_9) + && ( (hardwareMachine.firmwareType >= FirmwareType_EFI) + || (hardwareMachine.fHardwareVirtExclusive != HWVIRTEXCLUSIVEDEFAULT) + || machineUserData.fTeleporterEnabled + || machineUserData.uTeleporterPort + || !machineUserData.strTeleporterAddress.isEmpty() + || !machineUserData.strTeleporterPassword.isEmpty() + || !hardwareMachine.uuid.isEmpty() ) + ) + m->sv = SettingsVersion_v1_9; + + // "accelerate 2d video" requires settings version 1.8 + if ( (m->sv < SettingsVersion_v1_8) + && (hardwareMachine.fAccelerate2DVideo) ) - m->sv = SettingsVersion_v1_10; + m->sv = SettingsVersion_v1_8; + // The hardware versions other than "1" requires settings version 1.4 (2.1+). + if ( m->sv < SettingsVersion_v1_4 + && hardwareMachine.strVersion != "1" + ) + m->sv = SettingsVersion_v1_4; } /** @@ -4219,7 +4719,8 @@ void MachineConfigFile::write(const com::Utf8Str &strFilename) xml::ElementNode *pelmMachine = m->pelmRoot->createChild("Machine"); buildMachineXML(*pelmMachine, - MachineConfigFile::BuildMachineXML_IncludeSnapshots, + MachineConfigFile::BuildMachineXML_IncludeSnapshots + | MachineConfigFile::BuildMachineXML_MediaRegistry, // but not BuildMachineXML_WriteVboxVersionAttribute NULL); /* pllElementsWithUuidAttributes */ @@ -4236,4 +4737,3 @@ void MachineConfigFile::write(const com::Utf8Str &strFilename) throw; } } - diff --git a/src/VBox/Main/xml/VirtualBox-settings-common.xsd b/src/VBox/Main/xml/VirtualBox-settings-common.xsd index 1a2f89581..1c602d322 100644 --- a/src/VBox/Main/xml/VirtualBox-settings-common.xsd +++ b/src/VBox/Main/xml/VirtualBox-settings-common.xsd @@ -203,11 +203,12 @@ <xsd:enumeration value="QNX"/> <xsd:enumeration value="MacOS"/> <xsd:enumeration value="MacOS_64"/> + <xsd:enumeration value="JRockitVE"/> </xsd:restriction> </xsd:simpleType> -<xsd:simpleType name="TVRDPAuthType"> +<xsd:simpleType name="TAuthType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="Null"/> <xsd:enumeration value="Guest"/> @@ -306,6 +307,9 @@ <xsd:enumeration value="Normal"/> <xsd:enumeration value="Immutable"/> <xsd:enumeration value="Writethrough"/> + <xsd:enumeration value="Shareable"/> + <xsd:enumeration value="Readonly"/> + <xsd:enumeration value="MultiAttach"/> </xsd:restriction> </xsd:simpleType> </xsd:attribute> @@ -355,8 +359,9 @@ <xsd:attribute name="defaultMachineFolder" type="TLocalFile"/> <xsd:attribute name="defaultHardDiskFolder" type="TLocalFile"/> <xsd:attribute name="defaultHardDiskFormat" type="TNonEmptyString"/> - <xsd:attribute name="remoteDisplayAuthLibrary" type="TLocalFile"/> + <xsd:attribute name="VRDEAuthLibrary" type="TLocalFile"/> <xsd:attribute name="webServiceAuthLibrary" type="TLocalFile"/> + <xsd:attribute name="defaultVRDELibrary" type="TLocalFile"/> <xsd:attribute name="HWVirtExEnabled" type="xsd:boolean"/> <xsd:attribute name="LogHistoryCount" type="xsd:unsignedInt" default="3"/> </xsd:complexType> @@ -539,9 +544,7 @@ <xsd:complexType name="TRemoteDisplay"> <xsd:attribute name="enabled" type="xsd:boolean" use="required"/> - <xsd:attribute name="port" type="xsd:token" default="0"/> - <xsd:attribute name="netAddress" type="xsd:token" default=""/> - <xsd:attribute name="authType" type="TVRDPAuthType" default="Null"/> + <xsd:attribute name="authType" type="TAuthType" default="Null"/> <xsd:attribute name="authTimeout" type="xsd:unsignedInt" default="5000"/> <xsd:attribute name="allowMultiConnection" type="xsd:boolean" default="false"/> <xsd:attribute name="reuseSingleConnection" type="xsd:boolean" default="false"/> diff --git a/src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd b/src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd index 98857c1fe..d08048e9b 100644 --- a/src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd +++ b/src/VBox/Main/xml/VirtualBox-settings-freebsd.xsd @@ -35,7 +35,7 @@ <!-- this includes a computed VirtualBox element definition that contains - a proper 'version' attribute constraint (e.g. recent verison number + a proper 'version' attribute constraint (e.g. recent version number and platform suffix) --> <xsd:include schemaLocation="VirtualBox-settings-root.xsd"/> diff --git a/src/VBox/Main/xml/VirtualBox-settings-linux.xsd b/src/VBox/Main/xml/VirtualBox-settings-linux.xsd index e16e61d0d..20fad8095 100644 --- a/src/VBox/Main/xml/VirtualBox-settings-linux.xsd +++ b/src/VBox/Main/xml/VirtualBox-settings-linux.xsd @@ -35,7 +35,7 @@ <!-- this includes a computed VirtualBox element definition that contains - a proper 'version' attribute constraint (e.g. recent verison number + a proper 'version' attribute constraint (e.g. recent version number and platform suffix) --> <xsd:include schemaLocation="VirtualBox-settings-root.xsd"/> diff --git a/src/VBox/Main/xml/VirtualBox-settings-macosx.xsd b/src/VBox/Main/xml/VirtualBox-settings-macosx.xsd index cfa20d6fa..5d2d08d6d 100644 --- a/src/VBox/Main/xml/VirtualBox-settings-macosx.xsd +++ b/src/VBox/Main/xml/VirtualBox-settings-macosx.xsd @@ -35,7 +35,7 @@ <!-- this includes a computed VirtualBox element definition that contains - a proper 'version' attribute constraint (e.g. recent verison number + a proper 'version' attribute constraint (e.g. recent version number and platform suffix) --> <xsd:include schemaLocation="VirtualBox-settings-root.xsd"/> diff --git a/src/VBox/Main/xml/VirtualBox-settings-os2.xsd b/src/VBox/Main/xml/VirtualBox-settings-os2.xsd index 10938e246..6f53836c4 100644 --- a/src/VBox/Main/xml/VirtualBox-settings-os2.xsd +++ b/src/VBox/Main/xml/VirtualBox-settings-os2.xsd @@ -36,7 +36,7 @@ <!-- this includes a computed VirtualBox element definition that contains - a proper 'version' attribute constraint (e.g. recent verison number + a proper 'version' attribute constraint (e.g. recent version number and platform suffix) --> <xsd:include schemaLocation="VirtualBox-settings-root.xsd"/> diff --git a/src/VBox/Main/xml/VirtualBox-settings-solaris.xsd b/src/VBox/Main/xml/VirtualBox-settings-solaris.xsd index 3863a04e0..6af3eac98 100644 --- a/src/VBox/Main/xml/VirtualBox-settings-solaris.xsd +++ b/src/VBox/Main/xml/VirtualBox-settings-solaris.xsd @@ -35,7 +35,7 @@ <!-- this includes a computed VirtualBox element definition that contains - a proper 'version' attribute constraint (e.g. recent verison number + a proper 'version' attribute constraint (e.g. recent version number and platform suffix) --> <xsd:include schemaLocation="VirtualBox-settings-root.xsd"/> diff --git a/src/VBox/Main/xml/VirtualBox-settings-windows.xsd b/src/VBox/Main/xml/VirtualBox-settings-windows.xsd index 7011104b9..09efa71b5 100644 --- a/src/VBox/Main/xml/VirtualBox-settings-windows.xsd +++ b/src/VBox/Main/xml/VirtualBox-settings-windows.xsd @@ -35,7 +35,7 @@ <!-- this includes a computed VirtualBox element definition that contains - a proper 'version' attribute constraint (e.g. recent verison number + a proper 'version' attribute constraint (e.g. recent version number and platform suffix) --> <xsd:include schemaLocation="VirtualBox-settings-root.xsd"/> diff --git a/src/VBox/Main/xml/ovfreader.cpp b/src/VBox/Main/xml/ovfreader.cpp index 3167d45a9..963249701 100644 --- a/src/VBox/Main/xml/ovfreader.cpp +++ b/src/VBox/Main/xml/ovfreader.cpp @@ -1,4 +1,4 @@ -/* $Id: ovfreader.cpp $ */ +/* $Id: ovfreader.cpp 34501 2010-11-30 12:30:30Z vboxsync $ */ /** @file * * OVF reader declarations. Depends only on IPRT, including the iprt::MiniString @@ -25,11 +25,29 @@ using namespace ovf; //////////////////////////////////////////////////////////////////////////////// // -// OVF reader implemenation +// OVF reader implementation // //////////////////////////////////////////////////////////////////////////////// /** + * Constructor. This parses the given XML file out of the memory. Throws lots of exceptions + * on XML or OVF invalidity. + * @param pvBuf the memory buffer to parse + * @param cbSize the size of the memory buffer + * @param path path to a filename for error messages. + */ +OVFReader::OVFReader(const void *pvBuf, size_t cbSize, const MiniString &path) + : m_strPath(path) +{ + xml::XmlMemParser parser; + parser.read(pvBuf, cbSize, + m_strPath, + m_doc); + /* Start the parsing */ + parse(); +} + +/** * Constructor. This opens the given XML file and parses it. Throws lots of exceptions * on XML or OVF invalidity. * @param path @@ -40,7 +58,12 @@ OVFReader::OVFReader(const MiniString &path) xml::XmlFileParser parser; parser.read(m_strPath, m_doc); + /* Start the parsing */ + parse(); +} +void OVFReader::parse() +{ const xml::ElementNode *pRootElem = m_doc.getRootElement(); if ( !pRootElem || strcmp(pRootElem->getName(), "Envelope") @@ -751,6 +774,11 @@ void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSy const xml::ElementNode *pelmCIMOSDescription; if ((pelmCIMOSDescription = pelmThis->findChildElement("Description"))) vsys.strCimosDesc = pelmCIMOSDescription->getValue(); + + const xml::ElementNode *pelmVBoxOSType; + if ((pelmVBoxOSType = pelmThis->findChildElement("vbox", // namespace + "OSType"))) // element name + vsys.strTypeVbox = pelmVBoxOSType->getValue(); } else if ( (!strcmp(pcszElemName, "AnnotationSection")) || (!strcmp(pcszTypeAttr, "ovf:AnnotationSection_Type")) |
