main
cpp 1,069 lines 30.2 KB
Raw
1 // 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.
2
3 #include "precomp.h"
4
5
6 static DWORD vdwPackageSequence = 0;
7 static const DWORD LOG_OPEN_RETRY_COUNT = 3;
8 static const DWORD LOG_OPEN_RETRY_WAIT = 2000;
9 static CONST LPWSTR LOG_FAILED_EVENT_LOG_MESSAGE = L"Burn Engine Fatal Error: failed to open log file.";
10
11 // structs
12
13
14
15 // internal function declarations
16
17 static void CheckLoggingPolicy(
18 __inout DWORD* pdwAttributes
19 );
20 static HRESULT InitializeLogging(
21 __in BURN_LOGGING* pLog,
22 __in BURN_ENGINE_COMMAND* pInternalCommand
23 );
24 static HRESULT GetNonSessionSpecificTempFolder(
25 __deref_out_z LPWSTR* psczNonSessionTempFolder
26 );
27
28
29 // function definitions
30
31 extern "C" HRESULT LoggingParseFromXml(
32 __in BURN_LOGGING* pLog,
33 __in IXMLDOMNode* pixnBundle
34 )
35 {
36 HRESULT hr = S_OK;
37 IXMLDOMNode* pixnLog = NULL;
38 BOOL fXmlFound = FALSE;
39
40 // parse the log element, if present.
41 hr = XmlSelectSingleNode(pixnBundle, L"Log", &pixnLog);
42 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get Log element.");
43
44 if (fXmlFound)
45 {
46 hr = XmlGetAttributeEx(pixnLog, L"PathVariable", &pLog->sczPathVariable);
47 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get Log/@PathVariable.");
48
49 hr = XmlGetAttributeEx(pixnLog, L"Prefix", &pLog->sczPrefix);
50 ExitOnRequiredXmlQueryFailure(hr, "Failed to get Log/@Prefix attribute.");
51
52 hr = XmlGetAttributeEx(pixnLog, L"Extension", &pLog->sczExtension);
53 ExitOnRequiredXmlQueryFailure(hr, "Failed to get Log/@Extension attribute.");
54 }
55
56 LExit:
57 ReleaseObject(pixnLog);
58
59 return hr;
60 }
61
62 extern "C" HRESULT LoggingOpen(
63 __in BURN_LOGGING* pLog,
64 __in BURN_ENGINE_COMMAND* pInternalCommand,
65 __in BOOTSTRAPPER_COMMAND* pCommand,
66 __in BURN_VARIABLES* pVariables,
67 __in_z LPCWSTR wzBundleName
68 )
69 {
70 HRESULT hr = S_OK;
71 LPWSTR sczLoggingBaseFolder = NULL;
72 LPWSTR sczPrefixFormatted = NULL;
73 LPCWSTR wzPostfix = NULL;
74
75 switch (pInternalCommand->mode)
76 {
77 case BURN_MODE_ELEVATED:
78 wzPostfix = L".elevated";
79 break;
80 case BURN_MODE_RUNONCE:
81 wzPostfix = L".runonce";
82 break;
83 }
84
85 hr = InitializeLogging(pLog, pInternalCommand);
86 ExitOnFailure(hr, "Failed to initialize logging.");
87
88 if ((pLog->dwAttributes & BURN_LOGGING_ATTRIBUTE_VERBOSE) || (pLog->dwAttributes & BURN_LOGGING_ATTRIBUTE_EXTRADEBUG))
89 {
90 if (pLog->dwAttributes & BURN_LOGGING_ATTRIBUTE_EXTRADEBUG)
91 {
92 LogSetLevel(REPORT_DEBUG, FALSE);
93 }
94 else if (pLog->dwAttributes & BURN_LOGGING_ATTRIBUTE_VERBOSE)
95 {
96 LogSetLevel(REPORT_VERBOSE, FALSE);
97 }
98
99 // In these modes, make sure a log will be created even if the bundle wasn't configured to create one.
100 if ((!pLog->sczPath || !*pLog->sczPath) && (!pLog->sczPrefix || !*pLog->sczPrefix))
101 {
102 hr = StrAllocString(&pLog->sczPrefix, L"Setup", 0);
103 ExitOnFailure(hr, "Failed to copy default log prefix.");
104
105 if (!pLog->sczExtension || !*pLog->sczExtension)
106 {
107 hr = StrAllocString(&pLog->sczExtension, L"log", 0);
108 ExitOnFailure(hr, "Failed to copy default log extension.");
109 }
110 }
111 }
112
113 // Open the log appropriately.
114 if (pLog->sczPath && *pLog->sczPath)
115 {
116 DWORD cRetry = 0;
117
118 // Try pretty hard to open the log file when appending.
119 do
120 {
121 if (0 < cRetry)
122 {
123 ::Sleep(LOG_OPEN_RETRY_WAIT);
124 }
125
126 hr = LogOpen(NULL, pLog->sczPath, NULL, NULL, pLog->dwAttributes & BURN_LOGGING_ATTRIBUTE_APPEND, FALSE, &pLog->sczPath);
127 if (pLog->dwAttributes & BURN_LOGGING_ATTRIBUTE_APPEND && HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) == hr)
128 {
129 ++cRetry;
130 }
131 } while (cRetry > 0 && cRetry <= LOG_OPEN_RETRY_COUNT);
132
133 if (FAILED(hr))
134 {
135 // Log is not open, so note that.
136 LogDisable();
137 pLog->state = BURN_LOGGING_STATE_DISABLED;
138
139 if (pLog->dwAttributes & BURN_LOGGING_ATTRIBUTE_APPEND)
140 {
141 // If appending, ignore the failure and continue.
142 hr = S_OK;
143 }
144 else // specifically tried to create a log file so show an error if appropriate and bail.
145 {
146 HRESULT hrOriginal = hr;
147
148 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_LOG_FAILURE);
149 SplashScreenDisplayError(pCommand->display, wzBundleName, hr);
150
151 ExitOnFailure(hrOriginal, "Failed to open log: %ls", pLog->sczPath);
152 }
153 }
154 else
155 {
156 pLog->state = BURN_LOGGING_STATE_OPEN;
157 }
158 }
159 else
160 {
161 if (pLog->sczPrefix && *pLog->sczPrefix)
162 {
163 hr = VariableFormatString(pVariables, pLog->sczPrefix, &sczPrefixFormatted, NULL);
164 }
165
166 if (sczPrefixFormatted && *sczPrefixFormatted)
167 {
168 // Best effort to open default logging.
169 LPCWSTR wzPrefix = sczPrefixFormatted;
170 LPCWSTR wzPastRoot = PathSkipPastRoot(sczPrefixFormatted, NULL, NULL, NULL);
171
172 // If the log path is rooted and has a file component, then use that path as is.
173 if (wzPastRoot && *wzPastRoot)
174 {
175 hr = PathGetDirectory(sczPrefixFormatted, &sczLoggingBaseFolder);
176 ExitOnFailure(hr, "Failed to get parent directory from '%ls'.", sczPrefixFormatted);
177
178 wzPrefix = PathFile(sczPrefixFormatted);
179 }
180 else
181 {
182 hr = GetNonSessionSpecificTempFolder(&sczLoggingBaseFolder);
183 ExitOnFailure(hr, "Failed to get non-session specific TEMP folder.");
184 }
185
186 hr = LogOpen(sczLoggingBaseFolder, wzPrefix, wzPostfix, pLog->sczExtension, FALSE, FALSE, &pLog->sczPath);
187 if (FAILED(hr))
188 {
189 LogDisable();
190 pLog->state = BURN_LOGGING_STATE_DISABLED;
191
192 hr = S_OK;
193 }
194 else
195 {
196 pLog->state = BURN_LOGGING_STATE_OPEN;
197 }
198 }
199 else // no logging enabled.
200 {
201 LogDisable();
202 pLog->state = BURN_LOGGING_STATE_DISABLED;
203 }
204 }
205
206 // If the log was opened, write the header info and update the prefix and extension to match
207 // the log name so future logs are opened with the same pattern.
208 if (BURN_LOGGING_STATE_OPEN == pLog->state)
209 {
210 LPCWSTR wzExtension = PathExtension(pLog->sczPath);
211 if (wzExtension && *wzExtension)
212 {
213 hr = StrAllocString(&pLog->sczPrefix, pLog->sczPath, wzExtension - pLog->sczPath);
214 ExitOnFailure(hr, "Failed to copy log path to prefix.");
215
216 hr = StrAllocString(&pLog->sczExtension, wzExtension + 1, 0);
217 ExitOnFailure(hr, "Failed to copy log extension to extension.");
218 }
219 else
220 {
221 hr = StrAllocString(&pLog->sczPrefix, pLog->sczPath, 0);
222 ExitOnFailure(hr, "Failed to copy full log path to prefix.");
223 }
224
225 if (pLog->sczPathVariable && *pLog->sczPathVariable)
226 {
227 VariableSetString(pVariables, pLog->sczPathVariable, pLog->sczPath, FALSE, FALSE); // Ignore failure.
228 }
229 }
230
231 LExit:
232 ReleaseStr(sczLoggingBaseFolder);
233 StrSecureZeroFreeString(sczPrefixFormatted);
234
235 return hr;
236 }
237
238 extern "C" void LoggingOpenFailed()
239 {
240 HRESULT hr = S_OK;
241 HANDLE hEventLog = NULL;
242 LPCWSTR* lpStrings = const_cast<LPCWSTR*>(&LOG_FAILED_EVENT_LOG_MESSAGE);
243 WORD wNumStrings = 1;
244
245 hr = LogOpen(NULL, L"Setup", L"_Failed", L"log", FALSE, FALSE, NULL);
246 if (SUCCEEDED(hr))
247 {
248 ExitFunction();
249 }
250
251 // If opening the "failure" log failed, then attempt to record that in the Application event log.
252 hEventLog = ::OpenEventLogW(NULL, L"Application");
253 ExitOnNullWithLastError(hEventLog, hr, "Failed to open Application event log");
254
255 hr = ::ReportEventW(hEventLog, EVENTLOG_ERROR_TYPE, 1, 1, NULL, wNumStrings, 0, lpStrings, NULL);
256 ExitOnNullWithLastError(hEventLog, hr, "Failed to write event log entry");
257
258 LExit:
259 if (hEventLog)
260 {
261 ::CloseEventLog(hEventLog);
262 }
263 }
264
265 extern "C" void LoggingIncrementPackageSequence()
266 {
267 ++vdwPackageSequence;
268 }
269
270 extern "C" HRESULT LoggingSetCompatiblePackageVariable(
271 __in BURN_PACKAGE* pPackage,
272 __in BURN_LOGGING* pLog,
273 __in BURN_VARIABLES* pVariables,
274 __out_opt LPWSTR* psczLogPath
275 )
276 {
277 HRESULT hr = S_OK;
278 LPWSTR sczLogPath = NULL;
279
280 // Make sure that no package log files are created when logging has been disabled via Log element.
281 if (BURN_LOGGING_STATE_DISABLED == pLog->state)
282 {
283 ExitFunction();
284 }
285
286 if (pPackage->sczCompatibleLogPathVariable && *pPackage->sczCompatibleLogPathVariable)
287 {
288 hr = StrAllocFormatted(&sczLogPath, L"%ls_%03u_%ls_%ls.%ls", pLog->sczPrefix, vdwPackageSequence, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pLog->sczExtension);
289 ExitOnFailure(hr, "Failed to allocate path for package log.");
290
291 hr = VariableSetString(pVariables, pPackage->sczCompatibleLogPathVariable, sczLogPath, FALSE, FALSE);
292 ExitOnFailure(hr, "Failed to set log path into variable.");
293
294 if (psczLogPath)
295 {
296 hr = StrAllocString(psczLogPath, sczLogPath, 0);
297 ExitOnFailure(hr, "Failed to copy package log path.");
298 }
299 }
300
301 LExit:
302 ReleaseStr(sczLogPath);
303
304 return hr;
305 }
306
307 extern "C" HRESULT LoggingSetPackageVariable(
308 __in BURN_PACKAGE* pPackage,
309 __in_z_opt LPCWSTR wzSuffix,
310 __in BOOL fRollback,
311 __in BURN_LOGGING* pLog,
312 __in BURN_VARIABLES* pVariables,
313 __out_opt LPWSTR* psczLogPath
314 )
315 {
316 HRESULT hr = S_OK;
317 LPWSTR sczLogPath = NULL;
318
319 // Make sure that no package log files are created when logging has been disabled via Log element.
320 if (BURN_LOGGING_STATE_DISABLED == pLog->state)
321 {
322 ExitFunction();
323 }
324
325 // For burn packages we'll add logging even it it wasn't explictly specified
326 if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || (BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_PROTOCOL_TYPE_BURN == pPackage->Exe.protocol))
327 {
328 if (!fRollback && (!pPackage->sczLogPathVariable || !*pPackage->sczLogPathVariable))
329 {
330 StrAllocFormatted(&pPackage->sczLogPathVariable, L"WixBundleLog_%ls", pPackage->sczId);
331 }
332 else if (fRollback && (!pPackage->sczRollbackLogPathVariable || !*pPackage->sczRollbackLogPathVariable))
333 {
334 StrAllocFormatted(&pPackage->sczRollbackLogPathVariable, L"WixBundleRollbackLog_%ls", pPackage->sczId);
335 }
336 }
337
338 if ((!fRollback && pPackage->sczLogPathVariable && *pPackage->sczLogPathVariable) ||
339 (fRollback && pPackage->sczRollbackLogPathVariable && *pPackage->sczRollbackLogPathVariable))
340 {
341 hr = StrAllocFormatted(&sczLogPath, L"%ls%hs%ls_%03u_%ls%ls.%ls", pLog->sczPrefix, wzSuffix && *wzSuffix ? "_" : "", wzSuffix && *wzSuffix ? wzSuffix : L"", vdwPackageSequence, pPackage->sczId, fRollback ? L"_rollback" : L"", pLog->sczExtension);
342 ExitOnFailure(hr, "Failed to allocate path for package log.");
343
344 hr = VariableSetString(pVariables, fRollback ? pPackage->sczRollbackLogPathVariable : pPackage->sczLogPathVariable, sczLogPath, FALSE, FALSE);
345 ExitOnFailure(hr, "Failed to set log path into variable.");
346
347 if (psczLogPath)
348 {
349 hr = StrAllocString(psczLogPath, sczLogPath, 0);
350 ExitOnFailure(hr, "Failed to copy package log path.");
351 }
352 }
353
354 LExit:
355 ReleaseStr(sczLogPath);
356
357 return hr;
358 }
359
360 extern "C" HRESULT LoggingSetTransactionVariable(
361 __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
362 __in_z_opt LPCWSTR wzSuffix,
363 __in BURN_LOGGING* pLog,
364 __in BURN_VARIABLES* pVariables
365 )
366 {
367 HRESULT hr = S_OK;
368
369 // Make sure that no log files are created when logging has been disabled via Log element.
370 if (BURN_LOGGING_STATE_DISABLED == pLog->state)
371 {
372 ExitFunction();
373 }
374
375 if (pRollbackBoundary && pRollbackBoundary->sczLogPathVariable && *pRollbackBoundary->sczLogPathVariable)
376 {
377 hr = StrAllocFormatted(&pRollbackBoundary->sczLogPath, L"%ls%hs%ls_%03u_%ls.%ls", pLog->sczPrefix, wzSuffix && *wzSuffix ? "_" : "", wzSuffix && *wzSuffix ? wzSuffix : L"", vdwPackageSequence, pRollbackBoundary->sczId, pLog->sczExtension);
378 ExitOnFailure(hr, "Failed to allocate path for transaction log.");
379
380 hr = VariableSetString(pVariables, pRollbackBoundary->sczLogPathVariable, pRollbackBoundary->sczLogPath, FALSE, FALSE);
381 ExitOnFailure(hr, "Failed to set log path into variable.");
382 }
383
384 LExit:
385 ++vdwPackageSequence;
386
387 return hr;
388 }
389
390 extern "C" LPCSTR LoggingBurnActionToString(
391 __in BOOTSTRAPPER_ACTION action
392 )
393 {
394 switch (action)
395 {
396 case BOOTSTRAPPER_ACTION_UNKNOWN:
397 return "Unknown";
398 case BOOTSTRAPPER_ACTION_HELP:
399 return "Help";
400 case BOOTSTRAPPER_ACTION_LAYOUT:
401 return "Layout";
402 case BOOTSTRAPPER_ACTION_CACHE:
403 return "Cache";
404 case BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL:
405 return "UnsafeUninstall";
406 case BOOTSTRAPPER_ACTION_UNINSTALL:
407 return "Uninstall";
408 case BOOTSTRAPPER_ACTION_INSTALL:
409 return "Install";
410 case BOOTSTRAPPER_ACTION_MODIFY:
411 return "Modify";
412 case BOOTSTRAPPER_ACTION_REPAIR:
413 return "Repair";
414 case BOOTSTRAPPER_ACTION_UPDATE_REPLACE:
415 return "UpdateReplace";
416 case BOOTSTRAPPER_ACTION_UPDATE_REPLACE_EMBEDDED:
417 return "UpdateReplaceEmbedded";
418 default:
419 return "Invalid";
420 }
421 }
422
423 LPCSTR LoggingBurnMessageToString(
424 __in UINT message
425 )
426 {
427 switch (message)
428 {
429 case WM_BURN_APPLY:
430 return "Apply";
431 case WM_BURN_DETECT:
432 return "Detect";
433 case WM_BURN_ELEVATE:
434 return "Elevate";
435 case WM_BURN_LAUNCH_APPROVED_EXE:
436 return "LaunchApprovedExe";
437 case WM_BURN_PLAN:
438 return "Plan";
439 case WM_BURN_QUIT:
440 return "Quit";
441 default:
442 return "Invalid";
443 }
444 }
445
446 extern "C" LPCSTR LoggingActionStateToString(
447 __in BOOTSTRAPPER_ACTION_STATE actionState
448 )
449 {
450 switch (actionState)
451 {
452 case BOOTSTRAPPER_ACTION_STATE_NONE:
453 return "None";
454 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
455 return "Uninstall";
456 case BOOTSTRAPPER_ACTION_STATE_INSTALL:
457 return "Install";
458 case BOOTSTRAPPER_ACTION_STATE_MODIFY:
459 return "Modify";
460 case BOOTSTRAPPER_ACTION_STATE_REPAIR:
461 return "Repair";
462 case BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE:
463 return "MinorUpgrade";
464 default:
465 return "Invalid";
466 }
467 }
468
469 extern "C" LPCSTR LoggingCacheTypeToString(
470 BOOTSTRAPPER_CACHE_TYPE cacheType
471 )
472 {
473 switch (cacheType)
474 {
475 case BOOTSTRAPPER_CACHE_TYPE_FORCE:
476 return "Force";
477 case BOOTSTRAPPER_CACHE_TYPE_KEEP:
478 return "Keep";
479 case BOOTSTRAPPER_CACHE_TYPE_REMOVE:
480 return "Remove";
481 default:
482 return "Invalid";
483 }
484 }
485
486 extern "C" LPCSTR LoggingCachePackageTypeToString(
487 BURN_CACHE_PACKAGE_TYPE cachePackageType
488 )
489 {
490 switch (cachePackageType)
491 {
492 case BURN_CACHE_PACKAGE_TYPE_NONE:
493 return "None";
494 case BURN_CACHE_PACKAGE_TYPE_OPTIONAL:
495 return "Optional";
496 case BURN_CACHE_PACKAGE_TYPE_REQUIRED:
497 return "Required";
498 default:
499 return "Invalid";
500 }
501 }
502
503 extern "C" LPCSTR LoggingDependencyActionToString(
504 BURN_DEPENDENCY_ACTION action
505 )
506 {
507 switch (action)
508 {
509 case BURN_DEPENDENCY_ACTION_NONE:
510 return "None";
511 case BURN_DEPENDENCY_ACTION_REGISTER:
512 return "Register";
513 case BURN_DEPENDENCY_ACTION_UNREGISTER:
514 return "Unregister";
515 default:
516 return "Invalid";
517 }
518 }
519
520 extern "C" LPCSTR LoggingBoolToString(
521 __in BOOL f
522 )
523 {
524 if (f)
525 {
526 return "Yes";
527 }
528
529 return "No";
530 }
531
532 extern "C" LPCSTR LoggingTrueFalseToString(
533 __in BOOL f
534 )
535 {
536 if (f)
537 {
538 return "true";
539 }
540
541 return "false";
542 }
543
544 extern "C" LPCSTR LoggingExitCodeTypeToString(
545 __in BURN_EXE_EXIT_CODE_TYPE exitCodeType
546 )
547 {
548 switch (exitCodeType)
549 {
550 case BURN_EXE_EXIT_CODE_TYPE_SUCCESS:
551 return "Success";
552 case BURN_EXE_EXIT_CODE_TYPE_ERROR:
553 return "Error";
554 case BURN_EXE_EXIT_CODE_TYPE_SCHEDULE_REBOOT:
555 return "ScheduleReboot";
556 case BURN_EXE_EXIT_CODE_TYPE_FORCE_REBOOT:
557 return "ForceReboot";
558 case BURN_EXE_EXIT_CODE_TYPE_ERROR_SCHEDULE_REBOOT:
559 return "ErrorScheduleReboot";
560 case BURN_EXE_EXIT_CODE_TYPE_ERROR_FORCE_REBOOT:
561 return "ErrorForceReboot";
562 default:
563 return "Invalid";
564 }
565 }
566
567 extern "C" LPCSTR LoggingPackageStateToString(
568 __in BOOTSTRAPPER_PACKAGE_STATE packageState
569 )
570 {
571 switch (packageState)
572 {
573 case BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN:
574 return "Unknown";
575 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE:
576 return "Obsolete";
577 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
578 return "Absent";
579 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT:
580 return "Present";
581 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
582 return "Superseded";
583 default:
584 return "Invalid";
585 }
586 }
587
588 extern "C" LPCSTR LoggingPackageRegistrationStateToString(
589 __in BOOL fCanAffectRegistration,
590 __in BURN_PACKAGE_REGISTRATION_STATE registrationState
591 )
592 {
593 if (!fCanAffectRegistration)
594 {
595 return "(permanent)";
596 }
597
598 switch (registrationState)
599 {
600 case BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN:
601 return "Unknown";
602 case BURN_PACKAGE_REGISTRATION_STATE_IGNORED:
603 return "Ignored";
604 case BURN_PACKAGE_REGISTRATION_STATE_ABSENT:
605 return "Absent";
606 case BURN_PACKAGE_REGISTRATION_STATE_PRESENT:
607 return "Present";
608 default:
609 return "Invalid";
610 }
611 }
612
613 extern "C" LPCSTR LoggingMsiFileVersioningToString(
614 __in BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning
615 )
616 {
617 switch (fileVersioning)
618 {
619 case BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER:
620 return "o";
621 case BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER_OR_EQUAL:
622 return "e";
623 case BOOTSTRAPPER_MSI_FILE_VERSIONING_ALL:
624 return "a";
625 default:
626 return "Invalid";
627 }
628 }
629
630 extern "C" LPCSTR LoggingMsiFeatureStateToString(
631 __in BOOTSTRAPPER_FEATURE_STATE featureState
632 )
633 {
634 switch (featureState)
635 {
636 case BOOTSTRAPPER_FEATURE_STATE_UNKNOWN:
637 return "Unknown";
638 case BOOTSTRAPPER_FEATURE_STATE_ABSENT:
639 return "Absent";
640 case BOOTSTRAPPER_FEATURE_STATE_ADVERTISED:
641 return "Advertised";
642 case BOOTSTRAPPER_FEATURE_STATE_LOCAL:
643 return "Local";
644 case BOOTSTRAPPER_FEATURE_STATE_SOURCE:
645 return "Source";
646 default:
647 return "Invalid";
648 }
649 }
650
651 extern "C" LPCSTR LoggingMsiFeatureActionToString(
652 __in BOOTSTRAPPER_FEATURE_ACTION featureAction
653 )
654 {
655 switch (featureAction)
656 {
657 case BOOTSTRAPPER_FEATURE_ACTION_NONE:
658 return "None";
659 case BOOTSTRAPPER_FEATURE_ACTION_ADDLOCAL:
660 return "AddLocal";
661 case BOOTSTRAPPER_FEATURE_ACTION_ADDSOURCE:
662 return "AddSource";
663 case BOOTSTRAPPER_FEATURE_ACTION_ADDDEFAULT:
664 return "AddDefault";
665 case BOOTSTRAPPER_FEATURE_ACTION_REINSTALL:
666 return "Reinstall";
667 case BOOTSTRAPPER_FEATURE_ACTION_ADVERTISE:
668 return "Advertise";
669 case BOOTSTRAPPER_FEATURE_ACTION_REMOVE:
670 return "Remove";
671 default:
672 return "Invalid";
673 }
674 }
675
676 extern "C" LPCSTR LoggingMsiInstallContext(
677 __in MSIINSTALLCONTEXT context
678 )
679 {
680 switch (context)
681 {
682 case MSIINSTALLCONTEXT_ALL:
683 return "All";
684 case MSIINSTALLCONTEXT_ALLUSERMANAGED:
685 return "AllUserManaged";
686 case MSIINSTALLCONTEXT_MACHINE:
687 return "Machine";
688 case MSIINSTALLCONTEXT_NONE:
689 return "None";
690 case MSIINSTALLCONTEXT_USERMANAGED:
691 return "UserManaged";
692 case MSIINSTALLCONTEXT_USERUNMANAGED:
693 return "UserUnmanaged";
694 default:
695 return "Invalid";
696 }
697 }
698
699 extern "C" LPCWSTR LoggingBurnMsiPropertyToString(
700 __in BURN_MSI_PROPERTY burnMsiProperty
701 )
702 {
703 switch (burnMsiProperty)
704 {
705 case BURN_MSI_PROPERTY_INSTALL:
706 return BURNMSIINSTALL_PROPERTY_NAME;
707 case BURN_MSI_PROPERTY_MODIFY:
708 return BURNMSIMODIFY_PROPERTY_NAME;
709 case BURN_MSI_PROPERTY_NONE:
710 return L"(none)";
711 case BURN_MSI_PROPERTY_REPAIR:
712 return BURNMSIREPAIR_PROPERTY_NAME;
713 case BURN_MSI_PROPERTY_UNINSTALL:
714 return BURNMSIUNINSTALL_PROPERTY_NAME;
715 default:
716 return L"Invalid";
717 }
718 }
719
720 extern "C" LPCSTR LoggingMspTargetActionToString(
721 __in BOOTSTRAPPER_ACTION_STATE action,
722 __in BURN_PATCH_SKIP_STATE skipState
723 )
724 {
725 switch (skipState)
726 {
727 case BURN_PATCH_SKIP_STATE_NONE:
728 return LoggingActionStateToString(action);
729 case BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL:
730 return "Skipped (target uninstall)";
731 case BURN_PATCH_SKIP_STATE_SLIPSTREAM:
732 return "Skipped (slipstream)";
733 default:
734 return "Invalid";
735 }
736 }
737
738 extern "C" LPCSTR LoggingPerMachineToString(
739 __in BOOL fPerMachine
740 )
741 {
742 if (fPerMachine)
743 {
744 return "PerMachine";
745 }
746
747 return "PerUser";
748 }
749
750 extern "C" LPCSTR LoggingPlannedCacheToString(
751 __in const BURN_PACKAGE* pPackage
752 )
753 {
754 if (!pPackage->hCacheEvent)
755 {
756 return "No";
757 }
758
759 return pPackage->fCacheVital ? "Vital" : "NonVital";
760 }
761
762 extern "C" LPCSTR LoggingRegistrationTypeToString(
763 __in BOOTSTRAPPER_REGISTRATION_TYPE registrationType
764 )
765 {
766 switch (registrationType)
767 {
768 case BOOTSTRAPPER_REGISTRATION_TYPE_NONE:
769 return "None";
770 case BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS:
771 return "InProgress";
772 case BOOTSTRAPPER_REGISTRATION_TYPE_FULL:
773 return "Full";
774 default:
775 return "Invalid";
776 }
777 }
778
779 extern "C" LPCSTR LoggingRestartToString(
780 __in BOOTSTRAPPER_APPLY_RESTART restart
781 )
782 {
783 switch (restart)
784 {
785 case BOOTSTRAPPER_APPLY_RESTART_NONE:
786 return "None";
787 case BOOTSTRAPPER_APPLY_RESTART_REQUIRED:
788 return "Required";
789 case BOOTSTRAPPER_APPLY_RESTART_INITIATED:
790 return "Initiated";
791 default:
792 return "Invalid";
793 }
794 }
795
796 extern "C" LPCSTR LoggingResumeModeToString(
797 __in BURN_RESUME_MODE resumeMode
798 )
799 {
800 switch (resumeMode)
801 {
802 case BURN_RESUME_MODE_NONE:
803 return "None";
804 case BURN_RESUME_MODE_ACTIVE:
805 return "Active";
806 case BURN_RESUME_MODE_SUSPEND:
807 return "Suspend";
808 case BURN_RESUME_MODE_ARP:
809 return "ARP";
810 case BURN_RESUME_MODE_REBOOT_PENDING:
811 return "Reboot Pending";
812 default:
813 return "Invalid";
814 }
815 }
816
817 extern "C" LPCSTR LoggingPlanRelationTypeToString(
818 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE type
819 )
820 {
821 switch (type)
822 {
823 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE:
824 return "None";
825 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE:
826 return "Downgrade";
827 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE:
828 return "Upgrade";
829 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON:
830 return "Addon";
831 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH:
832 return "Patch";
833 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON:
834 return "DependentAddon";
835 case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH:
836 return "DependentPatch";
837 default:
838 return "Invalid";
839 }
840 }
841
842 extern "C" LPCSTR LoggingRegistrationOptionsToString(
843 __in DWORD dwRegistrationOptions
844 )
845 {
846 switch (dwRegistrationOptions)
847 {
848 case BURN_REGISTRATION_ACTION_OPERATIONS_NONE:
849 return "None";
850 case BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE:
851 return "CacheBundle";
852 case BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY:
853 return "WriteProviderKey";
854 case BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT:
855 return "ArpSystemComponent";
856 case BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE + BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY:
857 return "CacheBundle, WriteProviderKey";
858 case BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE + BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT:
859 return "CacheBundle, ArpSystemComponent";
860 case BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY + BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT:
861 return "WriteProviderKey, ArpSystemComponent";
862 case BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE + BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY + BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT:
863 return "CacheBundle, WriteProviderKey, ArpSystemComponent";
864 default:
865 return "Invalid";
866 }
867 }
868
869 extern "C" LPCSTR LoggingRelationTypeToString(
870 __in BOOTSTRAPPER_RELATION_TYPE type
871 )
872 {
873 switch (type)
874 {
875 case BOOTSTRAPPER_RELATION_NONE:
876 return "None";
877 case BOOTSTRAPPER_RELATION_DETECT:
878 return "Detect";
879 case BOOTSTRAPPER_RELATION_UPGRADE:
880 return "Upgrade";
881 case BOOTSTRAPPER_RELATION_ADDON:
882 return "Addon";
883 case BOOTSTRAPPER_RELATION_PATCH:
884 return "Patch";
885 case BOOTSTRAPPER_RELATION_DEPENDENT_ADDON:
886 return "DependentAddon";
887 case BOOTSTRAPPER_RELATION_DEPENDENT_PATCH:
888 return "DependentPatch";
889 case BOOTSTRAPPER_RELATION_UPDATE:
890 return "Update";
891 case BOOTSTRAPPER_RELATION_CHAIN_PACKAGE:
892 return "ChainPackage";
893 default:
894 return "Invalid";
895 }
896 }
897
898 extern "C" LPCSTR LoggingRelatedOperationToString(
899 __in BOOTSTRAPPER_RELATED_OPERATION operation
900 )
901 {
902 switch (operation)
903 {
904 case BOOTSTRAPPER_RELATED_OPERATION_NONE:
905 return "None";
906 case BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE:
907 return "Downgrade";
908 case BOOTSTRAPPER_RELATED_OPERATION_MINOR_UPDATE:
909 return "MinorUpdate";
910 case BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE:
911 return "MajorUpgrade";
912 case BOOTSTRAPPER_RELATED_OPERATION_REMOVE:
913 return "Remove";
914 case BOOTSTRAPPER_RELATED_OPERATION_INSTALL:
915 return "Install";
916 case BOOTSTRAPPER_RELATED_OPERATION_REPAIR:
917 return "Repair";
918 default:
919 return "Invalid";
920 }
921 }
922
923 extern "C" LPCSTR LoggingRequestStateToString(
924 __in BOOTSTRAPPER_REQUEST_STATE requestState
925 )
926 {
927 switch (requestState)
928 {
929 case BOOTSTRAPPER_REQUEST_STATE_NONE:
930 return "None";
931 case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT:
932 return "ForceAbsent";
933 case BOOTSTRAPPER_REQUEST_STATE_ABSENT:
934 return "Absent";
935 case BOOTSTRAPPER_REQUEST_STATE_CACHE:
936 return "Cache";
937 case BOOTSTRAPPER_REQUEST_STATE_PRESENT:
938 return "Present";
939 case BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT:
940 return "ForcePresent";
941 case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
942 return "Repair";
943 default:
944 return "Invalid";
945 }
946 }
947
948 extern "C" LPCSTR LoggingRollbackOrExecute(
949 __in BOOL fRollback
950 )
951 {
952 return fRollback ? "rollback" : "execute";
953 }
954
955 extern "C" LPWSTR LoggingStringOrUnknownIfNull(
956 __in LPCWSTR wz
957 )
958 {
959 return wz ? wz : L"Unknown";
960 }
961
962 extern "C" LPCSTR LoggingInstallScopeToString(
963 __in BOOL fPerMachine
964 )
965 {
966 return fPerMachine ? "PerMachine" : "PerUser";
967 }
968
969
970 // internal function declarations
971
972 static void CheckLoggingPolicy(
973 __inout DWORD *pdwAttributes
974 )
975 {
976 HRESULT hr = S_OK;
977 HKEY hk = NULL;
978 LPWSTR sczLoggingPolicy = NULL;
979
980 hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Policies\\Microsoft\\Windows\\Installer", KEY_READ, &hk);
981 if (SUCCEEDED(hr))
982 {
983 hr = RegReadString(hk, L"Logging", &sczLoggingPolicy);
984 if (SUCCEEDED(hr))
985 {
986 LPCWSTR wz = sczLoggingPolicy;
987 while (*wz)
988 {
989 if (L'v' == *wz || L'V' == *wz)
990 {
991 *pdwAttributes |= BURN_LOGGING_ATTRIBUTE_VERBOSE;
992 }
993 else if (L'x' == *wz || L'X' == *wz)
994 {
995 *pdwAttributes |= BURN_LOGGING_ATTRIBUTE_EXTRADEBUG;
996 }
997
998 ++wz;
999 }
1000 }
1001 }
1002
1003 ReleaseStr(sczLoggingPolicy);
1004 ReleaseRegKey(hk);
1005 }
1006
1007 static HRESULT InitializeLogging(
1008 __in BURN_LOGGING* pLog,
1009 __in BURN_ENGINE_COMMAND* pInternalCommand
1010 )
1011 {
1012 HRESULT hr = S_OK;
1013
1014 // Check if the logging policy is set and configure the logging appropriately.
1015 CheckLoggingPolicy(&pLog->dwAttributes);
1016
1017 pLog->dwAttributes |= pInternalCommand->dwLoggingAttributes;
1018
1019 // The untrusted process needs a separate log file.
1020 // TODO: Burn crashes if they do try to use the same log file.
1021 if (pInternalCommand->sczLogFile)
1022 {
1023 hr = StrAllocString(&pLog->sczPath, pInternalCommand->sczLogFile, 0);
1024 ExitOnFailure(hr, "Failed to copy log file path from command line.");
1025 }
1026
1027 LExit:
1028 return hr;
1029 }
1030
1031 static HRESULT GetNonSessionSpecificTempFolder(
1032 __deref_out_z LPWSTR* psczNonSessionTempFolder
1033 )
1034 {
1035 HRESULT hr = S_OK;
1036 LPWSTR sczTempFolder = NULL;
1037 SIZE_T cchTempFolder = 0;
1038 DWORD dwSessionId = 0;
1039 LPWSTR sczSessionId = 0;
1040 SIZE_T cchSessionId = 0;
1041
1042 hr = PathGetTempPath(&sczTempFolder, &cchTempFolder);
1043 ExitOnFailure(hr, "Failed to get temp folder.");
1044
1045 // If our session id is in the TEMP path then remove that part so we get the non-session
1046 // specific temporary folder.
1047 if (::ProcessIdToSessionId(::GetCurrentProcessId(), &dwSessionId))
1048 {
1049 hr = StrAllocFormatted(&sczSessionId, L"%u\\", dwSessionId);
1050 ExitOnFailure(hr, "Failed to format session id as a string.");
1051
1052 hr = ::StringCchLengthW(sczSessionId, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSessionId));
1053 ExitOnFailure(hr, "Failed to get length of session id string.");
1054
1055 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, sczTempFolder + cchTempFolder - cchSessionId, static_cast<DWORD>(cchSessionId), sczSessionId, static_cast<DWORD>(cchSessionId)))
1056 {
1057 cchTempFolder -= cchSessionId;
1058 }
1059 }
1060
1061 hr = StrAllocString(psczNonSessionTempFolder, sczTempFolder, cchTempFolder);
1062 ExitOnFailure(hr, "Failed to copy temp folder.");
1063
1064 LExit:
1065 ReleaseStr(sczSessionId);
1066 ReleaseStr(sczTempFolder);
1067
1068 return hr;
1069 }