diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2022-08-19 14:08:23 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2022-08-19 17:02:27 -0500 |
| commit | b72f58abdf6dd5d0020f174358027158cb52cb72 (patch) | |
| tree | 3070c1f1fa8a74125a2933f23a1be3c514ed1de7 /src | |
| parent | bbc36178172e4198351f2f84a91faf56c65e1475 (diff) | |
| download | wix-b72f58abdf6dd5d0020f174358027158cb52cb72.tar.gz wix-b72f58abdf6dd5d0020f174358027158cb52cb72.tar.bz2 wix-b72f58abdf6dd5d0020f174358027158cb52cb72.zip | |
Use a dedicated pipe for redirecting logging from the elevated process.
Fixes 6869
Diffstat (limited to 'src')
| -rw-r--r-- | src/burn/engine/core.cpp | 24 | ||||
| -rw-r--r-- | src/burn/engine/core.h | 2 | ||||
| -rw-r--r-- | src/burn/engine/elevation.cpp | 15 | ||||
| -rw-r--r-- | src/burn/engine/elevation.h | 1 | ||||
| -rw-r--r-- | src/burn/engine/embedded.cpp | 4 | ||||
| -rw-r--r-- | src/burn/engine/engine.cpp | 264 | ||||
| -rw-r--r-- | src/burn/engine/pipe.cpp | 91 | ||||
| -rw-r--r-- | src/burn/engine/pipe.h | 10 | ||||
| -rw-r--r-- | src/burn/engine/uithread.cpp | 12 | ||||
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/logutil.cpp | 4 | ||||
| -rw-r--r-- | src/test/burn/WixToolsetTest.BurnE2E/FilesInUseTests.cs | 2 | ||||
| -rw-r--r-- | src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs | 5 |
12 files changed, 335 insertions, 99 deletions
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index bfd979de..ed824411 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp | |||
| @@ -69,6 +69,9 @@ static HRESULT DetectPackagePayloadsCached( | |||
| 69 | static DWORD WINAPI CacheThreadProc( | 69 | static DWORD WINAPI CacheThreadProc( |
| 70 | __in LPVOID lpThreadParameter | 70 | __in LPVOID lpThreadParameter |
| 71 | ); | 71 | ); |
| 72 | static DWORD WINAPI LoggingThreadProc( | ||
| 73 | __in LPVOID lpThreadParameter | ||
| 74 | ); | ||
| 72 | static void LogPackages( | 75 | static void LogPackages( |
| 73 | __in_opt const BURN_PACKAGE* pUpgradeBundlePackage, | 76 | __in_opt const BURN_PACKAGE* pUpgradeBundlePackage, |
| 74 | __in_opt const BURN_PACKAGE* pForwardCompatibleBundlePackage, | 77 | __in_opt const BURN_PACKAGE* pForwardCompatibleBundlePackage, |
| @@ -615,6 +618,9 @@ extern "C" HRESULT CoreElevate( | |||
| 615 | 618 | ||
| 616 | hr = VariableSetNumeric(&pEngineState->variables, BURN_BUNDLE_ELEVATED, TRUE, TRUE); | 619 | hr = VariableSetNumeric(&pEngineState->variables, BURN_BUNDLE_ELEVATED, TRUE, TRUE); |
| 617 | ExitOnFailure(hr, "Failed to overwrite the %ls built-in variable.", BURN_BUNDLE_ELEVATED); | 620 | ExitOnFailure(hr, "Failed to overwrite the %ls built-in variable.", BURN_BUNDLE_ELEVATED); |
| 621 | |||
| 622 | pEngineState->hUnelevatedLoggingThread = ::CreateThread(NULL, 0, LoggingThreadProc, pEngineState, 0, NULL); | ||
| 623 | ExitOnNullWithLastError(pEngineState->hUnelevatedLoggingThread, hr, "Failed to create unelevated logging thread."); | ||
| 618 | } | 624 | } |
| 619 | 625 | ||
| 620 | LExit: | 626 | LExit: |
| @@ -2325,6 +2331,24 @@ LExit: | |||
| 2325 | return (DWORD)hr; | 2331 | return (DWORD)hr; |
| 2326 | } | 2332 | } |
| 2327 | 2333 | ||
| 2334 | static DWORD WINAPI LoggingThreadProc( | ||
| 2335 | __in LPVOID lpThreadParameter | ||
| 2336 | ) | ||
| 2337 | { | ||
| 2338 | HRESULT hr = S_OK; | ||
| 2339 | BURN_ENGINE_STATE* pEngineState = reinterpret_cast<BURN_ENGINE_STATE*>(lpThreadParameter); | ||
| 2340 | BURN_PIPE_RESULT result = { }; | ||
| 2341 | |||
| 2342 | hr = PipePumpMessages(pEngineState->companionConnection.hLoggingPipe, NULL, NULL, &result); | ||
| 2343 | ExitOnFailure(hr, "Failed to pump logging messages for elevated process."); | ||
| 2344 | |||
| 2345 | hr = (HRESULT)result.dwResult; | ||
| 2346 | |||
| 2347 | LExit: | ||
| 2348 | |||
| 2349 | return (DWORD)hr; | ||
| 2350 | } | ||
| 2351 | |||
| 2328 | static void LogPackages( | 2352 | static void LogPackages( |
| 2329 | __in_opt const BURN_PACKAGE* pUpgradeBundlePackage, | 2353 | __in_opt const BURN_PACKAGE* pUpgradeBundlePackage, |
| 2330 | __in_opt const BURN_PACKAGE* pForwardCompatibleBundlePackage, | 2354 | __in_opt const BURN_PACKAGE* pForwardCompatibleBundlePackage, |
diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h index c75d42de..a2f1ab4c 100644 --- a/src/burn/engine/core.h +++ b/src/burn/engine/core.h | |||
| @@ -152,7 +152,7 @@ typedef struct _BURN_ENGINE_STATE | |||
| 152 | 152 | ||
| 153 | BURN_PLAN plan; | 153 | BURN_PLAN plan; |
| 154 | 154 | ||
| 155 | DWORD dwElevatedLoggingTlsId; | 155 | HANDLE hUnelevatedLoggingThread; |
| 156 | 156 | ||
| 157 | LPWSTR sczBundleEngineWorkingPath; | 157 | LPWSTR sczBundleEngineWorkingPath; |
| 158 | BURN_PIPE_CONNECTION companionConnection; | 158 | BURN_PIPE_CONNECTION companionConnection; |
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index e30a05bb..adc3aad9 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp | |||
| @@ -91,7 +91,6 @@ typedef struct _BURN_ELEVATION_LAUNCH_APPROVED_EXE_MESSAGE_CONTEXT | |||
| 91 | 91 | ||
| 92 | typedef struct _BURN_ELEVATION_CHILD_MESSAGE_CONTEXT | 92 | typedef struct _BURN_ELEVATION_CHILD_MESSAGE_CONTEXT |
| 93 | { | 93 | { |
| 94 | DWORD dwLoggingTlsId; | ||
| 95 | HANDLE hPipe; | 94 | HANDLE hPipe; |
| 96 | HANDLE* phLock; | 95 | HANDLE* phLock; |
| 97 | BOOL* pfDisabledAutomaticUpdates; | 96 | BOOL* pfDisabledAutomaticUpdates; |
| @@ -397,10 +396,10 @@ extern "C" HRESULT ElevationElevate( | |||
| 397 | Assert(!pEngineState->companionConnection.dwProcessId); | 396 | Assert(!pEngineState->companionConnection.dwProcessId); |
| 398 | Assert(INVALID_HANDLE_VALUE == pEngineState->companionConnection.hPipe); | 397 | Assert(INVALID_HANDLE_VALUE == pEngineState->companionConnection.hPipe); |
| 399 | Assert(INVALID_HANDLE_VALUE == pEngineState->companionConnection.hCachePipe); | 398 | Assert(INVALID_HANDLE_VALUE == pEngineState->companionConnection.hCachePipe); |
| 399 | Assert(INVALID_HANDLE_VALUE == pEngineState->companionConnection.hLoggingPipe); | ||
| 400 | 400 | ||
| 401 | HRESULT hr = S_OK; | 401 | HRESULT hr = S_OK; |
| 402 | int nResult = IDOK; | 402 | int nResult = IDOK; |
| 403 | HANDLE hPipesCreatedEvent = INVALID_HANDLE_VALUE; | ||
| 404 | 403 | ||
| 405 | hr = UserExperienceOnElevateBegin(&pEngineState->userExperience); | 404 | hr = UserExperienceOnElevateBegin(&pEngineState->userExperience); |
| 406 | ExitOnRootFailure(hr, "BA aborted elevation requirement."); | 405 | ExitOnRootFailure(hr, "BA aborted elevation requirement."); |
| @@ -408,7 +407,7 @@ extern "C" HRESULT ElevationElevate( | |||
| 408 | hr = PipeCreateNameAndSecret(&pEngineState->companionConnection.sczName, &pEngineState->companionConnection.sczSecret); | 407 | hr = PipeCreateNameAndSecret(&pEngineState->companionConnection.sczName, &pEngineState->companionConnection.sczSecret); |
| 409 | ExitOnFailure(hr, "Failed to create pipe name and client token."); | 408 | ExitOnFailure(hr, "Failed to create pipe name and client token."); |
| 410 | 409 | ||
| 411 | hr = PipeCreatePipes(&pEngineState->companionConnection, TRUE, &hPipesCreatedEvent); | 410 | hr = PipeCreatePipes(&pEngineState->companionConnection, TRUE); |
| 412 | ExitOnFailure(hr, "Failed to create pipe and cache pipe."); | 411 | ExitOnFailure(hr, "Failed to create pipe and cache pipe."); |
| 413 | 412 | ||
| 414 | LogId(REPORT_STANDARD, MSG_LAUNCH_ELEVATED_ENGINE_STARTING); | 413 | LogId(REPORT_STANDARD, MSG_LAUNCH_ELEVATED_ENGINE_STARTING); |
| @@ -442,8 +441,6 @@ extern "C" HRESULT ElevationElevate( | |||
| 442 | ExitOnFailure(hr, "Failed to elevate."); | 441 | ExitOnFailure(hr, "Failed to elevate."); |
| 443 | 442 | ||
| 444 | LExit: | 443 | LExit: |
| 445 | ReleaseHandle(hPipesCreatedEvent); | ||
| 446 | |||
| 447 | if (FAILED(hr)) | 444 | if (FAILED(hr)) |
| 448 | { | 445 | { |
| 449 | PipeConnectionUninitialize(&pEngineState->companionConnection); | 446 | PipeConnectionUninitialize(&pEngineState->companionConnection); |
| @@ -1532,7 +1529,6 @@ LExit: | |||
| 1532 | 1529 | ||
| 1533 | *******************************************************************/ | 1530 | *******************************************************************/ |
| 1534 | extern "C" HRESULT ElevationChildPumpMessages( | 1531 | extern "C" HRESULT ElevationChildPumpMessages( |
| 1535 | __in DWORD dwLoggingTlsId, | ||
| 1536 | __in HANDLE hPipe, | 1532 | __in HANDLE hPipe, |
| 1537 | __in HANDLE hCachePipe, | 1533 | __in HANDLE hCachePipe, |
| 1538 | __in BURN_APPROVED_EXES* pApprovedExes, | 1534 | __in BURN_APPROVED_EXES* pApprovedExes, |
| @@ -1556,7 +1552,6 @@ extern "C" HRESULT ElevationChildPumpMessages( | |||
| 1556 | BURN_PIPE_RESULT result = { }; | 1552 | BURN_PIPE_RESULT result = { }; |
| 1557 | BOOL fDisabledAutomaticUpdates = FALSE; | 1553 | BOOL fDisabledAutomaticUpdates = FALSE; |
| 1558 | 1554 | ||
| 1559 | cacheContext.dwLoggingTlsId = dwLoggingTlsId; | ||
| 1560 | cacheContext.hPipe = hCachePipe; | 1555 | cacheContext.hPipe = hCachePipe; |
| 1561 | cacheContext.pCache = pCache; | 1556 | cacheContext.pCache = pCache; |
| 1562 | cacheContext.pContainers = pContainers; | 1557 | cacheContext.pContainers = pContainers; |
| @@ -1566,7 +1561,6 @@ extern "C" HRESULT ElevationChildPumpMessages( | |||
| 1566 | cacheContext.pRegistration = pRegistration; | 1561 | cacheContext.pRegistration = pRegistration; |
| 1567 | cacheContext.pUserExperience = pUserExperience; | 1562 | cacheContext.pUserExperience = pUserExperience; |
| 1568 | 1563 | ||
| 1569 | context.dwLoggingTlsId = dwLoggingTlsId; | ||
| 1570 | context.hPipe = hPipe; | 1564 | context.hPipe = hPipe; |
| 1571 | context.phLock = phLock; | 1565 | context.phLock = phLock; |
| 1572 | context.pfDisabledAutomaticUpdates = &fDisabledAutomaticUpdates; | 1566 | context.pfDisabledAutomaticUpdates = &fDisabledAutomaticUpdates; |
| @@ -1660,11 +1654,6 @@ static DWORD WINAPI ElevatedChildCacheThreadProc( | |||
| 1660 | BOOL fComInitialized = FALSE; | 1654 | BOOL fComInitialized = FALSE; |
| 1661 | BURN_PIPE_RESULT result = { }; | 1655 | BURN_PIPE_RESULT result = { }; |
| 1662 | 1656 | ||
| 1663 | if (!::TlsSetValue(pContext->dwLoggingTlsId, pContext->hPipe)) | ||
| 1664 | { | ||
| 1665 | ExitWithLastError(hr, "Failed to set elevated cache pipe into thread local storage for logging."); | ||
| 1666 | } | ||
| 1667 | |||
| 1668 | // initialize COM | 1657 | // initialize COM |
| 1669 | hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); | 1658 | hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); |
| 1670 | ExitOnFailure(hr, "Failed to initialize COM."); | 1659 | ExitOnFailure(hr, "Failed to initialize COM."); |
diff --git a/src/burn/engine/elevation.h b/src/burn/engine/elevation.h index bda0fdef..0d15b470 100644 --- a/src/burn/engine/elevation.h +++ b/src/burn/engine/elevation.h | |||
| @@ -166,7 +166,6 @@ HRESULT ElevationLaunchApprovedExe( | |||
| 166 | 166 | ||
| 167 | // Child (per-machine process) side functions. | 167 | // Child (per-machine process) side functions. |
| 168 | HRESULT ElevationChildPumpMessages( | 168 | HRESULT ElevationChildPumpMessages( |
| 169 | __in DWORD dwLoggingTlsId, | ||
| 170 | __in HANDLE hPipe, | 169 | __in HANDLE hPipe, |
| 171 | __in HANDLE hCachePipe, | 170 | __in HANDLE hCachePipe, |
| 172 | __in BURN_APPROVED_EXES* pApprovedExes, | 171 | __in BURN_APPROVED_EXES* pApprovedExes, |
diff --git a/src/burn/engine/embedded.cpp b/src/burn/engine/embedded.cpp index ac4c76d0..b9335cdf 100644 --- a/src/burn/engine/embedded.cpp +++ b/src/burn/engine/embedded.cpp | |||
| @@ -51,7 +51,6 @@ extern "C" HRESULT EmbeddedRunBundle( | |||
| 51 | { | 51 | { |
| 52 | HRESULT hr = S_OK; | 52 | HRESULT hr = S_OK; |
| 53 | DWORD dwCurrentProcessId = ::GetCurrentProcessId(); | 53 | DWORD dwCurrentProcessId = ::GetCurrentProcessId(); |
| 54 | HANDLE hCreatedPipesEvent = NULL; | ||
| 55 | LPWSTR sczCommand = NULL; | 54 | LPWSTR sczCommand = NULL; |
| 56 | PROCESS_INFORMATION pi = { }; | 55 | PROCESS_INFORMATION pi = { }; |
| 57 | BURN_PIPE_RESULT result = { }; | 56 | BURN_PIPE_RESULT result = { }; |
| @@ -65,7 +64,7 @@ extern "C" HRESULT EmbeddedRunBundle( | |||
| 65 | hr = PipeCreateNameAndSecret(&pConnection->sczName, &pConnection->sczSecret); | 64 | hr = PipeCreateNameAndSecret(&pConnection->sczName, &pConnection->sczSecret); |
| 66 | ExitOnFailure(hr, "Failed to create embedded pipe name and client token."); | 65 | ExitOnFailure(hr, "Failed to create embedded pipe name and client token."); |
| 67 | 66 | ||
| 68 | hr = PipeCreatePipes(pConnection, FALSE, &hCreatedPipesEvent); | 67 | hr = PipeCreatePipes(pConnection, FALSE); |
| 69 | ExitOnFailure(hr, "Failed to create embedded pipe."); | 68 | ExitOnFailure(hr, "Failed to create embedded pipe."); |
| 70 | 69 | ||
| 71 | hr = StrAllocFormatted(&sczCommand, L"%ls -%ls %ls %ls %u", sczBaseCommand, BURN_COMMANDLINE_SWITCH_EMBEDDED, pConnection->sczName, pConnection->sczSecret, dwCurrentProcessId); | 70 | hr = StrAllocFormatted(&sczCommand, L"%ls -%ls %ls %ls %u", sczBaseCommand, BURN_COMMANDLINE_SWITCH_EMBEDDED, pConnection->sczName, pConnection->sczSecret, dwCurrentProcessId); |
| @@ -100,7 +99,6 @@ LExit: | |||
| 100 | ReleaseHandle(pi.hProcess); | 99 | ReleaseHandle(pi.hProcess); |
| 101 | 100 | ||
| 102 | StrSecureZeroFreeString(sczCommand); | 101 | StrSecureZeroFreeString(sczCommand); |
| 103 | ReleaseHandle(hCreatedPipesEvent); | ||
| 104 | PipeConnectionUninitialize(pConnection); | 102 | PipeConnectionUninitialize(pConnection); |
| 105 | 103 | ||
| 106 | return hr; | 104 | return hr; |
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp index 323d2c3a..daaf51dc 100644 --- a/src/burn/engine/engine.cpp +++ b/src/burn/engine/engine.cpp | |||
| @@ -3,6 +3,15 @@ | |||
| 3 | #include "precomp.h" | 3 | #include "precomp.h" |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | typedef struct _REDIRECTED_LOGGING_CONTEXT | ||
| 7 | { | ||
| 8 | CRITICAL_SECTION csBuffer; | ||
| 9 | LPSTR sczBuffer; | ||
| 10 | HANDLE hPipe; | ||
| 11 | HANDLE hLogEvent; | ||
| 12 | HANDLE hFinishedEvent; | ||
| 13 | } REDIRECTED_LOGGING_CONTEXT; | ||
| 14 | |||
| 6 | // constants | 15 | // constants |
| 7 | 16 | ||
| 8 | const DWORD RESTART_RETRIES = 10; | 17 | const DWORD RESTART_RETRIES = 10; |
| @@ -49,6 +58,20 @@ static HRESULT DAPI RedirectLoggingOverPipe( | |||
| 49 | __in_z LPCSTR szString, | 58 | __in_z LPCSTR szString, |
| 50 | __in_opt LPVOID pvContext | 59 | __in_opt LPVOID pvContext |
| 51 | ); | 60 | ); |
| 61 | static HRESULT LogStringOverPipe( | ||
| 62 | __in_z LPCSTR szString, | ||
| 63 | __in HANDLE hPipe | ||
| 64 | ); | ||
| 65 | static DWORD WINAPI ElevatedLoggingThreadProc( | ||
| 66 | __in LPVOID lpThreadParameter | ||
| 67 | ); | ||
| 68 | static HRESULT WaitForElevatedLoggingThread( | ||
| 69 | __in REDIRECTED_LOGGING_CONTEXT* pContext, | ||
| 70 | __in HANDLE hLoggingThread | ||
| 71 | ); | ||
| 72 | static HRESULT WaitForUnelevatedLoggingThread( | ||
| 73 | __in HANDLE hUnelevatedLoggingThread | ||
| 74 | ); | ||
| 52 | static HRESULT Restart(); | 75 | static HRESULT Restart(); |
| 53 | static void CALLBACK BurnTraceError( | 76 | static void CALLBACK BurnTraceError( |
| 54 | __in_z LPCSTR szFile, | 77 | __in_z LPCSTR szFile, |
| @@ -361,7 +384,6 @@ static HRESULT InitializeEngineState( | |||
| 361 | HANDLE hSourceEngineFile = INVALID_HANDLE_VALUE; | 384 | HANDLE hSourceEngineFile = INVALID_HANDLE_VALUE; |
| 362 | 385 | ||
| 363 | pEngineState->internalCommand.automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED; | 386 | pEngineState->internalCommand.automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED; |
| 364 | pEngineState->dwElevatedLoggingTlsId = TLS_OUT_OF_INDEXES; | ||
| 365 | ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive); | 387 | ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive); |
| 366 | PipeConnectionInitialize(&pEngineState->companionConnection); | 388 | PipeConnectionInitialize(&pEngineState->companionConnection); |
| 367 | PipeConnectionInitialize(&pEngineState->embeddedConnection); | 389 | PipeConnectionInitialize(&pEngineState->embeddedConnection); |
| @@ -434,11 +456,6 @@ static void UninitializeEngineState( | |||
| 434 | ReleaseStr(pEngineState->log.sczPath); | 456 | ReleaseStr(pEngineState->log.sczPath); |
| 435 | ReleaseStr(pEngineState->log.sczPathVariable); | 457 | ReleaseStr(pEngineState->log.sczPathVariable); |
| 436 | 458 | ||
| 437 | if (TLS_OUT_OF_INDEXES != pEngineState->dwElevatedLoggingTlsId) | ||
| 438 | { | ||
| 439 | ::TlsFree(pEngineState->dwElevatedLoggingTlsId); | ||
| 440 | } | ||
| 441 | |||
| 442 | // clear struct | 459 | // clear struct |
| 443 | memset(pEngineState, 0, sizeof(BURN_ENGINE_STATE)); | 460 | memset(pEngineState, 0, sizeof(BURN_ENGINE_STATE)); |
| 444 | } | 461 | } |
| @@ -624,6 +641,8 @@ LExit: | |||
| 624 | if (INVALID_HANDLE_VALUE != pEngineState->companionConnection.hPipe) | 641 | if (INVALID_HANDLE_VALUE != pEngineState->companionConnection.hPipe) |
| 625 | { | 642 | { |
| 626 | PipeTerminateChildProcess(&pEngineState->companionConnection, pEngineState->userExperience.dwExitCode, FALSE); | 643 | PipeTerminateChildProcess(&pEngineState->companionConnection, pEngineState->userExperience.dwExitCode, FALSE); |
| 644 | |||
| 645 | WaitForUnelevatedLoggingThread(pEngineState->hUnelevatedLoggingThread); | ||
| 627 | } | 646 | } |
| 628 | 647 | ||
| 629 | // If the splash screen is still around, close it. | 648 | // If the splash screen is still around, close it. |
| @@ -646,6 +665,9 @@ static HRESULT RunElevated( | |||
| 646 | { | 665 | { |
| 647 | HRESULT hr = S_OK; | 666 | HRESULT hr = S_OK; |
| 648 | HANDLE hLock = NULL; | 667 | HANDLE hLock = NULL; |
| 668 | HANDLE hLoggingThread = NULL; | ||
| 669 | REDIRECTED_LOGGING_CONTEXT loggingContext = { }; | ||
| 670 | BOOL fDeleteLoggingCs = FALSE; | ||
| 649 | 671 | ||
| 650 | // Initialize logging. | 672 | // Initialize logging. |
| 651 | hr = LoggingOpen(&pEngineState->log, &pEngineState->internalCommand, &pEngineState->command, &pEngineState->variables, pEngineState->registration.sczDisplayName); | 673 | hr = LoggingOpen(&pEngineState->log, &pEngineState->internalCommand, &pEngineState->command, &pEngineState->variables, pEngineState->registration.sczDisplayName); |
| @@ -655,20 +677,23 @@ static HRESULT RunElevated( | |||
| 655 | hr = PipeChildConnect(&pEngineState->companionConnection, TRUE); | 677 | hr = PipeChildConnect(&pEngineState->companionConnection, TRUE); |
| 656 | ExitOnFailure(hr, "Failed to connect to unelevated process."); | 678 | ExitOnFailure(hr, "Failed to connect to unelevated process."); |
| 657 | 679 | ||
| 658 | // Set up the thread local storage to store the correct pipe to communicate logging then | 680 | // Set up the context for the logging thread then |
| 659 | // override logging to write over the pipe. | 681 | // override logging to write over the pipe. |
| 660 | pEngineState->dwElevatedLoggingTlsId = ::TlsAlloc(); | 682 | ::InitializeCriticalSection(&loggingContext.csBuffer); |
| 661 | if (TLS_OUT_OF_INDEXES == pEngineState->dwElevatedLoggingTlsId) | 683 | fDeleteLoggingCs = TRUE; |
| 662 | { | ||
| 663 | ExitWithLastError(hr, "Failed to allocate thread local storage for logging."); | ||
| 664 | } | ||
| 665 | 684 | ||
| 666 | if (!::TlsSetValue(pEngineState->dwElevatedLoggingTlsId, pEngineState->companionConnection.hPipe)) | 685 | loggingContext.hLogEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); |
| 667 | { | 686 | ExitOnNullWithLastError(loggingContext.hLogEvent, hr, "Failed to create log event for logging thread."); |
| 668 | ExitWithLastError(hr, "Failed to set elevated pipe into thread local storage for logging."); | 687 | |
| 669 | } | 688 | loggingContext.hFinishedEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); |
| 689 | ExitOnNullWithLastError(loggingContext.hFinishedEvent, hr, "Failed to create finished event for logging thread."); | ||
| 690 | |||
| 691 | loggingContext.hPipe = pEngineState->companionConnection.hLoggingPipe; | ||
| 692 | |||
| 693 | hLoggingThread = ::CreateThread(NULL, 0, ElevatedLoggingThreadProc, &loggingContext, 0, NULL); | ||
| 694 | ExitOnNullWithLastError(hLoggingThread, hr, "Failed to create elevated logging thread."); | ||
| 670 | 695 | ||
| 671 | LogRedirect(RedirectLoggingOverPipe, pEngineState); | 696 | LogRedirect(RedirectLoggingOverPipe, &loggingContext); |
| 672 | 697 | ||
| 673 | // Create a top-level window to prevent shutting down the elevated process. | 698 | // Create a top-level window to prevent shutting down the elevated process. |
| 674 | hr = UiCreateMessageWindow(hInstance, pEngineState); | 699 | hr = UiCreateMessageWindow(hInstance, pEngineState); |
| @@ -677,16 +702,35 @@ static HRESULT RunElevated( | |||
| 677 | SrpInitialize(TRUE); | 702 | SrpInitialize(TRUE); |
| 678 | 703 | ||
| 679 | // Pump messages from parent process. | 704 | // Pump messages from parent process. |
| 680 | hr = ElevationChildPumpMessages(pEngineState->dwElevatedLoggingTlsId, pEngineState->companionConnection.hPipe, pEngineState->companionConnection.hCachePipe, &pEngineState->approvedExes, &pEngineState->cache, &pEngineState->containers, &pEngineState->packages, &pEngineState->payloads, &pEngineState->variables, &pEngineState->registration, &pEngineState->userExperience, &hLock, &pEngineState->userExperience.dwExitCode, &pEngineState->fRestart, &pEngineState->plan.fApplying); | 705 | hr = ElevationChildPumpMessages(pEngineState->companionConnection.hPipe, pEngineState->companionConnection.hCachePipe, &pEngineState->approvedExes, &pEngineState->cache, &pEngineState->containers, &pEngineState->packages, &pEngineState->payloads, &pEngineState->variables, &pEngineState->registration, &pEngineState->userExperience, &hLock, &pEngineState->userExperience.dwExitCode, &pEngineState->fRestart, &pEngineState->plan.fApplying); |
| 681 | LogRedirect(NULL, NULL); // reset logging so the next failure gets written to "log buffer" for the failure log. | ||
| 682 | ExitOnFailure(hr, "Failed to pump messages from parent process."); | 706 | ExitOnFailure(hr, "Failed to pump messages from parent process."); |
| 683 | 707 | ||
| 708 | WaitForElevatedLoggingThread(&loggingContext, hLoggingThread); | ||
| 709 | |||
| 684 | LExit: | 710 | LExit: |
| 711 | ReleaseHandle(hLoggingThread); | ||
| 712 | |||
| 685 | LogRedirect(NULL, NULL); // we're done talking to the child so always reset logging now. | 713 | LogRedirect(NULL, NULL); // we're done talking to the child so always reset logging now. |
| 686 | 714 | ||
| 687 | // If the message window is still around, close it. | 715 | // If the message window is still around, close it. |
| 688 | UiCloseMessageWindow(pEngineState); | 716 | UiCloseMessageWindow(pEngineState); |
| 689 | 717 | ||
| 718 | if (fDeleteLoggingCs) | ||
| 719 | { | ||
| 720 | ::DeleteCriticalSection(&loggingContext.csBuffer); | ||
| 721 | } | ||
| 722 | |||
| 723 | ReleaseHandle(loggingContext.hLogEvent); | ||
| 724 | ReleaseHandle(loggingContext.hFinishedEvent); | ||
| 725 | |||
| 726 | // If there was a log message left, try to log it locally. | ||
| 727 | if (loggingContext.sczBuffer) | ||
| 728 | { | ||
| 729 | LogStringWorkRaw(loggingContext.sczBuffer); | ||
| 730 | |||
| 731 | ReleaseStr(loggingContext.sczBuffer); | ||
| 732 | } | ||
| 733 | |||
| 690 | if (hLock) | 734 | if (hLock) |
| 691 | { | 735 | { |
| 692 | ::ReleaseMutex(hLock); | 736 | ::ReleaseMutex(hLock); |
| @@ -883,54 +927,180 @@ static HRESULT DAPI RedirectLoggingOverPipe( | |||
| 883 | __in_opt LPVOID pvContext | 927 | __in_opt LPVOID pvContext |
| 884 | ) | 928 | ) |
| 885 | { | 929 | { |
| 886 | static BOOL s_fCurrentlyLoggingToPipe = FALSE; | 930 | HRESULT hr = S_OK; |
| 931 | REDIRECTED_LOGGING_CONTEXT* pContext = static_cast<REDIRECTED_LOGGING_CONTEXT*>(pvContext); | ||
| 932 | |||
| 933 | ::EnterCriticalSection(&pContext->csBuffer); | ||
| 934 | |||
| 935 | hr = StrAnsiAllocConcat(&pContext->sczBuffer, szString, 0); | ||
| 936 | |||
| 937 | if (SUCCEEDED(hr) && !::SetEvent(pContext->hLogEvent)) | ||
| 938 | { | ||
| 939 | HRESULT hrSet = HRESULT_FROM_WIN32(::GetLastError()); | ||
| 940 | if (FAILED(hrSet)) | ||
| 941 | { | ||
| 942 | TraceError(hrSet, "Failed to set log event."); | ||
| 943 | } | ||
| 944 | } | ||
| 945 | |||
| 946 | ::LeaveCriticalSection(&pContext->csBuffer); | ||
| 887 | 947 | ||
| 948 | return hr; | ||
| 949 | } | ||
| 950 | |||
| 951 | static HRESULT LogStringOverPipe( | ||
| 952 | __in_z LPCSTR szString, | ||
| 953 | __in HANDLE hPipe | ||
| 954 | ) | ||
| 955 | { | ||
| 888 | HRESULT hr = S_OK; | 956 | HRESULT hr = S_OK; |
| 889 | BURN_ENGINE_STATE* pEngineState = static_cast<BURN_ENGINE_STATE*>(pvContext); | ||
| 890 | BOOL fStartedLogging = FALSE; | ||
| 891 | HANDLE hPipe = INVALID_HANDLE_VALUE; | ||
| 892 | BYTE* pbData = NULL; | 957 | BYTE* pbData = NULL; |
| 893 | SIZE_T cbData = 0; | 958 | SIZE_T cbData = 0; |
| 894 | DWORD dwResult = 0; | 959 | DWORD dwResult = 0; |
| 895 | 960 | ||
| 896 | // Prevent this function from being called recursively. | 961 | hr = BuffWriteStringAnsi(&pbData, &cbData, szString); |
| 897 | if (s_fCurrentlyLoggingToPipe) | 962 | ExitOnFailure(hr, "Failed to prepare logging pipe message."); |
| 898 | { | 963 | |
| 899 | ExitFunction(); | 964 | hr = PipeSendMessage(hPipe, static_cast<DWORD>(BURN_PIPE_MESSAGE_TYPE_LOG), pbData, cbData, NULL, NULL, &dwResult); |
| 900 | } | 965 | ExitOnFailure(hr, "Failed to send logging message over the pipe."); |
| 966 | |||
| 967 | hr = (HRESULT)dwResult; | ||
| 968 | |||
| 969 | LExit: | ||
| 970 | ReleaseBuffer(pbData); | ||
| 901 | 971 | ||
| 902 | s_fCurrentlyLoggingToPipe = TRUE; | 972 | return hr; |
| 903 | fStartedLogging = TRUE; | 973 | } |
| 974 | |||
| 975 | static DWORD WINAPI ElevatedLoggingThreadProc( | ||
| 976 | __in LPVOID lpThreadParameter | ||
| 977 | ) | ||
| 978 | { | ||
| 979 | HRESULT hr = S_OK; | ||
| 980 | DWORD dwLastError = ERROR_SUCCESS; | ||
| 981 | REDIRECTED_LOGGING_CONTEXT* pContext = static_cast<REDIRECTED_LOGGING_CONTEXT*>(lpThreadParameter); | ||
| 982 | DWORD dwSignaledIndex = 0; | ||
| 983 | LPSTR sczBuffer = NULL; | ||
| 984 | BURN_PIPE_RESULT result = { }; | ||
| 985 | HANDLE rghEvents[2] = | ||
| 986 | { | ||
| 987 | pContext->hLogEvent, | ||
| 988 | pContext->hFinishedEvent, | ||
| 989 | }; | ||
| 904 | 990 | ||
| 905 | // Make sure the current thread set the pipe in TLS. | 991 | for (;;) |
| 906 | hPipe = ::TlsGetValue(pEngineState->dwElevatedLoggingTlsId); | ||
| 907 | if (!hPipe || INVALID_HANDLE_VALUE == hPipe) | ||
| 908 | { | 992 | { |
| 909 | hr = HRESULT_FROM_WIN32(ERROR_PIPE_NOT_CONNECTED); | 993 | hr = AppWaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE, &dwSignaledIndex); |
| 910 | ExitFunction(); | 994 | if (FAILED(hr)) |
| 995 | { | ||
| 996 | LogRedirect(NULL, NULL); // reset logging so the next failure gets written locally. | ||
| 997 | ExitOnFailure(hr, "Failed to wait for log thread events, signaled: %u.", dwSignaledIndex); | ||
| 998 | } | ||
| 999 | |||
| 1000 | if (1 == dwSignaledIndex) | ||
| 1001 | { | ||
| 1002 | LogRedirect(NULL, NULL); // No more messages will be logged over the pipe. | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | dwLastError = ERROR_SUCCESS; | ||
| 1006 | |||
| 1007 | ::EnterCriticalSection(&pContext->csBuffer); | ||
| 1008 | |||
| 1009 | sczBuffer = pContext->sczBuffer; | ||
| 1010 | pContext->sczBuffer = NULL; | ||
| 1011 | |||
| 1012 | if (0 == dwSignaledIndex && !::ResetEvent(rghEvents[0])) | ||
| 1013 | { | ||
| 1014 | dwLastError = ::GetLastError(); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | ::LeaveCriticalSection(&pContext->csBuffer); | ||
| 1018 | |||
| 1019 | if (ERROR_SUCCESS != dwLastError) | ||
| 1020 | { | ||
| 1021 | LogRedirect(NULL, NULL); // reset logging so the next failure gets written locally. | ||
| 1022 | ExitOnWin32Error(dwLastError, hr, "Failed to reset log event."); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | if (sczBuffer) | ||
| 1026 | { | ||
| 1027 | hr = LogStringOverPipe(sczBuffer, pContext->hPipe); | ||
| 1028 | if (FAILED(hr)) | ||
| 1029 | { | ||
| 1030 | LogRedirect(NULL, NULL); // reset logging so the next failure gets written locally. | ||
| 1031 | ExitOnFailure(hr, "Failed to wait log message over pipe."); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | ReleaseStr(sczBuffer); | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | if (1 == dwSignaledIndex) | ||
| 1038 | { | ||
| 1039 | break; | ||
| 1040 | } | ||
| 911 | } | 1041 | } |
| 912 | 1042 | ||
| 913 | // Do not log or use ExitOnFailure() macro here because they will be discarded | 1043 | LExit: |
| 914 | // by the recursive block at the top of this function. | 1044 | LogRedirect(NULL, NULL); // No more messages will be logged over the pipe. |
| 915 | hr = BuffWriteStringAnsi(&pbData, &cbData, szString); | 1045 | |
| 916 | if (SUCCEEDED(hr)) | ||
| 917 | { | 1046 | { |
| 918 | hr = PipeSendMessage(hPipe, static_cast<DWORD>(BURN_PIPE_MESSAGE_TYPE_LOG), pbData, cbData, NULL, NULL, &dwResult); | 1047 | HRESULT hrTerminate = PipeTerminateLoggingPipe(pContext->hPipe, hr); |
| 919 | if (SUCCEEDED(hr)) | 1048 | if (FAILED(hrTerminate)) |
| 920 | { | 1049 | { |
| 921 | hr = (HRESULT)dwResult; | 1050 | TraceError(hrTerminate, "Failed to terminate logging pipe."); |
| 922 | } | 1051 | } |
| 923 | } | 1052 | } |
| 924 | 1053 | ||
| 925 | LExit: | 1054 | // Log the message locally if it failed to go over the pipe. |
| 926 | ReleaseBuffer(pbData); | 1055 | if (sczBuffer) |
| 1056 | { | ||
| 1057 | LogStringWorkRaw(sczBuffer); | ||
| 1058 | |||
| 1059 | ReleaseStr(sczBuffer); | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | // Log any remaining message locally. | ||
| 1063 | if (pContext->sczBuffer) | ||
| 1064 | { | ||
| 1065 | AssertSz(FAILED(hr), "Exiting logging thread on success even though there was a leftover message"); | ||
| 1066 | LogStringWorkRaw(pContext->sczBuffer); | ||
| 1067 | |||
| 1068 | ReleaseStr(pContext->sczBuffer); | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | return (DWORD)hr; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | static HRESULT WaitForElevatedLoggingThread( | ||
| 1075 | __in REDIRECTED_LOGGING_CONTEXT* pContext, | ||
| 1076 | __in HANDLE hLoggingThread | ||
| 1077 | ) | ||
| 1078 | { | ||
| 1079 | HRESULT hr = S_OK; | ||
| 927 | 1080 | ||
| 928 | // We started logging so remember to say we are no longer logging. | 1081 | if (!::SetEvent(pContext->hFinishedEvent)) |
| 929 | if (fStartedLogging) | ||
| 930 | { | 1082 | { |
| 931 | s_fCurrentlyLoggingToPipe = FALSE; | 1083 | ExitWithLastError(hr, "Failed to set log finished event."); |
| 932 | } | 1084 | } |
| 933 | 1085 | ||
| 1086 | hr = AppWaitForSingleObject(hLoggingThread, 5 * 60 * 1000); // TODO: is 5 minutes good? | ||
| 1087 | ExitOnFailure(hr, "Failed to wait for elevated logging thread."); | ||
| 1088 | |||
| 1089 | LExit: | ||
| 1090 | return hr; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | static HRESULT WaitForUnelevatedLoggingThread( | ||
| 1094 | __in HANDLE hUnelevatedLoggingThread | ||
| 1095 | ) | ||
| 1096 | { | ||
| 1097 | HRESULT hr = S_OK; | ||
| 1098 | |||
| 1099 | // Give the thread 15 seconds to exit. | ||
| 1100 | hr = AppWaitForSingleObject(hUnelevatedLoggingThread, 15 * 1000); | ||
| 1101 | ExitOnFailure(hr, "Failed to wait for unelevated logging thread."); | ||
| 1102 | |||
| 1103 | LExit: | ||
| 934 | return hr; | 1104 | return hr; |
| 935 | } | 1105 | } |
| 936 | 1106 | ||
diff --git a/src/burn/engine/pipe.cpp b/src/burn/engine/pipe.cpp index 9529ef40..19bdcaa2 100644 --- a/src/burn/engine/pipe.cpp +++ b/src/burn/engine/pipe.cpp | |||
| @@ -8,6 +8,7 @@ static const DWORD PIPE_RETRY_FOR_CONNECTION = 1800; // for up to 3 minutes. | |||
| 8 | 8 | ||
| 9 | static const LPCWSTR PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls"; | 9 | static const LPCWSTR PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls"; |
| 10 | static const LPCWSTR CACHE_PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls.Cache"; | 10 | static const LPCWSTR CACHE_PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls.Cache"; |
| 11 | static const LPCWSTR LOGGING_PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls.Log"; | ||
| 11 | 12 | ||
| 12 | static HRESULT AllocatePipeMessage( | 13 | static HRESULT AllocatePipeMessage( |
| 13 | __in DWORD dwMessage, | 14 | __in DWORD dwMessage, |
| @@ -48,6 +49,7 @@ void PipeConnectionInitialize( | |||
| 48 | memset(pConnection, 0, sizeof(BURN_PIPE_CONNECTION)); | 49 | memset(pConnection, 0, sizeof(BURN_PIPE_CONNECTION)); |
| 49 | pConnection->hPipe = INVALID_HANDLE_VALUE; | 50 | pConnection->hPipe = INVALID_HANDLE_VALUE; |
| 50 | pConnection->hCachePipe = INVALID_HANDLE_VALUE; | 51 | pConnection->hCachePipe = INVALID_HANDLE_VALUE; |
| 52 | pConnection->hLoggingPipe = INVALID_HANDLE_VALUE; | ||
| 51 | } | 53 | } |
| 52 | 54 | ||
| 53 | /******************************************************************* | 55 | /******************************************************************* |
| @@ -58,15 +60,14 @@ void PipeConnectionUninitialize( | |||
| 58 | __in BURN_PIPE_CONNECTION* pConnection | 60 | __in BURN_PIPE_CONNECTION* pConnection |
| 59 | ) | 61 | ) |
| 60 | { | 62 | { |
| 63 | ReleaseFileHandle(pConnection->hLoggingPipe); | ||
| 61 | ReleaseFileHandle(pConnection->hCachePipe); | 64 | ReleaseFileHandle(pConnection->hCachePipe); |
| 62 | ReleaseFileHandle(pConnection->hPipe); | 65 | ReleaseFileHandle(pConnection->hPipe); |
| 63 | ReleaseHandle(pConnection->hProcess); | 66 | ReleaseHandle(pConnection->hProcess); |
| 64 | ReleaseStr(pConnection->sczSecret); | 67 | ReleaseStr(pConnection->sczSecret); |
| 65 | ReleaseStr(pConnection->sczName); | 68 | ReleaseStr(pConnection->sczName); |
| 66 | 69 | ||
| 67 | memset(pConnection, 0, sizeof(BURN_PIPE_CONNECTION)); | 70 | PipeConnectionInitialize(pConnection); |
| 68 | pConnection->hPipe = INVALID_HANDLE_VALUE; | ||
| 69 | pConnection->hCachePipe = INVALID_HANDLE_VALUE; | ||
| 70 | } | 71 | } |
| 71 | 72 | ||
| 72 | /******************************************************************* | 73 | /******************************************************************* |
| @@ -235,13 +236,13 @@ LExit: | |||
| 235 | *******************************************************************/ | 236 | *******************************************************************/ |
| 236 | extern "C" HRESULT PipeCreatePipes( | 237 | extern "C" HRESULT PipeCreatePipes( |
| 237 | __in BURN_PIPE_CONNECTION* pConnection, | 238 | __in BURN_PIPE_CONNECTION* pConnection, |
| 238 | __in BOOL fCreateCachePipe, | 239 | __in BOOL fCompanion |
| 239 | __out HANDLE* phEvent | ||
| 240 | ) | 240 | ) |
| 241 | { | 241 | { |
| 242 | Assert(pConnection->sczName); | 242 | Assert(pConnection->sczName); |
| 243 | Assert(INVALID_HANDLE_VALUE == pConnection->hPipe); | 243 | Assert(INVALID_HANDLE_VALUE == pConnection->hPipe); |
| 244 | Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe); | 244 | Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe); |
| 245 | Assert(INVALID_HANDLE_VALUE == pConnection->hLoggingPipe); | ||
| 245 | 246 | ||
| 246 | HRESULT hr = S_OK; | 247 | HRESULT hr = S_OK; |
| 247 | PSECURITY_DESCRIPTOR psd = NULL; | 248 | PSECURITY_DESCRIPTOR psd = NULL; |
| @@ -249,10 +250,10 @@ extern "C" HRESULT PipeCreatePipes( | |||
| 249 | LPWSTR sczFullPipeName = NULL; | 250 | LPWSTR sczFullPipeName = NULL; |
| 250 | HANDLE hPipe = INVALID_HANDLE_VALUE; | 251 | HANDLE hPipe = INVALID_HANDLE_VALUE; |
| 251 | HANDLE hCachePipe = INVALID_HANDLE_VALUE; | 252 | HANDLE hCachePipe = INVALID_HANDLE_VALUE; |
| 253 | HANDLE hLoggingPipe = INVALID_HANDLE_VALUE; | ||
| 252 | 254 | ||
| 253 | // Only the grant special rights when the pipe is being used for "embedded" | 255 | // Only grant special rights when the pipe is being used for "embedded" scenarios. |
| 254 | // scenarios (aka: there is no cache pipe). | 256 | if (!fCompanion) |
| 255 | if (!fCreateCachePipe) | ||
| 256 | { | 257 | { |
| 257 | // Create the security descriptor that grants read/write/sync access to Everyone. | 258 | // Create the security descriptor that grants read/write/sync access to Everyone. |
| 258 | // TODO: consider locking down "WD" to LogonIds (logon session) | 259 | // TODO: consider locking down "WD" to LogonIds (logon session) |
| @@ -278,7 +279,7 @@ extern "C" HRESULT PipeCreatePipes( | |||
| 278 | ExitWithLastError(hr, "Failed to create pipe: %ls", sczFullPipeName); | 279 | ExitWithLastError(hr, "Failed to create pipe: %ls", sczFullPipeName); |
| 279 | } | 280 | } |
| 280 | 281 | ||
| 281 | if (fCreateCachePipe) | 282 | if (fCompanion) |
| 282 | { | 283 | { |
| 283 | // Create the cache pipe. | 284 | // Create the cache pipe. |
| 284 | hr = StrAllocFormatted(&sczFullPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName); | 285 | hr = StrAllocFormatted(&sczFullPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName); |
| @@ -287,20 +288,31 @@ extern "C" HRESULT PipeCreatePipes( | |||
| 287 | hCachePipe = ::CreateNamedPipeW(sczFullPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, PIPE_64KB, PIPE_64KB, 1, NULL); | 288 | hCachePipe = ::CreateNamedPipeW(sczFullPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, PIPE_64KB, PIPE_64KB, 1, NULL); |
| 288 | if (INVALID_HANDLE_VALUE == hCachePipe) | 289 | if (INVALID_HANDLE_VALUE == hCachePipe) |
| 289 | { | 290 | { |
| 290 | ExitWithLastError(hr, "Failed to create pipe: %ls", sczFullPipeName); | 291 | ExitWithLastError(hr, "Failed to create cache pipe: %ls", sczFullPipeName); |
| 292 | } | ||
| 293 | |||
| 294 | // Create the logging pipe. | ||
| 295 | hr = StrAllocFormatted(&sczFullPipeName, LOGGING_PIPE_NAME_FORMAT_STRING, pConnection->sczName); | ||
| 296 | ExitOnFailure(hr, "Failed to allocate full name of logging pipe: %ls", pConnection->sczName); | ||
| 297 | |||
| 298 | hLoggingPipe = ::CreateNamedPipeW(sczFullPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, PIPE_64KB, PIPE_64KB, 1, NULL); | ||
| 299 | if (INVALID_HANDLE_VALUE == hLoggingPipe) | ||
| 300 | { | ||
| 301 | ExitWithLastError(hr, "Failed to create logging pipe: %ls", sczFullPipeName); | ||
| 291 | } | 302 | } |
| 292 | } | 303 | } |
| 293 | 304 | ||
| 305 | pConnection->hLoggingPipe = hLoggingPipe; | ||
| 306 | hLoggingPipe = INVALID_HANDLE_VALUE; | ||
| 307 | |||
| 294 | pConnection->hCachePipe = hCachePipe; | 308 | pConnection->hCachePipe = hCachePipe; |
| 295 | hCachePipe = INVALID_HANDLE_VALUE; | 309 | hCachePipe = INVALID_HANDLE_VALUE; |
| 296 | 310 | ||
| 297 | pConnection->hPipe = hPipe; | 311 | pConnection->hPipe = hPipe; |
| 298 | hPipe = INVALID_HANDLE_VALUE; | 312 | hPipe = INVALID_HANDLE_VALUE; |
| 299 | 313 | ||
| 300 | // TODO: remove the following | ||
| 301 | *phEvent = NULL; | ||
| 302 | |||
| 303 | LExit: | 314 | LExit: |
| 315 | ReleaseFileHandle(hLoggingPipe); | ||
| 304 | ReleaseFileHandle(hCachePipe); | 316 | ReleaseFileHandle(hCachePipe); |
| 305 | ReleaseFileHandle(hPipe); | 317 | ReleaseFileHandle(hPipe); |
| 306 | ReleaseStr(sczFullPipeName); | 318 | ReleaseStr(sczFullPipeName); |
| @@ -322,7 +334,7 @@ extern "C" HRESULT PipeWaitForChildConnect( | |||
| 322 | ) | 334 | ) |
| 323 | { | 335 | { |
| 324 | HRESULT hr = S_OK; | 336 | HRESULT hr = S_OK; |
| 325 | HANDLE hPipes[2] = { pConnection->hPipe, pConnection->hCachePipe}; | 337 | HANDLE hPipes[3] = { pConnection->hPipe, pConnection->hCachePipe, pConnection->hLoggingPipe}; |
| 326 | LPCWSTR wzSecret = pConnection->sczSecret; | 338 | LPCWSTR wzSecret = pConnection->sczSecret; |
| 327 | DWORD cbSecret = lstrlenW(wzSecret) * sizeof(WCHAR); | 339 | DWORD cbSecret = lstrlenW(wzSecret) * sizeof(WCHAR); |
| 328 | DWORD dwCurrentProcessId = ::GetCurrentProcessId(); | 340 | DWORD dwCurrentProcessId = ::GetCurrentProcessId(); |
| @@ -410,6 +422,32 @@ LExit: | |||
| 410 | } | 422 | } |
| 411 | 423 | ||
| 412 | /******************************************************************* | 424 | /******************************************************************* |
| 425 | PipeTerminateLoggingPipe - | ||
| 426 | |||
| 427 | *******************************************************************/ | ||
| 428 | extern "C" HRESULT PipeTerminateLoggingPipe( | ||
| 429 | __in HANDLE hLoggingPipe, | ||
| 430 | __in DWORD dwParentExitCode | ||
| 431 | ) | ||
| 432 | { | ||
| 433 | HRESULT hr = S_OK; | ||
| 434 | BYTE* pbData = NULL; | ||
| 435 | SIZE_T cbData = 0; | ||
| 436 | |||
| 437 | // Prepare the exit message. | ||
| 438 | hr = BuffWriteNumber(&pbData, &cbData, dwParentExitCode); | ||
| 439 | ExitOnFailure(hr, "Failed to write exit code to message buffer."); | ||
| 440 | |||
| 441 | hr = WritePipeMessage(hLoggingPipe, static_cast<DWORD>(BURN_PIPE_MESSAGE_TYPE_COMPLETE), pbData, cbData); | ||
| 442 | ExitOnFailure(hr, "Failed to post complete message to logging pipe."); | ||
| 443 | |||
| 444 | LExit: | ||
| 445 | ReleaseBuffer(pbData); | ||
| 446 | |||
| 447 | return hr; | ||
| 448 | } | ||
| 449 | |||
| 450 | /******************************************************************* | ||
| 413 | PipeTerminateChildProcess - | 451 | PipeTerminateChildProcess - |
| 414 | 452 | ||
| 415 | *******************************************************************/ | 453 | *******************************************************************/ |
| @@ -468,6 +506,8 @@ extern "C" HRESULT PipeTerminateChildProcess( | |||
| 468 | #endif | 506 | #endif |
| 469 | 507 | ||
| 470 | LExit: | 508 | LExit: |
| 509 | ReleaseBuffer(pbData); | ||
| 510 | |||
| 471 | return hr; | 511 | return hr; |
| 472 | } | 512 | } |
| 473 | 513 | ||
| @@ -478,7 +518,7 @@ LExit: | |||
| 478 | *******************************************************************/ | 518 | *******************************************************************/ |
| 479 | extern "C" HRESULT PipeChildConnect( | 519 | extern "C" HRESULT PipeChildConnect( |
| 480 | __in BURN_PIPE_CONNECTION* pConnection, | 520 | __in BURN_PIPE_CONNECTION* pConnection, |
| 481 | __in BOOL fConnectCachePipe | 521 | __in BOOL fCompanion |
| 482 | ) | 522 | ) |
| 483 | { | 523 | { |
| 484 | Assert(pConnection->sczName); | 524 | Assert(pConnection->sczName); |
| @@ -486,6 +526,7 @@ extern "C" HRESULT PipeChildConnect( | |||
| 486 | Assert(!pConnection->hProcess); | 526 | Assert(!pConnection->hProcess); |
| 487 | Assert(INVALID_HANDLE_VALUE == pConnection->hPipe); | 527 | Assert(INVALID_HANDLE_VALUE == pConnection->hPipe); |
| 488 | Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe); | 528 | Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe); |
| 529 | Assert(INVALID_HANDLE_VALUE == pConnection->hLoggingPipe); | ||
| 489 | 530 | ||
| 490 | HRESULT hr = S_OK; | 531 | HRESULT hr = S_OK; |
| 491 | LPWSTR sczPipeName = NULL; | 532 | LPWSTR sczPipeName = NULL; |
| @@ -519,7 +560,7 @@ extern "C" HRESULT PipeChildConnect( | |||
| 519 | hr = ChildPipeConnected(pConnection->hPipe, pConnection->sczSecret, &pConnection->dwProcessId); | 560 | hr = ChildPipeConnected(pConnection->hPipe, pConnection->sczSecret, &pConnection->dwProcessId); |
| 520 | ExitOnFailure(hr, "Failed to verify parent pipe: %ls", sczPipeName); | 561 | ExitOnFailure(hr, "Failed to verify parent pipe: %ls", sczPipeName); |
| 521 | 562 | ||
| 522 | if (fConnectCachePipe) | 563 | if (fCompanion) |
| 523 | { | 564 | { |
| 524 | // Connect to the parent for the cache pipe. | 565 | // Connect to the parent for the cache pipe. |
| 525 | hr = StrAllocFormatted(&sczPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName); | 566 | hr = StrAllocFormatted(&sczPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName); |
| @@ -528,12 +569,26 @@ extern "C" HRESULT PipeChildConnect( | |||
| 528 | pConnection->hCachePipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); | 569 | pConnection->hCachePipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); |
| 529 | if (INVALID_HANDLE_VALUE == pConnection->hCachePipe) | 570 | if (INVALID_HANDLE_VALUE == pConnection->hCachePipe) |
| 530 | { | 571 | { |
| 531 | ExitWithLastError(hr, "Failed to open parent pipe: %ls", sczPipeName) | 572 | ExitWithLastError(hr, "Failed to open parent cache pipe: %ls", sczPipeName) |
| 532 | } | 573 | } |
| 533 | 574 | ||
| 534 | // Verify the parent and notify it that the child connected. | 575 | // Verify the parent and notify it that the child connected. |
| 535 | hr = ChildPipeConnected(pConnection->hCachePipe, pConnection->sczSecret, &pConnection->dwProcessId); | 576 | hr = ChildPipeConnected(pConnection->hCachePipe, pConnection->sczSecret, &pConnection->dwProcessId); |
| 536 | ExitOnFailure(hr, "Failed to verify parent pipe: %ls", sczPipeName); | 577 | ExitOnFailure(hr, "Failed to verify parent cache pipe: %ls", sczPipeName); |
| 578 | |||
| 579 | // Connect to the parent for the logging pipe. | ||
| 580 | hr = StrAllocFormatted(&sczPipeName, LOGGING_PIPE_NAME_FORMAT_STRING, pConnection->sczName); | ||
| 581 | ExitOnFailure(hr, "Failed to allocate name of parent logging pipe."); | ||
| 582 | |||
| 583 | pConnection->hLoggingPipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); | ||
| 584 | if (INVALID_HANDLE_VALUE == pConnection->hLoggingPipe) | ||
| 585 | { | ||
| 586 | ExitWithLastError(hr, "Failed to open parent logging pipe: %ls", sczPipeName) | ||
| 587 | } | ||
| 588 | |||
| 589 | // Verify the parent and notify it that the child connected. | ||
| 590 | hr = ChildPipeConnected(pConnection->hLoggingPipe, pConnection->sczSecret, &pConnection->dwProcessId); | ||
| 591 | ExitOnFailure(hr, "Failed to verify parent logging pipe: %ls", sczPipeName); | ||
| 537 | } | 592 | } |
| 538 | 593 | ||
| 539 | pConnection->hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, pConnection->dwProcessId); | 594 | pConnection->hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, pConnection->dwProcessId); |
diff --git a/src/burn/engine/pipe.h b/src/burn/engine/pipe.h index f2d8070e..6571c0e2 100644 --- a/src/burn/engine/pipe.h +++ b/src/burn/engine/pipe.h | |||
| @@ -15,6 +15,7 @@ typedef struct _BURN_PIPE_CONNECTION | |||
| 15 | HANDLE hProcess; | 15 | HANDLE hProcess; |
| 16 | HANDLE hPipe; | 16 | HANDLE hPipe; |
| 17 | HANDLE hCachePipe; | 17 | HANDLE hCachePipe; |
| 18 | HANDLE hLoggingPipe; | ||
| 18 | } BURN_PIPE_CONNECTION; | 19 | } BURN_PIPE_CONNECTION; |
| 19 | 20 | ||
| 20 | typedef enum _BURN_PIPE_MESSAGE_TYPE : DWORD | 21 | typedef enum _BURN_PIPE_MESSAGE_TYPE : DWORD |
| @@ -77,12 +78,15 @@ HRESULT PipeCreateNameAndSecret( | |||
| 77 | ); | 78 | ); |
| 78 | HRESULT PipeCreatePipes( | 79 | HRESULT PipeCreatePipes( |
| 79 | __in BURN_PIPE_CONNECTION* pConnection, | 80 | __in BURN_PIPE_CONNECTION* pConnection, |
| 80 | __in BOOL fCreateCachePipe, | 81 | __in BOOL fCompanion |
| 81 | __out HANDLE* phEvent | ||
| 82 | ); | 82 | ); |
| 83 | HRESULT PipeWaitForChildConnect( | 83 | HRESULT PipeWaitForChildConnect( |
| 84 | __in BURN_PIPE_CONNECTION* pConnection | 84 | __in BURN_PIPE_CONNECTION* pConnection |
| 85 | ); | 85 | ); |
| 86 | HRESULT PipeTerminateLoggingPipe( | ||
| 87 | __in HANDLE hLoggingPipe, | ||
| 88 | __in DWORD dwParentExitCode | ||
| 89 | ); | ||
| 86 | HRESULT PipeTerminateChildProcess( | 90 | HRESULT PipeTerminateChildProcess( |
| 87 | __in BURN_PIPE_CONNECTION* pConnection, | 91 | __in BURN_PIPE_CONNECTION* pConnection, |
| 88 | __in DWORD dwParentExitCode, | 92 | __in DWORD dwParentExitCode, |
| @@ -92,7 +96,7 @@ HRESULT PipeTerminateChildProcess( | |||
| 92 | // Child functions. | 96 | // Child functions. |
| 93 | HRESULT PipeChildConnect( | 97 | HRESULT PipeChildConnect( |
| 94 | __in BURN_PIPE_CONNECTION* pConnection, | 98 | __in BURN_PIPE_CONNECTION* pConnection, |
| 95 | __in BOOL fConnectCachePipe | 99 | __in BOOL fCompanion |
| 96 | ); | 100 | ); |
| 97 | 101 | ||
| 98 | #ifdef __cplusplus | 102 | #ifdef __cplusplus |
diff --git a/src/burn/engine/uithread.cpp b/src/burn/engine/uithread.cpp index fe1c21b8..26a9b723 100644 --- a/src/burn/engine/uithread.cpp +++ b/src/burn/engine/uithread.cpp | |||
| @@ -107,18 +107,6 @@ static DWORD WINAPI ThreadProc( | |||
| 107 | BURN_ENGINE_STATE* pEngineState = pContext->pEngineState; | 107 | BURN_ENGINE_STATE* pEngineState = pContext->pEngineState; |
| 108 | BOOL fElevatedEngine = BURN_MODE_ELEVATED == pContext->pEngineState->internalCommand.mode; | 108 | BOOL fElevatedEngine = BURN_MODE_ELEVATED == pContext->pEngineState->internalCommand.mode; |
| 109 | 109 | ||
| 110 | // If elevated, set up the thread local storage to store the correct pipe to communicate logging. | ||
| 111 | if (fElevatedEngine) | ||
| 112 | { | ||
| 113 | Assert(TLS_OUT_OF_INDEXES != pEngineState->dwElevatedLoggingTlsId); | ||
| 114 | |||
| 115 | if (!::TlsSetValue(pEngineState->dwElevatedLoggingTlsId, pEngineState->companionConnection.hPipe)) | ||
| 116 | { | ||
| 117 | // If the function failed we cannot write to the pipe so just terminate. | ||
| 118 | ExitFunction1(hr = E_INVALIDSTATE); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | wc.lpfnWndProc = WndProc; | 110 | wc.lpfnWndProc = WndProc; |
| 123 | wc.hInstance = pContext->hInstance; | 111 | wc.hInstance = pContext->hInstance; |
| 124 | wc.lpszClassName = BURN_UITHREAD_CLASS_WINDOW; | 112 | wc.lpszClassName = BURN_UITHREAD_CLASS_WINDOW; |
diff --git a/src/libs/dutil/WixToolset.DUtil/logutil.cpp b/src/libs/dutil/WixToolset.DUtil/logutil.cpp index 3a130b4e..1453d1d2 100644 --- a/src/libs/dutil/WixToolset.DUtil/logutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/logutil.cpp | |||
| @@ -222,8 +222,12 @@ void DAPI LogRedirect( | |||
| 222 | __in_opt LPVOID pvContext | 222 | __in_opt LPVOID pvContext |
| 223 | ) | 223 | ) |
| 224 | { | 224 | { |
| 225 | ::EnterCriticalSection(&LogUtil_csLog); | ||
| 226 | |||
| 225 | s_vpfLogStringWorkRaw = vpfLogStringWorkRaw; | 227 | s_vpfLogStringWorkRaw = vpfLogStringWorkRaw; |
| 226 | s_vpvLogStringWorkRawContext = pvContext; | 228 | s_vpvLogStringWorkRawContext = pvContext; |
| 229 | |||
| 230 | ::LeaveCriticalSection(&LogUtil_csLog); | ||
| 227 | } | 231 | } |
| 228 | 232 | ||
| 229 | 233 | ||
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/FilesInUseTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/FilesInUseTests.cs index 12eca77d..1b2356e3 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/FilesInUseTests.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/FilesInUseTests.cs | |||
| @@ -34,7 +34,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 34 | packageA.VerifyInstalled(false); | 34 | packageA.VerifyInstalled(false); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | [RuntimeFact] | 37 | [LongRuntimeFact] |
| 38 | public void WixStdBAFailsWithLockedFile() | 38 | public void WixStdBAFailsWithLockedFile() |
| 39 | { | 39 | { |
| 40 | var packageA = this.CreatePackageInstaller("PackageA"); | 40 | var packageA = this.CreatePackageInstaller("PackageA"); |
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs index ba793d7a..b751ff75 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs | |||
| @@ -284,6 +284,11 @@ namespace WixToolsetTest.BurnE2E | |||
| 284 | { | 284 | { |
| 285 | WixAssert.Skip($"MAX_PATH is being enforced ({baseFolder})"); | 285 | WixAssert.Skip($"MAX_PATH is being enforced ({baseFolder})"); |
| 286 | } | 286 | } |
| 287 | else if (lastError == 3) | ||
| 288 | { | ||
| 289 | // TODO: figure out why Windows Sandbox returns this error instead of 206 like all other environments. | ||
| 290 | WixAssert.Skip($"The system cannot find the path specified ({baseFolder})"); | ||
| 291 | } | ||
| 287 | throw new Win32Exception(lastError); | 292 | throw new Win32Exception(lastError); |
| 288 | } | 293 | } |
| 289 | } | 294 | } |
