Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1963 lines
58 KiB

  1. /*
  2. Copyright (c) Microsoft Corporation
  3. */
  4. #include "stdinc.h"
  5. #include "sxsp.h"
  6. #include "nodefactory.h"
  7. #include "fusionarray.h"
  8. #include "sxsinstall.h"
  9. #include "sxspath.h"
  10. #include "recover.h"
  11. #include "cassemblyrecoveryinfo.h"
  12. #include "sxsexceptionhandling.h"
  13. #include "npapi.h"
  14. #include "util.h"
  15. #include "idp.h"
  16. #include "sxscabinet.h"
  17. #include "setupapi.h"
  18. #include "fcntl.h"
  19. #include "fdi.h"
  20. #include "patchapi.h"
  21. BOOL
  22. SxspSimpleAnsiToStringBuffer(CHAR* pszString, UINT uiLength, CBaseStringBuffer &tgt, bool fIsUtf8)
  23. {
  24. FN_PROLOG_WIN32
  25. PARAMETER_CHECK(pszString != NULL);
  26. //
  27. // The string buffer classes know all about converting ANSI to UNICODE strings
  28. //
  29. if (!fIsUtf8)
  30. {
  31. IFW32FALSE_EXIT(tgt.Win32Assign(pszString, uiLength));
  32. }
  33. else
  34. {
  35. CStringBufferAccessor Acc;
  36. int iRequired1 = 0;
  37. int iRequired2 = 0;
  38. tgt.Clear();
  39. Acc.Attach(&tgt);
  40. //
  41. // Attempt in-place conversion
  42. //
  43. iRequired1 = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, pszString, uiLength, Acc, Acc.GetBufferCchAsINT());
  44. //
  45. // Zero required, and nonzero last error? Problems, quit
  46. //
  47. if (iRequired1 == 0)
  48. {
  49. const DWORD dwWin32Error = ::FusionpGetLastWin32Error();
  50. if (dwWin32Error != ERROR_SUCCESS)
  51. {
  52. ORIGINATE_WIN32_FAILURE_AND_EXIT(MultiByteToWideChar, dwWin32Error);
  53. }
  54. }
  55. //
  56. // If the required chars are more than the buffer has? Enlarge, try again
  57. //
  58. else if (iRequired1 >= Acc.GetBufferCchAsINT())
  59. {
  60. Acc.Detach();
  61. IFW32FALSE_EXIT(tgt.Win32ResizeBuffer(iRequired1 + 1, eDoNotPreserveBufferContents));
  62. Acc.Attach(&tgt);
  63. iRequired2 = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, pszString, uiLength, Acc, Acc.GetBufferCchAsINT());
  64. //
  65. // If the second time around we still require more characters, someone's pulling
  66. // our leg, stop.
  67. //
  68. if (iRequired2 > tgt.GetBufferCchAsINT()) {
  69. ORIGINATE_WIN32_FAILURE_AND_EXIT(MultiByteToWideChar, ERROR_MORE_DATA);
  70. }
  71. }
  72. }
  73. //
  74. // Accessor will autodetach and return to the caller
  75. //
  76. FN_EPILOG
  77. }
  78. //
  79. // File decompression interface helper functions
  80. //
  81. INT_PTR
  82. DIAMONDAPI
  83. sxs_FdiOpen(
  84. IN char* szFileName,
  85. IN int oFlags,
  86. IN int pMode)
  87. {
  88. HANDLE hFile = INVALID_HANDLE_VALUE;
  89. INT_PTR ipResult = 0;
  90. CMediumStringBuffer sbFileName;
  91. bool fValidName = false;
  92. bool fSuccess = false;
  93. CSxsPreserveLastError ple;
  94. if ((oFlags & ~(_A_NAME_IS_UTF | _O_BINARY)) != 0)
  95. {
  96. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR, "SXS: %s(%s, 0x%x, 0x%x) - invalid flags\n",
  97. __FUNCTION__,
  98. szFileName,
  99. oFlags,
  100. pMode);
  101. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  102. ipResult = -1;
  103. goto Exit;
  104. }
  105. if (!::SxspSimpleAnsiToStringBuffer(szFileName, (UINT)strlen(szFileName), sbFileName, (oFlags & _A_NAME_IS_UTF) != 0))
  106. {
  107. ::FusionpDbgPrintEx(
  108. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  109. "SXS: %s failed converting %s to unicode, lasterror=0x%08lx\n",
  110. __FUNCTION__,
  111. szFileName,
  112. ::FusionpGetLastWin32Error());
  113. ipResult = -1;
  114. goto Exit;
  115. }
  116. hFile = ::CreateFileW(
  117. sbFileName,
  118. GENERIC_READ,
  119. FILE_SHARE_READ,
  120. NULL,
  121. OPEN_EXISTING,
  122. FILE_ATTRIBUTE_NORMAL,
  123. INVALID_HANDLE_VALUE);
  124. if (hFile == INVALID_HANDLE_VALUE)
  125. {
  126. ::FusionpDbgPrintEx(
  127. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  128. "SXS: %s failed opening file %ls, lasterror=0x%08lx\n",
  129. __FUNCTION__,
  130. static_cast<PCWSTR>(sbFileName),
  131. ::FusionpGetLastWin32Error());
  132. ipResult = -1;
  133. goto Exit;
  134. }
  135. else
  136. {
  137. ipResult = reinterpret_cast<INT_PTR>(hFile);
  138. }
  139. fSuccess = true;
  140. Exit:
  141. if (fSuccess)
  142. {
  143. ple.Restore();
  144. }
  145. return ipResult;
  146. }
  147. //
  148. // Thin shim around ReadFile for the Diamond APIs
  149. //
  150. UINT
  151. DIAMONDAPI
  152. sxs_FdiRead(
  153. INT_PTR hf,
  154. void* pv,
  155. UINT cb)
  156. {
  157. DWORD dwRetVal = 0;
  158. UINT uiResult = 0;
  159. CSxsPreserveLastError ple;
  160. if (::ReadFile(reinterpret_cast<HANDLE>(hf), pv, cb, &dwRetVal, NULL))
  161. {
  162. uiResult = (UINT)dwRetVal;
  163. ple.Restore();
  164. }
  165. else
  166. {
  167. ::FusionpDbgPrintEx(
  168. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  169. "SXS: %s failed reading %d bytes from handle %p, error 0x%08lx\n",
  170. __FUNCTION__,
  171. cb,
  172. hf,
  173. ::FusionpGetLastWin32Error());
  174. uiResult = (UINT)-1;
  175. }
  176. return uiResult;
  177. }
  178. //
  179. // Thin shim around WriteFile for the Diamond APIs
  180. //
  181. UINT
  182. DIAMONDAPI
  183. sxs_FdiWrite(
  184. INT_PTR hf,
  185. void* pv,
  186. UINT cb)
  187. {
  188. DWORD dwRetVal = 0;
  189. UINT uiResult = 0;
  190. CSxsPreserveLastError ple;
  191. if (::WriteFile(reinterpret_cast<HANDLE>(hf), pv, cb, &dwRetVal, NULL))
  192. {
  193. uiResult = (UINT)dwRetVal;
  194. ple.Restore();
  195. }
  196. else
  197. {
  198. ::FusionpDbgPrintEx(
  199. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  200. "SXS: %s failed reading %d bytes to handle %p, error 0x%08lx\n",
  201. __FUNCTION__,
  202. cb,
  203. hf,
  204. ::FusionpGetLastWin32Error());
  205. uiResult = (UINT)-1;
  206. }
  207. return uiResult;
  208. }
  209. //
  210. // Thin shim around CloseHandle for the Diamond APIs
  211. //
  212. INT
  213. DIAMONDAPI
  214. sxs_FdiClose(
  215. INT_PTR hr)
  216. {
  217. INT iResult;
  218. CSxsPreserveLastError ple;
  219. if (::CloseHandle(reinterpret_cast<HANDLE>(hr)))
  220. {
  221. iResult = 0;
  222. ple.Restore();
  223. }
  224. else
  225. {
  226. ::FusionpDbgPrintEx(
  227. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  228. "SXS: %s failed closing handle %p, error 0x%08lx\n",
  229. __FUNCTION__,
  230. hr,
  231. ::FusionpGetLastWin32Error());
  232. iResult = -1;
  233. }
  234. return iResult;
  235. }
  236. //
  237. // Thin shim around SetFilePos for the Diamond APIs
  238. //
  239. long
  240. DIAMONDAPI
  241. sxs_FdiSeek(
  242. INT_PTR hf,
  243. long dist,
  244. int seekType)
  245. {
  246. DWORD dwSeekType = 0;
  247. DWORD dwResult = 0;
  248. long lResult = 0;
  249. CSxsPreserveLastError ple;
  250. bool fSuccess = false;
  251. switch(seekType)
  252. {
  253. case SEEK_SET:
  254. dwSeekType = FILE_BEGIN;
  255. break;
  256. case SEEK_END:
  257. dwSeekType = FILE_END;
  258. break;
  259. case SEEK_CUR:
  260. dwSeekType = FILE_CURRENT;
  261. break;
  262. default:
  263. ::FusionpDbgPrintEx(
  264. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  265. "SXS: %s invalid seek type %d\n",
  266. seekType,
  267. ::FusionpGetLastWin32Error());
  268. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  269. goto Exit;
  270. }
  271. dwResult = ::SetFilePointer(reinterpret_cast<HANDLE>(hf), dist, NULL, dwSeekType);
  272. if (dwResult == 0xFFFFFFFF)
  273. {
  274. lResult = -1;
  275. ::FusionpDbgPrintEx(
  276. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  277. "SXS: %s seek type %d, offset %l, handle %p, error 0x%08lx\n",
  278. __FUNCTION__,
  279. seekType, dist, hf,
  280. ::FusionpGetLastWin32Error());
  281. goto Exit;
  282. }
  283. else
  284. {
  285. lResult = dwResult;
  286. }
  287. fSuccess = true;
  288. Exit:
  289. if (fSuccess)
  290. {
  291. ple.Restore();
  292. }
  293. return lResult;
  294. }
  295. FNALLOC(sxs_FdiAlloc)
  296. {
  297. PVOID pv;
  298. CSxsPreserveLastError ple;
  299. pv = FUSION_RAW_ALLOC(cb, __FUNCTION__);
  300. if (pv != NULL)
  301. {
  302. ple.Restore();
  303. }
  304. return pv;
  305. }
  306. FNFREE(sxs_FdiFree)
  307. {
  308. CSxsPreserveLastError ple;
  309. if (FUSION_RAW_DEALLOC(pv))
  310. {
  311. ple.Restore();
  312. }
  313. }
  314. BOOL
  315. SxspShouldExtractThisFileFromCab(
  316. CCabinetData *pState,
  317. const CBaseStringBuffer &FilePathInCab,
  318. bool &rfShouldExtract)
  319. {
  320. FN_PROLOG_WIN32
  321. rfShouldExtract = false;
  322. if (pState->m_pfnShouldExtractThisFileFromCabCallback == NULL)
  323. {
  324. rfShouldExtract = true;
  325. }
  326. else
  327. {
  328. IFW32FALSE_EXIT((*pState->m_pfnShouldExtractThisFileFromCabCallback)(
  329. FilePathInCab,
  330. rfShouldExtract,
  331. pState->m_pvShouldExtractThisFileFromCabCallbackContext));
  332. }
  333. FN_EPILOG
  334. }
  335. BOOL
  336. sxs_Win32FdiExtractionNotify(
  337. FDINOTIFICATIONTYPE NotifyType,
  338. PFDINOTIFICATION NotifyData,
  339. INT_PTR &ripResult)
  340. {
  341. FN_PROLOG_WIN32
  342. CCabinetData* const pState = reinterpret_cast<CCabinetData*>(NotifyData->pv);
  343. ripResult = 0;
  344. switch (NotifyType)
  345. {
  346. case fdintCABINET_INFO: // FALLTHROUGH
  347. case fdintENUMERATE:
  348. ripResult = 0; // ignore, success
  349. break;
  350. case fdintNEXT_CABINET: // FALLTHROUGH
  351. case fdintPARTIAL_FILE:
  352. //
  353. // we don't handle files split across multiple .cabs
  354. //
  355. ripResult = -1;
  356. INTERNAL_ERROR_CHECK(FALSE);
  357. break;
  358. case fdintCOPY_FILE:
  359. ripResult = -1; // assume failure
  360. {
  361. SIZE_T c = 0;
  362. bool fValidPath = false;
  363. bool fShouldExtract = false;
  364. PARAMETER_CHECK(pState != NULL);
  365. pState->sxs_FdiExtractionNotify_fdintCOPY_FILE.Clear();
  366. CFusionFile hNewFile;
  367. CStringBuffer &TempBuffer = pState->sxs_FdiExtractionNotify_fdintCOPY_FILE.TempBuffer;
  368. CStringBuffer &TempBuffer2 = pState->sxs_FdiExtractionNotify_fdintCOPY_FILE.TempBuffer2;
  369. //
  370. // Add this assembly to those being extracted
  371. //
  372. IFW32FALSE_EXIT(
  373. ::SxspSimpleAnsiToStringBuffer(
  374. NotifyData->psz1,
  375. (UINT)strlen(NotifyData->psz1),
  376. TempBuffer2,
  377. ((NotifyData->attribs & _A_NAME_IS_UTF) != 0)));
  378. IFW32FALSE_EXIT(::SxspIsFileNameValidForManifest(TempBuffer2, fValidPath));
  379. PARAMETER_CHECK(fValidPath);
  380. IFW32FALSE_EXIT(TempBuffer2.Win32GetFirstPathElement(TempBuffer));
  381. //
  382. // But only if it's not there already
  383. //
  384. for (c = 0; c < pState->m_AssembliesExtracted.GetSize(); c++)
  385. {
  386. const CStringBuffer &sb = pState->m_AssembliesExtracted[c];
  387. bool fMatches = false;
  388. IFW32FALSE_EXIT(sb.Win32Equals(TempBuffer, fMatches, true));
  389. if (fMatches) break;
  390. }
  391. // Ran off end w/o finding means add it to the list.
  392. if (c == pState->m_AssembliesExtracted.GetSize())
  393. {
  394. IFW32FALSE_EXIT(pState->m_AssembliesExtracted.Win32Append(TempBuffer));
  395. }
  396. if (!pState->IsExtracting())
  397. {
  398. ripResult = 0; // skip file, but no error
  399. FN_SUCCESSFUL_EXIT();
  400. }
  401. IFW32FALSE_EXIT(::SxspShouldExtractThisFileFromCab(pState, TempBuffer2, fShouldExtract));
  402. if (!fShouldExtract)
  403. {
  404. ripResult = 0; // skip file, but no error
  405. FN_SUCCESSFUL_EXIT();
  406. }
  407. //
  408. // Ensure that {base extract path}\{path in cab} exists.
  409. //
  410. IFW32FALSE_EXIT(::SxspCreateMultiLevelDirectory(
  411. pState->BasePath(),
  412. TempBuffer));
  413. //
  414. // Blob together {base extract path}\{path in cab}\{filename}
  415. //
  416. IFW32FALSE_EXIT(TempBuffer.Win32Assign(pState->BasePath()));
  417. IFW32FALSE_EXIT(TempBuffer.Win32AppendPathElement(TempBuffer2));
  418. //
  419. // And away we go!
  420. //
  421. IFW32FALSE_EXIT(hNewFile.Win32CreateFile(
  422. TempBuffer,
  423. GENERIC_WRITE,
  424. FILE_SHARE_READ,
  425. (pState->GetReplaceExisting() ? CREATE_ALWAYS : CREATE_NEW)));
  426. ripResult = reinterpret_cast<INT_PTR>(hNewFile.Detach());
  427. }
  428. break;
  429. case fdintCLOSE_FILE_INFO:
  430. ripResult = FALSE; // assume failure
  431. {
  432. const HANDLE hFileToClose = reinterpret_cast<HANDLE>(NotifyData->hf);
  433. if ((hFileToClose != NULL) && (hFileToClose != INVALID_HANDLE_VALUE))
  434. IFW32FALSE_ORIGINATE_AND_EXIT(::CloseHandle(hFileToClose));
  435. }
  436. ripResult = TRUE;
  437. break;
  438. }
  439. FN_EPILOG
  440. }
  441. FNFDINOTIFY(sxs_FdiExtractionNotify)
  442. {
  443. INT_PTR ipResult = 0;
  444. CSxsPreserveLastError ple;
  445. if (sxs_Win32FdiExtractionNotify(fdint, pfdin, ipResult))
  446. {
  447. ple.Restore();
  448. }
  449. return ipResult;
  450. }
  451. BOOL
  452. SxspExpandCabinetIntoTemp(
  453. DWORD dwFlags,
  454. const CBaseStringBuffer &buffCabinetPath,
  455. CImpersonationData &ImpersonateData,
  456. CCabinetData* pCabinetData)
  457. {
  458. FN_PROLOG_WIN32
  459. CImpersonate impersonate(ImpersonateData);
  460. CFileStreamBase fsb;
  461. static const BYTE s_CabSignature[] = { 'M', 'S', 'C', 'F' };
  462. BYTE SignatureBuffer[NUMBER_OF(s_CabSignature)] = {0};
  463. ULONG ulReadCount = 0;
  464. CFusionArray<CHAR> CabinetPathConverted;
  465. HFDI hCabinet = NULL;
  466. ERF ErfObject = { 0 };
  467. DWORD dwFailureCode = 0;
  468. CDynamicLinkLibrary SetupApi;
  469. BOOL (DIAMONDAPI *pfnFDICopy)(HFDI, char *, char *, int, PFNFDINOTIFY, PFNFDIDECRYPT, void *) = NULL;
  470. HFDI (DIAMONDAPI *pfnFDICreate)(PFNALLOC, PFNFREE, PFNOPEN, PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF) = NULL;
  471. BOOL (DIAMONDAPI *pfnFDIDestroy)(HFDI) = NULL;
  472. PARAMETER_CHECK(pCabinetData != NULL);
  473. PARAMETER_CHECK(dwFlags == 0);
  474. PARAMETER_CHECK(!buffCabinetPath.IsEmpty());
  475. //
  476. // Sniff the cabinet for the 'mscf' compressed-file marker
  477. //
  478. {
  479. //
  480. // Need to be in user's context when doing this.
  481. //
  482. IFW32FALSE_EXIT(impersonate.Impersonate());
  483. //
  484. // Open the cabinet for streaming
  485. //
  486. IFW32FALSE_EXIT(fsb.OpenForRead(
  487. buffCabinetPath,
  488. ImpersonateData,
  489. FILE_SHARE_READ,
  490. OPEN_EXISTING,
  491. 0));
  492. IFCOMFAILED_EXIT(fsb.Read(SignatureBuffer, sizeof(SignatureBuffer), &ulReadCount));
  493. if (ulReadCount >= 4)
  494. {
  495. if (memcmp(SignatureBuffer, s_CabSignature, sizeof(SignatureBuffer)) != 0)
  496. {
  497. // Can't use this catalog file!
  498. ORIGINATE_WIN32_FAILURE_AND_EXIT(SxspExpandCabinetIntoTemp, ERROR_INVALID_PARAMETER);
  499. }
  500. }
  501. IFW32FALSE_EXIT(fsb.Close());
  502. IFW32FALSE_EXIT(impersonate.Unimpersonate());
  503. }
  504. IFW32FALSE_EXIT(SetupApi.Win32LoadLibrary(L"cabinet.dll"));
  505. IFW32FALSE_EXIT(SetupApi.Win32GetProcAddress("FDICreate", &pfnFDICreate));
  506. IFW32FALSE_EXIT(SetupApi.Win32GetProcAddress("FDICopy", &pfnFDICopy));
  507. IFW32FALSE_EXIT(SetupApi.Win32GetProcAddress("FDIDestroy", &pfnFDIDestroy));
  508. //
  509. // Now create the FDI cabinet object
  510. //
  511. hCabinet = (*pfnFDICreate)(
  512. &sxs_FdiAlloc,
  513. &sxs_FdiFree,
  514. &sxs_FdiOpen,
  515. &sxs_FdiRead,
  516. &sxs_FdiWrite,
  517. &sxs_FdiClose,
  518. &sxs_FdiSeek,
  519. cpuUNKNOWN,
  520. &ErfObject);
  521. //
  522. // Convert string.
  523. //
  524. {
  525. SIZE_T iSize = ::WideCharToMultiByte(
  526. CP_ACP,
  527. WC_NO_BEST_FIT_CHARS,
  528. buffCabinetPath,
  529. buffCabinetPath.GetCchAsINT(),
  530. NULL,
  531. 0,
  532. NULL,
  533. NULL);
  534. if (iSize >= CabinetPathConverted.GetSize())
  535. {
  536. IFW32FALSE_EXIT(CabinetPathConverted.Win32SetSize(
  537. iSize + 2,
  538. CFusionArray<CHAR>::eSetSizeModeExact));
  539. }
  540. else if (iSize == 0)
  541. {
  542. ORIGINATE_WIN32_FAILURE_AND_EXIT(WideCharToMultiByte, ::FusionpGetLastWin32Error());
  543. }
  544. iSize = ::WideCharToMultiByte(
  545. CP_ACP,
  546. WC_NO_BEST_FIT_CHARS,
  547. buffCabinetPath,
  548. buffCabinetPath.GetCchAsINT(),
  549. CabinetPathConverted.GetArrayPtr(),
  550. (int)CabinetPathConverted.GetSize(),
  551. NULL,
  552. NULL);
  553. if (iSize == 0)
  554. {
  555. ORIGINATE_WIN32_FAILURE_AND_EXIT(WideCharToMultiByte, ::FusionpGetLastWin32Error());
  556. }
  557. (CabinetPathConverted.GetArrayPtr())[iSize] = 0;
  558. }
  559. ::FusionpSetLastWin32Error(NO_ERROR);
  560. //
  561. // Do the extraction
  562. //
  563. const BOOL fResult = (*pfnFDICopy)(
  564. hCabinet,
  565. CabinetPathConverted.GetArrayPtr(),
  566. "",
  567. 0,
  568. sxs_FdiExtractionNotify,
  569. NULL,
  570. static_cast<PVOID>(pCabinetData));
  571. dwFailureCode = ::FusionpGetLastWin32Error();
  572. //
  573. // Ignore errors here like setupapi.dll does.
  574. //
  575. IFW32FALSE_EXIT((*pfnFDIDestroy)(hCabinet));
  576. //
  577. // Failure? Luckily, we went to great lengths to ensure that lasterror is maintained, so
  578. // this should just be derivable from the last win32 error.
  579. //
  580. if (!fResult)
  581. {
  582. //
  583. // But, if something inside the cab code itself failed, then we should do something
  584. // about mapping the error result.
  585. //
  586. if (dwFailureCode == ERROR_SUCCESS)
  587. {
  588. switch (ErfObject.erfOper)
  589. {
  590. // Should never get these back if the lasterror was success.
  591. case FDIERROR_TARGET_FILE:
  592. case FDIERROR_USER_ABORT:
  593. case FDIERROR_NONE:
  594. ASSERT(FALSE && "Some internal cabinet problem");
  595. dwFailureCode = ERROR_INTERNAL_ERROR;
  596. break;
  597. case FDIERROR_NOT_A_CABINET:
  598. case FDIERROR_UNKNOWN_CABINET_VERSION:
  599. case FDIERROR_BAD_COMPR_TYPE:
  600. case FDIERROR_MDI_FAIL:
  601. case FDIERROR_RESERVE_MISMATCH:
  602. case FDIERROR_WRONG_CABINET:
  603. dwFailureCode = ERROR_INVALID_DATA;
  604. break;
  605. case FDIERROR_CABINET_NOT_FOUND:
  606. dwFailureCode = ERROR_FILE_NOT_FOUND;
  607. break;
  608. case FDIERROR_ALLOC_FAIL:
  609. dwFailureCode = ERROR_NOT_ENOUGH_MEMORY;
  610. break;
  611. break;
  612. }
  613. ASSERT(dwFailureCode != ERROR_SUCCESS);
  614. if (dwFailureCode == ERROR_SUCCESS)
  615. {
  616. dwFailureCode = ERROR_INTERNAL_ERROR;
  617. }
  618. }
  619. //
  620. // Now that we've mapped it, originate it.
  621. //
  622. ORIGINATE_WIN32_FAILURE_AND_EXIT(FDICopy, dwFailureCode);
  623. }
  624. FN_EPILOG
  625. }
  626. class CSxspFindManifestInCabinetPathLocals
  627. {
  628. public:
  629. CSxspFindManifestInCabinetPathLocals() { }
  630. ~CSxspFindManifestInCabinetPathLocals() { }
  631. void Clear()
  632. //
  633. // Clear is how you deal with the fact that some function calls were in loops
  634. // and/or some local variables were in loops.
  635. //
  636. // In "lifting up" the variables, we lose the repeated constructor/destructor calls.
  637. //
  638. {
  639. }
  640. WIN32_FIND_DATAW FindData;
  641. };
  642. BOOL
  643. SxspFindManifestInCabinetPath(
  644. const CBaseStringBuffer &rcsBasePath,
  645. const CBaseStringBuffer &rcsSubPath,
  646. CBaseStringBuffer &ManifestPath,
  647. bool &rfFound,
  648. CSxspFindManifestInCabinetPathLocals &Locals)
  649. /*++
  650. Given a 'base path' of where to look for a manifest, this looks for the candidate manifest
  651. in there.
  652. Example 1:
  653. foo\bar\x86_bink_{...}\x86_bink_{...}.man
  654. foo\bar\x86_bink_{...}\bop.man
  655. base path = foo\bar\x86_bink_{...}
  656. found manifest: foo\bar\x86_bink_{...}\x86_bink_{...}.man
  657. Example 2:
  658. foo\bar\x86_bink_{...}\bop.manifest
  659. base path = foo\bar\x86_bink_{...}
  660. found manifest = foo\bar\x86_bink_{...}\bop.manifest
  661. Priority:
  662. {basepath}\{subpath}\{subpath}.manifest
  663. {basepath}\{subpath}\{subpath}.man
  664. {basepath}\{subpath}\*.manifest
  665. {basepath}\{subpath}\*.man
  666. --*/
  667. {
  668. FN_PROLOG_WIN32
  669. Locals.Clear();
  670. #define ENTRY(_x) { _x, NUMBER_OF(_x) - 1 }
  671. const static struct {
  672. PCWSTR pcwsz;
  673. SIZE_T cch;
  674. } s_rgsExtensions[] = {
  675. ENTRY(ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX_MAN),
  676. ENTRY(ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX_MANIFEST),
  677. };
  678. #undef ENTRY
  679. struct {
  680. PCWSTR pcwsz;
  681. SIZE_T cch;
  682. } s_rgsNamePatterns[] = {
  683. { rcsSubPath, rcsSubPath.Cch() },
  684. { L"*", 1 }
  685. };
  686. SIZE_T cchBeforePatterns = 0;
  687. rfFound = false;
  688. //
  689. // Create the {basepath}\{subpath} search "root" path
  690. //
  691. IFW32FALSE_EXIT(ManifestPath.Win32Assign(rcsBasePath));
  692. IFW32FALSE_EXIT(ManifestPath.Win32AppendPathElement(rcsSubPath));
  693. cchBeforePatterns = ManifestPath.Cch();
  694. //
  695. // For each name pattern ({basepath} or *), look to see if there's a file with that
  696. // name present
  697. //
  698. for (SIZE_T cNamePattern = 0; cNamePattern < NUMBER_OF(s_rgsNamePatterns); cNamePattern++)
  699. {
  700. IFW32FALSE_EXIT(ManifestPath.Win32AppendPathElement(
  701. s_rgsNamePatterns[cNamePattern].pcwsz,
  702. s_rgsNamePatterns[cNamePattern].cch));
  703. //
  704. // Probe - look for .manifest/.man/.whatever based on the extension list above.
  705. //
  706. for (SIZE_T cExtension = 0; cExtension < NUMBER_OF(s_rgsExtensions); cExtension++)
  707. {
  708. CFindFile Finder;
  709. WIN32_FIND_DATAW &FindData = Locals.FindData;
  710. IFW32FALSE_EXIT(ManifestPath.Win32Append(
  711. s_rgsExtensions[cExtension].pcwsz,
  712. s_rgsExtensions[cExtension].cch));
  713. //
  714. // Find the first one of this name
  715. //
  716. Finder = FindFirstFileW(ManifestPath, &FindData);
  717. ManifestPath.Left(cchBeforePatterns);
  718. if (Finder.IsValid())
  719. {
  720. IFW32FALSE_EXIT(ManifestPath.Win32AppendPathElement(
  721. FindData.cFileName,
  722. ::wcslen(FindData.cFileName)));
  723. //
  724. // If we found one, then report it and stop trying.
  725. //
  726. rfFound = true;
  727. FN_SUCCESSFUL_EXIT();
  728. }
  729. }
  730. ManifestPath.Left(cchBeforePatterns);
  731. }
  732. FN_EPILOG
  733. }
  734. class CSxspDetectAndInstallFromPathLocals
  735. {
  736. public:
  737. CSxspDetectAndInstallFromPathLocals() { }
  738. ~CSxspDetectAndInstallFromPathLocals() { }
  739. void Clear()
  740. //
  741. // Clear is how you deal with the fact that some function calls were in loops
  742. // and/or some local variables were in loops.
  743. //
  744. // In "lifting up" the variables, we lose the repeated constructor/destructor calls.
  745. //
  746. {
  747. this->LocalPathWorker.Clear();
  748. this->SxspFindManifestInCabinetPath.Clear();
  749. }
  750. CStringBuffer LocalPathWorker;
  751. CSxspFindManifestInCabinetPathLocals SxspFindManifestInCabinetPath;
  752. };
  753. BOOL
  754. SxspDetectAndInstallFromPath(
  755. CAssemblyInstall &AssemblyContext,
  756. const CBaseStringBuffer &rcsbRelativeCodebasePath,
  757. const CBaseStringBuffer &rcsbCabinetExtractionPath,
  758. const CBaseStringBuffer &rcsbAssemblySubpath,
  759. CSxspDetectAndInstallFromPathLocals &Locals)
  760. {
  761. FN_PROLOG_WIN32
  762. bool fFoundSomething = false;
  763. Locals.Clear();
  764. CStringBuffer &LocalPathWorker = Locals.LocalPathWorker;
  765. IFW32FALSE_EXIT(::SxspFindManifestInCabinetPath(
  766. rcsbCabinetExtractionPath,
  767. rcsbAssemblySubpath,
  768. LocalPathWorker,
  769. fFoundSomething,
  770. Locals.SxspFindManifestInCabinetPath));
  771. if (fFoundSomething)
  772. {
  773. IFW32FALSE_EXIT(AssemblyContext.InstallFile(
  774. LocalPathWorker,
  775. rcsbRelativeCodebasePath));
  776. }
  777. #if DBG
  778. if (!fFoundSomething)
  779. {
  780. FusionpDbgPrintEx(FUSION_DBG_LEVEL_INSTALLATION,
  781. "sxs.dll: %s - Failed finding something to install in path %ls, skipping\n",
  782. __FUNCTION__,
  783. static_cast<PCWSTR>(LocalPathWorker));
  784. }
  785. #endif
  786. FN_EPILOG
  787. }
  788. BOOL
  789. SxspReadEntireFile(
  790. CFusionArray<BYTE> &rbBuffer,
  791. const CBaseStringBuffer &rcsbPath)
  792. {
  793. FN_PROLOG_WIN32
  794. CFusionFile File;
  795. CFileMapping FileMapping;
  796. CMappedViewOfFile MappedView;
  797. ULONGLONG ullFileSize = 0;
  798. ULONGLONG ullOffset = 0;
  799. DWORD dwReadSize = 0;
  800. IFW32FALSE_EXIT(File.Win32CreateFile(rcsbPath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
  801. IFW32FALSE_EXIT(File.Win32GetSize(ullFileSize));
  802. //
  803. // If the file is more than 4gb long, we'll have problems reading it. Don't bother trying.
  804. // On ia64, we could readin 4gb, but it seems like any file that's 4gb or more in this context
  805. // is either an erroneous file or a filesystem bug.
  806. //
  807. PARAMETER_CHECK(ullFileSize < MAXDWORD);
  808. //
  809. // Set the size of the output buffer to be exactly as big as we need.
  810. //
  811. if (rbBuffer.GetSize() != ullFileSize)
  812. {
  813. IFW32FALSE_EXIT(rbBuffer.Win32SetSize((SIZE_T)ullFileSize, CFusionArray<BYTE>::eSetSizeModeExact));
  814. }
  815. //
  816. // Read MAXDWORD chunks (or smaller) at a time to flesh out the entire thing in memory
  817. //
  818. while (ullFileSize) {
  819. IFW32FALSE_ORIGINATE_AND_EXIT(::ReadFile(
  820. File,
  821. rbBuffer.GetArrayPtr() + ullOffset,
  822. (DWORD)((ullFileSize > MAXDWORD) ? MAXDWORD : ullFileSize),
  823. &dwReadSize,
  824. NULL));
  825. //
  826. // We can't have read more than the bytes remaining in the file.
  827. //
  828. INTERNAL_ERROR_CHECK(dwReadSize <= (ullFileSize - ullOffset));
  829. ullFileSize -= dwReadSize;
  830. //
  831. // If somehow we sized the file upwards (not strictly possible b/c we set this to
  832. // only allow read sharing) or otherwise got back zero bytes read, we stop
  833. // before looping infinitely.
  834. //
  835. if (dwReadSize == 0)
  836. break;
  837. }
  838. FN_EPILOG
  839. }
  840. const static UNICODE_STRING assembly_dot_patch = RTL_CONSTANT_STRING(L"assembly.patch");
  841. class CSxspDeterminePatchSourceFromLocals
  842. {
  843. public:
  844. CSxspDeterminePatchSourceFromLocals() { }
  845. ~CSxspDeterminePatchSourceFromLocals() { }
  846. void Clear()
  847. //
  848. // Clear is how you deal with the fact that some function calls were in loops
  849. // and/or some local variables were in loops.
  850. //
  851. // In "lifting up" the variables, we lose the repeated constructor/destructor calls.
  852. //
  853. {
  854. this->sbBuffTemp.Clear();
  855. }
  856. CStringBuffer sbBuffTemp;
  857. };
  858. BOOL
  859. SxspDeterminePatchSourceFrom(
  860. const CBaseStringBuffer &rcsbBasePath,
  861. const CBaseStringBuffer &rcsbPath,
  862. CBaseStringBuffer &rsbPatchSourceName,
  863. BOOL &fFoundPatchBase,
  864. CSxspDeterminePatchSourceFromLocals &Locals)
  865. {
  866. FN_PROLOG_WIN32
  867. Locals.Clear();
  868. CStringBuffer &sbBuffTemp = Locals.sbBuffTemp;
  869. CFusionArray<BYTE> rgbFileContents;
  870. BOOL fNotFound = FALSE;
  871. CSmartPtrWithNamedDestructor<ASSEMBLY_IDENTITY, &::SxsDestroyAssemblyIdentity> pAsmIdentity;
  872. PBYTE pbStarting = NULL;
  873. PBYTE pbEnding = NULL;
  874. bool fIsUnicode = false;
  875. SIZE_T cchBeforeEOLN = 0;
  876. fFoundPatchBase = FALSE;
  877. IFW32FALSE_EXIT(sbBuffTemp.Win32Assign(rcsbBasePath));
  878. IFW32FALSE_EXIT(sbBuffTemp.Win32AppendPathElement(rcsbPath));
  879. IFW32FALSE_EXIT(sbBuffTemp.Win32AppendPathElement(&assembly_dot_patch));
  880. IFW32FALSE_EXIT(rgbFileContents.Win32Initialize());
  881. IFW32FALSE_EXIT_UNLESS2(
  882. ::SxspReadEntireFile(rgbFileContents, sbBuffTemp),
  883. LIST_2( ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND ),
  884. fNotFound);
  885. if (fNotFound || (rgbFileContents.GetSize() == 0))
  886. {
  887. FN_SUCCESSFUL_EXIT();
  888. }
  889. pbStarting = rgbFileContents.GetArrayPtr();
  890. pbEnding = pbStarting + rgbFileContents.GetSize();
  891. //
  892. // Is this UNICODE?
  893. //
  894. fIsUnicode =
  895. (rgbFileContents.GetSize() > sizeof(WCHAR)) &&
  896. (((PWCHAR)pbStarting)[0] == 0xFEFF);
  897. if (fIsUnicode)
  898. {
  899. pbStarting += sizeof(WCHAR);
  900. PARAMETER_CHECK(((pbEnding - pbStarting) % sizeof(WCHAR)) == 0);
  901. IFW32FALSE_EXIT(sbBuffTemp.Win32Assign(
  902. reinterpret_cast<PCWSTR>(pbStarting),
  903. (pbEnding - pbStarting) / sizeof(WCHAR)));
  904. }
  905. else
  906. {
  907. IFW32FALSE_EXIT(
  908. sbBuffTemp.Win32Assign(
  909. reinterpret_cast<PCSTR>(pbStarting),
  910. pbEnding - pbStarting));
  911. }
  912. //
  913. // Because this string should be "solid" ie: no \r\n in it,
  914. // we can whack everything after the first \r\n.
  915. //
  916. cchBeforeEOLN = wcscspn(sbBuffTemp, L"\r\n");
  917. if (cchBeforeEOLN != 0)
  918. {
  919. sbBuffTemp.Left(cchBeforeEOLN);
  920. }
  921. //
  922. // Convert back to an identity, then convert -that- back to
  923. // an installation path.
  924. //
  925. IFW32FALSE_EXIT(
  926. ::SxspCreateAssemblyIdentityFromTextualString(
  927. sbBuffTemp,
  928. &pAsmIdentity));
  929. IFW32FALSE_EXIT(
  930. ::SxspGetAssemblyIdentityAttributeValue(
  931. 0,
  932. pAsmIdentity,
  933. &s_IdentityAttribute_type,
  934. sbBuffTemp));
  935. if (::FusionpEqualStringsI(
  936. ASSEMBLY_TYPE_WIN32_POLICY, NUMBER_OF(ASSEMBLY_TYPE_WIN32_POLICY) - 1,
  937. sbBuffTemp))
  938. {
  939. ORIGINATE_WIN32_FAILURE_AND_EXIT(bad_type_of_patch_source_identity, ERROR_INTERNAL_ERROR);
  940. }
  941. IFW32FALSE_EXIT(
  942. ::SxspGenerateSxsPath(
  943. SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT,
  944. SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
  945. NULL,
  946. 0,
  947. pAsmIdentity,
  948. NULL,
  949. rsbPatchSourceName));
  950. fFoundPatchBase = TRUE;
  951. FN_EPILOG
  952. }
  953. class CSxspApplyPatchesForLocals
  954. {
  955. public:
  956. CSxspApplyPatchesForLocals() { }
  957. ~CSxspApplyPatchesForLocals() { }
  958. void Clear()
  959. //
  960. // Clear is how you deal with the fact that some function calls were in loops
  961. // and/or some local variables were in loops.
  962. //
  963. // In "lifting up" the variables, we lose the repeated constructor/destructor calls.
  964. //
  965. {
  966. this->sbTempBuffer.Clear();
  967. this->SourceAssemblyPath.Clear();
  968. this->TargetAssemblyPath.Clear();
  969. this->SxspDeterminePatchSourceFrom.Clear();
  970. }
  971. CSmallStringBuffer sbTempBuffer;
  972. CStringBuffer SourceAssemblyPath;
  973. CStringBuffer TargetAssemblyPath;
  974. WIN32_FIND_DATAW FindData;
  975. CSxspDeterminePatchSourceFromLocals SxspDeterminePatchSourceFrom;
  976. };
  977. BOOL
  978. SxspApplyPatchesFor(
  979. const CBaseStringBuffer &rcsbBasePath,
  980. const CBaseStringBuffer &rcsbPath,
  981. CSxspApplyPatchesForLocals &Locals)
  982. /*++
  983. Given a path, this function will look for the patch source description file
  984. which indicates what base assembly this assembly is patched from. It will then
  985. look through all the .patch files, and assume that (once the .patch is removed)
  986. that they map to files originally in the source assembly.
  987. --*/
  988. {
  989. FN_PROLOG_WIN32
  990. const static UNICODE_STRING dot_patch = RTL_CONSTANT_STRING(L".patch");
  991. const static UNICODE_STRING star_dot_patch = RTL_CONSTANT_STRING(L"*.patch");
  992. Locals.Clear();
  993. CSmallStringBuffer &sbTempBuffer = Locals.sbTempBuffer;
  994. CStringBuffer &SourceAssemblyPath = Locals.SourceAssemblyPath;
  995. CStringBuffer &TargetAssemblyPath = Locals.TargetAssemblyPath;
  996. CDynamicLinkLibrary PatchDll;
  997. CFindFile Finder;
  998. WIN32_FIND_DATAW &FindData = Locals.FindData;
  999. BOOL fError = FALSE;
  1000. BOOL fFoundPatchBase = FALSE;
  1001. SIZE_T cchTargetPathBase = 0;
  1002. SIZE_T cchSourcePathBase = 0;
  1003. BOOL (WINAPI *pfnApplyPatchToFileExW)(LPCWSTR, LPCWSTR, LPCWSTR, ULONG, PPATCH_PROGRESS_CALLBACK, PVOID) = NULL;
  1004. BOOL (WINAPI *pfnGetPatchSignatureW)(LPCWSTR, ULONG, PVOID, ULONG, PPATCH_IGNORE_RANGE, ULONG, PPATCH_RETAIN_RANGE, ULONG, PVOID) = NULL;
  1005. IFW32FALSE_EXIT(PatchDll.Win32LoadLibrary(L"mspatcha.dll"));
  1006. IFW32FALSE_EXIT(PatchDll.Win32GetProcAddress("ApplyPatchToFileExW", &pfnApplyPatchToFileExW));
  1007. IFW32FALSE_EXIT(PatchDll.Win32GetProcAddress("GetFilePatchSignatureW", &pfnGetPatchSignatureW));
  1008. //
  1009. // Where are we patching from?
  1010. //
  1011. IFW32FALSE_EXIT(::SxspDeterminePatchSourceFrom(
  1012. rcsbBasePath,
  1013. rcsbPath,
  1014. sbTempBuffer,
  1015. fFoundPatchBase,
  1016. Locals.SxspDeterminePatchSourceFrom));
  1017. //
  1018. // Hmm - no patch source, so we can't think about applying patches. Hope
  1019. // there's no *.patch
  1020. //
  1021. if (!fFoundPatchBase)
  1022. {
  1023. #if DBG
  1024. FusionpDbgPrintEx(FUSION_DBG_LEVEL_INSTALLATION,
  1025. "SXS: %s(%d) - No patches found in path %ls\\%ls, not applying any\n",
  1026. __FILE__,
  1027. __LINE__,
  1028. static_cast<PCWSTR>(rcsbBasePath),
  1029. static_cast<PCWSTR>(rcsbPath));
  1030. #endif
  1031. FN_SUCCESSFUL_EXIT();
  1032. }
  1033. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(SourceAssemblyPath));
  1034. IFW32FALSE_EXIT(SourceAssemblyPath.Win32AppendPathElement(sbTempBuffer));
  1035. cchSourcePathBase = SourceAssemblyPath.Cch();
  1036. IFW32FALSE_EXIT(TargetAssemblyPath.Win32Assign(rcsbBasePath));
  1037. IFW32FALSE_EXIT(TargetAssemblyPath.Win32AppendPathElement(rcsbPath));
  1038. cchTargetPathBase = TargetAssemblyPath.Cch();
  1039. //
  1040. // First, let's look for *.patch and apply them all
  1041. //
  1042. IFW32FALSE_EXIT(TargetAssemblyPath.Win32AppendPathElement(&star_dot_patch));
  1043. IFW32FALSE_EXIT_UNLESS2(Finder.Win32FindFirstFile(TargetAssemblyPath, &FindData),
  1044. LIST_3( ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND, ERROR_NO_MORE_FILES ),
  1045. fError);
  1046. TargetAssemblyPath.Left(cchTargetPathBase);
  1047. if (!fError) do
  1048. {
  1049. SIZE_T cFileName_Length = ::wcslen(FindData.cFileName);
  1050. //
  1051. // Skip 'assembly.patch'
  1052. //
  1053. if (::FusionpEqualStringsI(
  1054. FindData.cFileName,
  1055. cFileName_Length,
  1056. &assembly_dot_patch))
  1057. {
  1058. continue;
  1059. }
  1060. IFW32FALSE_EXIT(sbTempBuffer.Win32Assign(
  1061. FindData.cFileName,
  1062. cFileName_Length));
  1063. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1064. {
  1065. ORIGINATE_WIN32_FAILURE_AND_EXIT(patch_has_dot_patch_directory, ERROR_INTERNAL_ERROR);
  1066. }
  1067. //
  1068. // Pull off the .patch part
  1069. //
  1070. sbTempBuffer.Left(sbTempBuffer.Cch() - RTL_STRING_GET_LENGTH_CHARS(&dot_patch));
  1071. IFW32FALSE_EXIT(SourceAssemblyPath.Win32AppendPathElement(sbTempBuffer));
  1072. IFW32FALSE_EXIT(TargetAssemblyPath.Win32AppendPathElement(sbTempBuffer));
  1073. IFW32FALSE_EXIT(sbTempBuffer.Win32Assign(TargetAssemblyPath));
  1074. IFW32FALSE_EXIT(sbTempBuffer.Win32Append(&dot_patch));
  1075. #if DBG
  1076. ::FusionpDbgPrintEx(
  1077. FUSION_DBG_LEVEL_INSTALLATION,
  1078. "SXS: %s(%d) - Patching:\n"
  1079. "\tPatch: %ls\n"
  1080. "\tSource: %ls\n"
  1081. "\tTarget: %ls\n",
  1082. __FILE__, __LINE__,
  1083. static_cast<PCWSTR>(sbTempBuffer),
  1084. static_cast<PCWSTR>(SourceAssemblyPath),
  1085. static_cast<PCWSTR>(TargetAssemblyPath));
  1086. #endif
  1087. IFW32FALSE_EXIT((*pfnApplyPatchToFileExW)(
  1088. sbTempBuffer,
  1089. SourceAssemblyPath,
  1090. TargetAssemblyPath,
  1091. 0, NULL, NULL));
  1092. //
  1093. // Next?
  1094. //
  1095. SourceAssemblyPath.Left(cchSourcePathBase);
  1096. TargetAssemblyPath.Left(cchTargetPathBase);
  1097. }
  1098. while (FindNextFileW(Finder, &FindData));
  1099. FN_EPILOG
  1100. }
  1101. class CDirectoryDeleter
  1102. {
  1103. PRIVATIZE_COPY_CONSTRUCTORS(CDirectoryDeleter);
  1104. CStringBuffer m_OurDir;
  1105. bool m_fDoDelete;
  1106. public:
  1107. CDirectoryDeleter() : m_fDoDelete(false) { }
  1108. BOOL SetDelete(bool fDelete) { m_fDoDelete = fDelete; return TRUE; }
  1109. BOOL SetPath(const CBaseStringBuffer &path) { return m_OurDir.Win32Assign(path); }
  1110. ~CDirectoryDeleter()
  1111. {
  1112. if (m_fDoDelete)
  1113. {
  1114. CSxsPreserveLastError ple;
  1115. ::SxspDeleteDirectory(m_OurDir);
  1116. m_fDoDelete = false;
  1117. ple.Restore();
  1118. }
  1119. }
  1120. };
  1121. int
  1122. __cdecl
  1123. StringBufferCompareStrings(
  1124. const void* pLeft,
  1125. const void* pRight)
  1126. {
  1127. const CStringBuffer * pStrLeft = *reinterpret_cast<CStringBuffer const * const * >(pLeft);
  1128. const CStringBuffer * pStrRight = *reinterpret_cast<CStringBuffer const * const * >(pRight);
  1129. StringComparisonResult Result = eLessThan;
  1130. //
  1131. // On failure, leave in place
  1132. //
  1133. if (!pStrLeft->Win32Compare(*pStrRight, pStrRight->Cch(), Result, true))
  1134. {
  1135. Result = eLessThan;
  1136. }
  1137. switch (Result)
  1138. {
  1139. case eLessThan: return -1;
  1140. case eGreaterThan: return 1;
  1141. default: return 0;
  1142. }
  1143. }
  1144. class CSxspGatherCabinetsToInstallLocals
  1145. {
  1146. public:
  1147. CSxspGatherCabinetsToInstallLocals() { }
  1148. ~CSxspGatherCabinetsToInstallLocals() { }
  1149. void Clear()
  1150. //
  1151. // Clear is how you deal with the fact that some function calls were in loops
  1152. // and/or some local variables were in loops.
  1153. //
  1154. // In "lifting up" the variables, we lose the repeated constructor/destructor calls.
  1155. //
  1156. {
  1157. this->PathScan.Clear();
  1158. this->Temp.Clear();
  1159. }
  1160. CMediumStringBuffer PathScan;
  1161. WIN32_FIND_DATAW FindData;
  1162. CStringBuffer Temp;
  1163. };
  1164. BOOL
  1165. SxspGatherCabinetsToInstall(
  1166. const CBaseStringBuffer &CabinetBasePath,
  1167. CFusionArray<CStringBuffer> &CabinetNames_StringBuffers,
  1168. CFusionArray<CStringBuffer*> &CabinetNames_StringBufferPointers,
  1169. SIZE_T &CabCount,
  1170. CSxspGatherCabinetsToInstallLocals &Locals)
  1171. {
  1172. FN_PROLOG_WIN32
  1173. CFindFile Finder;
  1174. BOOL fNoFilesMatch = FALSE;
  1175. const static UNICODE_STRING asms_star_dot_cab = RTL_CONSTANT_STRING(L"asms*.cab");
  1176. DWORD dwWin32Error = 0;
  1177. Locals.Clear();
  1178. CMediumStringBuffer &PathScan = Locals.PathScan;
  1179. WIN32_FIND_DATAW &FindData = Locals.FindData;
  1180. CabCount = 0;
  1181. IFW32FALSE_EXIT(PathScan.Win32Assign(CabinetBasePath));
  1182. IFW32FALSE_EXIT(PathScan.Win32EnsureTrailingPathSeparator());
  1183. IFW32FALSE_EXIT(PathScan.Win32Append(&asms_star_dot_cab));
  1184. IFW32FALSE_EXIT_UNLESS2(
  1185. Finder.Win32FindFirstFile(PathScan, &FindData),
  1186. LIST_3(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_NO_MORE_FILES),
  1187. fNoFilesMatch);
  1188. //
  1189. // Nothing found, quit looking
  1190. //
  1191. if (fNoFilesMatch)
  1192. {
  1193. FN_SUCCESSFUL_EXIT();
  1194. }
  1195. //
  1196. // Zip through files
  1197. //
  1198. do
  1199. {
  1200. if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  1201. {
  1202. CStringBuffer &Temp = Locals.Temp;
  1203. IFW32FALSE_EXIT(Temp.Win32Assign(FindData.cFileName, lstrlenW(FindData.cFileName)));
  1204. IFW32FALSE_EXIT(CabinetNames_StringBuffers.Win32Append(Temp));
  1205. CabCount++;
  1206. }
  1207. }
  1208. while (FindNextFileW(Finder, &FindData));
  1209. //
  1210. // If we failed somehow
  1211. //
  1212. dwWin32Error = ::FusionpGetLastWin32Error();
  1213. if (dwWin32Error != ERROR_NO_MORE_FILES && dwWin32Error != ERROR_SUCCESS)
  1214. {
  1215. ORIGINATE_WIN32_FAILURE_AND_EXIT(FindNextFileW, dwWin32Error);
  1216. }
  1217. //
  1218. // CStringBuffers cannot be sorted by qsort because it copies
  1219. // array elements as if by memcpy, which is wrong for CStringBuffers.
  1220. // std::sort does the right thing, but it cannot be used here.
  1221. //
  1222. SIZE_T i = 0;
  1223. for ( i = 0 ; i != CabCount ; ++i )
  1224. {
  1225. IFW32FALSE_EXIT(CabinetNames_StringBufferPointers.Win32Append(&CabinetNames_StringBuffers[i]));
  1226. }
  1227. qsort(
  1228. CabinetNames_StringBufferPointers.GetArrayPtr(),
  1229. CabCount,
  1230. sizeof(CFusionArray<CStringBuffer*>::ValueType),
  1231. StringBufferCompareStrings);
  1232. FN_EPILOG
  1233. }
  1234. class CSxspInstallAsmsDotCabEtAlLocals
  1235. {
  1236. public:
  1237. CSxspInstallAsmsDotCabEtAlLocals() { }
  1238. ~CSxspInstallAsmsDotCabEtAlLocals() { }
  1239. void Clear()
  1240. //
  1241. // Clear is how you deal with the fact that some function calls were in loops
  1242. // and/or some local variables were in loops.
  1243. //
  1244. // In "lifting up" the variables, we lose the repeated constructor/destructor calls.
  1245. //
  1246. {
  1247. this->buffCabinetPath.Clear();
  1248. this->buffTempPath.Clear();
  1249. this->buffRelativePath.Clear();
  1250. this->SxspApplyPatchesFor.Clear();
  1251. this->SxspGatherCabinetsToInstall.Clear();
  1252. this->SxspDetectAndInstallFromPath.Clear();
  1253. }
  1254. CCabinetData CabData;
  1255. CStringBuffer buffCabinetPath;
  1256. CStringBuffer buffTempPath;
  1257. CStringBuffer buffRelativePath;
  1258. CSxspApplyPatchesForLocals SxspApplyPatchesFor;
  1259. CSxspGatherCabinetsToInstallLocals SxspGatherCabinetsToInstall;
  1260. CSxspDetectAndInstallFromPathLocals SxspDetectAndInstallFromPath;
  1261. };
  1262. BOOL
  1263. SxspInstallAsmsDotCabEtAl(
  1264. DWORD dwFlags,
  1265. CAssemblyInstall &AssemblyContext,
  1266. const CBaseStringBuffer &CabinetBasePath,
  1267. CFusionArray<CStringBuffer> *pAssembliesToInstall)
  1268. {
  1269. FN_PROLOG_WIN32
  1270. CSmartPtr<CSxspInstallAsmsDotCabEtAlLocals> Locals;
  1271. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  1272. IFW32FALSE_EXIT(SxspInstallAsmsDotCabEtAl(
  1273. dwFlags,
  1274. AssemblyContext,
  1275. CabinetBasePath,
  1276. pAssembliesToInstall,
  1277. *Locals));
  1278. FN_EPILOG
  1279. }
  1280. BOOL
  1281. SxspInstallAsmsDotCabEtAl(
  1282. DWORD dwFlags,
  1283. CAssemblyInstall &AssemblyContext,
  1284. const CBaseStringBuffer &CabinetBasePath,
  1285. CFusionArray<CStringBuffer> *pAssembliesToInstall,
  1286. CSxspInstallAsmsDotCabEtAlLocals &Locals)
  1287. {
  1288. FN_PROLOG_WIN32
  1289. CFusionArray<CStringBuffer> Cabinets_StringBuffers;
  1290. CFusionArray<CStringBuffer*> Cabinets_StringBufferPointers;
  1291. SIZE_T cchBasePath = 0;
  1292. SIZE_T CabinetCount = 0;
  1293. Locals.Clear();
  1294. CCabinetData &CabData = Locals.CabData;
  1295. CStringBuffer &buffCabinetPath = Locals.buffCabinetPath;
  1296. CStringBuffer &buffTempPath = Locals.buffTempPath;
  1297. CDirectoryDeleter Deleter;
  1298. //
  1299. // Go find the list (and ordering) of cabinets to install
  1300. //
  1301. IFW32FALSE_EXIT(Cabinets_StringBuffers.Win32Initialize(0));
  1302. IFW32FALSE_EXIT(Cabinets_StringBufferPointers.Win32Initialize(0));
  1303. IFW32FALSE_EXIT(::SxspGatherCabinetsToInstall(
  1304. CabinetBasePath,
  1305. Cabinets_StringBuffers,
  1306. Cabinets_StringBufferPointers,
  1307. CabinetCount,
  1308. Locals.SxspGatherCabinetsToInstall));
  1309. //
  1310. // Stash this, we'll need it - also create a temp directory for our use in
  1311. // uncompressing things. Ensure that it goes away after installation.
  1312. //
  1313. IFW32FALSE_EXIT(buffCabinetPath.Win32Assign(CabinetBasePath));
  1314. IFW32FALSE_EXIT(::SxspCreateWinSxsTempDirectory(buffTempPath, NULL, NULL, NULL));
  1315. IFW32FALSE_EXIT(Deleter.SetPath(buffTempPath));
  1316. IFW32FALSE_EXIT(Deleter.SetDelete(true));
  1317. //
  1318. // We'll be reusing this, so store the base length
  1319. //
  1320. cchBasePath = buffCabinetPath.Cch();
  1321. //
  1322. // Now for all the items we found:
  1323. // 1. Expand to the temporary directory
  1324. // 2. Apply patches
  1325. // 3. Install
  1326. //
  1327. for (SIZE_T cab = 0; cab < CabinetCount; cab++)
  1328. {
  1329. CabData.Initialize();
  1330. //
  1331. // If there's stuff at the end of the cabinet path, trim it.
  1332. //
  1333. if (buffCabinetPath.Cch() != cchBasePath)
  1334. {
  1335. buffCabinetPath.Left(cchBasePath);
  1336. }
  1337. //
  1338. // Set up the cabinet data object, create the cabinet path, and then really
  1339. // do the extraction
  1340. //
  1341. IFW32FALSE_EXIT(CabData.Initialize(buffTempPath, true));
  1342. IFW32FALSE_EXIT(buffCabinetPath.Win32AppendPathElement(*Cabinets_StringBufferPointers[cab]));
  1343. IFW32FALSE_EXIT(::SxspExpandCabinetIntoTemp(
  1344. 0,
  1345. buffCabinetPath,
  1346. AssemblyContext.m_ImpersonationData,
  1347. &CabData));
  1348. //
  1349. // For each assembly extracted, apply patches
  1350. //
  1351. for (SIZE_T a = 0; a < CabData.m_AssembliesExtracted.GetSize(); a++)
  1352. {
  1353. CBaseStringBuffer &buffRelativePath = Locals.buffRelativePath;
  1354. buffRelativePath.Clear();
  1355. //
  1356. // Patchy patchy
  1357. //
  1358. IFW32FALSE_EXIT(::SxspApplyPatchesFor(
  1359. CabData.BasePath(),
  1360. CabData.m_AssembliesExtracted[a],
  1361. Locals.SxspApplyPatchesFor));
  1362. //
  1363. // Find the portion of this path that's relative to the base path
  1364. //
  1365. IFW32FALSE_EXIT(buffRelativePath.Win32Assign(buffCabinetPath));
  1366. buffRelativePath.Right(buffRelativePath.Cch() - CabinetBasePath.Cch() - 1);
  1367. //
  1368. // If we're doing this during OS-setup, we need to crop off the first
  1369. // path piece
  1370. //
  1371. if (AssemblyContext.m_ActCtxGenCtx.m_ManifestOperationFlags & MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_OSSETUP)
  1372. {
  1373. CTinyStringBuffer tsb;
  1374. IFW32FALSE_EXIT(CabinetBasePath.Win32GetLastPathElement(tsb));
  1375. IFW32FALSE_EXIT(tsb.Win32AppendPathElement(buffRelativePath));
  1376. IFW32FALSE_EXIT(buffRelativePath.Win32Assign(tsb));
  1377. }
  1378. //
  1379. // Did the user provide a 'filter' to do installations? If so, compare the
  1380. // assembly that we just patched to all those in the list. If we were good
  1381. // citizens, if we found a match we'd remove it from the list of those
  1382. // found, but ... we're lousy and don't want to incur the overhead of sloshing
  1383. // array entries around.
  1384. //
  1385. if (pAssembliesToInstall != NULL)
  1386. {
  1387. bool fMatched = false;
  1388. for (SIZE_T idx = 0; !fMatched && (idx < pAssembliesToInstall->GetSize()); idx++)
  1389. {
  1390. IFW32FALSE_EXIT(CabData.m_AssembliesExtracted[a].Win32Equals(
  1391. (*pAssembliesToInstall)[idx],
  1392. fMatched,
  1393. true));
  1394. }
  1395. //
  1396. // No match, but they had a filter, so go do the next assembly, we don't care
  1397. // about this one.
  1398. //
  1399. if (!fMatched)
  1400. continue;
  1401. }
  1402. //
  1403. // Goody! Go do the installation
  1404. //
  1405. IFW32FALSE_EXIT(::SxspDetectAndInstallFromPath(
  1406. AssemblyContext,
  1407. buffRelativePath,
  1408. CabData.BasePath(),
  1409. CabData.m_AssembliesExtracted[a],
  1410. Locals.SxspDetectAndInstallFromPath));
  1411. }
  1412. }
  1413. FN_EPILOG
  1414. }
  1415. BOOL
  1416. SxspMapInstallFlagsToManifestOpFlags(
  1417. DWORD dwSourceFlags,
  1418. DWORD &dwTargetFlags)
  1419. {
  1420. FN_PROLOG_WIN32
  1421. dwTargetFlags = 0;
  1422. #define MAP_FLAG(x) do { if (dwSourceFlags & SXS_INSTALL_FLAG_ ## x) dwTargetFlags |= MANIFEST_OPERATION_INSTALL_FLAG_ ## x; } while (0)
  1423. MAP_FLAG(MOVE);
  1424. MAP_FLAG(FROM_RESOURCE);
  1425. MAP_FLAG(NO_VERIFY);
  1426. MAP_FLAG(NOT_TRANSACTIONAL);
  1427. MAP_FLAG(REPLACE_EXISTING);
  1428. MAP_FLAG(FROM_DIRECTORY);
  1429. MAP_FLAG(FROM_DIRECTORY_RECURSIVE);
  1430. MAP_FLAG(INSTALLED_BY_DARWIN);
  1431. MAP_FLAG(INSTALLED_BY_OSSETUP);
  1432. MAP_FLAG(REFERENCE_VALID);
  1433. MAP_FLAG(REFRESH);
  1434. MAP_FLAG(FROM_CABINET);
  1435. #undef MAP_FLAG
  1436. FN_EPILOG
  1437. }
  1438. class CSxspRecoverAssemblyFromCabinetLocals
  1439. {
  1440. public:
  1441. CSxspRecoverAssemblyFromCabinetLocals() { }
  1442. ~CSxspRecoverAssemblyFromCabinetLocals() { }
  1443. void Clear()
  1444. //
  1445. // Clear is how you deal with the fact that some function calls were in loops
  1446. // and/or some local variables were in loops.
  1447. //
  1448. // In "lifting up" the variables, we lose the repeated constructor/destructor calls.
  1449. //
  1450. {
  1451. ::ZeroMemory(&this->AttributeCache, sizeof(this->AttributeCache));
  1452. this->CabData.Clear();
  1453. this->buffTempPath.Clear();
  1454. this->buffRelativePathToManifestFile.Clear();
  1455. this->buffRelativePathToCatalogFile.Clear();
  1456. this->buffRelativePathPayloadDirectory.Clear();
  1457. this->buffAssemblyRootDirectory.Clear();
  1458. this->buffManifestOrCatalogFileFullTempManifestsPath.Clear();
  1459. this->buffManifestOrCatalogFileFullTempPayloadPath.Clear();
  1460. this->buffManifestOrCatalogLeafPath.Clear();
  1461. this->buffRelativeCodebasePathIgnoredDueToRefreshFlagRegistryNotTouched.Clear();
  1462. }
  1463. PROBING_ATTRIBUTE_CACHE AttributeCache;
  1464. CCabinetData CabData;
  1465. CStringBuffer buffTempPath;
  1466. CStringBuffer buffRelativePathToManifestFile;
  1467. CStringBuffer buffRelativePathToCatalogFile;
  1468. CStringBuffer buffRelativePathPayloadDirectory;
  1469. CStringBuffer buffAssemblyRootDirectory;
  1470. CStringBuffer buffManifestOrCatalogFileFullTempManifestsPath;
  1471. CStringBuffer buffManifestOrCatalogFileFullTempPayloadPath;
  1472. CStringBuffer buffManifestOrCatalogLeafPath;
  1473. CStringBuffer buffRelativeCodebasePathIgnoredDueToRefreshFlagRegistryNotTouched;
  1474. CAssemblyInstall Installer;
  1475. };
  1476. BOOL
  1477. SxspRecoverAssemblyFromCabinet_ShouldExtractFileFromCab(
  1478. const CBaseStringBuffer &rbuffPathInCab,
  1479. bool &rfShouldExtract,
  1480. PVOID VoidContext)
  1481. {
  1482. FN_PROLOG_WIN32
  1483. const CSxspRecoverAssemblyFromCabinetLocals * Context = reinterpret_cast<CSxspRecoverAssemblyFromCabinetLocals*>(VoidContext);
  1484. INTERNAL_ERROR_CHECK(Context != NULL);
  1485. INTERNAL_ERROR_CHECK(&rfShouldExtract != NULL);
  1486. INTERNAL_ERROR_CHECK(&rbuffPathInCab != NULL);
  1487. rfShouldExtract = false;
  1488. if (::FusionpEqualStringsI(rbuffPathInCab, Context->buffRelativePathToManifestFile))
  1489. {
  1490. rfShouldExtract = true;
  1491. FN_SUCCESSFUL_EXIT();
  1492. }
  1493. else if (::FusionpEqualStringsI(rbuffPathInCab, Context->buffRelativePathToCatalogFile))
  1494. {
  1495. rfShouldExtract = true;
  1496. FN_SUCCESSFUL_EXIT();
  1497. }
  1498. else
  1499. {
  1500. const SIZE_T cch = Context->buffRelativePathPayloadDirectory.Cch();
  1501. INTERNAL_ERROR_CHECK(cch != 0);
  1502. INTERNAL_ERROR_CHECK(::FusionpIsPathSeparator(Context->buffRelativePathPayloadDirectory[cch - 1]));
  1503. if (rbuffPathInCab.Cch() >= cch)
  1504. {
  1505. if (::FusionpEqualStringsI(
  1506. static_cast<PCWSTR>(rbuffPathInCab),
  1507. cch,
  1508. Context->buffRelativePathPayloadDirectory,
  1509. cch))
  1510. {
  1511. rfShouldExtract = true;
  1512. FN_SUCCESSFUL_EXIT();
  1513. }
  1514. }
  1515. }
  1516. rfShouldExtract = false;
  1517. FN_SUCCESSFUL_EXIT();
  1518. FN_EPILOG
  1519. }
  1520. BOOL
  1521. SxspDeleteFileOrEmptyDirectoryIfExists(
  1522. CBaseStringBuffer &buff)
  1523. {
  1524. FN_PROLOG_WIN32
  1525. DWORD dwFileOrDirectoryExists = 0;
  1526. IFW32FALSE_EXIT(SxspDoesFileOrDirectoryExist(0, buff, dwFileOrDirectoryExists));
  1527. switch (dwFileOrDirectoryExists)
  1528. {
  1529. case SXSP_DOES_FILE_OR_DIRECTORY_EXIST_DISPOSITION_FILE_EXISTS:
  1530. IFW32FALSE_ORIGINATE_AND_EXIT(::DeleteFileW(buff));
  1531. break;
  1532. case SXSP_DOES_FILE_OR_DIRECTORY_EXIST_DISPOSITION_DIRECTORY_EXISTS:
  1533. IFW32FALSE_ORIGINATE_AND_EXIT(::RemoveDirectoryW(buff));
  1534. break;
  1535. case SXSP_DOES_FILE_OR_DIRECTORY_EXIST_DISPOSITION_NEITHER_EXISTS:
  1536. // do nothing
  1537. break;
  1538. }
  1539. FN_EPILOG
  1540. }
  1541. BOOL
  1542. SxspRecoverAssemblyFromCabinet(
  1543. const CBaseStringBuffer &buffCabinetPath,
  1544. const CBaseStringBuffer &AssemblyIdentity,
  1545. PSXS_INSTALLW pInstall)
  1546. {
  1547. FN_PROLOG_WIN32
  1548. CSmartAssemblyIdentity pAssemblyIdentity;
  1549. CDirectoryDeleter Deleter;
  1550. CImpersonationData ImpersonationData;
  1551. DWORD dwFlags = 0;
  1552. CSmartPtr<CSxspRecoverAssemblyFromCabinetLocals> Locals;
  1553. IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
  1554. CCabinetData &CabData = Locals->CabData;
  1555. ::ZeroMemory(&Locals->AttributeCache, sizeof(Locals->AttributeCache));
  1556. //
  1557. // First get the identity back to a real thing we can use
  1558. //
  1559. IFW32FALSE_EXIT(::SxspCreateAssemblyIdentityFromTextualString(
  1560. AssemblyIdentity,
  1561. &pAssemblyIdentity));
  1562. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(Locals->buffAssemblyRootDirectory));
  1563. //
  1564. // And then turn that into paths
  1565. //
  1566. IFW32FALSE_EXIT(::SxspGenerateSxsPath_RelativePathToManifestOrPolicyFile(
  1567. Locals->buffAssemblyRootDirectory,
  1568. pAssemblyIdentity,
  1569. &Locals->AttributeCache,
  1570. Locals->buffRelativePathToManifestFile));
  1571. IFW32FALSE_EXIT(::SxspGenerateSxsPath_RelativePathToCatalogFile(
  1572. Locals->buffAssemblyRootDirectory,
  1573. pAssemblyIdentity,
  1574. &Locals->AttributeCache,
  1575. Locals->buffRelativePathToCatalogFile));
  1576. IFW32FALSE_EXIT(::SxspGenerateSxsPath_RelativePathToPayloadOrPolicyDirectory(
  1577. Locals->buffAssemblyRootDirectory,
  1578. pAssemblyIdentity,
  1579. &Locals->AttributeCache,
  1580. Locals->buffRelativePathPayloadDirectory));
  1581. IFW32FALSE_EXIT(Locals->buffRelativePathPayloadDirectory.Win32EnsureTrailingPathSeparator());
  1582. IFW32FALSE_EXIT(::SxspCreateWinSxsTempDirectory(Locals->buffTempPath, NULL, NULL, NULL));
  1583. IFW32FALSE_EXIT(Deleter.SetPath(Locals->buffTempPath));
  1584. IFW32FALSE_EXIT(Deleter.SetDelete(true));
  1585. IFW32FALSE_EXIT(CabData.Initialize(Locals->buffTempPath, true));
  1586. CabData.m_pfnShouldExtractThisFileFromCabCallback = &SxspRecoverAssemblyFromCabinet_ShouldExtractFileFromCab;
  1587. CabData.m_pvShouldExtractThisFileFromCabCallbackContext = static_cast<CSxspRecoverAssemblyFromCabinetLocals*>(Locals);
  1588. IFW32FALSE_EXIT(::SxspExpandCabinetIntoTemp(
  1589. 0,
  1590. buffCabinetPath,
  1591. ImpersonationData,
  1592. &CabData));
  1593. //
  1594. // now move temp\manifests\blah.manifest and temp\manifests\blah.cat into temp\blah
  1595. // so that existing code shared with sxsinstall works
  1596. //
  1597. {
  1598. const CBaseStringBuffer * FilesToMove[] =
  1599. {
  1600. &Locals->buffRelativePathToCatalogFile,
  1601. &Locals->buffRelativePathToManifestFile // manifest must be last, as we use the value
  1602. // outside the loop
  1603. };
  1604. SIZE_T i = 0;
  1605. for ( i = 0 ; i != NUMBER_OF(FilesToMove) ; ++i )
  1606. {
  1607. IFW32FALSE_EXIT(Locals->buffManifestOrCatalogFileFullTempManifestsPath.Win32Assign(Locals->buffTempPath));
  1608. IFW32FALSE_EXIT(Locals->buffManifestOrCatalogFileFullTempManifestsPath.Win32AppendPathElement(*FilesToMove[i]));
  1609. IFW32FALSE_EXIT(Locals->buffManifestOrCatalogFileFullTempManifestsPath.Win32GetLastPathElement(Locals->buffManifestOrCatalogLeafPath));
  1610. IFW32FALSE_EXIT(Locals->buffManifestOrCatalogFileFullTempPayloadPath.Win32Assign(Locals->buffTempPath));
  1611. IFW32FALSE_EXIT(Locals->buffManifestOrCatalogFileFullTempPayloadPath.Win32AppendPathElement(Locals->buffRelativePathPayloadDirectory));
  1612. IFW32FALSE_EXIT(Locals->buffManifestOrCatalogFileFullTempPayloadPath.Win32AppendPathElement(Locals->buffManifestOrCatalogLeafPath));
  1613. IFW32FALSE_EXIT(::SxspDeleteFileOrEmptyDirectoryIfExists(Locals->buffManifestOrCatalogFileFullTempPayloadPath));
  1614. IFW32FALSE_EXIT(::SxspInstallMoveFileExW(
  1615. Locals->buffManifestOrCatalogFileFullTempManifestsPath,
  1616. Locals->buffManifestOrCatalogFileFullTempPayloadPath,
  1617. MOVEFILE_REPLACE_EXISTING,
  1618. FALSE));
  1619. }
  1620. }
  1621. //
  1622. // Start up the installation
  1623. //
  1624. IFW32FALSE_EXIT(::SxspMapInstallFlagsToManifestOpFlags(pInstall->dwFlags, dwFlags));
  1625. IFW32FALSE_EXIT(Locals->Installer.BeginAssemblyInstall(
  1626. dwFlags | MANIFEST_OPERATION_INSTALL_FLAG_FORCE_LOOK_FOR_CATALOG,
  1627. NULL,
  1628. NULL,
  1629. ImpersonationData));
  1630. //
  1631. // Do the install directly.
  1632. //
  1633. // This circumventing SxsInstallW is consistent with what the
  1634. // code used to do (circa Jan. - June 2002), though it
  1635. // apparently did not actually work in that period.
  1636. //
  1637. BOOL fResult =
  1638. Locals->Installer.InstallFile(
  1639. Locals->buffManifestOrCatalogFileFullTempPayloadPath, // manifest file
  1640. Locals->buffRelativeCodebasePathIgnoredDueToRefreshFlagRegistryNotTouched);
  1641. //
  1642. // Now we have to end the installation, whether it worked or not.
  1643. //
  1644. if (fResult)
  1645. {
  1646. IFW32FALSE_EXIT(
  1647. Locals->Installer.EndAssemblyInstall(
  1648. MANIFEST_OPERATION_INSTALL_FLAG_COMMIT
  1649. | MANIFEST_OPERATION_INSTALL_FLAG_REFRESH,
  1650. NULL));
  1651. }
  1652. else
  1653. {
  1654. const DWORD dwWin32Error = ::FusionpGetLastWin32Error();
  1655. if (!Locals->Installer.EndAssemblyInstall(
  1656. MANIFEST_OPERATION_INSTALL_FLAG_ABORT
  1657. | MANIFEST_OPERATION_INSTALL_FLAG_REFRESH,
  1658. NULL))
  1659. {
  1660. ::FusionpDbgPrintEx(
  1661. FUSION_DBG_LEVEL_INSTALLATION | FUSION_DBG_LEVEL_ERROR,
  1662. "SXS: %s failure %lu in abort ignored\n",
  1663. __FUNCTION__,
  1664. ::FusionpGetLastWin32Error());
  1665. }
  1666. ::FusionpSetLastWin32Error(dwWin32Error);
  1667. ORIGINATE_WIN32_FAILURE_AND_EXIT(SxspRecoverAssemblyFromCabinet.InstallFile, dwWin32Error);
  1668. }
  1669. FN_EPILOG
  1670. }