VirtualBox

source: vbox/trunk/src/VBox/Main/xml/Settings.cpp@ 91187

最後變更 在這個檔案從91187是 90828,由 vboxsync 提交於 4 年 前

Main: bugref:1909: Added API localization

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Date Revision Author Id
檔案大小: 332.7 KB
 
1/* $Id: Settings.cpp 90828 2021-08-24 09:44:46Z vboxsync $ */
2/** @file
3 * Settings File Manipulation API.
4 *
5 * Two classes, MainConfigFile and MachineConfigFile, represent the VirtualBox.xml and
6 * machine XML files. They share a common ancestor class, ConfigFileBase, which shares
7 * functionality such as talking to the XML back-end classes and settings version management.
8 *
9 * The code can read all VirtualBox settings files version 1.3 and higher. That version was
10 * written by VirtualBox 2.0. It can write settings version 1.7 (used by VirtualBox 2.2 and
11 * 3.0) and 1.9 (used by VirtualBox 3.1) and newer ones obviously.
12 *
13 * The settings versions enum is defined in src/VBox/Main/idl/VirtualBox.xidl. To introduce
14 * a new settings version (should be necessary at most once per VirtualBox major release,
15 * if at all), add a new SettingsVersion value to that enum and grep for the previously
16 * highest value to see which code in here needs adjusting.
17 *
18 * Certainly ConfigFileBase::ConfigFileBase() will. Change VBOX_XML_VERSION below as well.
19 * VBOX_XML_VERSION does not have to be changed if the settings for a default VM do not
20 * touch newly introduced attributes or tags. It has the benefit that older VirtualBox
21 * versions do not trigger their "newer" code path.
22 *
23 * Once a new settings version has been added, these are the rules for introducing a new
24 * setting: If an XML element or attribute or value is introduced that was not present in
25 * previous versions, then settings version checks need to be introduced. See the
26 * SettingsVersion enumeration in src/VBox/Main/idl/VirtualBox.xidl for details about which
27 * version was used when.
28 *
29 * The settings versions checks are necessary because since version 3.1, VirtualBox no longer
30 * automatically converts XML settings files but only if necessary, that is, if settings are
31 * present that the old format does not support. If we write an element or attribute to a
32 * settings file of an older version, then an old VirtualBox (before 3.1) will attempt to
33 * validate it with XML schema, and that will certainly fail.
34 *
35 * So, to introduce a new setting:
36 *
37 * 1) Make sure the constructor of corresponding settings structure has a proper default.
38 *
39 * 2) In the settings reader method, try to read the setting; if it's there, great, if not,
40 * the default value will have been set by the constructor. The rule is to be tolerant
41 * here.
42 *
43 * 3) In MachineConfigFile::bumpSettingsVersionIfNeeded(), check if the new setting has
44 * a non-default value (i.e. that differs from the constructor). If so, bump the
45 * settings version to the current version so the settings writer (4) can write out
46 * the non-default value properly.
47 *
48 * So far a corresponding method for MainConfigFile has not been necessary since there
49 * have been no incompatible changes yet.
50 *
51 * 4) In the settings writer method, write the setting _only_ if the current settings
52 * version (stored in m->sv) is high enough. That is, for VirtualBox 4.0, write it
53 * only if (m->sv >= SettingsVersion_v1_11).
54 *
55 * 5) You _must_ update xml/VirtualBox-settings.xsd to contain the new tags and attributes.
56 * Check that settings file from before and after your change are validating properly.
57 * Use "kmk testvalidsettings", it should not find any files which don't validate.
58 */
59
60/*
61 * Copyright (C) 2007-2020 Oracle Corporation
62 *
63 * This file is part of VirtualBox Open Source Edition (OSE), as
64 * available from http://www.alldomusa.eu.org. This file is free software;
65 * you can redistribute it and/or modify it under the terms of the GNU
66 * General Public License (GPL) as published by the Free Software
67 * Foundation, in version 2 as it comes in the "COPYING" file of the
68 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
69 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
70 */
71
72#define LOG_GROUP LOG_GROUP_MAIN
73#include "VBox/com/string.h"
74#include "VBox/settings.h"
75#include <iprt/base64.h>
76#include <iprt/cpp/lock.h>
77#include <iprt/cpp/xml.h>
78#include <iprt/ctype.h>
79#include <iprt/err.h>
80#include <iprt/file.h>
81#include <iprt/ldr.h>
82#include <iprt/process.h>
83#include <iprt/stream.h>
84#include <iprt/uri.h>
85
86// generated header
87#include "SchemaDefs.h"
88
89#include "HashedPw.h"
90#include "LoggingNew.h"
91
92using namespace com;
93using namespace settings;
94
95////////////////////////////////////////////////////////////////////////////////
96//
97// Defines
98//
99////////////////////////////////////////////////////////////////////////////////
100
101/** VirtualBox XML settings namespace */
102#define VBOX_XML_NAMESPACE "http://www.alldomusa.eu.org/"
103
104/** VirtualBox XML schema location (relative URI) */
105#define VBOX_XML_SCHEMA "VirtualBox-settings.xsd"
106
107/** VirtualBox XML settings version number substring ("x.y") */
108#define VBOX_XML_VERSION "1.12"
109
110/** VirtualBox OVF settings import default version number substring ("x.y").
111 *
112 * Think twice before changing this, as all VirtualBox versions before 5.1
113 * wrote the settings version when exporting, but totally ignored it on
114 * importing (while it should have been a mandatory attribute), so 3rd party
115 * software out there creates OVF files with the VirtualBox specific settings
116 * but lacking the version attribute. This shouldn't happen any more, but
117 * breaking existing OVF files isn't nice. */
118#define VBOX_XML_IMPORT_VERSION "1.15"
119
120/** VirtualBox XML settings version platform substring */
121#if defined (RT_OS_DARWIN)
122# define VBOX_XML_PLATFORM "macosx"
123#elif defined (RT_OS_FREEBSD)
124# define VBOX_XML_PLATFORM "freebsd"
125#elif defined (RT_OS_LINUX)
126# define VBOX_XML_PLATFORM "linux"
127#elif defined (RT_OS_NETBSD)
128# define VBOX_XML_PLATFORM "netbsd"
129#elif defined (RT_OS_OPENBSD)
130# define VBOX_XML_PLATFORM "openbsd"
131#elif defined (RT_OS_OS2)
132# define VBOX_XML_PLATFORM "os2"
133#elif defined (RT_OS_SOLARIS)
134# define VBOX_XML_PLATFORM "solaris"
135#elif defined (RT_OS_WINDOWS)
136# define VBOX_XML_PLATFORM "windows"
137#else
138# error Unsupported platform!
139#endif
140
141/** VirtualBox XML settings full version string ("x.y-platform") */
142#define VBOX_XML_VERSION_FULL VBOX_XML_VERSION "-" VBOX_XML_PLATFORM
143
144/** VirtualBox OVF import default settings full version string ("x.y-platform") */
145#define VBOX_XML_IMPORT_VERSION_FULL VBOX_XML_IMPORT_VERSION "-" VBOX_XML_PLATFORM
146
147////////////////////////////////////////////////////////////////////////////////
148//
149// Internal data
150//
151////////////////////////////////////////////////////////////////////////////////
152
153/**
154 * Opaque data structore for ConfigFileBase (only declared
155 * in header, defined only here).
156 */
157
158struct ConfigFileBase::Data
159{
160 Data()
161 : pDoc(NULL),
162 pelmRoot(NULL),
163 sv(SettingsVersion_Null),
164 svRead(SettingsVersion_Null)
165 {}
166
167 ~Data()
168 {
169 cleanup();
170 }
171
172 RTCString strFilename;
173 bool fFileExists;
174
175 xml::Document *pDoc;
176 xml::ElementNode *pelmRoot;
177
178 com::Utf8Str strSettingsVersionFull; // e.g. "1.7-linux"
179 SettingsVersion_T sv; // e.g. SettingsVersion_v1_7
180
181 SettingsVersion_T svRead; // settings version that the original file had when it was read,
182 // or SettingsVersion_Null if none
183
184 void copyFrom(const Data &d)
185 {
186 strFilename = d.strFilename;
187 fFileExists = d.fFileExists;
188 strSettingsVersionFull = d.strSettingsVersionFull;
189 sv = d.sv;
190 svRead = d.svRead;
191 }
192
193 void cleanup()
194 {
195 if (pDoc)
196 {
197 delete pDoc;
198 pDoc = NULL;
199 pelmRoot = NULL;
200 }
201 }
202};
203
204/**
205 * Private exception class (not in the header file) that makes
206 * throwing xml::LogicError instances easier. That class is public
207 * and should be caught by client code.
208 */
209class settings::ConfigFileError : public xml::LogicError
210{
211public:
212 ConfigFileError(const ConfigFileBase *file,
213 const xml::Node *pNode,
214 const char *pcszFormat, ...)
215 : xml::LogicError()
216 {
217 va_list args;
218 va_start(args, pcszFormat);
219 Utf8Str strWhat(pcszFormat, args);
220 va_end(args);
221
222 Utf8Str strLine;
223 if (pNode)
224 strLine = Utf8StrFmt(" (line %RU32)", pNode->getLineNumber());
225
226 const char *pcsz = strLine.c_str();
227 Utf8StrFmt str(N_("Error in %s%s -- %s"),
228 file->m->strFilename.c_str(),
229 (pcsz) ? pcsz : "",
230 strWhat.c_str());
231
232 setWhat(str.c_str());
233 }
234};
235
236////////////////////////////////////////////////////////////////////////////////
237//
238// ConfigFileBase
239//
240////////////////////////////////////////////////////////////////////////////////
241
242/**
243 * Constructor. Allocates the XML internals, parses the XML file if
244 * pstrFilename is != NULL and reads the settings version from it.
245 * @param pstrFilename
246 */
247ConfigFileBase::ConfigFileBase(const com::Utf8Str *pstrFilename)
248 : m(new Data)
249{
250 m->fFileExists = false;
251
252 if (pstrFilename)
253 {
254 try
255 {
256 // reading existing settings file:
257 m->strFilename = *pstrFilename;
258
259 xml::XmlFileParser parser;
260 m->pDoc = new xml::Document;
261 parser.read(*pstrFilename,
262 *m->pDoc);
263
264 m->fFileExists = true;
265
266 m->pelmRoot = m->pDoc->getRootElement();
267 if (!m->pelmRoot || !m->pelmRoot->nameEquals("VirtualBox"))
268 throw ConfigFileError(this, m->pelmRoot, N_("Root element in VirtualBox settings files must be \"VirtualBox\""));
269
270 if (!(m->pelmRoot->getAttributeValue("version", m->strSettingsVersionFull)))
271 throw ConfigFileError(this, m->pelmRoot, N_("Required VirtualBox/@version attribute is missing"));
272
273 LogRel(("Loading settings file \"%s\" with version \"%s\"\n", m->strFilename.c_str(), m->strSettingsVersionFull.c_str()));
274
275 m->sv = parseVersion(m->strSettingsVersionFull, m->pelmRoot);
276
277 // remember the settings version we read in case it gets upgraded later,
278 // so we know when to make backups
279 m->svRead = m->sv;
280 }
281 catch(...)
282 {
283 /*
284 * The destructor is not called when an exception is thrown in the constructor,
285 * so we have to do the cleanup here.
286 */
287 delete m;
288 m = NULL;
289 throw;
290 }
291 }
292 else
293 {
294 // creating new settings file:
295 m->strSettingsVersionFull = VBOX_XML_VERSION_FULL;
296 m->sv = SettingsVersion_v1_12;
297 }
298}
299
300ConfigFileBase::ConfigFileBase(const ConfigFileBase &other)
301 : m(new Data)
302{
303 copyBaseFrom(other);
304 m->strFilename = "";
305 m->fFileExists = false;
306}
307
308/**
309 * Clean up.
310 */
311ConfigFileBase::~ConfigFileBase()
312{
313 if (m)
314 {
315 delete m;
316 m = NULL;
317 }
318}
319
320/**
321 * Helper function to convert a MediaType enum value into string from.
322 * @param t
323 */
324/*static*/
325const char *ConfigFileBase::stringifyMediaType(MediaType t)
326{
327 switch (t)
328 {
329 case HardDisk:
330 return "hard disk";
331 case DVDImage:
332 return "DVD";
333 case FloppyImage:
334 return "floppy";
335 default:
336 AssertMsgFailed(("media type %d\n", t));
337 return "UNKNOWN";
338 }
339}
340
341/**
342 * Helper function that parses a full version number.
343 *
344 * Allow future versions but fail if file is older than 1.6. Throws on errors.
345 * @returns settings version
346 * @param strVersion
347 * @param pElm
348 */
349SettingsVersion_T ConfigFileBase::parseVersion(const Utf8Str &strVersion, const xml::ElementNode *pElm)
350{
351 SettingsVersion_T sv = SettingsVersion_Null;
352 if (strVersion.length() > 3)
353 {
354 const char *pcsz = strVersion.c_str();
355
356 uint32_t uMajor = 0;
357 char ch;
358 while ( (ch = *pcsz)
359 && RT_C_IS_DIGIT(ch) )
360 {
361 uMajor *= 10;
362 uMajor += (uint32_t)(ch - '0');
363 ++pcsz;
364 }
365
366 uint32_t uMinor = 0;
367 if (ch == '.')
368 {
369 pcsz++;
370 while ( (ch = *pcsz)
371 && RT_C_IS_DIGIT(ch))
372 {
373 uMinor *= 10;
374 uMinor += (ULONG)(ch - '0');
375 ++pcsz;
376 }
377 }
378
379 if (uMajor == 1)
380 {
381 if (uMinor == 3)
382 sv = SettingsVersion_v1_3;
383 else if (uMinor == 4)
384 sv = SettingsVersion_v1_4;
385 else if (uMinor == 5)
386 sv = SettingsVersion_v1_5;
387 else if (uMinor == 6)
388 sv = SettingsVersion_v1_6;
389 else if (uMinor == 7)
390 sv = SettingsVersion_v1_7;
391 else if (uMinor == 8)
392 sv = SettingsVersion_v1_8;
393 else if (uMinor == 9)
394 sv = SettingsVersion_v1_9;
395 else if (uMinor == 10)
396 sv = SettingsVersion_v1_10;
397 else if (uMinor == 11)
398 sv = SettingsVersion_v1_11;
399 else if (uMinor == 12)
400 sv = SettingsVersion_v1_12;
401 else if (uMinor == 13)
402 sv = SettingsVersion_v1_13;
403 else if (uMinor == 14)
404 sv = SettingsVersion_v1_14;
405 else if (uMinor == 15)
406 sv = SettingsVersion_v1_15;
407 else if (uMinor == 16)
408 sv = SettingsVersion_v1_16;
409 else if (uMinor == 17)
410 sv = SettingsVersion_v1_17;
411 else if (uMinor == 18)
412 sv = SettingsVersion_v1_18;
413 else if (uMinor == 19)
414 sv = SettingsVersion_v1_19;
415 else if (uMinor > 19)
416 sv = SettingsVersion_Future;
417 }
418 else if (uMajor > 1)
419 sv = SettingsVersion_Future;
420
421 Log(("Parsed settings version %d.%d to enum value %d\n", uMajor, uMinor, sv));
422 }
423
424 if (sv == SettingsVersion_Null)
425 throw ConfigFileError(this, pElm, N_("Cannot handle settings version '%s'"), strVersion.c_str());
426
427 return sv;
428}
429
430/**
431 * Helper function that parses a UUID in string form into
432 * a com::Guid item. Accepts UUIDs both with and without
433 * "{}" brackets. Throws on errors.
434 * @param guid
435 * @param strUUID
436 * @param pElm
437 */
438void ConfigFileBase::parseUUID(Guid &guid,
439 const Utf8Str &strUUID,
440 const xml::ElementNode *pElm) const
441{
442 guid = strUUID.c_str();
443 if (guid.isZero())
444 throw ConfigFileError(this, pElm, N_("UUID \"%s\" has zero format"), strUUID.c_str());
445 else if (!guid.isValid())
446 throw ConfigFileError(this, pElm, N_("UUID \"%s\" has invalid format"), strUUID.c_str());
447}
448
449/**
450 * Parses the given string in str and attempts to treat it as an ISO
451 * date/time stamp to put into timestamp. Throws on errors.
452 * @param timestamp
453 * @param str
454 * @param pElm
455 */
456void ConfigFileBase::parseTimestamp(RTTIMESPEC &timestamp,
457 const com::Utf8Str &str,
458 const xml::ElementNode *pElm) const
459{
460 const char *pcsz = str.c_str();
461 // yyyy-mm-ddThh:mm:ss
462 // "2009-07-10T11:54:03Z"
463 // 01234567890123456789
464 // 1
465 if (str.length() > 19)
466 {
467 // timezone must either be unspecified or 'Z' for UTC
468 if ( (pcsz[19])
469 && (pcsz[19] != 'Z')
470 )
471 throw ConfigFileError(this, pElm, N_("Cannot handle ISO timestamp '%s': is not UTC date"), str.c_str());
472
473 int32_t yyyy;
474 uint32_t mm, dd, hh, min, secs;
475 if ( (pcsz[4] == '-')
476 && (pcsz[7] == '-')
477 && (pcsz[10] == 'T')
478 && (pcsz[13] == ':')
479 && (pcsz[16] == ':')
480 )
481 {
482 int rc;
483 if ( (RT_SUCCESS(rc = RTStrToInt32Ex(pcsz, NULL, 0, &yyyy)))
484 // could theoretically be negative but let's assume that nobody
485 // created virtual machines before the Christian era
486 && (RT_SUCCESS(rc = RTStrToUInt32Ex(pcsz + 5, NULL, 0, &mm)))
487 && (RT_SUCCESS(rc = RTStrToUInt32Ex(pcsz + 8, NULL, 0, &dd)))
488 && (RT_SUCCESS(rc = RTStrToUInt32Ex(pcsz + 11, NULL, 0, &hh)))
489 && (RT_SUCCESS(rc = RTStrToUInt32Ex(pcsz + 14, NULL, 0, &min)))
490 && (RT_SUCCESS(rc = RTStrToUInt32Ex(pcsz + 17, NULL, 0, &secs)))
491 )
492 {
493 RTTIME time =
494 {
495 yyyy,
496 (uint8_t)mm,
497 0,
498 0,
499 (uint8_t)dd,
500 (uint8_t)hh,
501 (uint8_t)min,
502 (uint8_t)secs,
503 0,
504 RTTIME_FLAGS_TYPE_UTC,
505 0
506 };
507 if (RTTimeNormalize(&time))
508 if (RTTimeImplode(&timestamp, &time))
509 return;
510 }
511
512 throw ConfigFileError(this, pElm, N_("Cannot parse ISO timestamp '%s': runtime error, %Rra"), str.c_str(), rc);
513 }
514
515 throw ConfigFileError(this, pElm, N_("Cannot parse ISO timestamp '%s': invalid format"), str.c_str());
516 }
517}
518
519/**
520 * Helper function that parses a Base64 formatted string into a binary blob.
521 * @param binary
522 * @param str
523 * @param pElm
524 */
525void ConfigFileBase::parseBase64(IconBlob &binary,
526 const Utf8Str &str,
527 const xml::ElementNode *pElm) const
528{
529#define DECODE_STR_MAX _1M
530 const char* psz = str.c_str();
531 ssize_t cbOut = RTBase64DecodedSize(psz, NULL);
532 if (cbOut > DECODE_STR_MAX)
533 throw ConfigFileError(this, pElm, N_("Base64 encoded data too long (%d > %d)"), cbOut, DECODE_STR_MAX);
534 else if (cbOut < 0)
535 throw ConfigFileError(this, pElm, N_("Base64 encoded data '%s' invalid"), psz);
536 binary.resize((size_t)cbOut);
537 int vrc = VINF_SUCCESS;
538 if (cbOut)
539 vrc = RTBase64Decode(psz, &binary.front(), (size_t)cbOut, NULL, NULL);
540 if (RT_FAILURE(vrc))
541 {
542 binary.resize(0);
543 throw ConfigFileError(this, pElm, N_("Base64 encoded data could not be decoded (%Rrc)"), vrc);
544 }
545}
546
547/**
548 * Helper to create a string for a RTTIMESPEC for writing out ISO timestamps.
549 * @param stamp
550 * @return
551 */
552com::Utf8Str ConfigFileBase::stringifyTimestamp(const RTTIMESPEC &stamp) const
553{
554 RTTIME time;
555 if (!RTTimeExplode(&time, &stamp))
556 throw ConfigFileError(this, NULL, N_("Timespec %lld ms is invalid"), RTTimeSpecGetMilli(&stamp));
557
558 return Utf8StrFmt("%04u-%02u-%02uT%02u:%02u:%02uZ",
559 time.i32Year, time.u8Month, time.u8MonthDay,
560 time.u8Hour, time.u8Minute, time.u8Second);
561}
562
563/**
564 * Helper to create a base64 encoded string out of a binary blob.
565 * @param str
566 * @param binary
567 * @throws std::bad_alloc and ConfigFileError
568 */
569void ConfigFileBase::toBase64(com::Utf8Str &str, const IconBlob &binary) const
570{
571 size_t cb = binary.size();
572 if (cb > 0)
573 {
574 size_t cchOut = RTBase64EncodedLength(cb);
575 str.reserve(cchOut + 1);
576 int vrc = RTBase64Encode(&binary.front(), cb, str.mutableRaw(), str.capacity(), NULL);
577 if (RT_FAILURE(vrc))
578 throw ConfigFileError(this, NULL, N_("Failed to convert binary data to base64 format (%Rrc)"), vrc);
579 str.jolt();
580 }
581}
582
583/**
584 * Helper method to read in an ExtraData subtree and stores its contents
585 * in the given map of extradata items. Used for both main and machine
586 * extradata (MainConfigFile and MachineConfigFile).
587 * @param elmExtraData
588 * @param map
589 */
590void ConfigFileBase::readExtraData(const xml::ElementNode &elmExtraData,
591 StringsMap &map)
592{
593 xml::NodesLoop nlLevel4(elmExtraData);
594 const xml::ElementNode *pelmExtraDataItem;
595 while ((pelmExtraDataItem = nlLevel4.forAllNodes()))
596 {
597 if (pelmExtraDataItem->nameEquals("ExtraDataItem"))
598 {
599 // <ExtraDataItem name="GUI/LastWindowPostion" value="97,88,981,858"/>
600 Utf8Str strName, strValue;
601 if ( pelmExtraDataItem->getAttributeValue("name", strName)
602 && pelmExtraDataItem->getAttributeValue("value", strValue) )
603 map[strName] = strValue;
604 else
605 throw ConfigFileError(this, pelmExtraDataItem, N_("Required ExtraDataItem/@name or @value attribute is missing"));
606 }
607 }
608}
609
610/**
611 * Reads \<USBDeviceFilter\> entries from under the given elmDeviceFilters node and
612 * stores them in the given linklist. This is in ConfigFileBase because it's used
613 * from both MainConfigFile (for host filters) and MachineConfigFile (for machine
614 * filters).
615 * @param elmDeviceFilters
616 * @param ll
617 */
618void ConfigFileBase::readUSBDeviceFilters(const xml::ElementNode &elmDeviceFilters,
619 USBDeviceFiltersList &ll)
620{
621 xml::NodesLoop nl1(elmDeviceFilters, "DeviceFilter");
622 const xml::ElementNode *pelmLevel4Child;
623 while ((pelmLevel4Child = nl1.forAllNodes()))
624 {
625 USBDeviceFilter flt;
626 flt.action = USBDeviceFilterAction_Ignore;
627 Utf8Str strAction;
628 if ( pelmLevel4Child->getAttributeValue("name", flt.strName)
629 && pelmLevel4Child->getAttributeValue("active", flt.fActive))
630 {
631 if (!pelmLevel4Child->getAttributeValue("vendorId", flt.strVendorId))
632 pelmLevel4Child->getAttributeValue("vendorid", flt.strVendorId); // used before 1.3
633 if (!pelmLevel4Child->getAttributeValue("productId", flt.strProductId))
634 pelmLevel4Child->getAttributeValue("productid", flt.strProductId); // used before 1.3
635 pelmLevel4Child->getAttributeValue("revision", flt.strRevision);
636 pelmLevel4Child->getAttributeValue("manufacturer", flt.strManufacturer);
637 pelmLevel4Child->getAttributeValue("product", flt.strProduct);
638 if (!pelmLevel4Child->getAttributeValue("serialNumber", flt.strSerialNumber))
639 pelmLevel4Child->getAttributeValue("serialnumber", flt.strSerialNumber); // used before 1.3
640 pelmLevel4Child->getAttributeValue("port", flt.strPort);
641
642 // the next 2 are irrelevant for host USB objects
643 pelmLevel4Child->getAttributeValue("remote", flt.strRemote);
644 pelmLevel4Child->getAttributeValue("maskedInterfaces", flt.ulMaskedInterfaces);
645
646 // action is only used with host USB objects
647 if (pelmLevel4Child->getAttributeValue("action", strAction))
648 {
649 if (strAction == "Ignore")
650 flt.action = USBDeviceFilterAction_Ignore;
651 else if (strAction == "Hold")
652 flt.action = USBDeviceFilterAction_Hold;
653 else
654 throw ConfigFileError(this, pelmLevel4Child, N_("Invalid value '%s' in DeviceFilter/@action attribute"), strAction.c_str());
655 }
656
657 ll.push_back(flt);
658 }
659 }
660}
661
662/**
663 * Reads a media registry entry from the main VirtualBox.xml file.
664 *
665 * Whereas the current media registry code is fairly straightforward, it was quite a mess
666 * with settings format before 1.4 (VirtualBox 2.0 used settings format 1.3). The elements
667 * in the media registry were much more inconsistent, and different elements were used
668 * depending on the type of device and image.
669 *
670 * @param t
671 * @param elmMedium
672 * @param med
673 */
674void ConfigFileBase::readMediumOne(MediaType t,
675 const xml::ElementNode &elmMedium,
676 Medium &med)
677{
678 // <HardDisk uuid="{5471ecdb-1ddb-4012-a801-6d98e226868b}" location="/mnt/innotek-unix/vdis/Windows XP.vdi" format="VDI" type="Normal">
679
680 Utf8Str strUUID;
681 if (!elmMedium.getAttributeValue("uuid", strUUID))
682 throw ConfigFileError(this, &elmMedium, N_("Required %s/@uuid attribute is missing"), elmMedium.getName());
683
684 parseUUID(med.uuid, strUUID, &elmMedium);
685
686 bool fNeedsLocation = true;
687
688 if (t == HardDisk)
689 {
690 if (m->sv < SettingsVersion_v1_4)
691 {
692 // here the system is:
693 // <HardDisk uuid="{....}" type="normal">
694 // <VirtualDiskImage filePath="/path/to/xxx.vdi"/>
695 // </HardDisk>
696
697 fNeedsLocation = false;
698 bool fNeedsFilePath = true;
699 const xml::ElementNode *pelmImage;
700 if ((pelmImage = elmMedium.findChildElement("VirtualDiskImage")))
701 med.strFormat = "VDI";
702 else if ((pelmImage = elmMedium.findChildElement("VMDKImage")))
703 med.strFormat = "VMDK";
704 else if ((pelmImage = elmMedium.findChildElement("VHDImage")))
705 med.strFormat = "VHD";
706 else if ((pelmImage = elmMedium.findChildElement("ISCSIHardDisk")))
707 {
708 med.strFormat = "iSCSI";
709
710 fNeedsFilePath = false;
711 // location is special here: current settings specify an "iscsi://user@server:port/target/lun"
712 // string for the location and also have several disk properties for these, whereas this used
713 // to be hidden in several sub-elements before 1.4, so compose a location string and set up
714 // the properties:
715 med.strLocation = "iscsi://";
716 Utf8Str strUser, strServer, strPort, strTarget, strLun;
717 if (pelmImage->getAttributeValue("userName", strUser))
718 {
719 med.strLocation.append(strUser);
720 med.strLocation.append("@");
721 }
722 Utf8Str strServerAndPort;
723 if (pelmImage->getAttributeValue("server", strServer))
724 {
725 strServerAndPort = strServer;
726 }
727 if (pelmImage->getAttributeValue("port", strPort))
728 {
729 if (strServerAndPort.length())
730 strServerAndPort.append(":");
731 strServerAndPort.append(strPort);
732 }
733 med.strLocation.append(strServerAndPort);
734 if (pelmImage->getAttributeValue("target", strTarget))
735 {
736 med.strLocation.append("/");
737 med.strLocation.append(strTarget);
738 }
739 if (pelmImage->getAttributeValue("lun", strLun))
740 {
741 med.strLocation.append("/");
742 med.strLocation.append(strLun);
743 }
744
745 if (strServer.length() && strPort.length())
746 med.properties["TargetAddress"] = strServerAndPort;
747 if (strTarget.length())
748 med.properties["TargetName"] = strTarget;
749 if (strUser.length())
750 med.properties["InitiatorUsername"] = strUser;
751 Utf8Str strPassword;
752 if (pelmImage->getAttributeValue("password", strPassword))
753 med.properties["InitiatorSecret"] = strPassword;
754 if (strLun.length())
755 med.properties["LUN"] = strLun;
756 }
757 else if ((pelmImage = elmMedium.findChildElement("CustomHardDisk")))
758 {
759 fNeedsFilePath = false;
760 fNeedsLocation = true;
761 // also requires @format attribute, which will be queried below
762 }
763 else
764 throw ConfigFileError(this, &elmMedium, N_("Required %s/VirtualDiskImage element is missing"), elmMedium.getName());
765
766 if (fNeedsFilePath)
767 {
768 if (!(pelmImage->getAttributeValuePath("filePath", med.strLocation)))
769 throw ConfigFileError(this, &elmMedium, N_("Required %s/@filePath attribute is missing"), elmMedium.getName());
770 }
771 }
772
773 if (med.strFormat.isEmpty()) // not set with 1.4 format above, or 1.4 Custom format?
774 if (!elmMedium.getAttributeValue("format", med.strFormat))
775 throw ConfigFileError(this, &elmMedium, N_("Required %s/@format attribute is missing"), elmMedium.getName());
776
777 if (!elmMedium.getAttributeValue("autoReset", med.fAutoReset))
778 med.fAutoReset = false;
779
780 Utf8Str strType;
781 if (elmMedium.getAttributeValue("type", strType))
782 {
783 // pre-1.4 used lower case, so make this case-insensitive
784 strType.toUpper();
785 if (strType == "NORMAL")
786 med.hdType = MediumType_Normal;
787 else if (strType == "IMMUTABLE")
788 med.hdType = MediumType_Immutable;
789 else if (strType == "WRITETHROUGH")
790 med.hdType = MediumType_Writethrough;
791 else if (strType == "SHAREABLE")
792 med.hdType = MediumType_Shareable;
793 else if (strType == "READONLY")
794 med.hdType = MediumType_Readonly;
795 else if (strType == "MULTIATTACH")
796 med.hdType = MediumType_MultiAttach;
797 else
798 throw ConfigFileError(this, &elmMedium, N_("HardDisk/@type attribute must be one of Normal, Immutable, Writethrough, Shareable, Readonly or MultiAttach"));
799 }
800 }
801 else
802 {
803 if (m->sv < SettingsVersion_v1_4)
804 {
805 // DVD and floppy images before 1.4 had "src" attribute instead of "location"
806 if (!elmMedium.getAttributeValue("src", med.strLocation))
807 throw ConfigFileError(this, &elmMedium, N_("Required %s/@src attribute is missing"), elmMedium.getName());
808
809 fNeedsLocation = false;
810 }
811
812 if (!elmMedium.getAttributeValue("format", med.strFormat))
813 {
814 // DVD and floppy images before 1.11 had no format attribute. assign the default.
815 med.strFormat = "RAW";
816 }
817
818 if (t == DVDImage)
819 med.hdType = MediumType_Readonly;
820 else if (t == FloppyImage)
821 med.hdType = MediumType_Writethrough;
822 }
823
824 if (fNeedsLocation)
825 // current files and 1.4 CustomHardDisk elements must have a location attribute
826 if (!elmMedium.getAttributeValue("location", med.strLocation))
827 throw ConfigFileError(this, &elmMedium, N_("Required %s/@location attribute is missing"), elmMedium.getName());
828
829 // 3.2 builds added Description as an attribute, read it silently
830 // and write it back as an element starting with 5.1.26
831 elmMedium.getAttributeValue("Description", med.strDescription);
832
833 xml::NodesLoop nlMediumChildren(elmMedium);
834 const xml::ElementNode *pelmMediumChild;
835 while ((pelmMediumChild = nlMediumChildren.forAllNodes()))
836 {
837 if (pelmMediumChild->nameEquals("Description"))
838 med.strDescription = pelmMediumChild->getValue();
839 else if (pelmMediumChild->nameEquals("Property"))
840 {
841 // handle medium properties
842 Utf8Str strPropName, strPropValue;
843 if ( pelmMediumChild->getAttributeValue("name", strPropName)
844 && pelmMediumChild->getAttributeValue("value", strPropValue) )
845 med.properties[strPropName] = strPropValue;
846 else
847 throw ConfigFileError(this, pelmMediumChild, N_("Required HardDisk/Property/@name or @value attribute is missing"));
848 }
849 }
850}
851
852/**
853 * Reads a media registry entry from the main VirtualBox.xml file and recurses
854 * into children where applicable.
855 *
856 * @param t
857 * @param depth
858 * @param elmMedium
859 * @param med
860 */
861void ConfigFileBase::readMedium(MediaType t,
862 uint32_t depth,
863 const xml::ElementNode &elmMedium, // HardDisk node if root; if recursing,
864 // child HardDisk node or DiffHardDisk node for pre-1.4
865 Medium &med) // medium settings to fill out
866{
867 if (depth > SETTINGS_MEDIUM_DEPTH_MAX)
868 throw ConfigFileError(this, &elmMedium, N_("Maximum medium tree depth of %u exceeded"), SETTINGS_MEDIUM_DEPTH_MAX);
869
870 // Do not inline this method call, as the purpose of having this separate
871 // is to save on stack size. Less local variables are the key for reaching
872 // deep recursion levels with small stack (XPCOM/g++ without optimization).
873 readMediumOne(t, elmMedium, med);
874
875 if (t != HardDisk)
876 return;
877
878 // recurse to handle children
879 MediaList &llSettingsChildren = med.llChildren;
880 xml::NodesLoop nl2(elmMedium, m->sv >= SettingsVersion_v1_4 ? "HardDisk" : "DiffHardDisk");
881 const xml::ElementNode *pelmHDChild;
882 while ((pelmHDChild = nl2.forAllNodes()))
883 {
884 // recurse with this element and put the child at the end of the list.
885 // XPCOM has very small stack, avoid big local variables and use the
886 // list element.
887 llSettingsChildren.push_back(Medium::Empty);
888 readMedium(t,
889 depth + 1,
890 *pelmHDChild,
891 llSettingsChildren.back());
892 }
893}
894
895/**
896 * Reads in the entire \<MediaRegistry\> chunk and stores its media in the lists
897 * of the given MediaRegistry structure.
898 *
899 * This is used in both MainConfigFile and MachineConfigFile since starting with
900 * VirtualBox 4.0, we can have media registries in both.
901 *
902 * For pre-1.4 files, this gets called with the \<DiskRegistry\> chunk instead.
903 *
904 * @param elmMediaRegistry
905 * @param mr
906 */
907void ConfigFileBase::readMediaRegistry(const xml::ElementNode &elmMediaRegistry,
908 MediaRegistry &mr)
909{
910 xml::NodesLoop nl1(elmMediaRegistry);
911 const xml::ElementNode *pelmChild1;
912 while ((pelmChild1 = nl1.forAllNodes()))
913 {
914 MediaType t = Error;
915 if (pelmChild1->nameEquals("HardDisks"))
916 t = HardDisk;
917 else if (pelmChild1->nameEquals("DVDImages"))
918 t = DVDImage;
919 else if (pelmChild1->nameEquals("FloppyImages"))
920 t = FloppyImage;
921 else
922 continue;
923
924 xml::NodesLoop nl2(*pelmChild1);
925 const xml::ElementNode *pelmMedium;
926 while ((pelmMedium = nl2.forAllNodes()))
927 {
928 if ( t == HardDisk
929 && (pelmMedium->nameEquals("HardDisk")))
930 {
931 mr.llHardDisks.push_back(Medium::Empty);
932 readMedium(t, 1, *pelmMedium, mr.llHardDisks.back());
933 }
934 else if ( t == DVDImage
935 && (pelmMedium->nameEquals("Image")))
936 {
937 mr.llDvdImages.push_back(Medium::Empty);
938 readMedium(t, 1, *pelmMedium, mr.llDvdImages.back());
939 }
940 else if ( t == FloppyImage
941 && (pelmMedium->nameEquals("Image")))
942 {
943 mr.llFloppyImages.push_back(Medium::Empty);
944 readMedium(t, 1, *pelmMedium, mr.llFloppyImages.back());
945 }
946 }
947 }
948}
949
950/**
951 * This is common version for reading NAT port forward rule in per-_machine's_adapter_ and
952 * per-network approaches.
953 * Note: this function doesn't in fill given list from xml::ElementNodesList, because there is conflicting
954 * declaration in ovmfreader.h.
955 */
956void ConfigFileBase::readNATForwardRulesMap(const xml::ElementNode &elmParent, NATRulesMap &mapRules)
957{
958 xml::ElementNodesList plstRules;
959 elmParent.getChildElements(plstRules, "Forwarding");
960 for (xml::ElementNodesList::iterator pf = plstRules.begin(); pf != plstRules.end(); ++pf)
961 {
962 NATRule rule;
963 uint32_t port = 0;
964 (*pf)->getAttributeValue("name", rule.strName);
965 (*pf)->getAttributeValue("proto", (uint32_t&)rule.proto);
966 (*pf)->getAttributeValue("hostip", rule.strHostIP);
967 (*pf)->getAttributeValue("hostport", port);
968 rule.u16HostPort = (uint16_t)port;
969 (*pf)->getAttributeValue("guestip", rule.strGuestIP);
970 (*pf)->getAttributeValue("guestport", port);
971 rule.u16GuestPort = (uint16_t)port;
972 mapRules.insert(std::make_pair(rule.strName, rule));
973 }
974}
975
976void ConfigFileBase::readNATLoopbacks(const xml::ElementNode &elmParent, NATLoopbackOffsetList &llLoopbacks)
977{
978 xml::ElementNodesList plstLoopbacks;
979 elmParent.getChildElements(plstLoopbacks, "Loopback4");
980 for (xml::ElementNodesList::iterator lo = plstLoopbacks.begin();
981 lo != plstLoopbacks.end(); ++lo)
982 {
983 NATHostLoopbackOffset loopback;
984 (*lo)->getAttributeValue("address", loopback.strLoopbackHostAddress);
985 (*lo)->getAttributeValue("offset", (uint32_t&)loopback.u32Offset);
986 llLoopbacks.push_back(loopback);
987 }
988}
989
990
991/**
992 * Adds a "version" attribute to the given XML element with the
993 * VirtualBox settings version (e.g. "1.10-linux"). Used by
994 * the XML format for the root element and by the OVF export
995 * for the vbox:Machine element.
996 * @param elm
997 */
998void ConfigFileBase::setVersionAttribute(xml::ElementNode &elm)
999{
1000 const char *pcszVersion = NULL;
1001 switch (m->sv)
1002 {
1003 case SettingsVersion_v1_8:
1004 pcszVersion = "1.8";
1005 break;
1006
1007 case SettingsVersion_v1_9:
1008 pcszVersion = "1.9";
1009 break;
1010
1011 case SettingsVersion_v1_10:
1012 pcszVersion = "1.10";
1013 break;
1014
1015 case SettingsVersion_v1_11:
1016 pcszVersion = "1.11";
1017 break;
1018
1019 case SettingsVersion_v1_12:
1020 pcszVersion = "1.12";
1021 break;
1022
1023 case SettingsVersion_v1_13:
1024 pcszVersion = "1.13";
1025 break;
1026
1027 case SettingsVersion_v1_14:
1028 pcszVersion = "1.14";
1029 break;
1030
1031 case SettingsVersion_v1_15:
1032 pcszVersion = "1.15";
1033 break;
1034
1035 case SettingsVersion_v1_16:
1036 pcszVersion = "1.16";
1037 break;
1038
1039 case SettingsVersion_v1_17:
1040 pcszVersion = "1.17";
1041 break;
1042
1043 case SettingsVersion_v1_18:
1044 pcszVersion = "1.18";
1045 break;
1046
1047 case SettingsVersion_v1_19:
1048 pcszVersion = "1.19";
1049 break;
1050
1051 default:
1052 // catch human error: the assertion below will trigger in debug
1053 // or dbgopt builds, so hopefully this will get noticed sooner in
1054 // the future, because it's easy to forget top update something.
1055 AssertMsg(m->sv <= SettingsVersion_v1_7, ("Settings.cpp: unexpected settings version %d, unhandled future version?\n", m->sv));
1056 // silently upgrade if this is less than 1.7 because that's the oldest we can write
1057 if (m->sv <= SettingsVersion_v1_7)
1058 {
1059 pcszVersion = "1.7";
1060 m->sv = SettingsVersion_v1_7;
1061 }
1062 else
1063 {
1064 // This is reached for SettingsVersion_Future and forgotten
1065 // settings version after SettingsVersion_v1_7, which should
1066 // not happen (see assertion above). Set the version to the
1067 // latest known version, to minimize loss of information, but
1068 // as we can't predict the future we have to use some format
1069 // we know, and latest should be the best choice. Note that
1070 // for "forgotten settings" this may not be the best choice,
1071 // but as it's an omission of someone who changed this file
1072 // it's the only generic possibility.
1073 pcszVersion = "1.19";
1074 m->sv = SettingsVersion_v1_19;
1075 }
1076 break;
1077 }
1078
1079 m->strSettingsVersionFull = Utf8StrFmt("%s-%s",
1080 pcszVersion,
1081 VBOX_XML_PLATFORM); // e.g. "linux"
1082 elm.setAttribute("version", m->strSettingsVersionFull);
1083}
1084
1085
1086/**
1087 * Creates a special backup file in case there is a version
1088 * bump, so that it is possible to go back to the previous
1089 * state. This is done only once (not for every settings
1090 * version bump), when the settings version is newer than
1091 * the version read from the config file. Must be called
1092 * before ConfigFileBase::createStubDocument, because that
1093 * method may alter information which this method needs.
1094 */
1095void ConfigFileBase::specialBackupIfFirstBump()
1096{
1097 // Since this gets called before the XML document is actually written out,
1098 // this is where we must check whether we're upgrading the settings version
1099 // and need to make a backup, so the user can go back to an earlier
1100 // VirtualBox version and recover his old settings files.
1101 if ( (m->svRead != SettingsVersion_Null) // old file exists?
1102 && (m->svRead < m->sv) // we're upgrading?
1103 )
1104 {
1105 // compose new filename: strip off trailing ".xml"/".vbox"
1106 Utf8Str strFilenameNew;
1107 Utf8Str strExt = ".xml";
1108 if (m->strFilename.endsWith(".xml"))
1109 strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 4);
1110 else if (m->strFilename.endsWith(".vbox"))
1111 {
1112 strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 5);
1113 strExt = ".vbox";
1114 }
1115
1116 // and append something like "-1.3-linux.xml"
1117 strFilenameNew.append("-");
1118 strFilenameNew.append(m->strSettingsVersionFull); // e.g. "1.3-linux"
1119 strFilenameNew.append(strExt); // .xml for main config, .vbox for machine config
1120
1121 // Copying the file cannot be avoided, as doing tricks with renaming
1122 // causes trouble on OS X with aliases (which follow the rename), and
1123 // on all platforms there is a risk of "losing" the VM config when
1124 // running out of space, as a rename here couldn't be rolled back.
1125 // Ignoring all errors besides running out of space is intentional, as
1126 // we don't want to do anything if the file already exists.
1127 int vrc = RTFileCopy(m->strFilename.c_str(), strFilenameNew.c_str());
1128 if (RT_UNLIKELY(vrc == VERR_DISK_FULL))
1129 throw ConfigFileError(this, NULL, N_("Cannot create settings backup file when upgrading to a newer settings format"));
1130
1131 // do this only once
1132 m->svRead = SettingsVersion_Null;
1133 }
1134}
1135
1136/**
1137 * Creates a new stub xml::Document in the m->pDoc member with the
1138 * root "VirtualBox" element set up. This is used by both
1139 * MainConfigFile and MachineConfigFile at the beginning of writing
1140 * out their XML.
1141 *
1142 * Before calling this, it is the responsibility of the caller to
1143 * set the "sv" member to the required settings version that is to
1144 * be written. For newly created files, the settings version will be
1145 * recent (1.12 or later if necessary); for files read in from disk
1146 * earlier, it will be the settings version indicated in the file.
1147 * However, this method will silently make sure that the settings
1148 * version is always at least 1.7 and change it if necessary, since
1149 * there is no write support for earlier settings versions.
1150 */
1151void ConfigFileBase::createStubDocument()
1152{
1153 Assert(m->pDoc == NULL);
1154 m->pDoc = new xml::Document;
1155
1156 m->pelmRoot = m->pDoc->createRootElement("VirtualBox",
1157 "\n"
1158 "** DO NOT EDIT THIS FILE.\n"
1159 "** If you make changes to this file while any VirtualBox related application\n"
1160 "** is running, your changes will be overwritten later, without taking effect.\n"
1161 "** Use VBoxManage or the VirtualBox Manager GUI to make changes.\n"
1162);
1163 m->pelmRoot->setAttribute("xmlns", VBOX_XML_NAMESPACE);
1164 // Have the code for producing a proper schema reference. Not used by most
1165 // tools, so don't bother doing it. The schema is not on the server anyway.
1166#ifdef VBOX_WITH_SETTINGS_SCHEMA
1167 m->pelmRoot->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
1168 m->pelmRoot->setAttribute("xsi:schemaLocation", VBOX_XML_NAMESPACE " " VBOX_XML_SCHEMA);
1169#endif
1170
1171 // add settings version attribute to root element, update m->strSettingsVersionFull
1172 setVersionAttribute(*m->pelmRoot);
1173
1174 LogRel(("Saving settings file \"%s\" with version \"%s\"\n", m->strFilename.c_str(), m->strSettingsVersionFull.c_str()));
1175}
1176
1177/**
1178 * Creates an \<ExtraData\> node under the given parent element with
1179 * \<ExtraDataItem\> childern according to the contents of the given
1180 * map.
1181 *
1182 * This is in ConfigFileBase because it's used in both MainConfigFile
1183 * and MachineConfigFile, which both can have extradata.
1184 *
1185 * @param elmParent
1186 * @param me
1187 */
1188void ConfigFileBase::buildExtraData(xml::ElementNode &elmParent,
1189 const StringsMap &me)
1190{
1191 if (me.size())
1192 {
1193 xml::ElementNode *pelmExtraData = elmParent.createChild("ExtraData");
1194 for (StringsMap::const_iterator it = me.begin();
1195 it != me.end();
1196 ++it)
1197 {
1198 const Utf8Str &strName = it->first;
1199 const Utf8Str &strValue = it->second;
1200 xml::ElementNode *pelmThis = pelmExtraData->createChild("ExtraDataItem");
1201 pelmThis->setAttribute("name", strName);
1202 pelmThis->setAttribute("value", strValue);
1203 }
1204 }
1205}
1206
1207/**
1208 * Creates \<DeviceFilter\> nodes under the given parent element according to
1209 * the contents of the given USBDeviceFiltersList. This is in ConfigFileBase
1210 * because it's used in both MainConfigFile (for host filters) and
1211 * MachineConfigFile (for machine filters).
1212 *
1213 * If fHostMode is true, this means that we're supposed to write filters
1214 * for the IHost interface (respect "action", omit "strRemote" and
1215 * "ulMaskedInterfaces" in struct USBDeviceFilter).
1216 *
1217 * @param elmParent
1218 * @param ll
1219 * @param fHostMode
1220 */
1221void ConfigFileBase::buildUSBDeviceFilters(xml::ElementNode &elmParent,
1222 const USBDeviceFiltersList &ll,
1223 bool fHostMode)
1224{
1225 for (USBDeviceFiltersList::const_iterator it = ll.begin();
1226 it != ll.end();
1227 ++it)
1228 {
1229 const USBDeviceFilter &flt = *it;
1230 xml::ElementNode *pelmFilter = elmParent.createChild("DeviceFilter");
1231 pelmFilter->setAttribute("name", flt.strName);
1232 pelmFilter->setAttribute("active", flt.fActive);
1233 if (flt.strVendorId.length())
1234 pelmFilter->setAttribute("vendorId", flt.strVendorId);
1235 if (flt.strProductId.length())
1236 pelmFilter->setAttribute("productId", flt.strProductId);
1237 if (flt.strRevision.length())
1238 pelmFilter->setAttribute("revision", flt.strRevision);
1239 if (flt.strManufacturer.length())
1240 pelmFilter->setAttribute("manufacturer", flt.strManufacturer);
1241 if (flt.strProduct.length())
1242 pelmFilter->setAttribute("product", flt.strProduct);
1243 if (flt.strSerialNumber.length())
1244 pelmFilter->setAttribute("serialNumber", flt.strSerialNumber);
1245 if (flt.strPort.length())
1246 pelmFilter->setAttribute("port", flt.strPort);
1247
1248 if (fHostMode)
1249 {
1250 const char *pcsz =
1251 (flt.action == USBDeviceFilterAction_Ignore) ? "Ignore"
1252 : /*(flt.action == USBDeviceFilterAction_Hold) ?*/ "Hold";
1253 pelmFilter->setAttribute("action", pcsz);
1254 }
1255 else
1256 {
1257 if (flt.strRemote.length())
1258 pelmFilter->setAttribute("remote", flt.strRemote);
1259 if (flt.ulMaskedInterfaces)
1260 pelmFilter->setAttribute("maskedInterfaces", flt.ulMaskedInterfaces);
1261 }
1262 }
1263}
1264
1265/**
1266 * Creates a single \<HardDisk\> element for the given Medium structure
1267 * and recurses to write the child hard disks underneath. Called from
1268 * MainConfigFile::write().
1269 *
1270 * @param t
1271 * @param depth
1272 * @param elmMedium
1273 * @param mdm
1274 */
1275void ConfigFileBase::buildMedium(MediaType t,
1276 uint32_t depth,
1277 xml::ElementNode &elmMedium,
1278 const Medium &mdm)
1279{
1280 if (depth > SETTINGS_MEDIUM_DEPTH_MAX)
1281 throw ConfigFileError(this, &elmMedium, N_("Maximum medium tree depth of %u exceeded"), SETTINGS_MEDIUM_DEPTH_MAX);
1282
1283 xml::ElementNode *pelmMedium;
1284
1285 if (t == HardDisk)
1286 pelmMedium = elmMedium.createChild("HardDisk");
1287 else
1288 pelmMedium = elmMedium.createChild("Image");
1289
1290 pelmMedium->setAttribute("uuid", mdm.uuid.toStringCurly());
1291
1292 pelmMedium->setAttributePath("location", mdm.strLocation);
1293
1294 if (t == HardDisk || RTStrICmp(mdm.strFormat.c_str(), "RAW"))
1295 pelmMedium->setAttribute("format", mdm.strFormat);
1296 if ( t == HardDisk
1297 && mdm.fAutoReset)
1298 pelmMedium->setAttribute("autoReset", mdm.fAutoReset);
1299 if (mdm.strDescription.length())
1300 pelmMedium->createChild("Description")->addContent(mdm.strDescription);
1301
1302 for (StringsMap::const_iterator it = mdm.properties.begin();
1303 it != mdm.properties.end();
1304 ++it)
1305 {
1306 xml::ElementNode *pelmProp = pelmMedium->createChild("Property");
1307 pelmProp->setAttribute("name", it->first);
1308 pelmProp->setAttribute("value", it->second);
1309 }
1310
1311 // only for base hard disks, save the type
1312 if (depth == 1)
1313 {
1314 // no need to save the usual DVD/floppy medium types
1315 if ( ( t != DVDImage
1316 || ( mdm.hdType != MediumType_Writethrough // shouldn't happen
1317 && mdm.hdType != MediumType_Readonly))
1318 && ( t != FloppyImage
1319 || mdm.hdType != MediumType_Writethrough))
1320 {
1321 const char *pcszType =
1322 mdm.hdType == MediumType_Normal ? "Normal" :
1323 mdm.hdType == MediumType_Immutable ? "Immutable" :
1324 mdm.hdType == MediumType_Writethrough ? "Writethrough" :
1325 mdm.hdType == MediumType_Shareable ? "Shareable" :
1326 mdm.hdType == MediumType_Readonly ? "Readonly" :
1327 mdm.hdType == MediumType_MultiAttach ? "MultiAttach" :
1328 "INVALID";
1329 pelmMedium->setAttribute("type", pcszType);
1330 }
1331 }
1332
1333 for (MediaList::const_iterator it = mdm.llChildren.begin();
1334 it != mdm.llChildren.end();
1335 ++it)
1336 {
1337 // recurse for children
1338 buildMedium(t, // device type
1339 depth + 1, // depth
1340 *pelmMedium, // parent
1341 *it); // settings::Medium
1342 }
1343}
1344
1345/**
1346 * Creates a \<MediaRegistry\> node under the given parent and writes out all
1347 * hard disks and DVD and floppy images from the lists in the given MediaRegistry
1348 * structure under it.
1349 *
1350 * This is used in both MainConfigFile and MachineConfigFile since starting with
1351 * VirtualBox 4.0, we can have media registries in both.
1352 *
1353 * @param elmParent
1354 * @param mr
1355 */
1356void ConfigFileBase::buildMediaRegistry(xml::ElementNode &elmParent,
1357 const MediaRegistry &mr)
1358{
1359 if (mr.llHardDisks.size() == 0 && mr.llDvdImages.size() == 0 && mr.llFloppyImages.size() == 0)
1360 return;
1361
1362 xml::ElementNode *pelmMediaRegistry = elmParent.createChild("MediaRegistry");
1363
1364 if (mr.llHardDisks.size())
1365 {
1366 xml::ElementNode *pelmHardDisks = pelmMediaRegistry->createChild("HardDisks");
1367 for (MediaList::const_iterator it = mr.llHardDisks.begin();
1368 it != mr.llHardDisks.end();
1369 ++it)
1370 {
1371 buildMedium(HardDisk, 1, *pelmHardDisks, *it);
1372 }
1373 }
1374
1375 if (mr.llDvdImages.size())
1376 {
1377 xml::ElementNode *pelmDVDImages = pelmMediaRegistry->createChild("DVDImages");
1378 for (MediaList::const_iterator it = mr.llDvdImages.begin();
1379 it != mr.llDvdImages.end();
1380 ++it)
1381 {
1382 buildMedium(DVDImage, 1, *pelmDVDImages, *it);
1383 }
1384 }
1385
1386 if (mr.llFloppyImages.size())
1387 {
1388 xml::ElementNode *pelmFloppyImages = pelmMediaRegistry->createChild("FloppyImages");
1389 for (MediaList::const_iterator it = mr.llFloppyImages.begin();
1390 it != mr.llFloppyImages.end();
1391 ++it)
1392 {
1393 buildMedium(FloppyImage, 1, *pelmFloppyImages, *it);
1394 }
1395 }
1396}
1397
1398/**
1399 * Serialize NAT port-forwarding rules in parent container.
1400 * Note: it's responsibility of caller to create parent of the list tag.
1401 * because this method used for serializing per-_mahine's_adapter_ and per-network approaches.
1402 */
1403void ConfigFileBase::buildNATForwardRulesMap(xml::ElementNode &elmParent, const NATRulesMap &mapRules)
1404{
1405 for (NATRulesMap::const_iterator r = mapRules.begin();
1406 r != mapRules.end(); ++r)
1407 {
1408 xml::ElementNode *pelmPF;
1409 pelmPF = elmParent.createChild("Forwarding");
1410 const NATRule &nr = r->second;
1411 if (nr.strName.length())
1412 pelmPF->setAttribute("name", nr.strName);
1413 pelmPF->setAttribute("proto", nr.proto);
1414 if (nr.strHostIP.length())
1415 pelmPF->setAttribute("hostip", nr.strHostIP);
1416 if (nr.u16HostPort)
1417 pelmPF->setAttribute("hostport", nr.u16HostPort);
1418 if (nr.strGuestIP.length())
1419 pelmPF->setAttribute("guestip", nr.strGuestIP);
1420 if (nr.u16GuestPort)
1421 pelmPF->setAttribute("guestport", nr.u16GuestPort);
1422 }
1423}
1424
1425
1426void ConfigFileBase::buildNATLoopbacks(xml::ElementNode &elmParent, const NATLoopbackOffsetList &natLoopbackOffsetList)
1427{
1428 for (NATLoopbackOffsetList::const_iterator lo = natLoopbackOffsetList.begin();
1429 lo != natLoopbackOffsetList.end(); ++lo)
1430 {
1431 xml::ElementNode *pelmLo;
1432 pelmLo = elmParent.createChild("Loopback4");
1433 pelmLo->setAttribute("address", (*lo).strLoopbackHostAddress);
1434 pelmLo->setAttribute("offset", (*lo).u32Offset);
1435 }
1436}
1437
1438/**
1439 * Cleans up memory allocated by the internal XML parser. To be called by
1440 * descendant classes when they're done analyzing the DOM tree to discard it.
1441 */
1442void ConfigFileBase::clearDocument()
1443{
1444 m->cleanup();
1445}
1446
1447/**
1448 * Returns true only if the underlying config file exists on disk;
1449 * either because the file has been loaded from disk, or it's been written
1450 * to disk, or both.
1451 * @return
1452 */
1453bool ConfigFileBase::fileExists()
1454{
1455 return m->fFileExists;
1456}
1457
1458/**
1459 * Copies the base variables from another instance. Used by Machine::saveSettings
1460 * so that the settings version does not get lost when a copy of the Machine settings
1461 * file is made to see if settings have actually changed.
1462 * @param b
1463 */
1464void ConfigFileBase::copyBaseFrom(const ConfigFileBase &b)
1465{
1466 m->copyFrom(*b.m);
1467}
1468
1469////////////////////////////////////////////////////////////////////////////////
1470//
1471// Structures shared between Machine XML and VirtualBox.xml
1472//
1473////////////////////////////////////////////////////////////////////////////////
1474
1475
1476/**
1477 * Constructor. Needs to set sane defaults which stand the test of time.
1478 */
1479USBDeviceFilter::USBDeviceFilter() :
1480 fActive(false),
1481 action(USBDeviceFilterAction_Null),
1482 ulMaskedInterfaces(0)
1483{
1484}
1485
1486/**
1487 * Comparison operator. This gets called from MachineConfigFile::operator==,
1488 * which in turn gets called from Machine::saveSettings to figure out whether
1489 * machine settings have really changed and thus need to be written out to disk.
1490 */
1491bool USBDeviceFilter::operator==(const USBDeviceFilter &u) const
1492{
1493 return (this == &u)
1494 || ( strName == u.strName
1495 && fActive == u.fActive
1496 && strVendorId == u.strVendorId
1497 && strProductId == u.strProductId
1498 && strRevision == u.strRevision
1499 && strManufacturer == u.strManufacturer
1500 && strProduct == u.strProduct
1501 && strSerialNumber == u.strSerialNumber
1502 && strPort == u.strPort
1503 && action == u.action
1504 && strRemote == u.strRemote
1505 && ulMaskedInterfaces == u.ulMaskedInterfaces);
1506}
1507
1508/**
1509 * Constructor. Needs to set sane defaults which stand the test of time.
1510 */
1511settings::Medium::Medium() :
1512 fAutoReset(false),
1513 hdType(MediumType_Normal)
1514{
1515}
1516
1517/**
1518 * Comparison operator. This gets called from MachineConfigFile::operator==,
1519 * which in turn gets called from Machine::saveSettings to figure out whether
1520 * machine settings have really changed and thus need to be written out to disk.
1521 */
1522bool settings::Medium::operator==(const settings::Medium &m) const
1523{
1524 return (this == &m)
1525 || ( uuid == m.uuid
1526 && strLocation == m.strLocation
1527 && strDescription == m.strDescription
1528 && strFormat == m.strFormat
1529 && fAutoReset == m.fAutoReset
1530 && properties == m.properties
1531 && hdType == m.hdType
1532 && llChildren == m.llChildren); // this is deep and recurses
1533}
1534
1535const struct settings::Medium settings::Medium::Empty; /* default ctor is OK */
1536
1537/**
1538 * Comparison operator. This gets called from MachineConfigFile::operator==,
1539 * which in turn gets called from Machine::saveSettings to figure out whether
1540 * machine settings have really changed and thus need to be written out to disk.
1541 */
1542bool MediaRegistry::operator==(const MediaRegistry &m) const
1543{
1544 return (this == &m)
1545 || ( llHardDisks == m.llHardDisks
1546 && llDvdImages == m.llDvdImages
1547 && llFloppyImages == m.llFloppyImages);
1548}
1549
1550/**
1551 * Constructor. Needs to set sane defaults which stand the test of time.
1552 */
1553NATRule::NATRule() :
1554 proto(NATProtocol_TCP),
1555 u16HostPort(0),
1556 u16GuestPort(0)
1557{
1558}
1559
1560/**
1561 * Comparison operator. This gets called from MachineConfigFile::operator==,
1562 * which in turn gets called from Machine::saveSettings to figure out whether
1563 * machine settings have really changed and thus need to be written out to disk.
1564 */
1565bool NATRule::operator==(const NATRule &r) const
1566{
1567 return (this == &r)
1568 || ( strName == r.strName
1569 && proto == r.proto
1570 && u16HostPort == r.u16HostPort
1571 && strHostIP == r.strHostIP
1572 && u16GuestPort == r.u16GuestPort
1573 && strGuestIP == r.strGuestIP);
1574}
1575
1576/**
1577 * Constructor. Needs to set sane defaults which stand the test of time.
1578 */
1579NATHostLoopbackOffset::NATHostLoopbackOffset() :
1580 u32Offset(0)
1581{
1582}
1583
1584/**
1585 * Comparison operator. This gets called from MachineConfigFile::operator==,
1586 * which in turn gets called from Machine::saveSettings to figure out whether
1587 * machine settings have really changed and thus need to be written out to disk.
1588 */
1589bool NATHostLoopbackOffset::operator==(const NATHostLoopbackOffset &o) const
1590{
1591 return (this == &o)
1592 || ( strLoopbackHostAddress == o.strLoopbackHostAddress
1593 && u32Offset == o.u32Offset);
1594}
1595
1596
1597////////////////////////////////////////////////////////////////////////////////
1598//
1599// VirtualBox.xml structures
1600//
1601////////////////////////////////////////////////////////////////////////////////
1602
1603/**
1604 * Constructor. Needs to set sane defaults which stand the test of time.
1605 */
1606SystemProperties::SystemProperties()
1607 : uProxyMode(ProxyMode_System)
1608 , uLogHistoryCount(3)
1609 , fExclusiveHwVirt(true)
1610 , fVBoxUpdateEnabled(true)
1611 , uVBoxUpdateCount(0)
1612 , uVBoxUpdateFrequency(1)
1613 , uVBoxUpdateTarget(VBoxUpdateTarget_Stable)
1614{
1615#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS)
1616 fExclusiveHwVirt = false;
1617#endif
1618}
1619
1620/**
1621 * Constructor. Needs to set sane defaults which stand the test of time.
1622 */
1623DhcpOptValue::DhcpOptValue()
1624 : strValue()
1625 , enmEncoding(DHCPOptionEncoding_Normal)
1626{
1627}
1628
1629/**
1630 * Non-standard constructor.
1631 */
1632DhcpOptValue::DhcpOptValue(const com::Utf8Str &aText, DHCPOptionEncoding_T aEncoding)
1633 : strValue(aText)
1634 , enmEncoding(aEncoding)
1635{
1636}
1637
1638/**
1639 * Default constructor.
1640 */
1641DHCPGroupCondition::DHCPGroupCondition()
1642 : fInclusive(true)
1643 , enmType(DHCPGroupConditionType_MAC)
1644 , strValue()
1645{
1646}
1647
1648/**
1649 * Default constructor.
1650 */
1651DHCPConfig::DHCPConfig()
1652 : mapOptions()
1653 , secMinLeaseTime(0)
1654 , secDefaultLeaseTime(0)
1655 , secMaxLeaseTime(0)
1656{
1657}
1658
1659/**
1660 * Default constructor.
1661 */
1662DHCPGroupConfig::DHCPGroupConfig()
1663 : DHCPConfig()
1664 , strName()
1665 , vecConditions()
1666{
1667}
1668
1669/**
1670 * Default constructor.
1671 */
1672DHCPIndividualConfig::DHCPIndividualConfig()
1673 : DHCPConfig()
1674 , strMACAddress()
1675 , strVMName()
1676 , uSlot(0)
1677{
1678}
1679
1680/**
1681 * Constructor. Needs to set sane defaults which stand the test of time.
1682 */
1683DHCPServer::DHCPServer()
1684 : fEnabled(false)
1685{
1686}
1687
1688/**
1689 * Constructor. Needs to set sane defaults which stand the test of time.
1690 */
1691NATNetwork::NATNetwork() :
1692 fEnabled(true),
1693 fIPv6Enabled(false),
1694 fAdvertiseDefaultIPv6Route(false),
1695 fNeedDhcpServer(true),
1696 u32HostLoopback6Offset(0)
1697{
1698}
1699
1700#ifdef VBOX_WITH_CLOUD_NET
1701/**
1702 * Constructor. Needs to set sane defaults which stand the test of time.
1703 */
1704CloudNetwork::CloudNetwork() :
1705 strProviderShortName("OCI"),
1706 strProfileName("Default"),
1707 fEnabled(true)
1708{
1709}
1710#endif /* VBOX_WITH_CLOUD_NET */
1711
1712
1713
1714////////////////////////////////////////////////////////////////////////////////
1715//
1716// MainConfigFile
1717//
1718////////////////////////////////////////////////////////////////////////////////
1719
1720/**
1721 * Reads one \<MachineEntry\> from the main VirtualBox.xml file.
1722 * @param elmMachineRegistry
1723 */
1724void MainConfigFile::readMachineRegistry(const xml::ElementNode &elmMachineRegistry)
1725{
1726 // <MachineEntry uuid="{ xxx }" src=" xxx "/>
1727 xml::NodesLoop nl1(elmMachineRegistry);
1728 const xml::ElementNode *pelmChild1;
1729 while ((pelmChild1 = nl1.forAllNodes()))
1730 {
1731 if (pelmChild1->nameEquals("MachineEntry"))
1732 {
1733 MachineRegistryEntry mre;
1734 Utf8Str strUUID;
1735 if ( pelmChild1->getAttributeValue("uuid", strUUID)
1736 && pelmChild1->getAttributeValue("src", mre.strSettingsFile) )
1737 {
1738 parseUUID(mre.uuid, strUUID, pelmChild1);
1739 llMachines.push_back(mre);
1740 }
1741 else
1742 throw ConfigFileError(this, pelmChild1, N_("Required MachineEntry/@uuid or @src attribute is missing"));
1743 }
1744 }
1745}
1746
1747/**
1748 * Builds the XML tree for the DHCP servers.
1749 */
1750void MainConfigFile::buildDHCPServers(xml::ElementNode &elmDHCPServers, DHCPServersList const &ll)
1751{
1752 for (DHCPServersList::const_iterator it = ll.begin(); it != ll.end(); ++it)
1753 {
1754 const DHCPServer &srv = *it;
1755 xml::ElementNode *pElmThis = elmDHCPServers.createChild("DHCPServer");
1756
1757 pElmThis->setAttribute("networkName", srv.strNetworkName);
1758 pElmThis->setAttribute("IPAddress", srv.strIPAddress);
1759 DhcpOptConstIterator itOpt = srv.globalConfig.mapOptions.find(DHCPOption_SubnetMask);
1760 if (itOpt != srv.globalConfig.mapOptions.end())
1761 pElmThis->setAttribute("networkMask", itOpt->second.strValue);
1762 pElmThis->setAttribute("lowerIP", srv.strIPLower);
1763 pElmThis->setAttribute("upperIP", srv.strIPUpper);
1764 pElmThis->setAttribute("enabled", (srv.fEnabled) ? 1 : 0); // too bad we chose 1 vs. 0 here
1765
1766 /* We don't want duplicate validation check of networkMask here*/
1767 if (srv.globalConfig.mapOptions.size() > (itOpt != srv.globalConfig.mapOptions.end() ? 1U : 0U))
1768 {
1769 xml::ElementNode *pElmOptions = pElmThis->createChild("Options");
1770 buildDHCPOptions(*pElmOptions, srv.globalConfig, true);
1771 }
1772
1773 for (DHCPGroupConfigVec::const_iterator itGroup = srv.vecGroupConfigs.begin();
1774 itGroup != srv.vecGroupConfigs.end(); ++itGroup)
1775 {
1776 DHCPGroupConfig const &rGroupConfig = *itGroup;
1777
1778 xml::ElementNode *pElmGroup = pElmThis->createChild("Group");
1779 pElmGroup->setAttribute("name", rGroupConfig.strName);
1780 buildDHCPOptions(*pElmGroup, rGroupConfig, false);
1781
1782 for (DHCPGroupConditionVec::const_iterator itCond = rGroupConfig.vecConditions.begin();
1783 itCond != rGroupConfig.vecConditions.end(); ++itCond)
1784 {
1785 xml::ElementNode *pElmCondition = pElmGroup->createChild("Condition");
1786 pElmCondition->setAttribute("inclusive", itCond->fInclusive);
1787 pElmCondition->setAttribute("type", (int32_t)itCond->enmType);
1788 pElmCondition->setAttribute("value", itCond->strValue);
1789 }
1790 }
1791
1792 for (DHCPIndividualConfigMap::const_iterator itHost = srv.mapIndividualConfigs.begin();
1793 itHost != srv.mapIndividualConfigs.end(); ++itHost)
1794 {
1795 DHCPIndividualConfig const &rIndividualConfig = itHost->second;
1796
1797 xml::ElementNode *pElmConfig = pElmThis->createChild("Config");
1798 if (rIndividualConfig.strMACAddress.isNotEmpty())
1799 pElmConfig->setAttribute("MACAddress", rIndividualConfig.strMACAddress);
1800 if (rIndividualConfig.strVMName.isNotEmpty())
1801 pElmConfig->setAttribute("vm-name", rIndividualConfig.strVMName);
1802 if (rIndividualConfig.uSlot != 0 || rIndividualConfig.strVMName.isNotEmpty())
1803 pElmConfig->setAttribute("slot", rIndividualConfig.uSlot);
1804 if (rIndividualConfig.strFixedAddress.isNotEmpty())
1805 pElmConfig->setAttribute("fixedAddress", rIndividualConfig.strFixedAddress);
1806 buildDHCPOptions(*pElmConfig, rIndividualConfig, false);
1807 }
1808 }
1809}
1810
1811/**
1812 * Worker for buildDHCPServers() that builds Options or Config element trees.
1813 */
1814void MainConfigFile::buildDHCPOptions(xml::ElementNode &elmOptions, DHCPConfig const &rConfig, bool fSkipSubnetMask)
1815{
1816 /* Generic (and optional) attributes on the Options or Config element: */
1817 if (rConfig.secMinLeaseTime > 0)
1818 elmOptions.setAttribute("secMinLeaseTime", rConfig.secMinLeaseTime);
1819 if (rConfig.secDefaultLeaseTime > 0)
1820 elmOptions.setAttribute("secDefaultLeaseTime", rConfig.secDefaultLeaseTime);
1821 if (rConfig.secMaxLeaseTime > 0)
1822 elmOptions.setAttribute("secMaxLeaseTime", rConfig.secMaxLeaseTime);
1823 if (rConfig.strForcedOptions.isNotEmpty())
1824 elmOptions.setAttribute("forcedOptions", rConfig.strForcedOptions);
1825 if (rConfig.strSuppressedOptions.isNotEmpty())
1826 elmOptions.setAttribute("suppressedOptions", rConfig.strSuppressedOptions);
1827
1828 /* The DHCP options are <Option> child elements: */
1829 for (DhcpOptConstIterator it = rConfig.mapOptions.begin(); it != rConfig.mapOptions.end(); ++it)
1830 if (it->first != DHCPOption_SubnetMask || !fSkipSubnetMask)
1831 {
1832 xml::ElementNode *pElmOption = elmOptions.createChild("Option");
1833 pElmOption->setAttribute("name", it->first);
1834 pElmOption->setAttribute("value", it->second.strValue);
1835 if (it->second.enmEncoding != DHCPOptionEncoding_Normal)
1836 pElmOption->setAttribute("encoding", (int32_t)it->second.enmEncoding);
1837 }
1838}
1839
1840/**
1841 * Reads in the \<DHCPServers\> chunk.
1842 * @param elmDHCPServers
1843 */
1844void MainConfigFile::readDHCPServers(const xml::ElementNode &elmDHCPServers)
1845{
1846 xml::NodesLoop nl1(elmDHCPServers);
1847 const xml::ElementNode *pelmServer;
1848 while ((pelmServer = nl1.forAllNodes()))
1849 {
1850 if (pelmServer->nameEquals("DHCPServer"))
1851 {
1852 DHCPServer srv;
1853 if ( pelmServer->getAttributeValue("networkName", srv.strNetworkName)
1854 && pelmServer->getAttributeValue("IPAddress", srv.strIPAddress)
1855 && pelmServer->getAttributeValue("networkMask", srv.globalConfig.mapOptions[DHCPOption_SubnetMask].strValue)
1856 && pelmServer->getAttributeValue("lowerIP", srv.strIPLower)
1857 && pelmServer->getAttributeValue("upperIP", srv.strIPUpper)
1858 && pelmServer->getAttributeValue("enabled", srv.fEnabled) )
1859 {
1860 /* Global options: */
1861 const xml::ElementNode *pElmOptions;
1862 xml::NodesLoop nlOptions(*pelmServer, "Options");
1863 while ((pElmOptions = nlOptions.forAllNodes()) != NULL) /** @todo this loop makes no sense, there can only be one \<Options\> child. */
1864 readDHCPOptions(srv.globalConfig, *pElmOptions, true /*fIgnoreSubnetMask*/);
1865
1866 /* Group configurations: */
1867 xml::NodesLoop nlGroup(*pelmServer, "Group");
1868 const xml::ElementNode *pElmGroup;
1869 size_t i = 0;
1870 while ((pElmGroup = nlGroup.forAllNodes()) != NULL)
1871 {
1872 srv.vecGroupConfigs.push_back(DHCPGroupConfig());
1873 DHCPGroupConfig &rGroupConfig = srv.vecGroupConfigs.back();
1874
1875 if (!pElmGroup->getAttributeValue("name", rGroupConfig.strName))
1876 rGroupConfig.strName.printf("Unamed Group #%u", ++i);
1877
1878 readDHCPOptions(rGroupConfig, *pElmGroup, false /*fIgnoreSubnetMask*/);
1879
1880 xml::NodesLoop nlCondition(*pElmGroup, "Condition");
1881 const xml::ElementNode *pElmCondition;
1882 while ((pElmCondition = nlCondition.forAllNodes()) != NULL)
1883 {
1884 rGroupConfig.vecConditions.push_back(DHCPGroupCondition());
1885 DHCPGroupCondition &rGroupCondition = rGroupConfig.vecConditions.back();
1886
1887 if (!pElmCondition->getAttributeValue("inclusive", rGroupCondition.fInclusive))
1888 rGroupCondition.fInclusive = true;
1889
1890 int32_t iType;
1891 if (!pElmCondition->getAttributeValue("type", iType))
1892 iType = DHCPGroupConditionType_MAC;
1893 rGroupCondition.enmType = (DHCPGroupConditionType_T)iType;
1894
1895 pElmCondition->getAttributeValue("value", rGroupCondition.strValue);
1896 }
1897 }
1898
1899 /* host specific configuration: */
1900 xml::NodesLoop nlConfig(*pelmServer, "Config");
1901 const xml::ElementNode *pElmConfig;
1902 while ((pElmConfig = nlConfig.forAllNodes()) != NULL)
1903 {
1904 com::Utf8Str strMACAddress;
1905 if (!pElmConfig->getAttributeValue("MACAddress", strMACAddress))
1906 strMACAddress.setNull();
1907
1908 com::Utf8Str strVMName;
1909 if (!pElmConfig->getAttributeValue("vm-name", strVMName))
1910 strVMName.setNull();
1911
1912 uint32_t uSlot;
1913 if (!pElmConfig->getAttributeValue("slot", uSlot))
1914 uSlot = 0;
1915
1916 com::Utf8Str strKey;
1917 if (strVMName.isNotEmpty())
1918 strKey.printf("%s/%u", strVMName.c_str(), uSlot);
1919 else
1920 strKey.printf("%s/%u", strMACAddress.c_str(), uSlot);
1921
1922 DHCPIndividualConfig &rIndividualConfig = srv.mapIndividualConfigs[strKey];
1923 rIndividualConfig.strMACAddress = strMACAddress;
1924 rIndividualConfig.strVMName = strVMName;
1925 rIndividualConfig.uSlot = uSlot;
1926 pElmConfig->getAttributeValue("fixedAddress", rIndividualConfig.strFixedAddress);
1927
1928 readDHCPOptions(rIndividualConfig, *pElmConfig, false /*fIgnoreSubnetMask*/);
1929 }
1930
1931 llDhcpServers.push_back(srv);
1932 }
1933 else
1934 throw ConfigFileError(this, pelmServer, N_("Required DHCPServer/@networkName, @IPAddress, @networkMask, @lowerIP, @upperIP or @enabled attribute is missing"));
1935 }
1936 }
1937}
1938
1939/**
1940 * Worker for readDHCPServers that reads a configuration, either global,
1941 * group or host (VM+NIC) specific.
1942 */
1943void MainConfigFile::readDHCPOptions(DHCPConfig &rConfig, const xml::ElementNode &elmConfig, bool fIgnoreSubnetMask)
1944{
1945 /* Generic (and optional) attributes on the Options or Config element: */
1946 if (!elmConfig.getAttributeValue("secMinLeaseTime", rConfig.secMinLeaseTime))
1947 rConfig.secMinLeaseTime = 0;
1948 if (!elmConfig.getAttributeValue("secDefaultLeaseTime", rConfig.secDefaultLeaseTime))
1949 rConfig.secDefaultLeaseTime = 0;
1950 if (!elmConfig.getAttributeValue("secMaxLeaseTime", rConfig.secMaxLeaseTime))
1951 rConfig.secMaxLeaseTime = 0;
1952 if (!elmConfig.getAttributeValue("forcedOptions", rConfig.strForcedOptions))
1953 rConfig.strSuppressedOptions.setNull();
1954 if (!elmConfig.getAttributeValue("suppressedOptions", rConfig.strSuppressedOptions))
1955 rConfig.strSuppressedOptions.setNull();
1956
1957 /* The DHCP options are <Option> child elements: */
1958 xml::NodesLoop nl2(elmConfig, "Option");
1959 const xml::ElementNode *pElmOption;
1960 while ((pElmOption = nl2.forAllNodes()) != NULL)
1961 {
1962 int32_t iOptName;
1963 if (!pElmOption->getAttributeValue("name", iOptName))
1964 continue;
1965 DHCPOption_T OptName = (DHCPOption_T)iOptName;
1966 if (OptName == DHCPOption_SubnetMask && fIgnoreSubnetMask)
1967 continue;
1968
1969 com::Utf8Str strValue;
1970 pElmOption->getAttributeValue("value", strValue);
1971
1972 int32_t iOptEnc;
1973 if (!pElmOption->getAttributeValue("encoding", iOptEnc))
1974 iOptEnc = DHCPOptionEncoding_Normal;
1975
1976 rConfig.mapOptions[OptName] = DhcpOptValue(strValue, (DHCPOptionEncoding_T)iOptEnc);
1977 } /* end of forall("Option") */
1978
1979}
1980
1981/**
1982 * Reads in the \<NATNetworks\> chunk.
1983 * @param elmNATNetworks
1984 */
1985void MainConfigFile::readNATNetworks(const xml::ElementNode &elmNATNetworks)
1986{
1987 xml::NodesLoop nl1(elmNATNetworks);
1988 const xml::ElementNode *pelmNet;
1989 while ((pelmNet = nl1.forAllNodes()))
1990 {
1991 if (pelmNet->nameEquals("NATNetwork"))
1992 {
1993 NATNetwork net;
1994 if ( pelmNet->getAttributeValue("networkName", net.strNetworkName)
1995 && pelmNet->getAttributeValue("enabled", net.fEnabled)
1996 && pelmNet->getAttributeValue("network", net.strIPv4NetworkCidr)
1997 && pelmNet->getAttributeValue("ipv6", net.fIPv6Enabled)
1998 && pelmNet->getAttributeValue("ipv6prefix", net.strIPv6Prefix)
1999 && pelmNet->getAttributeValue("advertiseDefaultIPv6Route", net.fAdvertiseDefaultIPv6Route)
2000 && pelmNet->getAttributeValue("needDhcp", net.fNeedDhcpServer) )
2001 {
2002 pelmNet->getAttributeValue("loopback6", net.u32HostLoopback6Offset);
2003 const xml::ElementNode *pelmMappings;
2004 if ((pelmMappings = pelmNet->findChildElement("Mappings")))
2005 readNATLoopbacks(*pelmMappings, net.llHostLoopbackOffsetList);
2006
2007 const xml::ElementNode *pelmPortForwardRules4;
2008 if ((pelmPortForwardRules4 = pelmNet->findChildElement("PortForwarding4")))
2009 readNATForwardRulesMap(*pelmPortForwardRules4,
2010 net.mapPortForwardRules4);
2011
2012 const xml::ElementNode *pelmPortForwardRules6;
2013 if ((pelmPortForwardRules6 = pelmNet->findChildElement("PortForwarding6")))
2014 readNATForwardRulesMap(*pelmPortForwardRules6,
2015 net.mapPortForwardRules6);
2016
2017 llNATNetworks.push_back(net);
2018 }
2019 else
2020 throw ConfigFileError(this, pelmNet, N_("Required NATNetwork/@networkName, @gateway, @network,@advertiseDefaultIpv6Route , @needDhcp or @enabled attribute is missing"));
2021 }
2022 }
2023}
2024
2025#ifdef VBOX_WITH_CLOUD_NET
2026/**
2027 * Reads in the \<CloudNetworks\> chunk.
2028 * @param elmCloudNetworks
2029 */
2030void MainConfigFile::readCloudNetworks(const xml::ElementNode &elmCloudNetworks)
2031{
2032 xml::NodesLoop nl1(elmCloudNetworks);
2033 const xml::ElementNode *pelmNet;
2034 while ((pelmNet = nl1.forAllNodes()))
2035 {
2036 if (pelmNet->nameEquals("CloudNetwork"))
2037 {
2038 CloudNetwork net;
2039 if ( pelmNet->getAttributeValue("name", net.strNetworkName)
2040 && pelmNet->getAttributeValue("provider", net.strProviderShortName)
2041 && pelmNet->getAttributeValue("profile", net.strProfileName)
2042 && pelmNet->getAttributeValue("id", net.strNetworkId)
2043 && pelmNet->getAttributeValue("enabled", net.fEnabled) )
2044 {
2045 llCloudNetworks.push_back(net);
2046 }
2047 else
2048 throw ConfigFileError(this, pelmNet, N_("Required CloudNetwork/@name, @provider, @profile, @id or @enabled attribute is missing"));
2049 }
2050 }
2051}
2052#endif /* VBOX_WITH_CLOUD_NET */
2053
2054/**
2055 * Creates \<USBDeviceSource\> nodes under the given parent element according to
2056 * the contents of the given USBDeviceSourcesList.
2057 *
2058 * @param elmParent
2059 * @param ll
2060 */
2061void MainConfigFile::buildUSBDeviceSources(xml::ElementNode &elmParent,
2062 const USBDeviceSourcesList &ll)
2063{
2064 for (USBDeviceSourcesList::const_iterator it = ll.begin();
2065 it != ll.end();
2066 ++it)
2067 {
2068 const USBDeviceSource &src = *it;
2069 xml::ElementNode *pelmSource = elmParent.createChild("USBDeviceSource");
2070 pelmSource->setAttribute("name", src.strName);
2071 pelmSource->setAttribute("backend", src.strBackend);
2072 pelmSource->setAttribute("address", src.strAddress);
2073
2074 /* Write the properties. */
2075 for (StringsMap::const_iterator itProp = src.properties.begin();
2076 itProp != src.properties.end();
2077 ++itProp)
2078 {
2079 xml::ElementNode *pelmProp = pelmSource->createChild("Property");
2080 pelmProp->setAttribute("name", itProp->first);
2081 pelmProp->setAttribute("value", itProp->second);
2082 }
2083 }
2084}
2085
2086/**
2087 * Reads \<USBDeviceFilter\> entries from under the given elmDeviceFilters node and
2088 * stores them in the given linklist. This is in ConfigFileBase because it's used
2089 * from both MainConfigFile (for host filters) and MachineConfigFile (for machine
2090 * filters).
2091 * @param elmDeviceSources
2092 * @param ll
2093 */
2094void MainConfigFile::readUSBDeviceSources(const xml::ElementNode &elmDeviceSources,
2095 USBDeviceSourcesList &ll)
2096{
2097 xml::NodesLoop nl1(elmDeviceSources, "USBDeviceSource");
2098 const xml::ElementNode *pelmChild;
2099 while ((pelmChild = nl1.forAllNodes()))
2100 {
2101 USBDeviceSource src;
2102
2103 if ( pelmChild->getAttributeValue("name", src.strName)
2104 && pelmChild->getAttributeValue("backend", src.strBackend)
2105 && pelmChild->getAttributeValue("address", src.strAddress))
2106 {
2107 // handle medium properties
2108 xml::NodesLoop nl2(*pelmChild, "Property");
2109 const xml::ElementNode *pelmSrcChild;
2110 while ((pelmSrcChild = nl2.forAllNodes()))
2111 {
2112 Utf8Str strPropName, strPropValue;
2113 if ( pelmSrcChild->getAttributeValue("name", strPropName)
2114 && pelmSrcChild->getAttributeValue("value", strPropValue) )
2115 src.properties[strPropName] = strPropValue;
2116 else
2117 throw ConfigFileError(this, pelmSrcChild, N_("Required USBDeviceSource/Property/@name or @value attribute is missing"));
2118 }
2119
2120 ll.push_back(src);
2121 }
2122 }
2123}
2124
2125/**
2126 * Converts old style Proxy settings from ExtraData/UI section.
2127 *
2128 * Saves proxy settings directly to systemProperties structure.
2129 *
2130 * @returns true if conversion was successfull, false if not.
2131 * @param strUIProxySettings The GUI settings string to convert.
2132 */
2133bool MainConfigFile::convertGuiProxySettings(const com::Utf8Str &strUIProxySettings)
2134{
2135 /*
2136 * Possible variants:
2137 * - "ProxyAuto,proxyserver.url,1080,authDisabled,,"
2138 * - "ProxyDisabled,proxyserver.url,1080,authDisabled,,"
2139 * - "ProxyEnabled,proxyserver.url,1080,authDisabled,,"
2140 *
2141 * Note! We only need to bother with the first three fields as the last
2142 * three was never really used or ever actually passed to the HTTP
2143 * client code.
2144 */
2145 /* First field: The proxy mode. */
2146 const char *psz = RTStrStripL(strUIProxySettings.c_str());
2147 static const struct { const char *psz; size_t cch; ProxyMode_T enmMode; } s_aModes[] =
2148 {
2149 { RT_STR_TUPLE("ProxyAuto"), ProxyMode_System },
2150 { RT_STR_TUPLE("ProxyDisabled"), ProxyMode_NoProxy },
2151 { RT_STR_TUPLE("ProxyEnabled"), ProxyMode_Manual },
2152 };
2153 for (size_t i = 0; i < RT_ELEMENTS(s_aModes); i++)
2154 if (RTStrNICmpAscii(psz, s_aModes[i].psz, s_aModes[i].cch) == 0)
2155 {
2156 systemProperties.uProxyMode = s_aModes[i].enmMode;
2157 psz = RTStrStripL(psz + s_aModes[i].cch);
2158 if (*psz == ',')
2159 {
2160 /* Second field: The proxy host, possibly fully fledged proxy URL. */
2161 psz = RTStrStripL(psz + 1);
2162 if (*psz != '\0' && *psz != ',')
2163 {
2164 const char *pszEnd = strchr(psz, ',');
2165 size_t cchHost = pszEnd ? (size_t)(pszEnd - psz) : strlen(psz);
2166 while (cchHost > 0 && RT_C_IS_SPACE(psz[cchHost - 1]))
2167 cchHost--;
2168 systemProperties.strProxyUrl.assign(psz, cchHost);
2169 if (systemProperties.strProxyUrl.find("://") == RTCString::npos)
2170 systemProperties.strProxyUrl.replace(0, 0, "http://");
2171
2172 /* Third field: The proxy port. Defaulted to 1080 for all proxies.
2173 The new settings has type specific default ports. */
2174 uint16_t uPort = 1080;
2175 if (pszEnd)
2176 {
2177 int rc = RTStrToUInt16Ex(RTStrStripL(pszEnd + 1), NULL, 10, &uPort);
2178 if (RT_FAILURE(rc))
2179 uPort = 1080;
2180 }
2181 RTURIPARSED Parsed;
2182 int rc = RTUriParse(systemProperties.strProxyUrl.c_str(), &Parsed);
2183 if (RT_SUCCESS(rc))
2184 {
2185 if (Parsed.uAuthorityPort == UINT32_MAX)
2186 systemProperties.strProxyUrl.appendPrintf(systemProperties.strProxyUrl.endsWith(":")
2187 ? "%u" : ":%u", uPort);
2188 }
2189 else
2190 {
2191 LogRelFunc(("Dropping invalid proxy URL for %u: %s\n",
2192 systemProperties.uProxyMode, systemProperties.strProxyUrl.c_str()));
2193 systemProperties.strProxyUrl.setNull();
2194 }
2195 }
2196 /* else: don't bother with the rest if we haven't got a host. */
2197 }
2198 if ( systemProperties.strProxyUrl.isEmpty()
2199 && systemProperties.uProxyMode == ProxyMode_Manual)
2200 {
2201 systemProperties.uProxyMode = ProxyMode_System;
2202 return false;
2203 }
2204 return true;
2205 }
2206 LogRelFunc(("Unknown proxy type: %s\n", psz));
2207 return false;
2208}
2209
2210/**
2211 * Constructor.
2212 *
2213 * If pstrFilename is != NULL, this reads the given settings file into the member
2214 * variables and various substructures and lists. Otherwise, the member variables
2215 * are initialized with default values.
2216 *
2217 * Throws variants of xml::Error for I/O, XML and logical content errors, which
2218 * the caller should catch; if this constructor does not throw, then the member
2219 * variables contain meaningful values (either from the file or defaults).
2220 *
2221 * @param pstrFilename
2222 */
2223MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename)
2224 : ConfigFileBase(pstrFilename)
2225{
2226 if (pstrFilename)
2227 {
2228 // the ConfigFileBase constructor has loaded the XML file, so now
2229 // we need only analyze what is in there
2230 xml::NodesLoop nlRootChildren(*m->pelmRoot);
2231 const xml::ElementNode *pelmRootChild;
2232 bool fCopyProxySettingsFromExtraData = false;
2233 while ((pelmRootChild = nlRootChildren.forAllNodes()))
2234 {
2235 if (pelmRootChild->nameEquals("Global"))
2236 {
2237 xml::NodesLoop nlGlobalChildren(*pelmRootChild);
2238 const xml::ElementNode *pelmGlobalChild;
2239 while ((pelmGlobalChild = nlGlobalChildren.forAllNodes()))
2240 {
2241 if (pelmGlobalChild->nameEquals("SystemProperties"))
2242 {
2243 pelmGlobalChild->getAttributeValue("defaultMachineFolder", systemProperties.strDefaultMachineFolder);
2244 pelmGlobalChild->getAttributeValue("LoggingLevel", systemProperties.strLoggingLevel);
2245 pelmGlobalChild->getAttributeValue("defaultHardDiskFormat", systemProperties.strDefaultHardDiskFormat);
2246 if (!pelmGlobalChild->getAttributeValue("VRDEAuthLibrary", systemProperties.strVRDEAuthLibrary))
2247 // pre-1.11 used @remoteDisplayAuthLibrary instead
2248 pelmGlobalChild->getAttributeValue("remoteDisplayAuthLibrary", systemProperties.strVRDEAuthLibrary);
2249 pelmGlobalChild->getAttributeValue("webServiceAuthLibrary", systemProperties.strWebServiceAuthLibrary);
2250 pelmGlobalChild->getAttributeValue("defaultVRDEExtPack", systemProperties.strDefaultVRDEExtPack);
2251 pelmGlobalChild->getAttributeValue("LogHistoryCount", systemProperties.uLogHistoryCount);
2252 pelmGlobalChild->getAttributeValue("autostartDatabasePath", systemProperties.strAutostartDatabasePath);
2253 pelmGlobalChild->getAttributeValue("defaultFrontend", systemProperties.strDefaultFrontend);
2254 pelmGlobalChild->getAttributeValue("exclusiveHwVirt", systemProperties.fExclusiveHwVirt);
2255 if (!pelmGlobalChild->getAttributeValue("proxyMode", systemProperties.uProxyMode))
2256 fCopyProxySettingsFromExtraData = true;
2257 pelmGlobalChild->getAttributeValue("proxyUrl", systemProperties.strProxyUrl);
2258 pelmGlobalChild->getAttributeValue("VBoxUpdateEnabled", systemProperties.fVBoxUpdateEnabled);
2259 pelmGlobalChild->getAttributeValue("VBoxUpdateCount", systemProperties.uVBoxUpdateCount);
2260 pelmGlobalChild->getAttributeValue("VBoxUpdateFrequency", systemProperties.uVBoxUpdateFrequency);
2261 pelmGlobalChild->getAttributeValue("VBoxUpdateTarget", systemProperties.uVBoxUpdateTarget);
2262 pelmGlobalChild->getAttributeValue("VBoxUpdateLastCheckDate",
2263 systemProperties.strVBoxUpdateLastCheckDate);
2264 pelmGlobalChild->getAttributeValue("LanguageId", systemProperties.strLanguageId);
2265 }
2266 else if (pelmGlobalChild->nameEquals("ExtraData"))
2267 readExtraData(*pelmGlobalChild, mapExtraDataItems);
2268 else if (pelmGlobalChild->nameEquals("MachineRegistry"))
2269 readMachineRegistry(*pelmGlobalChild);
2270 else if ( (pelmGlobalChild->nameEquals("MediaRegistry"))
2271 || ( (m->sv < SettingsVersion_v1_4)
2272 && (pelmGlobalChild->nameEquals("DiskRegistry"))
2273 )
2274 )
2275 readMediaRegistry(*pelmGlobalChild, mediaRegistry);
2276 else if (pelmGlobalChild->nameEquals("NetserviceRegistry"))
2277 {
2278 xml::NodesLoop nlLevel4(*pelmGlobalChild);
2279 const xml::ElementNode *pelmLevel4Child;
2280 while ((pelmLevel4Child = nlLevel4.forAllNodes()))
2281 {
2282 if (pelmLevel4Child->nameEquals("DHCPServers"))
2283 readDHCPServers(*pelmLevel4Child);
2284 if (pelmLevel4Child->nameEquals("NATNetworks"))
2285 readNATNetworks(*pelmLevel4Child);
2286#ifdef VBOX_WITH_CLOUD_NET
2287 if (pelmLevel4Child->nameEquals("CloudNetworks"))
2288 readCloudNetworks(*pelmLevel4Child);
2289#endif /* VBOX_WITH_CLOUD_NET */
2290 }
2291 }
2292 else if (pelmGlobalChild->nameEquals("USBDeviceFilters"))
2293 readUSBDeviceFilters(*pelmGlobalChild, host.llUSBDeviceFilters);
2294 else if (pelmGlobalChild->nameEquals("USBDeviceSources"))
2295 readUSBDeviceSources(*pelmGlobalChild, host.llUSBDeviceSources);
2296 }
2297 } // end if (pelmRootChild->nameEquals("Global"))
2298 }
2299
2300 if (fCopyProxySettingsFromExtraData)
2301 for (StringsMap::const_iterator it = mapExtraDataItems.begin(); it != mapExtraDataItems.end(); ++it)
2302 if (it->first.equals("GUI/ProxySettings"))
2303 {
2304 convertGuiProxySettings(it->second);
2305 break;
2306 }
2307
2308 clearDocument();
2309 }
2310
2311 // DHCP servers were introduced with settings version 1.7; if we're loading
2312 // from an older version OR this is a fresh install, then add one DHCP server
2313 // with default settings
2314 if ( (!llDhcpServers.size())
2315 && ( (!pstrFilename) // empty VirtualBox.xml file
2316 || (m->sv < SettingsVersion_v1_7) // upgrading from before 1.7
2317 )
2318 )
2319 {
2320 DHCPServer srv;
2321#ifdef RT_OS_WINDOWS
2322 srv.strNetworkName = "HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter";
2323#else
2324 srv.strNetworkName = "HostInterfaceNetworking-vboxnet0";
2325#endif
2326 srv.strIPAddress = "192.168.56.100";
2327 srv.globalConfig.mapOptions[DHCPOption_SubnetMask] = DhcpOptValue("255.255.255.0");
2328 srv.strIPLower = "192.168.56.101";
2329 srv.strIPUpper = "192.168.56.254";
2330 srv.fEnabled = true;
2331 llDhcpServers.push_back(srv);
2332 }
2333}
2334
2335void MainConfigFile::bumpSettingsVersionIfNeeded()
2336{
2337#ifdef VBOX_WITH_CLOUD_NET
2338 if (m->sv < SettingsVersion_v1_18)
2339 {
2340 // VirtualBox 6.1 adds support for cloud networks.
2341 if (!llCloudNetworks.empty())
2342 m->sv = SettingsVersion_v1_18;
2343 }
2344#endif /* VBOX_WITH_CLOUD_NET */
2345
2346 if (m->sv < SettingsVersion_v1_16)
2347 {
2348 // VirtualBox 5.1 add support for additional USB device sources.
2349 if (!host.llUSBDeviceSources.empty())
2350 m->sv = SettingsVersion_v1_16;
2351 }
2352
2353 if (m->sv < SettingsVersion_v1_14)
2354 {
2355 // VirtualBox 4.3 adds NAT networks.
2356 if ( !llNATNetworks.empty())
2357 m->sv = SettingsVersion_v1_14;
2358 }
2359}
2360
2361
2362/**
2363 * Called from the IVirtualBox interface to write out VirtualBox.xml. This
2364 * builds an XML DOM tree and writes it out to disk.
2365 */
2366void MainConfigFile::write(const com::Utf8Str strFilename)
2367{
2368 bumpSettingsVersionIfNeeded();
2369
2370 m->strFilename = strFilename;
2371 specialBackupIfFirstBump();
2372 createStubDocument();
2373
2374 xml::ElementNode *pelmGlobal = m->pelmRoot->createChild("Global");
2375
2376 buildExtraData(*pelmGlobal, mapExtraDataItems);
2377
2378 xml::ElementNode *pelmMachineRegistry = pelmGlobal->createChild("MachineRegistry");
2379 for (MachinesRegistry::const_iterator it = llMachines.begin();
2380 it != llMachines.end();
2381 ++it)
2382 {
2383 // <MachineEntry uuid="{5f102a55-a51b-48e3-b45a-b28d33469488}" src="/mnt/innotek-unix/vbox-machines/Windows 5.1 XP 1 (Office 2003)/Windows 5.1 XP 1 (Office 2003).xml"/>
2384 const MachineRegistryEntry &mre = *it;
2385 xml::ElementNode *pelmMachineEntry = pelmMachineRegistry->createChild("MachineEntry");
2386 pelmMachineEntry->setAttribute("uuid", mre.uuid.toStringCurly());
2387 pelmMachineEntry->setAttribute("src", mre.strSettingsFile);
2388 }
2389
2390 buildMediaRegistry(*pelmGlobal, mediaRegistry);
2391
2392 xml::ElementNode *pelmNetServiceRegistry = pelmGlobal->createChild("NetserviceRegistry"); /** @todo r=bird: wrong capitalization of NetServiceRegistry. sigh. */
2393 buildDHCPServers(*pelmNetServiceRegistry->createChild("DHCPServers"), llDhcpServers);
2394
2395 xml::ElementNode *pelmNATNetworks;
2396 /* don't create entry if no NAT networks are registered. */
2397 if (!llNATNetworks.empty())
2398 {
2399 pelmNATNetworks = pelmNetServiceRegistry->createChild("NATNetworks");
2400 for (NATNetworksList::const_iterator it = llNATNetworks.begin();
2401 it != llNATNetworks.end();
2402 ++it)
2403 {
2404 const NATNetwork &n = *it;
2405 xml::ElementNode *pelmThis = pelmNATNetworks->createChild("NATNetwork");
2406 pelmThis->setAttribute("networkName", n.strNetworkName);
2407 pelmThis->setAttribute("network", n.strIPv4NetworkCidr);
2408 pelmThis->setAttribute("ipv6", n.fIPv6Enabled ? 1 : 0);
2409 pelmThis->setAttribute("ipv6prefix", n.strIPv6Prefix);
2410 pelmThis->setAttribute("advertiseDefaultIPv6Route", (n.fAdvertiseDefaultIPv6Route)? 1 : 0);
2411 pelmThis->setAttribute("needDhcp", (n.fNeedDhcpServer) ? 1 : 0);
2412 pelmThis->setAttribute("enabled", (n.fEnabled) ? 1 : 0); // too bad we chose 1 vs. 0 here
2413 if (n.mapPortForwardRules4.size())
2414 {
2415 xml::ElementNode *pelmPf4 = pelmThis->createChild("PortForwarding4");
2416 buildNATForwardRulesMap(*pelmPf4, n.mapPortForwardRules4);
2417 }
2418 if (n.mapPortForwardRules6.size())
2419 {
2420 xml::ElementNode *pelmPf6 = pelmThis->createChild("PortForwarding6");
2421 buildNATForwardRulesMap(*pelmPf6, n.mapPortForwardRules6);
2422 }
2423
2424 if (n.llHostLoopbackOffsetList.size())
2425 {
2426 xml::ElementNode *pelmMappings = pelmThis->createChild("Mappings");
2427 buildNATLoopbacks(*pelmMappings, n.llHostLoopbackOffsetList);
2428
2429 }
2430 }
2431 }
2432
2433#ifdef VBOX_WITH_CLOUD_NET
2434 xml::ElementNode *pelmCloudNetworks;
2435 /* don't create entry if no cloud networks are registered. */
2436 if (!llCloudNetworks.empty())
2437 {
2438 pelmCloudNetworks = pelmNetServiceRegistry->createChild("CloudNetworks");
2439 for (CloudNetworksList::const_iterator it = llCloudNetworks.begin();
2440 it != llCloudNetworks.end();
2441 ++it)
2442 {
2443 const CloudNetwork &n = *it;
2444 xml::ElementNode *pelmThis = pelmCloudNetworks->createChild("CloudNetwork");
2445 pelmThis->setAttribute("name", n.strNetworkName);
2446 pelmThis->setAttribute("provider", n.strProviderShortName);
2447 pelmThis->setAttribute("profile", n.strProfileName);
2448 pelmThis->setAttribute("id", n.strNetworkId);
2449 pelmThis->setAttribute("enabled", (n.fEnabled) ? 1 : 0); // too bad we chose 1 vs. 0 here
2450 }
2451 }
2452#endif /* VBOX_WITH_CLOUD_NET */
2453
2454
2455 xml::ElementNode *pelmSysProps = pelmGlobal->createChild("SystemProperties");
2456 if (systemProperties.strDefaultMachineFolder.length())
2457 pelmSysProps->setAttribute("defaultMachineFolder", systemProperties.strDefaultMachineFolder);
2458 if (systemProperties.strLoggingLevel.length())
2459 pelmSysProps->setAttribute("LoggingLevel", systemProperties.strLoggingLevel);
2460 if (systemProperties.strDefaultHardDiskFormat.length())
2461 pelmSysProps->setAttribute("defaultHardDiskFormat", systemProperties.strDefaultHardDiskFormat);
2462 if (systemProperties.strVRDEAuthLibrary.length())
2463 pelmSysProps->setAttribute("VRDEAuthLibrary", systemProperties.strVRDEAuthLibrary);
2464 if (systemProperties.strWebServiceAuthLibrary.length())
2465 pelmSysProps->setAttribute("webServiceAuthLibrary", systemProperties.strWebServiceAuthLibrary);
2466 if (systemProperties.strDefaultVRDEExtPack.length())
2467 pelmSysProps->setAttribute("defaultVRDEExtPack", systemProperties.strDefaultVRDEExtPack);
2468 pelmSysProps->setAttribute("LogHistoryCount", systemProperties.uLogHistoryCount);
2469 if (systemProperties.strAutostartDatabasePath.length())
2470 pelmSysProps->setAttribute("autostartDatabasePath", systemProperties.strAutostartDatabasePath);
2471 if (systemProperties.strDefaultFrontend.length())
2472 pelmSysProps->setAttribute("defaultFrontend", systemProperties.strDefaultFrontend);
2473 if (systemProperties.strProxyUrl.length())
2474 pelmSysProps->setAttribute("proxyUrl", systemProperties.strProxyUrl);
2475 pelmSysProps->setAttribute("proxyMode", systemProperties.uProxyMode);
2476 pelmSysProps->setAttribute("exclusiveHwVirt", systemProperties.fExclusiveHwVirt);
2477 pelmSysProps->setAttribute("VBoxUpdateEnabled", systemProperties.fVBoxUpdateEnabled);
2478 pelmSysProps->setAttribute("VBoxUpdateCount", systemProperties.uVBoxUpdateCount);
2479 pelmSysProps->setAttribute("VBoxUpdateFrequency", systemProperties.uVBoxUpdateFrequency);
2480 pelmSysProps->setAttribute("VBoxUpdateTarget", systemProperties.uVBoxUpdateTarget);
2481 if (systemProperties.strVBoxUpdateLastCheckDate.length())
2482 pelmSysProps->setAttribute("VBoxUpdateLastCheckDate", systemProperties.strVBoxUpdateLastCheckDate);
2483 if (systemProperties.strLanguageId.isNotEmpty())
2484 pelmSysProps->setAttribute("LanguageId", systemProperties.strLanguageId);
2485
2486 buildUSBDeviceFilters(*pelmGlobal->createChild("USBDeviceFilters"),
2487 host.llUSBDeviceFilters,
2488 true); // fHostMode
2489
2490 if (!host.llUSBDeviceSources.empty())
2491 buildUSBDeviceSources(*pelmGlobal->createChild("USBDeviceSources"),
2492 host.llUSBDeviceSources);
2493
2494 // now go write the XML
2495 xml::XmlFileWriter writer(*m->pDoc);
2496 writer.write(m->strFilename.c_str(), true /*fSafe*/);
2497
2498 m->fFileExists = true;
2499
2500 clearDocument();
2501}
2502
2503////////////////////////////////////////////////////////////////////////////////
2504//
2505// Machine XML structures
2506//
2507////////////////////////////////////////////////////////////////////////////////
2508
2509/**
2510 * Constructor. Needs to set sane defaults which stand the test of time.
2511 */
2512VRDESettings::VRDESettings() :
2513 fEnabled(true), // default for old VMs, for new ones it's false
2514 authType(AuthType_Null),
2515 ulAuthTimeout(5000),
2516 fAllowMultiConnection(false),
2517 fReuseSingleConnection(false)
2518{
2519}
2520
2521/**
2522 * Check if all settings have default values.
2523 */
2524bool VRDESettings::areDefaultSettings(SettingsVersion_T sv) const
2525{
2526 return (sv < SettingsVersion_v1_16 ? fEnabled : !fEnabled)
2527 && authType == AuthType_Null
2528 && (ulAuthTimeout == 5000 || ulAuthTimeout == 0)
2529 && strAuthLibrary.isEmpty()
2530 && !fAllowMultiConnection
2531 && !fReuseSingleConnection
2532 && strVrdeExtPack.isEmpty()
2533 && mapProperties.size() == 0;
2534}
2535
2536/**
2537 * Comparison operator. This gets called from MachineConfigFile::operator==,
2538 * which in turn gets called from Machine::saveSettings to figure out whether
2539 * machine settings have really changed and thus need to be written out to disk.
2540 */
2541bool VRDESettings::operator==(const VRDESettings& v) const
2542{
2543 return (this == &v)
2544 || ( fEnabled == v.fEnabled
2545 && authType == v.authType
2546 && ulAuthTimeout == v.ulAuthTimeout
2547 && strAuthLibrary == v.strAuthLibrary
2548 && fAllowMultiConnection == v.fAllowMultiConnection
2549 && fReuseSingleConnection == v.fReuseSingleConnection
2550 && strVrdeExtPack == v.strVrdeExtPack
2551 && mapProperties == v.mapProperties);
2552}
2553
2554/**
2555 * Constructor. Needs to set sane defaults which stand the test of time.
2556 */
2557BIOSSettings::BIOSSettings() :
2558 fACPIEnabled(true),
2559 fIOAPICEnabled(false),
2560 fLogoFadeIn(true),
2561 fLogoFadeOut(true),
2562 fPXEDebugEnabled(false),
2563 fSmbiosUuidLittleEndian(true),
2564 ulLogoDisplayTime(0),
2565 biosBootMenuMode(BIOSBootMenuMode_MessageAndMenu),
2566 apicMode(APICMode_APIC),
2567 llTimeOffset(0)
2568{
2569}
2570
2571/**
2572 * Check if all settings have default values.
2573 */
2574bool BIOSSettings::areDefaultSettings() const
2575{
2576 return fACPIEnabled
2577 && !fIOAPICEnabled
2578 && fLogoFadeIn
2579 && fLogoFadeOut
2580 && !fPXEDebugEnabled
2581 && !fSmbiosUuidLittleEndian
2582 && ulLogoDisplayTime == 0
2583 && biosBootMenuMode == BIOSBootMenuMode_MessageAndMenu
2584 && apicMode == APICMode_APIC
2585 && llTimeOffset == 0
2586 && strLogoImagePath.isEmpty()
2587 && strNVRAMPath.isEmpty();
2588}
2589
2590/**
2591 * Comparison operator. This gets called from MachineConfigFile::operator==,
2592 * which in turn gets called from Machine::saveSettings to figure out whether
2593 * machine settings have really changed and thus need to be written out to disk.
2594 */
2595bool BIOSSettings::operator==(const BIOSSettings &d) const
2596{
2597 return (this == &d)
2598 || ( fACPIEnabled == d.fACPIEnabled
2599 && fIOAPICEnabled == d.fIOAPICEnabled
2600 && fLogoFadeIn == d.fLogoFadeIn
2601 && fLogoFadeOut == d.fLogoFadeOut
2602 && fPXEDebugEnabled == d.fPXEDebugEnabled
2603 && fSmbiosUuidLittleEndian == d.fSmbiosUuidLittleEndian
2604 && ulLogoDisplayTime == d.ulLogoDisplayTime
2605 && biosBootMenuMode == d.biosBootMenuMode
2606 && apicMode == d.apicMode
2607 && llTimeOffset == d.llTimeOffset
2608 && strLogoImagePath == d.strLogoImagePath
2609 && strNVRAMPath == d.strNVRAMPath);
2610}
2611
2612RecordingScreenSettings::RecordingScreenSettings(void)
2613{
2614 applyDefaults();
2615}
2616
2617RecordingScreenSettings::~RecordingScreenSettings()
2618{
2619
2620}
2621
2622/**
2623 * Applies the default settings.
2624 */
2625void RecordingScreenSettings::applyDefaults(void)
2626{
2627 /*
2628 * Set sensible defaults.
2629 */
2630
2631 fEnabled = false;
2632 enmDest = RecordingDestination_File;
2633 ulMaxTimeS = 0;
2634 strOptions = "";
2635 File.ulMaxSizeMB = 0;
2636 File.strName = "";
2637 Video.enmCodec = RecordingVideoCodec_VP8;
2638 Video.ulWidth = 1024;
2639 Video.ulHeight = 768;
2640 Video.ulRate = 512;
2641 Video.ulFPS = 25;
2642 Audio.enmAudioCodec = RecordingAudioCodec_Opus;
2643 Audio.cBits = 16;
2644 Audio.cChannels = 2;
2645 Audio.uHz = 22050;
2646
2647 featureMap[RecordingFeature_Video] = true;
2648 featureMap[RecordingFeature_Audio] = false; /** @todo Audio is not yet enabled by default. */
2649}
2650
2651/**
2652 * Check if all settings have default values.
2653 */
2654bool RecordingScreenSettings::areDefaultSettings(void) const
2655{
2656 return fEnabled == false
2657 && enmDest == RecordingDestination_File
2658 && ulMaxTimeS == 0
2659 && strOptions == ""
2660 && File.ulMaxSizeMB == 0
2661 && File.strName == ""
2662 && Video.enmCodec == RecordingVideoCodec_VP8
2663 && Video.ulWidth == 1024
2664 && Video.ulHeight == 768
2665 && Video.ulRate == 512
2666 && Video.ulFPS == 25
2667 && Audio.enmAudioCodec == RecordingAudioCodec_Opus
2668 && Audio.cBits == 16
2669 && Audio.cChannels == 2
2670 && Audio.uHz == 22050;
2671}
2672
2673/**
2674 * Returns if a certain recording feature is enabled or not.
2675 *
2676 * @returns \c true if the feature is enabled, \c false if not.
2677 * @param enmFeature Feature to check.
2678 */
2679bool RecordingScreenSettings::isFeatureEnabled(RecordingFeature_T enmFeature) const
2680{
2681 RecordingFeatureMap::const_iterator itFeature = featureMap.find(enmFeature);
2682 if (itFeature != featureMap.end())
2683 return itFeature->second;
2684
2685 return false;
2686}
2687
2688/**
2689 * Comparison operator. This gets called from MachineConfigFile::operator==,
2690 * which in turn gets called from Machine::saveSettings to figure out whether
2691 * machine settings have really changed and thus need to be written out to disk.
2692 */
2693bool RecordingScreenSettings::operator==(const RecordingScreenSettings &d) const
2694{
2695 return fEnabled == d.fEnabled
2696 && enmDest == d.enmDest
2697 && featureMap == d.featureMap
2698 && ulMaxTimeS == d.ulMaxTimeS
2699 && strOptions == d.strOptions
2700 && File.ulMaxSizeMB == d.File.ulMaxSizeMB
2701 && Video.enmCodec == d.Video.enmCodec
2702 && Video.ulWidth == d.Video.ulWidth
2703 && Video.ulHeight == d.Video.ulHeight
2704 && Video.ulRate == d.Video.ulRate
2705 && Video.ulFPS == d.Video.ulFPS
2706 && Audio.enmAudioCodec == d.Audio.enmAudioCodec
2707 && Audio.cBits == d.Audio.cBits
2708 && Audio.cChannels == d.Audio.cChannels
2709 && Audio.uHz == d.Audio.uHz;
2710}
2711
2712/**
2713 * Constructor. Needs to set sane defaults which stand the test of time.
2714 */
2715RecordingSettings::RecordingSettings()
2716{
2717 applyDefaults();
2718}
2719
2720/**
2721 * Applies the default settings.
2722 */
2723void RecordingSettings::applyDefaults(void)
2724{
2725 fEnabled = false;
2726
2727 mapScreens.clear();
2728
2729 try
2730 {
2731 /* Always add screen 0 to the default configuration. */
2732 RecordingScreenSettings screenSettings; /* Apply default settings for screen 0. */
2733 screenSettings.fEnabled = true; /* Enabled by default. */
2734 mapScreens[0] = screenSettings;
2735 }
2736 catch (std::bad_alloc &)
2737 {
2738 AssertFailed();
2739 }
2740}
2741
2742/**
2743 * Check if all settings have default values.
2744 */
2745bool RecordingSettings::areDefaultSettings() const
2746{
2747 const bool fDefault = fEnabled == false
2748 && mapScreens.size() == 1;
2749 if (!fDefault)
2750 return false;
2751
2752 RecordingScreenMap::const_iterator itScreen = mapScreens.begin();
2753 return itScreen->first == 0
2754 && itScreen->second.areDefaultSettings();
2755}
2756
2757/**
2758 * Comparison operator. This gets called from MachineConfigFile::operator==,
2759 * which in turn gets called from Machine::saveSettings to figure out whether
2760 * machine settings have really changed and thus need to be written out to disk.
2761 */
2762bool RecordingSettings::operator==(const RecordingSettings &d) const
2763{
2764 if (this == &d)
2765 return true;
2766
2767 if ( fEnabled != d.fEnabled
2768 || mapScreens.size() != d.mapScreens.size())
2769 return false;
2770
2771 RecordingScreenMap::const_iterator itScreen = mapScreens.begin();
2772 uint32_t i = 0;
2773 while (itScreen != mapScreens.end())
2774 {
2775 RecordingScreenMap::const_iterator itScreenThat = d.mapScreens.find(i);
2776 if (itScreen->second == itScreenThat->second)
2777 {
2778 /* Nothing to do in here (yet). */
2779 }
2780 else
2781 return false;
2782
2783 ++itScreen;
2784 ++i;
2785 }
2786
2787 return true;
2788}
2789
2790/**
2791 * Constructor. Needs to set sane defaults which stand the test of time.
2792 */
2793GraphicsAdapter::GraphicsAdapter() :
2794 graphicsControllerType(GraphicsControllerType_VBoxVGA),
2795 ulVRAMSizeMB(8),
2796 cMonitors(1),
2797 fAccelerate3D(false),
2798 fAccelerate2DVideo(false)
2799{
2800}
2801
2802/**
2803 * Check if all settings have default values.
2804 */
2805bool GraphicsAdapter::areDefaultSettings() const
2806{
2807 return graphicsControllerType == GraphicsControllerType_VBoxVGA
2808 && ulVRAMSizeMB == 8
2809 && cMonitors <= 1
2810 && !fAccelerate3D
2811 && !fAccelerate2DVideo;
2812}
2813
2814/**
2815 * Comparison operator. This gets called from MachineConfigFile::operator==,
2816 * which in turn gets called from Machine::saveSettings to figure out whether
2817 * machine settings have really changed and thus need to be written out to disk.
2818 */
2819bool GraphicsAdapter::operator==(const GraphicsAdapter &g) const
2820{
2821 return (this == &g)
2822 || ( graphicsControllerType == g.graphicsControllerType
2823 && ulVRAMSizeMB == g.ulVRAMSizeMB
2824 && cMonitors == g.cMonitors
2825 && fAccelerate3D == g.fAccelerate3D
2826 && fAccelerate2DVideo == g.fAccelerate2DVideo);
2827}
2828
2829/**
2830 * Constructor. Needs to set sane defaults which stand the test of time.
2831 */
2832USBController::USBController() :
2833 enmType(USBControllerType_Null)
2834{
2835}
2836
2837/**
2838 * Comparison operator. This gets called from MachineConfigFile::operator==,
2839 * which in turn gets called from Machine::saveSettings to figure out whether
2840 * machine settings have really changed and thus need to be written out to disk.
2841 */
2842bool USBController::operator==(const USBController &u) const
2843{
2844 return (this == &u)
2845 || ( strName == u.strName
2846 && enmType == u.enmType);
2847}
2848
2849/**
2850 * Constructor. Needs to set sane defaults which stand the test of time.
2851 */
2852USB::USB()
2853{
2854}
2855
2856/**
2857 * Comparison operator. This gets called from MachineConfigFile::operator==,
2858 * which in turn gets called from Machine::saveSettings to figure out whether
2859 * machine settings have really changed and thus need to be written out to disk.
2860 */
2861bool USB::operator==(const USB &u) const
2862{
2863 return (this == &u)
2864 || ( llUSBControllers == u.llUSBControllers
2865 && llDeviceFilters == u.llDeviceFilters);
2866}
2867
2868/**
2869 * Constructor. Needs to set sane defaults which stand the test of time.
2870 */
2871NAT::NAT() :
2872 u32Mtu(0),
2873 u32SockRcv(0),
2874 u32SockSnd(0),
2875 u32TcpRcv(0),
2876 u32TcpSnd(0),
2877 fDNSPassDomain(true), /* historically this value is true */
2878 fDNSProxy(false),
2879 fDNSUseHostResolver(false),
2880 fAliasLog(false),
2881 fAliasProxyOnly(false),
2882 fAliasUseSamePorts(false)
2883{
2884}
2885
2886/**
2887 * Check if all DNS settings have default values.
2888 */
2889bool NAT::areDNSDefaultSettings() const
2890{
2891 return fDNSPassDomain && !fDNSProxy && !fDNSUseHostResolver;
2892}
2893
2894/**
2895 * Check if all Alias settings have default values.
2896 */
2897bool NAT::areAliasDefaultSettings() const
2898{
2899 return !fAliasLog && !fAliasProxyOnly && !fAliasUseSamePorts;
2900}
2901
2902/**
2903 * Check if all TFTP settings have default values.
2904 */
2905bool NAT::areTFTPDefaultSettings() const
2906{
2907 return strTFTPPrefix.isEmpty()
2908 && strTFTPBootFile.isEmpty()
2909 && strTFTPNextServer.isEmpty();
2910}
2911
2912/**
2913 * Check if all settings have default values.
2914 */
2915bool NAT::areDefaultSettings() const
2916{
2917 return strNetwork.isEmpty()
2918 && strBindIP.isEmpty()
2919 && u32Mtu == 0
2920 && u32SockRcv == 0
2921 && u32SockSnd == 0
2922 && u32TcpRcv == 0
2923 && u32TcpSnd == 0
2924 && areDNSDefaultSettings()
2925 && areAliasDefaultSettings()
2926 && areTFTPDefaultSettings()
2927 && mapRules.size() == 0;
2928}
2929
2930/**
2931 * Comparison operator. This gets called from MachineConfigFile::operator==,
2932 * which in turn gets called from Machine::saveSettings to figure out whether
2933 * machine settings have really changed and thus need to be written out to disk.
2934 */
2935bool NAT::operator==(const NAT &n) const
2936{
2937 return (this == &n)
2938 || ( strNetwork == n.strNetwork
2939 && strBindIP == n.strBindIP
2940 && u32Mtu == n.u32Mtu
2941 && u32SockRcv == n.u32SockRcv
2942 && u32SockSnd == n.u32SockSnd
2943 && u32TcpSnd == n.u32TcpSnd
2944 && u32TcpRcv == n.u32TcpRcv
2945 && strTFTPPrefix == n.strTFTPPrefix
2946 && strTFTPBootFile == n.strTFTPBootFile
2947 && strTFTPNextServer == n.strTFTPNextServer
2948 && fDNSPassDomain == n.fDNSPassDomain
2949 && fDNSProxy == n.fDNSProxy
2950 && fDNSUseHostResolver == n.fDNSUseHostResolver
2951 && fAliasLog == n.fAliasLog
2952 && fAliasProxyOnly == n.fAliasProxyOnly
2953 && fAliasUseSamePorts == n.fAliasUseSamePorts
2954 && mapRules == n.mapRules);
2955}
2956
2957/**
2958 * Constructor. Needs to set sane defaults which stand the test of time.
2959 */
2960NetworkAdapter::NetworkAdapter() :
2961 ulSlot(0),
2962 type(NetworkAdapterType_Am79C970A), // default for old VMs, for new ones it's Am79C973
2963 fEnabled(false),
2964 fCableConnected(false), // default for old VMs, for new ones it's true
2965 ulLineSpeed(0),
2966 enmPromiscModePolicy(NetworkAdapterPromiscModePolicy_Deny),
2967 fTraceEnabled(false),
2968 mode(NetworkAttachmentType_Null),
2969 ulBootPriority(0)
2970{
2971}
2972
2973/**
2974 * Check if all Generic Driver settings have default values.
2975 */
2976bool NetworkAdapter::areGenericDriverDefaultSettings() const
2977{
2978 return strGenericDriver.isEmpty()
2979 && genericProperties.size() == 0;
2980}
2981
2982/**
2983 * Check if all settings have default values.
2984 */
2985bool NetworkAdapter::areDefaultSettings(SettingsVersion_T sv) const
2986{
2987 // 5.0 and earlier had a default of fCableConnected=false, which doesn't
2988 // make a lot of sense (but it's a fact). Later versions don't save the
2989 // setting if it's at the default value and thus must get it right.
2990 return !fEnabled
2991 && strMACAddress.isEmpty()
2992 && ( (sv >= SettingsVersion_v1_16 && fCableConnected && type == NetworkAdapterType_Am79C973)
2993 || (sv < SettingsVersion_v1_16 && !fCableConnected && type == NetworkAdapterType_Am79C970A))
2994 && ulLineSpeed == 0
2995 && enmPromiscModePolicy == NetworkAdapterPromiscModePolicy_Deny
2996 && mode == NetworkAttachmentType_Null
2997 && nat.areDefaultSettings()
2998 && strBridgedName.isEmpty()
2999 && strInternalNetworkName.isEmpty()
3000#ifdef VBOX_WITH_CLOUD_NET
3001 && strCloudNetworkName.isEmpty()
3002#endif /* VBOX_WITH_CLOUD_NET */
3003 && strHostOnlyName.isEmpty()
3004 && areGenericDriverDefaultSettings()
3005 && strNATNetworkName.isEmpty();
3006}
3007
3008/**
3009 * Special check if settings of the non-current attachment type have default values.
3010 */
3011bool NetworkAdapter::areDisabledDefaultSettings() const
3012{
3013 return (mode != NetworkAttachmentType_NAT ? nat.areDefaultSettings() : true)
3014 && (mode != NetworkAttachmentType_Bridged ? strBridgedName.isEmpty() : true)
3015 && (mode != NetworkAttachmentType_Internal ? strInternalNetworkName.isEmpty() : true)
3016#ifdef VBOX_WITH_CLOUD_NET
3017 && (mode != NetworkAttachmentType_Cloud ? strCloudNetworkName.isEmpty() : true)
3018#endif /* VBOX_WITH_CLOUD_NET */
3019 && (mode != NetworkAttachmentType_HostOnly ? strHostOnlyName.isEmpty() : true)
3020 && (mode != NetworkAttachmentType_Generic ? areGenericDriverDefaultSettings() : true)
3021 && (mode != NetworkAttachmentType_NATNetwork ? strNATNetworkName.isEmpty() : true);
3022}
3023
3024/**
3025 * Comparison operator. This gets called from MachineConfigFile::operator==,
3026 * which in turn gets called from Machine::saveSettings to figure out whether
3027 * machine settings have really changed and thus need to be written out to disk.
3028 */
3029bool NetworkAdapter::operator==(const NetworkAdapter &n) const
3030{
3031 return (this == &n)
3032 || ( ulSlot == n.ulSlot
3033 && type == n.type
3034 && fEnabled == n.fEnabled
3035 && strMACAddress == n.strMACAddress
3036 && fCableConnected == n.fCableConnected
3037 && ulLineSpeed == n.ulLineSpeed
3038 && enmPromiscModePolicy == n.enmPromiscModePolicy
3039 && fTraceEnabled == n.fTraceEnabled
3040 && strTraceFile == n.strTraceFile
3041 && mode == n.mode
3042 && nat == n.nat
3043 && strBridgedName == n.strBridgedName
3044 && strHostOnlyName == n.strHostOnlyName
3045 && strInternalNetworkName == n.strInternalNetworkName
3046#ifdef VBOX_WITH_CLOUD_NET
3047 && strCloudNetworkName == n.strCloudNetworkName
3048#endif /* VBOX_WITH_CLOUD_NET */
3049 && strGenericDriver == n.strGenericDriver
3050 && genericProperties == n.genericProperties
3051 && ulBootPriority == n.ulBootPriority
3052 && strBandwidthGroup == n.strBandwidthGroup);
3053}
3054
3055/**
3056 * Constructor. Needs to set sane defaults which stand the test of time.
3057 */
3058SerialPort::SerialPort() :
3059 ulSlot(0),
3060 fEnabled(false),
3061 ulIOBase(0x3f8),
3062 ulIRQ(4),
3063 portMode(PortMode_Disconnected),
3064 fServer(false),
3065 uartType(UartType_U16550A)
3066{
3067}
3068
3069/**
3070 * Comparison operator. This gets called from MachineConfigFile::operator==,
3071 * which in turn gets called from Machine::saveSettings to figure out whether
3072 * machine settings have really changed and thus need to be written out to disk.
3073 */
3074bool SerialPort::operator==(const SerialPort &s) const
3075{
3076 return (this == &s)
3077 || ( ulSlot == s.ulSlot
3078 && fEnabled == s.fEnabled
3079 && ulIOBase == s.ulIOBase
3080 && ulIRQ == s.ulIRQ
3081 && portMode == s.portMode
3082 && strPath == s.strPath
3083 && fServer == s.fServer
3084 && uartType == s.uartType);
3085}
3086
3087/**
3088 * Constructor. Needs to set sane defaults which stand the test of time.
3089 */
3090ParallelPort::ParallelPort() :
3091 ulSlot(0),
3092 fEnabled(false),
3093 ulIOBase(0x378),
3094 ulIRQ(7)
3095{
3096}
3097
3098/**
3099 * Comparison operator. This gets called from MachineConfigFile::operator==,
3100 * which in turn gets called from Machine::saveSettings to figure out whether
3101 * machine settings have really changed and thus need to be written out to disk.
3102 */
3103bool ParallelPort::operator==(const ParallelPort &s) const
3104{
3105 return (this == &s)
3106 || ( ulSlot == s.ulSlot
3107 && fEnabled == s.fEnabled
3108 && ulIOBase == s.ulIOBase
3109 && ulIRQ == s.ulIRQ
3110 && strPath == s.strPath);
3111}
3112
3113/**
3114 * Constructor. Needs to set sane defaults which stand the test of time.
3115 */
3116AudioAdapter::AudioAdapter() :
3117 fEnabled(true), // default for old VMs, for new ones it's false
3118 fEnabledIn(true), // default for old VMs, for new ones it's false
3119 fEnabledOut(true), // default for old VMs, for new ones it's false
3120 controllerType(AudioControllerType_AC97),
3121 codecType(AudioCodecType_STAC9700),
3122 driverType(AudioDriverType_Null)
3123{
3124}
3125
3126/**
3127 * Check if all settings have default values.
3128 */
3129bool AudioAdapter::areDefaultSettings(SettingsVersion_T sv) const
3130{
3131 return (sv < SettingsVersion_v1_16 ? false : !fEnabled)
3132 && (sv <= SettingsVersion_v1_16 ? fEnabledIn : !fEnabledIn)
3133 && (sv <= SettingsVersion_v1_16 ? fEnabledOut : !fEnabledOut)
3134 && fEnabledOut == true
3135 && controllerType == AudioControllerType_AC97
3136 && codecType == AudioCodecType_STAC9700
3137 && properties.size() == 0;
3138}
3139
3140/**
3141 * Comparison operator. This gets called from MachineConfigFile::operator==,
3142 * which in turn gets called from Machine::saveSettings to figure out whether
3143 * machine settings have really changed and thus need to be written out to disk.
3144 */
3145bool AudioAdapter::operator==(const AudioAdapter &a) const
3146{
3147 return (this == &a)
3148 || ( fEnabled == a.fEnabled
3149 && fEnabledIn == a.fEnabledIn
3150 && fEnabledOut == a.fEnabledOut
3151 && controllerType == a.controllerType
3152 && codecType == a.codecType
3153 && driverType == a.driverType
3154 && properties == a.properties);
3155}
3156
3157/**
3158 * Constructor. Needs to set sane defaults which stand the test of time.
3159 */
3160SharedFolder::SharedFolder() :
3161 fWritable(false),
3162 fAutoMount(false)
3163{
3164}
3165
3166/**
3167 * Comparison operator. This gets called from MachineConfigFile::operator==,
3168 * which in turn gets called from Machine::saveSettings to figure out whether
3169 * machine settings have really changed and thus need to be written out to disk.
3170 */
3171bool SharedFolder::operator==(const SharedFolder &g) const
3172{
3173 return (this == &g)
3174 || ( strName == g.strName
3175 && strHostPath == g.strHostPath
3176 && fWritable == g.fWritable
3177 && fAutoMount == g.fAutoMount
3178 && strAutoMountPoint == g.strAutoMountPoint);
3179}
3180
3181/**
3182 * Constructor. Needs to set sane defaults which stand the test of time.
3183 */
3184GuestProperty::GuestProperty() :
3185 timestamp(0)
3186{
3187}
3188
3189/**
3190 * Comparison operator. This gets called from MachineConfigFile::operator==,
3191 * which in turn gets called from Machine::saveSettings to figure out whether
3192 * machine settings have really changed and thus need to be written out to disk.
3193 */
3194bool GuestProperty::operator==(const GuestProperty &g) const
3195{
3196 return (this == &g)
3197 || ( strName == g.strName
3198 && strValue == g.strValue
3199 && timestamp == g.timestamp
3200 && strFlags == g.strFlags);
3201}
3202
3203/**
3204 * Constructor. Needs to set sane defaults which stand the test of time.
3205 */
3206CpuIdLeaf::CpuIdLeaf() :
3207 idx(UINT32_MAX),
3208 idxSub(0),
3209 uEax(0),
3210 uEbx(0),
3211 uEcx(0),
3212 uEdx(0)
3213{
3214}
3215
3216/**
3217 * Comparison operator. This gets called from MachineConfigFile::operator==,
3218 * which in turn gets called from Machine::saveSettings to figure out whether
3219 * machine settings have really changed and thus need to be written out to disk.
3220 */
3221bool CpuIdLeaf::operator==(const CpuIdLeaf &c) const
3222{
3223 return (this == &c)
3224 || ( idx == c.idx
3225 && idxSub == c.idxSub
3226 && uEax == c.uEax
3227 && uEbx == c.uEbx
3228 && uEcx == c.uEcx
3229 && uEdx == c.uEdx);
3230}
3231
3232/**
3233 * Constructor. Needs to set sane defaults which stand the test of time.
3234 */
3235Cpu::Cpu() :
3236 ulId(UINT32_MAX)
3237{
3238}
3239
3240/**
3241 * Comparison operator. This gets called from MachineConfigFile::operator==,
3242 * which in turn gets called from Machine::saveSettings to figure out whether
3243 * machine settings have really changed and thus need to be written out to disk.
3244 */
3245bool Cpu::operator==(const Cpu &c) const
3246{
3247 return (this == &c)
3248 || (ulId == c.ulId);
3249}
3250
3251/**
3252 * Constructor. Needs to set sane defaults which stand the test of time.
3253 */
3254BandwidthGroup::BandwidthGroup() :
3255 cMaxBytesPerSec(0),
3256 enmType(BandwidthGroupType_Null)
3257{
3258}
3259
3260/**
3261 * Comparison operator. This gets called from MachineConfigFile::operator==,
3262 * which in turn gets called from Machine::saveSettings to figure out whether
3263 * machine settings have really changed and thus need to be written out to disk.
3264 */
3265bool BandwidthGroup::operator==(const BandwidthGroup &i) const
3266{
3267 return (this == &i)
3268 || ( strName == i.strName
3269 && cMaxBytesPerSec == i.cMaxBytesPerSec
3270 && enmType == i.enmType);
3271}
3272
3273/**
3274 * IOSettings constructor.
3275 */
3276IOSettings::IOSettings() :
3277 fIOCacheEnabled(true),
3278 ulIOCacheSize(5)
3279{
3280}
3281
3282/**
3283 * Check if all IO Cache settings have default values.
3284 */
3285bool IOSettings::areIOCacheDefaultSettings() const
3286{
3287 return fIOCacheEnabled
3288 && ulIOCacheSize == 5;
3289}
3290
3291/**
3292 * Check if all settings have default values.
3293 */
3294bool IOSettings::areDefaultSettings() const
3295{
3296 return areIOCacheDefaultSettings()
3297 && llBandwidthGroups.size() == 0;
3298}
3299
3300/**
3301 * Comparison operator. This gets called from MachineConfigFile::operator==,
3302 * which in turn gets called from Machine::saveSettings to figure out whether
3303 * machine settings have really changed and thus need to be written out to disk.
3304 */
3305bool IOSettings::operator==(const IOSettings &i) const
3306{
3307 return (this == &i)
3308 || ( fIOCacheEnabled == i.fIOCacheEnabled
3309 && ulIOCacheSize == i.ulIOCacheSize
3310 && llBandwidthGroups == i.llBandwidthGroups);
3311}
3312
3313/**
3314 * Constructor. Needs to set sane defaults which stand the test of time.
3315 */
3316HostPCIDeviceAttachment::HostPCIDeviceAttachment() :
3317 uHostAddress(0),
3318 uGuestAddress(0)
3319{
3320}
3321
3322/**
3323 * Comparison operator. This gets called from MachineConfigFile::operator==,
3324 * which in turn gets called from Machine::saveSettings to figure out whether
3325 * machine settings have really changed and thus need to be written out to disk.
3326 */
3327bool HostPCIDeviceAttachment::operator==(const HostPCIDeviceAttachment &a) const
3328{
3329 return (this == &a)
3330 || ( uHostAddress == a.uHostAddress
3331 && uGuestAddress == a.uGuestAddress
3332 && strDeviceName == a.strDeviceName);
3333}
3334
3335
3336/**
3337 * Constructor. Needs to set sane defaults which stand the test of time.
3338 */
3339Hardware::Hardware() :
3340 strVersion("1"),
3341 fHardwareVirt(true),
3342 fNestedPaging(true),
3343 fVPID(true),
3344 fUnrestrictedExecution(true),
3345 fHardwareVirtForce(false),
3346 fUseNativeApi(false),
3347 fTripleFaultReset(false),
3348 fPAE(false),
3349 fAPIC(true),
3350 fX2APIC(false),
3351 fIBPBOnVMExit(false),
3352 fIBPBOnVMEntry(false),
3353 fSpecCtrl(false),
3354 fSpecCtrlByHost(false),
3355 fL1DFlushOnSched(true),
3356 fL1DFlushOnVMEntry(false),
3357 fMDSClearOnSched(true),
3358 fMDSClearOnVMEntry(false),
3359 fNestedHWVirt(false),
3360 fVirtVmsaveVmload(true),
3361 enmLongMode(HC_ARCH_BITS == 64 ? Hardware::LongMode_Enabled : Hardware::LongMode_Disabled),
3362 cCPUs(1),
3363 fCpuHotPlug(false),
3364 fHPETEnabled(false),
3365 ulCpuExecutionCap(100),
3366 uCpuIdPortabilityLevel(0),
3367 strCpuProfile("host"),
3368 ulMemorySizeMB((uint32_t)-1),
3369 firmwareType(FirmwareType_BIOS),
3370 pointingHIDType(PointingHIDType_PS2Mouse),
3371 keyboardHIDType(KeyboardHIDType_PS2Keyboard),
3372 chipsetType(ChipsetType_PIIX3),
3373 iommuType(IommuType_None),
3374 paravirtProvider(ParavirtProvider_Legacy), // default for old VMs, for new ones it's ParavirtProvider_Default
3375 strParavirtDebug(""),
3376 fEmulatedUSBCardReader(false),
3377 clipboardMode(ClipboardMode_Disabled),
3378 fClipboardFileTransfersEnabled(false),
3379 dndMode(DnDMode_Disabled),
3380 ulMemoryBalloonSize(0),
3381 fPageFusionEnabled(false)
3382{
3383 mapBootOrder[0] = DeviceType_Floppy;
3384 mapBootOrder[1] = DeviceType_DVD;
3385 mapBootOrder[2] = DeviceType_HardDisk;
3386
3387 /* The default value for PAE depends on the host:
3388 * - 64 bits host -> always true
3389 * - 32 bits host -> true for Windows & Darwin (masked off if the host cpu doesn't support it anyway)
3390 */
3391#if HC_ARCH_BITS == 64 || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
3392 fPAE = true;
3393#endif
3394
3395 /* The default value of large page supports depends on the host:
3396 * - 64 bits host -> true, unless it's Linux (pending further prediction work due to excessively expensive large page allocations)
3397 * - 32 bits host -> false
3398 */
3399#if HC_ARCH_BITS == 64 && !defined(RT_OS_LINUX)
3400 fLargePages = true;
3401#else
3402 /* Not supported on 32 bits hosts. */
3403 fLargePages = false;
3404#endif
3405}
3406
3407/**
3408 * Check if all Paravirt settings have default values.
3409 */
3410bool Hardware::areParavirtDefaultSettings(SettingsVersion_T sv) const
3411{
3412 // 5.0 didn't save the paravirt settings if it is ParavirtProvider_Legacy,
3413 // so this default must be kept. Later versions don't save the setting if
3414 // it's at the default value.
3415 return ( (sv >= SettingsVersion_v1_16 && paravirtProvider == ParavirtProvider_Default)
3416 || (sv < SettingsVersion_v1_16 && paravirtProvider == ParavirtProvider_Legacy))
3417 && strParavirtDebug.isEmpty();
3418}
3419
3420/**
3421 * Check if all Boot Order settings have default values.
3422 */
3423bool Hardware::areBootOrderDefaultSettings() const
3424{
3425 BootOrderMap::const_iterator it0 = mapBootOrder.find(0);
3426 BootOrderMap::const_iterator it1 = mapBootOrder.find(1);
3427 BootOrderMap::const_iterator it2 = mapBootOrder.find(2);
3428 BootOrderMap::const_iterator it3 = mapBootOrder.find(3);
3429 return ( mapBootOrder.size() == 3
3430 || ( mapBootOrder.size() == 4
3431 && (it3 != mapBootOrder.end() && it3->second == DeviceType_Null)))
3432 && (it0 != mapBootOrder.end() && it0->second == DeviceType_Floppy)
3433 && (it1 != mapBootOrder.end() && it1->second == DeviceType_DVD)
3434 && (it2 != mapBootOrder.end() && it2->second == DeviceType_HardDisk);
3435}
3436
3437/**
3438 * Check if all Network Adapter settings have default values.
3439 */
3440bool Hardware::areAllNetworkAdaptersDefaultSettings(SettingsVersion_T sv) const
3441{
3442 for (NetworkAdaptersList::const_iterator it = llNetworkAdapters.begin();
3443 it != llNetworkAdapters.end();
3444 ++it)
3445 {
3446 if (!it->areDefaultSettings(sv))
3447 return false;
3448 }
3449 return true;
3450}
3451
3452/**
3453 * Comparison operator. This gets called from MachineConfigFile::operator==,
3454 * which in turn gets called from Machine::saveSettings to figure out whether
3455 * machine settings have really changed and thus need to be written out to disk.
3456 */
3457bool Hardware::operator==(const Hardware& h) const
3458{
3459 return (this == &h)
3460 || ( strVersion == h.strVersion
3461 && uuid == h.uuid
3462 && fHardwareVirt == h.fHardwareVirt
3463 && fNestedPaging == h.fNestedPaging
3464 && fLargePages == h.fLargePages
3465 && fVPID == h.fVPID
3466 && fUnrestrictedExecution == h.fUnrestrictedExecution
3467 && fHardwareVirtForce == h.fHardwareVirtForce
3468 && fUseNativeApi == h.fUseNativeApi
3469 && fPAE == h.fPAE
3470 && enmLongMode == h.enmLongMode
3471 && fTripleFaultReset == h.fTripleFaultReset
3472 && fAPIC == h.fAPIC
3473 && fX2APIC == h.fX2APIC
3474 && fIBPBOnVMExit == h.fIBPBOnVMExit
3475 && fIBPBOnVMEntry == h.fIBPBOnVMEntry
3476 && fSpecCtrl == h.fSpecCtrl
3477 && fSpecCtrlByHost == h.fSpecCtrlByHost
3478 && fL1DFlushOnSched == h.fL1DFlushOnSched
3479 && fL1DFlushOnVMEntry == h.fL1DFlushOnVMEntry
3480 && fMDSClearOnSched == h.fMDSClearOnSched
3481 && fMDSClearOnVMEntry == h.fMDSClearOnVMEntry
3482 && fNestedHWVirt == h.fNestedHWVirt
3483 && fVirtVmsaveVmload == h.fVirtVmsaveVmload
3484 && cCPUs == h.cCPUs
3485 && fCpuHotPlug == h.fCpuHotPlug
3486 && ulCpuExecutionCap == h.ulCpuExecutionCap
3487 && uCpuIdPortabilityLevel == h.uCpuIdPortabilityLevel
3488 && strCpuProfile == h.strCpuProfile
3489 && fHPETEnabled == h.fHPETEnabled
3490 && llCpus == h.llCpus
3491 && llCpuIdLeafs == h.llCpuIdLeafs
3492 && ulMemorySizeMB == h.ulMemorySizeMB
3493 && mapBootOrder == h.mapBootOrder
3494 && firmwareType == h.firmwareType
3495 && pointingHIDType == h.pointingHIDType
3496 && keyboardHIDType == h.keyboardHIDType
3497 && chipsetType == h.chipsetType
3498 && iommuType == h.iommuType
3499 && paravirtProvider == h.paravirtProvider
3500 && strParavirtDebug == h.strParavirtDebug
3501 && fEmulatedUSBCardReader == h.fEmulatedUSBCardReader
3502 && vrdeSettings == h.vrdeSettings
3503 && biosSettings == h.biosSettings
3504 && graphicsAdapter == h.graphicsAdapter
3505 && usbSettings == h.usbSettings
3506 && llNetworkAdapters == h.llNetworkAdapters
3507 && llSerialPorts == h.llSerialPorts
3508 && llParallelPorts == h.llParallelPorts
3509 && audioAdapter == h.audioAdapter
3510 && storage == h.storage
3511 && llSharedFolders == h.llSharedFolders
3512 && clipboardMode == h.clipboardMode
3513 && fClipboardFileTransfersEnabled == h.fClipboardFileTransfersEnabled
3514 && dndMode == h.dndMode
3515 && ulMemoryBalloonSize == h.ulMemoryBalloonSize
3516 && fPageFusionEnabled == h.fPageFusionEnabled
3517 && llGuestProperties == h.llGuestProperties
3518 && ioSettings == h.ioSettings
3519 && pciAttachments == h.pciAttachments
3520 && strDefaultFrontend == h.strDefaultFrontend);
3521}
3522
3523/**
3524 * Constructor. Needs to set sane defaults which stand the test of time.
3525 */
3526AttachedDevice::AttachedDevice() :
3527 deviceType(DeviceType_Null),
3528 fPassThrough(false),
3529 fTempEject(false),
3530 fNonRotational(false),
3531 fDiscard(false),
3532 fHotPluggable(false),
3533 lPort(0),
3534 lDevice(0)
3535{
3536}
3537
3538/**
3539 * Comparison operator. This gets called from MachineConfigFile::operator==,
3540 * which in turn gets called from Machine::saveSettings to figure out whether
3541 * machine settings have really changed and thus need to be written out to disk.
3542 */
3543bool AttachedDevice::operator==(const AttachedDevice &a) const
3544{
3545 return (this == &a)
3546 || ( deviceType == a.deviceType
3547 && fPassThrough == a.fPassThrough
3548 && fTempEject == a.fTempEject
3549 && fNonRotational == a.fNonRotational
3550 && fDiscard == a.fDiscard
3551 && fHotPluggable == a.fHotPluggable
3552 && lPort == a.lPort
3553 && lDevice == a.lDevice
3554 && uuid == a.uuid
3555 && strHostDriveSrc == a.strHostDriveSrc
3556 && strBwGroup == a.strBwGroup);
3557}
3558
3559/**
3560 * Constructor. Needs to set sane defaults which stand the test of time.
3561 */
3562StorageController::StorageController() :
3563 storageBus(StorageBus_IDE),
3564 controllerType(StorageControllerType_PIIX3),
3565 ulPortCount(2),
3566 ulInstance(0),
3567 fUseHostIOCache(true),
3568 fBootable(true)
3569{
3570}
3571
3572/**
3573 * Comparison operator. This gets called from MachineConfigFile::operator==,
3574 * which in turn gets called from Machine::saveSettings to figure out whether
3575 * machine settings have really changed and thus need to be written out to disk.
3576 */
3577bool StorageController::operator==(const StorageController &s) const
3578{
3579 return (this == &s)
3580 || ( strName == s.strName
3581 && storageBus == s.storageBus
3582 && controllerType == s.controllerType
3583 && ulPortCount == s.ulPortCount
3584 && ulInstance == s.ulInstance
3585 && fUseHostIOCache == s.fUseHostIOCache
3586 && llAttachedDevices == s.llAttachedDevices);
3587}
3588
3589/**
3590 * Comparison operator. This gets called from MachineConfigFile::operator==,
3591 * which in turn gets called from Machine::saveSettings to figure out whether
3592 * machine settings have really changed and thus need to be written out to disk.
3593 */
3594bool Storage::operator==(const Storage &s) const
3595{
3596 return (this == &s)
3597 || (llStorageControllers == s.llStorageControllers); // deep compare
3598}
3599
3600/**
3601 * Constructor. Needs to set sane defaults which stand the test of time.
3602 */
3603Debugging::Debugging() :
3604 fTracingEnabled(false),
3605 fAllowTracingToAccessVM(false),
3606 strTracingConfig()
3607{
3608}
3609
3610/**
3611 * Check if all settings have default values.
3612 */
3613bool Debugging::areDefaultSettings() const
3614{
3615 return !fTracingEnabled
3616 && !fAllowTracingToAccessVM
3617 && strTracingConfig.isEmpty();
3618}
3619
3620/**
3621 * Comparison operator. This gets called from MachineConfigFile::operator==,
3622 * which in turn gets called from Machine::saveSettings to figure out whether
3623 * machine settings have really changed and thus need to be written out to disk.
3624 */
3625bool Debugging::operator==(const Debugging &d) const
3626{
3627 return (this == &d)
3628 || ( fTracingEnabled == d.fTracingEnabled
3629 && fAllowTracingToAccessVM == d.fAllowTracingToAccessVM
3630 && strTracingConfig == d.strTracingConfig);
3631}
3632
3633/**
3634 * Constructor. Needs to set sane defaults which stand the test of time.
3635 */
3636Autostart::Autostart() :
3637 fAutostartEnabled(false),
3638 uAutostartDelay(0),
3639 enmAutostopType(AutostopType_Disabled)
3640{
3641}
3642
3643/**
3644 * Check if all settings have default values.
3645 */
3646bool Autostart::areDefaultSettings() const
3647{
3648 return !fAutostartEnabled
3649 && !uAutostartDelay
3650 && enmAutostopType == AutostopType_Disabled;
3651}
3652
3653/**
3654 * Comparison operator. This gets called from MachineConfigFile::operator==,
3655 * which in turn gets called from Machine::saveSettings to figure out whether
3656 * machine settings have really changed and thus need to be written out to disk.
3657 */
3658bool Autostart::operator==(const Autostart &a) const
3659{
3660 return (this == &a)
3661 || ( fAutostartEnabled == a.fAutostartEnabled
3662 && uAutostartDelay == a.uAutostartDelay
3663 && enmAutostopType == a.enmAutostopType);
3664}
3665
3666/**
3667 * Constructor. Needs to set sane defaults which stand the test of time.
3668 */
3669Snapshot::Snapshot()
3670{
3671 RTTimeSpecSetNano(&timestamp, 0);
3672}
3673
3674/**
3675 * Comparison operator. This gets called from MachineConfigFile::operator==,
3676 * which in turn gets called from Machine::saveSettings to figure out whether
3677 * machine settings have really changed and thus need to be written out to disk.
3678 */
3679bool Snapshot::operator==(const Snapshot &s) const
3680{
3681 return (this == &s)
3682 || ( uuid == s.uuid
3683 && strName == s.strName
3684 && strDescription == s.strDescription
3685 && RTTimeSpecIsEqual(&timestamp, &s.timestamp)
3686 && strStateFile == s.strStateFile
3687 && hardware == s.hardware // deep compare
3688 && llChildSnapshots == s.llChildSnapshots // deep compare
3689 && debugging == s.debugging
3690 && autostart == s.autostart);
3691}
3692
3693const struct Snapshot settings::Snapshot::Empty; /* default ctor is OK */
3694
3695/**
3696 * Constructor. Needs to set sane defaults which stand the test of time.
3697 */
3698MachineUserData::MachineUserData() :
3699 fDirectoryIncludesUUID(false),
3700 fNameSync(true),
3701 fTeleporterEnabled(false),
3702 uTeleporterPort(0),
3703 fRTCUseUTC(false),
3704 enmVMPriority(VMProcPriority_Default)
3705{
3706 llGroups.push_back("/");
3707}
3708
3709/**
3710 * Comparison operator. This gets called from MachineConfigFile::operator==,
3711 * which in turn gets called from Machine::saveSettings to figure out whether
3712 * machine settings have really changed and thus need to be written out to disk.
3713 */
3714bool MachineUserData::operator==(const MachineUserData &c) const
3715{
3716 return (this == &c)
3717 || ( strName == c.strName
3718 && fDirectoryIncludesUUID == c.fDirectoryIncludesUUID
3719 && fNameSync == c.fNameSync
3720 && strDescription == c.strDescription
3721 && llGroups == c.llGroups
3722 && strOsType == c.strOsType
3723 && strSnapshotFolder == c.strSnapshotFolder
3724 && fTeleporterEnabled == c.fTeleporterEnabled
3725 && uTeleporterPort == c.uTeleporterPort
3726 && strTeleporterAddress == c.strTeleporterAddress
3727 && strTeleporterPassword == c.strTeleporterPassword
3728 && fRTCUseUTC == c.fRTCUseUTC
3729 && ovIcon == c.ovIcon
3730 && enmVMPriority == c.enmVMPriority);
3731}
3732
3733
3734////////////////////////////////////////////////////////////////////////////////
3735//
3736// MachineConfigFile
3737//
3738////////////////////////////////////////////////////////////////////////////////
3739
3740/**
3741 * Constructor.
3742 *
3743 * If pstrFilename is != NULL, this reads the given settings file into the member
3744 * variables and various substructures and lists. Otherwise, the member variables
3745 * are initialized with default values.
3746 *
3747 * Throws variants of xml::Error for I/O, XML and logical content errors, which
3748 * the caller should catch; if this constructor does not throw, then the member
3749 * variables contain meaningful values (either from the file or defaults).
3750 *
3751 * @param pstrFilename
3752 */
3753MachineConfigFile::MachineConfigFile(const Utf8Str *pstrFilename)
3754 : ConfigFileBase(pstrFilename),
3755 fCurrentStateModified(true),
3756 fAborted(false)
3757{
3758 RTTimeNow(&timeLastStateChange);
3759
3760 if (pstrFilename)
3761 {
3762 // the ConfigFileBase constructor has loaded the XML file, so now
3763 // we need only analyze what is in there
3764
3765 xml::NodesLoop nlRootChildren(*m->pelmRoot);
3766 const xml::ElementNode *pelmRootChild;
3767 while ((pelmRootChild = nlRootChildren.forAllNodes()))
3768 {
3769 if (pelmRootChild->nameEquals("Machine"))
3770 readMachine(*pelmRootChild);
3771 }
3772
3773 // clean up memory allocated by XML engine
3774 clearDocument();
3775 }
3776}
3777
3778/**
3779 * Public routine which returns true if this machine config file can have its
3780 * own media registry (which is true for settings version v1.11 and higher,
3781 * i.e. files created by VirtualBox 4.0 and higher).
3782 * @return
3783 */
3784bool MachineConfigFile::canHaveOwnMediaRegistry() const
3785{
3786 return (m->sv >= SettingsVersion_v1_11);
3787}
3788
3789/**
3790 * Public routine which allows for importing machine XML from an external DOM tree.
3791 * Use this after having called the constructor with a NULL argument.
3792 *
3793 * This is used by the OVF code if a <vbox:Machine> element has been encountered
3794 * in an OVF VirtualSystem element.
3795 *
3796 * @param elmMachine
3797 */
3798void MachineConfigFile::importMachineXML(const xml::ElementNode &elmMachine)
3799{
3800 // Ideally the version should be mandatory, but since VirtualBox didn't
3801 // care about it until 5.1 came with different defaults, there are OVF
3802 // files created by magicians (not using VirtualBox, which always wrote it)
3803 // which lack this information. Let's hope that they learn to add the
3804 // version when they switch to the newer settings style/defaults of 5.1.
3805 if (!(elmMachine.getAttributeValue("version", m->strSettingsVersionFull)))
3806 m->strSettingsVersionFull = VBOX_XML_IMPORT_VERSION_FULL;
3807
3808 LogRel(("Import settings with version \"%s\"\n", m->strSettingsVersionFull.c_str()));
3809
3810 m->sv = parseVersion(m->strSettingsVersionFull, &elmMachine);
3811
3812 // remember the settings version we read in case it gets upgraded later,
3813 // so we know when to make backups
3814 m->svRead = m->sv;
3815
3816 readMachine(elmMachine);
3817}
3818
3819/**
3820 * Comparison operator. This gets called from Machine::saveSettings to figure out
3821 * whether machine settings have really changed and thus need to be written out to disk.
3822 *
3823 * Even though this is called operator==, this does NOT compare all fields; the "equals"
3824 * should be understood as "has the same machine config as". The following fields are
3825 * NOT compared:
3826 * -- settings versions and file names inherited from ConfigFileBase;
3827 * -- fCurrentStateModified because that is considered separately in Machine::saveSettings!!
3828 *
3829 * The "deep" comparisons marked below will invoke the operator== functions of the
3830 * structs defined in this file, which may in turn go into comparing lists of
3831 * other structures. As a result, invoking this can be expensive, but it's
3832 * less expensive than writing out XML to disk.
3833 */
3834bool MachineConfigFile::operator==(const MachineConfigFile &c) const
3835{
3836 return (this == &c)
3837 || ( uuid == c.uuid
3838 && machineUserData == c.machineUserData
3839 && strStateFile == c.strStateFile
3840 && uuidCurrentSnapshot == c.uuidCurrentSnapshot
3841 // skip fCurrentStateModified!
3842 && RTTimeSpecIsEqual(&timeLastStateChange, &c.timeLastStateChange)
3843 && fAborted == c.fAborted
3844 && hardwareMachine == c.hardwareMachine // this one's deep
3845 && mediaRegistry == c.mediaRegistry // this one's deep
3846 // skip mapExtraDataItems! there is no old state available as it's always forced
3847 && llFirstSnapshot == c.llFirstSnapshot); // this one's deep
3848}
3849
3850/**
3851 * Called from MachineConfigFile::readHardware() to read cpu information.
3852 * @param elmCpu
3853 * @param ll
3854 */
3855void MachineConfigFile::readCpuTree(const xml::ElementNode &elmCpu,
3856 CpuList &ll)
3857{
3858 xml::NodesLoop nl1(elmCpu, "Cpu");
3859 const xml::ElementNode *pelmCpu;
3860 while ((pelmCpu = nl1.forAllNodes()))
3861 {
3862 Cpu cpu;
3863
3864 if (!pelmCpu->getAttributeValue("id", cpu.ulId))
3865 throw ConfigFileError(this, pelmCpu, N_("Required Cpu/@id attribute is missing"));
3866
3867 ll.push_back(cpu);
3868 }
3869}
3870
3871/**
3872 * Called from MachineConfigFile::readHardware() to cpuid information.
3873 * @param elmCpuid
3874 * @param ll
3875 */
3876void MachineConfigFile::readCpuIdTree(const xml::ElementNode &elmCpuid,
3877 CpuIdLeafsList &ll)
3878{
3879 xml::NodesLoop nl1(elmCpuid, "CpuIdLeaf");
3880 const xml::ElementNode *pelmCpuIdLeaf;
3881 while ((pelmCpuIdLeaf = nl1.forAllNodes()))
3882 {
3883 CpuIdLeaf leaf;
3884
3885 if (!pelmCpuIdLeaf->getAttributeValue("id", leaf.idx))
3886 throw ConfigFileError(this, pelmCpuIdLeaf, N_("Required CpuId/@id attribute is missing"));
3887
3888 if (!pelmCpuIdLeaf->getAttributeValue("subleaf", leaf.idxSub))
3889 leaf.idxSub = 0;
3890 pelmCpuIdLeaf->getAttributeValue("eax", leaf.uEax);
3891 pelmCpuIdLeaf->getAttributeValue("ebx", leaf.uEbx);
3892 pelmCpuIdLeaf->getAttributeValue("ecx", leaf.uEcx);
3893 pelmCpuIdLeaf->getAttributeValue("edx", leaf.uEdx);
3894
3895 ll.push_back(leaf);
3896 }
3897}
3898
3899/**
3900 * Called from MachineConfigFile::readHardware() to network information.
3901 * @param elmNetwork
3902 * @param ll
3903 */
3904void MachineConfigFile::readNetworkAdapters(const xml::ElementNode &elmNetwork,
3905 NetworkAdaptersList &ll)
3906{
3907 xml::NodesLoop nl1(elmNetwork, "Adapter");
3908 const xml::ElementNode *pelmAdapter;
3909 while ((pelmAdapter = nl1.forAllNodes()))
3910 {
3911 NetworkAdapter nic;
3912
3913 if (m->sv >= SettingsVersion_v1_16)
3914 {
3915 /* Starting with VirtualBox 5.1 the default is cable connected and
3916 * PCnet-FAST III. Needs to match NetworkAdapter.areDefaultSettings(). */
3917 nic.fCableConnected = true;
3918 nic.type = NetworkAdapterType_Am79C973;
3919 }
3920
3921 if (!pelmAdapter->getAttributeValue("slot", nic.ulSlot))
3922 throw ConfigFileError(this, pelmAdapter, N_("Required Adapter/@slot attribute is missing"));
3923
3924 Utf8Str strTemp;
3925 if (pelmAdapter->getAttributeValue("type", strTemp))
3926 {
3927 if (strTemp == "Am79C970A")
3928 nic.type = NetworkAdapterType_Am79C970A;
3929 else if (strTemp == "Am79C973")
3930 nic.type = NetworkAdapterType_Am79C973;
3931 else if (strTemp == "Am79C960")
3932 nic.type = NetworkAdapterType_Am79C960;
3933 else if (strTemp == "82540EM")
3934 nic.type = NetworkAdapterType_I82540EM;
3935 else if (strTemp == "82543GC")
3936 nic.type = NetworkAdapterType_I82543GC;
3937 else if (strTemp == "82545EM")
3938 nic.type = NetworkAdapterType_I82545EM;
3939 else if (strTemp == "virtio")
3940 nic.type = NetworkAdapterType_Virtio;
3941 else if (strTemp == "virtio_1.0")
3942 nic.type = NetworkAdapterType_Virtio_1_0;
3943 else
3944 throw ConfigFileError(this, pelmAdapter, N_("Invalid value '%s' in Adapter/@type attribute"), strTemp.c_str());
3945 }
3946
3947 pelmAdapter->getAttributeValue("enabled", nic.fEnabled);
3948 pelmAdapter->getAttributeValue("MACAddress", nic.strMACAddress);
3949 pelmAdapter->getAttributeValue("cable", nic.fCableConnected);
3950 pelmAdapter->getAttributeValue("speed", nic.ulLineSpeed);
3951
3952 if (pelmAdapter->getAttributeValue("promiscuousModePolicy", strTemp))
3953 {
3954 if (strTemp == "Deny")
3955 nic.enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
3956 else if (strTemp == "AllowNetwork")
3957 nic.enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
3958 else if (strTemp == "AllowAll")
3959 nic.enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
3960 else
3961 throw ConfigFileError(this, pelmAdapter,
3962 N_("Invalid value '%s' in Adapter/@promiscuousModePolicy attribute"), strTemp.c_str());
3963 }
3964
3965 pelmAdapter->getAttributeValue("trace", nic.fTraceEnabled);
3966 pelmAdapter->getAttributeValue("tracefile", nic.strTraceFile);
3967 pelmAdapter->getAttributeValue("bootPriority", nic.ulBootPriority);
3968 pelmAdapter->getAttributeValue("bandwidthGroup", nic.strBandwidthGroup);
3969
3970 xml::ElementNodesList llNetworkModes;
3971 pelmAdapter->getChildElements(llNetworkModes);
3972 xml::ElementNodesList::iterator it;
3973 /* We should have only active mode descriptor and disabled modes set */
3974 if (llNetworkModes.size() > 2)
3975 {
3976 throw ConfigFileError(this, pelmAdapter, N_("Invalid number of modes ('%d') attached to Adapter attribute"), llNetworkModes.size());
3977 }
3978 for (it = llNetworkModes.begin(); it != llNetworkModes.end(); ++it)
3979 {
3980 const xml::ElementNode *pelmNode = *it;
3981 if (pelmNode->nameEquals("DisabledModes"))
3982 {
3983 xml::ElementNodesList llDisabledNetworkModes;
3984 xml::ElementNodesList::iterator itDisabled;
3985 pelmNode->getChildElements(llDisabledNetworkModes);
3986 /* run over disabled list and load settings */
3987 for (itDisabled = llDisabledNetworkModes.begin();
3988 itDisabled != llDisabledNetworkModes.end(); ++itDisabled)
3989 {
3990 const xml::ElementNode *pelmDisabledNode = *itDisabled;
3991 readAttachedNetworkMode(*pelmDisabledNode, false, nic);
3992 }
3993 }
3994 else
3995 readAttachedNetworkMode(*pelmNode, true, nic);
3996 }
3997 // else: default is NetworkAttachmentType_Null
3998
3999 ll.push_back(nic);
4000 }
4001}
4002
4003void MachineConfigFile::readAttachedNetworkMode(const xml::ElementNode &elmMode, bool fEnabled, NetworkAdapter &nic)
4004{
4005 NetworkAttachmentType_T enmAttachmentType = NetworkAttachmentType_Null;
4006
4007 if (elmMode.nameEquals("NAT"))
4008 {
4009 enmAttachmentType = NetworkAttachmentType_NAT;
4010
4011 elmMode.getAttributeValue("network", nic.nat.strNetwork);
4012 elmMode.getAttributeValue("hostip", nic.nat.strBindIP);
4013 elmMode.getAttributeValue("mtu", nic.nat.u32Mtu);
4014 elmMode.getAttributeValue("sockrcv", nic.nat.u32SockRcv);
4015 elmMode.getAttributeValue("socksnd", nic.nat.u32SockSnd);
4016 elmMode.getAttributeValue("tcprcv", nic.nat.u32TcpRcv);
4017 elmMode.getAttributeValue("tcpsnd", nic.nat.u32TcpSnd);
4018 const xml::ElementNode *pelmDNS;
4019 if ((pelmDNS = elmMode.findChildElement("DNS")))
4020 {
4021 pelmDNS->getAttributeValue("pass-domain", nic.nat.fDNSPassDomain);
4022 pelmDNS->getAttributeValue("use-proxy", nic.nat.fDNSProxy);
4023 pelmDNS->getAttributeValue("use-host-resolver", nic.nat.fDNSUseHostResolver);
4024 }
4025 const xml::ElementNode *pelmAlias;
4026 if ((pelmAlias = elmMode.findChildElement("Alias")))
4027 {
4028 pelmAlias->getAttributeValue("logging", nic.nat.fAliasLog);
4029 pelmAlias->getAttributeValue("proxy-only", nic.nat.fAliasProxyOnly);
4030 pelmAlias->getAttributeValue("use-same-ports", nic.nat.fAliasUseSamePorts);
4031 }
4032 const xml::ElementNode *pelmTFTP;
4033 if ((pelmTFTP = elmMode.findChildElement("TFTP")))
4034 {
4035 pelmTFTP->getAttributeValue("prefix", nic.nat.strTFTPPrefix);
4036 pelmTFTP->getAttributeValue("boot-file", nic.nat.strTFTPBootFile);
4037 pelmTFTP->getAttributeValue("next-server", nic.nat.strTFTPNextServer);
4038 }
4039
4040 readNATForwardRulesMap(elmMode, nic.nat.mapRules);
4041 }
4042 else if ( elmMode.nameEquals("HostInterface")
4043 || elmMode.nameEquals("BridgedInterface"))
4044 {
4045 enmAttachmentType = NetworkAttachmentType_Bridged;
4046
4047 // optional network name, cannot be required or we have trouble with
4048 // settings which are saved before configuring the network name
4049 elmMode.getAttributeValue("name", nic.strBridgedName);
4050 }
4051 else if (elmMode.nameEquals("InternalNetwork"))
4052 {
4053 enmAttachmentType = NetworkAttachmentType_Internal;
4054
4055 // optional network name, cannot be required or we have trouble with
4056 // settings which are saved before configuring the network name
4057 elmMode.getAttributeValue("name", nic.strInternalNetworkName);
4058 }
4059 else if (elmMode.nameEquals("HostOnlyInterface"))
4060 {
4061 enmAttachmentType = NetworkAttachmentType_HostOnly;
4062
4063 // optional network name, cannot be required or we have trouble with
4064 // settings which are saved before configuring the network name
4065 elmMode.getAttributeValue("name", nic.strHostOnlyName);
4066 }
4067 else if (elmMode.nameEquals("GenericInterface"))
4068 {
4069 enmAttachmentType = NetworkAttachmentType_Generic;
4070
4071 elmMode.getAttributeValue("driver", nic.strGenericDriver); // optional network attachment driver
4072
4073 // get all properties
4074 xml::NodesLoop nl(elmMode);
4075 const xml::ElementNode *pelmModeChild;
4076 while ((pelmModeChild = nl.forAllNodes()))
4077 {
4078 if (pelmModeChild->nameEquals("Property"))
4079 {
4080 Utf8Str strPropName, strPropValue;
4081 if ( pelmModeChild->getAttributeValue("name", strPropName)
4082 && pelmModeChild->getAttributeValue("value", strPropValue) )
4083 nic.genericProperties[strPropName] = strPropValue;
4084 else
4085 throw ConfigFileError(this, pelmModeChild, N_("Required GenericInterface/Property/@name or @value attribute is missing"));
4086 }
4087 }
4088 }
4089 else if (elmMode.nameEquals("NATNetwork"))
4090 {
4091 enmAttachmentType = NetworkAttachmentType_NATNetwork;
4092
4093 // optional network name, cannot be required or we have trouble with
4094 // settings which are saved before configuring the network name
4095 elmMode.getAttributeValue("name", nic.strNATNetworkName);
4096 }
4097 else if (elmMode.nameEquals("VDE"))
4098 {
4099 // inofficial hack (VDE networking was never part of the official
4100 // settings, so it's not mentioned in VirtualBox-settings.xsd)
4101 enmAttachmentType = NetworkAttachmentType_Generic;
4102
4103 com::Utf8Str strVDEName;
4104 elmMode.getAttributeValue("network", strVDEName); // optional network name
4105 nic.strGenericDriver = "VDE";
4106 nic.genericProperties["network"] = strVDEName;
4107 }
4108#ifdef VBOX_WITH_CLOUD_NET
4109 else if (elmMode.nameEquals("CloudNetwork"))
4110 {
4111 enmAttachmentType = NetworkAttachmentType_Cloud;
4112
4113 // optional network name, cannot be required or we have trouble with
4114 // settings which are saved before configuring the network name
4115 elmMode.getAttributeValue("name", nic.strCloudNetworkName);
4116 }
4117#endif /* VBOX_WITH_CLOUD_NET */
4118
4119 if (fEnabled && enmAttachmentType != NetworkAttachmentType_Null)
4120 nic.mode = enmAttachmentType;
4121}
4122
4123/**
4124 * Called from MachineConfigFile::readHardware() to read serial port information.
4125 * @param elmUART
4126 * @param ll
4127 */
4128void MachineConfigFile::readSerialPorts(const xml::ElementNode &elmUART,
4129 SerialPortsList &ll)
4130{
4131 xml::NodesLoop nl1(elmUART, "Port");
4132 const xml::ElementNode *pelmPort;
4133 while ((pelmPort = nl1.forAllNodes()))
4134 {
4135 SerialPort port;
4136 if (!pelmPort->getAttributeValue("slot", port.ulSlot))
4137 throw ConfigFileError(this, pelmPort, N_("Required UART/Port/@slot attribute is missing"));
4138
4139 // slot must be unique
4140 for (SerialPortsList::const_iterator it = ll.begin();
4141 it != ll.end();
4142 ++it)
4143 if ((*it).ulSlot == port.ulSlot)
4144 throw ConfigFileError(this, pelmPort, N_("Invalid value %RU32 in UART/Port/@slot attribute: value is not unique"), port.ulSlot);
4145
4146 if (!pelmPort->getAttributeValue("enabled", port.fEnabled))
4147 throw ConfigFileError(this, pelmPort, N_("Required UART/Port/@enabled attribute is missing"));
4148 if (!pelmPort->getAttributeValue("IOBase", port.ulIOBase))
4149 throw ConfigFileError(this, pelmPort, N_("Required UART/Port/@IOBase attribute is missing"));
4150 if (!pelmPort->getAttributeValue("IRQ", port.ulIRQ))
4151 throw ConfigFileError(this, pelmPort, N_("Required UART/Port/@IRQ attribute is missing"));
4152
4153 Utf8Str strPortMode;
4154 if (!pelmPort->getAttributeValue("hostMode", strPortMode))
4155 throw ConfigFileError(this, pelmPort, N_("Required UART/Port/@hostMode attribute is missing"));
4156 if (strPortMode == "RawFile")
4157 port.portMode = PortMode_RawFile;
4158 else if (strPortMode == "HostPipe")
4159 port.portMode = PortMode_HostPipe;
4160 else if (strPortMode == "HostDevice")
4161 port.portMode = PortMode_HostDevice;
4162 else if (strPortMode == "Disconnected")
4163 port.portMode = PortMode_Disconnected;
4164 else if (strPortMode == "TCP")
4165 port.portMode = PortMode_TCP;
4166 else
4167 throw ConfigFileError(this, pelmPort, N_("Invalid value '%s' in UART/Port/@hostMode attribute"), strPortMode.c_str());
4168
4169 pelmPort->getAttributeValue("path", port.strPath);
4170 pelmPort->getAttributeValue("server", port.fServer);
4171
4172 Utf8Str strUartType;
4173 if (pelmPort->getAttributeValue("uartType", strUartType))
4174 {
4175 if (strUartType == "16450")
4176 port.uartType = UartType_U16450;
4177 else if (strUartType == "16550A")
4178 port.uartType = UartType_U16550A;
4179 else if (strUartType == "16750")
4180 port.uartType = UartType_U16750;
4181 else
4182 throw ConfigFileError(this, pelmPort, N_("Invalid value '%s' in UART/Port/@uartType attribute"), strUartType.c_str());
4183 }
4184
4185 ll.push_back(port);
4186 }
4187}
4188
4189/**
4190 * Called from MachineConfigFile::readHardware() to read parallel port information.
4191 * @param elmLPT
4192 * @param ll
4193 */
4194void MachineConfigFile::readParallelPorts(const xml::ElementNode &elmLPT,
4195 ParallelPortsList &ll)
4196{
4197 xml::NodesLoop nl1(elmLPT, "Port");
4198 const xml::ElementNode *pelmPort;
4199 while ((pelmPort = nl1.forAllNodes()))
4200 {
4201 ParallelPort port;
4202 if (!pelmPort->getAttributeValue("slot", port.ulSlot))
4203 throw ConfigFileError(this, pelmPort, N_("Required LPT/Port/@slot attribute is missing"));
4204
4205 // slot must be unique
4206 for (ParallelPortsList::const_iterator it = ll.begin();
4207 it != ll.end();
4208 ++it)
4209 if ((*it).ulSlot == port.ulSlot)
4210 throw ConfigFileError(this, pelmPort, N_("Invalid value %RU32 in LPT/Port/@slot attribute: value is not unique"), port.ulSlot);
4211
4212 if (!pelmPort->getAttributeValue("enabled", port.fEnabled))
4213 throw ConfigFileError(this, pelmPort, N_("Required LPT/Port/@enabled attribute is missing"));
4214 if (!pelmPort->getAttributeValue("IOBase", port.ulIOBase))
4215 throw ConfigFileError(this, pelmPort, N_("Required LPT/Port/@IOBase attribute is missing"));
4216 if (!pelmPort->getAttributeValue("IRQ", port.ulIRQ))
4217 throw ConfigFileError(this, pelmPort, N_("Required LPT/Port/@IRQ attribute is missing"));
4218
4219 pelmPort->getAttributeValue("path", port.strPath);
4220
4221 ll.push_back(port);
4222 }
4223}
4224
4225/**
4226 * Called from MachineConfigFile::readHardware() to read audio adapter information
4227 * and maybe fix driver information depending on the current host hardware.
4228 *
4229 * @param elmAudioAdapter "AudioAdapter" XML element.
4230 * @param aa
4231 */
4232void MachineConfigFile::readAudioAdapter(const xml::ElementNode &elmAudioAdapter,
4233 AudioAdapter &aa)
4234{
4235 if (m->sv >= SettingsVersion_v1_15)
4236 {
4237 // get all properties
4238 xml::NodesLoop nl1(elmAudioAdapter, "Property");
4239 const xml::ElementNode *pelmModeChild;
4240 while ((pelmModeChild = nl1.forAllNodes()))
4241 {
4242 Utf8Str strPropName, strPropValue;
4243 if ( pelmModeChild->getAttributeValue("name", strPropName)
4244 && pelmModeChild->getAttributeValue("value", strPropValue) )
4245 aa.properties[strPropName] = strPropValue;
4246 else
4247 throw ConfigFileError(this, pelmModeChild, N_("Required AudioAdapter/Property/@name or @value attribute "
4248 "is missing"));
4249 }
4250 }
4251
4252 elmAudioAdapter.getAttributeValue("enabled", aa.fEnabled);
4253 elmAudioAdapter.getAttributeValue("enabledIn", aa.fEnabledIn);
4254 elmAudioAdapter.getAttributeValue("enabledOut", aa.fEnabledOut);
4255
4256 Utf8Str strTemp;
4257 if (elmAudioAdapter.getAttributeValue("controller", strTemp))
4258 {
4259 if (strTemp == "SB16")
4260 aa.controllerType = AudioControllerType_SB16;
4261 else if (strTemp == "AC97")
4262 aa.controllerType = AudioControllerType_AC97;
4263 else if (strTemp == "HDA")
4264 aa.controllerType = AudioControllerType_HDA;
4265 else
4266 throw ConfigFileError(this, &elmAudioAdapter, N_("Invalid value '%s' in AudioAdapter/@controller attribute"), strTemp.c_str());
4267 }
4268
4269 if (elmAudioAdapter.getAttributeValue("codec", strTemp))
4270 {
4271 if (strTemp == "SB16")
4272 aa.codecType = AudioCodecType_SB16;
4273 else if (strTemp == "STAC9700")
4274 aa.codecType = AudioCodecType_STAC9700;
4275 else if (strTemp == "AD1980")
4276 aa.codecType = AudioCodecType_AD1980;
4277 else if (strTemp == "STAC9221")
4278 aa.codecType = AudioCodecType_STAC9221;
4279 else
4280 throw ConfigFileError(this, &elmAudioAdapter, N_("Invalid value '%s' in AudioAdapter/@codec attribute"), strTemp.c_str());
4281 }
4282 else
4283 {
4284 /* No codec attribute provided; use defaults. */
4285 switch (aa.controllerType)
4286 {
4287 case AudioControllerType_AC97:
4288 aa.codecType = AudioCodecType_STAC9700;
4289 break;
4290 case AudioControllerType_SB16:
4291 aa.codecType = AudioCodecType_SB16;
4292 break;
4293 case AudioControllerType_HDA:
4294 aa.codecType = AudioCodecType_STAC9221;
4295 break;
4296 default:
4297 Assert(false); /* We just checked the controller type above. */
4298 }
4299 }
4300
4301 if (elmAudioAdapter.getAttributeValue("driver", strTemp))
4302 {
4303 // settings before 1.3 used lower case so make sure this is case-insensitive
4304 strTemp.toUpper();
4305 if (strTemp == "NULL")
4306 aa.driverType = AudioDriverType_Null;
4307 else if (strTemp == "WINMM")
4308 aa.driverType = AudioDriverType_WinMM;
4309 else if ( (strTemp == "DIRECTSOUND") || (strTemp == "DSOUND") )
4310 aa.driverType = AudioDriverType_DirectSound;
4311 else if (strTemp == "SOLAUDIO") /* Deprecated -- Solaris will use OSS by default now. */
4312 aa.driverType = AudioDriverType_SolAudio;
4313 else if (strTemp == "ALSA")
4314 aa.driverType = AudioDriverType_ALSA;
4315 else if (strTemp == "PULSE")
4316 aa.driverType = AudioDriverType_Pulse;
4317 else if (strTemp == "OSS")
4318 aa.driverType = AudioDriverType_OSS;
4319 else if (strTemp == "COREAUDIO")
4320 aa.driverType = AudioDriverType_CoreAudio;
4321 else if (strTemp == "MMPM")
4322 aa.driverType = AudioDriverType_MMPM;
4323 else
4324 throw ConfigFileError(this, &elmAudioAdapter, N_("Invalid value '%s' in AudioAdapter/@driver attribute"), strTemp.c_str());
4325
4326 // now check if this is actually supported on the current host platform;
4327 // people might be opening a file created on a Windows host, and that
4328 // VM should still start on a Linux host
4329 if (!isAudioDriverAllowedOnThisHost(aa.driverType))
4330 aa.driverType = getHostDefaultAudioDriver();
4331 }
4332}
4333
4334/**
4335 * Called from MachineConfigFile::readHardware() to read guest property information.
4336 * @param elmGuestProperties
4337 * @param hw
4338 */
4339void MachineConfigFile::readGuestProperties(const xml::ElementNode &elmGuestProperties,
4340 Hardware &hw)
4341{
4342 xml::NodesLoop nl1(elmGuestProperties, "GuestProperty");
4343 const xml::ElementNode *pelmProp;
4344 while ((pelmProp = nl1.forAllNodes()))
4345 {
4346 GuestProperty prop;
4347 pelmProp->getAttributeValue("name", prop.strName);
4348 pelmProp->getAttributeValue("value", prop.strValue);
4349
4350 pelmProp->getAttributeValue("timestamp", prop.timestamp);
4351 pelmProp->getAttributeValue("flags", prop.strFlags);
4352 hw.llGuestProperties.push_back(prop);
4353 }
4354}
4355
4356/**
4357 * Helper function to read attributes that are common to \<SATAController\> (pre-1.7)
4358 * and \<StorageController\>.
4359 * @param elmStorageController
4360 * @param sctl
4361 */
4362void MachineConfigFile::readStorageControllerAttributes(const xml::ElementNode &elmStorageController,
4363 StorageController &sctl)
4364{
4365 elmStorageController.getAttributeValue("PortCount", sctl.ulPortCount);
4366 elmStorageController.getAttributeValue("useHostIOCache", sctl.fUseHostIOCache);
4367}
4368
4369/**
4370 * Reads in a \<Hardware\> block and stores it in the given structure. Used
4371 * both directly from readMachine and from readSnapshot, since snapshots
4372 * have their own hardware sections.
4373 *
4374 * For legacy pre-1.7 settings we also need a storage structure because
4375 * the IDE and SATA controllers used to be defined under \<Hardware\>.
4376 *
4377 * @param elmHardware
4378 * @param hw
4379 */
4380void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
4381 Hardware &hw)
4382{
4383 if (m->sv >= SettingsVersion_v1_16)
4384 {
4385 /* Starting with VirtualBox 5.1 the default is Default, before it was
4386 * Legacy. This needs to matched by areParavirtDefaultSettings(). */
4387 hw.paravirtProvider = ParavirtProvider_Default;
4388 /* The new default is disabled, before it was enabled by default. */
4389 hw.vrdeSettings.fEnabled = false;
4390 /* The new default is disabled, before it was enabled by default. */
4391 hw.audioAdapter.fEnabled = false;
4392 }
4393
4394 if (m->sv >= SettingsVersion_v1_17)
4395 {
4396 /* Starting with VirtualBox 5.2 the default is disabled, before it was
4397 * enabled. This needs to matched by AudioAdapter::areDefaultSettings(). */
4398 hw.audioAdapter.fEnabledIn = false;
4399 /* The new default is disabled, before it was enabled by default. */
4400 hw.audioAdapter.fEnabledOut = false;
4401 }
4402
4403 if (!elmHardware.getAttributeValue("version", hw.strVersion))
4404 {
4405 /* KLUDGE ALERT! For a while during the 3.1 development this was not
4406 written because it was thought to have a default value of "2". For
4407 sv <= 1.3 it defaults to "1" because the attribute didn't exist,
4408 while for 1.4+ it is sort of mandatory. Now, the buggy XML writer
4409 code only wrote 1.7 and later. So, if it's a 1.7+ XML file and it's
4410 missing the hardware version, then it probably should be "2" instead
4411 of "1". */
4412 if (m->sv < SettingsVersion_v1_7)
4413 hw.strVersion = "1";
4414 else
4415 hw.strVersion = "2";
4416 }
4417 Utf8Str strUUID;
4418 if (elmHardware.getAttributeValue("uuid", strUUID))
4419 parseUUID(hw.uuid, strUUID, &elmHardware);
4420
4421 xml::NodesLoop nl1(elmHardware);
4422 const xml::ElementNode *pelmHwChild;
4423 while ((pelmHwChild = nl1.forAllNodes()))
4424 {
4425 if (pelmHwChild->nameEquals("CPU"))
4426 {
4427 if (!pelmHwChild->getAttributeValue("count", hw.cCPUs))
4428 {
4429 // pre-1.5 variant; not sure if this actually exists in the wild anywhere
4430 const xml::ElementNode *pelmCPUChild;
4431 if ((pelmCPUChild = pelmHwChild->findChildElement("CPUCount")))
4432 pelmCPUChild->getAttributeValue("count", hw.cCPUs);
4433 }
4434
4435 pelmHwChild->getAttributeValue("hotplug", hw.fCpuHotPlug);
4436 pelmHwChild->getAttributeValue("executionCap", hw.ulCpuExecutionCap);
4437
4438 const xml::ElementNode *pelmCPUChild;
4439 if (hw.fCpuHotPlug)
4440 {
4441 if ((pelmCPUChild = pelmHwChild->findChildElement("CpuTree")))
4442 readCpuTree(*pelmCPUChild, hw.llCpus);
4443 }
4444
4445 if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtEx")))
4446 {
4447 pelmCPUChild->getAttributeValue("enabled", hw.fHardwareVirt);
4448 }
4449 if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExNestedPaging")))
4450 pelmCPUChild->getAttributeValue("enabled", hw.fNestedPaging);
4451 if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExLargePages")))
4452 pelmCPUChild->getAttributeValue("enabled", hw.fLargePages);
4453 if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExVPID")))
4454 pelmCPUChild->getAttributeValue("enabled", hw.fVPID);
4455 if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExUX")))
4456 pelmCPUChild->getAttributeValue("enabled", hw.fUnrestrictedExecution);
4457 if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtForce")))
4458 pelmCPUChild->getAttributeValue("enabled", hw.fHardwareVirtForce);
4459 if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExUseNativeApi")))
4460 pelmCPUChild->getAttributeValue("enabled", hw.fUseNativeApi);
4461 if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExVirtVmsaveVmload")))
4462 pelmCPUChild->getAttributeValue("enabled", hw.fVirtVmsaveVmload);
4463
4464 if (!(pelmCPUChild = pelmHwChild->findChildElement("PAE")))
4465 {
4466 /* The default for pre 3.1 was false, so we must respect that. */
4467 if (m->sv < SettingsVersion_v1_9)
4468 hw.fPAE = false;
4469 }
4470 else
4471 pelmCPUChild->getAttributeValue("enabled", hw.fPAE);
4472
4473 bool fLongMode;
4474 if ( (pelmCPUChild = pelmHwChild->findChildElement("LongMode"))
4475 && pelmCPUChild->getAttributeValue("enabled", fLongMode) )
4476 hw.enmLongMode = fLongMode ? Hardware::LongMode_Enabled : Hardware::LongMode_Disabled;
4477 else
4478 hw.enmLongMode = Hardware::LongMode_Legacy;
4479
4480 if ((pelmCPUChild = pelmHwChild->findChildElement("SyntheticCpu")))
4481 {
4482 bool fSyntheticCpu = false;
4483 pelmCPUChild->getAttributeValue("enabled", fSyntheticCpu);
4484 hw.uCpuIdPortabilityLevel = fSyntheticCpu ? 1 : 0;
4485 }
4486 pelmHwChild->getAttributeValue("CpuIdPortabilityLevel", hw.uCpuIdPortabilityLevel);
4487 pelmHwChild->getAttributeValue("CpuProfile", hw.strCpuProfile);
4488
4489 if ((pelmCPUChild = pelmHwChild->findChildElement("TripleFaultReset")))
4490 pelmCPUChild->getAttributeValue("enabled", hw.fTripleFaultReset);
4491
4492 if ((pelmCPUChild = pelmHwChild->findChildElement("APIC")))
4493 pelmCPUChild->getAttributeValue("enabled", hw.fAPIC);
4494 if ((pelmCPUChild = pelmHwChild->findChildElement("X2APIC")))
4495 pelmCPUChild->getAttributeValue("enabled", hw.fX2APIC);
4496 if (hw.fX2APIC)
4497 hw.fAPIC = true;
4498 pelmCPUChild = pelmHwChild->findChildElement("IBPBOn");
4499 if (pelmCPUChild)
4500 {
4501 pelmCPUChild->getAttributeValue("vmexit", hw.fIBPBOnVMExit);
4502 pelmCPUChild->getAttributeValue("vmentry", hw.fIBPBOnVMEntry);
4503 }
4504 pelmCPUChild = pelmHwChild->findChildElement("SpecCtrl");
4505 if (pelmCPUChild)
4506 pelmCPUChild->getAttributeValue("enabled", hw.fSpecCtrl);
4507 pelmCPUChild = pelmHwChild->findChildElement("SpecCtrlByHost");
4508 if (pelmCPUChild)
4509 pelmCPUChild->getAttributeValue("enabled", hw.fSpecCtrlByHost);
4510 pelmCPUChild = pelmHwChild->findChildElement("L1DFlushOn");
4511 if (pelmCPUChild)
4512 {
4513 pelmCPUChild->getAttributeValue("scheduling", hw.fL1DFlushOnSched);
4514 pelmCPUChild->getAttributeValue("vmentry", hw.fL1DFlushOnVMEntry);
4515 }
4516 pelmCPUChild = pelmHwChild->findChildElement("MDSClearOn");
4517 if (pelmCPUChild)
4518 {
4519 pelmCPUChild->getAttributeValue("scheduling", hw.fMDSClearOnSched);
4520 pelmCPUChild->getAttributeValue("vmentry", hw.fMDSClearOnVMEntry);
4521 }
4522 pelmCPUChild = pelmHwChild->findChildElement("NestedHWVirt");
4523 if (pelmCPUChild)
4524 pelmCPUChild->getAttributeValue("enabled", hw.fNestedHWVirt);
4525
4526 if ((pelmCPUChild = pelmHwChild->findChildElement("CpuIdTree")))
4527 readCpuIdTree(*pelmCPUChild, hw.llCpuIdLeafs);
4528 }
4529 else if (pelmHwChild->nameEquals("Memory"))
4530 {
4531 pelmHwChild->getAttributeValue("RAMSize", hw.ulMemorySizeMB);
4532 pelmHwChild->getAttributeValue("PageFusion", hw.fPageFusionEnabled);
4533 }
4534 else if (pelmHwChild->nameEquals("Firmware"))
4535 {
4536 Utf8Str strFirmwareType;
4537 if (pelmHwChild->getAttributeValue("type", strFirmwareType))
4538 {
4539 if ( (strFirmwareType == "BIOS")
4540 || (strFirmwareType == "1") // some trunk builds used the number here
4541 )
4542 hw.firmwareType = FirmwareType_BIOS;
4543 else if ( (strFirmwareType == "EFI")
4544 || (strFirmwareType == "2") // some trunk builds used the number here
4545 )
4546 hw.firmwareType = FirmwareType_EFI;
4547 else if ( strFirmwareType == "EFI32")
4548 hw.firmwareType = FirmwareType_EFI32;
4549 else if ( strFirmwareType == "EFI64")
4550 hw.firmwareType = FirmwareType_EFI64;
4551 else if ( strFirmwareType == "EFIDUAL")
4552 hw.firmwareType = FirmwareType_EFIDUAL;
4553 else
4554 throw ConfigFileError(this,
4555 pelmHwChild,
4556 N_("Invalid value '%s' in Firmware/@type"),
4557 strFirmwareType.c_str());
4558 }
4559 }
4560 else if (pelmHwChild->nameEquals("HID"))
4561 {
4562 Utf8Str strHIDType;
4563 if (pelmHwChild->getAttributeValue("Keyboard", strHIDType))
4564 {
4565 if (strHIDType == "None")
4566 hw.keyboardHIDType = KeyboardHIDType_None;
4567 else if (strHIDType == "USBKeyboard")
4568 hw.keyboardHIDType = KeyboardHIDType_USBKeyboard;
4569 else if (strHIDType == "PS2Keyboard")
4570 hw.keyboardHIDType = KeyboardHIDType_PS2Keyboard;
4571 else if (strHIDType == "ComboKeyboard")
4572 hw.keyboardHIDType = KeyboardHIDType_ComboKeyboard;
4573 else
4574 throw ConfigFileError(this,
4575 pelmHwChild,
4576 N_("Invalid value '%s' in HID/Keyboard/@type"),
4577 strHIDType.c_str());
4578 }
4579 if (pelmHwChild->getAttributeValue("Pointing", strHIDType))
4580 {
4581 if (strHIDType == "None")
4582 hw.pointingHIDType = PointingHIDType_None;
4583 else if (strHIDType == "USBMouse")
4584 hw.pointingHIDType = PointingHIDType_USBMouse;
4585 else if (strHIDType == "USBTablet")
4586 hw.pointingHIDType = PointingHIDType_USBTablet;
4587 else if (strHIDType == "PS2Mouse")
4588 hw.pointingHIDType = PointingHIDType_PS2Mouse;
4589 else if (strHIDType == "ComboMouse")
4590 hw.pointingHIDType = PointingHIDType_ComboMouse;
4591 else if (strHIDType == "USBMultiTouch")
4592 hw.pointingHIDType = PointingHIDType_USBMultiTouch;
4593 else
4594 throw ConfigFileError(this,
4595 pelmHwChild,
4596 N_("Invalid value '%s' in HID/Pointing/@type"),
4597 strHIDType.c_str());
4598 }
4599 }
4600 else if (pelmHwChild->nameEquals("Chipset"))
4601 {
4602 Utf8Str strChipsetType;
4603 if (pelmHwChild->getAttributeValue("type", strChipsetType))
4604 {
4605 if (strChipsetType == "PIIX3")
4606 hw.chipsetType = ChipsetType_PIIX3;
4607 else if (strChipsetType == "ICH9")
4608 hw.chipsetType = ChipsetType_ICH9;
4609 else
4610 throw ConfigFileError(this,
4611 pelmHwChild,
4612 N_("Invalid value '%s' in Chipset/@type"),
4613 strChipsetType.c_str());
4614 }
4615 }
4616 else if (pelmHwChild->nameEquals("Iommu"))
4617 {
4618 Utf8Str strIommuType;
4619 if (pelmHwChild->getAttributeValue("type", strIommuType))
4620 {
4621 if (strIommuType == "None")
4622 hw.iommuType = IommuType_None;
4623 else if (strIommuType == "Automatic")
4624 hw.iommuType = IommuType_Automatic;
4625 else if (strIommuType == "AMD")
4626 hw.iommuType = IommuType_AMD;
4627 else if (strIommuType == "Intel")
4628 hw.iommuType = IommuType_Intel;
4629 else
4630 throw ConfigFileError(this,
4631 pelmHwChild,
4632 N_("Invalid value '%s' in Iommu/@type"),
4633 strIommuType.c_str());
4634 }
4635 }
4636 else if (pelmHwChild->nameEquals("Paravirt"))
4637 {
4638 Utf8Str strProvider;
4639 if (pelmHwChild->getAttributeValue("provider", strProvider))
4640 {
4641 if (strProvider == "None")
4642 hw.paravirtProvider = ParavirtProvider_None;
4643 else if (strProvider == "Default")
4644 hw.paravirtProvider = ParavirtProvider_Default;
4645 else if (strProvider == "Legacy")
4646 hw.paravirtProvider = ParavirtProvider_Legacy;
4647 else if (strProvider == "Minimal")
4648 hw.paravirtProvider = ParavirtProvider_Minimal;
4649 else if (strProvider == "HyperV")
4650 hw.paravirtProvider = ParavirtProvider_HyperV;
4651 else if (strProvider == "KVM")
4652 hw.paravirtProvider = ParavirtProvider_KVM;
4653 else
4654 throw ConfigFileError(this,
4655 pelmHwChild,
4656 N_("Invalid value '%s' in Paravirt/@provider attribute"),
4657 strProvider.c_str());
4658 }
4659
4660 pelmHwChild->getAttributeValue("debug", hw.strParavirtDebug);
4661 }
4662 else if (pelmHwChild->nameEquals("HPET"))
4663 {
4664 pelmHwChild->getAttributeValue("enabled", hw.fHPETEnabled);
4665 }
4666 else if (pelmHwChild->nameEquals("Boot"))
4667 {
4668 hw.mapBootOrder.clear();
4669
4670 xml::NodesLoop nl2(*pelmHwChild, "Order");
4671 const xml::ElementNode *pelmOrder;
4672 while ((pelmOrder = nl2.forAllNodes()))
4673 {
4674 uint32_t ulPos;
4675 Utf8Str strDevice;
4676 if (!pelmOrder->getAttributeValue("position", ulPos))
4677 throw ConfigFileError(this, pelmOrder, N_("Required Boot/Order/@position attribute is missing"));
4678
4679 if ( ulPos < 1
4680 || ulPos > SchemaDefs::MaxBootPosition
4681 )
4682 throw ConfigFileError(this,
4683 pelmOrder,
4684 N_("Invalid value '%RU32' in Boot/Order/@position: must be greater than 0 and less than %RU32"),
4685 ulPos,
4686 SchemaDefs::MaxBootPosition + 1);
4687 // XML is 1-based but internal data is 0-based
4688 --ulPos;
4689
4690 if (hw.mapBootOrder.find(ulPos) != hw.mapBootOrder.end())
4691 throw ConfigFileError(this, pelmOrder, N_("Invalid value '%RU32' in Boot/Order/@position: value is not unique"), ulPos);
4692
4693 if (!pelmOrder->getAttributeValue("device", strDevice))
4694 throw ConfigFileError(this, pelmOrder, N_("Required Boot/Order/@device attribute is missing"));
4695
4696 DeviceType_T type;
4697 if (strDevice == "None")
4698 type = DeviceType_Null;
4699 else if (strDevice == "Floppy")
4700 type = DeviceType_Floppy;
4701 else if (strDevice == "DVD")
4702 type = DeviceType_DVD;
4703 else if (strDevice == "HardDisk")
4704 type = DeviceType_HardDisk;
4705 else if (strDevice == "Network")
4706 type = DeviceType_Network;
4707 else
4708 throw ConfigFileError(this, pelmOrder, N_("Invalid value '%s' in Boot/Order/@device attribute"), strDevice.c_str());
4709 hw.mapBootOrder[ulPos] = type;
4710 }
4711 }
4712 else if (pelmHwChild->nameEquals("Display"))
4713 {
4714 Utf8Str strGraphicsControllerType;
4715 if (!pelmHwChild->getAttributeValue("controller", strGraphicsControllerType))
4716 hw.graphicsAdapter.graphicsControllerType = GraphicsControllerType_VBoxVGA;
4717 else
4718 {
4719 strGraphicsControllerType.toUpper();
4720 GraphicsControllerType_T type;
4721 if (strGraphicsControllerType == "VBOXVGA")
4722 type = GraphicsControllerType_VBoxVGA;
4723 else if (strGraphicsControllerType == "VMSVGA")
4724 type = GraphicsControllerType_VMSVGA;
4725 else if (strGraphicsControllerType == "VBOXSVGA")
4726 type = GraphicsControllerType_VBoxSVGA;
4727 else if (strGraphicsControllerType == "NONE")
4728 type = GraphicsControllerType_Null;
4729 else
4730 throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in Display/@controller attribute"), strGraphicsControllerType.c_str());
4731 hw.graphicsAdapter.graphicsControllerType = type;
4732 }
4733 pelmHwChild->getAttributeValue("VRAMSize", hw.graphicsAdapter.ulVRAMSizeMB);
4734 if (!pelmHwChild->getAttributeValue("monitorCount", hw.graphicsAdapter.cMonitors))
4735 pelmHwChild->getAttributeValue("MonitorCount", hw.graphicsAdapter.cMonitors); // pre-v1.5 variant
4736 if (!pelmHwChild->getAttributeValue("accelerate3D", hw.graphicsAdapter.fAccelerate3D))
4737 pelmHwChild->getAttributeValue("Accelerate3D", hw.graphicsAdapter.fAccelerate3D); // pre-v1.5 variant
4738 pelmHwChild->getAttributeValue("accelerate2DVideo", hw.graphicsAdapter.fAccelerate2DVideo);
4739 }
4740 else if (pelmHwChild->nameEquals("VideoCapture"))
4741 {
4742 pelmHwChild->getAttributeValue("enabled", hw.recordingSettings.fEnabled);
4743
4744 /* Right now I don't want to bump the settings version, so just convert the enabled
4745 * screens to the former uint64t_t bit array and vice versa. */
4746 uint64_t u64VideoCaptureScreens;
4747 pelmHwChild->getAttributeValue("screens", u64VideoCaptureScreens);
4748
4749 /* At the moment we only support one capturing configuration, that is, all screens
4750 * have the same configuration. So load/save to/from screen 0. */
4751 Assert(hw.recordingSettings.mapScreens.size()); /* At least screen must be present. */
4752 RecordingScreenSettings &screen0Settings = hw.recordingSettings.mapScreens[0];
4753
4754 pelmHwChild->getAttributeValue("maxTime", screen0Settings.ulMaxTimeS);
4755 pelmHwChild->getAttributeValue("options", screen0Settings.strOptions);
4756 pelmHwChild->getAttributeValuePath("file", screen0Settings.File.strName);
4757 pelmHwChild->getAttributeValue("maxSize", screen0Settings.File.ulMaxSizeMB);
4758 pelmHwChild->getAttributeValue("horzRes", screen0Settings.Video.ulWidth);
4759 pelmHwChild->getAttributeValue("vertRes", screen0Settings.Video.ulHeight);
4760 pelmHwChild->getAttributeValue("rate", screen0Settings.Video.ulRate);
4761 pelmHwChild->getAttributeValue("fps", screen0Settings.Video.ulFPS);
4762
4763 for (unsigned i = 0; i < hw.graphicsAdapter.cMonitors; i++) /* Don't add more settings than we have monitors configured. */
4764 {
4765 /* Add screen i to config in any case. */
4766 hw.recordingSettings.mapScreens[i] = screen0Settings;
4767
4768 if (u64VideoCaptureScreens & RT_BIT_64(i)) /* Screen i enabled? */
4769 hw.recordingSettings.mapScreens[i].fEnabled = true;
4770 }
4771 }
4772 else if (pelmHwChild->nameEquals("RemoteDisplay"))
4773 {
4774 pelmHwChild->getAttributeValue("enabled", hw.vrdeSettings.fEnabled);
4775
4776 Utf8Str str;
4777 if (pelmHwChild->getAttributeValue("port", str))
4778 hw.vrdeSettings.mapProperties["TCP/Ports"] = str;
4779 if (pelmHwChild->getAttributeValue("netAddress", str))
4780 hw.vrdeSettings.mapProperties["TCP/Address"] = str;
4781
4782 Utf8Str strAuthType;
4783 if (pelmHwChild->getAttributeValue("authType", strAuthType))
4784 {
4785 // settings before 1.3 used lower case so make sure this is case-insensitive
4786 strAuthType.toUpper();
4787 if (strAuthType == "NULL")
4788 hw.vrdeSettings.authType = AuthType_Null;
4789 else if (strAuthType == "GUEST")
4790 hw.vrdeSettings.authType = AuthType_Guest;
4791 else if (strAuthType == "EXTERNAL")
4792 hw.vrdeSettings.authType = AuthType_External;
4793 else
4794 throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in RemoteDisplay/@authType attribute"), strAuthType.c_str());
4795 }
4796
4797 pelmHwChild->getAttributeValue("authLibrary", hw.vrdeSettings.strAuthLibrary);
4798 pelmHwChild->getAttributeValue("authTimeout", hw.vrdeSettings.ulAuthTimeout);
4799 pelmHwChild->getAttributeValue("allowMultiConnection", hw.vrdeSettings.fAllowMultiConnection);
4800 pelmHwChild->getAttributeValue("reuseSingleConnection", hw.vrdeSettings.fReuseSingleConnection);
4801
4802 /* 3.2 and 4.0 betas, 4.0 has this information in VRDEProperties. */
4803 const xml::ElementNode *pelmVideoChannel;
4804 if ((pelmVideoChannel = pelmHwChild->findChildElement("VideoChannel")))
4805 {
4806 bool fVideoChannel = false;
4807 pelmVideoChannel->getAttributeValue("enabled", fVideoChannel);
4808 hw.vrdeSettings.mapProperties["VideoChannel/Enabled"] = fVideoChannel? "true": "false";
4809
4810 uint32_t ulVideoChannelQuality = 75;
4811 pelmVideoChannel->getAttributeValue("quality", ulVideoChannelQuality);
4812 ulVideoChannelQuality = RT_CLAMP(ulVideoChannelQuality, 10, 100);
4813 char *pszBuffer = NULL;
4814 if (RTStrAPrintf(&pszBuffer, "%d", ulVideoChannelQuality) >= 0)
4815 {
4816 hw.vrdeSettings.mapProperties["VideoChannel/Quality"] = pszBuffer;
4817 RTStrFree(pszBuffer);
4818 }
4819 else
4820 hw.vrdeSettings.mapProperties["VideoChannel/Quality"] = "75";
4821 }
4822 pelmHwChild->getAttributeValue("VRDEExtPack", hw.vrdeSettings.strVrdeExtPack);
4823
4824 const xml::ElementNode *pelmProperties = pelmHwChild->findChildElement("VRDEProperties");
4825 if (pelmProperties != NULL)
4826 {
4827 xml::NodesLoop nl(*pelmProperties);
4828 const xml::ElementNode *pelmProperty;
4829 while ((pelmProperty = nl.forAllNodes()))
4830 {
4831 if (pelmProperty->nameEquals("Property"))
4832 {
4833 /* <Property name="TCP/Ports" value="3000-3002"/> */
4834 Utf8Str strName, strValue;
4835 if ( pelmProperty->getAttributeValue("name", strName)
4836 && pelmProperty->getAttributeValue("value", strValue))
4837 hw.vrdeSettings.mapProperties[strName] = strValue;
4838 else
4839 throw ConfigFileError(this, pelmProperty, N_("Required VRDE Property/@name or @value attribute is missing"));
4840 }
4841 }
4842 }
4843 }
4844 else if (pelmHwChild->nameEquals("BIOS"))
4845 {
4846 const xml::ElementNode *pelmBIOSChild;
4847 if ((pelmBIOSChild = pelmHwChild->findChildElement("ACPI")))
4848 pelmBIOSChild->getAttributeValue("enabled", hw.biosSettings.fACPIEnabled);
4849 if ((pelmBIOSChild = pelmHwChild->findChildElement("IOAPIC")))
4850 pelmBIOSChild->getAttributeValue("enabled", hw.biosSettings.fIOAPICEnabled);
4851 if ((pelmBIOSChild = pelmHwChild->findChildElement("APIC")))
4852 {
4853 Utf8Str strAPIC;
4854 if (pelmBIOSChild->getAttributeValue("mode", strAPIC))
4855 {
4856 strAPIC.toUpper();
4857 if (strAPIC == "DISABLED")
4858 hw.biosSettings.apicMode = APICMode_Disabled;
4859 else if (strAPIC == "APIC")
4860 hw.biosSettings.apicMode = APICMode_APIC;
4861 else if (strAPIC == "X2APIC")
4862 hw.biosSettings.apicMode = APICMode_X2APIC;
4863 else
4864 throw ConfigFileError(this, pelmBIOSChild, N_("Invalid value '%s' in APIC/@mode attribute"), strAPIC.c_str());
4865 }
4866 }
4867 if ((pelmBIOSChild = pelmHwChild->findChildElement("Logo")))
4868 {
4869 pelmBIOSChild->getAttributeValue("fadeIn", hw.biosSettings.fLogoFadeIn);
4870 pelmBIOSChild->getAttributeValue("fadeOut", hw.biosSettings.fLogoFadeOut);
4871 pelmBIOSChild->getAttributeValue("displayTime", hw.biosSettings.ulLogoDisplayTime);
4872 pelmBIOSChild->getAttributeValue("imagePath", hw.biosSettings.strLogoImagePath);
4873 }
4874 if ((pelmBIOSChild = pelmHwChild->findChildElement("BootMenu")))
4875 {
4876 Utf8Str strBootMenuMode;
4877 if (pelmBIOSChild->getAttributeValue("mode", strBootMenuMode))
4878 {
4879 // settings before 1.3 used lower case so make sure this is case-insensitive
4880 strBootMenuMode.toUpper();
4881 if (strBootMenuMode == "DISABLED")
4882 hw.biosSettings.biosBootMenuMode = BIOSBootMenuMode_Disabled;
4883 else if (strBootMenuMode == "MENUONLY")
4884 hw.biosSettings.biosBootMenuMode = BIOSBootMenuMode_MenuOnly;
4885 else if (strBootMenuMode == "MESSAGEANDMENU")
4886 hw.biosSettings.biosBootMenuMode = BIOSBootMenuMode_MessageAndMenu;
4887 else
4888 throw ConfigFileError(this, pelmBIOSChild, N_("Invalid value '%s' in BootMenu/@mode attribute"), strBootMenuMode.c_str());
4889 }
4890 }
4891 if ((pelmBIOSChild = pelmHwChild->findChildElement("PXEDebug")))
4892 pelmBIOSChild->getAttributeValue("enabled", hw.biosSettings.fPXEDebugEnabled);
4893 if ((pelmBIOSChild = pelmHwChild->findChildElement("TimeOffset")))
4894 pelmBIOSChild->getAttributeValue("value", hw.biosSettings.llTimeOffset);
4895 if ((pelmBIOSChild = pelmHwChild->findChildElement("NVRAM")))
4896 pelmBIOSChild->getAttributeValue("path", hw.biosSettings.strNVRAMPath);
4897 if ((pelmBIOSChild = pelmHwChild->findChildElement("SmbiosUuidLittleEndian")))
4898 pelmBIOSChild->getAttributeValue("enabled", hw.biosSettings.fSmbiosUuidLittleEndian);
4899 else
4900 hw.biosSettings.fSmbiosUuidLittleEndian = false; /* Default for existing VMs. */
4901
4902 // legacy BIOS/IDEController (pre 1.7)
4903 if ( (m->sv < SettingsVersion_v1_7)
4904 && (pelmBIOSChild = pelmHwChild->findChildElement("IDEController"))
4905 )
4906 {
4907 StorageController sctl;
4908 sctl.strName = "IDE Controller";
4909 sctl.storageBus = StorageBus_IDE;
4910
4911 Utf8Str strType;
4912 if (pelmBIOSChild->getAttributeValue("type", strType))
4913 {
4914 if (strType == "PIIX3")
4915 sctl.controllerType = StorageControllerType_PIIX3;
4916 else if (strType == "PIIX4")
4917 sctl.controllerType = StorageControllerType_PIIX4;
4918 else if (strType == "ICH6")
4919 sctl.controllerType = StorageControllerType_ICH6;
4920 else
4921 throw ConfigFileError(this, pelmBIOSChild, N_("Invalid value '%s' for IDEController/@type attribute"), strType.c_str());
4922 }
4923 sctl.ulPortCount = 2;
4924 hw.storage.llStorageControllers.push_back(sctl);
4925 }
4926 }
4927 else if ( (m->sv <= SettingsVersion_v1_14)
4928 && pelmHwChild->nameEquals("USBController"))
4929 {
4930 bool fEnabled = false;
4931
4932 pelmHwChild->getAttributeValue("enabled", fEnabled);
4933 if (fEnabled)
4934 {
4935 /* Create OHCI controller with default name. */
4936 USBController ctrl;
4937
4938 ctrl.strName = "OHCI";
4939 ctrl.enmType = USBControllerType_OHCI;
4940 hw.usbSettings.llUSBControllers.push_back(ctrl);
4941 }
4942
4943 pelmHwChild->getAttributeValue("enabledEhci", fEnabled);
4944 if (fEnabled)
4945 {
4946 /* Create OHCI controller with default name. */
4947 USBController ctrl;
4948
4949 ctrl.strName = "EHCI";
4950 ctrl.enmType = USBControllerType_EHCI;
4951 hw.usbSettings.llUSBControllers.push_back(ctrl);
4952 }
4953
4954 readUSBDeviceFilters(*pelmHwChild,
4955 hw.usbSettings.llDeviceFilters);
4956 }
4957 else if (pelmHwChild->nameEquals("USB"))
4958 {
4959 const xml::ElementNode *pelmUSBChild;
4960
4961 if ((pelmUSBChild = pelmHwChild->findChildElement("Controllers")))
4962 {
4963 xml::NodesLoop nl2(*pelmUSBChild, "Controller");
4964 const xml::ElementNode *pelmCtrl;
4965
4966 while ((pelmCtrl = nl2.forAllNodes()))
4967 {
4968 USBController ctrl;
4969 com::Utf8Str strCtrlType;
4970
4971 pelmCtrl->getAttributeValue("name", ctrl.strName);
4972
4973 if (pelmCtrl->getAttributeValue("type", strCtrlType))
4974 {
4975 if (strCtrlType == "OHCI")
4976 ctrl.enmType = USBControllerType_OHCI;
4977 else if (strCtrlType == "EHCI")
4978 ctrl.enmType = USBControllerType_EHCI;
4979 else if (strCtrlType == "XHCI")
4980 ctrl.enmType = USBControllerType_XHCI;
4981 else
4982 throw ConfigFileError(this, pelmCtrl, N_("Invalid value '%s' for Controller/@type attribute"), strCtrlType.c_str());
4983 }
4984
4985 hw.usbSettings.llUSBControllers.push_back(ctrl);
4986 }
4987 }
4988
4989 if ((pelmUSBChild = pelmHwChild->findChildElement("DeviceFilters")))
4990 readUSBDeviceFilters(*pelmUSBChild, hw.usbSettings.llDeviceFilters);
4991 }
4992 else if ( m->sv < SettingsVersion_v1_7
4993 && pelmHwChild->nameEquals("SATAController"))
4994 {
4995 bool f;
4996 if ( pelmHwChild->getAttributeValue("enabled", f)
4997 && f)
4998 {
4999 StorageController sctl;
5000 sctl.strName = "SATA Controller";
5001 sctl.storageBus = StorageBus_SATA;
5002 sctl.controllerType = StorageControllerType_IntelAhci;
5003
5004 readStorageControllerAttributes(*pelmHwChild, sctl);
5005
5006 hw.storage.llStorageControllers.push_back(sctl);
5007 }
5008 }
5009 else if (pelmHwChild->nameEquals("Network"))
5010 readNetworkAdapters(*pelmHwChild, hw.llNetworkAdapters);
5011 else if (pelmHwChild->nameEquals("RTC"))
5012 {
5013 Utf8Str strLocalOrUTC;
5014 machineUserData.fRTCUseUTC = pelmHwChild->getAttributeValue("localOrUTC", strLocalOrUTC)
5015 && strLocalOrUTC == "UTC";
5016 }
5017 else if ( pelmHwChild->nameEquals("UART")
5018 || pelmHwChild->nameEquals("Uart") // used before 1.3
5019 )
5020 readSerialPorts(*pelmHwChild, hw.llSerialPorts);
5021 else if ( pelmHwChild->nameEquals("LPT")
5022 || pelmHwChild->nameEquals("Lpt") // used before 1.3
5023 )
5024 readParallelPorts(*pelmHwChild, hw.llParallelPorts);
5025 else if (pelmHwChild->nameEquals("AudioAdapter"))
5026 readAudioAdapter(*pelmHwChild, hw.audioAdapter);
5027 else if (pelmHwChild->nameEquals("SharedFolders"))
5028 {
5029 xml::NodesLoop nl2(*pelmHwChild, "SharedFolder");
5030 const xml::ElementNode *pelmFolder;
5031 while ((pelmFolder = nl2.forAllNodes()))
5032 {
5033 SharedFolder sf;
5034 pelmFolder->getAttributeValue("name", sf.strName);
5035 pelmFolder->getAttributeValue("hostPath", sf.strHostPath);
5036 pelmFolder->getAttributeValue("writable", sf.fWritable);
5037 pelmFolder->getAttributeValue("autoMount", sf.fAutoMount);
5038 pelmFolder->getAttributeValue("autoMountPoint", sf.strAutoMountPoint);
5039 hw.llSharedFolders.push_back(sf);
5040 }
5041 }
5042 else if (pelmHwChild->nameEquals("Clipboard"))
5043 {
5044 Utf8Str strTemp;
5045 if (pelmHwChild->getAttributeValue("mode", strTemp))
5046 {
5047 if (strTemp == "Disabled")
5048 hw.clipboardMode = ClipboardMode_Disabled;
5049 else if (strTemp == "HostToGuest")
5050 hw.clipboardMode = ClipboardMode_HostToGuest;
5051 else if (strTemp == "GuestToHost")
5052 hw.clipboardMode = ClipboardMode_GuestToHost;
5053 else if (strTemp == "Bidirectional")
5054 hw.clipboardMode = ClipboardMode_Bidirectional;
5055 else
5056 throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in Clipboard/@mode attribute"), strTemp.c_str());
5057 }
5058
5059 pelmHwChild->getAttributeValue("fileTransfersEnabled", hw.fClipboardFileTransfersEnabled);
5060 }
5061 else if (pelmHwChild->nameEquals("DragAndDrop"))
5062 {
5063 Utf8Str strTemp;
5064 if (pelmHwChild->getAttributeValue("mode", strTemp))
5065 {
5066 if (strTemp == "Disabled")
5067 hw.dndMode = DnDMode_Disabled;
5068 else if (strTemp == "HostToGuest")
5069 hw.dndMode = DnDMode_HostToGuest;
5070 else if (strTemp == "GuestToHost")
5071 hw.dndMode = DnDMode_GuestToHost;
5072 else if (strTemp == "Bidirectional")
5073 hw.dndMode = DnDMode_Bidirectional;
5074 else
5075 throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in DragAndDrop/@mode attribute"), strTemp.c_str());
5076 }
5077 }
5078 else if (pelmHwChild->nameEquals("Guest"))
5079 {
5080 if (!pelmHwChild->getAttributeValue("memoryBalloonSize", hw.ulMemoryBalloonSize))
5081 pelmHwChild->getAttributeValue("MemoryBalloonSize", hw.ulMemoryBalloonSize); // used before 1.3
5082 }
5083 else if (pelmHwChild->nameEquals("GuestProperties"))
5084 readGuestProperties(*pelmHwChild, hw);
5085 else if (pelmHwChild->nameEquals("IO"))
5086 {
5087 const xml::ElementNode *pelmBwGroups;
5088 const xml::ElementNode *pelmIOChild;
5089
5090 if ((pelmIOChild = pelmHwChild->findChildElement("IoCache")))
5091 {
5092 pelmIOChild->getAttributeValue("enabled", hw.ioSettings.fIOCacheEnabled);
5093 pelmIOChild->getAttributeValue("size", hw.ioSettings.ulIOCacheSize);
5094 }
5095
5096 if ((pelmBwGroups = pelmHwChild->findChildElement("BandwidthGroups")))
5097 {
5098 xml::NodesLoop nl2(*pelmBwGroups, "BandwidthGroup");
5099 const xml::ElementNode *pelmBandwidthGroup;
5100 while ((pelmBandwidthGroup = nl2.forAllNodes()))
5101 {
5102 BandwidthGroup gr;
5103 Utf8Str strTemp;
5104
5105 pelmBandwidthGroup->getAttributeValue("name", gr.strName);
5106
5107 if (pelmBandwidthGroup->getAttributeValue("type", strTemp))
5108 {
5109 if (strTemp == "Disk")
5110 gr.enmType = BandwidthGroupType_Disk;
5111 else if (strTemp == "Network")
5112 gr.enmType = BandwidthGroupType_Network;
5113 else
5114 throw ConfigFileError(this, pelmBandwidthGroup, N_("Invalid value '%s' in BandwidthGroup/@type attribute"), strTemp.c_str());
5115 }
5116 else
5117 throw ConfigFileError(this, pelmBandwidthGroup, N_("Missing BandwidthGroup/@type attribute"));
5118
5119 if (!pelmBandwidthGroup->getAttributeValue("maxBytesPerSec", gr.cMaxBytesPerSec))
5120 {
5121 pelmBandwidthGroup->getAttributeValue("maxMbPerSec", gr.cMaxBytesPerSec);
5122 gr.cMaxBytesPerSec *= _1M;
5123 }
5124 hw.ioSettings.llBandwidthGroups.push_back(gr);
5125 }
5126 }
5127 }
5128 else if (pelmHwChild->nameEquals("HostPci"))
5129 {
5130 const xml::ElementNode *pelmDevices;
5131
5132 if ((pelmDevices = pelmHwChild->findChildElement("Devices")))
5133 {
5134 xml::NodesLoop nl2(*pelmDevices, "Device");
5135 const xml::ElementNode *pelmDevice;
5136 while ((pelmDevice = nl2.forAllNodes()))
5137 {
5138 HostPCIDeviceAttachment hpda;
5139
5140 if (!pelmDevice->getAttributeValue("host", hpda.uHostAddress))
5141 throw ConfigFileError(this, pelmDevice, N_("Missing Device/@host attribute"));
5142
5143 if (!pelmDevice->getAttributeValue("guest", hpda.uGuestAddress))
5144 throw ConfigFileError(this, pelmDevice, N_("Missing Device/@guest attribute"));
5145
5146 /* name is optional */
5147 pelmDevice->getAttributeValue("name", hpda.strDeviceName);
5148
5149 hw.pciAttachments.push_back(hpda);
5150 }
5151 }
5152 }
5153 else if (pelmHwChild->nameEquals("EmulatedUSB"))
5154 {
5155 const xml::ElementNode *pelmCardReader;
5156
5157 if ((pelmCardReader = pelmHwChild->findChildElement("CardReader")))
5158 {
5159 pelmCardReader->getAttributeValue("enabled", hw.fEmulatedUSBCardReader);
5160 }
5161 }
5162 else if (pelmHwChild->nameEquals("Frontend"))
5163 {
5164 const xml::ElementNode *pelmDefault;
5165
5166 if ((pelmDefault = pelmHwChild->findChildElement("Default")))
5167 {
5168 pelmDefault->getAttributeValue("type", hw.strDefaultFrontend);
5169 }
5170 }
5171 else if (pelmHwChild->nameEquals("StorageControllers"))
5172 readStorageControllers(*pelmHwChild, hw.storage);
5173 }
5174
5175 if (hw.ulMemorySizeMB == (uint32_t)-1)
5176 throw ConfigFileError(this, &elmHardware, N_("Required Memory/@RAMSize element/attribute is missing"));
5177}
5178
5179/**
5180 * This gets called instead of readStorageControllers() for legacy pre-1.7 settings
5181 * files which have a \<HardDiskAttachments\> node and storage controller settings
5182 * hidden in the \<Hardware\> settings. We set the StorageControllers fields just the
5183 * same, just from different sources.
5184 * @param elmHardDiskAttachments \<HardDiskAttachments\> XML node.
5185 * @param strg
5186 */
5187void MachineConfigFile::readHardDiskAttachments_pre1_7(const xml::ElementNode &elmHardDiskAttachments,
5188 Storage &strg)
5189{
5190 StorageController *pIDEController = NULL;
5191 StorageController *pSATAController = NULL;
5192
5193 for (StorageControllersList::iterator it = strg.llStorageControllers.begin();
5194 it != strg.llStorageControllers.end();
5195 ++it)
5196 {
5197 StorageController &s = *it;
5198 if (s.storageBus == StorageBus_IDE)
5199 pIDEController = &s;
5200 else if (s.storageBus == StorageBus_SATA)
5201 pSATAController = &s;
5202 }
5203
5204 xml::NodesLoop nl1(elmHardDiskAttachments, "HardDiskAttachment");
5205 const xml::ElementNode *pelmAttachment;
5206 while ((pelmAttachment = nl1.forAllNodes()))
5207 {
5208 AttachedDevice att;
5209 Utf8Str strUUID, strBus;
5210
5211 if (!pelmAttachment->getAttributeValue("hardDisk", strUUID))
5212 throw ConfigFileError(this, pelmAttachment, N_("Required HardDiskAttachment/@hardDisk attribute is missing"));
5213 parseUUID(att.uuid, strUUID, pelmAttachment);
5214
5215 if (!pelmAttachment->getAttributeValue("bus", strBus))
5216 throw ConfigFileError(this, pelmAttachment, N_("Required HardDiskAttachment/@bus attribute is missing"));
5217 // pre-1.7 'channel' is now port
5218 if (!pelmAttachment->getAttributeValue("channel", att.lPort))
5219 throw ConfigFileError(this, pelmAttachment, N_("Required HardDiskAttachment/@channel attribute is missing"));
5220 // pre-1.7 'device' is still device
5221 if (!pelmAttachment->getAttributeValue("device", att.lDevice))
5222 throw ConfigFileError(this, pelmAttachment, N_("Required HardDiskAttachment/@device attribute is missing"));
5223
5224 att.deviceType = DeviceType_HardDisk;
5225
5226 if (strBus == "IDE")
5227 {
5228 if (!pIDEController)
5229 throw ConfigFileError(this, pelmAttachment, N_("HardDiskAttachment/@bus is 'IDE' but cannot find IDE controller"));
5230 pIDEController->llAttachedDevices.push_back(att);
5231 }
5232 else if (strBus == "SATA")
5233 {
5234 if (!pSATAController)
5235 throw ConfigFileError(this, pelmAttachment, N_("HardDiskAttachment/@bus is 'SATA' but cannot find SATA controller"));
5236 pSATAController->llAttachedDevices.push_back(att);
5237 }
5238 else
5239 throw ConfigFileError(this, pelmAttachment, N_("HardDiskAttachment/@bus attribute has illegal value '%s'"), strBus.c_str());
5240 }
5241}
5242
5243/**
5244 * Reads in a \<StorageControllers\> block and stores it in the given Storage structure.
5245 * Used both directly from readMachine and from readSnapshot, since snapshots
5246 * have their own storage controllers sections.
5247 *
5248 * This is only called for settings version 1.7 and above; see readHardDiskAttachments_pre1_7()
5249 * for earlier versions.
5250 *
5251 * @param elmStorageControllers
5252 * @param strg
5253 */
5254void MachineConfigFile::readStorageControllers(const xml::ElementNode &elmStorageControllers,
5255 Storage &strg)
5256{
5257 xml::NodesLoop nlStorageControllers(elmStorageControllers, "StorageController");
5258 const xml::ElementNode *pelmController;
5259 while ((pelmController = nlStorageControllers.forAllNodes()))
5260 {
5261 StorageController sctl;
5262
5263 if (!pelmController->getAttributeValue("name", sctl.strName))
5264 throw ConfigFileError(this, pelmController, N_("Required StorageController/@name attribute is missing"));
5265 // canonicalize storage controller names for configs in the switchover
5266 // period.
5267 if (m->sv < SettingsVersion_v1_9)
5268 {
5269 if (sctl.strName == "IDE")
5270 sctl.strName = "IDE Controller";
5271 else if (sctl.strName == "SATA")
5272 sctl.strName = "SATA Controller";
5273 else if (sctl.strName == "SCSI")
5274 sctl.strName = "SCSI Controller";
5275 }
5276
5277 pelmController->getAttributeValue("Instance", sctl.ulInstance);
5278 // default from constructor is 0
5279
5280 pelmController->getAttributeValue("Bootable", sctl.fBootable);
5281 // default from constructor is true which is true
5282 // for settings below version 1.11 because they allowed only
5283 // one controller per type.
5284
5285 Utf8Str strType;
5286 if (!pelmController->getAttributeValue("type", strType))
5287 throw ConfigFileError(this, pelmController, N_("Required StorageController/@type attribute is missing"));
5288
5289 if (strType == "AHCI")
5290 {
5291 sctl.storageBus = StorageBus_SATA;
5292 sctl.controllerType = StorageControllerType_IntelAhci;
5293 }
5294 else if (strType == "LsiLogic")
5295 {
5296 sctl.storageBus = StorageBus_SCSI;
5297 sctl.controllerType = StorageControllerType_LsiLogic;
5298 }
5299 else if (strType == "BusLogic")
5300 {
5301 sctl.storageBus = StorageBus_SCSI;
5302 sctl.controllerType = StorageControllerType_BusLogic;
5303 }
5304 else if (strType == "PIIX3")
5305 {
5306 sctl.storageBus = StorageBus_IDE;
5307 sctl.controllerType = StorageControllerType_PIIX3;
5308 }
5309 else if (strType == "PIIX4")
5310 {
5311 sctl.storageBus = StorageBus_IDE;
5312 sctl.controllerType = StorageControllerType_PIIX4;
5313 }
5314 else if (strType == "ICH6")
5315 {
5316 sctl.storageBus = StorageBus_IDE;
5317 sctl.controllerType = StorageControllerType_ICH6;
5318 }
5319 else if ( (m->sv >= SettingsVersion_v1_9)
5320 && (strType == "I82078")
5321 )
5322 {
5323 sctl.storageBus = StorageBus_Floppy;
5324 sctl.controllerType = StorageControllerType_I82078;
5325 }
5326 else if (strType == "LsiLogicSas")
5327 {
5328 sctl.storageBus = StorageBus_SAS;
5329 sctl.controllerType = StorageControllerType_LsiLogicSas;
5330 }
5331 else if (strType == "USB")
5332 {
5333 sctl.storageBus = StorageBus_USB;
5334 sctl.controllerType = StorageControllerType_USB;
5335 }
5336 else if (strType == "NVMe")
5337 {
5338 sctl.storageBus = StorageBus_PCIe;
5339 sctl.controllerType = StorageControllerType_NVMe;
5340 }
5341 else if (strType == "VirtioSCSI")
5342 {
5343 sctl.storageBus = StorageBus_VirtioSCSI;
5344 sctl.controllerType = StorageControllerType_VirtioSCSI;
5345 }
5346 else
5347 throw ConfigFileError(this, pelmController, N_("Invalid value '%s' for StorageController/@type attribute"), strType.c_str());
5348
5349 readStorageControllerAttributes(*pelmController, sctl);
5350
5351 xml::NodesLoop nlAttached(*pelmController, "AttachedDevice");
5352 const xml::ElementNode *pelmAttached;
5353 while ((pelmAttached = nlAttached.forAllNodes()))
5354 {
5355 AttachedDevice att;
5356 Utf8Str strTemp;
5357 pelmAttached->getAttributeValue("type", strTemp);
5358
5359 att.fDiscard = false;
5360 att.fNonRotational = false;
5361 att.fHotPluggable = false;
5362 att.fPassThrough = false;
5363
5364 if (strTemp == "HardDisk")
5365 {
5366 att.deviceType = DeviceType_HardDisk;
5367 pelmAttached->getAttributeValue("nonrotational", att.fNonRotational);
5368 pelmAttached->getAttributeValue("discard", att.fDiscard);
5369 }
5370 else if (m->sv >= SettingsVersion_v1_9)
5371 {
5372 // starting with 1.9 we list DVD and floppy drive info + attachments under <StorageControllers>
5373 if (strTemp == "DVD")
5374 {
5375 att.deviceType = DeviceType_DVD;
5376 pelmAttached->getAttributeValue("passthrough", att.fPassThrough);
5377 pelmAttached->getAttributeValue("tempeject", att.fTempEject);
5378 }
5379 else if (strTemp == "Floppy")
5380 att.deviceType = DeviceType_Floppy;
5381 }
5382
5383 if (att.deviceType != DeviceType_Null)
5384 {
5385 const xml::ElementNode *pelmImage;
5386 // all types can have images attached, but for HardDisk it's required
5387 if (!(pelmImage = pelmAttached->findChildElement("Image")))
5388 {
5389 if (att.deviceType == DeviceType_HardDisk)
5390 throw ConfigFileError(this, pelmImage, N_("Required AttachedDevice/Image element is missing"));
5391 else
5392 {
5393 // DVDs and floppies can also have <HostDrive> instead of <Image>
5394 const xml::ElementNode *pelmHostDrive;
5395 if ((pelmHostDrive = pelmAttached->findChildElement("HostDrive")))
5396 if (!pelmHostDrive->getAttributeValue("src", att.strHostDriveSrc))
5397 throw ConfigFileError(this, pelmHostDrive, N_("Required AttachedDevice/HostDrive/@src attribute is missing"));
5398 }
5399 }
5400 else
5401 {
5402 if (!pelmImage->getAttributeValue("uuid", strTemp))
5403 throw ConfigFileError(this, pelmImage, N_("Required AttachedDevice/Image/@uuid attribute is missing"));
5404 parseUUID(att.uuid, strTemp, pelmImage);
5405 }
5406
5407 if (!pelmAttached->getAttributeValue("port", att.lPort))
5408 throw ConfigFileError(this, pelmImage, N_("Required AttachedDevice/@port attribute is missing"));
5409 if (!pelmAttached->getAttributeValue("device", att.lDevice))
5410 throw ConfigFileError(this, pelmImage, N_("Required AttachedDevice/@device attribute is missing"));
5411
5412 /* AHCI controller ports are hotpluggable by default, keep compatibility with existing settings. */
5413 if (m->sv >= SettingsVersion_v1_15)
5414 pelmAttached->getAttributeValue("hotpluggable", att.fHotPluggable);
5415 else if (sctl.controllerType == StorageControllerType_IntelAhci)
5416 att.fHotPluggable = true;
5417
5418 pelmAttached->getAttributeValue("bandwidthGroup", att.strBwGroup);
5419 sctl.llAttachedDevices.push_back(att);
5420 }
5421 }
5422
5423 strg.llStorageControllers.push_back(sctl);
5424 }
5425}
5426
5427/**
5428 * This gets called for legacy pre-1.9 settings files after having parsed the
5429 * \<Hardware\> and \<StorageControllers\> sections to parse \<Hardware\> once more
5430 * for the \<DVDDrive\> and \<FloppyDrive\> sections.
5431 *
5432 * Before settings version 1.9, DVD and floppy drives were specified separately
5433 * under \<Hardware\>; we then need this extra loop to make sure the storage
5434 * controller structs are already set up so we can add stuff to them.
5435 *
5436 * @param elmHardware
5437 * @param strg
5438 */
5439void MachineConfigFile::readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHardware,
5440 Storage &strg)
5441{
5442 xml::NodesLoop nl1(elmHardware);
5443 const xml::ElementNode *pelmHwChild;
5444 while ((pelmHwChild = nl1.forAllNodes()))
5445 {
5446 if (pelmHwChild->nameEquals("DVDDrive"))
5447 {
5448 // create a DVD "attached device" and attach it to the existing IDE controller
5449 AttachedDevice att;
5450 att.deviceType = DeviceType_DVD;
5451 // legacy DVD drive is always secondary master (port 1, device 0)
5452 att.lPort = 1;
5453 att.lDevice = 0;
5454 pelmHwChild->getAttributeValue("passthrough", att.fPassThrough);
5455 pelmHwChild->getAttributeValue("tempeject", att.fTempEject);
5456
5457 const xml::ElementNode *pDriveChild;
5458 Utf8Str strTmp;
5459 if ( (pDriveChild = pelmHwChild->findChildElement("Image")) != NULL
5460 && pDriveChild->getAttributeValue("uuid", strTmp))
5461 parseUUID(att.uuid, strTmp, pDriveChild);
5462 else if ((pDriveChild = pelmHwChild->findChildElement("HostDrive")))
5463 pDriveChild->getAttributeValue("src", att.strHostDriveSrc);
5464
5465 // find the IDE controller and attach the DVD drive
5466 bool fFound = false;
5467 for (StorageControllersList::iterator it = strg.llStorageControllers.begin();
5468 it != strg.llStorageControllers.end();
5469 ++it)
5470 {
5471 StorageController &sctl = *it;
5472 if (sctl.storageBus == StorageBus_IDE)
5473 {
5474 sctl.llAttachedDevices.push_back(att);
5475 fFound = true;
5476 break;
5477 }
5478 }
5479
5480 if (!fFound)
5481 throw ConfigFileError(this, pelmHwChild, N_("Internal error: found DVD drive but IDE controller does not exist"));
5482 // shouldn't happen because pre-1.9 settings files always had at least one IDE controller in the settings
5483 // which should have gotten parsed in <StorageControllers> before this got called
5484 }
5485 else if (pelmHwChild->nameEquals("FloppyDrive"))
5486 {
5487 bool fEnabled;
5488 if ( pelmHwChild->getAttributeValue("enabled", fEnabled)
5489 && fEnabled)
5490 {
5491 // create a new floppy controller and attach a floppy "attached device"
5492 StorageController sctl;
5493 sctl.strName = "Floppy Controller";
5494 sctl.storageBus = StorageBus_Floppy;
5495 sctl.controllerType = StorageControllerType_I82078;
5496 sctl.ulPortCount = 1;
5497
5498 AttachedDevice att;
5499 att.deviceType = DeviceType_Floppy;
5500 att.lPort = 0;
5501 att.lDevice = 0;
5502
5503 const xml::ElementNode *pDriveChild;
5504 Utf8Str strTmp;
5505 if ( (pDriveChild = pelmHwChild->findChildElement("Image"))
5506 && pDriveChild->getAttributeValue("uuid", strTmp) )
5507 parseUUID(att.uuid, strTmp, pDriveChild);
5508 else if ((pDriveChild = pelmHwChild->findChildElement("HostDrive")))
5509 pDriveChild->getAttributeValue("src", att.strHostDriveSrc);
5510
5511 // store attachment with controller
5512 sctl.llAttachedDevices.push_back(att);
5513 // store controller with storage
5514 strg.llStorageControllers.push_back(sctl);
5515 }
5516 }
5517 }
5518}
5519
5520/**
5521 * Called for reading the \<Teleporter\> element under \<Machine\>.
5522 */
5523void MachineConfigFile::readTeleporter(const xml::ElementNode *pElmTeleporter,
5524 MachineUserData *pUserData)
5525{
5526 pElmTeleporter->getAttributeValue("enabled", pUserData->fTeleporterEnabled);
5527 pElmTeleporter->getAttributeValue("port", pUserData->uTeleporterPort);
5528 pElmTeleporter->getAttributeValue("address", pUserData->strTeleporterAddress);
5529 pElmTeleporter->getAttributeValue("password", pUserData->strTeleporterPassword);
5530
5531 if ( pUserData->strTeleporterPassword.isNotEmpty()
5532 && !VBoxIsPasswordHashed(&pUserData->strTeleporterPassword))
5533 VBoxHashPassword(&pUserData->strTeleporterPassword);
5534}
5535
5536/**
5537 * Called for reading the \<Debugging\> element under \<Machine\> or \<Snapshot\>.
5538 */
5539void MachineConfigFile::readDebugging(const xml::ElementNode *pElmDebugging, Debugging *pDbg)
5540{
5541 if (!pElmDebugging || m->sv < SettingsVersion_v1_13)
5542 return;
5543
5544 const xml::ElementNode * const pelmTracing = pElmDebugging->findChildElement("Tracing");
5545 if (pelmTracing)
5546 {
5547 pelmTracing->getAttributeValue("enabled", pDbg->fTracingEnabled);
5548 pelmTracing->getAttributeValue("allowTracingToAccessVM", pDbg->fAllowTracingToAccessVM);
5549 pelmTracing->getAttributeValue("config", pDbg->strTracingConfig);
5550 }
5551}
5552
5553/**
5554 * Called for reading the \<Autostart\> element under \<Machine\> or \<Snapshot\>.
5555 */
5556void MachineConfigFile::readAutostart(const xml::ElementNode *pElmAutostart, Autostart *pAutostart)
5557{
5558 Utf8Str strAutostop;
5559
5560 if (!pElmAutostart || m->sv < SettingsVersion_v1_13)
5561 return;
5562
5563 pElmAutostart->getAttributeValue("enabled", pAutostart->fAutostartEnabled);
5564 pElmAutostart->getAttributeValue("delay", pAutostart->uAutostartDelay);
5565 pElmAutostart->getAttributeValue("autostop", strAutostop);
5566 if (strAutostop == "Disabled")
5567 pAutostart->enmAutostopType = AutostopType_Disabled;
5568 else if (strAutostop == "SaveState")
5569 pAutostart->enmAutostopType = AutostopType_SaveState;
5570 else if (strAutostop == "PowerOff")
5571 pAutostart->enmAutostopType = AutostopType_PowerOff;
5572 else if (strAutostop == "AcpiShutdown")
5573 pAutostart->enmAutostopType = AutostopType_AcpiShutdown;
5574 else
5575 throw ConfigFileError(this, pElmAutostart, N_("Invalid value '%s' for Autostart/@autostop attribute"), strAutostop.c_str());
5576}
5577
5578/**
5579 * Called for reading the \<Groups\> element under \<Machine\>.
5580 */
5581void MachineConfigFile::readGroups(const xml::ElementNode *pElmGroups, StringsList *pllGroups)
5582{
5583 pllGroups->clear();
5584 if (!pElmGroups || m->sv < SettingsVersion_v1_13)
5585 {
5586 pllGroups->push_back("/");
5587 return;
5588 }
5589
5590 xml::NodesLoop nlGroups(*pElmGroups);
5591 const xml::ElementNode *pelmGroup;
5592 while ((pelmGroup = nlGroups.forAllNodes()))
5593 {
5594 if (pelmGroup->nameEquals("Group"))
5595 {
5596 Utf8Str strGroup;
5597 if (!pelmGroup->getAttributeValue("name", strGroup))
5598 throw ConfigFileError(this, pelmGroup, N_("Required Group/@name attribute is missing"));
5599 pllGroups->push_back(strGroup);
5600 }
5601 }
5602}
5603
5604/**
5605 * Called initially for the \<Snapshot\> element under \<Machine\>, if present,
5606 * to store the snapshot's data into the given Snapshot structure (which is
5607 * then the one in the Machine struct). This might then recurse if
5608 * a \<Snapshots\> (plural) element is found in the snapshot, which should
5609 * contain a list of child snapshots; such lists are maintained in the
5610 * Snapshot structure.
5611 *
5612 * @param curSnapshotUuid
5613 * @param depth
5614 * @param elmSnapshot
5615 * @param snap
5616 * @returns true if curSnapshotUuid is in this snapshot subtree, otherwise false
5617 */
5618bool MachineConfigFile::readSnapshot(const Guid &curSnapshotUuid,
5619 uint32_t depth,
5620 const xml::ElementNode &elmSnapshot,
5621 Snapshot &snap)
5622{
5623 if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX)
5624 throw ConfigFileError(this, &elmSnapshot, N_("Maximum snapshot tree depth of %u exceeded"), SETTINGS_SNAPSHOT_DEPTH_MAX);
5625
5626 Utf8Str strTemp;
5627
5628 if (!elmSnapshot.getAttributeValue("uuid", strTemp))
5629 throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@uuid attribute is missing"));
5630 parseUUID(snap.uuid, strTemp, &elmSnapshot);
5631 bool foundCurrentSnapshot = (snap.uuid == curSnapshotUuid);
5632
5633 if (!elmSnapshot.getAttributeValue("name", snap.strName))
5634 throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@name attribute is missing"));
5635
5636 // 3.1 dev builds added Description as an attribute, read it silently
5637 // and write it back as an element
5638 elmSnapshot.getAttributeValue("Description", snap.strDescription);
5639
5640 if (!elmSnapshot.getAttributeValue("timeStamp", strTemp))
5641 throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@timeStamp attribute is missing"));
5642 parseTimestamp(snap.timestamp, strTemp, &elmSnapshot);
5643
5644 elmSnapshot.getAttributeValuePath("stateFile", snap.strStateFile); // online snapshots only
5645
5646 // parse Hardware before the other elements because other things depend on it
5647 const xml::ElementNode *pelmHardware;
5648 if (!(pelmHardware = elmSnapshot.findChildElement("Hardware")))
5649 throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@Hardware element is missing"));
5650 readHardware(*pelmHardware, snap.hardware);
5651
5652 xml::NodesLoop nlSnapshotChildren(elmSnapshot);
5653 const xml::ElementNode *pelmSnapshotChild;
5654 while ((pelmSnapshotChild = nlSnapshotChildren.forAllNodes()))
5655 {
5656 if (pelmSnapshotChild->nameEquals("Description"))
5657 snap.strDescription = pelmSnapshotChild->getValue();
5658 else if ( m->sv < SettingsVersion_v1_7
5659 && pelmSnapshotChild->nameEquals("HardDiskAttachments"))
5660 readHardDiskAttachments_pre1_7(*pelmSnapshotChild, snap.hardware.storage);
5661 else if ( m->sv >= SettingsVersion_v1_7
5662 && pelmSnapshotChild->nameEquals("StorageControllers"))
5663 readStorageControllers(*pelmSnapshotChild, snap.hardware.storage);
5664 else if (pelmSnapshotChild->nameEquals("Snapshots"))
5665 {
5666 xml::NodesLoop nlChildSnapshots(*pelmSnapshotChild);
5667 const xml::ElementNode *pelmChildSnapshot;
5668 while ((pelmChildSnapshot = nlChildSnapshots.forAllNodes()))
5669 {
5670 if (pelmChildSnapshot->nameEquals("Snapshot"))
5671 {
5672 // recurse with this element and put the child at the
5673 // end of the list. XPCOM has very small stack, avoid
5674 // big local variables and use the list element.
5675 snap.llChildSnapshots.push_back(Snapshot::Empty);
5676 bool found = readSnapshot(curSnapshotUuid, depth + 1, *pelmChildSnapshot, snap.llChildSnapshots.back());
5677 foundCurrentSnapshot = foundCurrentSnapshot || found;
5678 }
5679 }
5680 }
5681 }
5682
5683 if (m->sv < SettingsVersion_v1_9)
5684 // go through Hardware once more to repair the settings controller structures
5685 // with data from old DVDDrive and FloppyDrive elements
5686 readDVDAndFloppies_pre1_9(*pelmHardware, snap.hardware.storage);
5687
5688 readDebugging(elmSnapshot.findChildElement("Debugging"), &snap.debugging);
5689 readAutostart(elmSnapshot.findChildElement("Autostart"), &snap.autostart);
5690 // note: Groups exist only for Machine, not for Snapshot
5691
5692 return foundCurrentSnapshot;
5693}
5694
5695const struct {
5696 const char *pcszOld;
5697 const char *pcszNew;
5698} aConvertOSTypes[] =
5699{
5700 { "unknown", "Other" },
5701 { "dos", "DOS" },
5702 { "win31", "Windows31" },
5703 { "win95", "Windows95" },
5704 { "win98", "Windows98" },
5705 { "winme", "WindowsMe" },
5706 { "winnt4", "WindowsNT4" },
5707 { "win2k", "Windows2000" },
5708 { "winxp", "WindowsXP" },
5709 { "win2k3", "Windows2003" },
5710 { "winvista", "WindowsVista" },
5711 { "win2k8", "Windows2008" },
5712 { "os2warp3", "OS2Warp3" },
5713 { "os2warp4", "OS2Warp4" },
5714 { "os2warp45", "OS2Warp45" },
5715 { "ecs", "OS2eCS" },
5716 { "linux22", "Linux22" },
5717 { "linux24", "Linux24" },
5718 { "linux26", "Linux26" },
5719 { "archlinux", "ArchLinux" },
5720 { "debian", "Debian" },
5721 { "opensuse", "OpenSUSE" },
5722 { "fedoracore", "Fedora" },
5723 { "gentoo", "Gentoo" },
5724 { "mandriva", "Mandriva" },
5725 { "redhat", "RedHat" },
5726 { "ubuntu", "Ubuntu" },
5727 { "xandros", "Xandros" },
5728 { "freebsd", "FreeBSD" },
5729 { "openbsd", "OpenBSD" },
5730 { "netbsd", "NetBSD" },
5731 { "netware", "Netware" },
5732 { "solaris", "Solaris" },
5733 { "opensolaris", "OpenSolaris" },
5734 { "l4", "L4" }
5735};
5736
5737void MachineConfigFile::convertOldOSType_pre1_5(Utf8Str &str)
5738{
5739 for (unsigned u = 0;
5740 u < RT_ELEMENTS(aConvertOSTypes);
5741 ++u)
5742 {
5743 if (str == aConvertOSTypes[u].pcszOld)
5744 {
5745 str = aConvertOSTypes[u].pcszNew;
5746 break;
5747 }
5748 }
5749}
5750
5751/**
5752 * Called from the constructor to actually read in the \<Machine\> element
5753 * of a machine config file.
5754 * @param elmMachine
5755 */
5756void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine)
5757{
5758 Utf8Str strUUID;
5759 if ( elmMachine.getAttributeValue("uuid", strUUID)
5760 && elmMachine.getAttributeValue("name", machineUserData.strName))
5761 {
5762 parseUUID(uuid, strUUID, &elmMachine);
5763
5764 elmMachine.getAttributeValue("directoryIncludesUUID", machineUserData.fDirectoryIncludesUUID);
5765 elmMachine.getAttributeValue("nameSync", machineUserData.fNameSync);
5766
5767 Utf8Str str;
5768 elmMachine.getAttributeValue("Description", machineUserData.strDescription);
5769 elmMachine.getAttributeValue("OSType", machineUserData.strOsType);
5770 if (m->sv < SettingsVersion_v1_5)
5771 convertOldOSType_pre1_5(machineUserData.strOsType);
5772
5773 elmMachine.getAttributeValuePath("stateFile", strStateFile);
5774
5775 if (elmMachine.getAttributeValue("currentSnapshot", str))
5776 parseUUID(uuidCurrentSnapshot, str, &elmMachine);
5777
5778 elmMachine.getAttributeValuePath("snapshotFolder", machineUserData.strSnapshotFolder);
5779
5780 if (!elmMachine.getAttributeValue("currentStateModified", fCurrentStateModified))
5781 fCurrentStateModified = true;
5782 if (elmMachine.getAttributeValue("lastStateChange", str))
5783 parseTimestamp(timeLastStateChange, str, &elmMachine);
5784 // constructor has called RTTimeNow(&timeLastStateChange) before
5785 if (elmMachine.getAttributeValue("aborted", fAborted))
5786 fAborted = true;
5787
5788 {
5789 Utf8Str strVMPriority;
5790 if (elmMachine.getAttributeValue("processPriority", strVMPriority))
5791 {
5792 if (strVMPriority == "Flat")
5793 machineUserData.enmVMPriority = VMProcPriority_Flat;
5794 else if (strVMPriority == "Low")
5795 machineUserData.enmVMPriority = VMProcPriority_Low;
5796 else if (strVMPriority == "Normal")
5797 machineUserData.enmVMPriority = VMProcPriority_Normal;
5798 else if (strVMPriority == "High")
5799 machineUserData.enmVMPriority = VMProcPriority_High;
5800 else
5801 machineUserData.enmVMPriority = VMProcPriority_Default;
5802 }
5803 }
5804
5805 str.setNull();
5806 elmMachine.getAttributeValue("icon", str);
5807 parseBase64(machineUserData.ovIcon, str, &elmMachine);
5808
5809 // parse Hardware before the other elements because other things depend on it
5810 const xml::ElementNode *pelmHardware;
5811 if (!(pelmHardware = elmMachine.findChildElement("Hardware")))
5812 throw ConfigFileError(this, &elmMachine, N_("Required Machine/Hardware element is missing"));
5813 readHardware(*pelmHardware, hardwareMachine);
5814
5815 xml::NodesLoop nlRootChildren(elmMachine);
5816 const xml::ElementNode *pelmMachineChild;
5817 while ((pelmMachineChild = nlRootChildren.forAllNodes()))
5818 {
5819 if (pelmMachineChild->nameEquals("ExtraData"))
5820 readExtraData(*pelmMachineChild,
5821 mapExtraDataItems);
5822 else if ( (m->sv < SettingsVersion_v1_7)
5823 && (pelmMachineChild->nameEquals("HardDiskAttachments"))
5824 )
5825 readHardDiskAttachments_pre1_7(*pelmMachineChild, hardwareMachine.storage);
5826 else if ( (m->sv >= SettingsVersion_v1_7)
5827 && (pelmMachineChild->nameEquals("StorageControllers"))
5828 )
5829 readStorageControllers(*pelmMachineChild, hardwareMachine.storage);
5830 else if (pelmMachineChild->nameEquals("Snapshot"))
5831 {
5832 if (uuidCurrentSnapshot.isZero())
5833 throw ConfigFileError(this, &elmMachine, N_("Snapshots present but required Machine/@currentSnapshot attribute is missing"));
5834 bool foundCurrentSnapshot = false;
5835 Snapshot snap;
5836 // this will recurse into child snapshots, if necessary
5837 foundCurrentSnapshot = readSnapshot(uuidCurrentSnapshot, 1, *pelmMachineChild, snap);
5838 if (!foundCurrentSnapshot)
5839 throw ConfigFileError(this, &elmMachine, N_("Snapshots present but none matches the UUID in the Machine/@currentSnapshot attribute"));
5840 llFirstSnapshot.push_back(snap);
5841 }
5842 else if (pelmMachineChild->nameEquals("Description"))
5843 machineUserData.strDescription = pelmMachineChild->getValue();
5844 else if (pelmMachineChild->nameEquals("Teleporter"))
5845 readTeleporter(pelmMachineChild, &machineUserData);
5846 else if (pelmMachineChild->nameEquals("MediaRegistry"))
5847 readMediaRegistry(*pelmMachineChild, mediaRegistry);
5848 else if (pelmMachineChild->nameEquals("Debugging"))
5849 readDebugging(pelmMachineChild, &debugging);
5850 else if (pelmMachineChild->nameEquals("Autostart"))
5851 readAutostart(pelmMachineChild, &autostart);
5852 else if (pelmMachineChild->nameEquals("Groups"))
5853 readGroups(pelmMachineChild, &machineUserData.llGroups);
5854 }
5855
5856 if (m->sv < SettingsVersion_v1_9)
5857 // go through Hardware once more to repair the settings controller structures
5858 // with data from old DVDDrive and FloppyDrive elements
5859 readDVDAndFloppies_pre1_9(*pelmHardware, hardwareMachine.storage);
5860 }
5861 else
5862 throw ConfigFileError(this, &elmMachine, N_("Required Machine/@uuid or @name attributes is missing"));
5863}
5864
5865/**
5866 * Creates a \<Hardware\> node under elmParent and then writes out the XML
5867 * keys under that. Called for both the \<Machine\> node and for snapshots.
5868 * @param elmParent
5869 * @param hw
5870 * @param fl
5871 * @param pllElementsWithUuidAttributes
5872 */
5873void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
5874 const Hardware &hw,
5875 uint32_t fl,
5876 std::list<xml::ElementNode*> *pllElementsWithUuidAttributes)
5877{
5878 xml::ElementNode *pelmHardware = elmParent.createChild("Hardware");
5879
5880 if ( m->sv >= SettingsVersion_v1_4
5881 && (m->sv < SettingsVersion_v1_7 ? hw.strVersion != "1" : hw.strVersion != "2"))
5882 pelmHardware->setAttribute("version", hw.strVersion);
5883
5884 if ((m->sv >= SettingsVersion_v1_9)
5885 && !hw.uuid.isZero()
5886 && hw.uuid.isValid()
5887 )
5888 pelmHardware->setAttribute("uuid", hw.uuid.toStringCurly());
5889
5890 xml::ElementNode *pelmCPU = pelmHardware->createChild("CPU");
5891
5892 if (!hw.fHardwareVirt)
5893 pelmCPU->createChild("HardwareVirtEx")->setAttribute("enabled", hw.fHardwareVirt);
5894 if (!hw.fNestedPaging)
5895 pelmCPU->createChild("HardwareVirtExNestedPaging")->setAttribute("enabled", hw.fNestedPaging);
5896 if (!hw.fVPID)
5897 pelmCPU->createChild("HardwareVirtExVPID")->setAttribute("enabled", hw.fVPID);
5898 if (!hw.fUnrestrictedExecution)
5899 pelmCPU->createChild("HardwareVirtExUX")->setAttribute("enabled", hw.fUnrestrictedExecution);
5900 // PAE has too crazy default handling, must always save this setting.
5901 pelmCPU->createChild("PAE")->setAttribute("enabled", hw.fPAE);
5902 if (m->sv >= SettingsVersion_v1_16)
5903 {
5904 if (hw.fIBPBOnVMEntry || hw.fIBPBOnVMExit)
5905 {
5906 xml::ElementNode *pelmChild = pelmCPU->createChild("IBPBOn");
5907 if (hw.fIBPBOnVMExit)
5908 pelmChild->setAttribute("vmexit", hw.fIBPBOnVMExit);
5909 if (hw.fIBPBOnVMEntry)
5910 pelmChild->setAttribute("vmentry", hw.fIBPBOnVMEntry);
5911 }
5912 if (hw.fSpecCtrl)
5913 pelmCPU->createChild("SpecCtrl")->setAttribute("enabled", hw.fSpecCtrl);
5914 if (hw.fSpecCtrlByHost)
5915 pelmCPU->createChild("SpecCtrlByHost")->setAttribute("enabled", hw.fSpecCtrlByHost);
5916 if (!hw.fL1DFlushOnSched || hw.fL1DFlushOnVMEntry)
5917 {
5918 xml::ElementNode *pelmChild = pelmCPU->createChild("L1DFlushOn");
5919 if (!hw.fL1DFlushOnSched)
5920 pelmChild->setAttribute("scheduling", hw.fL1DFlushOnSched);
5921 if (hw.fL1DFlushOnVMEntry)
5922 pelmChild->setAttribute("vmentry", hw.fL1DFlushOnVMEntry);
5923 }
5924 if (!hw.fMDSClearOnSched || hw.fMDSClearOnVMEntry)
5925 {
5926 xml::ElementNode *pelmChild = pelmCPU->createChild("MDSClearOn");
5927 if (!hw.fMDSClearOnSched)
5928 pelmChild->setAttribute("scheduling", hw.fMDSClearOnSched);
5929 if (hw.fMDSClearOnVMEntry)
5930 pelmChild->setAttribute("vmentry", hw.fMDSClearOnVMEntry);
5931 }
5932 }
5933 if (m->sv >= SettingsVersion_v1_17 && hw.fNestedHWVirt)
5934 pelmCPU->createChild("NestedHWVirt")->setAttribute("enabled", hw.fNestedHWVirt);
5935
5936 if (m->sv >= SettingsVersion_v1_18 && !hw.fVirtVmsaveVmload)
5937 pelmCPU->createChild("HardwareVirtExVirtVmsaveVmload")->setAttribute("enabled", hw.fVirtVmsaveVmload);
5938
5939 if (m->sv >= SettingsVersion_v1_14 && hw.enmLongMode != Hardware::LongMode_Legacy)
5940 {
5941 // LongMode has too crazy default handling, must always save this setting.
5942 pelmCPU->createChild("LongMode")->setAttribute("enabled", hw.enmLongMode == Hardware::LongMode_Enabled);
5943 }
5944
5945 if (hw.fTripleFaultReset)
5946 pelmCPU->createChild("TripleFaultReset")->setAttribute("enabled", hw.fTripleFaultReset);
5947 if (m->sv >= SettingsVersion_v1_14)
5948 {
5949 if (hw.fX2APIC)
5950 pelmCPU->createChild("X2APIC")->setAttribute("enabled", hw.fX2APIC);
5951 else if (!hw.fAPIC)
5952 pelmCPU->createChild("APIC")->setAttribute("enabled", hw.fAPIC);
5953 }
5954 if (hw.cCPUs > 1)
5955 pelmCPU->setAttribute("count", hw.cCPUs);
5956 if (hw.ulCpuExecutionCap != 100)
5957 pelmCPU->setAttribute("executionCap", hw.ulCpuExecutionCap);
5958 if (hw.uCpuIdPortabilityLevel != 0)
5959 pelmCPU->setAttribute("CpuIdPortabilityLevel", hw.uCpuIdPortabilityLevel);
5960 if (!hw.strCpuProfile.equals("host") && hw.strCpuProfile.isNotEmpty())
5961 pelmCPU->setAttribute("CpuProfile", hw.strCpuProfile);
5962
5963 // HardwareVirtExLargePages has too crazy default handling, must always save this setting.
5964 pelmCPU->createChild("HardwareVirtExLargePages")->setAttribute("enabled", hw.fLargePages);
5965
5966 if (m->sv >= SettingsVersion_v1_9)
5967 {
5968 if (hw.fHardwareVirtForce)
5969 pelmCPU->createChild("HardwareVirtForce")->setAttribute("enabled", hw.fHardwareVirtForce);
5970 }
5971
5972 if (m->sv >= SettingsVersion_v1_9 && hw.fUseNativeApi)
5973 pelmCPU->createChild("HardwareVirtExUseNativeApi")->setAttribute("enabled", hw.fUseNativeApi);
5974
5975 if (m->sv >= SettingsVersion_v1_10)
5976 {
5977 if (hw.fCpuHotPlug)
5978 pelmCPU->setAttribute("hotplug", hw.fCpuHotPlug);
5979
5980 xml::ElementNode *pelmCpuTree = NULL;
5981 for (CpuList::const_iterator it = hw.llCpus.begin();
5982 it != hw.llCpus.end();
5983 ++it)
5984 {
5985 const Cpu &cpu = *it;
5986
5987 if (pelmCpuTree == NULL)
5988 pelmCpuTree = pelmCPU->createChild("CpuTree");
5989
5990 xml::ElementNode *pelmCpu = pelmCpuTree->createChild("Cpu");
5991 pelmCpu->setAttribute("id", cpu.ulId);
5992 }
5993 }
5994
5995 xml::ElementNode *pelmCpuIdTree = NULL;
5996 for (CpuIdLeafsList::const_iterator it = hw.llCpuIdLeafs.begin();
5997 it != hw.llCpuIdLeafs.end();
5998 ++it)
5999 {
6000 const CpuIdLeaf &leaf = *it;
6001
6002 if (pelmCpuIdTree == NULL)
6003 pelmCpuIdTree = pelmCPU->createChild("CpuIdTree");
6004
6005 xml::ElementNode *pelmCpuIdLeaf = pelmCpuIdTree->createChild("CpuIdLeaf");
6006 pelmCpuIdLeaf->setAttribute("id", leaf.idx);
6007 if (leaf.idxSub != 0)
6008 pelmCpuIdLeaf->setAttribute("subleaf", leaf.idxSub);
6009 pelmCpuIdLeaf->setAttribute("eax", leaf.uEax);
6010 pelmCpuIdLeaf->setAttribute("ebx", leaf.uEbx);
6011 pelmCpuIdLeaf->setAttribute("ecx", leaf.uEcx);
6012 pelmCpuIdLeaf->setAttribute("edx", leaf.uEdx);
6013 }
6014
6015 xml::ElementNode *pelmMemory = pelmHardware->createChild("Memory");
6016 pelmMemory->setAttribute("RAMSize", hw.ulMemorySizeMB);
6017 if (m->sv >= SettingsVersion_v1_10)
6018 {
6019 if (hw.fPageFusionEnabled)
6020 pelmMemory->setAttribute("PageFusion", hw.fPageFusionEnabled);
6021 }
6022
6023 if ( (m->sv >= SettingsVersion_v1_9)
6024 && (hw.firmwareType >= FirmwareType_EFI)
6025 )
6026 {
6027 xml::ElementNode *pelmFirmware = pelmHardware->createChild("Firmware");
6028 const char *pcszFirmware;
6029
6030 switch (hw.firmwareType)
6031 {
6032 case FirmwareType_EFI: pcszFirmware = "EFI"; break;
6033 case FirmwareType_EFI32: pcszFirmware = "EFI32"; break;
6034 case FirmwareType_EFI64: pcszFirmware = "EFI64"; break;
6035 case FirmwareType_EFIDUAL: pcszFirmware = "EFIDUAL"; break;
6036 default: pcszFirmware = "None"; break;
6037 }
6038 pelmFirmware->setAttribute("type", pcszFirmware);
6039 }
6040
6041 if ( m->sv >= SettingsVersion_v1_10
6042 && ( hw.pointingHIDType != PointingHIDType_PS2Mouse
6043 || hw.keyboardHIDType != KeyboardHIDType_PS2Keyboard))
6044 {
6045 xml::ElementNode *pelmHID = pelmHardware->createChild("HID");
6046 const char *pcszHID;
6047
6048 if (hw.pointingHIDType != PointingHIDType_PS2Mouse)
6049 {
6050 switch (hw.pointingHIDType)
6051 {
6052 case PointingHIDType_USBMouse: pcszHID = "USBMouse"; break;
6053 case PointingHIDType_USBTablet: pcszHID = "USBTablet"; break;
6054 case PointingHIDType_PS2Mouse: pcszHID = "PS2Mouse"; break;
6055 case PointingHIDType_ComboMouse: pcszHID = "ComboMouse"; break;
6056 case PointingHIDType_USBMultiTouch: pcszHID = "USBMultiTouch";break;
6057 case PointingHIDType_None: pcszHID = "None"; break;
6058 default: Assert(false); pcszHID = "PS2Mouse"; break;
6059 }
6060 pelmHID->setAttribute("Pointing", pcszHID);
6061 }
6062
6063 if (hw.keyboardHIDType != KeyboardHIDType_PS2Keyboard)
6064 {
6065 switch (hw.keyboardHIDType)
6066 {
6067 case KeyboardHIDType_USBKeyboard: pcszHID = "USBKeyboard"; break;
6068 case KeyboardHIDType_PS2Keyboard: pcszHID = "PS2Keyboard"; break;
6069 case KeyboardHIDType_ComboKeyboard: pcszHID = "ComboKeyboard"; break;
6070 case KeyboardHIDType_None: pcszHID = "None"; break;
6071 default: Assert(false); pcszHID = "PS2Keyboard"; break;
6072 }
6073 pelmHID->setAttribute("Keyboard", pcszHID);
6074 }
6075 }
6076
6077 if ( (m->sv >= SettingsVersion_v1_10)
6078 && hw.fHPETEnabled
6079 )
6080 {
6081 xml::ElementNode *pelmHPET = pelmHardware->createChild("HPET");
6082 pelmHPET->setAttribute("enabled", hw.fHPETEnabled);
6083 }
6084
6085 if ( (m->sv >= SettingsVersion_v1_11)
6086 )
6087 {
6088 if (hw.chipsetType != ChipsetType_PIIX3)
6089 {
6090 xml::ElementNode *pelmChipset = pelmHardware->createChild("Chipset");
6091 const char *pcszChipset;
6092
6093 switch (hw.chipsetType)
6094 {
6095 case ChipsetType_PIIX3: pcszChipset = "PIIX3"; break;
6096 case ChipsetType_ICH9: pcszChipset = "ICH9"; break;
6097 default: Assert(false); pcszChipset = "PIIX3"; break;
6098 }
6099 pelmChipset->setAttribute("type", pcszChipset);
6100 }
6101 }
6102
6103 if ( (m->sv >= SettingsVersion_v1_15)
6104 && !hw.areParavirtDefaultSettings(m->sv)
6105 )
6106 {
6107 const char *pcszParavirtProvider;
6108 switch (hw.paravirtProvider)
6109 {
6110 case ParavirtProvider_None: pcszParavirtProvider = "None"; break;
6111 case ParavirtProvider_Default: pcszParavirtProvider = "Default"; break;
6112 case ParavirtProvider_Legacy: pcszParavirtProvider = "Legacy"; break;
6113 case ParavirtProvider_Minimal: pcszParavirtProvider = "Minimal"; break;
6114 case ParavirtProvider_HyperV: pcszParavirtProvider = "HyperV"; break;
6115 case ParavirtProvider_KVM: pcszParavirtProvider = "KVM"; break;
6116 default: Assert(false); pcszParavirtProvider = "None"; break;
6117 }
6118
6119 xml::ElementNode *pelmParavirt = pelmHardware->createChild("Paravirt");
6120 pelmParavirt->setAttribute("provider", pcszParavirtProvider);
6121
6122 if ( m->sv >= SettingsVersion_v1_16
6123 && hw.strParavirtDebug.isNotEmpty())
6124 pelmParavirt->setAttribute("debug", hw.strParavirtDebug);
6125 }
6126
6127 if ( m->sv >= SettingsVersion_v1_19
6128 && hw.iommuType != IommuType_None)
6129 {
6130 const char *pcszIommuType;
6131 switch (hw.iommuType)
6132 {
6133 case IommuType_None: pcszIommuType = "None"; break;
6134 case IommuType_Automatic: pcszIommuType = "Automatic"; break;
6135 case IommuType_AMD: pcszIommuType = "AMD"; break;
6136 case IommuType_Intel: pcszIommuType = "Intel"; break;
6137 default: Assert(false); pcszIommuType = "None"; break;
6138 }
6139
6140 xml::ElementNode *pelmIommu = pelmHardware->createChild("Iommu");
6141 pelmIommu->setAttribute("type", pcszIommuType);
6142 }
6143
6144 if (!hw.areBootOrderDefaultSettings())
6145 {
6146 xml::ElementNode *pelmBoot = pelmHardware->createChild("Boot");
6147 for (BootOrderMap::const_iterator it = hw.mapBootOrder.begin();
6148 it != hw.mapBootOrder.end();
6149 ++it)
6150 {
6151 uint32_t i = it->first;
6152 DeviceType_T type = it->second;
6153 const char *pcszDevice;
6154
6155 switch (type)
6156 {
6157 case DeviceType_Floppy: pcszDevice = "Floppy"; break;
6158 case DeviceType_DVD: pcszDevice = "DVD"; break;
6159 case DeviceType_HardDisk: pcszDevice = "HardDisk"; break;
6160 case DeviceType_Network: pcszDevice = "Network"; break;
6161 default: /*case DeviceType_Null:*/ pcszDevice = "None"; break;
6162 }
6163
6164 xml::ElementNode *pelmOrder = pelmBoot->createChild("Order");
6165 pelmOrder->setAttribute("position",
6166 i + 1); // XML is 1-based but internal data is 0-based
6167 pelmOrder->setAttribute("device", pcszDevice);
6168 }
6169 }
6170
6171 if (!hw.graphicsAdapter.areDefaultSettings())
6172 {
6173 xml::ElementNode *pelmDisplay = pelmHardware->createChild("Display");
6174 if (hw.graphicsAdapter.graphicsControllerType != GraphicsControllerType_VBoxVGA)
6175 {
6176 const char *pcszGraphics;
6177 switch (hw.graphicsAdapter.graphicsControllerType)
6178 {
6179 case GraphicsControllerType_VBoxVGA: pcszGraphics = "VBoxVGA"; break;
6180 case GraphicsControllerType_VMSVGA: pcszGraphics = "VMSVGA"; break;
6181 case GraphicsControllerType_VBoxSVGA: pcszGraphics = "VBoxSVGA"; break;
6182 default: /*case GraphicsControllerType_Null:*/ pcszGraphics = "None"; break;
6183 }
6184 pelmDisplay->setAttribute("controller", pcszGraphics);
6185 }
6186 if (hw.graphicsAdapter.ulVRAMSizeMB != 8)
6187 pelmDisplay->setAttribute("VRAMSize", hw.graphicsAdapter.ulVRAMSizeMB);
6188 if (hw.graphicsAdapter.cMonitors > 1)
6189 pelmDisplay->setAttribute("monitorCount", hw.graphicsAdapter.cMonitors);
6190 if (hw.graphicsAdapter.fAccelerate3D)
6191 pelmDisplay->setAttribute("accelerate3D", hw.graphicsAdapter.fAccelerate3D);
6192
6193 if (m->sv >= SettingsVersion_v1_8)
6194 {
6195 if (hw.graphicsAdapter.fAccelerate2DVideo)
6196 pelmDisplay->setAttribute("accelerate2DVideo", hw.graphicsAdapter.fAccelerate2DVideo);
6197 }
6198 }
6199
6200 if (m->sv >= SettingsVersion_v1_14 && !hw.recordingSettings.areDefaultSettings())
6201 {
6202 xml::ElementNode *pelmVideoCapture = pelmHardware->createChild("VideoCapture");
6203
6204 if (hw.recordingSettings.fEnabled)
6205 pelmVideoCapture->setAttribute("enabled", hw.recordingSettings.fEnabled);
6206
6207 /* Right now I don't want to bump the settings version, so just convert the enabled
6208 * screens to the former uint64t_t bit array and vice versa. */
6209 uint64_t u64VideoCaptureScreens = 0;
6210 RecordingScreenMap::const_iterator itScreen = hw.recordingSettings.mapScreens.begin();
6211 while (itScreen != hw.recordingSettings.mapScreens.end())
6212 {
6213 if (itScreen->second.fEnabled)
6214 u64VideoCaptureScreens |= RT_BIT_64(itScreen->first);
6215 ++itScreen;
6216 }
6217
6218 if (u64VideoCaptureScreens)
6219 pelmVideoCapture->setAttribute("screens", u64VideoCaptureScreens);
6220
6221 /* At the moment we only support one capturing configuration, that is, all screens
6222 * have the same configuration. So load/save to/from screen 0. */
6223 Assert(hw.recordingSettings.mapScreens.size());
6224 const RecordingScreenMap::const_iterator itScreen0Settings = hw.recordingSettings.mapScreens.find(0);
6225 Assert(itScreen0Settings != hw.recordingSettings.mapScreens.end());
6226
6227 if (itScreen0Settings->second.ulMaxTimeS)
6228 pelmVideoCapture->setAttribute("maxTime", itScreen0Settings->second.ulMaxTimeS);
6229 if (itScreen0Settings->second.strOptions.isNotEmpty())
6230 pelmVideoCapture->setAttributePath("options", itScreen0Settings->second.strOptions);
6231
6232 if (!itScreen0Settings->second.File.strName.isEmpty())
6233 pelmVideoCapture->setAttributePath("file", itScreen0Settings->second.File.strName);
6234 if (itScreen0Settings->second.File.ulMaxSizeMB)
6235 pelmVideoCapture->setAttribute("maxSize", itScreen0Settings->second.File.ulMaxSizeMB);
6236
6237 if ( itScreen0Settings->second.Video.ulWidth != 1024
6238 || itScreen0Settings->second.Video.ulHeight != 768)
6239 {
6240 pelmVideoCapture->setAttribute("horzRes", itScreen0Settings->second.Video.ulWidth);
6241 pelmVideoCapture->setAttribute("vertRes", itScreen0Settings->second.Video.ulHeight);
6242 }
6243 if (itScreen0Settings->second.Video.ulRate != 512)
6244 pelmVideoCapture->setAttribute("rate", itScreen0Settings->second.Video.ulRate);
6245 if (itScreen0Settings->second.Video.ulFPS)
6246 pelmVideoCapture->setAttribute("fps", itScreen0Settings->second.Video.ulFPS);
6247 }
6248
6249 if (!hw.vrdeSettings.areDefaultSettings(m->sv))
6250 {
6251 xml::ElementNode *pelmVRDE = pelmHardware->createChild("RemoteDisplay");
6252 if (m->sv < SettingsVersion_v1_16 ? !hw.vrdeSettings.fEnabled : hw.vrdeSettings.fEnabled)
6253 pelmVRDE->setAttribute("enabled", hw.vrdeSettings.fEnabled);
6254 if (m->sv < SettingsVersion_v1_11)
6255 {
6256 /* In VBox 4.0 these attributes are replaced with "Properties". */
6257 Utf8Str strPort;
6258 StringsMap::const_iterator it = hw.vrdeSettings.mapProperties.find("TCP/Ports");
6259 if (it != hw.vrdeSettings.mapProperties.end())
6260 strPort = it->second;
6261 if (!strPort.length())
6262 strPort = "3389";
6263 pelmVRDE->setAttribute("port", strPort);
6264
6265 Utf8Str strAddress;
6266 it = hw.vrdeSettings.mapProperties.find("TCP/Address");
6267 if (it != hw.vrdeSettings.mapProperties.end())
6268 strAddress = it->second;
6269 if (strAddress.length())
6270 pelmVRDE->setAttribute("netAddress", strAddress);
6271 }
6272 if (hw.vrdeSettings.authType != AuthType_Null)
6273 {
6274 const char *pcszAuthType;
6275 switch (hw.vrdeSettings.authType)
6276 {
6277 case AuthType_Guest: pcszAuthType = "Guest"; break;
6278 case AuthType_External: pcszAuthType = "External"; break;
6279 default: /*case AuthType_Null:*/ pcszAuthType = "Null"; break;
6280 }
6281 pelmVRDE->setAttribute("authType", pcszAuthType);
6282 }
6283
6284 if (hw.vrdeSettings.ulAuthTimeout != 0 && hw.vrdeSettings.ulAuthTimeout != 5000)
6285 pelmVRDE->setAttribute("authTimeout", hw.vrdeSettings.ulAuthTimeout);
6286 if (hw.vrdeSettings.fAllowMultiConnection)
6287 pelmVRDE->setAttribute("allowMultiConnection", hw.vrdeSettings.fAllowMultiConnection);
6288 if (hw.vrdeSettings.fReuseSingleConnection)
6289 pelmVRDE->setAttribute("reuseSingleConnection", hw.vrdeSettings.fReuseSingleConnection);
6290
6291 if (m->sv == SettingsVersion_v1_10)
6292 {
6293 xml::ElementNode *pelmVideoChannel = pelmVRDE->createChild("VideoChannel");
6294
6295 /* In 4.0 videochannel settings were replaced with properties, so look at properties. */
6296 Utf8Str str;
6297 StringsMap::const_iterator it = hw.vrdeSettings.mapProperties.find("VideoChannel/Enabled");
6298 if (it != hw.vrdeSettings.mapProperties.end())
6299 str = it->second;
6300 bool fVideoChannel = RTStrICmp(str.c_str(), "true") == 0
6301 || RTStrCmp(str.c_str(), "1") == 0;
6302 pelmVideoChannel->setAttribute("enabled", fVideoChannel);
6303
6304 it = hw.vrdeSettings.mapProperties.find("VideoChannel/Quality");
6305 if (it != hw.vrdeSettings.mapProperties.end())
6306 str = it->second;
6307 uint32_t ulVideoChannelQuality = RTStrToUInt32(str.c_str()); /* This returns 0 on invalid string which is ok. */
6308 if (ulVideoChannelQuality == 0)
6309 ulVideoChannelQuality = 75;
6310 else
6311 ulVideoChannelQuality = RT_CLAMP(ulVideoChannelQuality, 10, 100);
6312 pelmVideoChannel->setAttribute("quality", ulVideoChannelQuality);
6313 }
6314 if (m->sv >= SettingsVersion_v1_11)
6315 {
6316 if (hw.vrdeSettings.strAuthLibrary.length())
6317 pelmVRDE->setAttribute("authLibrary", hw.vrdeSettings.strAuthLibrary);
6318 if (hw.vrdeSettings.strVrdeExtPack.isNotEmpty())
6319 pelmVRDE->setAttribute("VRDEExtPack", hw.vrdeSettings.strVrdeExtPack);
6320 if (hw.vrdeSettings.mapProperties.size() > 0)
6321 {
6322 xml::ElementNode *pelmProperties = pelmVRDE->createChild("VRDEProperties");
6323 for (StringsMap::const_iterator it = hw.vrdeSettings.mapProperties.begin();
6324 it != hw.vrdeSettings.mapProperties.end();
6325 ++it)
6326 {
6327 const Utf8Str &strName = it->first;
6328 const Utf8Str &strValue = it->second;
6329 xml::ElementNode *pelm = pelmProperties->createChild("Property");
6330 pelm->setAttribute("name", strName);
6331 pelm->setAttribute("value", strValue);
6332 }
6333 }
6334 }
6335 }
6336
6337 if (!hw.biosSettings.areDefaultSettings())
6338 {
6339 xml::ElementNode *pelmBIOS = pelmHardware->createChild("BIOS");
6340 if (!hw.biosSettings.fACPIEnabled)
6341 pelmBIOS->createChild("ACPI")->setAttribute("enabled", hw.biosSettings.fACPIEnabled);
6342 if (hw.biosSettings.fIOAPICEnabled)
6343 pelmBIOS->createChild("IOAPIC")->setAttribute("enabled", hw.biosSettings.fIOAPICEnabled);
6344 if (hw.biosSettings.apicMode != APICMode_APIC)
6345 {
6346 const char *pcszAPIC;
6347 switch (hw.biosSettings.apicMode)
6348 {
6349 case APICMode_Disabled:
6350 pcszAPIC = "Disabled";
6351 break;
6352 case APICMode_APIC:
6353 default:
6354 pcszAPIC = "APIC";
6355 break;
6356 case APICMode_X2APIC:
6357 pcszAPIC = "X2APIC";
6358 break;
6359 }
6360 pelmBIOS->createChild("APIC")->setAttribute("mode", pcszAPIC);
6361 }
6362
6363 if ( !hw.biosSettings.fLogoFadeIn
6364 || !hw.biosSettings.fLogoFadeOut
6365 || hw.biosSettings.ulLogoDisplayTime
6366 || !hw.biosSettings.strLogoImagePath.isEmpty())
6367 {
6368 xml::ElementNode *pelmLogo = pelmBIOS->createChild("Logo");
6369 pelmLogo->setAttribute("fadeIn", hw.biosSettings.fLogoFadeIn);
6370 pelmLogo->setAttribute("fadeOut", hw.biosSettings.fLogoFadeOut);
6371 pelmLogo->setAttribute("displayTime", hw.biosSettings.ulLogoDisplayTime);
6372 if (!hw.biosSettings.strLogoImagePath.isEmpty())
6373 pelmLogo->setAttribute("imagePath", hw.biosSettings.strLogoImagePath);
6374 }
6375
6376 if (hw.biosSettings.biosBootMenuMode != BIOSBootMenuMode_MessageAndMenu)
6377 {
6378 const char *pcszBootMenu;
6379 switch (hw.biosSettings.biosBootMenuMode)
6380 {
6381 case BIOSBootMenuMode_Disabled: pcszBootMenu = "Disabled"; break;
6382 case BIOSBootMenuMode_MenuOnly: pcszBootMenu = "MenuOnly"; break;
6383 default: /*BIOSBootMenuMode_MessageAndMenu*/ pcszBootMenu = "MessageAndMenu"; break;
6384 }
6385 pelmBIOS->createChild("BootMenu")->setAttribute("mode", pcszBootMenu);
6386 }
6387 if (hw.biosSettings.llTimeOffset)
6388 pelmBIOS->createChild("TimeOffset")->setAttribute("value", hw.biosSettings.llTimeOffset);
6389 if (hw.biosSettings.fPXEDebugEnabled)
6390 pelmBIOS->createChild("PXEDebug")->setAttribute("enabled", hw.biosSettings.fPXEDebugEnabled);
6391 if (!hw.biosSettings.strNVRAMPath.isEmpty())
6392 pelmBIOS->createChild("NVRAM")->setAttribute("path", hw.biosSettings.strNVRAMPath);
6393 if (hw.biosSettings.fSmbiosUuidLittleEndian)
6394 pelmBIOS->createChild("SmbiosUuidLittleEndian")->setAttribute("enabled", hw.biosSettings.fSmbiosUuidLittleEndian);
6395 }
6396
6397 if (m->sv < SettingsVersion_v1_9)
6398 {
6399 // settings formats before 1.9 had separate DVDDrive and FloppyDrive items under Hardware;
6400 // run thru the storage controllers to see if we have a DVD or floppy drives
6401 size_t cDVDs = 0;
6402 size_t cFloppies = 0;
6403
6404 xml::ElementNode *pelmDVD = pelmHardware->createChild("DVDDrive");
6405 xml::ElementNode *pelmFloppy = pelmHardware->createChild("FloppyDrive");
6406
6407 for (StorageControllersList::const_iterator it = hw.storage.llStorageControllers.begin();
6408 it != hw.storage.llStorageControllers.end();
6409 ++it)
6410 {
6411 const StorageController &sctl = *it;
6412 // in old settings format, the DVD drive could only have been under the IDE controller
6413 if (sctl.storageBus == StorageBus_IDE)
6414 {
6415 for (AttachedDevicesList::const_iterator it2 = sctl.llAttachedDevices.begin();
6416 it2 != sctl.llAttachedDevices.end();
6417 ++it2)
6418 {
6419 const AttachedDevice &att = *it2;
6420 if (att.deviceType == DeviceType_DVD)
6421 {
6422 if (cDVDs > 0)
6423 throw ConfigFileError(this, NULL, N_("Internal error: cannot save more than one DVD drive with old settings format"));
6424
6425 ++cDVDs;
6426
6427 pelmDVD->setAttribute("passthrough", att.fPassThrough);
6428 if (att.fTempEject)
6429 pelmDVD->setAttribute("tempeject", att.fTempEject);
6430
6431 if (!att.uuid.isZero() && att.uuid.isValid())
6432 pelmDVD->createChild("Image")->setAttribute("uuid", att.uuid.toStringCurly());
6433 else if (att.strHostDriveSrc.length())
6434 pelmDVD->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc);
6435 }
6436 }
6437 }
6438 else if (sctl.storageBus == StorageBus_Floppy)
6439 {
6440 size_t cFloppiesHere = sctl.llAttachedDevices.size();
6441 if (cFloppiesHere > 1)
6442 throw ConfigFileError(this, NULL, N_("Internal error: floppy controller cannot have more than one device attachment"));
6443 if (cFloppiesHere)
6444 {
6445 const AttachedDevice &att = sctl.llAttachedDevices.front();
6446 pelmFloppy->setAttribute("enabled", true);
6447
6448 if (!att.uuid.isZero() && att.uuid.isValid())
6449 pelmFloppy->createChild("Image")->setAttribute("uuid", att.uuid.toStringCurly());
6450 else if (att.strHostDriveSrc.length())
6451 pelmFloppy->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc);
6452 }
6453
6454 cFloppies += cFloppiesHere;
6455 }
6456 }
6457
6458 if (cFloppies == 0)
6459 pelmFloppy->setAttribute("enabled", false);
6460 else if (cFloppies > 1)
6461 throw ConfigFileError(this, NULL, N_("Internal error: cannot save more than one floppy drive with old settings format"));
6462 }
6463
6464 if (m->sv < SettingsVersion_v1_14)
6465 {
6466 bool fOhciEnabled = false;
6467 bool fEhciEnabled = false;
6468 xml::ElementNode *pelmUSB = pelmHardware->createChild("USBController");
6469
6470 for (USBControllerList::const_iterator it = hw.usbSettings.llUSBControllers.begin();
6471 it != hw.usbSettings.llUSBControllers.end();
6472 ++it)
6473 {
6474 const USBController &ctrl = *it;
6475
6476 switch (ctrl.enmType)
6477 {
6478 case USBControllerType_OHCI:
6479 fOhciEnabled = true;
6480 break;
6481 case USBControllerType_EHCI:
6482 fEhciEnabled = true;
6483 break;
6484 default:
6485 AssertMsgFailed(("Unknown USB controller type %d\n", ctrl.enmType));
6486 }
6487 }
6488
6489 pelmUSB->setAttribute("enabled", fOhciEnabled);
6490 pelmUSB->setAttribute("enabledEhci", fEhciEnabled);
6491
6492 buildUSBDeviceFilters(*pelmUSB, hw.usbSettings.llDeviceFilters, false /* fHostMode */);
6493 }
6494 else
6495 {
6496 if ( hw.usbSettings.llUSBControllers.size()
6497 || hw.usbSettings.llDeviceFilters.size())
6498 {
6499 xml::ElementNode *pelmUSB = pelmHardware->createChild("USB");
6500 if (hw.usbSettings.llUSBControllers.size())
6501 {
6502 xml::ElementNode *pelmCtrls = pelmUSB->createChild("Controllers");
6503
6504 for (USBControllerList::const_iterator it = hw.usbSettings.llUSBControllers.begin();
6505 it != hw.usbSettings.llUSBControllers.end();
6506 ++it)
6507 {
6508 const USBController &ctrl = *it;
6509 com::Utf8Str strType;
6510 xml::ElementNode *pelmCtrl = pelmCtrls->createChild("Controller");
6511
6512 switch (ctrl.enmType)
6513 {
6514 case USBControllerType_OHCI:
6515 strType = "OHCI";
6516 break;
6517 case USBControllerType_EHCI:
6518 strType = "EHCI";
6519 break;
6520 case USBControllerType_XHCI:
6521 strType = "XHCI";
6522 break;
6523 default:
6524 AssertMsgFailed(("Unknown USB controller type %d\n", ctrl.enmType));
6525 }
6526
6527 pelmCtrl->setAttribute("name", ctrl.strName);
6528 pelmCtrl->setAttribute("type", strType);
6529 }
6530 }
6531
6532 if (hw.usbSettings.llDeviceFilters.size())
6533 {
6534 xml::ElementNode *pelmFilters = pelmUSB->createChild("DeviceFilters");
6535 buildUSBDeviceFilters(*pelmFilters, hw.usbSettings.llDeviceFilters, false /* fHostMode */);
6536 }
6537 }
6538 }
6539
6540 if ( hw.llNetworkAdapters.size()
6541 && !hw.areAllNetworkAdaptersDefaultSettings(m->sv))
6542 {
6543 xml::ElementNode *pelmNetwork = pelmHardware->createChild("Network");
6544 for (NetworkAdaptersList::const_iterator it = hw.llNetworkAdapters.begin();
6545 it != hw.llNetworkAdapters.end();
6546 ++it)
6547 {
6548 const NetworkAdapter &nic = *it;
6549
6550 if (!nic.areDefaultSettings(m->sv))
6551 {
6552 xml::ElementNode *pelmAdapter = pelmNetwork->createChild("Adapter");
6553 pelmAdapter->setAttribute("slot", nic.ulSlot);
6554 if (nic.fEnabled)
6555 pelmAdapter->setAttribute("enabled", nic.fEnabled);
6556 if (!nic.strMACAddress.isEmpty())
6557 pelmAdapter->setAttribute("MACAddress", nic.strMACAddress);
6558 if ( (m->sv >= SettingsVersion_v1_16 && !nic.fCableConnected)
6559 || (m->sv < SettingsVersion_v1_16 && nic.fCableConnected))
6560 pelmAdapter->setAttribute("cable", nic.fCableConnected);
6561 if (nic.ulLineSpeed)
6562 pelmAdapter->setAttribute("speed", nic.ulLineSpeed);
6563 if (nic.ulBootPriority != 0)
6564 pelmAdapter->setAttribute("bootPriority", nic.ulBootPriority);
6565 if (nic.fTraceEnabled)
6566 {
6567 pelmAdapter->setAttribute("trace", nic.fTraceEnabled);
6568 pelmAdapter->setAttribute("tracefile", nic.strTraceFile);
6569 }
6570 if (nic.strBandwidthGroup.isNotEmpty())
6571 pelmAdapter->setAttribute("bandwidthGroup", nic.strBandwidthGroup);
6572
6573 const char *pszPolicy;
6574 switch (nic.enmPromiscModePolicy)
6575 {
6576 case NetworkAdapterPromiscModePolicy_Deny: pszPolicy = NULL; break;
6577 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPolicy = "AllowNetwork"; break;
6578 case NetworkAdapterPromiscModePolicy_AllowAll: pszPolicy = "AllowAll"; break;
6579 default: pszPolicy = NULL; AssertFailed(); break;
6580 }
6581 if (pszPolicy)
6582 pelmAdapter->setAttribute("promiscuousModePolicy", pszPolicy);
6583
6584 if ( (m->sv >= SettingsVersion_v1_16 && nic.type != NetworkAdapterType_Am79C973)
6585 || (m->sv < SettingsVersion_v1_16 && nic.type != NetworkAdapterType_Am79C970A))
6586 {
6587 const char *pcszType;
6588 switch (nic.type)
6589 {
6590 case NetworkAdapterType_Am79C973: pcszType = "Am79C973"; break;
6591 case NetworkAdapterType_Am79C960: pcszType = "Am79C960"; break;
6592 case NetworkAdapterType_I82540EM: pcszType = "82540EM"; break;
6593 case NetworkAdapterType_I82543GC: pcszType = "82543GC"; break;
6594 case NetworkAdapterType_I82545EM: pcszType = "82545EM"; break;
6595 case NetworkAdapterType_Virtio: pcszType = "virtio"; break;
6596 case NetworkAdapterType_Virtio_1_0: pcszType = "virtio_1.0"; break;
6597 default: /*case NetworkAdapterType_Am79C970A:*/ pcszType = "Am79C970A"; break;
6598 }
6599 pelmAdapter->setAttribute("type", pcszType);
6600 }
6601
6602 xml::ElementNode *pelmNAT;
6603 if (m->sv < SettingsVersion_v1_10)
6604 {
6605 switch (nic.mode)
6606 {
6607 case NetworkAttachmentType_NAT:
6608 pelmNAT = pelmAdapter->createChild("NAT");
6609 if (nic.nat.strNetwork.length())
6610 pelmNAT->setAttribute("network", nic.nat.strNetwork);
6611 break;
6612
6613 case NetworkAttachmentType_Bridged:
6614 pelmAdapter->createChild("BridgedInterface")->setAttribute("name", nic.strBridgedName);
6615 break;
6616
6617 case NetworkAttachmentType_Internal:
6618 pelmAdapter->createChild("InternalNetwork")->setAttribute("name", nic.strInternalNetworkName);
6619 break;
6620
6621 case NetworkAttachmentType_HostOnly:
6622 pelmAdapter->createChild("HostOnlyInterface")->setAttribute("name", nic.strHostOnlyName);
6623 break;
6624
6625 default: /*case NetworkAttachmentType_Null:*/
6626 break;
6627 }
6628 }
6629 else
6630 {
6631 /* m->sv >= SettingsVersion_v1_10 */
6632 if (!nic.areDisabledDefaultSettings())
6633 {
6634 xml::ElementNode *pelmDisabledNode = pelmAdapter->createChild("DisabledModes");
6635 if (nic.mode != NetworkAttachmentType_NAT)
6636 buildNetworkXML(NetworkAttachmentType_NAT, false, *pelmDisabledNode, nic);
6637 if (nic.mode != NetworkAttachmentType_Bridged)
6638 buildNetworkXML(NetworkAttachmentType_Bridged, false, *pelmDisabledNode, nic);
6639 if (nic.mode != NetworkAttachmentType_Internal)
6640 buildNetworkXML(NetworkAttachmentType_Internal, false, *pelmDisabledNode, nic);
6641 if (nic.mode != NetworkAttachmentType_HostOnly)
6642 buildNetworkXML(NetworkAttachmentType_HostOnly, false, *pelmDisabledNode, nic);
6643 if (nic.mode != NetworkAttachmentType_Generic)
6644 buildNetworkXML(NetworkAttachmentType_Generic, false, *pelmDisabledNode, nic);
6645 if (nic.mode != NetworkAttachmentType_NATNetwork)
6646 buildNetworkXML(NetworkAttachmentType_NATNetwork, false, *pelmDisabledNode, nic);
6647#ifdef VBOX_WITH_CLOUD_NET
6648 /// @todo Bump settings version!
6649 if (nic.mode != NetworkAttachmentType_Cloud)
6650 buildNetworkXML(NetworkAttachmentType_Cloud, false, *pelmDisabledNode, nic);
6651#endif /* VBOX_WITH_CLOUD_NET */
6652 }
6653 buildNetworkXML(nic.mode, true, *pelmAdapter, nic);
6654 }
6655 }
6656 }
6657 }
6658
6659 if (hw.llSerialPorts.size())
6660 {
6661 xml::ElementNode *pelmPorts = pelmHardware->createChild("UART");
6662 for (SerialPortsList::const_iterator it = hw.llSerialPorts.begin();
6663 it != hw.llSerialPorts.end();
6664 ++it)
6665 {
6666 const SerialPort &port = *it;
6667 xml::ElementNode *pelmPort = pelmPorts->createChild("Port");
6668 pelmPort->setAttribute("slot", port.ulSlot);
6669 pelmPort->setAttribute("enabled", port.fEnabled);
6670 pelmPort->setAttributeHex("IOBase", port.ulIOBase);
6671 pelmPort->setAttribute("IRQ", port.ulIRQ);
6672
6673 const char *pcszHostMode;
6674 switch (port.portMode)
6675 {
6676 case PortMode_HostPipe: pcszHostMode = "HostPipe"; break;
6677 case PortMode_HostDevice: pcszHostMode = "HostDevice"; break;
6678 case PortMode_TCP: pcszHostMode = "TCP"; break;
6679 case PortMode_RawFile: pcszHostMode = "RawFile"; break;
6680 default: /*case PortMode_Disconnected:*/ pcszHostMode = "Disconnected"; break;
6681 }
6682 switch (port.portMode)
6683 {
6684 case PortMode_TCP:
6685 case PortMode_HostPipe:
6686 pelmPort->setAttribute("server", port.fServer);
6687 RT_FALL_THRU();
6688 case PortMode_HostDevice:
6689 case PortMode_RawFile:
6690 pelmPort->setAttribute("path", port.strPath);
6691 break;
6692
6693 default:
6694 break;
6695 }
6696 pelmPort->setAttribute("hostMode", pcszHostMode);
6697
6698 if ( m->sv >= SettingsVersion_v1_17
6699 && port.uartType != UartType_U16550A)
6700 {
6701 const char *pcszUartType;
6702
6703 switch (port.uartType)
6704 {
6705 case UartType_U16450: pcszUartType = "16450"; break;
6706 case UartType_U16550A: pcszUartType = "16550A"; break;
6707 case UartType_U16750: pcszUartType = "16750"; break;
6708 default: pcszUartType = "16550A"; break;
6709 }
6710 pelmPort->setAttribute("uartType", pcszUartType);
6711 }
6712 }
6713 }
6714
6715 if (hw.llParallelPorts.size())
6716 {
6717 xml::ElementNode *pelmPorts = pelmHardware->createChild("LPT");
6718 for (ParallelPortsList::const_iterator it = hw.llParallelPorts.begin();
6719 it != hw.llParallelPorts.end();
6720 ++it)
6721 {
6722 const ParallelPort &port = *it;
6723 xml::ElementNode *pelmPort = pelmPorts->createChild("Port");
6724 pelmPort->setAttribute("slot", port.ulSlot);
6725 pelmPort->setAttribute("enabled", port.fEnabled);
6726 pelmPort->setAttributeHex("IOBase", port.ulIOBase);
6727 pelmPort->setAttribute("IRQ", port.ulIRQ);
6728 if (port.strPath.length())
6729 pelmPort->setAttribute("path", port.strPath);
6730 }
6731 }
6732
6733 /* Always write the AudioAdapter config, intentionally not checking if
6734 * the settings are at the default, because that would be problematic
6735 * for the configured host driver type, which would automatically change
6736 * if the default host driver is detected differently. */
6737 {
6738 xml::ElementNode *pelmAudio = pelmHardware->createChild("AudioAdapter");
6739
6740 const char *pcszController;
6741 switch (hw.audioAdapter.controllerType)
6742 {
6743 case AudioControllerType_SB16:
6744 pcszController = "SB16";
6745 break;
6746 case AudioControllerType_HDA:
6747 if (m->sv >= SettingsVersion_v1_11)
6748 {
6749 pcszController = "HDA";
6750 break;
6751 }
6752 RT_FALL_THRU();
6753 case AudioControllerType_AC97:
6754 default:
6755 pcszController = NULL;
6756 break;
6757 }
6758 if (pcszController)
6759 pelmAudio->setAttribute("controller", pcszController);
6760
6761 const char *pcszCodec;
6762 switch (hw.audioAdapter.codecType)
6763 {
6764 /* Only write out the setting for non-default AC'97 codec
6765 * and leave the rest alone.
6766 */
6767#if 0
6768 case AudioCodecType_SB16:
6769 pcszCodec = "SB16";
6770 break;
6771 case AudioCodecType_STAC9221:
6772 pcszCodec = "STAC9221";
6773 break;
6774 case AudioCodecType_STAC9700:
6775 pcszCodec = "STAC9700";
6776 break;
6777#endif
6778 case AudioCodecType_AD1980:
6779 pcszCodec = "AD1980";
6780 break;
6781 default:
6782 /* Don't write out anything if unknown. */
6783 pcszCodec = NULL;
6784 }
6785 if (pcszCodec)
6786 pelmAudio->setAttribute("codec", pcszCodec);
6787
6788 const char *pcszDriver;
6789 switch (hw.audioAdapter.driverType)
6790 {
6791 case AudioDriverType_WinMM: pcszDriver = "WinMM"; break;
6792 case AudioDriverType_DirectSound: pcszDriver = "DirectSound"; break;
6793 case AudioDriverType_SolAudio: pcszDriver = "SolAudio"; break;
6794 case AudioDriverType_ALSA: pcszDriver = "ALSA"; break;
6795 case AudioDriverType_Pulse: pcszDriver = "Pulse"; break;
6796 case AudioDriverType_OSS: pcszDriver = "OSS"; break;
6797 case AudioDriverType_CoreAudio: pcszDriver = "CoreAudio"; break;
6798 case AudioDriverType_MMPM: pcszDriver = "MMPM"; break;
6799 default: /*case AudioDriverType_Null:*/ pcszDriver = "Null"; break;
6800 }
6801 /* Deliberately have the audio driver explicitly in the config file,
6802 * otherwise an unwritten default driver triggers auto-detection. */
6803 pelmAudio->setAttribute("driver", pcszDriver);
6804
6805 if (hw.audioAdapter.fEnabled || m->sv < SettingsVersion_v1_16)
6806 pelmAudio->setAttribute("enabled", hw.audioAdapter.fEnabled);
6807
6808 if ( (m->sv <= SettingsVersion_v1_16 && !hw.audioAdapter.fEnabledIn)
6809 || (m->sv > SettingsVersion_v1_16 && hw.audioAdapter.fEnabledIn))
6810 pelmAudio->setAttribute("enabledIn", hw.audioAdapter.fEnabledIn);
6811
6812 if ( (m->sv <= SettingsVersion_v1_16 && !hw.audioAdapter.fEnabledOut)
6813 || (m->sv > SettingsVersion_v1_16 && hw.audioAdapter.fEnabledOut))
6814 pelmAudio->setAttribute("enabledOut", hw.audioAdapter.fEnabledOut);
6815
6816 if (m->sv >= SettingsVersion_v1_15 && hw.audioAdapter.properties.size() > 0)
6817 {
6818 for (StringsMap::const_iterator it = hw.audioAdapter.properties.begin();
6819 it != hw.audioAdapter.properties.end();
6820 ++it)
6821 {
6822 const Utf8Str &strName = it->first;
6823 const Utf8Str &strValue = it->second;
6824 xml::ElementNode *pelm = pelmAudio->createChild("Property");
6825 pelm->setAttribute("name", strName);
6826 pelm->setAttribute("value", strValue);
6827 }
6828 }
6829 }
6830
6831 if (m->sv >= SettingsVersion_v1_10 && machineUserData.fRTCUseUTC)
6832 {
6833 xml::ElementNode *pelmRTC = pelmHardware->createChild("RTC");
6834 pelmRTC->setAttribute("localOrUTC", machineUserData.fRTCUseUTC ? "UTC" : "local");
6835 }
6836
6837 if (hw.llSharedFolders.size())
6838 {
6839 xml::ElementNode *pelmSharedFolders = pelmHardware->createChild("SharedFolders");
6840 for (SharedFoldersList::const_iterator it = hw.llSharedFolders.begin();
6841 it != hw.llSharedFolders.end();
6842 ++it)
6843 {
6844 const SharedFolder &sf = *it;
6845 xml::ElementNode *pelmThis = pelmSharedFolders->createChild("SharedFolder");
6846 pelmThis->setAttribute("name", sf.strName);
6847 pelmThis->setAttribute("hostPath", sf.strHostPath);
6848 pelmThis->setAttribute("writable", sf.fWritable);
6849 pelmThis->setAttribute("autoMount", sf.fAutoMount);
6850 if (sf.strAutoMountPoint.isNotEmpty())
6851 pelmThis->setAttribute("autoMountPoint", sf.strAutoMountPoint);
6852 }
6853 }
6854
6855 xml::ElementNode *pelmClip = pelmHardware->createChild("Clipboard");
6856 if (pelmClip)
6857 {
6858 if (hw.clipboardMode != ClipboardMode_Disabled)
6859 {
6860 const char *pcszClip;
6861 switch (hw.clipboardMode)
6862 {
6863 default: /*case ClipboardMode_Disabled:*/ pcszClip = "Disabled"; break;
6864 case ClipboardMode_HostToGuest: pcszClip = "HostToGuest"; break;
6865 case ClipboardMode_GuestToHost: pcszClip = "GuestToHost"; break;
6866 case ClipboardMode_Bidirectional: pcszClip = "Bidirectional"; break;
6867 }
6868 pelmClip->setAttribute("mode", pcszClip);
6869 }
6870
6871 if (hw.fClipboardFileTransfersEnabled)
6872 pelmClip->setAttribute("fileTransfersEnabled", hw.fClipboardFileTransfersEnabled);
6873 }
6874
6875 if (hw.dndMode != DnDMode_Disabled)
6876 {
6877 xml::ElementNode *pelmDragAndDrop = pelmHardware->createChild("DragAndDrop");
6878 const char *pcszDragAndDrop;
6879 switch (hw.dndMode)
6880 {
6881 default: /*case DnDMode_Disabled:*/ pcszDragAndDrop = "Disabled"; break;
6882 case DnDMode_HostToGuest: pcszDragAndDrop = "HostToGuest"; break;
6883 case DnDMode_GuestToHost: pcszDragAndDrop = "GuestToHost"; break;
6884 case DnDMode_Bidirectional: pcszDragAndDrop = "Bidirectional"; break;
6885 }
6886 pelmDragAndDrop->setAttribute("mode", pcszDragAndDrop);
6887 }
6888
6889 if ( m->sv >= SettingsVersion_v1_10
6890 && !hw.ioSettings.areDefaultSettings())
6891 {
6892 xml::ElementNode *pelmIO = pelmHardware->createChild("IO");
6893 xml::ElementNode *pelmIOCache;
6894
6895 if (!hw.ioSettings.areDefaultSettings())
6896 {
6897 pelmIOCache = pelmIO->createChild("IoCache");
6898 if (!hw.ioSettings.fIOCacheEnabled)
6899 pelmIOCache->setAttribute("enabled", hw.ioSettings.fIOCacheEnabled);
6900 if (hw.ioSettings.ulIOCacheSize != 5)
6901 pelmIOCache->setAttribute("size", hw.ioSettings.ulIOCacheSize);
6902 }
6903
6904 if ( m->sv >= SettingsVersion_v1_11
6905 && hw.ioSettings.llBandwidthGroups.size())
6906 {
6907 xml::ElementNode *pelmBandwidthGroups = pelmIO->createChild("BandwidthGroups");
6908 for (BandwidthGroupList::const_iterator it = hw.ioSettings.llBandwidthGroups.begin();
6909 it != hw.ioSettings.llBandwidthGroups.end();
6910 ++it)
6911 {
6912 const BandwidthGroup &gr = *it;
6913 const char *pcszType;
6914 xml::ElementNode *pelmThis = pelmBandwidthGroups->createChild("BandwidthGroup");
6915 pelmThis->setAttribute("name", gr.strName);
6916 switch (gr.enmType)
6917 {
6918 case BandwidthGroupType_Network: pcszType = "Network"; break;
6919 default: /* BandwidthGrouptype_Disk */ pcszType = "Disk"; break;
6920 }
6921 pelmThis->setAttribute("type", pcszType);
6922 if (m->sv >= SettingsVersion_v1_13)
6923 pelmThis->setAttribute("maxBytesPerSec", gr.cMaxBytesPerSec);
6924 else
6925 pelmThis->setAttribute("maxMbPerSec", gr.cMaxBytesPerSec / _1M);
6926 }
6927 }
6928 }
6929
6930 if ( m->sv >= SettingsVersion_v1_12
6931 && hw.pciAttachments.size())
6932 {
6933 xml::ElementNode *pelmPCI = pelmHardware->createChild("HostPci");
6934 xml::ElementNode *pelmPCIDevices = pelmPCI->createChild("Devices");
6935
6936 for (HostPCIDeviceAttachmentList::const_iterator it = hw.pciAttachments.begin();
6937 it != hw.pciAttachments.end();
6938 ++it)
6939 {
6940 const HostPCIDeviceAttachment &hpda = *it;
6941
6942 xml::ElementNode *pelmThis = pelmPCIDevices->createChild("Device");
6943
6944 pelmThis->setAttribute("host", hpda.uHostAddress);
6945 pelmThis->setAttribute("guest", hpda.uGuestAddress);
6946 pelmThis->setAttribute("name", hpda.strDeviceName);
6947 }
6948 }
6949
6950 if ( m->sv >= SettingsVersion_v1_12
6951 && hw.fEmulatedUSBCardReader)
6952 {
6953 xml::ElementNode *pelmEmulatedUSB = pelmHardware->createChild("EmulatedUSB");
6954
6955 xml::ElementNode *pelmCardReader = pelmEmulatedUSB->createChild("CardReader");
6956 pelmCardReader->setAttribute("enabled", hw.fEmulatedUSBCardReader);
6957 }
6958
6959 if ( m->sv >= SettingsVersion_v1_14
6960 && !hw.strDefaultFrontend.isEmpty())
6961 {
6962 xml::ElementNode *pelmFrontend = pelmHardware->createChild("Frontend");
6963 xml::ElementNode *pelmDefault = pelmFrontend->createChild("Default");
6964 pelmDefault->setAttribute("type", hw.strDefaultFrontend);
6965 }
6966
6967 if (hw.ulMemoryBalloonSize)
6968 {
6969 xml::ElementNode *pelmGuest = pelmHardware->createChild("Guest");
6970 pelmGuest->setAttribute("memoryBalloonSize", hw.ulMemoryBalloonSize);
6971 }
6972
6973 if (hw.llGuestProperties.size())
6974 {
6975 xml::ElementNode *pelmGuestProps = pelmHardware->createChild("GuestProperties");
6976 for (GuestPropertiesList::const_iterator it = hw.llGuestProperties.begin();
6977 it != hw.llGuestProperties.end();
6978 ++it)
6979 {
6980 const GuestProperty &prop = *it;
6981 xml::ElementNode *pelmProp = pelmGuestProps->createChild("GuestProperty");
6982 pelmProp->setAttribute("name", prop.strName);
6983 pelmProp->setAttribute("value", prop.strValue);
6984 pelmProp->setAttribute("timestamp", prop.timestamp);
6985 pelmProp->setAttribute("flags", prop.strFlags);
6986 }
6987 }
6988
6989 /* Starting with settings version of 6.0 (and only 6.1 and later does this, while
6990 * 5.2 and 6.0 understand it), place storage controller settings under hardware,
6991 * where it always should've been. */
6992 xml::ElementNode &elmStorageParent = (m->sv >= SettingsVersion_v1_17) ? *pelmHardware : elmParent;
6993 buildStorageControllersXML(elmStorageParent,
6994 hw.storage,
6995 !!(fl & BuildMachineXML_SkipRemovableMedia),
6996 pllElementsWithUuidAttributes);
6997}
6998
6999/**
7000 * Fill a \<Network\> node. Only relevant for XML version >= v1_10.
7001 * @param mode
7002 * @param fEnabled
7003 * @param elmParent
7004 * @param nic
7005 */
7006void MachineConfigFile::buildNetworkXML(NetworkAttachmentType_T mode,
7007 bool fEnabled,
7008 xml::ElementNode &elmParent,
7009 const NetworkAdapter &nic)
7010{
7011 switch (mode)
7012 {
7013 case NetworkAttachmentType_NAT:
7014 // For the currently active network attachment type we have to
7015 // generate the tag, otherwise the attachment type is lost.
7016 if (fEnabled || !nic.nat.areDefaultSettings())
7017 {
7018 xml::ElementNode *pelmNAT = elmParent.createChild("NAT");
7019
7020 if (!nic.nat.areDefaultSettings())
7021 {
7022 if (nic.nat.strNetwork.length())
7023 pelmNAT->setAttribute("network", nic.nat.strNetwork);
7024 if (nic.nat.strBindIP.length())
7025 pelmNAT->setAttribute("hostip", nic.nat.strBindIP);
7026 if (nic.nat.u32Mtu)
7027 pelmNAT->setAttribute("mtu", nic.nat.u32Mtu);
7028 if (nic.nat.u32SockRcv)
7029 pelmNAT->setAttribute("sockrcv", nic.nat.u32SockRcv);
7030 if (nic.nat.u32SockSnd)
7031 pelmNAT->setAttribute("socksnd", nic.nat.u32SockSnd);
7032 if (nic.nat.u32TcpRcv)
7033 pelmNAT->setAttribute("tcprcv", nic.nat.u32TcpRcv);
7034 if (nic.nat.u32TcpSnd)
7035 pelmNAT->setAttribute("tcpsnd", nic.nat.u32TcpSnd);
7036 if (!nic.nat.areDNSDefaultSettings())
7037 {
7038 xml::ElementNode *pelmDNS = pelmNAT->createChild("DNS");
7039 if (!nic.nat.fDNSPassDomain)
7040 pelmDNS->setAttribute("pass-domain", nic.nat.fDNSPassDomain);
7041 if (nic.nat.fDNSProxy)
7042 pelmDNS->setAttribute("use-proxy", nic.nat.fDNSProxy);
7043 if (nic.nat.fDNSUseHostResolver)
7044 pelmDNS->setAttribute("use-host-resolver", nic.nat.fDNSUseHostResolver);
7045 }
7046
7047 if (!nic.nat.areAliasDefaultSettings())
7048 {
7049 xml::ElementNode *pelmAlias = pelmNAT->createChild("Alias");
7050 if (nic.nat.fAliasLog)
7051 pelmAlias->setAttribute("logging", nic.nat.fAliasLog);
7052 if (nic.nat.fAliasProxyOnly)
7053 pelmAlias->setAttribute("proxy-only", nic.nat.fAliasProxyOnly);
7054 if (nic.nat.fAliasUseSamePorts)
7055 pelmAlias->setAttribute("use-same-ports", nic.nat.fAliasUseSamePorts);
7056 }
7057
7058 if (!nic.nat.areTFTPDefaultSettings())
7059 {
7060 xml::ElementNode *pelmTFTP;
7061 pelmTFTP = pelmNAT->createChild("TFTP");
7062 if (nic.nat.strTFTPPrefix.length())
7063 pelmTFTP->setAttribute("prefix", nic.nat.strTFTPPrefix);
7064 if (nic.nat.strTFTPBootFile.length())
7065 pelmTFTP->setAttribute("boot-file", nic.nat.strTFTPBootFile);
7066 if (nic.nat.strTFTPNextServer.length())
7067 pelmTFTP->setAttribute("next-server", nic.nat.strTFTPNextServer);
7068 }
7069 buildNATForwardRulesMap(*pelmNAT, nic.nat.mapRules);
7070 }
7071 }
7072 break;
7073
7074 case NetworkAttachmentType_Bridged:
7075 // For the currently active network attachment type we have to
7076 // generate the tag, otherwise the attachment type is lost.
7077 if (fEnabled || !nic.strBridgedName.isEmpty())
7078 {
7079 xml::ElementNode *pelmMode = elmParent.createChild("BridgedInterface");
7080 if (!nic.strBridgedName.isEmpty())
7081 pelmMode->setAttribute("name", nic.strBridgedName);
7082 }
7083 break;
7084
7085 case NetworkAttachmentType_Internal:
7086 // For the currently active network attachment type we have to
7087 // generate the tag, otherwise the attachment type is lost.
7088 if (fEnabled || !nic.strInternalNetworkName.isEmpty())
7089 {
7090 xml::ElementNode *pelmMode = elmParent.createChild("InternalNetwork");
7091 if (!nic.strInternalNetworkName.isEmpty())
7092 pelmMode->setAttribute("name", nic.strInternalNetworkName);
7093 }
7094 break;
7095
7096 case NetworkAttachmentType_HostOnly:
7097 // For the currently active network attachment type we have to
7098 // generate the tag, otherwise the attachment type is lost.
7099 if (fEnabled || !nic.strHostOnlyName.isEmpty())
7100 {
7101 xml::ElementNode *pelmMode = elmParent.createChild("HostOnlyInterface");
7102 if (!nic.strHostOnlyName.isEmpty())
7103 pelmMode->setAttribute("name", nic.strHostOnlyName);
7104 }
7105 break;
7106
7107 case NetworkAttachmentType_Generic:
7108 // For the currently active network attachment type we have to
7109 // generate the tag, otherwise the attachment type is lost.
7110 if (fEnabled || !nic.areGenericDriverDefaultSettings())
7111 {
7112 xml::ElementNode *pelmMode = elmParent.createChild("GenericInterface");
7113 if (!nic.areGenericDriverDefaultSettings())
7114 {
7115 pelmMode->setAttribute("driver", nic.strGenericDriver);
7116 for (StringsMap::const_iterator it = nic.genericProperties.begin();
7117 it != nic.genericProperties.end();
7118 ++it)
7119 {
7120 xml::ElementNode *pelmProp = pelmMode->createChild("Property");
7121 pelmProp->setAttribute("name", it->first);
7122 pelmProp->setAttribute("value", it->second);
7123 }
7124 }
7125 }
7126 break;
7127
7128 case NetworkAttachmentType_NATNetwork:
7129 // For the currently active network attachment type we have to
7130 // generate the tag, otherwise the attachment type is lost.
7131 if (fEnabled || !nic.strNATNetworkName.isEmpty())
7132 {
7133 xml::ElementNode *pelmMode = elmParent.createChild("NATNetwork");
7134 if (!nic.strNATNetworkName.isEmpty())
7135 pelmMode->setAttribute("name", nic.strNATNetworkName);
7136 }
7137 break;
7138
7139#ifdef VBOX_WITH_CLOUD_NET
7140 case NetworkAttachmentType_Cloud:
7141 // For the currently active network attachment type we have to
7142 // generate the tag, otherwise the attachment type is lost.
7143 if (fEnabled || !nic.strCloudNetworkName.isEmpty())
7144 {
7145 xml::ElementNode *pelmMode = elmParent.createChild("CloudNetwork");
7146 if (!nic.strCloudNetworkName.isEmpty())
7147 pelmMode->setAttribute("name", nic.strCloudNetworkName);
7148 }
7149 break;
7150#endif /* VBOX_WITH_CLOUD_NET */
7151
7152 default: /*case NetworkAttachmentType_Null:*/
7153 break;
7154 }
7155}
7156
7157/**
7158 * Creates a \<StorageControllers\> node under elmParent and then writes out the XML
7159 * keys under that. Called for both the \<Machine\> node and for snapshots.
7160 * @param elmParent
7161 * @param st
7162 * @param fSkipRemovableMedia If true, DVD and floppy attachments are skipped and
7163 * an empty drive is always written instead. This is for the OVF export case.
7164 * This parameter is ignored unless the settings version is at least v1.9, which
7165 * is always the case when this gets called for OVF export.
7166 * @param pllElementsWithUuidAttributes If not NULL, must point to a list of element node
7167 * pointers to which we will append all elements that we created here that contain
7168 * UUID attributes. This allows the OVF export code to quickly replace the internal
7169 * media UUIDs with the UUIDs of the media that were exported.
7170 */
7171void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent,
7172 const Storage &st,
7173 bool fSkipRemovableMedia,
7174 std::list<xml::ElementNode*> *pllElementsWithUuidAttributes)
7175{
7176 if (!st.llStorageControllers.size())
7177 return;
7178 xml::ElementNode *pelmStorageControllers = elmParent.createChild("StorageControllers");
7179
7180 for (StorageControllersList::const_iterator it = st.llStorageControllers.begin();
7181 it != st.llStorageControllers.end();
7182 ++it)
7183 {
7184 const StorageController &sc = *it;
7185
7186 if ( (m->sv < SettingsVersion_v1_9)
7187 && (sc.controllerType == StorageControllerType_I82078)
7188 )
7189 // floppy controller already got written into <Hardware>/<FloppyController> in buildHardwareXML()
7190 // for pre-1.9 settings
7191 continue;
7192
7193 xml::ElementNode *pelmController = pelmStorageControllers->createChild("StorageController");
7194 com::Utf8Str name = sc.strName;
7195 if (m->sv < SettingsVersion_v1_8)
7196 {
7197 // pre-1.8 settings use shorter controller names, they are
7198 // expanded when reading the settings
7199 if (name == "IDE Controller")
7200 name = "IDE";
7201 else if (name == "SATA Controller")
7202 name = "SATA";
7203 else if (name == "SCSI Controller")
7204 name = "SCSI";
7205 }
7206 pelmController->setAttribute("name", sc.strName);
7207
7208 const char *pcszType;
7209 switch (sc.controllerType)
7210 {
7211 case StorageControllerType_IntelAhci: pcszType = "AHCI"; break;
7212 case StorageControllerType_LsiLogic: pcszType = "LsiLogic"; break;
7213 case StorageControllerType_BusLogic: pcszType = "BusLogic"; break;
7214 case StorageControllerType_PIIX4: pcszType = "PIIX4"; break;
7215 case StorageControllerType_ICH6: pcszType = "ICH6"; break;
7216 case StorageControllerType_I82078: pcszType = "I82078"; break;
7217 case StorageControllerType_LsiLogicSas: pcszType = "LsiLogicSas"; break;
7218 case StorageControllerType_USB: pcszType = "USB"; break;
7219 case StorageControllerType_NVMe: pcszType = "NVMe"; break;
7220 case StorageControllerType_VirtioSCSI: pcszType = "VirtioSCSI"; break;
7221 default: /*case StorageControllerType_PIIX3:*/ pcszType = "PIIX3"; break;
7222 }
7223 pelmController->setAttribute("type", pcszType);
7224
7225 pelmController->setAttribute("PortCount", sc.ulPortCount);
7226
7227 if (m->sv >= SettingsVersion_v1_9)
7228 if (sc.ulInstance)
7229 pelmController->setAttribute("Instance", sc.ulInstance);
7230
7231 if (m->sv >= SettingsVersion_v1_10)
7232 pelmController->setAttribute("useHostIOCache", sc.fUseHostIOCache);
7233
7234 if (m->sv >= SettingsVersion_v1_11)
7235 pelmController->setAttribute("Bootable", sc.fBootable);
7236
7237 if (sc.controllerType == StorageControllerType_IntelAhci)
7238 {
7239 pelmController->setAttribute("IDE0MasterEmulationPort", 0);
7240 pelmController->setAttribute("IDE0SlaveEmulationPort", 1);
7241 pelmController->setAttribute("IDE1MasterEmulationPort", 2);
7242 pelmController->setAttribute("IDE1SlaveEmulationPort", 3);
7243 }
7244
7245 for (AttachedDevicesList::const_iterator it2 = sc.llAttachedDevices.begin();
7246 it2 != sc.llAttachedDevices.end();
7247 ++it2)
7248 {
7249 const AttachedDevice &att = *it2;
7250
7251 // For settings version before 1.9, DVDs and floppies are in hardware, not storage controllers,
7252 // so we shouldn't write them here; we only get here for DVDs though because we ruled out
7253 // the floppy controller at the top of the loop
7254 if ( att.deviceType == DeviceType_DVD
7255 && m->sv < SettingsVersion_v1_9
7256 )
7257 continue;
7258
7259 xml::ElementNode *pelmDevice = pelmController->createChild("AttachedDevice");
7260
7261 pcszType = NULL;
7262
7263 switch (att.deviceType)
7264 {
7265 case DeviceType_HardDisk:
7266 pcszType = "HardDisk";
7267 if (att.fNonRotational)
7268 pelmDevice->setAttribute("nonrotational", att.fNonRotational);
7269 if (att.fDiscard)
7270 pelmDevice->setAttribute("discard", att.fDiscard);
7271 break;
7272
7273 case DeviceType_DVD:
7274 pcszType = "DVD";
7275 pelmDevice->setAttribute("passthrough", att.fPassThrough);
7276 if (att.fTempEject)
7277 pelmDevice->setAttribute("tempeject", att.fTempEject);
7278 break;
7279
7280 case DeviceType_Floppy:
7281 pcszType = "Floppy";
7282 break;
7283
7284 default: break; /* Shut up MSC. */
7285 }
7286
7287 pelmDevice->setAttribute("type", pcszType);
7288
7289 if (m->sv >= SettingsVersion_v1_15)
7290 pelmDevice->setAttribute("hotpluggable", att.fHotPluggable);
7291
7292 pelmDevice->setAttribute("port", att.lPort);
7293 pelmDevice->setAttribute("device", att.lDevice);
7294
7295 if (att.strBwGroup.length())
7296 pelmDevice->setAttribute("bandwidthGroup", att.strBwGroup);
7297
7298 // attached image, if any
7299 if (!att.uuid.isZero()
7300 && att.uuid.isValid()
7301 && (att.deviceType == DeviceType_HardDisk
7302 || !fSkipRemovableMedia
7303 )
7304 )
7305 {
7306 xml::ElementNode *pelmImage = pelmDevice->createChild("Image");
7307 pelmImage->setAttribute("uuid", att.uuid.toStringCurly());
7308
7309 // if caller wants a list of UUID elements, give it to them
7310 if (pllElementsWithUuidAttributes)
7311 pllElementsWithUuidAttributes->push_back(pelmImage);
7312 }
7313 else if ( (m->sv >= SettingsVersion_v1_9)
7314 && (att.strHostDriveSrc.length())
7315 )
7316 pelmDevice->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc);
7317 }
7318 }
7319}
7320
7321/**
7322 * Creates a \<Debugging\> node under elmParent and then writes out the XML
7323 * keys under that. Called for both the \<Machine\> node and for snapshots.
7324 *
7325 * @param pElmParent Pointer to the parent element.
7326 * @param pDbg Pointer to the debugging settings.
7327 */
7328void MachineConfigFile::buildDebuggingXML(xml::ElementNode *pElmParent, const Debugging *pDbg)
7329{
7330 if (m->sv < SettingsVersion_v1_13 || pDbg->areDefaultSettings())
7331 return;
7332
7333 xml::ElementNode *pElmDebugging = pElmParent->createChild("Debugging");
7334 xml::ElementNode *pElmTracing = pElmDebugging->createChild("Tracing");
7335 pElmTracing->setAttribute("enabled", pDbg->fTracingEnabled);
7336 pElmTracing->setAttribute("allowTracingToAccessVM", pDbg->fAllowTracingToAccessVM);
7337 pElmTracing->setAttribute("config", pDbg->strTracingConfig);
7338}
7339
7340/**
7341 * Creates a \<Autostart\> node under elmParent and then writes out the XML
7342 * keys under that. Called for both the \<Machine\> node and for snapshots.
7343 *
7344 * @param pElmParent Pointer to the parent element.
7345 * @param pAutostart Pointer to the autostart settings.
7346 */
7347void MachineConfigFile::buildAutostartXML(xml::ElementNode *pElmParent, const Autostart *pAutostart)
7348{
7349 const char *pcszAutostop = NULL;
7350
7351 if (m->sv < SettingsVersion_v1_13 || pAutostart->areDefaultSettings())
7352 return;
7353
7354 xml::ElementNode *pElmAutostart = pElmParent->createChild("Autostart");
7355 pElmAutostart->setAttribute("enabled", pAutostart->fAutostartEnabled);
7356 pElmAutostart->setAttribute("delay", pAutostart->uAutostartDelay);
7357
7358 switch (pAutostart->enmAutostopType)
7359 {
7360 case AutostopType_Disabled: pcszAutostop = "Disabled"; break;
7361 case AutostopType_SaveState: pcszAutostop = "SaveState"; break;
7362 case AutostopType_PowerOff: pcszAutostop = "PowerOff"; break;
7363 case AutostopType_AcpiShutdown: pcszAutostop = "AcpiShutdown"; break;
7364 default: Assert(false); pcszAutostop = "Disabled"; break;
7365 }
7366 pElmAutostart->setAttribute("autostop", pcszAutostop);
7367}
7368
7369/**
7370 * Creates a \<Groups\> node under elmParent and then writes out the XML
7371 * keys under that. Called for the \<Machine\> node only.
7372 *
7373 * @param pElmParent Pointer to the parent element.
7374 * @param pllGroups Pointer to the groups list.
7375 */
7376void MachineConfigFile::buildGroupsXML(xml::ElementNode *pElmParent, const StringsList *pllGroups)
7377{
7378 if ( m->sv < SettingsVersion_v1_13 || pllGroups->size() == 0
7379 || (pllGroups->size() == 1 && pllGroups->front() == "/"))
7380 return;
7381
7382 xml::ElementNode *pElmGroups = pElmParent->createChild("Groups");
7383 for (StringsList::const_iterator it = pllGroups->begin();
7384 it != pllGroups->end();
7385 ++it)
7386 {
7387 const Utf8Str &group = *it;
7388 xml::ElementNode *pElmGroup = pElmGroups->createChild("Group");
7389 pElmGroup->setAttribute("name", group);
7390 }
7391}
7392
7393/**
7394 * Writes a single snapshot into the DOM tree. Initially this gets called from MachineConfigFile::write()
7395 * for the root snapshot of a machine, if present; elmParent then points to the \<Snapshots\> node under the
7396 * \<Machine\> node to which \<Snapshot\> must be added. This may then recurse for child snapshots.
7397 *
7398 * @param depth
7399 * @param elmParent
7400 * @param snap
7401 */
7402void MachineConfigFile::buildSnapshotXML(uint32_t depth,
7403 xml::ElementNode &elmParent,
7404 const Snapshot &snap)
7405{
7406 if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX)
7407 throw ConfigFileError(this, NULL, N_("Maximum snapshot tree depth of %u exceeded"), SETTINGS_SNAPSHOT_DEPTH_MAX);
7408
7409 xml::ElementNode *pelmSnapshot = elmParent.createChild("Snapshot");
7410
7411 pelmSnapshot->setAttribute("uuid", snap.uuid.toStringCurly());
7412 pelmSnapshot->setAttribute("name", snap.strName);
7413 pelmSnapshot->setAttribute("timeStamp", stringifyTimestamp(snap.timestamp));
7414
7415 if (snap.strStateFile.length())
7416 pelmSnapshot->setAttributePath("stateFile", snap.strStateFile);
7417
7418 if (snap.strDescription.length())
7419 pelmSnapshot->createChild("Description")->addContent(snap.strDescription);
7420
7421 // We only skip removable media for OVF, but OVF never includes snapshots.
7422 buildHardwareXML(*pelmSnapshot, snap.hardware, 0 /* fl */, NULL /* pllElementsWithUuidAttributes */);
7423 buildDebuggingXML(pelmSnapshot, &snap.debugging);
7424 buildAutostartXML(pelmSnapshot, &snap.autostart);
7425 // note: Groups exist only for Machine, not for Snapshot
7426
7427 if (snap.llChildSnapshots.size())
7428 {
7429 xml::ElementNode *pelmChildren = pelmSnapshot->createChild("Snapshots");
7430 for (SnapshotsList::const_iterator it = snap.llChildSnapshots.begin();
7431 it != snap.llChildSnapshots.end();
7432 ++it)
7433 {
7434 const Snapshot &child = *it;
7435 buildSnapshotXML(depth + 1, *pelmChildren, child);
7436 }
7437 }
7438}
7439
7440/**
7441 * Builds the XML DOM tree for the machine config under the given XML element.
7442 *
7443 * This has been separated out from write() so it can be called from elsewhere,
7444 * such as the OVF code, to build machine XML in an existing XML tree.
7445 *
7446 * As a result, this gets called from two locations:
7447 *
7448 * -- MachineConfigFile::write();
7449 *
7450 * -- Appliance::buildXMLForOneVirtualSystem()
7451 *
7452 * In fl, the following flag bits are recognized:
7453 *
7454 * -- BuildMachineXML_MediaRegistry: If set, the machine's media registry will
7455 * be written, if present. This is not set when called from OVF because OVF
7456 * has its own variant of a media registry. This flag is ignored unless the
7457 * settings version is at least v1.11 (VirtualBox 4.0).
7458 *
7459 * -- BuildMachineXML_IncludeSnapshots: If set, descend into the snapshots tree
7460 * of the machine and write out \<Snapshot\> and possibly more snapshots under
7461 * that, if snapshots are present. Otherwise all snapshots are suppressed
7462 * (when called from OVF).
7463 *
7464 * -- BuildMachineXML_WriteVBoxVersionAttribute: If set, add a settingsVersion
7465 * attribute to the machine tag with the vbox settings version. This is for
7466 * the OVF export case in which we don't have the settings version set in
7467 * the root element.
7468 *
7469 * -- BuildMachineXML_SkipRemovableMedia: If set, removable media attachments
7470 * (DVDs, floppies) are silently skipped. This is for the OVF export case
7471 * until we support copying ISO and RAW media as well. This flag is ignored
7472 * unless the settings version is at least v1.9, which is always the case
7473 * when this gets called for OVF export.
7474 *
7475 * -- BuildMachineXML_SuppressSavedState: If set, the Machine/stateFile
7476 * attribute is never set. This is also for the OVF export case because we
7477 * cannot save states with OVF.
7478 *
7479 * @param elmMachine XML \<Machine\> element to add attributes and elements to.
7480 * @param fl Flags.
7481 * @param pllElementsWithUuidAttributes pointer to list that should receive UUID elements or NULL;
7482 * see buildStorageControllersXML() for details.
7483 */
7484void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine,
7485 uint32_t fl,
7486 std::list<xml::ElementNode*> *pllElementsWithUuidAttributes)
7487{
7488 if (fl & BuildMachineXML_WriteVBoxVersionAttribute)
7489 {
7490 // add settings version attribute to machine element
7491 setVersionAttribute(elmMachine);
7492 LogRel(("Exporting settings file \"%s\" with version \"%s\"\n", m->strFilename.c_str(), m->strSettingsVersionFull.c_str()));
7493 }
7494
7495 elmMachine.setAttribute("uuid", uuid.toStringCurly());
7496 elmMachine.setAttribute("name", machineUserData.strName);
7497 if (machineUserData.fDirectoryIncludesUUID)
7498 elmMachine.setAttribute("directoryIncludesUUID", machineUserData.fDirectoryIncludesUUID);
7499 if (!machineUserData.fNameSync)
7500 elmMachine.setAttribute("nameSync", machineUserData.fNameSync);
7501 if (machineUserData.strDescription.length())
7502 elmMachine.createChild("Description")->addContent(machineUserData.strDescription);
7503 elmMachine.setAttribute("OSType", machineUserData.strOsType);
7504 if ( strStateFile.length()
7505 && !(fl & BuildMachineXML_SuppressSavedState)
7506 )
7507 elmMachine.setAttributePath("stateFile", strStateFile);
7508
7509 if ((fl & BuildMachineXML_IncludeSnapshots)
7510 && !uuidCurrentSnapshot.isZero()
7511 && uuidCurrentSnapshot.isValid())
7512 elmMachine.setAttribute("currentSnapshot", uuidCurrentSnapshot.toStringCurly());
7513
7514 if (machineUserData.strSnapshotFolder.length())
7515 elmMachine.setAttributePath("snapshotFolder", machineUserData.strSnapshotFolder);
7516 if (!fCurrentStateModified)
7517 elmMachine.setAttribute("currentStateModified", fCurrentStateModified);
7518 elmMachine.setAttribute("lastStateChange", stringifyTimestamp(timeLastStateChange));
7519 if (fAborted)
7520 elmMachine.setAttribute("aborted", fAborted);
7521
7522 switch (machineUserData.enmVMPriority)
7523 {
7524 case VMProcPriority_Flat:
7525 elmMachine.setAttribute("processPriority", "Flat");
7526 break;
7527 case VMProcPriority_Low:
7528 elmMachine.setAttribute("processPriority", "Low");
7529 break;
7530 case VMProcPriority_Normal:
7531 elmMachine.setAttribute("processPriority", "Normal");
7532 break;
7533 case VMProcPriority_High:
7534 elmMachine.setAttribute("processPriority", "High");
7535 break;
7536 default:
7537 break;
7538 }
7539 // Please keep the icon last so that one doesn't have to check if there
7540 // is anything in the line after this very long attribute in the XML.
7541 if (machineUserData.ovIcon.size())
7542 {
7543 Utf8Str strIcon;
7544 toBase64(strIcon, machineUserData.ovIcon);
7545 elmMachine.setAttribute("icon", strIcon);
7546 }
7547 if ( m->sv >= SettingsVersion_v1_9
7548 && ( machineUserData.fTeleporterEnabled
7549 || machineUserData.uTeleporterPort
7550 || !machineUserData.strTeleporterAddress.isEmpty()
7551 || !machineUserData.strTeleporterPassword.isEmpty()
7552 )
7553 )
7554 {
7555 xml::ElementNode *pelmTeleporter = elmMachine.createChild("Teleporter");
7556 pelmTeleporter->setAttribute("enabled", machineUserData.fTeleporterEnabled);
7557 pelmTeleporter->setAttribute("port", machineUserData.uTeleporterPort);
7558 pelmTeleporter->setAttribute("address", machineUserData.strTeleporterAddress);
7559 pelmTeleporter->setAttribute("password", machineUserData.strTeleporterPassword);
7560 }
7561
7562 if ( (fl & BuildMachineXML_MediaRegistry)
7563 && (m->sv >= SettingsVersion_v1_11)
7564 )
7565 buildMediaRegistry(elmMachine, mediaRegistry);
7566
7567 buildExtraData(elmMachine, mapExtraDataItems);
7568
7569 if ( (fl & BuildMachineXML_IncludeSnapshots)
7570 && llFirstSnapshot.size())
7571 buildSnapshotXML(1, elmMachine, llFirstSnapshot.front());
7572
7573 buildHardwareXML(elmMachine, hardwareMachine, fl, pllElementsWithUuidAttributes);
7574 buildDebuggingXML(&elmMachine, &debugging);
7575 buildAutostartXML(&elmMachine, &autostart);
7576 buildGroupsXML(&elmMachine, &machineUserData.llGroups);
7577}
7578
7579/**
7580 * Returns true only if the given AudioDriverType is supported on
7581 * the current host platform. For example, this would return false
7582 * for AudioDriverType_DirectSound when compiled on a Linux host.
7583 * @param drv AudioDriverType_* enum to test.
7584 * @return true only if the current host supports that driver.
7585 */
7586/*static*/
7587bool MachineConfigFile::isAudioDriverAllowedOnThisHost(AudioDriverType_T drv)
7588{
7589 switch (drv)
7590 {
7591 case AudioDriverType_Null:
7592#ifdef RT_OS_WINDOWS
7593 case AudioDriverType_DirectSound:
7594#endif
7595#ifdef VBOX_WITH_AUDIO_OSS
7596 case AudioDriverType_OSS:
7597#endif
7598#ifdef VBOX_WITH_AUDIO_ALSA
7599 case AudioDriverType_ALSA:
7600#endif
7601#ifdef VBOX_WITH_AUDIO_PULSE
7602 case AudioDriverType_Pulse:
7603#endif
7604#ifdef RT_OS_DARWIN
7605 case AudioDriverType_CoreAudio:
7606#endif
7607#ifdef RT_OS_OS2
7608 case AudioDriverType_MMPM:
7609#endif
7610 return true;
7611 default: break; /* Shut up MSC. */
7612 }
7613
7614 return false;
7615}
7616
7617/**
7618 * Returns the AudioDriverType_* which should be used by default on this
7619 * host platform. On Linux, this will check at runtime whether PulseAudio
7620 * or ALSA are actually supported on the first call.
7621 *
7622 * @return Default audio driver type for this host platform.
7623 */
7624/*static*/
7625AudioDriverType_T MachineConfigFile::getHostDefaultAudioDriver()
7626{
7627#if defined(RT_OS_WINDOWS)
7628 return AudioDriverType_DirectSound;
7629
7630#elif defined(RT_OS_LINUX)
7631 /* On Linux, we need to check at runtime what's actually supported. */
7632 static RTCLockMtx s_mtx;
7633 static AudioDriverType_T s_enmLinuxDriver = AudioDriverType_Null;
7634 RTCLock lock(s_mtx);
7635 if (s_enmLinuxDriver == AudioDriverType_Null)
7636 {
7637# ifdef VBOX_WITH_AUDIO_PULSE
7638 /* Check for the pulse library & that the pulse audio daemon is running. */
7639 if (RTProcIsRunningByName("pulseaudio") &&
7640 RTLdrIsLoadable("libpulse.so.0"))
7641 s_enmLinuxDriver = AudioDriverType_Pulse;
7642 else
7643# endif /* VBOX_WITH_AUDIO_PULSE */
7644# ifdef VBOX_WITH_AUDIO_ALSA
7645 /* Check if we can load the ALSA library */
7646 if (RTLdrIsLoadable("libasound.so.2"))
7647 s_enmLinuxDriver = AudioDriverType_ALSA;
7648 else
7649# endif /* VBOX_WITH_AUDIO_ALSA */
7650 s_enmLinuxDriver = AudioDriverType_OSS;
7651 }
7652 return s_enmLinuxDriver;
7653
7654#elif defined(RT_OS_DARWIN)
7655 return AudioDriverType_CoreAudio;
7656
7657#elif defined(RT_OS_OS2)
7658 return AudioDriverType_MMPM;
7659
7660#else /* All other platforms. */
7661# ifdef VBOX_WITH_AUDIO_OSS
7662 return AudioDriverType_OSS;
7663# else
7664 /* Return NULL driver as a fallback if nothing of the above is available. */
7665 return AudioDriverType_Null;
7666# endif
7667#endif
7668}
7669
7670/**
7671 * Called from write() before calling ConfigFileBase::createStubDocument().
7672 * This adjusts the settings version in m->sv if incompatible settings require
7673 * a settings bump, whereas otherwise we try to preserve the settings version
7674 * to avoid breaking compatibility with older versions.
7675 *
7676 * We do the checks in here in reverse order: newest first, oldest last, so
7677 * that we avoid unnecessary checks since some of these are expensive.
7678 */
7679void MachineConfigFile::bumpSettingsVersionIfNeeded()
7680{
7681 if (m->sv < SettingsVersion_v1_19)
7682 {
7683 // VirtualBox 6.2 adds iommu device.
7684 if (hardwareMachine.iommuType != IommuType_None)
7685 {
7686 m->sv = SettingsVersion_v1_19;
7687 return;
7688 }
7689 }
7690
7691 if (m->sv < SettingsVersion_v1_18)
7692 {
7693 if (!hardwareMachine.biosSettings.strNVRAMPath.isEmpty())
7694 {
7695 m->sv = SettingsVersion_v1_18;
7696 return;
7697 }
7698
7699 // VirtualBox 6.1 adds AMD-V virtualized VMSAVE/VMLOAD setting.
7700 if (hardwareMachine.fVirtVmsaveVmload == false)
7701 {
7702 m->sv = SettingsVersion_v1_18;
7703 return;
7704 }
7705
7706 // VirtualBox 6.1 adds a virtio-scsi storage controller.
7707 for (StorageControllersList::const_iterator it = hardwareMachine.storage.llStorageControllers.begin();
7708 it != hardwareMachine.storage.llStorageControllers.end();
7709 ++it)
7710 {
7711 const StorageController &sctl = *it;
7712
7713 if (sctl.controllerType == StorageControllerType_VirtioSCSI)
7714 {
7715 m->sv = SettingsVersion_v1_18;
7716 return;
7717 }
7718 }
7719 }
7720
7721 if (m->sv < SettingsVersion_v1_17)
7722 {
7723 if (machineUserData.enmVMPriority != VMProcPriority_Default)
7724 {
7725 m->sv = SettingsVersion_v1_17;
7726 return;
7727 }
7728
7729 // VirtualBox 6.0 adds nested hardware virtualization, using native API (NEM).
7730 if ( hardwareMachine.fNestedHWVirt
7731 || hardwareMachine.fUseNativeApi)
7732 {
7733 m->sv = SettingsVersion_v1_17;
7734 return;
7735 }
7736 if (hardwareMachine.llSharedFolders.size())
7737 for (SharedFoldersList::const_iterator it = hardwareMachine.llSharedFolders.begin();
7738 it != hardwareMachine.llSharedFolders.end();
7739 ++it)
7740 if (it->strAutoMountPoint.isNotEmpty())
7741 {
7742 m->sv = SettingsVersion_v1_17;
7743 return;
7744 }
7745
7746 /*
7747 * Check if any serial port uses a non 16550A serial port.
7748 */
7749 for (SerialPortsList::const_iterator it = hardwareMachine.llSerialPorts.begin();
7750 it != hardwareMachine.llSerialPorts.end();
7751 ++it)
7752 {
7753 const SerialPort &port = *it;
7754 if (port.uartType != UartType_U16550A)
7755 {
7756 m->sv = SettingsVersion_v1_17;
7757 return;
7758 }
7759 }
7760 }
7761
7762 if (m->sv < SettingsVersion_v1_16)
7763 {
7764 // VirtualBox 5.1 adds a NVMe storage controller, paravirt debug
7765 // options, cpu profile, APIC settings (CPU capability and BIOS).
7766
7767 if ( hardwareMachine.strParavirtDebug.isNotEmpty()
7768 || (!hardwareMachine.strCpuProfile.equals("host") && hardwareMachine.strCpuProfile.isNotEmpty())
7769 || hardwareMachine.biosSettings.apicMode != APICMode_APIC
7770 || !hardwareMachine.fAPIC
7771 || hardwareMachine.fX2APIC
7772 || hardwareMachine.fIBPBOnVMExit
7773 || hardwareMachine.fIBPBOnVMEntry
7774 || hardwareMachine.fSpecCtrl
7775 || hardwareMachine.fSpecCtrlByHost
7776 || !hardwareMachine.fL1DFlushOnSched
7777 || hardwareMachine.fL1DFlushOnVMEntry
7778 || !hardwareMachine.fMDSClearOnSched
7779 || hardwareMachine.fMDSClearOnVMEntry)
7780 {
7781 m->sv = SettingsVersion_v1_16;
7782 return;
7783 }
7784
7785 for (StorageControllersList::const_iterator it = hardwareMachine.storage.llStorageControllers.begin();
7786 it != hardwareMachine.storage.llStorageControllers.end();
7787 ++it)
7788 {
7789 const StorageController &sctl = *it;
7790
7791 if (sctl.controllerType == StorageControllerType_NVMe)
7792 {
7793 m->sv = SettingsVersion_v1_16;
7794 return;
7795 }
7796 }
7797
7798 for (CpuIdLeafsList::const_iterator it = hardwareMachine.llCpuIdLeafs.begin();
7799 it != hardwareMachine.llCpuIdLeafs.end();
7800 ++it)
7801 if (it->idxSub != 0)
7802 {
7803 m->sv = SettingsVersion_v1_16;
7804 return;
7805 }
7806 }
7807
7808 if (m->sv < SettingsVersion_v1_15)
7809 {
7810 // VirtualBox 5.0 adds paravirt providers, explicit AHCI port hotplug
7811 // setting, USB storage controller, xHCI, serial port TCP backend
7812 // and VM process priority.
7813
7814 /*
7815 * Check simple configuration bits first, loopy stuff afterwards.
7816 */
7817 if ( hardwareMachine.paravirtProvider != ParavirtProvider_Legacy
7818 || hardwareMachine.uCpuIdPortabilityLevel != 0)
7819 {
7820 m->sv = SettingsVersion_v1_15;
7821 return;
7822 }
7823
7824 /*
7825 * Check whether the hotpluggable flag of all storage devices differs
7826 * from the default for old settings.
7827 * AHCI ports are hotpluggable by default every other device is not.
7828 * Also check if there are USB storage controllers.
7829 */
7830 for (StorageControllersList::const_iterator it = hardwareMachine.storage.llStorageControllers.begin();
7831 it != hardwareMachine.storage.llStorageControllers.end();
7832 ++it)
7833 {
7834 const StorageController &sctl = *it;
7835
7836 if (sctl.controllerType == StorageControllerType_USB)
7837 {
7838 m->sv = SettingsVersion_v1_15;
7839 return;
7840 }
7841
7842 for (AttachedDevicesList::const_iterator it2 = sctl.llAttachedDevices.begin();
7843 it2 != sctl.llAttachedDevices.end();
7844 ++it2)
7845 {
7846 const AttachedDevice &att = *it2;
7847
7848 if ( ( att.fHotPluggable
7849 && sctl.controllerType != StorageControllerType_IntelAhci)
7850 || ( !att.fHotPluggable
7851 && sctl.controllerType == StorageControllerType_IntelAhci))
7852 {
7853 m->sv = SettingsVersion_v1_15;
7854 return;
7855 }
7856 }
7857 }
7858
7859 /*
7860 * Check if there is an xHCI (USB3) USB controller.
7861 */
7862 for (USBControllerList::const_iterator it = hardwareMachine.usbSettings.llUSBControllers.begin();
7863 it != hardwareMachine.usbSettings.llUSBControllers.end();
7864 ++it)
7865 {
7866 const USBController &ctrl = *it;
7867 if (ctrl.enmType == USBControllerType_XHCI)
7868 {
7869 m->sv = SettingsVersion_v1_15;
7870 return;
7871 }
7872 }
7873
7874 /*
7875 * Check if any serial port uses the TCP backend.
7876 */
7877 for (SerialPortsList::const_iterator it = hardwareMachine.llSerialPorts.begin();
7878 it != hardwareMachine.llSerialPorts.end();
7879 ++it)
7880 {
7881 const SerialPort &port = *it;
7882 if (port.portMode == PortMode_TCP)
7883 {
7884 m->sv = SettingsVersion_v1_15;
7885 return;
7886 }
7887 }
7888 }
7889
7890 if (m->sv < SettingsVersion_v1_14)
7891 {
7892 // VirtualBox 4.3 adds default frontend setting, graphics controller
7893 // setting, explicit long mode setting, (video) capturing and NAT networking.
7894 if ( !hardwareMachine.strDefaultFrontend.isEmpty()
7895 || hardwareMachine.graphicsAdapter.graphicsControllerType != GraphicsControllerType_VBoxVGA
7896 || hardwareMachine.enmLongMode != Hardware::LongMode_Legacy
7897 || machineUserData.ovIcon.size() > 0
7898 || hardwareMachine.recordingSettings.fEnabled)
7899 {
7900 m->sv = SettingsVersion_v1_14;
7901 return;
7902 }
7903 NetworkAdaptersList::const_iterator netit;
7904 for (netit = hardwareMachine.llNetworkAdapters.begin();
7905 netit != hardwareMachine.llNetworkAdapters.end();
7906 ++netit)
7907 {
7908 if (netit->mode == NetworkAttachmentType_NATNetwork)
7909 {
7910 m->sv = SettingsVersion_v1_14;
7911 break;
7912 }
7913 }
7914 }
7915
7916 if (m->sv < SettingsVersion_v1_14)
7917 {
7918 unsigned cOhciCtrls = 0;
7919 unsigned cEhciCtrls = 0;
7920 bool fNonStdName = false;
7921
7922 for (USBControllerList::const_iterator it = hardwareMachine.usbSettings.llUSBControllers.begin();
7923 it != hardwareMachine.usbSettings.llUSBControllers.end();
7924 ++it)
7925 {
7926 const USBController &ctrl = *it;
7927
7928 switch (ctrl.enmType)
7929 {
7930 case USBControllerType_OHCI:
7931 cOhciCtrls++;
7932 if (ctrl.strName != "OHCI")
7933 fNonStdName = true;
7934 break;
7935 case USBControllerType_EHCI:
7936 cEhciCtrls++;
7937 if (ctrl.strName != "EHCI")
7938 fNonStdName = true;
7939 break;
7940 default:
7941 /* Anything unknown forces a bump. */
7942 fNonStdName = true;
7943 }
7944
7945 /* Skip checking other controllers if the settings bump is necessary. */
7946 if (cOhciCtrls > 1 || cEhciCtrls > 1 || fNonStdName)
7947 {
7948 m->sv = SettingsVersion_v1_14;
7949 break;
7950 }
7951 }
7952 }
7953
7954 if (m->sv < SettingsVersion_v1_13)
7955 {
7956 // VirtualBox 4.2 adds tracing, autostart, UUID in directory and groups.
7957 if ( !debugging.areDefaultSettings()
7958 || !autostart.areDefaultSettings()
7959 || machineUserData.fDirectoryIncludesUUID
7960 || machineUserData.llGroups.size() > 1
7961 || machineUserData.llGroups.front() != "/")
7962 m->sv = SettingsVersion_v1_13;
7963 }
7964
7965 if (m->sv < SettingsVersion_v1_13)
7966 {
7967 // VirtualBox 4.2 changes the units for bandwidth group limits.
7968 for (BandwidthGroupList::const_iterator it = hardwareMachine.ioSettings.llBandwidthGroups.begin();
7969 it != hardwareMachine.ioSettings.llBandwidthGroups.end();
7970 ++it)
7971 {
7972 const BandwidthGroup &gr = *it;
7973 if (gr.cMaxBytesPerSec % _1M)
7974 {
7975 // Bump version if a limit cannot be expressed in megabytes
7976 m->sv = SettingsVersion_v1_13;
7977 break;
7978 }
7979 }
7980 }
7981
7982 if (m->sv < SettingsVersion_v1_12)
7983 {
7984 // VirtualBox 4.1 adds PCI passthrough and emulated USB Smart Card reader
7985 if ( hardwareMachine.pciAttachments.size()
7986 || hardwareMachine.fEmulatedUSBCardReader)
7987 m->sv = SettingsVersion_v1_12;
7988 }
7989
7990 if (m->sv < SettingsVersion_v1_12)
7991 {
7992 // VirtualBox 4.1 adds a promiscuous mode policy to the network
7993 // adapters and a generic network driver transport.
7994 NetworkAdaptersList::const_iterator netit;
7995 for (netit = hardwareMachine.llNetworkAdapters.begin();
7996 netit != hardwareMachine.llNetworkAdapters.end();
7997 ++netit)
7998 {
7999 if ( netit->enmPromiscModePolicy != NetworkAdapterPromiscModePolicy_Deny
8000 || netit->mode == NetworkAttachmentType_Generic
8001 || !netit->areGenericDriverDefaultSettings()
8002 )
8003 {
8004 m->sv = SettingsVersion_v1_12;
8005 break;
8006 }
8007 }
8008 }
8009
8010 if (m->sv < SettingsVersion_v1_11)
8011 {
8012 // VirtualBox 4.0 adds HD audio, CPU priorities, ~fault tolerance~,
8013 // per-machine media registries, VRDE, JRockitVE, bandwidth groups,
8014 // ICH9 chipset
8015 if ( hardwareMachine.audioAdapter.controllerType == AudioControllerType_HDA
8016 || hardwareMachine.ulCpuExecutionCap != 100
8017 || mediaRegistry.llHardDisks.size()
8018 || mediaRegistry.llDvdImages.size()
8019 || mediaRegistry.llFloppyImages.size()
8020 || !hardwareMachine.vrdeSettings.strVrdeExtPack.isEmpty()
8021 || !hardwareMachine.vrdeSettings.strAuthLibrary.isEmpty()
8022 || machineUserData.strOsType == "JRockitVE"
8023 || hardwareMachine.ioSettings.llBandwidthGroups.size()
8024 || hardwareMachine.chipsetType == ChipsetType_ICH9
8025 )
8026 m->sv = SettingsVersion_v1_11;
8027 }
8028
8029 if (m->sv < SettingsVersion_v1_10)
8030 {
8031 /* If the properties contain elements other than "TCP/Ports" and "TCP/Address",
8032 * then increase the version to at least VBox 3.2, which can have video channel properties.
8033 */
8034 unsigned cOldProperties = 0;
8035
8036 StringsMap::const_iterator it = hardwareMachine.vrdeSettings.mapProperties.find("TCP/Ports");
8037 if (it != hardwareMachine.vrdeSettings.mapProperties.end())
8038 cOldProperties++;
8039 it = hardwareMachine.vrdeSettings.mapProperties.find("TCP/Address");
8040 if (it != hardwareMachine.vrdeSettings.mapProperties.end())
8041 cOldProperties++;
8042
8043 if (hardwareMachine.vrdeSettings.mapProperties.size() != cOldProperties)
8044 m->sv = SettingsVersion_v1_10;
8045 }
8046
8047 if (m->sv < SettingsVersion_v1_11)
8048 {
8049 /* If the properties contain elements other than "TCP/Ports", "TCP/Address",
8050 * "VideoChannel/Enabled" and "VideoChannel/Quality" then increase the version to VBox 4.0.
8051 */
8052 unsigned cOldProperties = 0;
8053
8054 StringsMap::const_iterator it = hardwareMachine.vrdeSettings.mapProperties.find("TCP/Ports");
8055 if (it != hardwareMachine.vrdeSettings.mapProperties.end())
8056 cOldProperties++;
8057 it = hardwareMachine.vrdeSettings.mapProperties.find("TCP/Address");
8058 if (it != hardwareMachine.vrdeSettings.mapProperties.end())
8059 cOldProperties++;
8060 it = hardwareMachine.vrdeSettings.mapProperties.find("VideoChannel/Enabled");
8061 if (it != hardwareMachine.vrdeSettings.mapProperties.end())
8062 cOldProperties++;
8063 it = hardwareMachine.vrdeSettings.mapProperties.find("VideoChannel/Quality");
8064 if (it != hardwareMachine.vrdeSettings.mapProperties.end())
8065 cOldProperties++;
8066
8067 if (hardwareMachine.vrdeSettings.mapProperties.size() != cOldProperties)
8068 m->sv = SettingsVersion_v1_11;
8069 }
8070
8071 // settings version 1.9 is required if there is not exactly one DVD
8072 // or more than one floppy drive present or the DVD is not at the secondary
8073 // master; this check is a bit more complicated
8074 //
8075 // settings version 1.10 is required if the host cache should be disabled
8076 //
8077 // settings version 1.11 is required for bandwidth limits and if more than
8078 // one controller of each type is present.
8079 if (m->sv < SettingsVersion_v1_11)
8080 {
8081 // count attached DVDs and floppies (only if < v1.9)
8082 size_t cDVDs = 0;
8083 size_t cFloppies = 0;
8084
8085 // count storage controllers (if < v1.11)
8086 size_t cSata = 0;
8087 size_t cScsiLsi = 0;
8088 size_t cScsiBuslogic = 0;
8089 size_t cSas = 0;
8090 size_t cIde = 0;
8091 size_t cFloppy = 0;
8092
8093 // need to run thru all the storage controllers and attached devices to figure this out
8094 for (StorageControllersList::const_iterator it = hardwareMachine.storage.llStorageControllers.begin();
8095 it != hardwareMachine.storage.llStorageControllers.end();
8096 ++it)
8097 {
8098 const StorageController &sctl = *it;
8099
8100 // count storage controllers of each type; 1.11 is required if more than one
8101 // controller of one type is present
8102 switch (sctl.storageBus)
8103 {
8104 case StorageBus_IDE:
8105 cIde++;
8106 break;
8107 case StorageBus_SATA:
8108 cSata++;
8109 break;
8110 case StorageBus_SAS:
8111 cSas++;
8112 break;
8113 case StorageBus_SCSI:
8114 if (sctl.controllerType == StorageControllerType_LsiLogic)
8115 cScsiLsi++;
8116 else
8117 cScsiBuslogic++;
8118 break;
8119 case StorageBus_Floppy:
8120 cFloppy++;
8121 break;
8122 default:
8123 // Do nothing
8124 break;
8125 }
8126
8127 if ( cSata > 1
8128 || cScsiLsi > 1
8129 || cScsiBuslogic > 1
8130 || cSas > 1
8131 || cIde > 1
8132 || cFloppy > 1)
8133 {
8134 m->sv = SettingsVersion_v1_11;
8135 break; // abort the loop -- we will not raise the version further
8136 }
8137
8138 for (AttachedDevicesList::const_iterator it2 = sctl.llAttachedDevices.begin();
8139 it2 != sctl.llAttachedDevices.end();
8140 ++it2)
8141 {
8142 const AttachedDevice &att = *it2;
8143
8144 // Bandwidth limitations are new in VirtualBox 4.0 (1.11)
8145 if (m->sv < SettingsVersion_v1_11)
8146 {
8147 if (att.strBwGroup.length() != 0)
8148 {
8149 m->sv = SettingsVersion_v1_11;
8150 break; // abort the loop -- we will not raise the version further
8151 }
8152 }
8153
8154 // disabling the host IO cache requires settings version 1.10
8155 if ( (m->sv < SettingsVersion_v1_10)
8156 && (!sctl.fUseHostIOCache)
8157 )
8158 m->sv = SettingsVersion_v1_10;
8159
8160 // we can only write the StorageController/@Instance attribute with v1.9
8161 if ( (m->sv < SettingsVersion_v1_9)
8162 && (sctl.ulInstance != 0)
8163 )
8164 m->sv = SettingsVersion_v1_9;
8165
8166 if (m->sv < SettingsVersion_v1_9)
8167 {
8168 if (att.deviceType == DeviceType_DVD)
8169 {
8170 if ( (sctl.storageBus != StorageBus_IDE) // DVD at bus other than DVD?
8171 || (att.lPort != 1) // DVDs not at secondary master?
8172 || (att.lDevice != 0)
8173 )
8174 m->sv = SettingsVersion_v1_9;
8175
8176 ++cDVDs;
8177 }
8178 else if (att.deviceType == DeviceType_Floppy)
8179 ++cFloppies;
8180 }
8181 }
8182
8183 if (m->sv >= SettingsVersion_v1_11)
8184 break; // abort the loop -- we will not raise the version further
8185 }
8186
8187 // VirtualBox before 3.1 had zero or one floppy and exactly one DVD,
8188 // so any deviation from that will require settings version 1.9
8189 if ( (m->sv < SettingsVersion_v1_9)
8190 && ( (cDVDs != 1)
8191 || (cFloppies > 1)
8192 )
8193 )
8194 m->sv = SettingsVersion_v1_9;
8195 }
8196
8197 // VirtualBox 3.2: Check for non default I/O settings
8198 if (m->sv < SettingsVersion_v1_10)
8199 {
8200 if ( (hardwareMachine.ioSettings.fIOCacheEnabled != true)
8201 || (hardwareMachine.ioSettings.ulIOCacheSize != 5)
8202 // and page fusion
8203 || (hardwareMachine.fPageFusionEnabled)
8204 // and CPU hotplug, RTC timezone control, HID type and HPET
8205 || machineUserData.fRTCUseUTC
8206 || hardwareMachine.fCpuHotPlug
8207 || hardwareMachine.pointingHIDType != PointingHIDType_PS2Mouse
8208 || hardwareMachine.keyboardHIDType != KeyboardHIDType_PS2Keyboard
8209 || hardwareMachine.fHPETEnabled
8210 )
8211 m->sv = SettingsVersion_v1_10;
8212 }
8213
8214 // VirtualBox 3.2 adds NAT and boot priority to the NIC config in Main
8215 // VirtualBox 4.0 adds network bandwitdth
8216 if (m->sv < SettingsVersion_v1_11)
8217 {
8218 NetworkAdaptersList::const_iterator netit;
8219 for (netit = hardwareMachine.llNetworkAdapters.begin();
8220 netit != hardwareMachine.llNetworkAdapters.end();
8221 ++netit)
8222 {
8223 if ( (m->sv < SettingsVersion_v1_12)
8224 && (netit->strBandwidthGroup.isNotEmpty())
8225 )
8226 {
8227 /* New in VirtualBox 4.1 */
8228 m->sv = SettingsVersion_v1_12;
8229 break;
8230 }
8231 else if ( (m->sv < SettingsVersion_v1_10)
8232 && (netit->fEnabled)
8233 && (netit->mode == NetworkAttachmentType_NAT)
8234 && ( netit->nat.u32Mtu != 0
8235 || netit->nat.u32SockRcv != 0
8236 || netit->nat.u32SockSnd != 0
8237 || netit->nat.u32TcpRcv != 0
8238 || netit->nat.u32TcpSnd != 0
8239 || !netit->nat.fDNSPassDomain
8240 || netit->nat.fDNSProxy
8241 || netit->nat.fDNSUseHostResolver
8242 || netit->nat.fAliasLog
8243 || netit->nat.fAliasProxyOnly
8244 || netit->nat.fAliasUseSamePorts
8245 || netit->nat.strTFTPPrefix.length()
8246 || netit->nat.strTFTPBootFile.length()
8247 || netit->nat.strTFTPNextServer.length()
8248 || netit->nat.mapRules.size()
8249 )
8250 )
8251 {
8252 m->sv = SettingsVersion_v1_10;
8253 // no break because we still might need v1.11 above
8254 }
8255 else if ( (m->sv < SettingsVersion_v1_10)
8256 && (netit->fEnabled)
8257 && (netit->ulBootPriority != 0)
8258 )
8259 {
8260 m->sv = SettingsVersion_v1_10;
8261 // no break because we still might need v1.11 above
8262 }
8263 }
8264 }
8265
8266 // all the following require settings version 1.9
8267 if ( (m->sv < SettingsVersion_v1_9)
8268 && ( (hardwareMachine.firmwareType >= FirmwareType_EFI)
8269 || machineUserData.fTeleporterEnabled
8270 || machineUserData.uTeleporterPort
8271 || !machineUserData.strTeleporterAddress.isEmpty()
8272 || !machineUserData.strTeleporterPassword.isEmpty()
8273 || (!hardwareMachine.uuid.isZero() && hardwareMachine.uuid.isValid())
8274 )
8275 )
8276 m->sv = SettingsVersion_v1_9;
8277
8278 // "accelerate 2d video" requires settings version 1.8
8279 if ( (m->sv < SettingsVersion_v1_8)
8280 && (hardwareMachine.graphicsAdapter.fAccelerate2DVideo)
8281 )
8282 m->sv = SettingsVersion_v1_8;
8283
8284 // The hardware versions other than "1" requires settings version 1.4 (2.1+).
8285 if ( m->sv < SettingsVersion_v1_4
8286 && hardwareMachine.strVersion != "1"
8287 )
8288 m->sv = SettingsVersion_v1_4;
8289}
8290
8291/**
8292 * Called from Main code to write a machine config file to disk. This builds a DOM tree from
8293 * the member variables and then writes the XML file; it throws xml::Error instances on errors,
8294 * in particular if the file cannot be written.
8295 */
8296void MachineConfigFile::write(const com::Utf8Str &strFilename)
8297{
8298 try
8299 {
8300 // createStubDocument() sets the settings version to at least 1.7; however,
8301 // we might need to enfore a later settings version if incompatible settings
8302 // are present:
8303 bumpSettingsVersionIfNeeded();
8304
8305 m->strFilename = strFilename;
8306 specialBackupIfFirstBump();
8307 createStubDocument();
8308
8309 xml::ElementNode *pelmMachine = m->pelmRoot->createChild("Machine");
8310 buildMachineXML(*pelmMachine,
8311 MachineConfigFile::BuildMachineXML_IncludeSnapshots
8312 | MachineConfigFile::BuildMachineXML_MediaRegistry,
8313 // but not BuildMachineXML_WriteVBoxVersionAttribute
8314 NULL); /* pllElementsWithUuidAttributes */
8315
8316 // now go write the XML
8317 xml::XmlFileWriter writer(*m->pDoc);
8318 writer.write(m->strFilename.c_str(), true /*fSafe*/);
8319
8320 m->fFileExists = true;
8321 clearDocument();
8322 }
8323 catch (...)
8324 {
8325 clearDocument();
8326 throw;
8327 }
8328}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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