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.

3802 lines
135 KiB

  1. #include <precomp.h>
  2. //
  3. // patchapi.c
  4. //
  5. // Implementation of PatchAPI for creating and applying patches to files.
  6. //
  7. // Author: Tom McGuire (tommcg) 2/97 - 9/97
  8. //
  9. // Copyright (C) Microsoft, 1997-1999.
  10. //
  11. // MICROSOFT CONFIDENTIAL
  12. //
  13. typedef struct _PATCH_DATA {
  14. PVOID PatchData;
  15. ULONG PatchSize;
  16. } PATCH_DATA, *PPATCH_DATA;
  17. //
  18. // If we're building a DLL, and it's not the applyer-only DLL, we need to
  19. // hook DLL_PROCESS_DETACH so we can unload imagehlp.dll if we dynamically
  20. // load it. We only need imagehlp.dll if we're creating patches.
  21. //
  22. #ifdef BUILDING_PATCHAPI_DLL
  23. #ifndef PATCH_APPLY_CODE_ONLY
  24. BOOL
  25. WINAPI
  26. DllEntryPoint(
  27. HANDLE hDll,
  28. DWORD Reason,
  29. PVOID Reserved // NULL for dynamic unload, non-NULL for terminating
  30. )
  31. {
  32. if ( Reason == DLL_PROCESS_ATTACH ) {
  33. DisableThreadLibraryCalls( hDll );
  34. InitImagehlpCritSect();
  35. }
  36. else if (( Reason == DLL_PROCESS_DETACH ) && ( ! Reserved )) {
  37. UnloadImagehlp();
  38. }
  39. return TRUE;
  40. }
  41. #endif // ! PATCH_APPLY_CODE_ONLY
  42. #endif // BUILDING_PATCHAPI_DLL
  43. BOOL
  44. ProgressCallbackWrapper(
  45. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  46. IN PVOID CallbackContext,
  47. IN ULONG CurrentPosition,
  48. IN ULONG MaximumPosition
  49. )
  50. {
  51. BOOL Success = TRUE;
  52. if ( ProgressCallback != NULL ) {
  53. __try {
  54. Success = ProgressCallback(
  55. CallbackContext,
  56. CurrentPosition,
  57. MaximumPosition
  58. );
  59. if (( ! Success ) && ( GetLastError() == ERROR_SUCCESS )) {
  60. SetLastError( ERROR_CANCELLED );
  61. }
  62. }
  63. __except( EXCEPTION_EXECUTE_HANDLER ) {
  64. SetLastError( ERROR_CANCELLED );
  65. Success = FALSE;
  66. }
  67. }
  68. return Success;
  69. }
  70. BOOL
  71. WINAPIV
  72. NormalizeOldFileImageForPatching(
  73. IN PVOID FileMappedImage,
  74. IN ULONG FileSize,
  75. IN ULONG OptionFlags,
  76. IN PVOID OptionData,
  77. IN ULONG NewFileCoffBase,
  78. IN ULONG NewFileCoffTime,
  79. IN ULONG IgnoreRangeCount,
  80. IN PPATCH_IGNORE_RANGE IgnoreRangeArray,
  81. IN ULONG RetainRangeCount,
  82. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  83. ...
  84. )
  85. {
  86. UP_IMAGE_NT_HEADERS32 NtHeader;
  87. PUCHAR MappedFile;
  88. BOOL Modified;
  89. BOOL Success;
  90. ULONG i;
  91. MappedFile = FileMappedImage;
  92. Modified = FALSE;
  93. Success = TRUE;
  94. __try {
  95. NtHeader = GetNtHeader( MappedFile, FileSize );
  96. if ( NtHeader ) {
  97. //
  98. // This is a coff image.
  99. //
  100. Modified = NormalizeCoffImage(
  101. NtHeader,
  102. MappedFile,
  103. FileSize,
  104. OptionFlags,
  105. OptionData,
  106. NewFileCoffBase,
  107. NewFileCoffTime
  108. );
  109. }
  110. else {
  111. //
  112. // Other file type normalizations could be performed here.
  113. //
  114. }
  115. #ifdef TESTCODE
  116. //
  117. // The following test-only code creates a file containing
  118. // the modified coff image to verify that the coff image
  119. // is really a valid coff image. This is for debugging
  120. // only.
  121. //
  122. if ( Modified ) {
  123. HANDLE hFile = CreateFile(
  124. "Normalized.out",
  125. GENERIC_WRITE,
  126. FILE_SHARE_READ,
  127. NULL,
  128. CREATE_ALWAYS,
  129. FILE_ATTRIBUTE_NORMAL,
  130. NULL
  131. );
  132. if ( hFile != INVALID_HANDLE_VALUE ) {
  133. DWORD Actual;
  134. WriteFile( hFile, MappedFile, FileSize, &Actual, NULL );
  135. CloseHandle( hFile );
  136. }
  137. }
  138. #endif // TESTCODE
  139. for ( i = 0; i < IgnoreRangeCount; i++ ) {
  140. if (( IgnoreRangeArray[ i ].OffsetInOldFile + IgnoreRangeArray[ i ].LengthInBytes ) <= FileSize ) {
  141. ZeroMemory( MappedFile + IgnoreRangeArray[ i ].OffsetInOldFile, IgnoreRangeArray[ i ].LengthInBytes );
  142. }
  143. }
  144. for ( i = 0; i < RetainRangeCount; i++ ) {
  145. if (( RetainRangeArray[ i ].OffsetInOldFile + RetainRangeArray[ i ].LengthInBytes ) <= FileSize ) {
  146. ZeroMemory( MappedFile + RetainRangeArray[ i ].OffsetInOldFile, RetainRangeArray[ i ].LengthInBytes );
  147. }
  148. }
  149. }
  150. __except( EXCEPTION_EXECUTE_HANDLER ) {
  151. SetLastError( GetExceptionCode() );
  152. Success = FALSE;
  153. }
  154. return Success;
  155. }
  156. BOOL
  157. PATCHAPI
  158. GetFilePatchSignatureA(
  159. IN LPCSTR FileName,
  160. IN ULONG OptionFlags,
  161. IN PVOID OptionData,
  162. IN ULONG IgnoreRangeCount,
  163. IN PPATCH_IGNORE_RANGE IgnoreRangeArray,
  164. IN ULONG RetainRangeCount,
  165. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  166. IN ULONG SignatureBufferSize,
  167. OUT PVOID SignatureBuffer
  168. )
  169. {
  170. BOOL Success = FALSE;
  171. HANDLE FileHandle;
  172. FileHandle = CreateFileA(
  173. FileName,
  174. GENERIC_READ,
  175. FILE_SHARE_READ | FILE_SHARE_WRITE,
  176. NULL,
  177. OPEN_EXISTING,
  178. FILE_FLAG_SEQUENTIAL_SCAN,
  179. NULL
  180. );
  181. if ( FileHandle != INVALID_HANDLE_VALUE ) {
  182. Success = GetFilePatchSignatureByHandle(
  183. FileHandle,
  184. OptionFlags,
  185. OptionData,
  186. IgnoreRangeCount,
  187. IgnoreRangeArray,
  188. RetainRangeCount,
  189. RetainRangeArray,
  190. SignatureBufferSize,
  191. SignatureBuffer
  192. );
  193. CloseHandle( FileHandle );
  194. }
  195. return Success;
  196. }
  197. BOOL
  198. PATCHAPI
  199. GetFilePatchSignatureW(
  200. IN LPCWSTR FileName,
  201. IN ULONG OptionFlags,
  202. IN PVOID OptionData,
  203. IN ULONG IgnoreRangeCount,
  204. IN PPATCH_IGNORE_RANGE IgnoreRangeArray,
  205. IN ULONG RetainRangeCount,
  206. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  207. IN ULONG SignatureBufferSizeInBytes,
  208. OUT PVOID SignatureBuffer
  209. )
  210. {
  211. CHAR AnsiSignatureBuffer[ 40 ]; // big enough for hex MD5 (33 bytes)
  212. HANDLE FileHandle;
  213. INT Converted;
  214. BOOL Success = FALSE;
  215. FileHandle = CreateFileW(
  216. FileName,
  217. GENERIC_READ,
  218. FILE_SHARE_READ | FILE_SHARE_WRITE,
  219. NULL,
  220. OPEN_EXISTING,
  221. FILE_FLAG_SEQUENTIAL_SCAN,
  222. NULL
  223. );
  224. if ( FileHandle != INVALID_HANDLE_VALUE ) {
  225. Success = GetFilePatchSignatureByHandle(
  226. FileHandle,
  227. OptionFlags,
  228. OptionData,
  229. IgnoreRangeCount,
  230. IgnoreRangeArray,
  231. RetainRangeCount,
  232. RetainRangeArray,
  233. sizeof( AnsiSignatureBuffer ),
  234. AnsiSignatureBuffer
  235. );
  236. if ( Success ) {
  237. //
  238. // Worst case growth from ANSI to UNICODE is 2X.
  239. //
  240. if (( SignatureBufferSizeInBytes / 2 ) < ( strlen( AnsiSignatureBuffer ) + 1 )) {
  241. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  242. Success = FALSE;
  243. }
  244. else {
  245. Converted = MultiByteToWideChar(
  246. CP_ACP,
  247. MB_PRECOMPOSED,
  248. AnsiSignatureBuffer,
  249. -1,
  250. SignatureBuffer,
  251. SignatureBufferSizeInBytes / 2
  252. );
  253. Success = Converted ? TRUE : FALSE;
  254. }
  255. }
  256. CloseHandle( FileHandle );
  257. }
  258. return Success;
  259. }
  260. BOOL
  261. PATCHAPI
  262. GetFilePatchSignatureByHandle(
  263. IN HANDLE FileHandle,
  264. IN ULONG OptionFlags,
  265. IN PVOID OptionData,
  266. IN ULONG IgnoreRangeCount,
  267. IN PPATCH_IGNORE_RANGE IgnoreRangeArray,
  268. IN ULONG RetainRangeCount,
  269. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  270. IN ULONG SignatureBufferSize,
  271. OUT PVOID SignatureBuffer
  272. )
  273. {
  274. PVOID FileMapped;
  275. ULONG FileSize;
  276. ULONG FileCrc;
  277. MD5_HASH FileMD5;
  278. BOOL Success;
  279. Success = MyMapViewOfFileByHandle(
  280. FileHandle,
  281. &FileSize,
  282. &FileMapped
  283. );
  284. if ( Success ) {
  285. //
  286. // Note that we must normalize to a fixed known rebase address,
  287. // so the CRC from this might be different than the OldFileCrc
  288. // in a patch header that is specific to a new file's rebase
  289. // address. Note that if PATCH_OPTION_NO_REBASE is specified
  290. // then the rebase address is ignored.
  291. //
  292. Success = NormalizeOldFileImageForPatching(
  293. FileMapped,
  294. FileSize,
  295. OptionFlags,
  296. OptionData,
  297. 0x10000000, // non-zero fixed coff base
  298. 0x10000000, // non-zero fixed coff time
  299. IgnoreRangeCount,
  300. IgnoreRangeArray,
  301. RetainRangeCount,
  302. RetainRangeArray
  303. );
  304. if ( Success ) {
  305. if ( OptionFlags & PATCH_OPTION_SIGNATURE_MD5 ) {
  306. Success = SafeCompleteMD5(
  307. FileMapped,
  308. FileSize,
  309. &FileMD5
  310. );
  311. if ( Success ) {
  312. if ( SignatureBufferSize < 33 ) {
  313. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  314. Success = FALSE;
  315. }
  316. else {
  317. HashToHexString( &FileMD5, ((LPSTR) SignatureBuffer ));
  318. }
  319. }
  320. }
  321. else { // signature type is CRC-32
  322. Success = SafeCompleteCrc32(
  323. FileMapped,
  324. FileSize,
  325. &FileCrc
  326. );
  327. if ( Success ) {
  328. if ( SignatureBufferSize < 9 ) {
  329. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  330. Success = FALSE;
  331. }
  332. else {
  333. DwordToHexString( FileCrc, (LPSTR) SignatureBuffer );
  334. }
  335. }
  336. }
  337. }
  338. UnmapViewOfFile( FileMapped );
  339. }
  340. if (( ! Success ) &&
  341. ( GetLastError() == ERROR_SUCCESS )) {
  342. SetLastError( ERROR_EXTENDED_ERROR );
  343. }
  344. return Success;
  345. }
  346. #ifndef PATCH_APPLY_CODE_ONLY
  347. VOID
  348. ReduceRiftTable(
  349. IN PRIFT_TABLE RiftTable
  350. )
  351. {
  352. PRIFT_ENTRY RiftEntryArray = RiftTable->RiftEntryArray;
  353. PUCHAR RiftUsageArray = RiftTable->RiftUsageArray;
  354. ULONG RiftEntryCount = RiftTable->RiftEntryCount;
  355. LONG CurrentDisplacement;
  356. LONG ThisDisplacement;
  357. ULONG i;
  358. //
  359. // Essentially we want to remove the usage count from any entry where
  360. // the preceding USED entry would produce the same rift displacement.
  361. //
  362. // The first used entry should contain a non-zero displacement (any
  363. // USED entries before that should be marked UNUSED because they will
  364. // coast from zero).
  365. //
  366. CurrentDisplacement = 0;
  367. for ( i = 0; i < RiftEntryCount; i++ ) {
  368. if ( RiftUsageArray[ i ] != 0 ) {
  369. ThisDisplacement = RiftEntryArray[ i ].NewFileRva - RiftEntryArray[ i ].OldFileRva;
  370. if ( ThisDisplacement == CurrentDisplacement ) {
  371. RiftUsageArray[ i ] = 0; // not needed
  372. }
  373. else {
  374. CurrentDisplacement = ThisDisplacement;
  375. }
  376. }
  377. }
  378. }
  379. #endif // PATCH_APPLY_CODE_ONLY
  380. BOOL
  381. WINAPIV
  382. TransformOldFileImageForPatching(
  383. IN ULONG TransformOptions,
  384. IN PVOID OldFileMapped,
  385. IN ULONG OldFileSize,
  386. IN ULONG NewFileResTime,
  387. IN PRIFT_TABLE RiftTable,
  388. ...
  389. )
  390. {
  391. UP_IMAGE_NT_HEADERS32 NtHeader;
  392. BOOL Success = TRUE;
  393. __try {
  394. NtHeader = GetNtHeader( OldFileMapped, OldFileSize );
  395. if ( NtHeader ) {
  396. Success = TransformCoffImage(
  397. TransformOptions,
  398. NtHeader,
  399. OldFileMapped,
  400. OldFileSize,
  401. NewFileResTime,
  402. RiftTable,
  403. NULL
  404. );
  405. }
  406. else {
  407. //
  408. // Other file type transformations could be performed here.
  409. //
  410. }
  411. #ifndef PATCH_APPLY_CODE_ONLY
  412. if ( RiftTable->RiftUsageArray != NULL ) {
  413. ReduceRiftTable( RiftTable );
  414. }
  415. #endif // PATCH_APPLY_CODE_ONLY
  416. }
  417. __except( EXCEPTION_EXECUTE_HANDLER ) {
  418. SetLastError( GetExceptionCode() );
  419. Success = FALSE;
  420. }
  421. #ifdef TESTCODE
  422. //
  423. // The following test-only code creates a file containing
  424. // the modified coff image to verify that the coff image
  425. // is really a valid coff image. This is for debugging
  426. // only.
  427. //
  428. if ( Success ) {
  429. HANDLE hFile = CreateFile(
  430. "Transformed.out",
  431. GENERIC_WRITE,
  432. FILE_SHARE_READ,
  433. NULL,
  434. CREATE_ALWAYS,
  435. FILE_ATTRIBUTE_NORMAL,
  436. NULL
  437. );
  438. if ( hFile != INVALID_HANDLE_VALUE ) {
  439. DWORD Actual;
  440. WriteFile( hFile, OldFileMapped, OldFileSize, &Actual, NULL );
  441. CloseHandle( hFile );
  442. }
  443. }
  444. #endif // TESTCODE
  445. return Success;
  446. }
  447. PUCHAR
  448. __fastcall
  449. VariableLengthUnsignedDecode(
  450. IN PUCHAR Buffer,
  451. OUT PULONG ReturnValue
  452. )
  453. {
  454. PUCHAR p = Buffer;
  455. ULONG Value = 0;
  456. ULONG Shift = 0;
  457. do {
  458. Value |= (( *p & 0x7F ) << Shift );
  459. Shift += 7;
  460. }
  461. while (( ! ( *p++ & 0x80 )) && ( Shift < 32 ));
  462. *ReturnValue = Value;
  463. return p;
  464. }
  465. PUCHAR
  466. __fastcall
  467. VariableLengthSignedDecode(
  468. IN PUCHAR Buffer,
  469. OUT PLONG ReturnValue
  470. )
  471. {
  472. PUCHAR p = Buffer;
  473. ULONG Shift;
  474. LONG Value;
  475. Value = *p & 0x3F;
  476. Shift = 6;
  477. if ( ! ( *p++ & 0x80 )) {
  478. do {
  479. Value |= (( *p & 0x7F ) << Shift );
  480. Shift += 7;
  481. }
  482. while (( ! ( *p++ & 0x80 )) && ( Shift < 32 ));
  483. }
  484. if ( *Buffer & 0x40 ) {
  485. Value = -Value;
  486. }
  487. *ReturnValue = Value;
  488. return p;
  489. }
  490. UCHAR
  491. PatchVersion(
  492. IN ULONG PatchSignature
  493. )
  494. {
  495. union {
  496. ULONG Signature;
  497. UCHAR Byte[ 4 ];
  498. } u;
  499. u.Signature = PatchSignature;
  500. if (( u.Byte[ 0 ] == 'P' ) && ( u.Byte[ 1 ] == 'A' ) &&
  501. ( u.Byte[ 2 ] >= '0' ) && ( u.Byte[ 2 ] <= '9' ) &&
  502. ( u.Byte[ 3 ] >= '0' ) && ( u.Byte[ 3 ] <= '9' )) {
  503. return (UCHAR)(( u.Byte[ 2 ] - '0' ) * 10 + ( u.Byte[ 3 ] - '0' ));
  504. }
  505. return 0;
  506. }
  507. BOOL
  508. DecodePatchHeader(
  509. IN PVOID PatchHeader,
  510. IN ULONG PatchHeaderMaxSize,
  511. IN HANDLE SubAllocator,
  512. OUT PULONG PatchHeaderActualSize,
  513. OUT PPATCH_HEADER_INFO *HeaderInfo
  514. )
  515. {
  516. PHEADER_OLD_FILE_INFO OldFileInfo;
  517. PPATCH_HEADER_INFO Header;
  518. ULONG i, j;
  519. LONG Delta;
  520. LONG DeltaNew;
  521. ULONG DeltaPos;
  522. ULONG Length;
  523. ULONG PreviousOffset;
  524. ULONG PreviousOldRva;
  525. ULONG PreviousNewRva;
  526. BOOL Success;
  527. PUCHAR p;
  528. //
  529. // A couple of implementation notes here. The PatchHeaderMaxSize
  530. // value does NOT guarantee that we won't try to read beyond that
  531. // memory address in this routine. This routine should be called
  532. // under try/except to trap the case where we walk off the end of
  533. // a corrupt patch header. The PatchHeaderMaxSize is just a helper
  534. // value that lets us know if we did have a corrupt header in the
  535. // case where we walked too far but not off the end of the page.
  536. //
  537. Success = FALSE;
  538. p = PatchHeader;
  539. Header = SubAllocate( SubAllocator, sizeof( PATCH_HEADER_INFO ));
  540. //
  541. // SubAllocate provides zeroed memory.
  542. //
  543. if ( Header != NULL ) {
  544. __try {
  545. Header->Signature = *(UNALIGNED ULONG *)( p );
  546. p += sizeof( ULONG );
  547. if ( Header->Signature != PATCH_SIGNATURE ) {
  548. if ( PatchVersion( Header->Signature ) > PatchVersion( PATCH_SIGNATURE )) {
  549. SetLastError( ERROR_PATCH_NEWER_FORMAT );
  550. }
  551. else {
  552. SetLastError( ERROR_PATCH_CORRUPT );
  553. }
  554. __leave;
  555. }
  556. Header->OptionFlags = *(UNALIGNED ULONG *)( p );
  557. p += sizeof( ULONG );
  558. //
  559. // The PATCH_OPTION_NO_TIMESTAMP flag is stored inverse for
  560. // backward compatibility, so flip it back here.
  561. //
  562. Header->OptionFlags ^= PATCH_OPTION_NO_TIMESTAMP;
  563. //
  564. // Now check for invalid flags.
  565. //
  566. if ( Header->OptionFlags & ~PATCH_OPTION_VALID_FLAGS ) {
  567. SetLastError( ERROR_PATCH_CORRUPT );
  568. __leave;
  569. }
  570. //
  571. // If the PATCH_OPTION_EXTENDED_OPTIONS flag is set, the next
  572. // 4 bytes is the ExtendedOptionFlags value.
  573. //
  574. if ( Header->OptionFlags & PATCH_OPTION_EXTENDED_OPTIONS ) {
  575. Header->ExtendedOptionFlags = *(UNALIGNED ULONG *)( p );
  576. p += sizeof( ULONG );
  577. }
  578. //
  579. // No stored OptionData defined for now.
  580. //
  581. if ( ! ( Header->OptionFlags & PATCH_OPTION_NO_TIMESTAMP )) {
  582. Header->NewFileTime = *(UNALIGNED ULONG *)( p );
  583. p += sizeof( ULONG );
  584. }
  585. if ( ! ( Header->OptionFlags & PATCH_OPTION_NO_REBASE )) {
  586. Header->NewFileCoffBase = ((ULONG)*(UNALIGNED USHORT *)( p )) << 16;
  587. p += sizeof( USHORT );
  588. ASSERT( Header->NewFileCoffBase != 0 );
  589. //
  590. // If NewFileTime is nonzero, CoffTime is stored as a signed
  591. // delta from NewFileTime since they are usually very close.
  592. // If NewFileTime is zero, CoffTime is encoded as a ULONG.
  593. //
  594. if ( Header->NewFileTime != 0 ) {
  595. p = VariableLengthSignedDecode( p, &Delta );
  596. Header->NewFileCoffTime = Header->NewFileTime - Delta;
  597. }
  598. else {
  599. Header->NewFileCoffTime = *(UNALIGNED ULONG *)( p );
  600. p += sizeof( ULONG );
  601. }
  602. }
  603. if ( ! ( Header->OptionFlags & PATCH_OPTION_NO_RESTIMEFIX )) {
  604. //
  605. // If NewFileCoffTime is nonzero, ResTime is stored as a
  606. // signed delta from NewFileCoffTime since they are usually
  607. // very close. If NewFileCoffTime is zero, ResTime is
  608. // encoded as a ULONG.
  609. //
  610. if ( Header->NewFileCoffTime != 0 ) {
  611. p = VariableLengthSignedDecode( p, &Delta );
  612. Header->NewFileResTime = Header->NewFileCoffTime - Delta;
  613. }
  614. else {
  615. Header->NewFileResTime = *(UNALIGNED ULONG *)( p );
  616. p += sizeof( ULONG );
  617. }
  618. }
  619. p = VariableLengthUnsignedDecode( p, &Header->NewFileSize );
  620. Header->NewFileCrc = *(UNALIGNED ULONG *)( p );
  621. p += sizeof( ULONG );
  622. Header->OldFileCount = *p++;
  623. Header->OldFileInfoArray = SubAllocate( SubAllocator, Header->OldFileCount * sizeof( HEADER_OLD_FILE_INFO ));
  624. if ( Header->OldFileInfoArray == NULL ) {
  625. __leave;
  626. }
  627. for ( i = 0; i < Header->OldFileCount; i++ ) {
  628. OldFileInfo = &Header->OldFileInfoArray[ i ];
  629. p = VariableLengthSignedDecode( p, &Delta );
  630. if ((LONG)( Header->NewFileSize + Delta ) < 0 ) {
  631. SetLastError( ERROR_PATCH_CORRUPT );
  632. __leave;
  633. }
  634. OldFileInfo->OldFileSize = Header->NewFileSize + Delta;
  635. OldFileInfo->OldFileCrc = *(UNALIGNED ULONG *)( p );
  636. p += sizeof( ULONG );
  637. OldFileInfo->IgnoreRangeCount = *p++;
  638. if ( OldFileInfo->IgnoreRangeCount != 0 ) {
  639. OldFileInfo->IgnoreRangeArray = SubAllocate( SubAllocator, OldFileInfo->IgnoreRangeCount * sizeof( PATCH_IGNORE_RANGE ));
  640. if ( OldFileInfo->IgnoreRangeArray == NULL ) {
  641. __leave;
  642. }
  643. PreviousOffset = 0;
  644. for ( j = 0; j < OldFileInfo->IgnoreRangeCount; j++ ) {
  645. p = VariableLengthSignedDecode( p, &Delta );
  646. p = VariableLengthUnsignedDecode( p, &Length );
  647. OldFileInfo->IgnoreRangeArray[ j ].OffsetInOldFile = PreviousOffset + Delta;
  648. OldFileInfo->IgnoreRangeArray[ j ].LengthInBytes = Length;
  649. PreviousOffset = PreviousOffset + Delta + Length;
  650. if ( PreviousOffset > OldFileInfo->OldFileSize ) {
  651. SetLastError( ERROR_PATCH_CORRUPT );
  652. __leave;
  653. }
  654. }
  655. }
  656. OldFileInfo->RetainRangeCount = *p++;
  657. if ( OldFileInfo->RetainRangeCount != 0 ) {
  658. OldFileInfo->RetainRangeArray = SubAllocate( SubAllocator, OldFileInfo->RetainRangeCount * sizeof( PATCH_RETAIN_RANGE ));
  659. if ( OldFileInfo->RetainRangeArray == NULL ) {
  660. __leave;
  661. }
  662. PreviousOffset = 0;
  663. for ( j = 0; j < OldFileInfo->RetainRangeCount; j++ ) {
  664. p = VariableLengthSignedDecode( p, &Delta );
  665. p = VariableLengthSignedDecode( p, &DeltaNew );
  666. p = VariableLengthUnsignedDecode( p, &Length );
  667. OldFileInfo->RetainRangeArray[ j ].OffsetInOldFile = PreviousOffset + Delta;
  668. OldFileInfo->RetainRangeArray[ j ].OffsetInNewFile = PreviousOffset + Delta + DeltaNew;
  669. OldFileInfo->RetainRangeArray[ j ].LengthInBytes = Length;
  670. PreviousOffset = PreviousOffset + Delta + Length;
  671. if (( PreviousOffset > OldFileInfo->OldFileSize ) ||
  672. (( PreviousOffset + DeltaNew ) > Header->NewFileSize )) {
  673. SetLastError( ERROR_PATCH_CORRUPT );
  674. __leave;
  675. }
  676. }
  677. }
  678. p = VariableLengthUnsignedDecode( p, &OldFileInfo->RiftTable.RiftEntryCount );
  679. if ( OldFileInfo->RiftTable.RiftEntryCount != 0 ) {
  680. OldFileInfo->RiftTable.RiftEntryArray = SubAllocate( SubAllocator, OldFileInfo->RiftTable.RiftEntryCount * sizeof( RIFT_ENTRY ));
  681. if ( OldFileInfo->RiftTable.RiftEntryArray == NULL ) {
  682. __leave;
  683. }
  684. OldFileInfo->RiftTable.RiftUsageArray = NULL;
  685. PreviousOldRva = 0;
  686. PreviousNewRva = 0;
  687. for ( j = 0; j < OldFileInfo->RiftTable.RiftEntryCount; j++ ) {
  688. p = VariableLengthUnsignedDecode( p, &DeltaPos );
  689. p = VariableLengthSignedDecode( p, &DeltaNew );
  690. OldFileInfo->RiftTable.RiftEntryArray[ j ].OldFileRva = PreviousOldRva + DeltaPos;
  691. OldFileInfo->RiftTable.RiftEntryArray[ j ].NewFileRva = PreviousNewRva + DeltaNew;
  692. PreviousOldRva += DeltaPos;
  693. PreviousNewRva += DeltaNew;
  694. }
  695. }
  696. p = VariableLengthUnsignedDecode( p, &OldFileInfo->PatchDataSize );
  697. }
  698. if ( p > ((PUCHAR)PatchHeader + PatchHeaderMaxSize )) {
  699. SetLastError( ERROR_PATCH_CORRUPT );
  700. __leave;
  701. }
  702. Success = TRUE;
  703. }
  704. __except( EXCEPTION_EXECUTE_HANDLER ) {
  705. SetLastError( ERROR_PATCH_CORRUPT );
  706. Success = FALSE;
  707. }
  708. }
  709. if ( Success ) {
  710. if ( PatchHeaderActualSize ) {
  711. *PatchHeaderActualSize = (ULONG)( p - (PUCHAR)PatchHeader );
  712. }
  713. if ( HeaderInfo ) {
  714. *HeaderInfo = Header;
  715. }
  716. }
  717. return Success;
  718. }
  719. //
  720. // Following group of functions and exported apis are exclusively for
  721. // creating patches. If we're only compiling the apply code, ignore
  722. // this group of functions.
  723. //
  724. #ifndef PATCH_APPLY_CODE_ONLY
  725. PUCHAR
  726. __fastcall
  727. VariableLengthUnsignedEncode(
  728. OUT PUCHAR Buffer,
  729. IN ULONG Value
  730. )
  731. {
  732. UCHAR Byte = (UCHAR)( Value & 0x7F ); // low order 7 bits
  733. Value >>= 7;
  734. while ( Value ) {
  735. *Buffer++ = Byte;
  736. Byte = (UCHAR)( Value & 0x7F ); // next 7 higher order bits
  737. Value >>= 7;
  738. }
  739. *Buffer++ = (UCHAR)( Byte | 0x80 );
  740. return Buffer;
  741. }
  742. PUCHAR
  743. __fastcall
  744. VariableLengthSignedEncode(
  745. OUT PUCHAR Buffer,
  746. IN LONG Value
  747. )
  748. {
  749. UCHAR Byte;
  750. if ( Value < 0 ) {
  751. Value = -Value;
  752. Byte = (UCHAR)(( Value & 0x3F ) | 0x40 );
  753. }
  754. else {
  755. Byte = (UCHAR)( Value & 0x3F );
  756. }
  757. Value >>= 6;
  758. while ( Value ) {
  759. *Buffer++ = Byte;
  760. Byte = (UCHAR)( Value & 0x7F ); // next 7 higher order bits
  761. Value >>= 7;
  762. }
  763. *Buffer++ = (UCHAR)( Byte | 0x80 );
  764. return Buffer;
  765. }
  766. ULONG
  767. EncodePatchHeader(
  768. IN PPATCH_HEADER_INFO HeaderInfo,
  769. OUT PVOID PatchHeaderBuffer
  770. )
  771. {
  772. PHEADER_OLD_FILE_INFO OldFileInfo;
  773. ULONG i, j;
  774. LONG Delta;
  775. ULONG PreviousOffset;
  776. ULONG PreviousOldRva;
  777. ULONG PreviousNewRva;
  778. ULONG ActiveRiftCount;
  779. PUCHAR p = PatchHeaderBuffer;
  780. #ifdef TESTCODE
  781. PUCHAR q;
  782. #endif // TESTCODE
  783. ASSERT( HeaderInfo->Signature == PATCH_SIGNATURE );
  784. ASSERT((( HeaderInfo->OptionFlags & ~PATCH_OPTION_VALID_FLAGS ) == 0 ));
  785. ASSERT((( HeaderInfo->OptionFlags & PATCH_OPTION_EXTENDED_OPTIONS ) != 0 ) == ( HeaderInfo->ExtendedOptionFlags != 0 ));
  786. ASSERT((( HeaderInfo->OptionFlags & PATCH_OPTION_NO_TIMESTAMP ) == 0 ) == ( HeaderInfo->NewFileTime != 0 ));
  787. ASSERT((( HeaderInfo->OptionFlags & PATCH_OPTION_NO_REBASE ) == 0 ) == ( HeaderInfo->NewFileCoffBase != 0 ));
  788. ASSERT((( HeaderInfo->OptionFlags & PATCH_OPTION_NO_REBASE ) == 0 ) == ( HeaderInfo->NewFileCoffTime != 0 ));
  789. ASSERT((( HeaderInfo->OptionFlags & PATCH_OPTION_NO_RESTIMEFIX ) == 0 ) == ( HeaderInfo->NewFileResTime != 0 ));
  790. *(UNALIGNED ULONG *)( p ) = HeaderInfo->Signature;
  791. p += sizeof( ULONG );
  792. //
  793. // The PATCH_OPTION_NO_TIMESTAMP flag is stored inverse for
  794. // backward compatibility, so flip it when storing it here.
  795. //
  796. *(UNALIGNED ULONG *)( p ) = ( HeaderInfo->OptionFlags ^ PATCH_OPTION_NO_TIMESTAMP );
  797. p += sizeof( ULONG );
  798. //
  799. // If the PATCH_OPTION_EXTENDED_OPTIONS flag is set, the next
  800. // 4 bytes is the ExtendedOptionFlags value.
  801. //
  802. if ( HeaderInfo->OptionFlags & PATCH_OPTION_EXTENDED_OPTIONS ) {
  803. *(UNALIGNED ULONG *)( p ) = HeaderInfo->ExtendedOptionFlags;
  804. p += sizeof( ULONG );
  805. }
  806. //
  807. // No stored OptionData defined for now.
  808. //
  809. if ( ! ( HeaderInfo->OptionFlags & PATCH_OPTION_NO_TIMESTAMP )) {
  810. *(UNALIGNED ULONG *)( p ) = HeaderInfo->NewFileTime;
  811. p += sizeof( ULONG );
  812. }
  813. if ( ! ( HeaderInfo->OptionFlags & PATCH_OPTION_NO_REBASE )) {
  814. ASSERT(( HeaderInfo->NewFileCoffBase >> 16 ) != 0 );
  815. *(UNALIGNED USHORT *)( p ) = (USHORT)( HeaderInfo->NewFileCoffBase >> 16 );
  816. p += sizeof( USHORT );
  817. //
  818. // If NewFileTime is nonzero, CoffTime is stored as a signed
  819. // delta from NewFileTime since they are usually very close.
  820. // If NewFileTime is zero, CoffTime is encoded as a ULONG.
  821. //
  822. if ( HeaderInfo->NewFileTime != 0 ) {
  823. Delta = HeaderInfo->NewFileTime - HeaderInfo->NewFileCoffTime;
  824. p = VariableLengthSignedEncode( p, Delta );
  825. }
  826. else {
  827. *(UNALIGNED ULONG *)( p ) = HeaderInfo->NewFileCoffTime;
  828. p += sizeof( ULONG );
  829. }
  830. }
  831. if ( ! ( HeaderInfo->OptionFlags & PATCH_OPTION_NO_RESTIMEFIX )) {
  832. //
  833. // If NewFileCoffTime is nonzero, ResTime is stored as a
  834. // signed delta from NewFileCoffTime since they are usually
  835. // very close. If NewFileCoffTime is zero, ResTime is
  836. // encoded as a ULONG.
  837. //
  838. if ( HeaderInfo->NewFileCoffTime != 0 ) {
  839. Delta = HeaderInfo->NewFileCoffTime - HeaderInfo->NewFileResTime;
  840. p = VariableLengthSignedEncode( p, Delta );
  841. }
  842. else {
  843. *(UNALIGNED ULONG *)( p ) = HeaderInfo->NewFileResTime;
  844. p += sizeof( ULONG );
  845. }
  846. }
  847. p = VariableLengthUnsignedEncode( p, HeaderInfo->NewFileSize );
  848. *(UNALIGNED ULONG *)( p ) = HeaderInfo->NewFileCrc;
  849. p += sizeof( ULONG );
  850. ASSERT( HeaderInfo->OldFileCount < 256 );
  851. *p++ = (UCHAR)( HeaderInfo->OldFileCount );
  852. for ( i = 0; i < HeaderInfo->OldFileCount; i++ ) {
  853. OldFileInfo = &HeaderInfo->OldFileInfoArray[ i ];
  854. Delta = OldFileInfo->OldFileSize - HeaderInfo->NewFileSize;
  855. p = VariableLengthSignedEncode( p, Delta );
  856. *(UNALIGNED ULONG *)( p ) = OldFileInfo->OldFileCrc;
  857. p += sizeof( ULONG );
  858. ASSERT( OldFileInfo->IgnoreRangeCount < 256 );
  859. *p++ = (UCHAR)( OldFileInfo->IgnoreRangeCount );
  860. PreviousOffset = 0;
  861. for ( j = 0; j < OldFileInfo->IgnoreRangeCount; j++ ) {
  862. Delta = OldFileInfo->IgnoreRangeArray[ j ].OffsetInOldFile - PreviousOffset;
  863. PreviousOffset = OldFileInfo->IgnoreRangeArray[ j ].OffsetInOldFile +
  864. OldFileInfo->IgnoreRangeArray[ j ].LengthInBytes;
  865. ASSERT( PreviousOffset <= OldFileInfo->OldFileSize );
  866. p = VariableLengthSignedEncode( p, Delta );
  867. p = VariableLengthUnsignedEncode( p, OldFileInfo->IgnoreRangeArray[ j ].LengthInBytes );
  868. }
  869. ASSERT( OldFileInfo->RetainRangeCount < 256 );
  870. *p++ = (UCHAR)( OldFileInfo->RetainRangeCount );
  871. PreviousOffset = 0;
  872. for ( j = 0; j < OldFileInfo->RetainRangeCount; j++ ) {
  873. Delta = OldFileInfo->RetainRangeArray[ j ].OffsetInOldFile - PreviousOffset;
  874. PreviousOffset = OldFileInfo->RetainRangeArray[ j ].OffsetInOldFile +
  875. OldFileInfo->RetainRangeArray[ j ].LengthInBytes;
  876. ASSERT( PreviousOffset <= OldFileInfo->OldFileSize );
  877. p = VariableLengthSignedEncode( p, Delta );
  878. Delta = OldFileInfo->RetainRangeArray[ j ].OffsetInNewFile -
  879. OldFileInfo->RetainRangeArray[ j ].OffsetInOldFile;
  880. p = VariableLengthSignedEncode( p, Delta );
  881. p = VariableLengthUnsignedEncode( p, OldFileInfo->RetainRangeArray[ j ].LengthInBytes );
  882. }
  883. ActiveRiftCount = 0;
  884. ASSERT(( OldFileInfo->RiftTable.RiftEntryCount == 0 ) || ( OldFileInfo->RiftTable.RiftUsageArray != NULL ));
  885. for ( j = 0; j < OldFileInfo->RiftTable.RiftEntryCount; j++ ) {
  886. if ( OldFileInfo->RiftTable.RiftUsageArray[ j ] ) {
  887. ++ActiveRiftCount;
  888. }
  889. }
  890. #ifdef TESTCODE2
  891. fprintf( stderr, "\n\n" );
  892. #endif // TESTCODE2
  893. #ifdef TESTCODE
  894. q = p;
  895. #endif // TESTCODE
  896. if (( OldFileInfo->RiftTable.RiftEntryCount ) && ( ActiveRiftCount == 0 )) {
  897. //
  898. // This is a special case. We have a rift table but didn't use
  899. // any entries during transformation. This can happen if all the
  900. // rifts coast to zero for extremely similar files. If we encode
  901. // the rift count as zero, no transformations will be performed
  902. // during patch apply. To prevent that, we'll encode one rift of
  903. // 0,0 which is usually just the implied initial rift.
  904. //
  905. ActiveRiftCount = 1;
  906. p = VariableLengthUnsignedEncode( p, ActiveRiftCount );
  907. p = VariableLengthUnsignedEncode( p, 0 );
  908. p = VariableLengthSignedEncode( p, 0 );
  909. }
  910. else {
  911. p = VariableLengthUnsignedEncode( p, ActiveRiftCount );
  912. PreviousOldRva = 0;
  913. PreviousNewRva = 0;
  914. for ( j = 0; j < OldFileInfo->RiftTable.RiftEntryCount; j++ ) {
  915. if ( OldFileInfo->RiftTable.RiftUsageArray[ j ] ) {
  916. #ifdef TESTCODE2
  917. fprintf( stderr, "%9X ", OldFileInfo->RiftTable.RiftEntryArray[ j ].OldFileRva );
  918. fprintf( stderr, "%9X ", OldFileInfo->RiftTable.RiftEntryArray[ j ].NewFileRva );
  919. #endif // TESTCODE2
  920. Delta = OldFileInfo->RiftTable.RiftEntryArray[ j ].OldFileRva - PreviousOldRva;
  921. ASSERT( Delta > 0 ); // sorted by OldFileRva
  922. #ifdef TESTCODE2
  923. fprintf( stderr, "%9d ", Delta );
  924. #endif // TESTCODE2
  925. PreviousOldRva = OldFileInfo->RiftTable.RiftEntryArray[ j ].OldFileRva;
  926. p = VariableLengthUnsignedEncode( p, Delta );
  927. Delta = OldFileInfo->RiftTable.RiftEntryArray[ j ].NewFileRva - PreviousNewRva;
  928. #ifdef TESTCODE2
  929. fprintf( stderr, "%9d\n", Delta );
  930. #endif // TESTCODE2
  931. PreviousNewRva = OldFileInfo->RiftTable.RiftEntryArray[ j ].NewFileRva;
  932. p = VariableLengthSignedEncode( p, Delta );
  933. }
  934. }
  935. }
  936. #ifdef TESTCODE
  937. if ( ActiveRiftCount > 0 ) {
  938. printf( "\r%9d rifts encoded in %d bytes (%.1f bytes per rift)\n", ActiveRiftCount, p - q, ((double)( p - q ) / ActiveRiftCount ));
  939. }
  940. #endif // TESTCODE
  941. p = VariableLengthUnsignedEncode( p, OldFileInfo->PatchDataSize );
  942. }
  943. return (ULONG)( p - (PUCHAR) PatchHeaderBuffer );
  944. }
  945. BOOL
  946. PATCHAPI
  947. CreatePatchFileA(
  948. IN LPCSTR OldFileName,
  949. IN LPCSTR NewFileName,
  950. OUT LPCSTR PatchFileName,
  951. IN ULONG OptionFlags,
  952. IN PPATCH_OPTION_DATA OptionData // optional
  953. )
  954. {
  955. PATCH_OLD_FILE_INFO_A OldFileInfo = {
  956. sizeof( PATCH_OLD_FILE_INFO_A ),
  957. OldFileName,
  958. 0,
  959. NULL,
  960. 0,
  961. NULL
  962. };
  963. return CreatePatchFileExA(
  964. 1,
  965. &OldFileInfo,
  966. NewFileName,
  967. PatchFileName,
  968. OptionFlags,
  969. OptionData,
  970. NULL,
  971. NULL
  972. );
  973. }
  974. BOOL
  975. PATCHAPI
  976. CreatePatchFileW(
  977. IN LPCWSTR OldFileName,
  978. IN LPCWSTR NewFileName,
  979. OUT LPCWSTR PatchFileName,
  980. IN ULONG OptionFlags,
  981. IN PPATCH_OPTION_DATA OptionData // optional
  982. )
  983. {
  984. PATCH_OLD_FILE_INFO_W OldFileInfo = {
  985. sizeof( PATCH_OLD_FILE_INFO_W ),
  986. OldFileName,
  987. 0,
  988. NULL,
  989. 0,
  990. NULL
  991. };
  992. return CreatePatchFileExW(
  993. 1,
  994. &OldFileInfo,
  995. NewFileName,
  996. PatchFileName,
  997. OptionFlags,
  998. OptionData,
  999. NULL,
  1000. NULL
  1001. );
  1002. }
  1003. BOOL
  1004. PATCHAPI
  1005. CreatePatchFileByHandles(
  1006. IN HANDLE OldFileHandle,
  1007. IN HANDLE NewFileHandle,
  1008. OUT HANDLE PatchFileHandle,
  1009. IN ULONG OptionFlags,
  1010. IN PPATCH_OPTION_DATA OptionData // optional
  1011. )
  1012. {
  1013. PATCH_OLD_FILE_INFO_H OldFileInfo = {
  1014. sizeof( PATCH_OLD_FILE_INFO_H ),
  1015. OldFileHandle,
  1016. 0,
  1017. NULL,
  1018. 0,
  1019. NULL
  1020. };
  1021. return CreatePatchFileByHandlesEx(
  1022. 1,
  1023. &OldFileInfo,
  1024. NewFileHandle,
  1025. PatchFileHandle,
  1026. OptionFlags,
  1027. OptionData,
  1028. NULL,
  1029. NULL
  1030. );
  1031. }
  1032. BOOL
  1033. PATCHAPI
  1034. CreatePatchFileExA(
  1035. IN ULONG OldFileCount,
  1036. IN PPATCH_OLD_FILE_INFO_A OldFileInfoArray,
  1037. IN LPCSTR NewFileName,
  1038. OUT LPCSTR PatchFileName,
  1039. IN ULONG OptionFlags,
  1040. IN PPATCH_OPTION_DATA OptionData, // optional
  1041. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  1042. IN PVOID CallbackContext
  1043. )
  1044. {
  1045. PPATCH_OLD_FILE_INFO_H OldFileInfoByHandle = NULL;
  1046. HANDLE PatchFileHandle;
  1047. HANDLE NewFileHandle;
  1048. BOOL Success;
  1049. ULONG i;
  1050. if ( OldFileCount == 0 ) {
  1051. SetLastError( ERROR_INVALID_PARAMETER );
  1052. return FALSE;
  1053. }
  1054. OldFileInfoByHandle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, OldFileCount * sizeof(PATCH_OLD_FILE_INFO_H));
  1055. if (!OldFileInfoByHandle) {
  1056. SetLastError(ERROR_OUTOFMEMORY);
  1057. return FALSE;
  1058. }
  1059. Success = TRUE;
  1060. for ( i = 0; i < OldFileCount; i++ ) {
  1061. OldFileInfoByHandle[ i ].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO_H );
  1062. OldFileInfoByHandle[ i ].IgnoreRangeCount = OldFileInfoArray[ i ].IgnoreRangeCount;
  1063. OldFileInfoByHandle[ i ].IgnoreRangeArray = OldFileInfoArray[ i ].IgnoreRangeArray;
  1064. OldFileInfoByHandle[ i ].RetainRangeCount = OldFileInfoArray[ i ].RetainRangeCount;
  1065. OldFileInfoByHandle[ i ].RetainRangeArray = OldFileInfoArray[ i ].RetainRangeArray;
  1066. OldFileInfoByHandle[ i ].OldFileHandle = CreateFileA(
  1067. OldFileInfoArray[ i ].OldFileName,
  1068. GENERIC_READ,
  1069. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1070. NULL,
  1071. OPEN_EXISTING,
  1072. FILE_FLAG_SEQUENTIAL_SCAN,
  1073. NULL
  1074. );
  1075. if ( OldFileInfoByHandle[ i ].OldFileHandle == INVALID_HANDLE_VALUE ) {
  1076. Success = FALSE;
  1077. break;
  1078. }
  1079. }
  1080. if ( Success ) {
  1081. Success = FALSE;
  1082. NewFileHandle = CreateFileA(
  1083. NewFileName,
  1084. GENERIC_READ,
  1085. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1086. NULL,
  1087. OPEN_EXISTING,
  1088. FILE_FLAG_SEQUENTIAL_SCAN,
  1089. NULL
  1090. );
  1091. if ( NewFileHandle != INVALID_HANDLE_VALUE ) {
  1092. PatchFileHandle = CreateFileA(
  1093. PatchFileName,
  1094. GENERIC_READ | GENERIC_WRITE,
  1095. FILE_SHARE_READ,
  1096. NULL,
  1097. CREATE_ALWAYS,
  1098. FILE_ATTRIBUTE_NORMAL,
  1099. NULL
  1100. );
  1101. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  1102. Success = CreatePatchFileByHandlesEx(
  1103. OldFileCount,
  1104. OldFileInfoByHandle,
  1105. NewFileHandle,
  1106. PatchFileHandle,
  1107. OptionFlags,
  1108. OptionData,
  1109. ProgressCallback,
  1110. CallbackContext
  1111. );
  1112. CloseHandle( PatchFileHandle );
  1113. if ( ! Success ) {
  1114. DeleteFileA( PatchFileName );
  1115. }
  1116. }
  1117. CloseHandle( NewFileHandle );
  1118. }
  1119. }
  1120. for ( i = 0; i < OldFileCount; i++ ) {
  1121. if (( OldFileInfoByHandle[ i ].OldFileHandle != NULL ) &&
  1122. ( OldFileInfoByHandle[ i ].OldFileHandle != INVALID_HANDLE_VALUE )) {
  1123. CloseHandle( OldFileInfoByHandle[ i ].OldFileHandle );
  1124. }
  1125. }
  1126. HeapFree(GetProcessHeap(), 0, OldFileInfoByHandle);
  1127. return Success;
  1128. }
  1129. BOOL
  1130. PATCHAPI
  1131. CreatePatchFileExW(
  1132. IN ULONG OldFileCount,
  1133. IN PPATCH_OLD_FILE_INFO_W OldFileInfoArray,
  1134. IN LPCWSTR NewFileName,
  1135. OUT LPCWSTR PatchFileName,
  1136. IN ULONG OptionFlags,
  1137. IN PPATCH_OPTION_DATA OptionData, // optional
  1138. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  1139. IN PVOID CallbackContext
  1140. )
  1141. {
  1142. PPATCH_OLD_FILE_INFO_H OldFileInfoByHandle = NULL;
  1143. HANDLE PatchFileHandle;
  1144. HANDLE NewFileHandle;
  1145. BOOL Success;
  1146. ULONG i;
  1147. if ( OldFileCount == 0 ) {
  1148. SetLastError( ERROR_INVALID_PARAMETER );
  1149. return FALSE;
  1150. }
  1151. OldFileInfoByHandle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, OldFileCount * sizeof(PATCH_OLD_FILE_INFO_H));
  1152. if (!OldFileInfoByHandle) {
  1153. SetLastError(ERROR_OUTOFMEMORY);
  1154. return FALSE;
  1155. }
  1156. Success = TRUE;
  1157. for ( i = 0; i < OldFileCount; i++ ) {
  1158. OldFileInfoByHandle[ i ].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO_H );
  1159. OldFileInfoByHandle[ i ].IgnoreRangeCount = OldFileInfoArray[ i ].IgnoreRangeCount;
  1160. OldFileInfoByHandle[ i ].IgnoreRangeArray = OldFileInfoArray[ i ].IgnoreRangeArray;
  1161. OldFileInfoByHandle[ i ].RetainRangeCount = OldFileInfoArray[ i ].RetainRangeCount;
  1162. OldFileInfoByHandle[ i ].RetainRangeArray = OldFileInfoArray[ i ].RetainRangeArray;
  1163. OldFileInfoByHandle[ i ].OldFileHandle = CreateFileW(
  1164. OldFileInfoArray[ i ].OldFileName,
  1165. GENERIC_READ,
  1166. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1167. NULL,
  1168. OPEN_EXISTING,
  1169. FILE_FLAG_SEQUENTIAL_SCAN,
  1170. NULL
  1171. );
  1172. if ( OldFileInfoByHandle[ i ].OldFileHandle == INVALID_HANDLE_VALUE ) {
  1173. Success = FALSE;
  1174. break;
  1175. }
  1176. }
  1177. if ( Success ) {
  1178. Success = FALSE;
  1179. NewFileHandle = CreateFileW(
  1180. NewFileName,
  1181. GENERIC_READ,
  1182. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1183. NULL,
  1184. OPEN_EXISTING,
  1185. FILE_FLAG_SEQUENTIAL_SCAN,
  1186. NULL
  1187. );
  1188. if ( NewFileHandle != INVALID_HANDLE_VALUE ) {
  1189. PatchFileHandle = CreateFileW(
  1190. PatchFileName,
  1191. GENERIC_READ | GENERIC_WRITE,
  1192. FILE_SHARE_READ,
  1193. NULL,
  1194. CREATE_ALWAYS,
  1195. FILE_ATTRIBUTE_NORMAL,
  1196. NULL
  1197. );
  1198. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  1199. Success = CreatePatchFileByHandlesEx(
  1200. OldFileCount,
  1201. OldFileInfoByHandle,
  1202. NewFileHandle,
  1203. PatchFileHandle,
  1204. OptionFlags,
  1205. OptionData,
  1206. ProgressCallback,
  1207. CallbackContext
  1208. );
  1209. CloseHandle( PatchFileHandle );
  1210. if ( ! Success ) {
  1211. DeleteFileW( PatchFileName );
  1212. }
  1213. }
  1214. CloseHandle( NewFileHandle );
  1215. }
  1216. }
  1217. for ( i = 0; i < OldFileCount; i++ ) {
  1218. if (( OldFileInfoByHandle[ i ].OldFileHandle != NULL ) &&
  1219. ( OldFileInfoByHandle[ i ].OldFileHandle != INVALID_HANDLE_VALUE )) {
  1220. CloseHandle( OldFileInfoByHandle[ i ].OldFileHandle );
  1221. }
  1222. }
  1223. HeapFree(GetProcessHeap(), 0, OldFileInfoByHandle);
  1224. return Success;
  1225. }
  1226. BOOL
  1227. PATCHAPI
  1228. CreatePatchFileByHandlesEx(
  1229. IN ULONG OldFileCount,
  1230. IN PPATCH_OLD_FILE_INFO_H OldFileInfoArray,
  1231. IN HANDLE NewFileHandle,
  1232. OUT HANDLE PatchFileHandle,
  1233. IN ULONG OptionFlags,
  1234. IN PPATCH_OPTION_DATA OptionData, // optional
  1235. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  1236. IN PVOID CallbackContext
  1237. )
  1238. {
  1239. PATCH_HEADER_INFO HeaderInfo;
  1240. UP_IMAGE_NT_HEADERS32 NtHeader;
  1241. UP_IMAGE_NT_HEADERS32 OldFileNtHeader;
  1242. PPATCH_DATA PatchArray;
  1243. PFILETIME PatchFileTime;
  1244. FILETIME NewFileTime;
  1245. PUCHAR NewFileMapped;
  1246. ULONG NewFileSize;
  1247. ULONG NewFileCrc;
  1248. ULONG NewFileCoffBase;
  1249. ULONG NewFileCoffTime;
  1250. ULONG NewFileResTime;
  1251. ULONG NewFileCompressedSize;
  1252. PUCHAR OldFileMapped;
  1253. ULONG OldFileSize;
  1254. ULONG OldFileCrc;
  1255. PUCHAR PatchFileMapped;
  1256. PUCHAR PatchBuffer;
  1257. ULONG PatchBufferSize;
  1258. PUCHAR PatchAltBuffer;
  1259. ULONG PatchAltSize;
  1260. ULONG PatchDataSize;
  1261. ULONG PatchFileCrc;
  1262. ULONG HeaderSize;
  1263. ULONG HeaderOldFileCount;
  1264. ULONG ProgressPosition;
  1265. ULONG ProgressMaximum;
  1266. ULONG ErrorCode;
  1267. BOOL TryLzxBoth;
  1268. BOOL Success;
  1269. BOOL Transform;
  1270. HANDLE SubAllocatorHandle;
  1271. ULONG EstimatedLzxMemory;
  1272. ULONG ExtendedOptionFlags;
  1273. ULONG AltExtendedOptionFlags;
  1274. ULONG OldFileOriginalChecksum;
  1275. ULONG OldFileOriginalTimeDate;
  1276. ULONG i, j;
  1277. PUCHAR p;
  1278. ULONG LargestOldFileSize = 0;
  1279. if (( OldFileCount == 0 ) || ( OldFileCount > 127 )) {
  1280. SetLastError( ERROR_INVALID_PARAMETER );
  1281. return FALSE;
  1282. }
  1283. if ( OptionFlags & PATCH_OPTION_SIGNATURE_MD5 ) {
  1284. SetLastError( ERROR_INVALID_PARAMETER );
  1285. return FALSE;
  1286. }
  1287. HeaderInfo.OldFileInfoArray = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, OldFileCount * sizeof( HEADER_OLD_FILE_INFO ));
  1288. if (!HeaderInfo.OldFileInfoArray) {
  1289. SetLastError(ERROR_OUTOFMEMORY);
  1290. return FALSE;
  1291. }
  1292. PatchArray = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, OldFileCount * sizeof( PATCH_DATA ));
  1293. if (!PatchArray) {
  1294. HeapFree(GetProcessHeap(), 0, HeaderInfo.OldFileInfoArray);
  1295. SetLastError(ERROR_OUTOFMEMORY);
  1296. return FALSE;
  1297. }
  1298. if (( OptionFlags & 0x0000FFFF ) == PATCH_OPTION_USE_BEST ) {
  1299. OptionFlags |= PATCH_OPTION_USE_LZX_BEST;
  1300. }
  1301. for ( i = 1; i < OldFileCount; i++ ) {
  1302. if ( OldFileInfoArray[ i ].RetainRangeCount != OldFileInfoArray[ 0 ].RetainRangeCount ) {
  1303. HeapFree(GetProcessHeap(), 0, PatchArray);
  1304. HeapFree(GetProcessHeap(), 0, HeaderInfo.OldFileInfoArray);
  1305. SetLastError( ERROR_PATCH_RETAIN_RANGES_DIFFER );
  1306. return FALSE;
  1307. }
  1308. for ( j = 0; j < OldFileInfoArray[ 0 ].RetainRangeCount; j++ ) {
  1309. if (( OldFileInfoArray[ i ].RetainRangeArray[ j ].OffsetInNewFile !=
  1310. OldFileInfoArray[ 0 ].RetainRangeArray[ j ].OffsetInNewFile ) ||
  1311. ( OldFileInfoArray[ i ].RetainRangeArray[ j ].LengthInBytes !=
  1312. OldFileInfoArray[ 0 ].RetainRangeArray[ j ].LengthInBytes )) {
  1313. HeapFree(GetProcessHeap(), 0, PatchArray);
  1314. HeapFree(GetProcessHeap(), 0, HeaderInfo.OldFileInfoArray);
  1315. SetLastError( ERROR_PATCH_RETAIN_RANGES_DIFFER );
  1316. return FALSE;
  1317. }
  1318. }
  1319. }
  1320. ExtendedOptionFlags = 0;
  1321. if (( OptionData ) && ( OptionData->SizeOfThisStruct >= sizeof( PATCH_OPTION_DATA ))) {
  1322. ExtendedOptionFlags = OptionData->ExtendedOptionFlags;
  1323. }
  1324. Success = MyMapViewOfFileByHandle(
  1325. NewFileHandle,
  1326. &NewFileSize,
  1327. &NewFileMapped
  1328. );
  1329. if ( ! Success ) {
  1330. if ( GetLastError() == ERROR_SUCCESS ) {
  1331. SetLastError( ERROR_EXTENDED_ERROR );
  1332. }
  1333. HeapFree(GetProcessHeap(), 0, PatchArray);
  1334. HeapFree(GetProcessHeap(), 0, HeaderInfo.OldFileInfoArray);
  1335. return FALSE;
  1336. }
  1337. GetFileTime( NewFileHandle, NULL, NULL, &NewFileTime );
  1338. PatchFileTime = &NewFileTime;
  1339. NewFileCoffBase = 0;
  1340. NewFileCoffTime = 0;
  1341. NewFileResTime = 0;
  1342. HeaderOldFileCount = 0;
  1343. HeaderSize = 0;
  1344. NewFileCrc = 0; // prevent compiler warning
  1345. ProgressPosition = 0;
  1346. ProgressMaximum = 0; // prevent compiler warning
  1347. __try {
  1348. NtHeader = GetNtHeader( NewFileMapped, NewFileSize );
  1349. if ( ! ( OptionFlags & PATCH_OPTION_NO_REBASE )) {
  1350. if ( NtHeader ) {
  1351. NewFileCoffTime = NtHeader->FileHeader.TimeDateStamp;
  1352. NewFileCoffBase = NtHeader->OptionalHeader.ImageBase;
  1353. }
  1354. else {
  1355. OptionFlags |= PATCH_OPTION_NO_REBASE;
  1356. }
  1357. }
  1358. if (( NtHeader ) && ( NtHeader->OptionalHeader.CheckSum == 0 )) {
  1359. OptionFlags |= PATCH_OPTION_NO_CHECKSUM;
  1360. }
  1361. if ( ! ( OptionFlags & PATCH_OPTION_NO_RESTIMEFIX )) {
  1362. if ( NtHeader ) {
  1363. UP_IMAGE_RESOURCE_DIRECTORY ResDir;
  1364. ResDir = ImageDirectoryMappedAddress(
  1365. NtHeader,
  1366. IMAGE_DIRECTORY_ENTRY_RESOURCE,
  1367. NULL,
  1368. NewFileMapped,
  1369. NewFileSize
  1370. );
  1371. if ( ResDir ) {
  1372. NewFileResTime = ResDir->TimeDateStamp;
  1373. }
  1374. }
  1375. if ( NewFileResTime == 0 ) {
  1376. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  1377. }
  1378. }
  1379. TryLzxBoth = FALSE;
  1380. if (( OptionFlags & PATCH_OPTION_USE_LZX_BEST ) == PATCH_OPTION_USE_LZX_BEST ) {
  1381. OptionFlags &= ~PATCH_OPTION_USE_LZX_B; // No E8 translation on first try.
  1382. if ((( ! NtHeader ) && ( *(UNALIGNED USHORT *)NewFileMapped == 0x5A4D )) || // MZ, not PE
  1383. (( NtHeader ) && ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ))) { // PE, i386
  1384. TryLzxBoth = TRUE; // Will force E8 translation on second try.
  1385. }
  1386. }
  1387. else if (( OptionFlags & PATCH_OPTION_USE_LZX_BEST ) == PATCH_OPTION_USE_LZX_B ) {
  1388. //
  1389. // Caller is requesting forced E8 translation, so disable E8
  1390. // transformation.
  1391. //
  1392. if (( NtHeader ) && ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 )) { // PE, i386
  1393. ExtendedOptionFlags |= PATCH_TRANSFORM_NO_RELCALLS;
  1394. }
  1395. }
  1396. ProgressMaximum = NewFileSize * OldFileCount;
  1397. for ( i = 0; i < OldFileCount; i++ ) {
  1398. OldFileSize = GetFileSize( OldFileInfoArray[ i ].OldFileHandle, NULL );
  1399. if ( LargestOldFileSize < OldFileSize ) {
  1400. LargestOldFileSize = OldFileSize;
  1401. }
  1402. ProgressMaximum += LzxInsertSize( OldFileSize, OptionFlags );
  1403. }
  1404. if ( TryLzxBoth ) {
  1405. ProgressMaximum *= 2;
  1406. }
  1407. if ( OptionFlags & PATCH_OPTION_FAIL_IF_BIGGER ) {
  1408. ProgressMaximum += NewFileSize;
  1409. }
  1410. Success = ProgressCallbackWrapper(
  1411. ProgressCallback,
  1412. CallbackContext,
  1413. 0,
  1414. ProgressMaximum
  1415. );
  1416. if ( ! Success ) {
  1417. __leave;
  1418. }
  1419. for ( j = 0; j < OldFileInfoArray[ 0 ].RetainRangeCount; j++ ) {
  1420. ZeroMemory(
  1421. OldFileInfoArray[ 0 ].RetainRangeArray[ j ].OffsetInNewFile + NewFileMapped,
  1422. OldFileInfoArray[ 0 ].RetainRangeArray[ j ].LengthInBytes
  1423. );
  1424. }
  1425. NewFileCrc = Crc32( 0xFFFFFFFF, NewFileMapped, NewFileSize ) ^ 0xFFFFFFFF;
  1426. PatchBufferSize = ROUNDUP2( NewFileSize + ( NewFileSize / 256 ), 0x10000 );
  1427. Success = FALSE;
  1428. for ( i = 0; i < OldFileCount; i++ ) {
  1429. Success = MyMapViewOfFileByHandle(
  1430. OldFileInfoArray[ i ].OldFileHandle,
  1431. &OldFileSize,
  1432. &OldFileMapped
  1433. );
  1434. if ( ! Success ) {
  1435. break;
  1436. }
  1437. OldFileOriginalChecksum = 0;
  1438. OldFileOriginalTimeDate = 0;
  1439. OldFileNtHeader = NULL;
  1440. __try {
  1441. OldFileNtHeader = GetNtHeader( OldFileMapped, OldFileSize );
  1442. if ( OldFileNtHeader ) {
  1443. OldFileOriginalChecksum = OldFileNtHeader->OptionalHeader.CheckSum;
  1444. OldFileOriginalTimeDate = OldFileNtHeader->FileHeader.TimeDateStamp;
  1445. }
  1446. }
  1447. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1448. }
  1449. Success = NormalizeOldFileImageForPatching(
  1450. OldFileMapped,
  1451. OldFileSize,
  1452. OptionFlags,
  1453. OptionData,
  1454. NewFileCoffBase,
  1455. NewFileCoffTime,
  1456. OldFileInfoArray[ i ].IgnoreRangeCount,
  1457. OldFileInfoArray[ i ].IgnoreRangeArray,
  1458. OldFileInfoArray[ i ].RetainRangeCount,
  1459. OldFileInfoArray[ i ].RetainRangeArray
  1460. );
  1461. if ( Success ) {
  1462. Success = SafeCompleteCrc32( OldFileMapped, OldFileSize, &OldFileCrc );
  1463. if ( Success ) {
  1464. //
  1465. // First determine if this old file is the same as any already
  1466. // processed old files.
  1467. //
  1468. Success = FALSE;
  1469. for ( j = 0; j < HeaderOldFileCount; j++ ) {
  1470. if (( HeaderInfo.OldFileInfoArray[ j ].OldFileCrc == OldFileCrc ) &&
  1471. ( HeaderInfo.OldFileInfoArray[ j ].OldFileSize == OldFileSize )) {
  1472. //
  1473. // We have to remap the other old file here to make the
  1474. // comparison.
  1475. //
  1476. PUCHAR CompareFileMapped;
  1477. ULONG CompareFileSize;
  1478. Success = MyMapViewOfFileByHandle(
  1479. HeaderInfo.OldFileInfoArray[ j ].OldFileHandle,
  1480. &CompareFileSize,
  1481. &CompareFileMapped
  1482. );
  1483. if ( Success ) {
  1484. ASSERT( CompareFileSize == HeaderInfo.OldFileInfoArray[ j ].OldFileSize );
  1485. NormalizeOldFileImageForPatching(
  1486. CompareFileMapped,
  1487. CompareFileSize,
  1488. OptionFlags,
  1489. OptionData,
  1490. NewFileCoffBase,
  1491. NewFileCoffTime,
  1492. HeaderInfo.OldFileInfoArray[ j ].IgnoreRangeCount,
  1493. HeaderInfo.OldFileInfoArray[ j ].IgnoreRangeArray,
  1494. HeaderInfo.OldFileInfoArray[ j ].RetainRangeCount,
  1495. HeaderInfo.OldFileInfoArray[ j ].RetainRangeArray
  1496. );
  1497. __try {
  1498. Success = ( memcmp( CompareFileMapped, OldFileMapped, OldFileSize ) == 0 );
  1499. }
  1500. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1501. SetLastError( GetExceptionCode() );
  1502. Success = FALSE;
  1503. }
  1504. UnmapViewOfFile( CompareFileMapped );
  1505. if ( Success ) {
  1506. break;
  1507. }
  1508. }
  1509. }
  1510. }
  1511. if ( ! Success ) {
  1512. //
  1513. // Now see if old file is same as new file.
  1514. //
  1515. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryAlloc = 0;
  1516. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount = 0;
  1517. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryArray = NULL;
  1518. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftUsageArray = NULL;
  1519. PatchBuffer = NULL;
  1520. PatchDataSize = 0;
  1521. if (( NewFileCrc == OldFileCrc ) && ( NewFileSize == OldFileSize )) {
  1522. __try {
  1523. Success = ( memcmp( NewFileMapped, OldFileMapped, NewFileSize ) == 0 );
  1524. }
  1525. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1526. SetLastError( GetExceptionCode() );
  1527. Success = FALSE;
  1528. }
  1529. }
  1530. if ( ! Success ) {
  1531. //
  1532. // It's a unique file, so create the patch for it.
  1533. //
  1534. // First we need to apply the transforms.
  1535. //
  1536. Transform = TRUE;
  1537. //
  1538. // NOTE: This test for NtHeader is a perf tweak
  1539. // for non-coff files. If we ever have any
  1540. // transformations for non-coff files, this
  1541. // test should be removed.
  1542. //
  1543. if (( NtHeader ) && ( OldFileNtHeader )) {
  1544. //
  1545. // See if rift table already provided by
  1546. // caller so we don't need to generate it.
  1547. //
  1548. if (( OptionData ) &&
  1549. ( OptionData->SizeOfThisStruct >= sizeof( PATCH_OPTION_DATA )) &&
  1550. ( OptionData->SymbolOptionFlags & PATCH_SYMBOL_EXTERNAL_RIFT ) &&
  1551. ( OptionData->OldFileSymbolPathArray ) &&
  1552. ( OptionData->OldFileSymbolPathArray[ i ] )) {
  1553. //
  1554. // This hidden private flag that tells us the rift information
  1555. // is already specified for us. The LPCSTR pointer at
  1556. // OptionData->OldFileSymbolPathArray[ i ] is really a
  1557. // PRIFT_TABLE pointer. Note that no validation of external
  1558. // rift data is performed (must be in ascending order with
  1559. // no OldRva duplicates).
  1560. //
  1561. // We need to be careful to treat this external rift table
  1562. // differently in that we don't want to free the arrays
  1563. // like we do for our internally allocated rift tables.
  1564. // So, mark the RiftEntryAlloc field as zero to indicate
  1565. // that the rift arrays were not internally allocated.
  1566. //
  1567. PRIFT_TABLE ExternalRiftTable = (PVOID) OptionData->OldFileSymbolPathArray[ i ];
  1568. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryAlloc = 0;
  1569. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount = ExternalRiftTable->RiftEntryCount;
  1570. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryArray = ExternalRiftTable->RiftEntryArray;
  1571. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftUsageArray = ExternalRiftTable->RiftUsageArray;
  1572. }
  1573. else {
  1574. //
  1575. // Need to allocate rift arrays and generate rift data.
  1576. // This (NewSize+OldSize)/sizeof(RIFT) allocation will
  1577. // provide enough space for one rift entry for every
  1578. // four bytes in the files.
  1579. //
  1580. ULONG AllocCount = ( NewFileSize + OldFileSize ) / sizeof( RIFT_ENTRY );
  1581. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount = 0;
  1582. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryAlloc = AllocCount;
  1583. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryArray = MyVirtualAlloc( AllocCount * sizeof( RIFT_ENTRY ));
  1584. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftUsageArray = MyVirtualAlloc( AllocCount * sizeof( UCHAR ));
  1585. if (( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryArray == NULL ) ||
  1586. ( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftUsageArray == NULL )) {
  1587. Transform = FALSE;
  1588. }
  1589. else {
  1590. Transform = GenerateRiftTable(
  1591. OldFileInfoArray[ i ].OldFileHandle,
  1592. OldFileMapped,
  1593. OldFileSize,
  1594. OldFileOriginalChecksum,
  1595. OldFileOriginalTimeDate,
  1596. NewFileHandle,
  1597. NewFileMapped,
  1598. NewFileSize,
  1599. OptionFlags,
  1600. OptionData,
  1601. i,
  1602. &HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable
  1603. );
  1604. ASSERT( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount <= HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryAlloc );
  1605. #ifdef TESTCODE
  1606. printf( "\r%9d unique rift entries generated\n", HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount );
  1607. #endif
  1608. }
  1609. }
  1610. if ( Transform ) {
  1611. if ( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount != 0 ) {
  1612. Transform = TransformOldFileImageForPatching(
  1613. ExtendedOptionFlags,
  1614. OldFileMapped,
  1615. OldFileSize,
  1616. NewFileResTime,
  1617. &HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable
  1618. );
  1619. }
  1620. }
  1621. }
  1622. if ( Transform ) {
  1623. PatchBuffer = MyVirtualAlloc( PatchBufferSize );
  1624. if ( PatchBuffer != NULL ) {
  1625. EstimatedLzxMemory = EstimateLzxCompressionMemoryRequirement(
  1626. OldFileSize,
  1627. NewFileSize,
  1628. OptionFlags
  1629. );
  1630. SubAllocatorHandle = CreateSubAllocator(
  1631. EstimatedLzxMemory,
  1632. MINIMUM_VM_ALLOCATION
  1633. );
  1634. if ( SubAllocatorHandle != NULL ) {
  1635. __try {
  1636. ErrorCode = CreateRawLzxPatchDataFromBuffers(
  1637. OldFileMapped,
  1638. OldFileSize,
  1639. NewFileMapped,
  1640. NewFileSize,
  1641. PatchBufferSize,
  1642. PatchBuffer,
  1643. &PatchDataSize,
  1644. OptionFlags,
  1645. OptionData,
  1646. SubAllocate,
  1647. SubAllocatorHandle,
  1648. ProgressCallback,
  1649. CallbackContext,
  1650. ProgressPosition,
  1651. ProgressMaximum
  1652. );
  1653. }
  1654. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1655. ErrorCode = GetExceptionCode();
  1656. }
  1657. DestroySubAllocator( SubAllocatorHandle );
  1658. if ( ErrorCode == NO_ERROR ) {
  1659. Success = TRUE;
  1660. if ( TryLzxBoth ) {
  1661. AltExtendedOptionFlags = ExtendedOptionFlags;
  1662. if (( NtHeader ) && ( ! ( AltExtendedOptionFlags | PATCH_TRANSFORM_NO_RELCALLS ))) {
  1663. //
  1664. // Need to map, normalize, and transform
  1665. // old file again without E8 transform.
  1666. //
  1667. AltExtendedOptionFlags |= PATCH_TRANSFORM_NO_RELCALLS;
  1668. UnmapViewOfFile( OldFileMapped );
  1669. OldFileMapped = NULL;
  1670. Success = MyMapViewOfFileByHandle(
  1671. OldFileInfoArray[ i ].OldFileHandle,
  1672. &OldFileSize,
  1673. &OldFileMapped
  1674. );
  1675. if ( Success ) {
  1676. Success = NormalizeOldFileImageForPatching(
  1677. OldFileMapped,
  1678. OldFileSize,
  1679. OptionFlags,
  1680. OptionData,
  1681. NewFileCoffBase,
  1682. NewFileCoffTime,
  1683. OldFileInfoArray[ i ].IgnoreRangeCount,
  1684. OldFileInfoArray[ i ].IgnoreRangeArray,
  1685. OldFileInfoArray[ i ].RetainRangeCount,
  1686. OldFileInfoArray[ i ].RetainRangeArray
  1687. );
  1688. if ( Success ) {
  1689. if ( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount != 0 ) {
  1690. Success = TransformOldFileImageForPatching(
  1691. AltExtendedOptionFlags,
  1692. OldFileMapped,
  1693. OldFileSize,
  1694. NewFileResTime,
  1695. &HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable
  1696. );
  1697. }
  1698. }
  1699. }
  1700. }
  1701. if ( Success ) {
  1702. PatchAltBuffer = MyVirtualAlloc( PatchBufferSize );
  1703. if ( PatchAltBuffer != NULL ) {
  1704. SubAllocatorHandle = CreateSubAllocator(
  1705. EstimatedLzxMemory,
  1706. MINIMUM_VM_ALLOCATION
  1707. );
  1708. if ( SubAllocatorHandle != NULL ) {
  1709. PatchAltSize = 0; // prevent compiler warning
  1710. __try {
  1711. ErrorCode = CreateRawLzxPatchDataFromBuffers(
  1712. OldFileMapped,
  1713. OldFileSize,
  1714. NewFileMapped,
  1715. NewFileSize,
  1716. PatchBufferSize,
  1717. PatchAltBuffer,
  1718. &PatchAltSize,
  1719. OptionFlags | PATCH_OPTION_USE_LZX_B,
  1720. OptionData,
  1721. SubAllocate,
  1722. SubAllocatorHandle,
  1723. ProgressCallback,
  1724. CallbackContext,
  1725. ProgressPosition + NewFileSize + LzxInsertSize( OldFileSize, OptionFlags ),
  1726. ProgressMaximum
  1727. );
  1728. }
  1729. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1730. ErrorCode = GetExceptionCode();
  1731. }
  1732. DestroySubAllocator( SubAllocatorHandle );
  1733. if (( ErrorCode == NO_ERROR ) && ( PatchAltSize <= PatchDataSize )) {
  1734. MyVirtualFree( PatchBuffer );
  1735. PatchBuffer = PatchAltBuffer;
  1736. PatchDataSize = PatchAltSize;
  1737. ExtendedOptionFlags = AltExtendedOptionFlags;
  1738. }
  1739. else {
  1740. MyVirtualFree( PatchAltBuffer );
  1741. }
  1742. }
  1743. }
  1744. }
  1745. }
  1746. }
  1747. else {
  1748. SetLastError( ErrorCode );
  1749. }
  1750. }
  1751. }
  1752. }
  1753. }
  1754. if ( Success ) {
  1755. PatchArray[ HeaderOldFileCount ].PatchData = PatchBuffer;
  1756. PatchArray[ HeaderOldFileCount ].PatchSize = PatchDataSize;
  1757. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].OldFileHandle = OldFileInfoArray[ i ].OldFileHandle;
  1758. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].OldFileSize = OldFileSize;
  1759. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].OldFileCrc = OldFileCrc;
  1760. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].PatchDataSize = PatchDataSize;
  1761. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].IgnoreRangeCount = OldFileInfoArray[ i ].IgnoreRangeCount;
  1762. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].IgnoreRangeArray = OldFileInfoArray[ i ].IgnoreRangeArray;
  1763. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RetainRangeCount = OldFileInfoArray[ i ].RetainRangeCount;
  1764. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RetainRangeArray = OldFileInfoArray[ i ].RetainRangeArray;
  1765. //
  1766. // We overestimate (worst case) the possible
  1767. // header size here. Note that typical rift
  1768. // encoding size is around 5 bytes per entry,
  1769. // but we expect that to decrease when we switch
  1770. // to Huffman encoding for the rift table.
  1771. //
  1772. HeaderSize += 32;
  1773. HeaderSize += HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].IgnoreRangeCount * sizeof( PATCH_IGNORE_RANGE );
  1774. HeaderSize += HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RetainRangeCount * sizeof( PATCH_RETAIN_RANGE );
  1775. HeaderSize += HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount * sizeof( RIFT_ENTRY );
  1776. ++HeaderOldFileCount;
  1777. }
  1778. }
  1779. }
  1780. }
  1781. if ( OldFileMapped != NULL ) {
  1782. UnmapViewOfFile( OldFileMapped );
  1783. OldFileMapped = NULL;
  1784. }
  1785. if ( Success ) {
  1786. ProgressPosition += ( LzxInsertSize( OldFileSize, OptionFlags ) + NewFileSize ) * ( TryLzxBoth ? 2 : 1 );
  1787. Success = ProgressCallbackWrapper(
  1788. ProgressCallback,
  1789. CallbackContext,
  1790. ProgressPosition,
  1791. ProgressMaximum
  1792. );
  1793. }
  1794. if ( ! Success ) {
  1795. break;
  1796. }
  1797. }
  1798. }
  1799. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1800. SetLastError( GetExceptionCode() );
  1801. Success = FALSE;
  1802. }
  1803. if ( Success ) {
  1804. if (( OptionFlags & PATCH_OPTION_FAIL_IF_SAME_FILE ) &&
  1805. ( HeaderOldFileCount == 1 ) &&
  1806. ( PatchArray[ 0 ].PatchSize == 0 )) {
  1807. SetLastError( ERROR_PATCH_SAME_FILE );
  1808. Success = FALSE;
  1809. }
  1810. }
  1811. PatchBuffer = NULL;
  1812. PatchDataSize = 0;
  1813. if ( Success ) {
  1814. //
  1815. // Create header
  1816. //
  1817. Success = FALSE;
  1818. HeaderSize = ROUNDUP2( HeaderSize, 0x10000 );
  1819. PatchBuffer = MyVirtualAlloc( HeaderSize );
  1820. if ( PatchBuffer != NULL ) {
  1821. Success = TRUE;
  1822. //
  1823. // Compute size of PatchData without the header.
  1824. //
  1825. PatchDataSize = 0;
  1826. for ( i = 0; i < HeaderOldFileCount; i++ ) {
  1827. PatchDataSize += PatchArray[ i ].PatchSize;
  1828. }
  1829. //
  1830. // Don't need to encode NewFileResTime if the patch is simply
  1831. // a header with no patch data (new file is same as old file).
  1832. // We do still need the NewFileCoffTime and NewFileCoffBase
  1833. // though because we still need to normalize the old file.
  1834. //
  1835. if ( PatchDataSize == 0 ) {
  1836. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  1837. NewFileResTime = 0;
  1838. }
  1839. if ( ExtendedOptionFlags ) {
  1840. OptionFlags |= PATCH_OPTION_EXTENDED_OPTIONS;
  1841. }
  1842. else {
  1843. OptionFlags &= ~PATCH_OPTION_EXTENDED_OPTIONS;
  1844. }
  1845. //
  1846. // Don't need to set PATCH_OPTION_LZX_LARGE unless an LZX window larger
  1847. // than 8Mb was used. This allows backwards compatibility by default for
  1848. // files smaller than 8Mb.
  1849. //
  1850. if ( OptionFlags & PATCH_OPTION_USE_LZX_LARGE ) {
  1851. if ( LzxWindowSize( LargestOldFileSize, NewFileSize, OptionFlags ) <= LZX_MAXWINDOW_8 ) {
  1852. OptionFlags &= ~PATCH_OPTION_USE_LZX_LARGE;
  1853. }
  1854. }
  1855. HeaderInfo.Signature = PATCH_SIGNATURE;
  1856. HeaderInfo.OptionFlags = OptionFlags;
  1857. HeaderInfo.ExtendedOptionFlags = ExtendedOptionFlags;
  1858. HeaderInfo.OptionData = OptionData;
  1859. HeaderInfo.NewFileCoffBase = NewFileCoffBase;
  1860. HeaderInfo.NewFileCoffTime = NewFileCoffTime;
  1861. HeaderInfo.NewFileResTime = NewFileResTime;
  1862. HeaderInfo.NewFileSize = NewFileSize;
  1863. HeaderInfo.NewFileCrc = NewFileCrc;
  1864. HeaderInfo.OldFileCount = HeaderOldFileCount;
  1865. HeaderInfo.NewFileTime = 0;
  1866. if ( ! ( OptionFlags & PATCH_OPTION_NO_TIMESTAMP )) {
  1867. HeaderInfo.NewFileTime = FileTimeToUlongTime( &NewFileTime );
  1868. PatchFileTime = NULL;
  1869. }
  1870. HeaderSize = EncodePatchHeader( &HeaderInfo, PatchBuffer );
  1871. PatchDataSize += HeaderSize + sizeof( ULONG );
  1872. //
  1873. // Now we know the size of the patch file, so if we want to
  1874. // make sure it's not bigger than just compressing the new
  1875. // file, we need to compress the new file to see (the output
  1876. // of the compression is discarded -- we just want to know
  1877. // how big it would be. Obviously if the patch file is bigger
  1878. // than the raw new file, no need to compress the new file to
  1879. // see if that is smaller!
  1880. //
  1881. if ( OptionFlags & PATCH_OPTION_FAIL_IF_BIGGER ) {
  1882. if ( PatchDataSize > NewFileSize ) {
  1883. SetLastError( ERROR_PATCH_BIGGER_THAN_COMPRESSED );
  1884. Success = FALSE;
  1885. }
  1886. else {
  1887. EstimatedLzxMemory = EstimateLzxCompressionMemoryRequirement(
  1888. 0,
  1889. NewFileSize,
  1890. 0 // CAB has only 2Mb window size
  1891. );
  1892. SubAllocatorHandle = CreateSubAllocator(
  1893. EstimatedLzxMemory,
  1894. MINIMUM_VM_ALLOCATION
  1895. );
  1896. if ( SubAllocatorHandle != NULL ) {
  1897. NewFileCompressedSize = 0; // prevent compiler warning
  1898. __try {
  1899. ErrorCode = RawLzxCompressBuffer(
  1900. NewFileMapped,
  1901. NewFileSize,
  1902. 0,
  1903. NULL,
  1904. &NewFileCompressedSize,
  1905. SubAllocate,
  1906. SubAllocatorHandle,
  1907. ProgressCallback,
  1908. CallbackContext,
  1909. ProgressPosition,
  1910. ProgressMaximum
  1911. );
  1912. }
  1913. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1914. ErrorCode = GetExceptionCode();
  1915. }
  1916. DestroySubAllocator( SubAllocatorHandle );
  1917. if ( ErrorCode == NO_ERROR ) {
  1918. if ( PatchDataSize > NewFileCompressedSize ) {
  1919. SetLastError( ERROR_PATCH_BIGGER_THAN_COMPRESSED );
  1920. Success = FALSE;
  1921. }
  1922. }
  1923. }
  1924. }
  1925. if ( Success ) {
  1926. ProgressPosition += NewFileSize;
  1927. Success = ProgressCallbackWrapper(
  1928. ProgressCallback,
  1929. CallbackContext,
  1930. ProgressPosition,
  1931. ProgressMaximum
  1932. );
  1933. }
  1934. }
  1935. }
  1936. }
  1937. UnmapViewOfFile( NewFileMapped );
  1938. if ( Success ) {
  1939. Success = MyCreateMappedFileByHandle(
  1940. PatchFileHandle,
  1941. PatchDataSize,
  1942. &PatchFileMapped
  1943. );
  1944. if ( Success ) {
  1945. __try {
  1946. p = PatchFileMapped;
  1947. CopyMemory( p, PatchBuffer, HeaderSize );
  1948. p += HeaderSize;
  1949. for ( i = 0; i < HeaderOldFileCount; i++ ) {
  1950. if ( PatchArray[ i ].PatchSize != 0 ) {
  1951. CopyMemory( p, PatchArray[ i ].PatchData, PatchArray[ i ].PatchSize );
  1952. p += PatchArray[ i ].PatchSize;
  1953. }
  1954. }
  1955. PatchFileCrc = Crc32( 0xFFFFFFFF, PatchFileMapped, PatchDataSize - sizeof( ULONG ));
  1956. *(UNALIGNED ULONG *)( PatchFileMapped + PatchDataSize - sizeof( ULONG )) = PatchFileCrc;
  1957. }
  1958. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1959. SetLastError( GetExceptionCode() );
  1960. PatchDataSize = 0;
  1961. Success = FALSE;
  1962. }
  1963. MyUnmapCreatedMappedFile(
  1964. PatchFileHandle,
  1965. PatchFileMapped,
  1966. PatchDataSize,
  1967. PatchFileTime
  1968. );
  1969. }
  1970. }
  1971. //
  1972. // Cleanup
  1973. //
  1974. if ( PatchBuffer ) {
  1975. MyVirtualFree( PatchBuffer );
  1976. }
  1977. for ( i = 0; i < OldFileCount; i++ ) {
  1978. if ( PatchArray[ i ].PatchData ) {
  1979. MyVirtualFree( PatchArray[ i ].PatchData );
  1980. }
  1981. if ( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftEntryAlloc ) {
  1982. if ( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftEntryArray ) {
  1983. MyVirtualFree( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftEntryArray );
  1984. }
  1985. if ( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftUsageArray ) {
  1986. MyVirtualFree( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftUsageArray );
  1987. }
  1988. }
  1989. }
  1990. if ( Success ) {
  1991. ASSERT( ProgressPosition == ProgressMaximum );
  1992. }
  1993. if (( ! Success ) &&
  1994. ( GetLastError() == ERROR_SUCCESS )) {
  1995. SetLastError( ERROR_EXTENDED_ERROR );
  1996. }
  1997. HeapFree(GetProcessHeap(), 0, PatchArray);
  1998. HeapFree(GetProcessHeap(), 0, HeaderInfo.OldFileInfoArray);
  1999. return Success;
  2000. }
  2001. BOOL
  2002. PATCHAPI
  2003. ExtractPatchHeaderToFileA(
  2004. IN LPCSTR PatchFileName,
  2005. OUT LPCSTR PatchHeaderFileName
  2006. )
  2007. {
  2008. HANDLE PatchFileHandle;
  2009. HANDLE HeaderFileHandle;
  2010. BOOL Success = FALSE;
  2011. PatchFileHandle = CreateFileA(
  2012. PatchFileName,
  2013. GENERIC_READ,
  2014. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2015. NULL,
  2016. OPEN_EXISTING,
  2017. FILE_FLAG_RANDOM_ACCESS,
  2018. NULL
  2019. );
  2020. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  2021. HeaderFileHandle = CreateFileA(
  2022. PatchHeaderFileName,
  2023. GENERIC_READ | GENERIC_WRITE,
  2024. FILE_SHARE_READ,
  2025. NULL,
  2026. CREATE_ALWAYS,
  2027. FILE_ATTRIBUTE_NORMAL,
  2028. NULL
  2029. );
  2030. if ( HeaderFileHandle != INVALID_HANDLE_VALUE ) {
  2031. Success = ExtractPatchHeaderToFileByHandles(
  2032. PatchFileHandle,
  2033. HeaderFileHandle
  2034. );
  2035. CloseHandle( HeaderFileHandle );
  2036. if ( ! Success ) {
  2037. DeleteFileA( PatchHeaderFileName );
  2038. }
  2039. }
  2040. CloseHandle( PatchFileHandle );
  2041. }
  2042. return Success;
  2043. }
  2044. BOOL
  2045. PATCHAPI
  2046. ExtractPatchHeaderToFileW(
  2047. IN LPCWSTR PatchFileName,
  2048. OUT LPCWSTR PatchHeaderFileName
  2049. )
  2050. {
  2051. HANDLE PatchFileHandle;
  2052. HANDLE HeaderFileHandle;
  2053. BOOL Success = FALSE;
  2054. PatchFileHandle = CreateFileW(
  2055. PatchFileName,
  2056. GENERIC_READ,
  2057. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2058. NULL,
  2059. OPEN_EXISTING,
  2060. FILE_FLAG_RANDOM_ACCESS,
  2061. NULL
  2062. );
  2063. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  2064. HeaderFileHandle = CreateFileW(
  2065. PatchHeaderFileName,
  2066. GENERIC_READ | GENERIC_WRITE,
  2067. FILE_SHARE_READ,
  2068. NULL,
  2069. CREATE_ALWAYS,
  2070. FILE_ATTRIBUTE_NORMAL,
  2071. NULL
  2072. );
  2073. if ( HeaderFileHandle != INVALID_HANDLE_VALUE ) {
  2074. Success = ExtractPatchHeaderToFileByHandles(
  2075. PatchFileHandle,
  2076. HeaderFileHandle
  2077. );
  2078. CloseHandle( HeaderFileHandle );
  2079. if ( ! Success ) {
  2080. DeleteFileW( PatchHeaderFileName );
  2081. }
  2082. }
  2083. CloseHandle( PatchFileHandle );
  2084. }
  2085. return Success;
  2086. }
  2087. BOOL
  2088. PATCHAPI
  2089. ExtractPatchHeaderToFileByHandles(
  2090. IN HANDLE PatchFileHandle,
  2091. OUT HANDLE PatchHeaderFileHandle
  2092. )
  2093. {
  2094. PPATCH_HEADER_INFO HeaderInfo;
  2095. HANDLE SubAllocator;
  2096. PUCHAR PatchFileMapped;
  2097. FILETIME PatchFileTime;
  2098. ULONG PatchFileSize;
  2099. ULONG PatchFileCrc;
  2100. ULONG PatchHeaderSize;
  2101. ULONG ActualSize;
  2102. ULONG i;
  2103. BOOL Success;
  2104. BOOL Mapped;
  2105. Success = FALSE;
  2106. Mapped = MyMapViewOfFileByHandle(
  2107. PatchFileHandle,
  2108. &PatchFileSize,
  2109. &PatchFileMapped
  2110. );
  2111. if ( Mapped ) {
  2112. GetFileTime( PatchFileHandle, NULL, NULL, &PatchFileTime );
  2113. PatchFileCrc = 0;
  2114. SafeCompleteCrc32( PatchFileMapped, PatchFileSize, &PatchFileCrc );
  2115. if ( PatchFileCrc == 0xFFFFFFFF ) {
  2116. SubAllocator = CreateSubAllocator( 0x10000, 0x10000 );
  2117. if ( SubAllocator ) {
  2118. Success = DecodePatchHeader(
  2119. PatchFileMapped,
  2120. PatchFileSize,
  2121. SubAllocator,
  2122. &PatchHeaderSize,
  2123. &HeaderInfo
  2124. );
  2125. if ( Success ) {
  2126. //
  2127. // Header extraction is provided so that a header without
  2128. // the bulk of the patch data can be used to determine if
  2129. // an old file is correct for this patch header (can be
  2130. // patched).
  2131. //
  2132. // Since the extracted header will not be used to actually
  2133. // apply, we don't need any of the header data that is
  2134. // used only for transformation (RiftTable and NewResTime).
  2135. // Since NewResTime is typically encoded as one byte (as
  2136. // delta from NewCoffTime), we won't bother throwing it
  2137. // away, but we will throw away the RiftTable.
  2138. //
  2139. // Zero out the rift entry counts, then re-create the
  2140. // patch header with the zeroed rift counts (create over
  2141. // the write-copy mapped patch file buffer, then write
  2142. // that buffer to disk).
  2143. //
  2144. for ( i = 0; i < HeaderInfo->OldFileCount; i++ ) {
  2145. HeaderInfo->OldFileInfoArray[ i ].RiftTable.RiftEntryCount = 0;
  2146. }
  2147. __try {
  2148. PatchHeaderSize = EncodePatchHeader( HeaderInfo, PatchFileMapped );
  2149. PatchFileCrc = Crc32( 0xFFFFFFFF, PatchFileMapped, PatchHeaderSize );
  2150. *(UNALIGNED ULONG *)( PatchFileMapped + PatchHeaderSize ) = PatchFileCrc;
  2151. Success = WriteFile(
  2152. PatchHeaderFileHandle,
  2153. PatchFileMapped,
  2154. PatchHeaderSize + sizeof( ULONG ),
  2155. &ActualSize,
  2156. NULL
  2157. );
  2158. }
  2159. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2160. SetLastError( GetExceptionCode() );
  2161. Success = FALSE;
  2162. }
  2163. if ( Success ) {
  2164. SetFileTime( PatchHeaderFileHandle, NULL, NULL, &PatchFileTime );
  2165. }
  2166. }
  2167. DestroySubAllocator( SubAllocator );
  2168. }
  2169. }
  2170. else {
  2171. SetLastError( ERROR_PATCH_CORRUPT );
  2172. }
  2173. UnmapViewOfFile( PatchFileMapped );
  2174. }
  2175. return Success;
  2176. }
  2177. #endif // ! PATCH_APPLY_CODE_ONLY
  2178. //
  2179. // Following group of functions and exported apis are exclusively for
  2180. // applying patches. If we're only compiling the create code, ignore
  2181. // this group of functions.
  2182. //
  2183. #ifndef PATCH_CREATE_CODE_ONLY
  2184. PVOID
  2185. SaveRetainRanges(
  2186. IN PUCHAR MappedFile,
  2187. IN ULONG FileSize,
  2188. IN ULONG RetainRangeCount,
  2189. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  2190. IN BOOL SaveFromNewFile
  2191. )
  2192. {
  2193. PUCHAR Buffer, p;
  2194. ULONG Offset;
  2195. ULONG TotalSize = 0;
  2196. ULONG i;
  2197. for ( i = 0; i < RetainRangeCount; i++ ) {
  2198. TotalSize += RetainRangeArray[ i ].LengthInBytes;
  2199. }
  2200. Buffer = MyVirtualAlloc( TotalSize );
  2201. if ( Buffer ) {
  2202. __try {
  2203. p = Buffer;
  2204. for ( i = 0; i < RetainRangeCount; i++ ) {
  2205. Offset = SaveFromNewFile ?
  2206. RetainRangeArray[ i ].OffsetInNewFile :
  2207. RetainRangeArray[ i ].OffsetInOldFile;
  2208. if (( Offset + RetainRangeArray[ i ].LengthInBytes ) <= FileSize ) {
  2209. CopyMemory( p, MappedFile + Offset, RetainRangeArray[ i ].LengthInBytes );
  2210. }
  2211. p += RetainRangeArray[ i ].LengthInBytes;
  2212. }
  2213. }
  2214. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2215. SetLastError( GetExceptionCode() );
  2216. MyVirtualFree( Buffer );
  2217. Buffer = NULL;
  2218. }
  2219. }
  2220. return Buffer;
  2221. }
  2222. BOOL
  2223. CreateNewFileFromOldFileMapped(
  2224. IN PUCHAR OldFileMapped,
  2225. IN ULONG OldFileSize,
  2226. OUT HANDLE NewFileHandle,
  2227. IN PFILETIME NewFileTime,
  2228. IN ULONG NewFileExpectedCrc,
  2229. IN ULONG RetainRangeCount,
  2230. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  2231. IN PUCHAR RetainBuffer,
  2232. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2233. IN PVOID CallbackContext
  2234. )
  2235. {
  2236. PUCHAR NewFileMapped;
  2237. ULONG NewFileCrc;
  2238. BOOL Success;
  2239. ULONG i;
  2240. Success = MyCreateMappedFileByHandle(
  2241. NewFileHandle,
  2242. OldFileSize,
  2243. &NewFileMapped
  2244. );
  2245. if ( Success ) {
  2246. __try {
  2247. CopyMemory( NewFileMapped, OldFileMapped, OldFileSize );
  2248. NewFileCrc = Crc32( 0xFFFFFFFF, NewFileMapped, OldFileSize ) ^ 0xFFFFFFFF;
  2249. if ( NewFileCrc == NewFileExpectedCrc ) {
  2250. for ( i = 0; i < RetainRangeCount; i++ ) {
  2251. if (( RetainRangeArray[ i ].OffsetInNewFile + RetainRangeArray[ i ].LengthInBytes ) <= OldFileSize ) {
  2252. CopyMemory(
  2253. RetainRangeArray[ i ].OffsetInNewFile + NewFileMapped,
  2254. RetainBuffer,
  2255. RetainRangeArray[ i ].LengthInBytes
  2256. );
  2257. }
  2258. RetainBuffer += RetainRangeArray[ i ].LengthInBytes;
  2259. }
  2260. Success = ProgressCallbackWrapper(
  2261. ProgressCallback,
  2262. CallbackContext,
  2263. OldFileSize,
  2264. OldFileSize
  2265. );
  2266. }
  2267. else {
  2268. SetLastError( ERROR_PATCH_WRONG_FILE );
  2269. OldFileSize = 0;
  2270. Success = FALSE;
  2271. }
  2272. }
  2273. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2274. SetLastError( GetExceptionCode());
  2275. OldFileSize = 0;
  2276. Success = FALSE;
  2277. }
  2278. MyUnmapCreatedMappedFile(
  2279. NewFileHandle,
  2280. NewFileMapped,
  2281. OldFileSize,
  2282. NewFileTime
  2283. );
  2284. }
  2285. return Success;
  2286. }
  2287. BOOL
  2288. CreateNewFileFromPatchData(
  2289. IN PUCHAR OldFileMapped,
  2290. IN ULONG OldFileSize,
  2291. IN PUCHAR PatchData,
  2292. IN ULONG PatchDataSize,
  2293. OUT HANDLE NewFileHandle,
  2294. IN ULONG NewFileSize,
  2295. IN PFILETIME NewFileTime,
  2296. IN ULONG NewFileExpectedCrc,
  2297. IN ULONG RetainRangeCount,
  2298. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  2299. IN PUCHAR RetainBuffer,
  2300. IN ULONG OptionFlags,
  2301. IN PVOID OptionData,
  2302. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2303. IN PVOID CallbackContext
  2304. )
  2305. {
  2306. HANDLE SubAllocatorHandle;
  2307. ULONG EstimatedLzxMemory;
  2308. PUCHAR NewFileMapped;
  2309. ULONG NewFileCrc;
  2310. ULONG ErrorCode;
  2311. BOOL Success;
  2312. ULONG i;
  2313. UNREFERENCED_PARAMETER( OptionData );
  2314. Success = MyCreateMappedFileByHandle(
  2315. NewFileHandle,
  2316. NewFileSize,
  2317. &NewFileMapped
  2318. );
  2319. if ( Success ) {
  2320. ErrorCode = NO_ERROR;
  2321. EstimatedLzxMemory = EstimateLzxDecompressionMemoryRequirement(
  2322. OldFileSize,
  2323. NewFileSize,
  2324. OptionFlags
  2325. );
  2326. SubAllocatorHandle = CreateSubAllocator(
  2327. EstimatedLzxMemory,
  2328. MINIMUM_VM_ALLOCATION
  2329. );
  2330. if ( SubAllocatorHandle != NULL ) {
  2331. __try {
  2332. ErrorCode = ApplyRawLzxPatchToBuffer(
  2333. OldFileMapped,
  2334. OldFileSize,
  2335. PatchData,
  2336. PatchDataSize,
  2337. NewFileMapped,
  2338. NewFileSize,
  2339. OptionFlags,
  2340. OptionData,
  2341. SubAllocate,
  2342. SubAllocatorHandle,
  2343. ProgressCallback,
  2344. CallbackContext,
  2345. 0,
  2346. NewFileSize
  2347. );
  2348. if ( ErrorCode == NO_ERROR ) {
  2349. NewFileCrc = Crc32( 0xFFFFFFFF, NewFileMapped, NewFileSize ) ^ 0xFFFFFFFF;
  2350. if ( NewFileCrc == NewFileExpectedCrc ) {
  2351. for ( i = 0; i < RetainRangeCount; i++ ) {
  2352. if (( RetainRangeArray[ i ].OffsetInNewFile + RetainRangeArray[ i ].LengthInBytes ) <= OldFileSize ) {
  2353. CopyMemory(
  2354. RetainRangeArray[ i ].OffsetInNewFile + NewFileMapped,
  2355. RetainBuffer,
  2356. RetainRangeArray[ i ].LengthInBytes
  2357. );
  2358. }
  2359. RetainBuffer += RetainRangeArray[ i ].LengthInBytes;
  2360. }
  2361. }
  2362. else {
  2363. ErrorCode = ERROR_PATCH_WRONG_FILE;
  2364. }
  2365. }
  2366. #ifdef TESTCODE
  2367. if ( ErrorCode != NO_ERROR ) {
  2368. HANDLE hFile = CreateFile(
  2369. "Wrong.out",
  2370. GENERIC_WRITE,
  2371. FILE_SHARE_READ,
  2372. NULL,
  2373. CREATE_ALWAYS,
  2374. FILE_ATTRIBUTE_NORMAL,
  2375. NULL
  2376. );
  2377. if ( hFile != INVALID_HANDLE_VALUE ) {
  2378. DWORD Actual;
  2379. WriteFile( hFile, NewFileMapped, NewFileSize, &Actual, NULL );
  2380. CloseHandle( hFile );
  2381. }
  2382. }
  2383. #endif // TESTCODE
  2384. }
  2385. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2386. ErrorCode = GetExceptionCode();
  2387. }
  2388. DestroySubAllocator( SubAllocatorHandle );
  2389. }
  2390. MyUnmapCreatedMappedFile(
  2391. NewFileHandle,
  2392. NewFileMapped,
  2393. ( ErrorCode == NO_ERROR ) ? NewFileSize : 0,
  2394. NewFileTime
  2395. );
  2396. if ( ErrorCode == NO_ERROR ) {
  2397. Success = TRUE;
  2398. }
  2399. else {
  2400. SetLastError( ErrorCode );
  2401. Success = FALSE;
  2402. }
  2403. }
  2404. return Success;
  2405. }
  2406. BOOL
  2407. PATCHAPI
  2408. ApplyPatchToFileByHandlesEx(
  2409. IN HANDLE PatchFileHandle,
  2410. IN HANDLE OldFileHandle,
  2411. OUT HANDLE NewFileHandle,
  2412. IN ULONG ApplyOptionFlags,
  2413. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2414. IN PVOID CallbackContext
  2415. )
  2416. {
  2417. PHEADER_OLD_FILE_INFO OldFileInfo;
  2418. PPATCH_HEADER_INFO HeaderInfo;
  2419. PPATCH_RETAIN_RANGE RetainRangeArray;
  2420. ULONG RetainRangeCount;
  2421. PUCHAR RetainBuffer;
  2422. HANDLE SubAllocator;
  2423. ULONG PatchHeaderSize;
  2424. FILETIME NewFileTime;
  2425. PUCHAR PatchFileMapped;
  2426. ULONG PatchFileSize;
  2427. ULONG PatchFileCrc;
  2428. PUCHAR PatchData;
  2429. PUCHAR OldFileMapped;
  2430. ULONG OldFileSize;
  2431. ULONG OldFileCrc;
  2432. BOOL Mapped;
  2433. BOOL Success;
  2434. BOOL Finished;
  2435. ULONG i;
  2436. Success = FALSE;
  2437. Mapped = MyMapViewOfFileByHandle(
  2438. PatchFileHandle,
  2439. &PatchFileSize,
  2440. &PatchFileMapped
  2441. );
  2442. if ( Mapped ) {
  2443. GetFileTime( PatchFileHandle, NULL, NULL, &NewFileTime );
  2444. PatchFileCrc = 0;
  2445. SafeCompleteCrc32( PatchFileMapped, PatchFileSize, &PatchFileCrc );
  2446. if ( PatchFileCrc == 0xFFFFFFFF ) {
  2447. SubAllocator = CreateSubAllocator( 0x10000, 0x10000 );
  2448. if ( SubAllocator ) {
  2449. Success = DecodePatchHeader(
  2450. PatchFileMapped,
  2451. PatchFileSize,
  2452. SubAllocator,
  2453. &PatchHeaderSize,
  2454. &HeaderInfo
  2455. );
  2456. if ( Success ) {
  2457. //
  2458. // Patch is valid.
  2459. //
  2460. Success = ProgressCallbackWrapper(
  2461. ProgressCallback,
  2462. CallbackContext,
  2463. 0,
  2464. HeaderInfo->NewFileSize
  2465. );
  2466. if ( Success ) {
  2467. Finished = FALSE;
  2468. Success = FALSE;
  2469. if (( ! ( HeaderInfo->OptionFlags & PATCH_OPTION_NO_TIMESTAMP )) &&
  2470. ( HeaderInfo->NewFileTime != 0 )) {
  2471. UlongTimeToFileTime( HeaderInfo->NewFileTime, &NewFileTime );
  2472. }
  2473. OldFileSize = GetFileSize( OldFileHandle, NULL );
  2474. //
  2475. // First see if the old file is really the new file.
  2476. //
  2477. if ( OldFileSize == HeaderInfo->NewFileSize ) {
  2478. Mapped = MyMapViewOfFileByHandle(
  2479. OldFileHandle,
  2480. &OldFileSize,
  2481. &OldFileMapped
  2482. );
  2483. if ( ! Mapped ) {
  2484. Success = FALSE;
  2485. Finished = TRUE;
  2486. }
  2487. else {
  2488. RetainBuffer = NULL;
  2489. OldFileCrc = 0;
  2490. OldFileInfo = &HeaderInfo->OldFileInfoArray[ 0 ];
  2491. RetainRangeCount = OldFileInfo->RetainRangeCount;
  2492. RetainRangeArray = OldFileInfo->RetainRangeArray;
  2493. if (( RetainRangeCount != 0 ) &&
  2494. ( ! ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ))) {
  2495. RetainBuffer = SaveRetainRanges(
  2496. OldFileMapped,
  2497. OldFileSize,
  2498. RetainRangeCount,
  2499. RetainRangeArray,
  2500. TRUE
  2501. );
  2502. if ( RetainBuffer == NULL ) {
  2503. Finished = TRUE;
  2504. }
  2505. }
  2506. if ( ! Finished ) {
  2507. __try {
  2508. //
  2509. // First see if they match exact, without
  2510. // normalizing.
  2511. //
  2512. for ( i = 0; i < RetainRangeCount; i++ ) {
  2513. if (( RetainRangeArray[ i ].OffsetInNewFile + RetainRangeArray[ i ].LengthInBytes ) <= OldFileSize ) {
  2514. ZeroMemory( OldFileMapped + RetainRangeArray[ i ].OffsetInNewFile, RetainRangeArray[ i ].LengthInBytes );
  2515. }
  2516. }
  2517. OldFileCrc = Crc32( 0xFFFFFFFF, OldFileMapped, OldFileSize ) ^ 0xFFFFFFFF;
  2518. if ( OldFileCrc != HeaderInfo->NewFileCrc ) {
  2519. //
  2520. // Don't match exact, so try with
  2521. // normalizing.
  2522. //
  2523. // NOTE: We're assuming here that the
  2524. // zeroed retain ranges don't overlap
  2525. // with the binding info that we're
  2526. // correcting.
  2527. //
  2528. NormalizeOldFileImageForPatching(
  2529. OldFileMapped,
  2530. OldFileSize,
  2531. HeaderInfo->OptionFlags,
  2532. HeaderInfo->OptionData,
  2533. HeaderInfo->NewFileCoffBase,
  2534. HeaderInfo->NewFileCoffTime,
  2535. 0,
  2536. NULL,
  2537. 0,
  2538. NULL
  2539. );
  2540. OldFileCrc = Crc32( 0xFFFFFFFF, OldFileMapped, OldFileSize ) ^ 0xFFFFFFFF;
  2541. }
  2542. }
  2543. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2544. SetLastError( GetExceptionCode() );
  2545. Finished = TRUE;
  2546. }
  2547. if (( ! Finished ) &&
  2548. ( OldFileCrc == HeaderInfo->NewFileCrc ) &&
  2549. ( OldFileSize == HeaderInfo->NewFileSize )) {
  2550. Finished = TRUE;
  2551. if ( ApplyOptionFlags & APPLY_OPTION_FAIL_IF_EXACT ) {
  2552. SetLastError( ERROR_PATCH_NOT_NECESSARY );
  2553. Success = FALSE;
  2554. }
  2555. else if ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ) {
  2556. Success = TRUE;
  2557. }
  2558. else {
  2559. Success = CreateNewFileFromOldFileMapped(
  2560. OldFileMapped,
  2561. OldFileSize,
  2562. NewFileHandle,
  2563. &NewFileTime,
  2564. HeaderInfo->NewFileCrc,
  2565. RetainRangeCount,
  2566. RetainRangeArray,
  2567. RetainBuffer,
  2568. ProgressCallback,
  2569. CallbackContext
  2570. );
  2571. }
  2572. }
  2573. if ( RetainBuffer != NULL ) {
  2574. MyVirtualFree( RetainBuffer );
  2575. }
  2576. }
  2577. UnmapViewOfFile( OldFileMapped );
  2578. }
  2579. }
  2580. if ( ! Finished ) {
  2581. //
  2582. // Now see if the old file matches one of the old
  2583. // files we have in our patch file. For each set
  2584. // of old file info in our patch file, we have to
  2585. // remap the old file to check it since each old
  2586. // file might have different ignore range parameters
  2587. // (we modify the buffer for the ignore ranges).
  2588. //
  2589. PatchData = PatchFileMapped + PatchHeaderSize;
  2590. Success = FALSE;
  2591. for ( i = 0; ( i < HeaderInfo->OldFileCount ) && ( ! Finished ) && ( ! Success ); i++ ) {
  2592. OldFileInfo = &HeaderInfo->OldFileInfoArray[ i ];
  2593. if ( OldFileInfo->OldFileSize == OldFileSize ) {
  2594. Mapped = MyMapViewOfFileByHandle(
  2595. OldFileHandle,
  2596. &OldFileSize,
  2597. &OldFileMapped
  2598. );
  2599. if ( ! Mapped ) {
  2600. Finished = TRUE;
  2601. }
  2602. else {
  2603. RetainBuffer = NULL;
  2604. if (( OldFileInfo->RetainRangeCount != 0 ) &&
  2605. ( ! ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ))) {
  2606. RetainBuffer = SaveRetainRanges(
  2607. OldFileMapped,
  2608. OldFileSize,
  2609. OldFileInfo->RetainRangeCount,
  2610. OldFileInfo->RetainRangeArray,
  2611. FALSE
  2612. );
  2613. if ( RetainBuffer == NULL ) {
  2614. Finished = TRUE;
  2615. }
  2616. }
  2617. if ( ! Finished ) {
  2618. NormalizeOldFileImageForPatching(
  2619. OldFileMapped,
  2620. OldFileSize,
  2621. HeaderInfo->OptionFlags,
  2622. HeaderInfo->OptionData,
  2623. HeaderInfo->NewFileCoffBase,
  2624. HeaderInfo->NewFileCoffTime,
  2625. OldFileInfo->IgnoreRangeCount,
  2626. OldFileInfo->IgnoreRangeArray,
  2627. OldFileInfo->RetainRangeCount,
  2628. OldFileInfo->RetainRangeArray
  2629. );
  2630. OldFileCrc = 0;
  2631. if (( SafeCompleteCrc32( OldFileMapped, OldFileSize, &OldFileCrc )) &&
  2632. ( OldFileCrc == OldFileInfo->OldFileCrc ) &&
  2633. ( OldFileSize == OldFileInfo->OldFileSize )) {
  2634. //
  2635. // CRC's match
  2636. //
  2637. if ( OldFileInfo->PatchDataSize == 0 ) {
  2638. if ( ApplyOptionFlags & APPLY_OPTION_FAIL_IF_CLOSE ) {
  2639. SetLastError( ERROR_PATCH_NOT_NECESSARY );
  2640. Finished = TRUE;
  2641. }
  2642. else if ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ) {
  2643. Success = TRUE;
  2644. }
  2645. else {
  2646. Success = CreateNewFileFromOldFileMapped(
  2647. OldFileMapped,
  2648. OldFileSize,
  2649. NewFileHandle,
  2650. &NewFileTime,
  2651. HeaderInfo->NewFileCrc,
  2652. OldFileInfo->RetainRangeCount,
  2653. OldFileInfo->RetainRangeArray,
  2654. RetainBuffer,
  2655. ProgressCallback,
  2656. CallbackContext
  2657. );
  2658. if ( ! Success ) {
  2659. Finished = TRUE;
  2660. }
  2661. }
  2662. }
  2663. else {
  2664. if ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ) {
  2665. Success = TRUE;
  2666. }
  2667. else if (( PatchData + OldFileInfo->PatchDataSize ) > ( PatchFileMapped + PatchFileSize )) {
  2668. SetLastError( ERROR_PATCH_NOT_AVAILABLE );
  2669. Finished = TRUE;
  2670. }
  2671. else {
  2672. Success = TRUE;
  2673. if ( OldFileInfo->RiftTable.RiftEntryCount != 0 ) {
  2674. Success = TransformOldFileImageForPatching(
  2675. HeaderInfo->ExtendedOptionFlags,
  2676. OldFileMapped,
  2677. OldFileSize,
  2678. HeaderInfo->NewFileResTime,
  2679. &OldFileInfo->RiftTable
  2680. );
  2681. }
  2682. if ( Success ) {
  2683. Success = CreateNewFileFromPatchData(
  2684. OldFileMapped,
  2685. OldFileSize,
  2686. PatchData,
  2687. OldFileInfo->PatchDataSize,
  2688. NewFileHandle,
  2689. HeaderInfo->NewFileSize,
  2690. &NewFileTime,
  2691. HeaderInfo->NewFileCrc,
  2692. OldFileInfo->RetainRangeCount,
  2693. OldFileInfo->RetainRangeArray,
  2694. RetainBuffer,
  2695. HeaderInfo->OptionFlags,
  2696. HeaderInfo->OptionData,
  2697. ProgressCallback,
  2698. CallbackContext
  2699. );
  2700. }
  2701. if ( ! Success ) {
  2702. Finished = TRUE;
  2703. }
  2704. }
  2705. }
  2706. }
  2707. if ( RetainBuffer != NULL ) {
  2708. MyVirtualFree( RetainBuffer );
  2709. }
  2710. }
  2711. UnmapViewOfFile( OldFileMapped );
  2712. }
  2713. }
  2714. PatchData += OldFileInfo->PatchDataSize;
  2715. }
  2716. if (( ! Finished ) && ( ! Success )) {
  2717. SetLastError( ERROR_PATCH_WRONG_FILE );
  2718. }
  2719. }
  2720. }
  2721. }
  2722. DestroySubAllocator( SubAllocator );
  2723. }
  2724. }
  2725. else {
  2726. SetLastError( ERROR_PATCH_CORRUPT );
  2727. }
  2728. UnmapViewOfFile( PatchFileMapped );
  2729. }
  2730. if (( ! Success ) &&
  2731. ( GetLastError() == ERROR_SUCCESS )) {
  2732. SetLastError( ERROR_EXTENDED_ERROR );
  2733. }
  2734. return Success;
  2735. }
  2736. BOOL
  2737. PATCHAPI
  2738. TestApplyPatchToFileByHandles(
  2739. IN HANDLE PatchFileHandle, // requires GENERIC_READ access
  2740. IN HANDLE OldFileHandle, // requires GENERIC_READ access
  2741. IN ULONG ApplyOptionFlags
  2742. )
  2743. {
  2744. return ApplyPatchToFileByHandles(
  2745. PatchFileHandle,
  2746. OldFileHandle,
  2747. INVALID_HANDLE_VALUE,
  2748. ApplyOptionFlags | APPLY_OPTION_TEST_ONLY
  2749. );
  2750. }
  2751. BOOL
  2752. PATCHAPI
  2753. ApplyPatchToFileByHandles(
  2754. IN HANDLE PatchFileHandle, // requires GENERIC_READ access
  2755. IN HANDLE OldFileHandle, // requires GENERIC_READ access
  2756. OUT HANDLE NewFileHandle, // requires GENERIC_READ | GENERIC_WRITE
  2757. IN ULONG ApplyOptionFlags
  2758. )
  2759. {
  2760. return ApplyPatchToFileByHandlesEx(
  2761. PatchFileHandle,
  2762. OldFileHandle,
  2763. NewFileHandle,
  2764. ApplyOptionFlags,
  2765. NULL,
  2766. NULL
  2767. );
  2768. }
  2769. BOOL
  2770. PATCHAPI
  2771. TestApplyPatchToFileA(
  2772. IN LPCSTR PatchFileName,
  2773. IN LPCSTR OldFileName,
  2774. IN ULONG ApplyOptionFlags
  2775. )
  2776. {
  2777. return ApplyPatchToFileA(
  2778. PatchFileName,
  2779. OldFileName,
  2780. INVALID_HANDLE_VALUE,
  2781. ApplyOptionFlags | APPLY_OPTION_TEST_ONLY
  2782. );
  2783. }
  2784. BOOL
  2785. PATCHAPI
  2786. ApplyPatchToFileA(
  2787. IN LPCSTR PatchFileName,
  2788. IN LPCSTR OldFileName,
  2789. OUT LPCSTR NewFileName,
  2790. IN ULONG ApplyOptionFlags
  2791. )
  2792. {
  2793. return ApplyPatchToFileExA(
  2794. PatchFileName,
  2795. OldFileName,
  2796. NewFileName,
  2797. ApplyOptionFlags,
  2798. NULL,
  2799. NULL
  2800. );
  2801. }
  2802. BOOL
  2803. PATCHAPI
  2804. ApplyPatchToFileExA(
  2805. IN LPCSTR PatchFileName,
  2806. IN LPCSTR OldFileName,
  2807. OUT LPCSTR NewFileName,
  2808. IN ULONG ApplyOptionFlags,
  2809. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2810. IN PVOID CallbackContext
  2811. )
  2812. {
  2813. HANDLE PatchFileHandle;
  2814. HANDLE OldFileHandle;
  2815. HANDLE NewFileHandle;
  2816. BOOL Success = FALSE;
  2817. PatchFileHandle = CreateFileA(
  2818. PatchFileName,
  2819. GENERIC_READ,
  2820. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2821. NULL,
  2822. OPEN_EXISTING,
  2823. FILE_FLAG_SEQUENTIAL_SCAN,
  2824. NULL
  2825. );
  2826. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  2827. OldFileHandle = CreateFileA(
  2828. OldFileName,
  2829. GENERIC_READ,
  2830. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2831. NULL,
  2832. OPEN_EXISTING,
  2833. FILE_FLAG_SEQUENTIAL_SCAN,
  2834. NULL
  2835. );
  2836. if ( OldFileHandle != INVALID_HANDLE_VALUE ) {
  2837. NewFileHandle = CreateFileA(
  2838. NewFileName,
  2839. GENERIC_READ | GENERIC_WRITE,
  2840. FILE_SHARE_READ,
  2841. NULL,
  2842. CREATE_ALWAYS,
  2843. FILE_ATTRIBUTE_NORMAL,
  2844. NULL
  2845. );
  2846. if ( NewFileHandle != INVALID_HANDLE_VALUE ) {
  2847. Success = ApplyPatchToFileByHandlesEx(
  2848. PatchFileHandle,
  2849. OldFileHandle,
  2850. NewFileHandle,
  2851. ApplyOptionFlags,
  2852. ProgressCallback,
  2853. CallbackContext
  2854. );
  2855. CloseHandle( NewFileHandle );
  2856. if ( ! Success ) {
  2857. DeleteFileA( NewFileName );
  2858. }
  2859. }
  2860. CloseHandle( OldFileHandle );
  2861. }
  2862. CloseHandle( PatchFileHandle );
  2863. }
  2864. return Success;
  2865. }
  2866. BOOL
  2867. PATCHAPI
  2868. TestApplyPatchToFileW(
  2869. IN LPCWSTR PatchFileName,
  2870. IN LPCWSTR OldFileName,
  2871. IN ULONG ApplyOptionFlags
  2872. )
  2873. {
  2874. return ApplyPatchToFileW(
  2875. PatchFileName,
  2876. OldFileName,
  2877. INVALID_HANDLE_VALUE,
  2878. ApplyOptionFlags | APPLY_OPTION_TEST_ONLY
  2879. );
  2880. }
  2881. BOOL
  2882. PATCHAPI
  2883. ApplyPatchToFileW(
  2884. IN LPCWSTR PatchFileName,
  2885. IN LPCWSTR OldFileName,
  2886. OUT LPCWSTR NewFileName,
  2887. IN ULONG ApplyOptionFlags
  2888. )
  2889. {
  2890. return ApplyPatchToFileExW(
  2891. PatchFileName,
  2892. OldFileName,
  2893. NewFileName,
  2894. ApplyOptionFlags,
  2895. NULL,
  2896. NULL
  2897. );
  2898. }
  2899. BOOL
  2900. PATCHAPI
  2901. ApplyPatchToFileExW(
  2902. IN LPCWSTR PatchFileName,
  2903. IN LPCWSTR OldFileName,
  2904. OUT LPCWSTR NewFileName,
  2905. IN ULONG ApplyOptionFlags,
  2906. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2907. IN PVOID CallbackContext
  2908. )
  2909. {
  2910. HANDLE PatchFileHandle;
  2911. HANDLE OldFileHandle;
  2912. HANDLE NewFileHandle;
  2913. BOOL Success = FALSE;
  2914. PatchFileHandle = CreateFileW(
  2915. PatchFileName,
  2916. GENERIC_READ,
  2917. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2918. NULL,
  2919. OPEN_EXISTING,
  2920. FILE_FLAG_SEQUENTIAL_SCAN,
  2921. NULL
  2922. );
  2923. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  2924. OldFileHandle = CreateFileW(
  2925. OldFileName,
  2926. GENERIC_READ,
  2927. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2928. NULL,
  2929. OPEN_EXISTING,
  2930. FILE_FLAG_SEQUENTIAL_SCAN,
  2931. NULL
  2932. );
  2933. if ( OldFileHandle != INVALID_HANDLE_VALUE ) {
  2934. NewFileHandle = CreateFileW(
  2935. NewFileName,
  2936. GENERIC_READ | GENERIC_WRITE,
  2937. FILE_SHARE_READ,
  2938. NULL,
  2939. CREATE_ALWAYS,
  2940. FILE_ATTRIBUTE_NORMAL,
  2941. NULL
  2942. );
  2943. if ( NewFileHandle != INVALID_HANDLE_VALUE ) {
  2944. Success = ApplyPatchToFileByHandlesEx(
  2945. PatchFileHandle,
  2946. OldFileHandle,
  2947. NewFileHandle,
  2948. ApplyOptionFlags,
  2949. ProgressCallback,
  2950. CallbackContext
  2951. );
  2952. CloseHandle( NewFileHandle );
  2953. if ( ! Success ) {
  2954. DeleteFileW( NewFileName );
  2955. }
  2956. }
  2957. CloseHandle( OldFileHandle );
  2958. }
  2959. CloseHandle( PatchFileHandle );
  2960. }
  2961. return Success;
  2962. }
  2963. #endif // ! PATCH_CREATE_CODE_ONLY