Source code of Windows XP (NT5)
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.

3777 lines
130 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;
  1046. HANDLE PatchFileHandle;
  1047. HANDLE NewFileHandle;
  1048. BOOL Success;
  1049. ULONG i;
  1050. OldFileInfoByHandle = _alloca( OldFileCount * sizeof( PATCH_OLD_FILE_INFO_H ));
  1051. ZeroMemory( OldFileInfoByHandle, OldFileCount * sizeof( PATCH_OLD_FILE_INFO_H ));
  1052. if ( OldFileCount == 0 ) {
  1053. SetLastError( ERROR_INVALID_PARAMETER );
  1054. return FALSE;
  1055. }
  1056. Success = TRUE;
  1057. for ( i = 0; i < OldFileCount; i++ ) {
  1058. OldFileInfoByHandle[ i ].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO_H );
  1059. OldFileInfoByHandle[ i ].IgnoreRangeCount = OldFileInfoArray[ i ].IgnoreRangeCount;
  1060. OldFileInfoByHandle[ i ].IgnoreRangeArray = OldFileInfoArray[ i ].IgnoreRangeArray;
  1061. OldFileInfoByHandle[ i ].RetainRangeCount = OldFileInfoArray[ i ].RetainRangeCount;
  1062. OldFileInfoByHandle[ i ].RetainRangeArray = OldFileInfoArray[ i ].RetainRangeArray;
  1063. OldFileInfoByHandle[ i ].OldFileHandle = CreateFileA(
  1064. OldFileInfoArray[ i ].OldFileName,
  1065. GENERIC_READ,
  1066. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1067. NULL,
  1068. OPEN_EXISTING,
  1069. FILE_FLAG_SEQUENTIAL_SCAN,
  1070. NULL
  1071. );
  1072. if ( OldFileInfoByHandle[ i ].OldFileHandle == INVALID_HANDLE_VALUE ) {
  1073. Success = FALSE;
  1074. break;
  1075. }
  1076. }
  1077. if ( Success ) {
  1078. Success = FALSE;
  1079. NewFileHandle = CreateFileA(
  1080. NewFileName,
  1081. GENERIC_READ,
  1082. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1083. NULL,
  1084. OPEN_EXISTING,
  1085. FILE_FLAG_SEQUENTIAL_SCAN,
  1086. NULL
  1087. );
  1088. if ( NewFileHandle != INVALID_HANDLE_VALUE ) {
  1089. PatchFileHandle = CreateFileA(
  1090. PatchFileName,
  1091. GENERIC_READ | GENERIC_WRITE,
  1092. FILE_SHARE_READ,
  1093. NULL,
  1094. CREATE_ALWAYS,
  1095. FILE_ATTRIBUTE_NORMAL,
  1096. NULL
  1097. );
  1098. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  1099. Success = CreatePatchFileByHandlesEx(
  1100. OldFileCount,
  1101. OldFileInfoByHandle,
  1102. NewFileHandle,
  1103. PatchFileHandle,
  1104. OptionFlags,
  1105. OptionData,
  1106. ProgressCallback,
  1107. CallbackContext
  1108. );
  1109. CloseHandle( PatchFileHandle );
  1110. if ( ! Success ) {
  1111. DeleteFileA( PatchFileName );
  1112. }
  1113. }
  1114. CloseHandle( NewFileHandle );
  1115. }
  1116. }
  1117. for ( i = 0; i < OldFileCount; i++ ) {
  1118. if (( OldFileInfoByHandle[ i ].OldFileHandle != NULL ) &&
  1119. ( OldFileInfoByHandle[ i ].OldFileHandle != INVALID_HANDLE_VALUE )) {
  1120. CloseHandle( OldFileInfoByHandle[ i ].OldFileHandle );
  1121. }
  1122. }
  1123. return Success;
  1124. }
  1125. BOOL
  1126. PATCHAPI
  1127. CreatePatchFileExW(
  1128. IN ULONG OldFileCount,
  1129. IN PPATCH_OLD_FILE_INFO_W OldFileInfoArray,
  1130. IN LPCWSTR NewFileName,
  1131. OUT LPCWSTR PatchFileName,
  1132. IN ULONG OptionFlags,
  1133. IN PPATCH_OPTION_DATA OptionData, // optional
  1134. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  1135. IN PVOID CallbackContext
  1136. )
  1137. {
  1138. PPATCH_OLD_FILE_INFO_H OldFileInfoByHandle;
  1139. HANDLE PatchFileHandle;
  1140. HANDLE NewFileHandle;
  1141. BOOL Success;
  1142. ULONG i;
  1143. OldFileInfoByHandle = _alloca( OldFileCount * sizeof( PATCH_OLD_FILE_INFO_H ));
  1144. ZeroMemory( OldFileInfoByHandle, OldFileCount * sizeof( PATCH_OLD_FILE_INFO_H ));
  1145. if ( OldFileCount == 0 ) {
  1146. SetLastError( ERROR_INVALID_PARAMETER );
  1147. return FALSE;
  1148. }
  1149. Success = TRUE;
  1150. for ( i = 0; i < OldFileCount; i++ ) {
  1151. OldFileInfoByHandle[ i ].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO_H );
  1152. OldFileInfoByHandle[ i ].IgnoreRangeCount = OldFileInfoArray[ i ].IgnoreRangeCount;
  1153. OldFileInfoByHandle[ i ].IgnoreRangeArray = OldFileInfoArray[ i ].IgnoreRangeArray;
  1154. OldFileInfoByHandle[ i ].RetainRangeCount = OldFileInfoArray[ i ].RetainRangeCount;
  1155. OldFileInfoByHandle[ i ].RetainRangeArray = OldFileInfoArray[ i ].RetainRangeArray;
  1156. OldFileInfoByHandle[ i ].OldFileHandle = CreateFileW(
  1157. OldFileInfoArray[ i ].OldFileName,
  1158. GENERIC_READ,
  1159. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1160. NULL,
  1161. OPEN_EXISTING,
  1162. FILE_FLAG_SEQUENTIAL_SCAN,
  1163. NULL
  1164. );
  1165. if ( OldFileInfoByHandle[ i ].OldFileHandle == INVALID_HANDLE_VALUE ) {
  1166. Success = FALSE;
  1167. break;
  1168. }
  1169. }
  1170. if ( Success ) {
  1171. Success = FALSE;
  1172. NewFileHandle = CreateFileW(
  1173. NewFileName,
  1174. GENERIC_READ,
  1175. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1176. NULL,
  1177. OPEN_EXISTING,
  1178. FILE_FLAG_SEQUENTIAL_SCAN,
  1179. NULL
  1180. );
  1181. if ( NewFileHandle != INVALID_HANDLE_VALUE ) {
  1182. PatchFileHandle = CreateFileW(
  1183. PatchFileName,
  1184. GENERIC_READ | GENERIC_WRITE,
  1185. FILE_SHARE_READ,
  1186. NULL,
  1187. CREATE_ALWAYS,
  1188. FILE_ATTRIBUTE_NORMAL,
  1189. NULL
  1190. );
  1191. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  1192. Success = CreatePatchFileByHandlesEx(
  1193. OldFileCount,
  1194. OldFileInfoByHandle,
  1195. NewFileHandle,
  1196. PatchFileHandle,
  1197. OptionFlags,
  1198. OptionData,
  1199. ProgressCallback,
  1200. CallbackContext
  1201. );
  1202. CloseHandle( PatchFileHandle );
  1203. if ( ! Success ) {
  1204. DeleteFileW( PatchFileName );
  1205. }
  1206. }
  1207. CloseHandle( NewFileHandle );
  1208. }
  1209. }
  1210. for ( i = 0; i < OldFileCount; i++ ) {
  1211. if (( OldFileInfoByHandle[ i ].OldFileHandle != NULL ) &&
  1212. ( OldFileInfoByHandle[ i ].OldFileHandle != INVALID_HANDLE_VALUE )) {
  1213. CloseHandle( OldFileInfoByHandle[ i ].OldFileHandle );
  1214. }
  1215. }
  1216. return Success;
  1217. }
  1218. BOOL
  1219. PATCHAPI
  1220. CreatePatchFileByHandlesEx(
  1221. IN ULONG OldFileCount,
  1222. IN PPATCH_OLD_FILE_INFO_H OldFileInfoArray,
  1223. IN HANDLE NewFileHandle,
  1224. OUT HANDLE PatchFileHandle,
  1225. IN ULONG OptionFlags,
  1226. IN PPATCH_OPTION_DATA OptionData, // optional
  1227. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  1228. IN PVOID CallbackContext
  1229. )
  1230. {
  1231. PATCH_HEADER_INFO HeaderInfo;
  1232. UP_IMAGE_NT_HEADERS32 NtHeader;
  1233. UP_IMAGE_NT_HEADERS32 OldFileNtHeader;
  1234. PPATCH_DATA PatchArray;
  1235. PFILETIME PatchFileTime;
  1236. FILETIME NewFileTime;
  1237. PUCHAR NewFileMapped;
  1238. ULONG NewFileSize;
  1239. ULONG NewFileCrc;
  1240. ULONG NewFileCoffBase;
  1241. ULONG NewFileCoffTime;
  1242. ULONG NewFileResTime;
  1243. ULONG NewFileCompressedSize;
  1244. PUCHAR OldFileMapped;
  1245. ULONG OldFileSize;
  1246. ULONG OldFileCrc;
  1247. PUCHAR PatchFileMapped;
  1248. PUCHAR PatchBuffer;
  1249. ULONG PatchBufferSize;
  1250. PUCHAR PatchAltBuffer;
  1251. ULONG PatchAltSize;
  1252. ULONG PatchDataSize;
  1253. ULONG PatchFileCrc;
  1254. ULONG HeaderSize;
  1255. ULONG HeaderOldFileCount;
  1256. ULONG ProgressPosition;
  1257. ULONG ProgressMaximum;
  1258. ULONG ErrorCode;
  1259. BOOL TryLzxBoth;
  1260. BOOL Success;
  1261. BOOL Transform;
  1262. HANDLE SubAllocatorHandle;
  1263. ULONG EstimatedLzxMemory;
  1264. ULONG ExtendedOptionFlags;
  1265. ULONG AltExtendedOptionFlags;
  1266. ULONG OldFileOriginalChecksum;
  1267. ULONG OldFileOriginalTimeDate;
  1268. ULONG i, j;
  1269. PUCHAR p;
  1270. ULONG LargestOldFileSize = 0;
  1271. HeaderInfo.OldFileInfoArray = _alloca( OldFileCount * sizeof( HEADER_OLD_FILE_INFO ));
  1272. PatchArray = _alloca( OldFileCount * sizeof( PATCH_DATA ));
  1273. ZeroMemory( HeaderInfo.OldFileInfoArray, OldFileCount * sizeof( HEADER_OLD_FILE_INFO ));
  1274. ZeroMemory( PatchArray, OldFileCount * sizeof( PATCH_DATA ));
  1275. if (( OldFileCount == 0 ) || ( OldFileCount > 127 )) {
  1276. SetLastError( ERROR_INVALID_PARAMETER );
  1277. return FALSE;
  1278. }
  1279. if ( OptionFlags & PATCH_OPTION_SIGNATURE_MD5 ) {
  1280. SetLastError( ERROR_INVALID_PARAMETER );
  1281. return FALSE;
  1282. }
  1283. if (( OptionFlags & 0x0000FFFF ) == PATCH_OPTION_USE_BEST ) {
  1284. OptionFlags |= PATCH_OPTION_USE_LZX_BEST;
  1285. }
  1286. for ( i = 1; i < OldFileCount; i++ ) {
  1287. if ( OldFileInfoArray[ i ].RetainRangeCount != OldFileInfoArray[ 0 ].RetainRangeCount ) {
  1288. SetLastError( ERROR_PATCH_RETAIN_RANGES_DIFFER );
  1289. return FALSE;
  1290. }
  1291. for ( j = 0; j < OldFileInfoArray[ 0 ].RetainRangeCount; j++ ) {
  1292. if (( OldFileInfoArray[ i ].RetainRangeArray[ j ].OffsetInNewFile !=
  1293. OldFileInfoArray[ 0 ].RetainRangeArray[ j ].OffsetInNewFile ) ||
  1294. ( OldFileInfoArray[ i ].RetainRangeArray[ j ].LengthInBytes !=
  1295. OldFileInfoArray[ 0 ].RetainRangeArray[ j ].LengthInBytes )) {
  1296. SetLastError( ERROR_PATCH_RETAIN_RANGES_DIFFER );
  1297. return FALSE;
  1298. }
  1299. }
  1300. }
  1301. ExtendedOptionFlags = 0;
  1302. if (( OptionData ) && ( OptionData->SizeOfThisStruct >= sizeof( PATCH_OPTION_DATA ))) {
  1303. ExtendedOptionFlags = OptionData->ExtendedOptionFlags;
  1304. }
  1305. Success = MyMapViewOfFileByHandle(
  1306. NewFileHandle,
  1307. &NewFileSize,
  1308. &NewFileMapped
  1309. );
  1310. if ( ! Success ) {
  1311. if ( GetLastError() == ERROR_SUCCESS ) {
  1312. SetLastError( ERROR_EXTENDED_ERROR );
  1313. }
  1314. return FALSE;
  1315. }
  1316. GetFileTime( NewFileHandle, NULL, NULL, &NewFileTime );
  1317. PatchFileTime = &NewFileTime;
  1318. NewFileCoffBase = 0;
  1319. NewFileCoffTime = 0;
  1320. NewFileResTime = 0;
  1321. HeaderOldFileCount = 0;
  1322. HeaderSize = 0;
  1323. NewFileCrc = 0; // prevent compiler warning
  1324. ProgressPosition = 0;
  1325. ProgressMaximum = 0; // prevent compiler warning
  1326. __try {
  1327. NtHeader = GetNtHeader( NewFileMapped, NewFileSize );
  1328. if ( ! ( OptionFlags & PATCH_OPTION_NO_REBASE )) {
  1329. if ( NtHeader ) {
  1330. NewFileCoffTime = NtHeader->FileHeader.TimeDateStamp;
  1331. NewFileCoffBase = NtHeader->OptionalHeader.ImageBase;
  1332. }
  1333. else {
  1334. OptionFlags |= PATCH_OPTION_NO_REBASE;
  1335. }
  1336. }
  1337. if (( NtHeader ) && ( NtHeader->OptionalHeader.CheckSum == 0 )) {
  1338. OptionFlags |= PATCH_OPTION_NO_CHECKSUM;
  1339. }
  1340. if ( ! ( OptionFlags & PATCH_OPTION_NO_RESTIMEFIX )) {
  1341. if ( NtHeader ) {
  1342. UP_IMAGE_RESOURCE_DIRECTORY ResDir;
  1343. ResDir = ImageDirectoryMappedAddress(
  1344. NtHeader,
  1345. IMAGE_DIRECTORY_ENTRY_RESOURCE,
  1346. NULL,
  1347. NewFileMapped,
  1348. NewFileSize
  1349. );
  1350. if ( ResDir ) {
  1351. NewFileResTime = ResDir->TimeDateStamp;
  1352. }
  1353. }
  1354. if ( NewFileResTime == 0 ) {
  1355. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  1356. }
  1357. }
  1358. TryLzxBoth = FALSE;
  1359. if (( OptionFlags & PATCH_OPTION_USE_LZX_BEST ) == PATCH_OPTION_USE_LZX_BEST ) {
  1360. OptionFlags &= ~PATCH_OPTION_USE_LZX_B; // No E8 translation on first try.
  1361. if ((( ! NtHeader ) && ( *(UNALIGNED USHORT *)NewFileMapped == 0x5A4D )) || // MZ, not PE
  1362. (( NtHeader ) && ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ))) { // PE, i386
  1363. TryLzxBoth = TRUE; // Will force E8 translation on second try.
  1364. }
  1365. }
  1366. else if (( OptionFlags & PATCH_OPTION_USE_LZX_BEST ) == PATCH_OPTION_USE_LZX_B ) {
  1367. //
  1368. // Caller is requesting forced E8 translation, so disable E8
  1369. // transformation.
  1370. //
  1371. if (( NtHeader ) && ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 )) { // PE, i386
  1372. ExtendedOptionFlags |= PATCH_TRANSFORM_NO_RELCALLS;
  1373. }
  1374. }
  1375. ProgressMaximum = NewFileSize * OldFileCount;
  1376. for ( i = 0; i < OldFileCount; i++ ) {
  1377. OldFileSize = GetFileSize( OldFileInfoArray[ i ].OldFileHandle, NULL );
  1378. if ( LargestOldFileSize < OldFileSize ) {
  1379. LargestOldFileSize = OldFileSize;
  1380. }
  1381. ProgressMaximum += LzxInsertSize( OldFileSize, OptionFlags );
  1382. }
  1383. if ( TryLzxBoth ) {
  1384. ProgressMaximum *= 2;
  1385. }
  1386. if ( OptionFlags & PATCH_OPTION_FAIL_IF_BIGGER ) {
  1387. ProgressMaximum += NewFileSize;
  1388. }
  1389. Success = ProgressCallbackWrapper(
  1390. ProgressCallback,
  1391. CallbackContext,
  1392. 0,
  1393. ProgressMaximum
  1394. );
  1395. if ( ! Success ) {
  1396. __leave;
  1397. }
  1398. for ( j = 0; j < OldFileInfoArray[ 0 ].RetainRangeCount; j++ ) {
  1399. ZeroMemory(
  1400. OldFileInfoArray[ 0 ].RetainRangeArray[ j ].OffsetInNewFile + NewFileMapped,
  1401. OldFileInfoArray[ 0 ].RetainRangeArray[ j ].LengthInBytes
  1402. );
  1403. }
  1404. NewFileCrc = Crc32( 0xFFFFFFFF, NewFileMapped, NewFileSize ) ^ 0xFFFFFFFF;
  1405. PatchBufferSize = ROUNDUP2( NewFileSize + ( NewFileSize / 256 ), 0x10000 );
  1406. Success = FALSE;
  1407. for ( i = 0; i < OldFileCount; i++ ) {
  1408. Success = MyMapViewOfFileByHandle(
  1409. OldFileInfoArray[ i ].OldFileHandle,
  1410. &OldFileSize,
  1411. &OldFileMapped
  1412. );
  1413. if ( ! Success ) {
  1414. break;
  1415. }
  1416. OldFileOriginalChecksum = 0;
  1417. OldFileOriginalTimeDate = 0;
  1418. OldFileNtHeader = NULL;
  1419. __try {
  1420. OldFileNtHeader = GetNtHeader( OldFileMapped, OldFileSize );
  1421. if ( OldFileNtHeader ) {
  1422. OldFileOriginalChecksum = OldFileNtHeader->OptionalHeader.CheckSum;
  1423. OldFileOriginalTimeDate = OldFileNtHeader->FileHeader.TimeDateStamp;
  1424. }
  1425. }
  1426. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1427. }
  1428. Success = NormalizeOldFileImageForPatching(
  1429. OldFileMapped,
  1430. OldFileSize,
  1431. OptionFlags,
  1432. OptionData,
  1433. NewFileCoffBase,
  1434. NewFileCoffTime,
  1435. OldFileInfoArray[ i ].IgnoreRangeCount,
  1436. OldFileInfoArray[ i ].IgnoreRangeArray,
  1437. OldFileInfoArray[ i ].RetainRangeCount,
  1438. OldFileInfoArray[ i ].RetainRangeArray
  1439. );
  1440. if ( Success ) {
  1441. Success = SafeCompleteCrc32( OldFileMapped, OldFileSize, &OldFileCrc );
  1442. if ( Success ) {
  1443. //
  1444. // First determine if this old file is the same as any already
  1445. // processed old files.
  1446. //
  1447. Success = FALSE;
  1448. for ( j = 0; j < HeaderOldFileCount; j++ ) {
  1449. if (( HeaderInfo.OldFileInfoArray[ j ].OldFileCrc == OldFileCrc ) &&
  1450. ( HeaderInfo.OldFileInfoArray[ j ].OldFileSize == OldFileSize )) {
  1451. //
  1452. // We have to remap the other old file here to make the
  1453. // comparison.
  1454. //
  1455. PUCHAR CompareFileMapped;
  1456. ULONG CompareFileSize;
  1457. Success = MyMapViewOfFileByHandle(
  1458. HeaderInfo.OldFileInfoArray[ j ].OldFileHandle,
  1459. &CompareFileSize,
  1460. &CompareFileMapped
  1461. );
  1462. if ( Success ) {
  1463. ASSERT( CompareFileSize == HeaderInfo.OldFileInfoArray[ j ].OldFileSize );
  1464. NormalizeOldFileImageForPatching(
  1465. CompareFileMapped,
  1466. CompareFileSize,
  1467. OptionFlags,
  1468. OptionData,
  1469. NewFileCoffBase,
  1470. NewFileCoffTime,
  1471. HeaderInfo.OldFileInfoArray[ j ].IgnoreRangeCount,
  1472. HeaderInfo.OldFileInfoArray[ j ].IgnoreRangeArray,
  1473. HeaderInfo.OldFileInfoArray[ j ].RetainRangeCount,
  1474. HeaderInfo.OldFileInfoArray[ j ].RetainRangeArray
  1475. );
  1476. __try {
  1477. Success = ( memcmp( CompareFileMapped, OldFileMapped, OldFileSize ) == 0 );
  1478. }
  1479. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1480. SetLastError( GetExceptionCode() );
  1481. Success = FALSE;
  1482. }
  1483. UnmapViewOfFile( CompareFileMapped );
  1484. if ( Success ) {
  1485. break;
  1486. }
  1487. }
  1488. }
  1489. }
  1490. if ( ! Success ) {
  1491. //
  1492. // Now see if old file is same as new file.
  1493. //
  1494. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryAlloc = 0;
  1495. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount = 0;
  1496. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryArray = NULL;
  1497. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftUsageArray = NULL;
  1498. PatchBuffer = NULL;
  1499. PatchDataSize = 0;
  1500. if (( NewFileCrc == OldFileCrc ) && ( NewFileSize == OldFileSize )) {
  1501. __try {
  1502. Success = ( memcmp( NewFileMapped, OldFileMapped, NewFileSize ) == 0 );
  1503. }
  1504. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1505. SetLastError( GetExceptionCode() );
  1506. Success = FALSE;
  1507. }
  1508. }
  1509. if ( ! Success ) {
  1510. //
  1511. // It's a unique file, so create the patch for it.
  1512. //
  1513. // First we need to apply the transforms.
  1514. //
  1515. Transform = TRUE;
  1516. //
  1517. // NOTE: This test for NtHeader is a perf tweak
  1518. // for non-coff files. If we ever have any
  1519. // transformations for non-coff files, this
  1520. // test should be removed.
  1521. //
  1522. if (( NtHeader ) && ( OldFileNtHeader )) {
  1523. //
  1524. // See if rift table already provided by
  1525. // caller so we don't need to generate it.
  1526. //
  1527. if (( OptionData ) &&
  1528. ( OptionData->SizeOfThisStruct >= sizeof( PATCH_OPTION_DATA )) &&
  1529. ( OptionData->SymbolOptionFlags & PATCH_SYMBOL_EXTERNAL_RIFT ) &&
  1530. ( OptionData->OldFileSymbolPathArray ) &&
  1531. ( OptionData->OldFileSymbolPathArray[ i ] )) {
  1532. //
  1533. // This hidden private flag that tells us the rift information
  1534. // is already specified for us. The LPCSTR pointer at
  1535. // OptionData->OldFileSymbolPathArray[ i ] is really a
  1536. // PRIFT_TABLE pointer. Note that no validation of external
  1537. // rift data is performed (must be in ascending order with
  1538. // no OldRva duplicates).
  1539. //
  1540. // We need to be careful to treat this external rift table
  1541. // differently in that we don't want to free the arrays
  1542. // like we do for our internally allocated rift tables.
  1543. // So, mark the RiftEntryAlloc field as zero to indicate
  1544. // that the rift arrays were not internally allocated.
  1545. //
  1546. PRIFT_TABLE ExternalRiftTable = (PVOID) OptionData->OldFileSymbolPathArray[ i ];
  1547. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryAlloc = 0;
  1548. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount = ExternalRiftTable->RiftEntryCount;
  1549. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryArray = ExternalRiftTable->RiftEntryArray;
  1550. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftUsageArray = ExternalRiftTable->RiftUsageArray;
  1551. }
  1552. else {
  1553. //
  1554. // Need to allocate rift arrays and generate rift data.
  1555. // This (NewSize+OldSize)/sizeof(RIFT) allocation will
  1556. // provide enough space for one rift entry for every
  1557. // four bytes in the files.
  1558. //
  1559. ULONG AllocCount = ( NewFileSize + OldFileSize ) / sizeof( RIFT_ENTRY );
  1560. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount = 0;
  1561. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryAlloc = AllocCount;
  1562. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryArray = MyVirtualAlloc( AllocCount * sizeof( RIFT_ENTRY ));
  1563. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftUsageArray = MyVirtualAlloc( AllocCount * sizeof( UCHAR ));
  1564. if (( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryArray == NULL ) ||
  1565. ( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftUsageArray == NULL )) {
  1566. Transform = FALSE;
  1567. }
  1568. else {
  1569. Transform = GenerateRiftTable(
  1570. OldFileInfoArray[ i ].OldFileHandle,
  1571. OldFileMapped,
  1572. OldFileSize,
  1573. OldFileOriginalChecksum,
  1574. OldFileOriginalTimeDate,
  1575. NewFileHandle,
  1576. NewFileMapped,
  1577. NewFileSize,
  1578. OptionFlags,
  1579. OptionData,
  1580. i,
  1581. &HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable
  1582. );
  1583. ASSERT( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount <= HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryAlloc );
  1584. #ifdef TESTCODE
  1585. printf( "\r%9d unique rift entries generated\n", HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount );
  1586. #endif
  1587. }
  1588. }
  1589. if ( Transform ) {
  1590. if ( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount != 0 ) {
  1591. Transform = TransformOldFileImageForPatching(
  1592. ExtendedOptionFlags,
  1593. OldFileMapped,
  1594. OldFileSize,
  1595. NewFileResTime,
  1596. &HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable
  1597. );
  1598. }
  1599. }
  1600. }
  1601. if ( Transform ) {
  1602. PatchBuffer = MyVirtualAlloc( PatchBufferSize );
  1603. if ( PatchBuffer != NULL ) {
  1604. EstimatedLzxMemory = EstimateLzxCompressionMemoryRequirement(
  1605. OldFileSize,
  1606. NewFileSize,
  1607. OptionFlags
  1608. );
  1609. SubAllocatorHandle = CreateSubAllocator(
  1610. EstimatedLzxMemory,
  1611. MINIMUM_VM_ALLOCATION
  1612. );
  1613. if ( SubAllocatorHandle != NULL ) {
  1614. __try {
  1615. ErrorCode = CreateRawLzxPatchDataFromBuffers(
  1616. OldFileMapped,
  1617. OldFileSize,
  1618. NewFileMapped,
  1619. NewFileSize,
  1620. PatchBufferSize,
  1621. PatchBuffer,
  1622. &PatchDataSize,
  1623. OptionFlags,
  1624. OptionData,
  1625. SubAllocate,
  1626. SubAllocatorHandle,
  1627. ProgressCallback,
  1628. CallbackContext,
  1629. ProgressPosition,
  1630. ProgressMaximum
  1631. );
  1632. }
  1633. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1634. ErrorCode = GetExceptionCode();
  1635. }
  1636. DestroySubAllocator( SubAllocatorHandle );
  1637. if ( ErrorCode == NO_ERROR ) {
  1638. Success = TRUE;
  1639. if ( TryLzxBoth ) {
  1640. AltExtendedOptionFlags = ExtendedOptionFlags;
  1641. if (( NtHeader ) && ( ! ( AltExtendedOptionFlags | PATCH_TRANSFORM_NO_RELCALLS ))) {
  1642. //
  1643. // Need to map, normalize, and transform
  1644. // old file again without E8 transform.
  1645. //
  1646. AltExtendedOptionFlags |= PATCH_TRANSFORM_NO_RELCALLS;
  1647. UnmapViewOfFile( OldFileMapped );
  1648. OldFileMapped = NULL;
  1649. Success = MyMapViewOfFileByHandle(
  1650. OldFileInfoArray[ i ].OldFileHandle,
  1651. &OldFileSize,
  1652. &OldFileMapped
  1653. );
  1654. if ( Success ) {
  1655. Success = NormalizeOldFileImageForPatching(
  1656. OldFileMapped,
  1657. OldFileSize,
  1658. OptionFlags,
  1659. OptionData,
  1660. NewFileCoffBase,
  1661. NewFileCoffTime,
  1662. OldFileInfoArray[ i ].IgnoreRangeCount,
  1663. OldFileInfoArray[ i ].IgnoreRangeArray,
  1664. OldFileInfoArray[ i ].RetainRangeCount,
  1665. OldFileInfoArray[ i ].RetainRangeArray
  1666. );
  1667. if ( Success ) {
  1668. if ( HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount != 0 ) {
  1669. Success = TransformOldFileImageForPatching(
  1670. AltExtendedOptionFlags,
  1671. OldFileMapped,
  1672. OldFileSize,
  1673. NewFileResTime,
  1674. &HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable
  1675. );
  1676. }
  1677. }
  1678. }
  1679. }
  1680. if ( Success ) {
  1681. PatchAltBuffer = MyVirtualAlloc( PatchBufferSize );
  1682. if ( PatchAltBuffer != NULL ) {
  1683. SubAllocatorHandle = CreateSubAllocator(
  1684. EstimatedLzxMemory,
  1685. MINIMUM_VM_ALLOCATION
  1686. );
  1687. if ( SubAllocatorHandle != NULL ) {
  1688. PatchAltSize = 0; // prevent compiler warning
  1689. __try {
  1690. ErrorCode = CreateRawLzxPatchDataFromBuffers(
  1691. OldFileMapped,
  1692. OldFileSize,
  1693. NewFileMapped,
  1694. NewFileSize,
  1695. PatchBufferSize,
  1696. PatchAltBuffer,
  1697. &PatchAltSize,
  1698. OptionFlags | PATCH_OPTION_USE_LZX_B,
  1699. OptionData,
  1700. SubAllocate,
  1701. SubAllocatorHandle,
  1702. ProgressCallback,
  1703. CallbackContext,
  1704. ProgressPosition + NewFileSize + LzxInsertSize( OldFileSize, OptionFlags ),
  1705. ProgressMaximum
  1706. );
  1707. }
  1708. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1709. ErrorCode = GetExceptionCode();
  1710. }
  1711. DestroySubAllocator( SubAllocatorHandle );
  1712. if (( ErrorCode == NO_ERROR ) && ( PatchAltSize <= PatchDataSize )) {
  1713. MyVirtualFree( PatchBuffer );
  1714. PatchBuffer = PatchAltBuffer;
  1715. PatchDataSize = PatchAltSize;
  1716. ExtendedOptionFlags = AltExtendedOptionFlags;
  1717. }
  1718. else {
  1719. MyVirtualFree( PatchAltBuffer );
  1720. }
  1721. }
  1722. }
  1723. }
  1724. }
  1725. }
  1726. else {
  1727. SetLastError( ErrorCode );
  1728. }
  1729. }
  1730. }
  1731. }
  1732. }
  1733. if ( Success ) {
  1734. PatchArray[ HeaderOldFileCount ].PatchData = PatchBuffer;
  1735. PatchArray[ HeaderOldFileCount ].PatchSize = PatchDataSize;
  1736. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].OldFileHandle = OldFileInfoArray[ i ].OldFileHandle;
  1737. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].OldFileSize = OldFileSize;
  1738. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].OldFileCrc = OldFileCrc;
  1739. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].PatchDataSize = PatchDataSize;
  1740. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].IgnoreRangeCount = OldFileInfoArray[ i ].IgnoreRangeCount;
  1741. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].IgnoreRangeArray = OldFileInfoArray[ i ].IgnoreRangeArray;
  1742. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RetainRangeCount = OldFileInfoArray[ i ].RetainRangeCount;
  1743. HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RetainRangeArray = OldFileInfoArray[ i ].RetainRangeArray;
  1744. //
  1745. // We overestimate (worst case) the possible
  1746. // header size here. Note that typical rift
  1747. // encoding size is around 5 bytes per entry,
  1748. // but we expect that to decrease when we switch
  1749. // to Huffman encoding for the rift table.
  1750. //
  1751. HeaderSize += 32;
  1752. HeaderSize += HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].IgnoreRangeCount * sizeof( PATCH_IGNORE_RANGE );
  1753. HeaderSize += HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RetainRangeCount * sizeof( PATCH_RETAIN_RANGE );
  1754. HeaderSize += HeaderInfo.OldFileInfoArray[ HeaderOldFileCount ].RiftTable.RiftEntryCount * sizeof( RIFT_ENTRY );
  1755. ++HeaderOldFileCount;
  1756. }
  1757. }
  1758. }
  1759. }
  1760. if ( OldFileMapped != NULL ) {
  1761. UnmapViewOfFile( OldFileMapped );
  1762. OldFileMapped = NULL;
  1763. }
  1764. if ( Success ) {
  1765. ProgressPosition += ( LzxInsertSize( OldFileSize, OptionFlags ) + NewFileSize ) * ( TryLzxBoth ? 2 : 1 );
  1766. Success = ProgressCallbackWrapper(
  1767. ProgressCallback,
  1768. CallbackContext,
  1769. ProgressPosition,
  1770. ProgressMaximum
  1771. );
  1772. }
  1773. if ( ! Success ) {
  1774. break;
  1775. }
  1776. }
  1777. }
  1778. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1779. SetLastError( GetExceptionCode() );
  1780. Success = FALSE;
  1781. }
  1782. if ( Success ) {
  1783. if (( OptionFlags & PATCH_OPTION_FAIL_IF_SAME_FILE ) &&
  1784. ( HeaderOldFileCount == 1 ) &&
  1785. ( PatchArray[ 0 ].PatchSize == 0 )) {
  1786. SetLastError( ERROR_PATCH_SAME_FILE );
  1787. Success = FALSE;
  1788. }
  1789. }
  1790. PatchBuffer = NULL;
  1791. PatchDataSize = 0;
  1792. if ( Success ) {
  1793. //
  1794. // Create header
  1795. //
  1796. Success = FALSE;
  1797. HeaderSize = ROUNDUP2( HeaderSize, 0x10000 );
  1798. PatchBuffer = MyVirtualAlloc( HeaderSize );
  1799. if ( PatchBuffer != NULL ) {
  1800. Success = TRUE;
  1801. //
  1802. // Compute size of PatchData without the header.
  1803. //
  1804. PatchDataSize = 0;
  1805. for ( i = 0; i < HeaderOldFileCount; i++ ) {
  1806. PatchDataSize += PatchArray[ i ].PatchSize;
  1807. }
  1808. //
  1809. // Don't need to encode NewFileResTime if the patch is simply
  1810. // a header with no patch data (new file is same as old file).
  1811. // We do still need the NewFileCoffTime and NewFileCoffBase
  1812. // though because we still need to normalize the old file.
  1813. //
  1814. if ( PatchDataSize == 0 ) {
  1815. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  1816. NewFileResTime = 0;
  1817. }
  1818. if ( ExtendedOptionFlags ) {
  1819. OptionFlags |= PATCH_OPTION_EXTENDED_OPTIONS;
  1820. }
  1821. else {
  1822. OptionFlags &= ~PATCH_OPTION_EXTENDED_OPTIONS;
  1823. }
  1824. //
  1825. // Don't need to set PATCH_OPTION_LZX_LARGE unless an LZX window larger
  1826. // than 8Mb was used. This allows backwards compatibility by default for
  1827. // files smaller than 8Mb.
  1828. //
  1829. if ( OptionFlags & PATCH_OPTION_USE_LZX_LARGE ) {
  1830. if ( LzxWindowSize( LargestOldFileSize, NewFileSize, OptionFlags ) <= LZX_MAXWINDOW_8 ) {
  1831. OptionFlags &= ~PATCH_OPTION_USE_LZX_LARGE;
  1832. }
  1833. }
  1834. HeaderInfo.Signature = PATCH_SIGNATURE;
  1835. HeaderInfo.OptionFlags = OptionFlags;
  1836. HeaderInfo.ExtendedOptionFlags = ExtendedOptionFlags;
  1837. HeaderInfo.OptionData = OptionData;
  1838. HeaderInfo.NewFileCoffBase = NewFileCoffBase;
  1839. HeaderInfo.NewFileCoffTime = NewFileCoffTime;
  1840. HeaderInfo.NewFileResTime = NewFileResTime;
  1841. HeaderInfo.NewFileSize = NewFileSize;
  1842. HeaderInfo.NewFileCrc = NewFileCrc;
  1843. HeaderInfo.OldFileCount = HeaderOldFileCount;
  1844. HeaderInfo.NewFileTime = 0;
  1845. if ( ! ( OptionFlags & PATCH_OPTION_NO_TIMESTAMP )) {
  1846. HeaderInfo.NewFileTime = FileTimeToUlongTime( &NewFileTime );
  1847. PatchFileTime = NULL;
  1848. }
  1849. HeaderSize = EncodePatchHeader( &HeaderInfo, PatchBuffer );
  1850. PatchDataSize += HeaderSize + sizeof( ULONG );
  1851. //
  1852. // Now we know the size of the patch file, so if we want to
  1853. // make sure it's not bigger than just compressing the new
  1854. // file, we need to compress the new file to see (the output
  1855. // of the compression is discarded -- we just want to know
  1856. // how big it would be. Obviously if the patch file is bigger
  1857. // than the raw new file, no need to compress the new file to
  1858. // see if that is smaller!
  1859. //
  1860. if ( OptionFlags & PATCH_OPTION_FAIL_IF_BIGGER ) {
  1861. if ( PatchDataSize > NewFileSize ) {
  1862. SetLastError( ERROR_PATCH_BIGGER_THAN_COMPRESSED );
  1863. Success = FALSE;
  1864. }
  1865. else {
  1866. EstimatedLzxMemory = EstimateLzxCompressionMemoryRequirement(
  1867. 0,
  1868. NewFileSize,
  1869. 0 // CAB has only 2Mb window size
  1870. );
  1871. SubAllocatorHandle = CreateSubAllocator(
  1872. EstimatedLzxMemory,
  1873. MINIMUM_VM_ALLOCATION
  1874. );
  1875. if ( SubAllocatorHandle != NULL ) {
  1876. NewFileCompressedSize = 0; // prevent compiler warning
  1877. __try {
  1878. ErrorCode = RawLzxCompressBuffer(
  1879. NewFileMapped,
  1880. NewFileSize,
  1881. 0,
  1882. NULL,
  1883. &NewFileCompressedSize,
  1884. SubAllocate,
  1885. SubAllocatorHandle,
  1886. ProgressCallback,
  1887. CallbackContext,
  1888. ProgressPosition,
  1889. ProgressMaximum
  1890. );
  1891. }
  1892. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1893. ErrorCode = GetExceptionCode();
  1894. }
  1895. DestroySubAllocator( SubAllocatorHandle );
  1896. if ( ErrorCode == NO_ERROR ) {
  1897. if ( PatchDataSize > NewFileCompressedSize ) {
  1898. SetLastError( ERROR_PATCH_BIGGER_THAN_COMPRESSED );
  1899. Success = FALSE;
  1900. }
  1901. }
  1902. }
  1903. }
  1904. if ( Success ) {
  1905. ProgressPosition += NewFileSize;
  1906. Success = ProgressCallbackWrapper(
  1907. ProgressCallback,
  1908. CallbackContext,
  1909. ProgressPosition,
  1910. ProgressMaximum
  1911. );
  1912. }
  1913. }
  1914. }
  1915. }
  1916. UnmapViewOfFile( NewFileMapped );
  1917. if ( Success ) {
  1918. Success = MyCreateMappedFileByHandle(
  1919. PatchFileHandle,
  1920. PatchDataSize,
  1921. &PatchFileMapped
  1922. );
  1923. if ( Success ) {
  1924. __try {
  1925. p = PatchFileMapped;
  1926. CopyMemory( p, PatchBuffer, HeaderSize );
  1927. p += HeaderSize;
  1928. for ( i = 0; i < HeaderOldFileCount; i++ ) {
  1929. if ( PatchArray[ i ].PatchSize != 0 ) {
  1930. CopyMemory( p, PatchArray[ i ].PatchData, PatchArray[ i ].PatchSize );
  1931. p += PatchArray[ i ].PatchSize;
  1932. }
  1933. }
  1934. PatchFileCrc = Crc32( 0xFFFFFFFF, PatchFileMapped, PatchDataSize - sizeof( ULONG ));
  1935. *(UNALIGNED ULONG *)( PatchFileMapped + PatchDataSize - sizeof( ULONG )) = PatchFileCrc;
  1936. }
  1937. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1938. SetLastError( GetExceptionCode() );
  1939. PatchDataSize = 0;
  1940. Success = FALSE;
  1941. }
  1942. MyUnmapCreatedMappedFile(
  1943. PatchFileHandle,
  1944. PatchFileMapped,
  1945. PatchDataSize,
  1946. PatchFileTime
  1947. );
  1948. }
  1949. }
  1950. //
  1951. // Cleanup
  1952. //
  1953. if ( PatchBuffer ) {
  1954. MyVirtualFree( PatchBuffer );
  1955. }
  1956. for ( i = 0; i < OldFileCount; i++ ) {
  1957. if ( PatchArray[ i ].PatchData ) {
  1958. MyVirtualFree( PatchArray[ i ].PatchData );
  1959. }
  1960. if ( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftEntryAlloc ) {
  1961. if ( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftEntryArray ) {
  1962. MyVirtualFree( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftEntryArray );
  1963. }
  1964. if ( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftUsageArray ) {
  1965. MyVirtualFree( HeaderInfo.OldFileInfoArray[ i ].RiftTable.RiftUsageArray );
  1966. }
  1967. }
  1968. }
  1969. if ( Success ) {
  1970. ASSERT( ProgressPosition == ProgressMaximum );
  1971. }
  1972. if (( ! Success ) &&
  1973. ( GetLastError() == ERROR_SUCCESS )) {
  1974. SetLastError( ERROR_EXTENDED_ERROR );
  1975. }
  1976. return Success;
  1977. }
  1978. BOOL
  1979. PATCHAPI
  1980. ExtractPatchHeaderToFileA(
  1981. IN LPCSTR PatchFileName,
  1982. OUT LPCSTR PatchHeaderFileName
  1983. )
  1984. {
  1985. HANDLE PatchFileHandle;
  1986. HANDLE HeaderFileHandle;
  1987. BOOL Success = FALSE;
  1988. PatchFileHandle = CreateFileA(
  1989. PatchFileName,
  1990. GENERIC_READ,
  1991. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1992. NULL,
  1993. OPEN_EXISTING,
  1994. FILE_FLAG_RANDOM_ACCESS,
  1995. NULL
  1996. );
  1997. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  1998. HeaderFileHandle = CreateFileA(
  1999. PatchHeaderFileName,
  2000. GENERIC_READ | GENERIC_WRITE,
  2001. FILE_SHARE_READ,
  2002. NULL,
  2003. CREATE_ALWAYS,
  2004. FILE_ATTRIBUTE_NORMAL,
  2005. NULL
  2006. );
  2007. if ( HeaderFileHandle != INVALID_HANDLE_VALUE ) {
  2008. Success = ExtractPatchHeaderToFileByHandles(
  2009. PatchFileHandle,
  2010. HeaderFileHandle
  2011. );
  2012. CloseHandle( HeaderFileHandle );
  2013. if ( ! Success ) {
  2014. DeleteFileA( PatchHeaderFileName );
  2015. }
  2016. }
  2017. CloseHandle( PatchFileHandle );
  2018. }
  2019. return Success;
  2020. }
  2021. BOOL
  2022. PATCHAPI
  2023. ExtractPatchHeaderToFileW(
  2024. IN LPCWSTR PatchFileName,
  2025. OUT LPCWSTR PatchHeaderFileName
  2026. )
  2027. {
  2028. HANDLE PatchFileHandle;
  2029. HANDLE HeaderFileHandle;
  2030. BOOL Success = FALSE;
  2031. PatchFileHandle = CreateFileW(
  2032. PatchFileName,
  2033. GENERIC_READ,
  2034. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2035. NULL,
  2036. OPEN_EXISTING,
  2037. FILE_FLAG_RANDOM_ACCESS,
  2038. NULL
  2039. );
  2040. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  2041. HeaderFileHandle = CreateFileW(
  2042. PatchHeaderFileName,
  2043. GENERIC_READ | GENERIC_WRITE,
  2044. FILE_SHARE_READ,
  2045. NULL,
  2046. CREATE_ALWAYS,
  2047. FILE_ATTRIBUTE_NORMAL,
  2048. NULL
  2049. );
  2050. if ( HeaderFileHandle != INVALID_HANDLE_VALUE ) {
  2051. Success = ExtractPatchHeaderToFileByHandles(
  2052. PatchFileHandle,
  2053. HeaderFileHandle
  2054. );
  2055. CloseHandle( HeaderFileHandle );
  2056. if ( ! Success ) {
  2057. DeleteFileW( PatchHeaderFileName );
  2058. }
  2059. }
  2060. CloseHandle( PatchFileHandle );
  2061. }
  2062. return Success;
  2063. }
  2064. BOOL
  2065. PATCHAPI
  2066. ExtractPatchHeaderToFileByHandles(
  2067. IN HANDLE PatchFileHandle,
  2068. OUT HANDLE PatchHeaderFileHandle
  2069. )
  2070. {
  2071. PPATCH_HEADER_INFO HeaderInfo;
  2072. HANDLE SubAllocator;
  2073. PUCHAR PatchFileMapped;
  2074. FILETIME PatchFileTime;
  2075. ULONG PatchFileSize;
  2076. ULONG PatchFileCrc;
  2077. ULONG PatchHeaderSize;
  2078. ULONG ActualSize;
  2079. ULONG i;
  2080. BOOL Success;
  2081. BOOL Mapped;
  2082. Success = FALSE;
  2083. Mapped = MyMapViewOfFileByHandle(
  2084. PatchFileHandle,
  2085. &PatchFileSize,
  2086. &PatchFileMapped
  2087. );
  2088. if ( Mapped ) {
  2089. GetFileTime( PatchFileHandle, NULL, NULL, &PatchFileTime );
  2090. PatchFileCrc = 0;
  2091. SafeCompleteCrc32( PatchFileMapped, PatchFileSize, &PatchFileCrc );
  2092. if ( PatchFileCrc == 0xFFFFFFFF ) {
  2093. SubAllocator = CreateSubAllocator( 0x10000, 0x10000 );
  2094. if ( SubAllocator ) {
  2095. Success = DecodePatchHeader(
  2096. PatchFileMapped,
  2097. PatchFileSize,
  2098. SubAllocator,
  2099. &PatchHeaderSize,
  2100. &HeaderInfo
  2101. );
  2102. if ( Success ) {
  2103. //
  2104. // Header extraction is provided so that a header without
  2105. // the bulk of the patch data can be used to determine if
  2106. // an old file is correct for this patch header (can be
  2107. // patched).
  2108. //
  2109. // Since the extracted header will not be used to actually
  2110. // apply, we don't need any of the header data that is
  2111. // used only for transformation (RiftTable and NewResTime).
  2112. // Since NewResTime is typically encoded as one byte (as
  2113. // delta from NewCoffTime), we won't bother throwing it
  2114. // away, but we will throw away the RiftTable.
  2115. //
  2116. // Zero out the rift entry counts, then re-create the
  2117. // patch header with the zeroed rift counts (create over
  2118. // the write-copy mapped patch file buffer, then write
  2119. // that buffer to disk).
  2120. //
  2121. for ( i = 0; i < HeaderInfo->OldFileCount; i++ ) {
  2122. HeaderInfo->OldFileInfoArray[ i ].RiftTable.RiftEntryCount = 0;
  2123. }
  2124. __try {
  2125. PatchHeaderSize = EncodePatchHeader( HeaderInfo, PatchFileMapped );
  2126. PatchFileCrc = Crc32( 0xFFFFFFFF, PatchFileMapped, PatchHeaderSize );
  2127. *(UNALIGNED ULONG *)( PatchFileMapped + PatchHeaderSize ) = PatchFileCrc;
  2128. Success = WriteFile(
  2129. PatchHeaderFileHandle,
  2130. PatchFileMapped,
  2131. PatchHeaderSize + sizeof( ULONG ),
  2132. &ActualSize,
  2133. NULL
  2134. );
  2135. }
  2136. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2137. SetLastError( GetExceptionCode() );
  2138. Success = FALSE;
  2139. }
  2140. if ( Success ) {
  2141. SetFileTime( PatchHeaderFileHandle, NULL, NULL, &PatchFileTime );
  2142. }
  2143. }
  2144. DestroySubAllocator( SubAllocator );
  2145. }
  2146. }
  2147. else {
  2148. SetLastError( ERROR_PATCH_CORRUPT );
  2149. }
  2150. UnmapViewOfFile( PatchFileMapped );
  2151. }
  2152. return Success;
  2153. }
  2154. #endif // ! PATCH_APPLY_CODE_ONLY
  2155. //
  2156. // Following group of functions and exported apis are exclusively for
  2157. // applying patches. If we're only compiling the create code, ignore
  2158. // this group of functions.
  2159. //
  2160. #ifndef PATCH_CREATE_CODE_ONLY
  2161. PVOID
  2162. SaveRetainRanges(
  2163. IN PUCHAR MappedFile,
  2164. IN ULONG FileSize,
  2165. IN ULONG RetainRangeCount,
  2166. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  2167. IN BOOL SaveFromNewFile
  2168. )
  2169. {
  2170. PUCHAR Buffer, p;
  2171. ULONG Offset;
  2172. ULONG TotalSize = 0;
  2173. ULONG i;
  2174. for ( i = 0; i < RetainRangeCount; i++ ) {
  2175. TotalSize += RetainRangeArray[ i ].LengthInBytes;
  2176. }
  2177. Buffer = MyVirtualAlloc( TotalSize );
  2178. if ( Buffer ) {
  2179. __try {
  2180. p = Buffer;
  2181. for ( i = 0; i < RetainRangeCount; i++ ) {
  2182. Offset = SaveFromNewFile ?
  2183. RetainRangeArray[ i ].OffsetInNewFile :
  2184. RetainRangeArray[ i ].OffsetInOldFile;
  2185. if (( Offset + RetainRangeArray[ i ].LengthInBytes ) <= FileSize ) {
  2186. CopyMemory( p, MappedFile + Offset, RetainRangeArray[ i ].LengthInBytes );
  2187. }
  2188. p += RetainRangeArray[ i ].LengthInBytes;
  2189. }
  2190. }
  2191. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2192. SetLastError( GetExceptionCode() );
  2193. MyVirtualFree( Buffer );
  2194. Buffer = NULL;
  2195. }
  2196. }
  2197. return Buffer;
  2198. }
  2199. BOOL
  2200. CreateNewFileFromOldFileMapped(
  2201. IN PUCHAR OldFileMapped,
  2202. IN ULONG OldFileSize,
  2203. OUT HANDLE NewFileHandle,
  2204. IN PFILETIME NewFileTime,
  2205. IN ULONG NewFileExpectedCrc,
  2206. IN ULONG RetainRangeCount,
  2207. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  2208. IN PUCHAR RetainBuffer,
  2209. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2210. IN PVOID CallbackContext
  2211. )
  2212. {
  2213. PUCHAR NewFileMapped;
  2214. ULONG NewFileCrc;
  2215. BOOL Success;
  2216. ULONG i;
  2217. Success = MyCreateMappedFileByHandle(
  2218. NewFileHandle,
  2219. OldFileSize,
  2220. &NewFileMapped
  2221. );
  2222. if ( Success ) {
  2223. __try {
  2224. CopyMemory( NewFileMapped, OldFileMapped, OldFileSize );
  2225. NewFileCrc = Crc32( 0xFFFFFFFF, NewFileMapped, OldFileSize ) ^ 0xFFFFFFFF;
  2226. if ( NewFileCrc == NewFileExpectedCrc ) {
  2227. for ( i = 0; i < RetainRangeCount; i++ ) {
  2228. if (( RetainRangeArray[ i ].OffsetInNewFile + RetainRangeArray[ i ].LengthInBytes ) <= OldFileSize ) {
  2229. CopyMemory(
  2230. RetainRangeArray[ i ].OffsetInNewFile + NewFileMapped,
  2231. RetainBuffer,
  2232. RetainRangeArray[ i ].LengthInBytes
  2233. );
  2234. }
  2235. RetainBuffer += RetainRangeArray[ i ].LengthInBytes;
  2236. }
  2237. Success = ProgressCallbackWrapper(
  2238. ProgressCallback,
  2239. CallbackContext,
  2240. OldFileSize,
  2241. OldFileSize
  2242. );
  2243. }
  2244. else {
  2245. SetLastError( ERROR_PATCH_WRONG_FILE );
  2246. OldFileSize = 0;
  2247. Success = FALSE;
  2248. }
  2249. }
  2250. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2251. SetLastError( GetExceptionCode());
  2252. OldFileSize = 0;
  2253. Success = FALSE;
  2254. }
  2255. MyUnmapCreatedMappedFile(
  2256. NewFileHandle,
  2257. NewFileMapped,
  2258. OldFileSize,
  2259. NewFileTime
  2260. );
  2261. }
  2262. return Success;
  2263. }
  2264. BOOL
  2265. CreateNewFileFromPatchData(
  2266. IN PUCHAR OldFileMapped,
  2267. IN ULONG OldFileSize,
  2268. IN PUCHAR PatchData,
  2269. IN ULONG PatchDataSize,
  2270. OUT HANDLE NewFileHandle,
  2271. IN ULONG NewFileSize,
  2272. IN PFILETIME NewFileTime,
  2273. IN ULONG NewFileExpectedCrc,
  2274. IN ULONG RetainRangeCount,
  2275. IN PPATCH_RETAIN_RANGE RetainRangeArray,
  2276. IN PUCHAR RetainBuffer,
  2277. IN ULONG OptionFlags,
  2278. IN PVOID OptionData,
  2279. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2280. IN PVOID CallbackContext
  2281. )
  2282. {
  2283. HANDLE SubAllocatorHandle;
  2284. ULONG EstimatedLzxMemory;
  2285. PUCHAR NewFileMapped;
  2286. ULONG NewFileCrc;
  2287. ULONG ErrorCode;
  2288. BOOL Success;
  2289. ULONG i;
  2290. UNREFERENCED_PARAMETER( OptionData );
  2291. Success = MyCreateMappedFileByHandle(
  2292. NewFileHandle,
  2293. NewFileSize,
  2294. &NewFileMapped
  2295. );
  2296. if ( Success ) {
  2297. ErrorCode = NO_ERROR;
  2298. EstimatedLzxMemory = EstimateLzxDecompressionMemoryRequirement(
  2299. OldFileSize,
  2300. NewFileSize,
  2301. OptionFlags
  2302. );
  2303. SubAllocatorHandle = CreateSubAllocator(
  2304. EstimatedLzxMemory,
  2305. MINIMUM_VM_ALLOCATION
  2306. );
  2307. if ( SubAllocatorHandle != NULL ) {
  2308. __try {
  2309. ErrorCode = ApplyRawLzxPatchToBuffer(
  2310. OldFileMapped,
  2311. OldFileSize,
  2312. PatchData,
  2313. PatchDataSize,
  2314. NewFileMapped,
  2315. NewFileSize,
  2316. OptionFlags,
  2317. OptionData,
  2318. SubAllocate,
  2319. SubAllocatorHandle,
  2320. ProgressCallback,
  2321. CallbackContext,
  2322. 0,
  2323. NewFileSize
  2324. );
  2325. if ( ErrorCode == NO_ERROR ) {
  2326. NewFileCrc = Crc32( 0xFFFFFFFF, NewFileMapped, NewFileSize ) ^ 0xFFFFFFFF;
  2327. if ( NewFileCrc == NewFileExpectedCrc ) {
  2328. for ( i = 0; i < RetainRangeCount; i++ ) {
  2329. if (( RetainRangeArray[ i ].OffsetInNewFile + RetainRangeArray[ i ].LengthInBytes ) <= OldFileSize ) {
  2330. CopyMemory(
  2331. RetainRangeArray[ i ].OffsetInNewFile + NewFileMapped,
  2332. RetainBuffer,
  2333. RetainRangeArray[ i ].LengthInBytes
  2334. );
  2335. }
  2336. RetainBuffer += RetainRangeArray[ i ].LengthInBytes;
  2337. }
  2338. }
  2339. else {
  2340. ErrorCode = ERROR_PATCH_WRONG_FILE;
  2341. }
  2342. }
  2343. #ifdef TESTCODE
  2344. if ( ErrorCode != NO_ERROR ) {
  2345. HANDLE hFile = CreateFile(
  2346. "Wrong.out",
  2347. GENERIC_WRITE,
  2348. FILE_SHARE_READ,
  2349. NULL,
  2350. CREATE_ALWAYS,
  2351. FILE_ATTRIBUTE_NORMAL,
  2352. NULL
  2353. );
  2354. if ( hFile != INVALID_HANDLE_VALUE ) {
  2355. DWORD Actual;
  2356. WriteFile( hFile, NewFileMapped, NewFileSize, &Actual, NULL );
  2357. CloseHandle( hFile );
  2358. }
  2359. }
  2360. #endif // TESTCODE
  2361. }
  2362. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2363. ErrorCode = GetExceptionCode();
  2364. }
  2365. DestroySubAllocator( SubAllocatorHandle );
  2366. }
  2367. MyUnmapCreatedMappedFile(
  2368. NewFileHandle,
  2369. NewFileMapped,
  2370. ( ErrorCode == NO_ERROR ) ? NewFileSize : 0,
  2371. NewFileTime
  2372. );
  2373. if ( ErrorCode == NO_ERROR ) {
  2374. Success = TRUE;
  2375. }
  2376. else {
  2377. SetLastError( ErrorCode );
  2378. Success = FALSE;
  2379. }
  2380. }
  2381. return Success;
  2382. }
  2383. BOOL
  2384. PATCHAPI
  2385. ApplyPatchToFileByHandlesEx(
  2386. IN HANDLE PatchFileHandle,
  2387. IN HANDLE OldFileHandle,
  2388. OUT HANDLE NewFileHandle,
  2389. IN ULONG ApplyOptionFlags,
  2390. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2391. IN PVOID CallbackContext
  2392. )
  2393. {
  2394. PHEADER_OLD_FILE_INFO OldFileInfo;
  2395. PPATCH_HEADER_INFO HeaderInfo;
  2396. PPATCH_RETAIN_RANGE RetainRangeArray;
  2397. ULONG RetainRangeCount;
  2398. PUCHAR RetainBuffer;
  2399. HANDLE SubAllocator;
  2400. ULONG PatchHeaderSize;
  2401. FILETIME NewFileTime;
  2402. PUCHAR PatchFileMapped;
  2403. ULONG PatchFileSize;
  2404. ULONG PatchFileCrc;
  2405. PUCHAR PatchData;
  2406. PUCHAR OldFileMapped;
  2407. ULONG OldFileSize;
  2408. ULONG OldFileCrc;
  2409. BOOL Mapped;
  2410. BOOL Success;
  2411. BOOL Finished;
  2412. ULONG i;
  2413. Success = FALSE;
  2414. Mapped = MyMapViewOfFileByHandle(
  2415. PatchFileHandle,
  2416. &PatchFileSize,
  2417. &PatchFileMapped
  2418. );
  2419. if ( Mapped ) {
  2420. GetFileTime( PatchFileHandle, NULL, NULL, &NewFileTime );
  2421. PatchFileCrc = 0;
  2422. SafeCompleteCrc32( PatchFileMapped, PatchFileSize, &PatchFileCrc );
  2423. if ( PatchFileCrc == 0xFFFFFFFF ) {
  2424. SubAllocator = CreateSubAllocator( 0x10000, 0x10000 );
  2425. if ( SubAllocator ) {
  2426. Success = DecodePatchHeader(
  2427. PatchFileMapped,
  2428. PatchFileSize,
  2429. SubAllocator,
  2430. &PatchHeaderSize,
  2431. &HeaderInfo
  2432. );
  2433. if ( Success ) {
  2434. //
  2435. // Patch is valid.
  2436. //
  2437. Success = ProgressCallbackWrapper(
  2438. ProgressCallback,
  2439. CallbackContext,
  2440. 0,
  2441. HeaderInfo->NewFileSize
  2442. );
  2443. if ( Success ) {
  2444. Finished = FALSE;
  2445. Success = FALSE;
  2446. if (( ! ( HeaderInfo->OptionFlags & PATCH_OPTION_NO_TIMESTAMP )) &&
  2447. ( HeaderInfo->NewFileTime != 0 )) {
  2448. UlongTimeToFileTime( HeaderInfo->NewFileTime, &NewFileTime );
  2449. }
  2450. OldFileSize = GetFileSize( OldFileHandle, NULL );
  2451. //
  2452. // First see if the old file is really the new file.
  2453. //
  2454. if ( OldFileSize == HeaderInfo->NewFileSize ) {
  2455. Mapped = MyMapViewOfFileByHandle(
  2456. OldFileHandle,
  2457. &OldFileSize,
  2458. &OldFileMapped
  2459. );
  2460. if ( ! Mapped ) {
  2461. Success = FALSE;
  2462. Finished = TRUE;
  2463. }
  2464. else {
  2465. RetainBuffer = NULL;
  2466. OldFileCrc = 0;
  2467. OldFileInfo = &HeaderInfo->OldFileInfoArray[ 0 ];
  2468. RetainRangeCount = OldFileInfo->RetainRangeCount;
  2469. RetainRangeArray = OldFileInfo->RetainRangeArray;
  2470. if (( RetainRangeCount != 0 ) &&
  2471. ( ! ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ))) {
  2472. RetainBuffer = SaveRetainRanges(
  2473. OldFileMapped,
  2474. OldFileSize,
  2475. RetainRangeCount,
  2476. RetainRangeArray,
  2477. TRUE
  2478. );
  2479. if ( RetainBuffer == NULL ) {
  2480. Finished = TRUE;
  2481. }
  2482. }
  2483. if ( ! Finished ) {
  2484. __try {
  2485. //
  2486. // First see if they match exact, without
  2487. // normalizing.
  2488. //
  2489. for ( i = 0; i < RetainRangeCount; i++ ) {
  2490. if (( RetainRangeArray[ i ].OffsetInNewFile + RetainRangeArray[ i ].LengthInBytes ) <= OldFileSize ) {
  2491. ZeroMemory( OldFileMapped + RetainRangeArray[ i ].OffsetInNewFile, RetainRangeArray[ i ].LengthInBytes );
  2492. }
  2493. }
  2494. OldFileCrc = Crc32( 0xFFFFFFFF, OldFileMapped, OldFileSize ) ^ 0xFFFFFFFF;
  2495. if ( OldFileCrc != HeaderInfo->NewFileCrc ) {
  2496. //
  2497. // Don't match exact, so try with
  2498. // normalizing.
  2499. //
  2500. // NOTE: We're assuming here that the
  2501. // zeroed retain ranges don't overlap
  2502. // with the binding info that we're
  2503. // correcting.
  2504. //
  2505. NormalizeOldFileImageForPatching(
  2506. OldFileMapped,
  2507. OldFileSize,
  2508. HeaderInfo->OptionFlags,
  2509. HeaderInfo->OptionData,
  2510. HeaderInfo->NewFileCoffBase,
  2511. HeaderInfo->NewFileCoffTime,
  2512. 0,
  2513. NULL,
  2514. 0,
  2515. NULL
  2516. );
  2517. OldFileCrc = Crc32( 0xFFFFFFFF, OldFileMapped, OldFileSize ) ^ 0xFFFFFFFF;
  2518. }
  2519. }
  2520. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2521. SetLastError( GetExceptionCode() );
  2522. Finished = TRUE;
  2523. }
  2524. if (( ! Finished ) &&
  2525. ( OldFileCrc == HeaderInfo->NewFileCrc ) &&
  2526. ( OldFileSize == HeaderInfo->NewFileSize )) {
  2527. Finished = TRUE;
  2528. if ( ApplyOptionFlags & APPLY_OPTION_FAIL_IF_EXACT ) {
  2529. SetLastError( ERROR_PATCH_NOT_NECESSARY );
  2530. Success = FALSE;
  2531. }
  2532. else if ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ) {
  2533. Success = TRUE;
  2534. }
  2535. else {
  2536. Success = CreateNewFileFromOldFileMapped(
  2537. OldFileMapped,
  2538. OldFileSize,
  2539. NewFileHandle,
  2540. &NewFileTime,
  2541. HeaderInfo->NewFileCrc,
  2542. RetainRangeCount,
  2543. RetainRangeArray,
  2544. RetainBuffer,
  2545. ProgressCallback,
  2546. CallbackContext
  2547. );
  2548. }
  2549. }
  2550. if ( RetainBuffer != NULL ) {
  2551. MyVirtualFree( RetainBuffer );
  2552. }
  2553. }
  2554. UnmapViewOfFile( OldFileMapped );
  2555. }
  2556. }
  2557. if ( ! Finished ) {
  2558. //
  2559. // Now see if the old file matches one of the old
  2560. // files we have in our patch file. For each set
  2561. // of old file info in our patch file, we have to
  2562. // remap the old file to check it since each old
  2563. // file might have different ignore range parameters
  2564. // (we modify the buffer for the ignore ranges).
  2565. //
  2566. PatchData = PatchFileMapped + PatchHeaderSize;
  2567. Success = FALSE;
  2568. for ( i = 0; ( i < HeaderInfo->OldFileCount ) && ( ! Finished ) && ( ! Success ); i++ ) {
  2569. OldFileInfo = &HeaderInfo->OldFileInfoArray[ i ];
  2570. if ( OldFileInfo->OldFileSize == OldFileSize ) {
  2571. Mapped = MyMapViewOfFileByHandle(
  2572. OldFileHandle,
  2573. &OldFileSize,
  2574. &OldFileMapped
  2575. );
  2576. if ( ! Mapped ) {
  2577. Finished = TRUE;
  2578. }
  2579. else {
  2580. RetainBuffer = NULL;
  2581. if (( OldFileInfo->RetainRangeCount != 0 ) &&
  2582. ( ! ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ))) {
  2583. RetainBuffer = SaveRetainRanges(
  2584. OldFileMapped,
  2585. OldFileSize,
  2586. OldFileInfo->RetainRangeCount,
  2587. OldFileInfo->RetainRangeArray,
  2588. FALSE
  2589. );
  2590. if ( RetainBuffer == NULL ) {
  2591. Finished = TRUE;
  2592. }
  2593. }
  2594. if ( ! Finished ) {
  2595. NormalizeOldFileImageForPatching(
  2596. OldFileMapped,
  2597. OldFileSize,
  2598. HeaderInfo->OptionFlags,
  2599. HeaderInfo->OptionData,
  2600. HeaderInfo->NewFileCoffBase,
  2601. HeaderInfo->NewFileCoffTime,
  2602. OldFileInfo->IgnoreRangeCount,
  2603. OldFileInfo->IgnoreRangeArray,
  2604. OldFileInfo->RetainRangeCount,
  2605. OldFileInfo->RetainRangeArray
  2606. );
  2607. OldFileCrc = 0;
  2608. if (( SafeCompleteCrc32( OldFileMapped, OldFileSize, &OldFileCrc )) &&
  2609. ( OldFileCrc == OldFileInfo->OldFileCrc ) &&
  2610. ( OldFileSize == OldFileInfo->OldFileSize )) {
  2611. //
  2612. // CRC's match
  2613. //
  2614. if ( OldFileInfo->PatchDataSize == 0 ) {
  2615. if ( ApplyOptionFlags & APPLY_OPTION_FAIL_IF_CLOSE ) {
  2616. SetLastError( ERROR_PATCH_NOT_NECESSARY );
  2617. Finished = TRUE;
  2618. }
  2619. else if ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ) {
  2620. Success = TRUE;
  2621. }
  2622. else {
  2623. Success = CreateNewFileFromOldFileMapped(
  2624. OldFileMapped,
  2625. OldFileSize,
  2626. NewFileHandle,
  2627. &NewFileTime,
  2628. HeaderInfo->NewFileCrc,
  2629. OldFileInfo->RetainRangeCount,
  2630. OldFileInfo->RetainRangeArray,
  2631. RetainBuffer,
  2632. ProgressCallback,
  2633. CallbackContext
  2634. );
  2635. if ( ! Success ) {
  2636. Finished = TRUE;
  2637. }
  2638. }
  2639. }
  2640. else {
  2641. if ( ApplyOptionFlags & APPLY_OPTION_TEST_ONLY ) {
  2642. Success = TRUE;
  2643. }
  2644. else if (( PatchData + OldFileInfo->PatchDataSize ) > ( PatchFileMapped + PatchFileSize )) {
  2645. SetLastError( ERROR_PATCH_NOT_AVAILABLE );
  2646. Finished = TRUE;
  2647. }
  2648. else {
  2649. Success = TRUE;
  2650. if ( OldFileInfo->RiftTable.RiftEntryCount != 0 ) {
  2651. Success = TransformOldFileImageForPatching(
  2652. HeaderInfo->ExtendedOptionFlags,
  2653. OldFileMapped,
  2654. OldFileSize,
  2655. HeaderInfo->NewFileResTime,
  2656. &OldFileInfo->RiftTable
  2657. );
  2658. }
  2659. if ( Success ) {
  2660. Success = CreateNewFileFromPatchData(
  2661. OldFileMapped,
  2662. OldFileSize,
  2663. PatchData,
  2664. OldFileInfo->PatchDataSize,
  2665. NewFileHandle,
  2666. HeaderInfo->NewFileSize,
  2667. &NewFileTime,
  2668. HeaderInfo->NewFileCrc,
  2669. OldFileInfo->RetainRangeCount,
  2670. OldFileInfo->RetainRangeArray,
  2671. RetainBuffer,
  2672. HeaderInfo->OptionFlags,
  2673. HeaderInfo->OptionData,
  2674. ProgressCallback,
  2675. CallbackContext
  2676. );
  2677. }
  2678. if ( ! Success ) {
  2679. Finished = TRUE;
  2680. }
  2681. }
  2682. }
  2683. }
  2684. if ( RetainBuffer != NULL ) {
  2685. MyVirtualFree( RetainBuffer );
  2686. }
  2687. }
  2688. UnmapViewOfFile( OldFileMapped );
  2689. }
  2690. }
  2691. PatchData += OldFileInfo->PatchDataSize;
  2692. }
  2693. if (( ! Finished ) && ( ! Success )) {
  2694. SetLastError( ERROR_PATCH_WRONG_FILE );
  2695. }
  2696. }
  2697. }
  2698. }
  2699. DestroySubAllocator( SubAllocator );
  2700. }
  2701. }
  2702. else {
  2703. SetLastError( ERROR_PATCH_CORRUPT );
  2704. }
  2705. UnmapViewOfFile( PatchFileMapped );
  2706. }
  2707. if (( ! Success ) &&
  2708. ( GetLastError() == ERROR_SUCCESS )) {
  2709. SetLastError( ERROR_EXTENDED_ERROR );
  2710. }
  2711. return Success;
  2712. }
  2713. BOOL
  2714. PATCHAPI
  2715. TestApplyPatchToFileByHandles(
  2716. IN HANDLE PatchFileHandle, // requires GENERIC_READ access
  2717. IN HANDLE OldFileHandle, // requires GENERIC_READ access
  2718. IN ULONG ApplyOptionFlags
  2719. )
  2720. {
  2721. return ApplyPatchToFileByHandles(
  2722. PatchFileHandle,
  2723. OldFileHandle,
  2724. INVALID_HANDLE_VALUE,
  2725. ApplyOptionFlags | APPLY_OPTION_TEST_ONLY
  2726. );
  2727. }
  2728. BOOL
  2729. PATCHAPI
  2730. ApplyPatchToFileByHandles(
  2731. IN HANDLE PatchFileHandle, // requires GENERIC_READ access
  2732. IN HANDLE OldFileHandle, // requires GENERIC_READ access
  2733. OUT HANDLE NewFileHandle, // requires GENERIC_READ | GENERIC_WRITE
  2734. IN ULONG ApplyOptionFlags
  2735. )
  2736. {
  2737. return ApplyPatchToFileByHandlesEx(
  2738. PatchFileHandle,
  2739. OldFileHandle,
  2740. NewFileHandle,
  2741. ApplyOptionFlags,
  2742. NULL,
  2743. NULL
  2744. );
  2745. }
  2746. BOOL
  2747. PATCHAPI
  2748. TestApplyPatchToFileA(
  2749. IN LPCSTR PatchFileName,
  2750. IN LPCSTR OldFileName,
  2751. IN ULONG ApplyOptionFlags
  2752. )
  2753. {
  2754. return ApplyPatchToFileA(
  2755. PatchFileName,
  2756. OldFileName,
  2757. INVALID_HANDLE_VALUE,
  2758. ApplyOptionFlags | APPLY_OPTION_TEST_ONLY
  2759. );
  2760. }
  2761. BOOL
  2762. PATCHAPI
  2763. ApplyPatchToFileA(
  2764. IN LPCSTR PatchFileName,
  2765. IN LPCSTR OldFileName,
  2766. OUT LPCSTR NewFileName,
  2767. IN ULONG ApplyOptionFlags
  2768. )
  2769. {
  2770. return ApplyPatchToFileExA(
  2771. PatchFileName,
  2772. OldFileName,
  2773. NewFileName,
  2774. ApplyOptionFlags,
  2775. NULL,
  2776. NULL
  2777. );
  2778. }
  2779. BOOL
  2780. PATCHAPI
  2781. ApplyPatchToFileExA(
  2782. IN LPCSTR PatchFileName,
  2783. IN LPCSTR OldFileName,
  2784. OUT LPCSTR NewFileName,
  2785. IN ULONG ApplyOptionFlags,
  2786. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2787. IN PVOID CallbackContext
  2788. )
  2789. {
  2790. HANDLE PatchFileHandle;
  2791. HANDLE OldFileHandle;
  2792. HANDLE NewFileHandle;
  2793. BOOL Success = FALSE;
  2794. PatchFileHandle = CreateFileA(
  2795. PatchFileName,
  2796. GENERIC_READ,
  2797. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2798. NULL,
  2799. OPEN_EXISTING,
  2800. FILE_FLAG_SEQUENTIAL_SCAN,
  2801. NULL
  2802. );
  2803. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  2804. OldFileHandle = CreateFileA(
  2805. OldFileName,
  2806. GENERIC_READ,
  2807. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2808. NULL,
  2809. OPEN_EXISTING,
  2810. FILE_FLAG_SEQUENTIAL_SCAN,
  2811. NULL
  2812. );
  2813. if ( OldFileHandle != INVALID_HANDLE_VALUE ) {
  2814. NewFileHandle = CreateFileA(
  2815. NewFileName,
  2816. GENERIC_READ | GENERIC_WRITE,
  2817. FILE_SHARE_READ,
  2818. NULL,
  2819. CREATE_ALWAYS,
  2820. FILE_ATTRIBUTE_NORMAL,
  2821. NULL
  2822. );
  2823. if ( NewFileHandle != INVALID_HANDLE_VALUE ) {
  2824. Success = ApplyPatchToFileByHandlesEx(
  2825. PatchFileHandle,
  2826. OldFileHandle,
  2827. NewFileHandle,
  2828. ApplyOptionFlags,
  2829. ProgressCallback,
  2830. CallbackContext
  2831. );
  2832. CloseHandle( NewFileHandle );
  2833. if ( ! Success ) {
  2834. DeleteFileA( NewFileName );
  2835. }
  2836. }
  2837. CloseHandle( OldFileHandle );
  2838. }
  2839. CloseHandle( PatchFileHandle );
  2840. }
  2841. return Success;
  2842. }
  2843. BOOL
  2844. PATCHAPI
  2845. TestApplyPatchToFileW(
  2846. IN LPCWSTR PatchFileName,
  2847. IN LPCWSTR OldFileName,
  2848. IN ULONG ApplyOptionFlags
  2849. )
  2850. {
  2851. return ApplyPatchToFileW(
  2852. PatchFileName,
  2853. OldFileName,
  2854. INVALID_HANDLE_VALUE,
  2855. ApplyOptionFlags | APPLY_OPTION_TEST_ONLY
  2856. );
  2857. }
  2858. BOOL
  2859. PATCHAPI
  2860. ApplyPatchToFileW(
  2861. IN LPCWSTR PatchFileName,
  2862. IN LPCWSTR OldFileName,
  2863. OUT LPCWSTR NewFileName,
  2864. IN ULONG ApplyOptionFlags
  2865. )
  2866. {
  2867. return ApplyPatchToFileExW(
  2868. PatchFileName,
  2869. OldFileName,
  2870. NewFileName,
  2871. ApplyOptionFlags,
  2872. NULL,
  2873. NULL
  2874. );
  2875. }
  2876. BOOL
  2877. PATCHAPI
  2878. ApplyPatchToFileExW(
  2879. IN LPCWSTR PatchFileName,
  2880. IN LPCWSTR OldFileName,
  2881. OUT LPCWSTR NewFileName,
  2882. IN ULONG ApplyOptionFlags,
  2883. IN PPATCH_PROGRESS_CALLBACK ProgressCallback,
  2884. IN PVOID CallbackContext
  2885. )
  2886. {
  2887. HANDLE PatchFileHandle;
  2888. HANDLE OldFileHandle;
  2889. HANDLE NewFileHandle;
  2890. BOOL Success = FALSE;
  2891. PatchFileHandle = CreateFileW(
  2892. PatchFileName,
  2893. GENERIC_READ,
  2894. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2895. NULL,
  2896. OPEN_EXISTING,
  2897. FILE_FLAG_SEQUENTIAL_SCAN,
  2898. NULL
  2899. );
  2900. if ( PatchFileHandle != INVALID_HANDLE_VALUE ) {
  2901. OldFileHandle = CreateFileW(
  2902. OldFileName,
  2903. GENERIC_READ,
  2904. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2905. NULL,
  2906. OPEN_EXISTING,
  2907. FILE_FLAG_SEQUENTIAL_SCAN,
  2908. NULL
  2909. );
  2910. if ( OldFileHandle != INVALID_HANDLE_VALUE ) {
  2911. NewFileHandle = CreateFileW(
  2912. NewFileName,
  2913. GENERIC_READ | GENERIC_WRITE,
  2914. FILE_SHARE_READ,
  2915. NULL,
  2916. CREATE_ALWAYS,
  2917. FILE_ATTRIBUTE_NORMAL,
  2918. NULL
  2919. );
  2920. if ( NewFileHandle != INVALID_HANDLE_VALUE ) {
  2921. Success = ApplyPatchToFileByHandlesEx(
  2922. PatchFileHandle,
  2923. OldFileHandle,
  2924. NewFileHandle,
  2925. ApplyOptionFlags,
  2926. ProgressCallback,
  2927. CallbackContext
  2928. );
  2929. CloseHandle( NewFileHandle );
  2930. if ( ! Success ) {
  2931. DeleteFileW( NewFileName );
  2932. }
  2933. }
  2934. CloseHandle( OldFileHandle );
  2935. }
  2936. CloseHandle( PatchFileHandle );
  2937. }
  2938. return Success;
  2939. }
  2940. #endif // ! PATCH_CREATE_CODE_ONLY