From aacd6b677332f2e262d0df67603c246cd65d833e Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Mon, 1 Aug 2022 17:07:25 -0500 Subject: Store list of persisted well-known variables in Burn. This allows it to reject Variables declared in the manifest that start with the reserved prefix 'Wix'. --- src/burn/engine/approvedexe.h | 9 -- src/burn/engine/core.h | 7 +- src/burn/engine/logging.cpp | 41 ++++-- src/burn/engine/logging.h | 4 + src/burn/engine/manifest.cpp | 22 +--- src/burn/engine/package.cpp | 8 ++ src/burn/engine/package.h | 1 + src/burn/engine/platform.h | 10 ++ src/burn/engine/registration.cpp | 2 +- src/burn/engine/variable.cpp | 140 +++++++++++++++++---- src/burn/engine/variable.h | 1 + src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj | 1 + .../test/BurnUnitTest/BurnUnitTest.vcxproj.filters | 3 + src/burn/test/BurnUnitTest/LoggingTest.cpp | 68 ++++++++++ src/burn/test/BurnUnitTest/ManifestTest.cpp | 6 +- .../BasicFunctionality_BundleA_manifest.xml | 2 +- .../PlanTest/BundlePackage_Multiple_manifest.xml | 2 +- .../ExePackage_PerUserArpEntry_manifest.xml | 2 +- .../TestData/PlanTest/Failure_BundleD_manifest.xml | 2 +- .../PlanTest/MsiTransaction_BundleAv1_manifest.xml | 2 +- .../PlanTest/MsuPackageFixture_manifest.xml | 2 +- .../PlanTest/Slipstream_BundleA_manifest.xml | 2 +- .../Slipstream_BundleA_modified_manifest.xml | 2 +- src/burn/test/BurnUnitTest/VariableTest.cpp | 37 ++++++ 24 files changed, 300 insertions(+), 76 deletions(-) create mode 100644 src/burn/test/BurnUnitTest/LoggingTest.cpp (limited to 'src/burn') diff --git a/src/burn/engine/approvedexe.h b/src/burn/engine/approvedexe.h index cbfda601..7a68c174 100644 --- a/src/burn/engine/approvedexe.h +++ b/src/burn/engine/approvedexe.h @@ -6,15 +6,6 @@ extern "C" { #endif -// forward declare - -enum BURN_MODE; -typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT; -typedef struct _BURN_CACHE BURN_CACHE; -typedef struct _BURN_DEPENDENCIES BURN_DEPENDENCIES; -typedef struct _BURN_ENGINE_COMMAND BURN_ENGINE_COMMAND; -typedef struct _BURN_LOGGING BURN_LOGGING; - // structs typedef struct _BURN_APPROVED_EXE diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h index 31f63ed4..c75d42de 100644 --- a/src/burn/engine/core.h +++ b/src/burn/engine/core.h @@ -38,7 +38,6 @@ const LPCWSTR BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN = L"burn.splash.screen"; const LPCWSTR BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT = L"burn.system.component"; const LPCWSTR BURN_COMMANDLINE_SWITCH_PREFIX = L"burn."; -const LPCWSTR BURN_BUNDLE_LAYOUT_DIRECTORY = L"WixBundleLayoutDirectory"; const LPCWSTR BURN_BUNDLE_ACTION = L"WixBundleAction"; const LPCWSTR BURN_BUNDLE_ACTIVE_PARENT = L"WixBundleActiveParent"; const LPCWSTR BURN_BUNDLE_COMMAND_LINE_ACTION = L"WixBundleCommandLineAction"; @@ -48,17 +47,17 @@ const LPCWSTR BURN_BUNDLE_FORCED_RESTART_PACKAGE = L"WixBundleForcedRestartPacka const LPCWSTR BURN_BUNDLE_INSTALLED = L"WixBundleInstalled"; const LPCWSTR BURN_BUNDLE_ELEVATED = L"WixBundleElevated"; const LPCWSTR BURN_BUNDLE_PROVIDER_KEY = L"WixBundleProviderKey"; -const LPCWSTR BURN_BUNDLE_MANUFACTURER = L"WixBundleManufacturer"; const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_PATH = L"WixBundleSourceProcessPath"; const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_FOLDER = L"WixBundleSourceProcessFolder"; const LPCWSTR BURN_BUNDLE_TAG = L"WixBundleTag"; const LPCWSTR BURN_BUNDLE_UILEVEL = L"WixBundleUILevel"; const LPCWSTR BURN_BUNDLE_VERSION = L"WixBundleVersion"; -const LPCWSTR BURN_REBOOT_PENDING = L"RebootPending"; -// The following constants must stay in sync with src\api\wix\WixToolset.Data\Burn\BurnConstants.cs +// The following well-known variables are settable by the BA. +const LPCWSTR BURN_BUNDLE_LAYOUT_DIRECTORY = L"WixBundleLayoutDirectory"; const LPCWSTR BURN_BUNDLE_NAME = L"WixBundleName"; const LPCWSTR BURN_BUNDLE_INPROGRESS_NAME = L"WixBundleInProgressName"; +const LPCWSTR BURN_BUNDLE_MANUFACTURER = L"WixBundleManufacturer"; const LPCWSTR BURN_BUNDLE_ORIGINAL_SOURCE = L"WixBundleOriginalSource"; const LPCWSTR BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER = L"WixBundleOriginalSourceFolder"; const LPCWSTR BURN_BUNDLE_LAST_USED_SOURCE = L"WixBundleLastUsedSource"; diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 68f0c35b..ae056921 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -28,6 +28,37 @@ static HRESULT GetNonSessionSpecificTempFolder( // function definitions +extern "C" HRESULT LoggingParseFromXml( + __in BURN_LOGGING* pLog, + __in IXMLDOMNode* pixnBundle + ) +{ + HRESULT hr = S_OK; + IXMLDOMNode* pixnLog = NULL; + BOOL fXmlFound = FALSE; + + // parse the log element, if present. + hr = XmlSelectSingleNode(pixnBundle, L"Log", &pixnLog); + ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get Log element."); + + if (fXmlFound) + { + hr = XmlGetAttributeEx(pixnLog, L"PathVariable", &pLog->sczPathVariable); + ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get Log/@PathVariable."); + + hr = XmlGetAttributeEx(pixnLog, L"Prefix", &pLog->sczPrefix); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get Log/@Prefix attribute."); + + hr = XmlGetAttributeEx(pixnLog, L"Extension", &pLog->sczExtension); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get Log/@Extension attribute."); + } + +LExit: + ReleaseObject(pixnLog); + + return hr; +} + extern "C" HRESULT LoggingOpen( __in BURN_LOGGING* pLog, __in BURN_ENGINE_COMMAND* pInternalCommand, @@ -244,7 +275,6 @@ extern "C" HRESULT LoggingSetCompatiblePackageVariable( ) { HRESULT hr = S_OK; - LPWSTR sczLogPathVariable = NULL; LPWSTR sczLogPath = NULL; // Make sure that no package log files are created when logging has been disabled via Log element. @@ -253,16 +283,12 @@ extern "C" HRESULT LoggingSetCompatiblePackageVariable( ExitFunction(); } - if (pPackage->sczLogPathVariable && *pPackage->sczLogPathVariable) + if (pPackage->sczCompatibleLogPathVariable && *pPackage->sczCompatibleLogPathVariable) { - // Format a suitable log path variable from the original package. - hr = StrAllocFormatted(&sczLogPathVariable, L"%ls_Compatible", pPackage->sczLogPathVariable); - ExitOnFailure(hr, "Failed to format log path variable for compatible package."); - hr = StrAllocFormatted(&sczLogPath, L"%ls_%03u_%ls_%ls.%ls", pLog->sczPrefix, vdwPackageSequence, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pLog->sczExtension); ExitOnFailure(hr, "Failed to allocate path for package log."); - hr = VariableSetString(pVariables, sczLogPathVariable, sczLogPath, FALSE, FALSE); + hr = VariableSetString(pVariables, pPackage->sczCompatibleLogPathVariable, sczLogPath, FALSE, FALSE); ExitOnFailure(hr, "Failed to set log path into variable."); if (psczLogPath) @@ -273,7 +299,6 @@ extern "C" HRESULT LoggingSetCompatiblePackageVariable( } LExit: - ReleaseStr(sczLogPathVariable); ReleaseStr(sczLogPath); return hr; diff --git a/src/burn/engine/logging.h b/src/burn/engine/logging.h index 000b04f8..5597bb57 100644 --- a/src/burn/engine/logging.h +++ b/src/burn/engine/logging.h @@ -41,6 +41,10 @@ typedef struct _BURN_LOGGING // function declarations +HRESULT LoggingParseFromXml( + __in BURN_LOGGING* pLog, + __in IXMLDOMNode* pixnBundle + ); HRESULT LoggingOpen( __in BURN_LOGGING* pLog, __in BURN_ENGINE_COMMAND* pInternalCommand, diff --git a/src/burn/engine/manifest.cpp b/src/burn/engine/manifest.cpp index 0cd10dbb..c0d67c19 100644 --- a/src/burn/engine/manifest.cpp +++ b/src/burn/engine/manifest.cpp @@ -67,31 +67,14 @@ static HRESULT ParseFromXml( { HRESULT hr = S_OK; IXMLDOMElement* pixeBundle = NULL; - IXMLDOMNode* pixnLog = NULL; IXMLDOMNode* pixnChain = NULL; // get bundle element hr = pixdDocument->get_documentElement(&pixeBundle); ExitOnFailure(hr, "Failed to get bundle element."); - // parse the log element, if present. - hr = XmlSelectSingleNode(pixeBundle, L"Log", &pixnLog); - ExitOnFailure(hr, "Failed to get Log element."); - - if (S_OK == hr) - { - hr = XmlGetAttributeEx(pixnLog, L"PathVariable", &pEngineState->log.sczPathVariable); - if (E_NOTFOUND != hr) - { - ExitOnFailure(hr, "Failed to get Log/@PathVariable."); - } - - hr = XmlGetAttributeEx(pixnLog, L"Prefix", &pEngineState->log.sczPrefix); - ExitOnFailure(hr, "Failed to get Log/@Prefix attribute."); - - hr = XmlGetAttributeEx(pixnLog, L"Extension", &pEngineState->log.sczExtension); - ExitOnFailure(hr, "Failed to get Log/@Extension attribute."); - } + hr = LoggingParseFromXml(&pEngineState->log, pixeBundle); + ExitOnFailure(hr, "Failed to parse logging."); // get the chain element hr = XmlSelectSingleNode(pixeBundle, L"Chain", &pixnChain); @@ -167,7 +150,6 @@ static HRESULT ParseFromXml( LExit: ReleaseObject(pixnChain); - ReleaseObject(pixnLog); ReleaseObject(pixeBundle); return hr; } diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp index c56f74c8..fe8af497 100644 --- a/src/burn/engine/package.cpp +++ b/src/burn/engine/package.cpp @@ -174,6 +174,13 @@ extern "C" HRESULT PackagesParseFromXml( hr = XmlGetAttributeEx(pixnNode, L"RollbackLogPathVariable", &pPackage->sczRollbackLogPathVariable); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RollbackLogPathVariable."); + if (pPackage->sczLogPathVariable && *pPackage->sczLogPathVariable) + { + // Format a suitable log path variable from the original package. + hr = StrAllocFormatted(&pPackage->sczCompatibleLogPathVariable, L"%ls_Compatible", pPackage->sczLogPathVariable); + ExitOnFailure(hr, "Failed to format log path variable for compatible package."); + } + // @InstallCondition hr = XmlGetAttributeEx(pixnNode, L"InstallCondition", &pPackage->sczInstallCondition); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallCondition."); @@ -365,6 +372,7 @@ extern "C" void PackageUninitialize( ReleaseStr(pPackage->sczId); ReleaseStr(pPackage->sczLogPathVariable); ReleaseStr(pPackage->sczRollbackLogPathVariable); + ReleaseStr(pPackage->sczCompatibleLogPathVariable); ReleaseStr(pPackage->sczInstallCondition); ReleaseStr(pPackage->sczRepairCondition); ReleaseStr(pPackage->sczCacheId); diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index e8d49e53..e45c775d 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -262,6 +262,7 @@ typedef struct _BURN_PACKAGE LPWSTR sczLogPathVariable; // name of the variable that will be set to the log path. LPWSTR sczRollbackLogPathVariable; // name of the variable that will be set to the rollback path. + LPWSTR sczCompatibleLogPathVariable; LPWSTR sczInstallCondition; LPWSTR sczRepairCondition; diff --git a/src/burn/engine/platform.h b/src/burn/engine/platform.h index 876b02c2..49d8f3e9 100644 --- a/src/burn/engine/platform.h +++ b/src/burn/engine/platform.h @@ -8,6 +8,16 @@ extern "C" { #endif +// forward declare + +enum BURN_MODE; +typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT; +typedef struct _BURN_CACHE BURN_CACHE; +typedef struct _BURN_DEPENDENCIES BURN_DEPENDENCIES; +typedef struct _BURN_ENGINE_COMMAND BURN_ENGINE_COMMAND; +typedef struct _BURN_LOGGING BURN_LOGGING; +typedef struct _BURN_PACKAGES BURN_PACKAGES; + // typedefs diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp index d0e5c677..484c08ac 100644 --- a/src/burn/engine/registration.cpp +++ b/src/burn/engine/registration.cpp @@ -443,7 +443,7 @@ extern "C" HRESULT RegistrationSetDynamicVariables( hr = VariableSetNumeric(pVariables, BURN_BUNDLE_INSTALLED, llInstalled, TRUE); ExitOnFailure(hr, "Failed to set the bundle installed built-in variable."); - hr = VariableSetNumeric(pVariables, BURN_REBOOT_PENDING, IsWuRebootPending() || IsRegistryRebootPending(), TRUE); + hr = VariableSetNumeric(pVariables, VARIABLE_REBOOTPENDING, IsWuRebootPending() || IsRegistryRebootPending(), TRUE); ExitOnFailure(hr, "Failed to overwrite the bundle reboot-pending built-in variable."); LExit: diff --git a/src/burn/engine/variable.cpp b/src/burn/engine/variable.cpp index 8d208a66..81fa31b7 100644 --- a/src/burn/engine/variable.cpp +++ b/src/burn/engine/variable.cpp @@ -14,6 +14,12 @@ typedef const struct _BUILT_IN_VARIABLE_DECLARATION BOOL fOverridable; } BUILT_IN_VARIABLE_DECLARATION; +typedef const struct _WELL_KNOWN_VARIABLE_DECLARATION +{ + LPCWSTR wzVariable; + BOOL fPersist; +} WELL_KNOWN_VARIABLE_DECLARATION; + // constants @@ -71,6 +77,11 @@ static HRESULT AddBuiltInVariable( __in BOOL fPersist, __in BOOL fOverridable ); +static HRESULT AddWellKnownVariable( + __in BURN_VARIABLES* pVariables, + __in LPCWSTR wzVariable, + __in BOOL fPersisted + ); static HRESULT GetVariable( __in BURN_VARIABLES* pVariables, __in_z LPCWSTR wzVariable, @@ -81,6 +92,11 @@ static HRESULT FindVariableIndexByName( __in_z LPCWSTR wzVariable, __out DWORD* piVariable ); +static HRESULT InsertUserVariable( + __in BURN_VARIABLES* pVariables, + __in_z LPCWSTR wzVariable, + __in DWORD iPosition + ); static HRESULT InsertVariable( __in BURN_VARIABLES* pVariables, __in_z LPCWSTR wzVariable, @@ -248,7 +264,7 @@ extern "C" HRESULT VariableInitialize( #endif {L"ProgramFiles6432Folder", InitializeVariable6432Folder, CSIDL_PROGRAM_FILES}, {L"ProgramMenuFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAMS}, - {L"RebootPending", InitializeVariableNumeric, 0}, + {VARIABLE_REBOOTPENDING, InitializeVariableNumeric, 0}, {L"SendToFolder", InitializeVariableCsidlFolder, CSIDL_SENDTO}, {L"ServicePackLevel", InitializeVariableVersionNT, OS_INFO_VARIABLE_ServicePackLevel}, {L"StartMenuFolder", InitializeVariableCsidlFolder, CSIDL_STARTMENU}, @@ -283,6 +299,17 @@ extern "C" HRESULT VariableInitialize( {BURN_BUNDLE_VERSION, InitializeVariableVersion, (DWORD_PTR)L"0", FALSE, TRUE}, }; + const WELL_KNOWN_VARIABLE_DECLARATION vrgWellKnownVariableNames[] = + { + { BURN_BUNDLE_LAYOUT_DIRECTORY }, + { BURN_BUNDLE_NAME, TRUE }, + { BURN_BUNDLE_INPROGRESS_NAME, TRUE }, + { BURN_BUNDLE_LAST_USED_SOURCE, TRUE }, + { BURN_BUNDLE_MANUFACTURER, TRUE }, + { BURN_BUNDLE_ORIGINAL_SOURCE, TRUE }, + { BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER, TRUE }, + }; + for (DWORD i = 0; i < countof(vrgBuiltInVariables); ++i) { BUILT_IN_VARIABLE_DECLARATION* pBuiltInVariable = &vrgBuiltInVariables[i]; @@ -291,6 +318,14 @@ extern "C" HRESULT VariableInitialize( ExitOnFailure(hr, "Failed to add built-in variable: %ls.", pBuiltInVariable->wzVariable); } + for (DWORD i = 0; i < countof(vrgWellKnownVariableNames); ++i) + { + WELL_KNOWN_VARIABLE_DECLARATION* pWellKnownVariable = &vrgWellKnownVariableNames[i]; + + hr = AddWellKnownVariable(pVariables, pWellKnownVariable->wzVariable, pWellKnownVariable->fPersist); + ExitOnFailure(hr, "Failed to add well-known variable: %ls.", pWellKnownVariable->wzVariable); + } + LExit: return hr; } @@ -301,6 +336,7 @@ extern "C" HRESULT VariablesParseFromXml( ) { HRESULT hr = S_OK; + BOOL fXmlFound = FALSE; IXMLDOMNode* pixnCommandLine = NULL; IXMLDOMNodeList* pixnNodes = NULL; IXMLDOMNode* pixnNode = NULL; @@ -315,17 +351,13 @@ extern "C" HRESULT VariablesParseFromXml( ::EnterCriticalSection(&pVariables->csAccess); - // select registration node + // select command-line node hr = XmlSelectSingleNode(pixnBundle, L"CommandLine", &pixnCommandLine); - if (S_FALSE == hr) - { - hr = E_NOTFOUND; - } - ExitOnFailure(hr, "Failed to select CommandLine node."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to select CommandLine node."); // @Variables hr = XmlGetAttributeEx(pixnCommandLine, L"Variables", &scz); - ExitOnFailure(hr, "Failed to get CommandLine/@Variables."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get CommandLine/@Variables."); if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"upperCase", -1)) { @@ -337,8 +369,7 @@ extern "C" HRESULT VariablesParseFromXml( } else { - hr = E_INVALIDARG; - ExitOnFailure(hr, "Invalid value for CommandLine/@Variables: %ls", scz); + ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for CommandLine/@Variables: %ls", scz); } // select variable nodes @@ -357,28 +388,28 @@ extern "C" HRESULT VariablesParseFromXml( // @Id hr = XmlGetAttributeEx(pixnNode, L"Id", &sczId); - ExitOnFailure(hr, "Failed to get @Id."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Id."); // @Hidden hr = XmlGetYesNoAttribute(pixnNode, L"Hidden", &fHidden); - ExitOnFailure(hr, "Failed to get @Hidden."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Hidden."); // @Persisted hr = XmlGetYesNoAttribute(pixnNode, L"Persisted", &fPersisted); - ExitOnFailure(hr, "Failed to get @Persisted."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Persisted."); // @Value hr = XmlGetAttributeEx(pixnNode, L"Value", &scz); - if (E_NOTFOUND != hr) - { - ExitOnFailure(hr, "Failed to get @Value."); + ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get @Value."); + if (fXmlFound) + { hr = BVariantSetString(&value, scz, 0, FALSE); ExitOnFailure(hr, "Failed to set variant value."); // @Type hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); - ExitOnFailure(hr, "Failed to get @Type."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Type."); if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"formatted", -1)) { @@ -414,8 +445,7 @@ extern "C" HRESULT VariablesParseFromXml( } else { - hr = E_INVALIDARG; - ExitOnFailure(hr, "Invalid value for @Type: %ls", scz); + ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for @Type: %ls", scz); } } else @@ -444,14 +474,18 @@ extern "C" HRESULT VariablesParseFromXml( // insert element if not found if (S_FALSE == hr) { - hr = InsertVariable(pVariables, sczId, iVariable); + hr = InsertUserVariable(pVariables, sczId, iVariable); ExitOnFailure(hr, "Failed to insert variable '%ls'.", sczId); } else if (BURN_VARIABLE_INTERNAL_TYPE_NORMAL < pVariables->rgVariables[iVariable].internalType) { - hr = E_INVALIDARG; - ExitOnRootFailure(hr, "Attempt to set built-in variable value: %ls", sczId); + ExitWithRootFailure(hr, E_INVALIDARG, "Attempt to add built-in variable: %ls", sczId); } + else + { + ExitWithRootFailure(hr, E_INVALIDARG, "Attempt to add variable again: %ls", sczId); + } + pVariables->rgVariables[iVariable].fHidden = fHidden; pVariables->rgVariables[iVariable].fPersisted = fPersisted; @@ -1409,8 +1443,12 @@ static HRESULT AddBuiltInVariable( hr = InsertVariable(pVariables, wzVariable, iVariable); ExitOnFailure(hr, "Failed to insert variable."); } + else + { + ExitWithRootFailure(hr, E_INVALIDSTATE, "Attempted to add built-in variable again: %ls", wzVariable); + } - // set variable values + // set variable details pVariable = &pVariables->rgVariables[iVariable]; pVariable->fPersisted = fPersist; pVariable->internalType = fOverridable ? BURN_VARIABLE_INTERNAL_TYPE_OVERRIDABLE_BUILTIN : BURN_VARIABLE_INTERNAL_TYPE_BUILTIN; @@ -1421,6 +1459,43 @@ LExit: return hr; } +static HRESULT AddWellKnownVariable( + __in BURN_VARIABLES* pVariables, + __in LPCWSTR wzVariable, + __in BOOL fPersisted + ) +{ + HRESULT hr = S_OK; + DWORD iVariable = 0; + BURN_VARIABLE* pVariable = NULL; + + hr = FindVariableIndexByName(pVariables, wzVariable, &iVariable); + ExitOnFailure(hr, "Failed to find variable value."); + + // insert element if not found + if (S_FALSE == hr) + { + hr = InsertVariable(pVariables, wzVariable, iVariable); + ExitOnFailure(hr, "Failed to insert variable."); + } + else if (BURN_VARIABLE_INTERNAL_TYPE_NORMAL != pVariables->rgVariables[iVariable].internalType) + { + ExitWithRootFailure(hr, E_INVALIDSTATE, "Attempted to add built-in variable as a well-known variable: %ls", wzVariable); + } + else + { + ExitWithRootFailure(hr, E_INVALIDSTATE, "Attempted to add well-known variable again: %ls", wzVariable); + } + + // set variable details + pVariable = &pVariables->rgVariables[iVariable]; + pVariable->fPersisted = fPersisted; + pVariable->internalType = BURN_VARIABLE_INTERNAL_TYPE_NORMAL; + +LExit: + return hr; +} + static HRESULT GetVariable( __in BURN_VARIABLES* pVariables, __in_z LPCWSTR wzVariable, @@ -1497,6 +1572,25 @@ LExit: return hr; } +static HRESULT InsertUserVariable( + __in BURN_VARIABLES* pVariables, + __in_z LPCWSTR wzVariable, + __in DWORD iPosition + ) +{ + HRESULT hr = S_OK; + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, wzVariable, 3, L"Wix", 3)) + { + ExitWithRootFailure(hr, E_INVALIDARG, "Attempted to insert variable with reserved prefix: %ls", wzVariable); + } + + hr = InsertVariable(pVariables, wzVariable, iPosition); + +LExit: + return hr; +} + static HRESULT InsertVariable( __in BURN_VARIABLES* pVariables, __in_z LPCWSTR wzVariable, diff --git a/src/burn/engine/variable.h b/src/burn/engine/variable.h index 9ed86ca7..f8d3e1e2 100644 --- a/src/burn/engine/variable.h +++ b/src/burn/engine/variable.h @@ -13,6 +13,7 @@ const LPCWSTR VARIABLE_DATE = L"Date"; const LPCWSTR VARIABLE_LOGONUSER = L"LogonUser"; const LPCWSTR VARIABLE_INSTALLERNAME = L"InstallerName"; const LPCWSTR VARIABLE_INSTALLERVERSION = L"InstallerVersion"; +const LPCWSTR VARIABLE_REBOOTPENDING = L"RebootPending"; // typedefs diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj index 5f8004b4..04491608 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj @@ -48,6 +48,7 @@ + diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters index 9cfe9ee6..19061009 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters @@ -27,6 +27,9 @@ Source Files + + Source Files + Source Files diff --git a/src/burn/test/BurnUnitTest/LoggingTest.cpp b/src/burn/test/BurnUnitTest/LoggingTest.cpp new file mode 100644 index 00000000..ed74c875 --- /dev/null +++ b/src/burn/test/BurnUnitTest/LoggingTest.cpp @@ -0,0 +1,68 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +namespace Microsoft +{ +namespace Tools +{ +namespace WindowsInstallerXml +{ +namespace Test +{ +namespace Bootstrapper +{ + using namespace System; + using namespace Xunit; + + public ref class LoggingTest : BurnUnitTest + { + public: + LoggingTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture) + { + } + + [Fact] + void LoggingLoadXmlTest() + { + HRESULT hr = S_OK; + IXMLDOMElement* pixeBundle = NULL; + BURN_ENGINE_STATE engineState = { }; + try + { + LPCWSTR wzDocument = + L"" + L" " + L""; + + // logutil is static so there can only be one log active at a time. + // This test needs to open a log so need to close the default one for the tests and then open a new one at the end for the tests that run after this one. + LogClose(FALSE); + + VariableInitialize(&engineState.variables); + + LoadBundleXmlHelper(wzDocument, &pixeBundle); + + hr = LoggingParseFromXml(&engineState.log, pixeBundle); + NativeAssert::Succeeded(hr, L"Failed to parse logging from XML."); + + engineState.internalCommand.mode = BURN_MODE_NORMAL; + + hr = LoggingOpen(&engineState.log, &engineState.internalCommand, &engineState.command, &engineState.variables, L"BundleA"); + NativeAssert::Succeeded(hr, L"Failed to open logging."); + + Assert::True(VariableExistsHelper(&engineState.variables, L"WixBundleLog")); + } + finally + { + ReleaseObject(pixeBundle); + LogClose(FALSE); + LogOpen(NULL, L"BurnUnitTest", NULL, L"txt", FALSE, FALSE, NULL); + } + } + }; +} +} +} +} +} diff --git a/src/burn/test/BurnUnitTest/ManifestTest.cpp b/src/burn/test/BurnUnitTest/ManifestTest.cpp index d899e3f9..5e2725bf 100644 --- a/src/burn/test/BurnUnitTest/ManifestTest.cpp +++ b/src/burn/test/BurnUnitTest/ManifestTest.cpp @@ -37,8 +37,8 @@ namespace Bootstrapper "yes" #endif "'>" - " " - " " + " " + " " " " " " "