Changeset 64541 in vbox
- Timestamp:
- Nov 3, 2016 7:13:53 PM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 111725
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/settings.h
r62602 r64541 233 233 234 234 static const char *stringifyMediaType(MediaType t); 235 SettingsVersion_T parseVersion(const com::Utf8Str &strVersion); 235 SettingsVersion_T parseVersion(const com::Utf8Str &strVersion, 236 const xml::ElementNode *pElm); 236 237 void parseUUID(com::Guid &guid, 237 const com::Utf8Str &strUUID) const; 238 const com::Utf8Str &strUUID, 239 const xml::ElementNode *pElm) const; 238 240 void parseTimestamp(RTTIMESPEC ×tamp, 239 const com::Utf8Str &str) const; 241 const com::Utf8Str &str, 242 const xml::ElementNode *pElm) const; 240 243 void parseBase64(IconBlob &binary, 241 const com::Utf8Str &str) const; 244 const com::Utf8Str &str, 245 const xml::ElementNode *pElm) const; 242 246 com::Utf8Str stringifyTimestamp(const RTTIMESPEC &tm) const; 243 247 void toBase64(com::Utf8Str &str, … … 255 259 256 260 void setVersionAttribute(xml::ElementNode &elm); 261 void specialBackupIfFirstBump(); 257 262 void createStubDocument(); 258 263 -
trunk/src/VBox/Main/xml/Settings.cpp
r64517 r64541 105 105 #define VBOX_XML_VERSION "1.12" 106 106 107 /** VirtualBox OVF settings import default version number substring ("x.y"). 108 * 109 * Think twice before changing this, as all VirtualBox versions before 5.1 110 * wrote the settings version when exporting, but totally ignored it on 111 * importing (while it should have been a mandatory attribute), so 3rd party 112 * software out there creates OVF files with the VirtualBox specific settings 113 * but lacking the version attribute. This shouldn't happen any more, but 114 * breaking existing OVF files isn't nice. */ 115 #define VBOX_XML_IMPORT_VERSION "1.15" 116 107 117 /** VirtualBox XML settings version platform substring */ 108 118 #if defined (RT_OS_DARWIN) … … 129 139 #define VBOX_XML_VERSION_FULL VBOX_XML_VERSION "-" VBOX_XML_PLATFORM 130 140 141 /** VirtualBox OVF import default settings full version string ("x.y-platform") */ 142 #define VBOX_XML_IMPORT_VERSION_FULL VBOX_XML_IMPORT_VERSION "-" VBOX_XML_PLATFORM 143 131 144 //////////////////////////////////////////////////////////////////////////////// 132 145 // … … 248 261 m->pelmRoot = m->pDoc->getRootElement(); 249 262 if (!m->pelmRoot || !m->pelmRoot->nameEquals("VirtualBox")) 250 throw ConfigFileError(this, NULL, N_("Root element in VirtualBox settings files must be \"VirtualBox\"."));263 throw ConfigFileError(this, m->pelmRoot, N_("Root element in VirtualBox settings files must be \"VirtualBox\"")); 251 264 252 265 if (!(m->pelmRoot->getAttributeValue("version", m->strSettingsVersionFull))) … … 255 268 LogRel(("Loading settings file \"%s\" with version \"%s\"\n", m->strFilename.c_str(), m->strSettingsVersionFull.c_str())); 256 269 257 m->sv = parseVersion(m->strSettingsVersionFull );270 m->sv = parseVersion(m->strSettingsVersionFull, m->pelmRoot); 258 271 259 272 // remember the settings version we read in case it gets upgraded later, … … 316 329 * @returns settings version 317 330 * @param strVersion 318 */ 319 SettingsVersion_T ConfigFileBase::parseVersion(const Utf8Str &strVersion) 331 * @param pElm 332 */ 333 SettingsVersion_T ConfigFileBase::parseVersion(const Utf8Str &strVersion, const xml::ElementNode *pElm) 320 334 { 321 335 SettingsVersion_T sv = SettingsVersion_Null; … … 389 403 390 404 if (sv == SettingsVersion_Null) 391 throw ConfigFileError(this, NULL, N_("Cannot handle settings version '%s'"), strVersion.c_str());405 throw ConfigFileError(this, pElm, N_("Cannot handle settings version '%s'"), strVersion.c_str()); 392 406 393 407 return sv; … … 400 414 * @param guid 401 415 * @param strUUID 416 * @param pElm 402 417 */ 403 418 void ConfigFileBase::parseUUID(Guid &guid, 404 const Utf8Str &strUUID) const 419 const Utf8Str &strUUID, 420 const xml::ElementNode *pElm) const 405 421 { 406 422 guid = strUUID.c_str(); 407 423 if (guid.isZero()) 408 throw ConfigFileError(this, NULL, N_("UUID \"%s\" has zero format"), strUUID.c_str());424 throw ConfigFileError(this, pElm, N_("UUID \"%s\" has zero format"), strUUID.c_str()); 409 425 else if (!guid.isValid()) 410 throw ConfigFileError(this, NULL, N_("UUID \"%s\" has invalid format"), strUUID.c_str());426 throw ConfigFileError(this, pElm, N_("UUID \"%s\" has invalid format"), strUUID.c_str()); 411 427 } 412 428 … … 416 432 * @param timestamp 417 433 * @param str 434 * @param pElm 418 435 */ 419 436 void ConfigFileBase::parseTimestamp(RTTIMESPEC ×tamp, 420 const com::Utf8Str &str) const 437 const com::Utf8Str &str, 438 const xml::ElementNode *pElm) const 421 439 { 422 440 const char *pcsz = str.c_str(); … … 431 449 && (pcsz[19] != 'Z') 432 450 ) 433 throw ConfigFileError(this, NULL, N_("Cannot handle ISO timestamp '%s': is not UTC date"), str.c_str());451 throw ConfigFileError(this, pElm, N_("Cannot handle ISO timestamp '%s': is not UTC date"), str.c_str()); 434 452 435 453 int32_t yyyy; … … 472 490 } 473 491 474 throw ConfigFileError(this, NULL, N_("Cannot parse ISO timestamp '%s': runtime error, %Rra"), str.c_str(), rc);475 } 476 477 throw ConfigFileError(this, NULL, N_("Cannot parse ISO timestamp '%s': invalid format"), str.c_str());492 throw ConfigFileError(this, pElm, N_("Cannot parse ISO timestamp '%s': runtime error, %Rra"), str.c_str(), rc); 493 } 494 495 throw ConfigFileError(this, pElm, N_("Cannot parse ISO timestamp '%s': invalid format"), str.c_str()); 478 496 } 479 497 } … … 481 499 /** 482 500 * Helper function that parses a Base64 formatted string into a binary blob. 483 * @param guid 484 * @param strUUID 501 * @param binary 502 * @param str 503 * @param pElm 485 504 */ 486 505 void ConfigFileBase::parseBase64(IconBlob &binary, 487 const Utf8Str &str) const 506 const Utf8Str &str, 507 const xml::ElementNode *pElm) const 488 508 { 489 509 #define DECODE_STR_MAX _1M … … 491 511 ssize_t cbOut = RTBase64DecodedSize(psz, NULL); 492 512 if (cbOut > DECODE_STR_MAX) 493 throw ConfigFileError(this, NULL, N_("Base64 encoded data too long (%d > %d)"), cbOut, DECODE_STR_MAX);513 throw ConfigFileError(this, pElm, N_("Base64 encoded data too long (%d > %d)"), cbOut, DECODE_STR_MAX); 494 514 else if (cbOut < 0) 495 throw ConfigFileError(this, NULL, N_("Base64 encoded data '%s' invalid"), psz);515 throw ConfigFileError(this, pElm, N_("Base64 encoded data '%s' invalid"), psz); 496 516 binary.resize(cbOut); 497 517 int vrc = VINF_SUCCESS; … … 501 521 { 502 522 binary.resize(0); 503 throw ConfigFileError(this, NULL, N_("Base64 encoded data could not be decoded (%Rrc)"), vrc);523 throw ConfigFileError(this, pElm, N_("Base64 encoded data could not be decoded (%Rrc)"), vrc); 504 524 } 505 525 } … … 643 663 throw ConfigFileError(this, &elmMedium, N_("Required %s/@uuid attribute is missing"), elmMedium.getName()); 644 664 645 parseUUID(med.uuid, strUUID );665 parseUUID(med.uuid, strUUID, &elmMedium); 646 666 647 667 bool fNeedsLocation = true; … … 1018 1038 } 1019 1039 1020 elm.setAttribute("version",Utf8StrFmt("%s-%s",1040 m->strSettingsVersionFull = Utf8StrFmt("%s-%s", 1021 1041 pcszVersion, 1022 VBOX_XML_PLATFORM)); // e.g. "linux" 1042 VBOX_XML_PLATFORM); // e.g. "linux" 1043 elm.setAttribute("version", m->strSettingsVersionFull); 1044 } 1045 1046 1047 /** 1048 * Creates a special backup file in case there is a version 1049 * bump, so that it is possible to go back to the previous 1050 * state. This is done only once (not for every settings 1051 * version bump), when the settings version is newer than 1052 * the version read from the config file. Must be called 1053 * before ConfigFileBase::createStubDocument, because that 1054 * method may alter information which this method needs. 1055 */ 1056 void ConfigFileBase::specialBackupIfFirstBump() 1057 { 1058 // Since this gets called before the XML document is actually written out, 1059 // this is where we must check whether we're upgrading the settings version 1060 // and need to make a backup, so the user can go back to an earlier 1061 // VirtualBox version and recover his old settings files. 1062 if ( (m->svRead != SettingsVersion_Null) // old file exists? 1063 && (m->svRead < m->sv) // we're upgrading? 1064 ) 1065 { 1066 // compose new filename: strip off trailing ".xml"/".vbox" 1067 Utf8Str strFilenameNew; 1068 Utf8Str strExt = ".xml"; 1069 if (m->strFilename.endsWith(".xml")) 1070 strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 4); 1071 else if (m->strFilename.endsWith(".vbox")) 1072 { 1073 strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 5); 1074 strExt = ".vbox"; 1075 } 1076 1077 // and append something like "-1.3-linux.xml" 1078 strFilenameNew.append("-"); 1079 strFilenameNew.append(m->strSettingsVersionFull); // e.g. "1.3-linux" 1080 strFilenameNew.append(strExt); // .xml for main config, .vbox for machine config 1081 1082 // Copying the file cannot be avoided, as doing tricks with renaming 1083 // causes trouble on OS X with aliases (which follow the rename), and 1084 // on all platforms there is a risk of "losing" the VM config when 1085 // running out of space, as a rename here couldn't be rolled back. 1086 // Ignoring all errors besides running out of space is intentional, as 1087 // we don't want to do anything if the file already exists. 1088 int vrc = RTFileCopy(m->strFilename.c_str(), strFilenameNew.c_str()); 1089 if (RT_UNLIKELY(vrc == VERR_DISK_FULL)) 1090 throw ConfigFileError(this, NULL, N_("Cannot create settings backup file when upgrading to a newer settings format")); 1091 1092 // do this only once 1093 m->svRead = SettingsVersion_Null; 1094 } 1023 1095 } 1024 1096 … … 1032 1104 * set the "sv" member to the required settings version that is to 1033 1105 * be written. For newly created files, the settings version will be 1034 * the latest (1.12); for files read in from disk earlier, it will be1035 * the settings version indicated in the file. However, this method1036 * will silently make sure that the settings version is always1037 * at least 1.7 and change it if necessary, since there is no write1038 * support for earlier settings versions.1106 * recent (1.12 or later if necessary); for files read in from disk 1107 * earlier, it will be the settings version indicated in the file. 1108 * However, this method will silently make sure that the settings 1109 * version is always at least 1.7 and change it if necessary, since 1110 * there is no write support for earlier settings versions. 1039 1111 */ 1040 1112 void ConfigFileBase::createStubDocument() … … 1058 1130 #endif 1059 1131 1060 // add settings version attribute to root element 1132 // add settings version attribute to root element, update m->strSettingsVersionFull 1061 1133 setVersionAttribute(*m->pelmRoot); 1062 1134 1063 // since this gets called before the XML document is actually written out, 1064 // this is where we must check whether we're upgrading the settings version 1065 // and need to make a backup, so the user can go back to an earlier 1066 // VirtualBox version and recover his old settings files. 1067 if ( (m->svRead != SettingsVersion_Null) // old file exists? 1068 && (m->svRead < m->sv) // we're upgrading? 1069 ) 1070 { 1071 // compose new filename: strip off trailing ".xml"/".vbox" 1072 Utf8Str strFilenameNew; 1073 Utf8Str strExt = ".xml"; 1074 if (m->strFilename.endsWith(".xml")) 1075 strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 4); 1076 else if (m->strFilename.endsWith(".vbox")) 1077 { 1078 strFilenameNew = m->strFilename.substr(0, m->strFilename.length() - 5); 1079 strExt = ".vbox"; 1080 } 1081 1082 // and append something like "-1.3-linux.xml" 1083 strFilenameNew.append("-"); 1084 strFilenameNew.append(m->strSettingsVersionFull); // e.g. "1.3-linux" 1085 strFilenameNew.append(strExt); // .xml for main config, .vbox for machine config 1086 1087 RTFileMove(m->strFilename.c_str(), 1088 strFilenameNew.c_str(), 1089 0); // no RTFILEMOVE_FLAGS_REPLACE 1090 1091 // do this only once 1092 m->svRead = SettingsVersion_Null; 1093 } 1135 LogRel(("Saving settings file \"%s\" with version \"%s\"\n", m->strFilename.c_str(), m->strSettingsVersionFull.c_str())); 1094 1136 } 1095 1137 … … 1616 1658 && pelmChild1->getAttributeValue("src", mre.strSettingsFile) ) 1617 1659 { 1618 parseUUID(mre.uuid, strUUID );1660 parseUUID(mre.uuid, strUUID, pelmChild1); 1619 1661 llMachines.push_back(mre); 1620 1662 } … … 1940 1982 1941 1983 m->strFilename = strFilename; 1984 specialBackupIfFirstBump(); 1942 1985 createStubDocument(); 1943 1986 … … 3205 3248 // version when they switch to the newer settings style/defaults of 5.1. 3206 3249 if (!(elmMachine.getAttributeValue("version", m->strSettingsVersionFull))) 3207 m->strSettingsVersionFull = "1.15";3250 m->strSettingsVersionFull = VBOX_XML_IMPORT_VERSION_FULL; 3208 3251 3209 3252 LogRel(("Import settings with version \"%s\"\n", m->strSettingsVersionFull.c_str())); 3210 3253 3211 m->sv = parseVersion(m->strSettingsVersionFull );3254 m->sv = parseVersion(m->strSettingsVersionFull, &elmMachine); 3212 3255 3213 3256 // remember the settings version we read in case it gets upgraded later, … … 3778 3821 Utf8Str strUUID; 3779 3822 if (elmHardware.getAttributeValue("uuid", strUUID)) 3780 parseUUID(hw.uuid, strUUID );3823 parseUUID(hw.uuid, strUUID, &elmHardware); 3781 3824 3782 3825 xml::NodesLoop nl1(elmHardware); … … 4491 4534 if (!pelmAttachment->getAttributeValue("hardDisk", strUUID)) 4492 4535 throw ConfigFileError(this, pelmAttachment, N_("Required HardDiskAttachment/@hardDisk attribute is missing")); 4493 parseUUID(att.uuid, strUUID );4536 parseUUID(att.uuid, strUUID, pelmAttachment); 4494 4537 4495 4538 if (!pelmAttachment->getAttributeValue("bus", strBus)) … … 4675 4718 if (!pelmImage->getAttributeValue("uuid", strTemp)) 4676 4719 throw ConfigFileError(this, pelmImage, N_("Required AttachedDevice/Image/@uuid attribute is missing")); 4677 parseUUID(att.uuid, strTemp );4720 parseUUID(att.uuid, strTemp, pelmImage); 4678 4721 } 4679 4722 … … 4732 4775 if ( (pDriveChild = pelmHwChild->findChildElement("Image")) != NULL 4733 4776 && pDriveChild->getAttributeValue("uuid", strTmp)) 4734 parseUUID(att.uuid, strTmp );4777 parseUUID(att.uuid, strTmp, pDriveChild); 4735 4778 else if ((pDriveChild = pelmHwChild->findChildElement("HostDrive"))) 4736 4779 pDriveChild->getAttributeValue("src", att.strHostDriveSrc); … … 4778 4821 if ( (pDriveChild = pelmHwChild->findChildElement("Image")) 4779 4822 && pDriveChild->getAttributeValue("uuid", strTmp) ) 4780 parseUUID(att.uuid, strTmp );4823 parseUUID(att.uuid, strTmp, pDriveChild); 4781 4824 else if ((pDriveChild = pelmHwChild->findChildElement("HostDrive"))) 4782 4825 pDriveChild->getAttributeValue("src", att.strHostDriveSrc); … … 4901 4944 if (!elmSnapshot.getAttributeValue("uuid", strTemp)) 4902 4945 throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@uuid attribute is missing")); 4903 parseUUID(snap.uuid, strTemp );4946 parseUUID(snap.uuid, strTemp, &elmSnapshot); 4904 4947 bool foundCurrentSnapshot = (snap.uuid == curSnapshotUuid); 4905 4948 … … 4912 4955 if (!elmSnapshot.getAttributeValue("timeStamp", strTemp)) 4913 4956 throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@timeStamp attribute is missing")); 4914 parseTimestamp(snap.timestamp, strTemp );4957 parseTimestamp(snap.timestamp, strTemp, &elmSnapshot); 4915 4958 4916 4959 elmSnapshot.getAttributeValuePath("stateFile", snap.strStateFile); // online snapshots only … … 5032 5075 && elmMachine.getAttributeValue("name", machineUserData.strName)) 5033 5076 { 5034 parseUUID(uuid, strUUID );5077 parseUUID(uuid, strUUID, &elmMachine); 5035 5078 5036 5079 elmMachine.getAttributeValue("directoryIncludesUUID", machineUserData.fDirectoryIncludesUUID); … … 5046 5089 5047 5090 if (elmMachine.getAttributeValue("currentSnapshot", str)) 5048 parseUUID(uuidCurrentSnapshot, str );5091 parseUUID(uuidCurrentSnapshot, str, &elmMachine); 5049 5092 5050 5093 elmMachine.getAttributeValuePath("snapshotFolder", machineUserData.strSnapshotFolder); … … 5053 5096 fCurrentStateModified = true; 5054 5097 if (elmMachine.getAttributeValue("lastStateChange", str)) 5055 parseTimestamp(timeLastStateChange, str );5098 parseTimestamp(timeLastStateChange, str, &elmMachine); 5056 5099 // constructor has called RTTimeNow(&timeLastStateChange) before 5057 5100 if (elmMachine.getAttributeValue("aborted", fAborted)) … … 5062 5105 str.setNull(); 5063 5106 elmMachine.getAttributeValue("icon", str); 5064 parseBase64(machineUserData.ovIcon, str );5107 parseBase64(machineUserData.ovIcon, str, &elmMachine); 5065 5108 5066 5109 // parse Hardware before the other elements because other things depend on it … … 6623 6666 { 6624 6667 if (fl & BuildMachineXML_WriteVBoxVersionAttribute) 6668 { 6625 6669 // add settings version attribute to machine element 6626 6670 setVersionAttribute(elmMachine); 6671 LogRel(("Exporting settings file \"%s\" with version \"%s\"\n", m->strFilename.c_str(), m->strSettingsVersionFull.c_str())); 6672 } 6627 6673 6628 6674 elmMachine.setAttribute("uuid", uuid.toStringCurly()); … … 7356 7402 7357 7403 m->strFilename = strFilename; 7404 specialBackupIfFirstBump(); 7358 7405 createStubDocument(); 7359 7406
Note:
See TracChangeset
for help on using the changeset viewer.