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.

664 lines
21 KiB

  1. #include <windows.h>
  2. #include <fusenetincludes.h>
  3. #include <stdio.h>
  4. #include <msxml2.h>
  5. #include "list.h"
  6. #include "patchapi.h"
  7. #include "patchprv.h"
  8. #include "patchlzx.h"
  9. #include "xmlutil.h"
  10. #include "pg.h"
  11. #define DIRECTORY_PATH 0
  12. #define FILE_PATH 1
  13. #define HASHTABLE_SIZE 257
  14. /////////////////////////////////////////////////////////////////////////
  15. // PathNormalize
  16. /////////////////////////////////////////////////////////////////////////
  17. HRESULT PathNormalize(LPWSTR pwzPath, LPWSTR *ppwzAbsolutePath, DWORD dwFlag, BOOL bCreate)
  18. {
  19. HRESULT hr = S_OK;
  20. WCHAR pwzTempDir[MAX_PATH], pwzAbsolutePath[MAX_PATH];
  21. DWORD ccDir = MAX_PATH;
  22. *ppwzAbsolutePath = NULL;
  23. //If path is relative, prepend the current directory
  24. if (PathIsRelative(pwzPath))
  25. {
  26. GetCurrentDirectory(ccDir, pwzTempDir);
  27. StrCat(pwzTempDir, L"\\");
  28. StrCat(pwzTempDir, pwzPath);
  29. }
  30. else
  31. StrCpy(pwzTempDir, pwzPath);
  32. if (!PathCanonicalize(pwzAbsolutePath, pwzTempDir))
  33. {
  34. printf("Dir \"%ws\" canonicalize error\n", pwzTempDir);
  35. hr = E_FAIL;
  36. goto exit;
  37. }
  38. //If path is supposed to be a diesctory, append a trailing slash if not already there
  39. ccDir = lstrlen(pwzAbsolutePath);
  40. if (dwFlag == DIRECTORY_PATH && pwzAbsolutePath[ccDir -1] != L'\\')
  41. {
  42. pwzAbsolutePath[ccDir] = L'\\';
  43. pwzAbsolutePath[ccDir +1] = L'\0';
  44. }
  45. //Make sure the direcotry exists
  46. if (dwFlag == DIRECTORY_PATH && !bCreate)
  47. {
  48. if(!PathIsDirectory(pwzAbsolutePath))
  49. {
  50. printf("Dir \"%ws\" is not a valid directory\n", pwzPath);
  51. hr = E_FAIL;
  52. goto exit;
  53. }
  54. }
  55. //Make sure the file exists
  56. else if (dwFlag == FILE_PATH)
  57. {
  58. if(!bCreate)
  59. {
  60. if(!PathFileExists(pwzAbsolutePath))
  61. {
  62. printf("File \"%ws\" does not exist\n", pwzPath);
  63. hr = E_FAIL;
  64. goto exit;
  65. }
  66. }
  67. if(PathIsDirectory(pwzAbsolutePath))
  68. {
  69. printf("File \"%ws\" is a directory\n", pwzPath);
  70. hr = E_FAIL;
  71. goto exit;
  72. }
  73. }
  74. (*ppwzAbsolutePath) = WSTRDupDynamic(pwzAbsolutePath);
  75. exit:
  76. return hr;
  77. }
  78. /////////////////////////////////////////////////////////////////////////
  79. // IsValidManifestImport
  80. /////////////////////////////////////////////////////////////////////////
  81. HRESULT IsValidManifestImport (LPWSTR pwzManifestPath)
  82. {
  83. HRESULT hr = S_OK;
  84. IAssemblyManifestImport *pManImport = NULL;
  85. IAssemblyIdentity *pAssemblyId = NULL;
  86. if((hr = CreateAssemblyManifestImport(&pManImport, pwzManifestPath, NULL, 0)) != S_OK)
  87. goto exit;
  88. if((hr = pManImport->GetAssemblyIdentity(&pAssemblyId)) != S_OK)
  89. goto exit;
  90. exit:
  91. SAFERELEASE(pAssemblyId);
  92. SAFERELEASE(pManImport);
  93. return hr;
  94. }
  95. /////////////////////////////////////////////////////////////////////////
  96. // FindAllFiles
  97. /////////////////////////////////////////////////////////////////////////
  98. HRESULT FindAllFiles (LPWSTR pwzDir, List<LPWSTR> *pFileList)
  99. {
  100. HRESULT hr = S_OK;
  101. HANDLE hFind = INVALID_HANDLE_VALUE;
  102. WIN32_FIND_DATA fdFile;
  103. CString sSearchString, sFileName;
  104. DWORD dwHash = 0;
  105. DWORD dwLastError = 0;
  106. // set up search string to find all files in the passed in directory
  107. sSearchString.Assign(pwzDir);
  108. sSearchString.Append(L"*");
  109. if (sSearchString._cc > MAX_PATH)
  110. {
  111. hr = CO_E_PATHTOOLONG;
  112. printf("Error: Search path too long\n");
  113. goto exit;
  114. }
  115. hFind = FindFirstFile(sSearchString._pwz, &fdFile);
  116. if (hFind == INVALID_HANDLE_VALUE)
  117. {
  118. hr = E_FAIL;
  119. printf("Find file error\n");
  120. goto exit;
  121. }
  122. //enumerate through all the files in the directory,
  123. // and recursivly call FindAllAssemblies on any directories encountered
  124. while(TRUE)
  125. {
  126. LPWSTR pwzFileName = NULL;
  127. if (StrCmp(fdFile.cFileName, L".") != 0 && StrCmp(fdFile.cFileName, L"..") != 0)
  128. {
  129. CString sFilePath;
  130. //create absolute file name by appending the filename to the dir name
  131. sFilePath.Assign(pwzDir);
  132. sFilePath.Append(fdFile.cFileName);
  133. if (sSearchString._cc > MAX_PATH)
  134. {
  135. hr = CO_E_PATHTOOLONG;
  136. printf("Error: File path too long\n");
  137. goto exit;
  138. }
  139. //If the file is a directory, recursivly call FindAllFiles
  140. if ((fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  141. {
  142. sFilePath.Append(L"\\");
  143. if (FAILED(hr = FindAllFiles(sFilePath._pwz, pFileList)))
  144. goto exit;
  145. }
  146. // If a file add it to our master list
  147. else
  148. {
  149. if (StrCmp(sFilePath._pwz, g_sSourceManifest._pwz))
  150. {
  151. sFileName.Assign(sFilePath._pwz+ g_sSourceBase._cc -1);
  152. dwHash = HashString(sFileName._pwz, HASHTABLE_SIZE, false);
  153. sFileName.ReleaseOwnership(&pwzFileName);
  154. pFileList[dwHash].AddTail(pwzFileName);
  155. }
  156. }
  157. }
  158. if (!FindNextFile(hFind, &fdFile))
  159. {
  160. dwLastError = GetLastError();
  161. break;
  162. }
  163. if(dwLastError == ERROR_NO_MORE_FILES)
  164. hr = S_OK;
  165. else
  166. hr = HRESULT_FROM_WIN32(dwLastError);
  167. }
  168. hr = S_OK;
  169. exit:
  170. return hr;
  171. }
  172. /////////////////////////////////////////////////////////////////////////
  173. // CrossReferenceFiles
  174. /////////////////////////////////////////////////////////////////////////
  175. HRESULT CrossReferenceFiles (LPWSTR pwzDir, List<LPWSTR> *pFileList, List<LPWSTR> *pPatchableFiles)
  176. {
  177. HRESULT hr = S_OK;
  178. HANDLE hFind = INVALID_HANDLE_VALUE;
  179. WIN32_FIND_DATA fdFile;
  180. CString sSearchString, sFileName;
  181. DWORD dwHash=0;
  182. LISTNODE pos;
  183. LPWSTR pwzBuf = NULL;
  184. DWORD dwLastError = 0;
  185. // set up search string to find all files in the passed in directory
  186. sSearchString.Assign(pwzDir);
  187. sSearchString.Append(L"*");
  188. if (sSearchString._cc > MAX_PATH)
  189. {
  190. hr = CO_E_PATHTOOLONG;
  191. printf("Error: Search path too long\n");
  192. goto exit;
  193. }
  194. hFind = FindFirstFile(sSearchString._pwz, &fdFile);
  195. if (hFind == INVALID_HANDLE_VALUE)
  196. {
  197. hr = E_FAIL;
  198. printf("Find file error\n");
  199. goto exit;
  200. }
  201. //enumerate through all the files in the directory,
  202. // and recursivly call FindAllAssemblies on any directories encountered
  203. while(dwLastError != ERROR_NO_MORE_FILES)
  204. {
  205. LPWSTR pwzFileName = NULL;
  206. if (StrCmp(fdFile.cFileName, L".") != 0 && StrCmp(fdFile.cFileName, L"..") != 0)
  207. {
  208. CString sFilePath;
  209. //create absolute file name by appending the filename to the dir name
  210. sFilePath.Assign(pwzDir);
  211. sFilePath.Append(fdFile.cFileName);
  212. if (sSearchString._cc > MAX_PATH)
  213. {
  214. hr = CO_E_PATHTOOLONG;
  215. printf("Error: File path too long\n");
  216. goto exit;
  217. }
  218. //If the file is a directory, recursivly call CrossReferenceFiles
  219. if ((fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  220. {
  221. sFilePath.Append(L"\\");
  222. if (FAILED(hr = CrossReferenceFiles(sFilePath._pwz, pFileList, pPatchableFiles)))
  223. goto exit;
  224. }
  225. // If a file, check to see if it can be patched
  226. else
  227. {
  228. sFileName.Assign(sFilePath._pwz+g_sDestBase._cc -1);
  229. dwHash = HashString(sFileName._pwz, HASHTABLE_SIZE, false);
  230. pos = pFileList[dwHash].GetHeadPosition();
  231. while (pos)
  232. {
  233. pwzBuf = pFileList[dwHash].GetNext(pos);
  234. //if equal, attempt to path file
  235. if (!StrCmpI(pwzBuf, sFileName._pwz))
  236. {
  237. sFileName.ReleaseOwnership(&pwzFileName);
  238. pPatchableFiles->AddTail(pwzFileName);
  239. break;
  240. }
  241. }
  242. }
  243. }
  244. if (!FindNextFile(hFind, &fdFile))
  245. {
  246. dwLastError = GetLastError();
  247. break;
  248. }
  249. }
  250. if(dwLastError == ERROR_NO_MORE_FILES)
  251. hr = S_OK;
  252. else
  253. hr = HRESULT_FROM_WIN32(dwLastError);
  254. hr = S_OK;
  255. exit:
  256. return hr;
  257. }
  258. /////////////////////////////////////////////////////////////////////////
  259. // MyProgressCallback
  260. /////////////////////////////////////////////////////////////////////////
  261. BOOL CALLBACK MyProgressCallback(PVOID CallbackContext, ULONG CurrentPosition,
  262. ULONG MaximumPosition)
  263. {
  264. UNREFERENCED_PARAMETER( CallbackContext );
  265. if ( MaximumPosition != 0 )
  266. fprintf(stderr, "\r%6.2f%% complete", ( CurrentPosition * 100.0 ) / MaximumPosition );
  267. return TRUE;
  268. }
  269. /////////////////////////////////////////////////////////////////////////
  270. // ApplyPatchToFiles
  271. /////////////////////////////////////////////////////////////////////////
  272. HRESULT ApplyPatchToFiles (List<LPWSTR> *pPatchableFiles, /* out */ List<LPWSTR> *pPatchedFiles, LPWSTR pwzSourceDir, LPWSTR pwzDestDir, LPWSTR pwzPatchDir)
  273. {
  274. HRESULT hr = S_OK;
  275. LISTNODE pos;
  276. LPWSTR pwzBuf = NULL, pwzDestFile = NULL;
  277. CString sSourceFile, sDestFile, sPatchFile, sRelativeDest, sRelativePatch;
  278. PATCH_OPTION_DATA OptionData = { sizeof( PATCH_OPTION_DATA ) };
  279. PATCH_OPTION_DATA *OptionDataPointer = &OptionData;
  280. BOOL bSuccess = FALSE;
  281. ULONG OldFileCount;
  282. //CreatePatchFileEx allows you to create patchs file which
  283. //can patch from multiple source files. You can have up to
  284. // 256 different source files, hence the arrays with 256 elements.
  285. //FileNameArray has 257 elemnts since the destination file (which
  286. // there can only be one) is stored as the first element and all the
  287. // source files, are stored in the remaining 256 elements.
  288. // BUGBUG - t-peterf to document why 256, 257.
  289. PATCH_OLD_FILE_INFO_W OldFileInfo[ 256 ];
  290. LPWSTR FileNameArray[ 257 ];
  291. LPSTR OldFileSymPathArray[256];
  292. LPSTR NewFileSymPath = new CHAR[MAX_PATH];
  293. ULONG OptionFlags = PATCH_OPTION_USE_LZX_BEST |
  294. PATCH_OPTION_USE_LZX_LARGE |
  295. PATCH_OPTION_FAIL_IF_SAME_FILE |
  296. PATCH_OPTION_FAIL_IF_BIGGER |
  297. PATCH_OPTION_INTERLEAVE_FILES;
  298. //Step through list of patchable files
  299. pos = pPatchableFiles->GetHeadPosition();
  300. while (pos)
  301. {
  302. pwzBuf = pPatchableFiles->GetNext(pos);
  303. //Set up source file path
  304. sSourceFile.Assign(pwzSourceDir);
  305. sSourceFile.Append(pwzBuf);
  306. //Set up dest file path
  307. sDestFile.Assign(pwzDestDir);
  308. sDestFile.Append(pwzBuf);
  309. //set up patchfile path
  310. sPatchFile.Assign(pwzPatchDir);
  311. sPatchFile.Append(pwzBuf);
  312. sPatchFile.Append(L"._p");
  313. CreateDirectoryHierarchy(sPatchFile._pwz, NULL);
  314. //Set up Patching Information
  315. OldFileCount = 1;
  316. OldFileInfo[0].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO);
  317. OldFileInfo[0].OldFileName = sSourceFile._pwz;
  318. OldFileInfo[0].IgnoreRangeArray = NULL;
  319. OldFileInfo[0].IgnoreRangeCount = NULL;
  320. OldFileInfo[0].RetainRangeArray = NULL;
  321. OldFileInfo[0].RetainRangeCount = NULL;
  322. OldFileSymPathArray[0] = new CHAR[MAX_PATH];
  323. WideCharToMultiByte(CP_ACP, 0, pwzSourceDir, lstrlen(pwzSourceDir), OldFileSymPathArray[0], MAX_PATH, NULL, NULL);
  324. WideCharToMultiByte(CP_ACP, 0, pwzDestDir, lstrlen(pwzDestDir), NewFileSymPath, MAX_PATH, NULL, NULL);
  325. OptionData.SizeOfThisStruct = NULL;
  326. OptionData.SymLoadCallback = NULL;
  327. OptionData.SymLoadContext = FileNameArray;
  328. OptionData.ExtendedOptionFlags = NULL;
  329. OptionData.InterleaveMapArray = NULL;
  330. OptionData.MaxLzxWindowSize = NULL;
  331. OptionData.SymbolOptionFlags = NULL;
  332. OptionData.NewFileSymbolPath = (LPCSTR)NewFileSymPath;
  333. OptionData.OldFileSymbolPathArray = (LPCSTR *)OldFileSymPathArray;
  334. FileNameArray[0] = WSTRDupDynamic(sDestFile._pwz);
  335. FileNameArray[1] = WSTRDupDynamic(sSourceFile._pwz);
  336. //Applypatch
  337. bSuccess = CreatePatchFileEx(
  338. OldFileCount,
  339. OldFileInfo,
  340. sDestFile._pwz,
  341. sPatchFile._pwz,
  342. OptionFlags,
  343. OptionDataPointer,
  344. MyProgressCallback,
  345. NULL
  346. );
  347. sRelativeDest.Assign(sDestFile._pwz + g_sDestBase._cc-1);
  348. sRelativePatch.Assign(sPatchFile._pwz + g_sDestBase._cc-1);
  349. if(bSuccess)
  350. {
  351. fprintf(stderr, "\r%ws has been patched successfully to %ws\n", sRelativeDest._pwz, sRelativePatch._pwz);
  352. sDestFile.ReleaseOwnership(&pwzDestFile);
  353. pPatchedFiles->AddTail(pwzDestFile);
  354. }
  355. else
  356. fprintf(stderr, "\rCould/would not patch %ws. Not adding file to patch manifest\n",sRelativeDest._pwz);
  357. }
  358. SAFEDELETEARRAY(NewFileSymPath);
  359. return hr;
  360. }
  361. /////////////////////////////////////////////////////////////////////////
  362. // CheckForDuplicate
  363. /////////////////////////////////////////////////////////////////////////
  364. HRESULT CheckForDuplicate(LPWSTR pwzSourceManifestPath, LPWSTR pwzDestManifestPath)
  365. {
  366. HRESULT hr = S_OK;
  367. IXMLDOMDocument2 *pXMLDoc = NULL;
  368. IXMLDOMNode *pNode = NULL;
  369. IAssemblyManifestImport *pSourceManImport = NULL;
  370. IAssemblyIdentity *pSourceAssemblyId = NULL;
  371. CString sSearchString, sBuffer;
  372. BSTR bstrSearchString = NULL;
  373. LPWSTR pwzBuf=NULL;
  374. DWORD ccBuf=0;
  375. LPWSTR rpwzAttrNames[6] =
  376. {
  377. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PROCESSOR_ARCHITECTURE,
  378. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
  379. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN,
  380. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION,
  381. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_LANGUAGE,
  382. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_TYPE,
  383. };
  384. if(FAILED(hr = LoadXMLDocument(pwzDestManifestPath, &pXMLDoc)))
  385. goto exit;
  386. if(FAILED(hr = CreateAssemblyManifestImport(&pSourceManImport, pwzSourceManifestPath, NULL, 0)))
  387. goto exit;
  388. if(FAILED(hr = pSourceManImport->GetAssemblyIdentity(&pSourceAssemblyId)))
  389. goto exit;
  390. //set up search string
  391. sSearchString.Assign(L"/assembly/Patch/SourceAssembly/assemblyIdentity[");
  392. for (int i = 0; i < 6; i++)
  393. {
  394. if (i)
  395. sSearchString.Append(L" and ");
  396. sSearchString.Append(L"@");
  397. sSearchString.Append(rpwzAttrNames[i]);
  398. sSearchString.Append(L"=\"");
  399. if (FAILED(hr = pSourceAssemblyId->GetAttribute(rpwzAttrNames[i], &pwzBuf, &ccBuf)))
  400. goto exit;
  401. sBuffer.TakeOwnership(pwzBuf, ccBuf);
  402. sSearchString.Append(sBuffer);
  403. sSearchString.Append(L"\"");
  404. }
  405. sSearchString.Append(L"]");
  406. bstrSearchString = ::SysAllocString(sSearchString._pwz);
  407. if (!bstrSearchString)
  408. {
  409. hr = E_OUTOFMEMORY;
  410. goto exit;
  411. }
  412. //if source assembly already exists, exit and do nothing
  413. if (FAILED(hr = pXMLDoc->selectSingleNode(bstrSearchString, &pNode)))
  414. goto exit;
  415. else if (hr == S_OK)
  416. {
  417. fprintf(stderr, "Duplicate Source Assembly! Not adding to manfiest\n");
  418. hr = S_FALSE;
  419. goto exit;
  420. }
  421. else if (hr == S_FALSE)
  422. {
  423. hr = S_OK;
  424. goto exit;
  425. }
  426. exit:
  427. if(bstrSearchString)
  428. ::SysFreeString(bstrSearchString);
  429. SAFERELEASE(pXMLDoc);
  430. SAFERELEASE(pNode);
  431. SAFERELEASE(pSourceAssemblyId);
  432. SAFERELEASE(pSourceManImport);
  433. return hr;
  434. }
  435. /////////////////////////////////////////////////////////////////////////
  436. // Usage
  437. /////////////////////////////////////////////////////////////////////////
  438. HRESULT GetPatchDirectory(LPWSTR pwzSourceManifestPath, LPWSTR *ppwzPatchDir)
  439. {
  440. HRESULT hr = S_OK;
  441. IAssemblyManifestImport *pSourceManImport = NULL;
  442. IAssemblyIdentity *pSourceAssemblyId = NULL;
  443. LPWSTR pwzBuf=NULL;
  444. DWORD ccBuf =0;
  445. CString sBuffer, sPatchDir;
  446. if(FAILED(hr = CreateAssemblyManifestImport(&pSourceManImport, pwzSourceManifestPath, NULL, 0)))
  447. goto exit;
  448. if(FAILED(hr = pSourceManImport->GetAssemblyIdentity(&pSourceAssemblyId)))
  449. goto exit;
  450. if (FAILED(hr = pSourceAssemblyId->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &ccBuf)))
  451. goto exit;
  452. sBuffer.TakeOwnership(pwzBuf, ccBuf);
  453. sPatchDir.Assign(g_sDestBase);
  454. sPatchDir.Append(L"__patch__\\");
  455. sPatchDir.Append(pwzBuf);
  456. sPatchDir.Append(L"\\");
  457. sPatchDir.ReleaseOwnership(ppwzPatchDir);
  458. exit:
  459. return hr;
  460. }
  461. /////////////////////////////////////////////////////////////////////////
  462. // Usage
  463. /////////////////////////////////////////////////////////////////////////
  464. HRESULT Usage()
  465. {
  466. printf("Usage: \n"
  467. "pg [source manifest path] [dest manifest path]:\n"
  468. "\t[source manifest path] = path of the Application for which you want to generate a manifest for\n"
  469. "\t[dest manifest path] = path of the Application for which you want to generate a manifest for\n");
  470. return S_OK;
  471. }
  472. /////////////////////////////////////////////////////////////////////////
  473. // wmain
  474. /////////////////////////////////////////////////////////////////////////
  475. int __cdecl wmain(int argc, WCHAR **argv)
  476. {
  477. HRESULT hr = S_OK;
  478. LPWSTR pwzSourceManifest=NULL, pwzDestManifest=NULL;
  479. List <LPWSTR> pFileList[HASHTABLE_SIZE], PatchableFiles, PatchedFiles;
  480. BOOL bCoInitialized = FALSE;
  481. CString sPatchDir;
  482. LPWSTR pwzBuf=NULL;
  483. hr = CoInitialize(NULL);
  484. if (FAILED(hr))
  485. {
  486. goto exit;
  487. }
  488. bCoInitialized = TRUE;
  489. if (!StrCmp(argv[1], L"-?") || !(argc == 3))
  490. {
  491. hr = Usage();
  492. goto exit;
  493. }
  494. if (FAILED(hr = PathNormalize(argv[1], &pwzSourceManifest, FILE_PATH, FALSE)))
  495. {
  496. hr = Usage();
  497. goto exit;
  498. }
  499. if (FAILED(hr = PathNormalize(argv[2], &pwzDestManifest, FILE_PATH, FALSE)))
  500. {
  501. hr = Usage();
  502. goto exit;
  503. }
  504. g_sSourceManifest.Assign(pwzSourceManifest);
  505. g_sSourceBase.Assign(g_sSourceManifest);
  506. g_sSourceBase.RemoveLastElement();
  507. g_sSourceBase.Append(L"\\");
  508. g_sDestBase.Assign(pwzDestManifest);
  509. g_sDestBase.RemoveLastElement();
  510. g_sDestBase.Append(L"\\");
  511. //Bugbug, could run into naming conflicts with the patch dir
  512. sPatchDir.Assign(g_sDestBase);
  513. sPatchDir.Append(L"__patch__\\");
  514. if(FAILED(hr = IsValidManifestImport(pwzSourceManifest)))
  515. {
  516. fprintf(stderr, "%ws is not a valid application manifest\n", pwzSourceManifest);
  517. goto exit;
  518. }
  519. if(FAILED(hr = IsValidManifestImport(pwzDestManifest)))
  520. {
  521. fprintf(stderr, "%ws is not a valid application manifest\n", pwzDestManifest);
  522. goto exit;
  523. }
  524. if((hr = CheckForDuplicate(pwzSourceManifest, pwzDestManifest)) != S_OK)
  525. goto exit;
  526. if(FAILED(hr = GetPatchDirectory(g_sSourceManifest._pwz, &pwzBuf)))
  527. goto exit;
  528. sPatchDir.TakeOwnership(pwzBuf);
  529. if(FAILED(hr = FindAllFiles(g_sSourceBase._pwz, pFileList)))
  530. goto exit;
  531. if(FAILED(hr = CrossReferenceFiles(g_sDestBase._pwz, pFileList, &PatchableFiles)))
  532. goto exit;
  533. if(FAILED(hr = ApplyPatchToFiles(&PatchableFiles, &PatchedFiles, g_sSourceBase._pwz, g_sDestBase._pwz, sPatchDir._pwz)))
  534. goto exit;
  535. if(FAILED(hr = CreatePatchManifest(&PatchedFiles, sPatchDir._pwz, pwzSourceManifest, pwzDestManifest)))
  536. goto exit;
  537. exit:
  538. SAFEDELETEARRAY(pwzSourceManifest);
  539. SAFEDELETEARRAY(pwzDestManifest);
  540. if (bCoInitialized)
  541. CoUninitialize();
  542. if (FAILED(hr))
  543. fprintf(stderr, "\nFailed with code 0x%x", hr);
  544. return 0;
  545. }