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.

1414 lines
44 KiB

  1. #ifndef _WIN32_WINNT
  2. #define _WIN32_WINNT 0x0400
  3. #endif
  4. #ifndef WIN32
  5. #define WIN32 0x0400
  6. #endif
  7. #pragma warning( disable: 4001 4035 4115 4200 4201 4204 4209 4214 4514 4699 )
  8. #include <windows.h>
  9. #include <wincrypt.h>
  10. #pragma warning( disable: 4201 )
  11. #include <imagehlp.h>
  12. #pragma warning( disable: 4001 4035 4115 4200 4201 4204 4209 4214 4514 4699 )
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include "patchapi.h"
  17. #include "patchprv.h"
  18. #include <ntverp.h>
  19. #include <common.ver>
  20. void CopyRight( void ) {
  21. printf(
  22. "\n"
  23. "MPATCH " VER_PRODUCTVERSION_STR " Patch Creation Utility\n"
  24. VER_LEGALCOPYRIGHT_STR
  25. "\n\n"
  26. );
  27. }
  28. void Usage( void ) {
  29. printf(
  30. "Usage: MPATCH [options] OldFile[;OldFile2[;OldFile3]] NewFile TargetPatchFile\n"
  31. "\n"
  32. " Options:\n"
  33. "\n"
  34. " -NOBINDFIX Turn off automatic compensation for bound imports in\n"
  35. " the the old file. The default is to ignore binding\n"
  36. " data in the old file during patch creation which will\n"
  37. " cause the application of the patch to succeed whether\n"
  38. " or not the old file on the target machine is bound, not\n"
  39. " bound, or even bound to different import addresses.\n"
  40. " If the files are not Win32 binaries, this option is\n"
  41. " ignored and has no effect.\n"
  42. "\n"
  43. " -NOLOCKFIX Turn off automatic compensation for smashed lock prefix\n"
  44. " instructions. If the files are not Win32 binaries,\n"
  45. " this option is ignored and has no effect.\n"
  46. "\n"
  47. " -NOREBASE Turn off automatic internal rebasing of old file to new\n"
  48. " file's image base address. If the files are not Win32\n"
  49. " binaries, this option is ignored and has no effect.\n"
  50. "\n"
  51. " -NORESTIME Turn off automatic fixup of resource section timestamps\n"
  52. " (ignored if not Win32 binaries).\n"
  53. "\n"
  54. " -NOSTORETIME Don't store the timestamp of the new file in the patch\n"
  55. " file. Instead, set the timestamp of the patch file to\n"
  56. " the timestamp of the new file.\n"
  57. "\n"
  58. " -IGNORE:Offset,Length[,FileNumber]\n"
  59. "\n"
  60. " Ignore a range of bytes in the OldFile because those\n"
  61. " bytes might be different in the old file being patched\n"
  62. " on the target machine.\n"
  63. "\n"
  64. " -RETAIN:Offset,Length[,OffsetInNewFile[,FileNumber]]\n"
  65. "\n"
  66. " When applying the patch, preserve the range of bytes in\n"
  67. " the old file and copy them to the new file at the given\n"
  68. " OffsetInNewFile.\n"
  69. "\n"
  70. #if 0
  71. " -RIFTINFO:FileName[,FileNumber]\n"
  72. "\n"
  73. " Use rift table information from FileName (produced from\n"
  74. " riftinfo.exe).\n"
  75. "\n"
  76. #endif
  77. " -FAILBIGGER If patch file is bigger than simple compressed file,\n"
  78. " don't create the patch file (takes longer).\n"
  79. "\n"
  80. " -FAILIFSAME If old and new files are the same (ignoring binding\n"
  81. " differences, etc), don't create the patch file.\n"
  82. "\n"
  83. " -NOCOMPARE Don't compare patch compression against ordinary non-\n"
  84. " patch compression (saves time).\n"
  85. "\n"
  86. " -NOPROGRESS Don't display percent complete while building patch.\n"
  87. "\n"
  88. " -NEWSYMPATH:PathName[;PathName]\n"
  89. "\n"
  90. " For NewFile, search for symbol file(s) in these path\n"
  91. " locations (recursive search each path until found).\n"
  92. " The default is to search for symbol files(s) starting\n"
  93. " in the same directory as the NewFile.\n"
  94. "\n"
  95. " -OLDSYMPATH:PathName[;PathName][,FileNumber]\n"
  96. "\n"
  97. " For OldFile, search for symbol file(s) in these path\n"
  98. " locations (recursive search each path until found).\n"
  99. " The default is to search for symbol files(s) starting\n"
  100. " in the same directory as the OldFile.\n"
  101. "\n"
  102. " -UNDECORATED After matching decorated symbol names, match remaining\n"
  103. " symbols using undecorated names.\n"
  104. "\n"
  105. " -NOSYMS Don't use debug symbol files when creating the patch.\n"
  106. "\n"
  107. " -NOSYMFAIL Don't fail to create patch if symbols cannot be loaded.\n"
  108. "\n"
  109. " -NOSYMWARN Don't warn if symbols can't be found or don't match the\n"
  110. " corresponding file (symbol checksum mismatch).\n"
  111. "\n"
  112. " -USEBADSYMS Rather than ignoring symbols if the checksums don't\n"
  113. " match the corresponding files, use the bad symbols.\n"
  114. "\n"
  115. " -E8 Force E8 call translation for x86 binaries.\n"
  116. "\n"
  117. " -NOE8 Force no E8 call translation for x86 binaries.\n"
  118. "\n"
  119. " If neither -E8 or -NOE8 are specified, and the files\n"
  120. " are x86 binaries, the patch will be built internally\n"
  121. " twice and the smaller will be chosen for output.\n"
  122. "\n"
  123. " -MSPATCH194COMPAT Assure the patch file can be used with version\n"
  124. " 1.94 of MSPATCH*.DLL. May increase size of patch\n"
  125. " file if old or new file is larger than 4Mb.\n"
  126. "\n"
  127. " MPATCH will also look for environment variables named \"MPATCH\"\n"
  128. " followed by an underscore and the name of the option. Command line\n"
  129. " specified options override environment variable options. Examples:\n"
  130. "\n"
  131. " MPATCH_NOCOMPARE=1\n"
  132. " MPATCH_NEWSYMPATH=c:\\winnt\\symbols;\\\\server\\share\\symbols\n"
  133. "\n"
  134. );
  135. exit( 1 );
  136. }
  137. BOOL bNoProgress;
  138. BOOL bNoSymWarn;
  139. BOOL bUseBadSyms;
  140. DWORDLONG
  141. GetFileSizeByName(
  142. IN LPCSTR FileName
  143. )
  144. {
  145. DWORDLONG FileSizeReturn;
  146. ULONG FileSizeHigh;
  147. ULONG FileSizeLow;
  148. HANDLE hFile;
  149. FileSizeReturn = 0xFFFFFFFFFFFFFFFF;
  150. hFile = CreateFile(
  151. FileName,
  152. GENERIC_READ,
  153. FILE_SHARE_READ | FILE_SHARE_WRITE,
  154. NULL,
  155. OPEN_EXISTING,
  156. 0,
  157. NULL
  158. );
  159. if ( hFile != INVALID_HANDLE_VALUE ) {
  160. FileSizeLow = GetFileSize( hFile, &FileSizeHigh );
  161. if (( FileSizeLow != 0xFFFFFFFF ) || ( GetLastError() == NO_ERROR )) {
  162. FileSizeReturn = ((DWORDLONG)FileSizeHigh << 32 ) | FileSizeLow;
  163. }
  164. CloseHandle( hFile );
  165. }
  166. return FileSizeReturn;
  167. }
  168. BOOL
  169. GetMpatchEnvironString(
  170. IN LPCSTR VarName,
  171. OUT LPSTR Buffer,
  172. IN DWORD BufferSize
  173. )
  174. {
  175. CHAR EnvironName[ 256 ];
  176. sprintf( EnvironName, "mpatch_%s", VarName );
  177. if ( GetEnvironmentVariable( EnvironName, Buffer, BufferSize )) {
  178. return TRUE;
  179. }
  180. return FALSE;
  181. }
  182. BOOL
  183. GetMpatchEnvironValue(
  184. IN LPCSTR VarName
  185. )
  186. {
  187. CHAR LocalBuffer[ 256 ];
  188. if ( GetMpatchEnvironString( VarName, LocalBuffer, sizeof( LocalBuffer ))) {
  189. if (( *LocalBuffer == '0' ) && ( strtoul( LocalBuffer, NULL, 0 ) == 0 )) {
  190. return FALSE;
  191. }
  192. return TRUE;
  193. }
  194. return FALSE;
  195. }
  196. BOOL
  197. CALLBACK
  198. MyProgressCallback(
  199. PVOID CallbackContext,
  200. ULONG CurrentPosition,
  201. ULONG MaximumPosition
  202. )
  203. {
  204. UNREFERENCED_PARAMETER( CallbackContext );
  205. if ( MaximumPosition != 0 ) {
  206. fprintf( stderr, "\r%3.1f%% complete", ( CurrentPosition * 100.0 ) / MaximumPosition );
  207. }
  208. return TRUE;
  209. }
  210. BOOL
  211. CALLBACK
  212. MySymLoadCallback(
  213. IN ULONG WhichFile,
  214. IN LPCSTR SymbolFileName,
  215. IN ULONG SymType,
  216. IN ULONG SymbolFileCheckSum,
  217. IN ULONG SymbolFileTimeDate,
  218. IN ULONG ImageFileCheckSum,
  219. IN ULONG ImageFileTimeDate,
  220. IN PVOID CallbackContext
  221. )
  222. {
  223. LPCSTR *FileNameArray = CallbackContext;
  224. LPCSTR SymTypeText;
  225. if (( SymType == SymNone ) || ( SymType == SymExport )) {
  226. //
  227. // Symbols could not be found.
  228. //
  229. if ( ! bNoSymWarn ) {
  230. printf(
  231. "\n"
  232. "WARNING: no debug symbols for %s\n\n",
  233. FileNameArray[ WhichFile ]
  234. );
  235. }
  236. return TRUE;
  237. }
  238. //
  239. // Note that the Old file checksum is the checksum AFTER normalization,
  240. // so if the original .dbg file was updated with bound checksum, the
  241. // old file's checksum will not match the symbol file's checksum. But,
  242. // binding a file does not change its TimeDateStamp, so that should be
  243. // a valid comparison. But, .sym files don't have a TimeDateStamp, so
  244. // the SymbolFileTimeDate may be zero. If either the checksums match
  245. // or the timedate stamps match, we'll say its valid.
  246. //
  247. if (( ImageFileCheckSum == SymbolFileCheckSum ) ||
  248. ( ImageFileTimeDate == SymbolFileTimeDate )) {
  249. return TRUE;
  250. }
  251. if ( ! bNoSymWarn ) {
  252. switch ( SymType ) {
  253. case SymNone: SymTypeText = "No"; break;
  254. case SymCoff: SymTypeText = "Coff"; break;
  255. case SymCv: SymTypeText = "CodeView"; break;
  256. case SymPdb: SymTypeText = "Pdb"; break;
  257. case SymExport: SymTypeText = "Export"; break;
  258. case SymDeferred: SymTypeText = "Deferred"; break;
  259. case SymSym: SymTypeText = "Sym"; break;
  260. default: SymTypeText = "Unknown"; break;
  261. }
  262. printf(
  263. "\n"
  264. "WARNING: %s symbols %s don't match %s:\n"
  265. " symbol file checksum (%08X) does not match image (%08X), and\n"
  266. " symbol file timedate (%08X) does not match image (%08X).\n\n",
  267. SymTypeText,
  268. SymbolFileName,
  269. FileNameArray[ WhichFile ],
  270. SymbolFileCheckSum,
  271. ImageFileCheckSum,
  272. SymbolFileTimeDate,
  273. ImageFileTimeDate
  274. );
  275. }
  276. return bUseBadSyms;
  277. }
  278. PRIFT_TABLE RiftTableArray[ 256 ];
  279. PATCH_OLD_FILE_INFO_A OldFileInfo[ 256 ];
  280. LPSTR OldFileSymPathArray[ 256 ];
  281. LPSTR NewFileSymPath;
  282. LPSTR FileNameArray[ 257 ];
  283. PATCH_OPTION_DATA OptionData = { sizeof( PATCH_OPTION_DATA ) };
  284. CHAR TextBuffer[ 65000 ];
  285. void __cdecl main( int argc, char *argv[] ) {
  286. LPSTR OldFileName = NULL;
  287. LPSTR NewFileName = NULL;
  288. LPSTR PatchFileName = NULL;
  289. ULONG OptionFlags = PATCH_OPTION_USE_LZX_BEST | PATCH_OPTION_USE_LZX_LARGE;
  290. BOOL Success;
  291. LPSTR arg;
  292. LPSTR p, q;
  293. LPSTR FileName;
  294. int i, j, n;
  295. ULONG OldOffset;
  296. ULONG NewOffset;
  297. ULONG Length;
  298. ULONG FileNum;
  299. ULONG OldFileCount;
  300. ULONG ErrorCode;
  301. ULONG NewFileSize;
  302. ULONG PatchFileSize;
  303. ULONG OldFileRva;
  304. ULONG NewFileRva;
  305. BOOL bNoCompare = FALSE;
  306. FILE *RiftFile;
  307. LPSTR FileNamePart;
  308. SetErrorMode( SEM_FAILCRITICALERRORS );
  309. #ifndef DEBUG
  310. SetErrorMode( SEM_NOALIGNMENTFAULTEXCEPT | SEM_FAILCRITICALERRORS );
  311. #endif
  312. #ifdef TESTCODE
  313. bNoCompare = TRUE;
  314. #endif
  315. CopyRight();
  316. for ( i = 1; i < argc; i++ ) {
  317. arg = argv[ i ];
  318. if ( strchr( arg, '?' )) {
  319. Usage();
  320. }
  321. }
  322. //
  323. // First get environment arguments because command-line args will
  324. // override them.
  325. //
  326. if ( GetMpatchEnvironValue( "e8" )) {
  327. OptionFlags &= ~PATCH_OPTION_USE_LZX_A;
  328. }
  329. if ( GetMpatchEnvironValue( "noe8" )) {
  330. OptionFlags &= ~PATCH_OPTION_USE_LZX_B;
  331. }
  332. if ( GetMpatchEnvironValue( "mspatch194compat" )) {
  333. OptionFlags &= ~PATCH_OPTION_USE_LZX_LARGE;
  334. }
  335. if ( GetMpatchEnvironValue( "nobindfix" )) {
  336. OptionFlags |= PATCH_OPTION_NO_BINDFIX;
  337. }
  338. if ( GetMpatchEnvironValue( "nolockfix" )) {
  339. OptionFlags |= PATCH_OPTION_NO_LOCKFIX;
  340. }
  341. if ( GetMpatchEnvironValue( "norebase" )) {
  342. OptionFlags |= PATCH_OPTION_NO_REBASE;
  343. }
  344. if ( GetMpatchEnvironValue( "norestime" )) {
  345. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  346. }
  347. if ( GetMpatchEnvironValue( "nostoretime" )) {
  348. OptionFlags |= PATCH_OPTION_NO_TIMESTAMP;
  349. }
  350. if ( GetMpatchEnvironValue( "failbigger" )) {
  351. OptionFlags |= PATCH_OPTION_FAIL_IF_BIGGER;
  352. }
  353. if ( GetMpatchEnvironValue( "failifbigger" )) {
  354. OptionFlags |= PATCH_OPTION_FAIL_IF_BIGGER;
  355. }
  356. if ( GetMpatchEnvironValue( "failsame" )) {
  357. OptionFlags |= PATCH_OPTION_FAIL_IF_SAME_FILE;
  358. }
  359. if ( GetMpatchEnvironValue( "failifsame" )) {
  360. OptionFlags |= PATCH_OPTION_FAIL_IF_SAME_FILE;
  361. }
  362. if ( GetMpatchEnvironValue( "nocompare" )) {
  363. bNoCompare = TRUE;
  364. }
  365. if ( GetMpatchEnvironValue( "noprogress" )) {
  366. bNoProgress = TRUE;
  367. }
  368. if ( GetMpatchEnvironValue( "undecorated" )) {
  369. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_UNDECORATED_TOO;
  370. }
  371. if ( GetMpatchEnvironValue( "nosyms" )) {
  372. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_NO_IMAGEHLP;
  373. }
  374. if ( GetMpatchEnvironValue( "nosymfail" )) {
  375. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_NO_FAILURES;
  376. }
  377. if ( GetMpatchEnvironValue( "nosymwarn" )) {
  378. bNoSymWarn = TRUE;
  379. }
  380. if ( GetMpatchEnvironValue( "usebadsyms" )) {
  381. bUseBadSyms = TRUE;
  382. }
  383. if ( GetMpatchEnvironString( "ignore", TextBuffer, sizeof( TextBuffer ))) {
  384. p = TextBuffer;
  385. q = strchr( p, ',' );
  386. if ( q != NULL ) {
  387. *q = 0;
  388. OldOffset = strtoul( p, NULL, 0 );
  389. p = q + 1;
  390. q = strchr( p, ',' );
  391. if ( q ) {
  392. *q = 0;
  393. }
  394. Length = strtoul( p, NULL, 0 );
  395. FileNum = 1;
  396. if ( q ) {
  397. p = q + 1;
  398. FileNum = strtoul( p, NULL, 0 );
  399. if ( FileNum == 0 ) {
  400. FileNum = 1;
  401. }
  402. }
  403. if ( FileNum <= 255 ) {
  404. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray = realloc(
  405. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray,
  406. OldFileInfo[ FileNum - 1 ].IgnoreRangeCount * sizeof( PATCH_IGNORE_RANGE ) + sizeof( PATCH_IGNORE_RANGE )
  407. );
  408. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray[ OldFileInfo[ FileNum - 1 ].IgnoreRangeCount ].OffsetInOldFile = OldOffset;
  409. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray[ OldFileInfo[ FileNum - 1 ].IgnoreRangeCount ].LengthInBytes = Length;
  410. OldFileInfo[ FileNum - 1 ].IgnoreRangeCount++;
  411. }
  412. }
  413. }
  414. if ( GetMpatchEnvironString( "retain", TextBuffer, sizeof( TextBuffer ))) {
  415. p = TextBuffer;
  416. q = strchr( p, ',' );
  417. if ( q != NULL ) {
  418. *q = 0;
  419. OldOffset = strtoul( p, NULL, 0 );
  420. p = q + 1;
  421. q = strchr( p, ',' );
  422. if ( q ) {
  423. *q = 0;
  424. }
  425. Length = strtoul( p, NULL, 0 );
  426. NewOffset = OldOffset;
  427. FileNum = 1;
  428. if ( q ) {
  429. p = q + 1;
  430. q = strchr( p, ',' );
  431. if ( q ) {
  432. *q = 0;
  433. }
  434. NewOffset = strtoul( p, NULL, 0 );
  435. if ( q ) {
  436. p = q + 1;
  437. FileNum = strtoul( p, NULL, 0 );
  438. if ( FileNum == 0 ) {
  439. FileNum = 1;
  440. }
  441. }
  442. }
  443. if ( FileNum <= 255 ) {
  444. OldFileInfo[ FileNum - 1 ].RetainRangeArray = realloc(
  445. OldFileInfo[ FileNum - 1 ].RetainRangeArray,
  446. OldFileInfo[ FileNum - 1 ].RetainRangeCount * sizeof( PATCH_RETAIN_RANGE ) + sizeof( PATCH_RETAIN_RANGE )
  447. );
  448. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].OffsetInOldFile = OldOffset;
  449. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].OffsetInNewFile = NewOffset;
  450. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].LengthInBytes = Length;
  451. OldFileInfo[ FileNum - 1 ].RetainRangeCount++;
  452. }
  453. }
  454. }
  455. if ( GetMpatchEnvironString( "riftinfo", TextBuffer, sizeof( TextBuffer ))) {
  456. p = TextBuffer;
  457. q = strchr( p, ',' );
  458. if ( q ) {
  459. *q = 0;
  460. }
  461. FileName = p;
  462. FileNum = 1;
  463. if ( q ) {
  464. p = q + 1;
  465. FileNum = strtoul( p, NULL, 0 );
  466. if ( FileNum == 0 ) {
  467. FileNum = 1;
  468. }
  469. }
  470. if ( FileNum <= 255 ) {
  471. RiftTableArray[ FileNum - 1 ] = malloc( sizeof( RIFT_TABLE ));
  472. if ( RiftTableArray[ FileNum - 1 ] == NULL ) {
  473. printf( "Out of memory\n" );
  474. exit( 1 );
  475. }
  476. RiftTableArray[ FileNum - 1 ]->RiftEntryCount = 0;
  477. RiftTableArray[ FileNum - 1 ]->RiftEntryAlloc = 0;
  478. RiftTableArray[ FileNum - 1 ]->RiftEntryArray = NULL;
  479. RiftTableArray[ FileNum - 1 ]->RiftUsageArray = NULL;
  480. RiftFile = fopen( FileName, "rt" );
  481. if ( RiftFile == NULL ) {
  482. printf( "Could not open %s\n", FileName );
  483. exit( 1 );
  484. }
  485. while ( fgets( TextBuffer, sizeof( TextBuffer ), RiftFile )) {
  486. //
  487. // Line looks like "00001456 00002345" where each number
  488. // is an RVA in hexadecimal and the first column is the
  489. // OldFileRva and the second column is the NewFileRva.
  490. // Any text beyond column 17 is considered a comment, and
  491. // any line that does not begin with a digit is ignored.
  492. //
  493. if (( isxdigit( *TextBuffer )) && ( strlen( TextBuffer ) >= 17 )) {
  494. OldFileRva = strtoul( TextBuffer, NULL, 16 );
  495. NewFileRva = strtoul( TextBuffer + 9, NULL, 16 );
  496. if (( OldFileRva + NewFileRva ) != 0 ) {
  497. RiftTableArray[ FileNum - 1 ]->RiftEntryArray = realloc(
  498. RiftTableArray[ FileNum - 1 ]->RiftEntryArray,
  499. RiftTableArray[ FileNum - 1 ]->RiftEntryCount * sizeof( RIFT_ENTRY ) + sizeof( RIFT_ENTRY )
  500. );
  501. RiftTableArray[ FileNum - 1 ]->RiftEntryArray[ RiftTableArray[ FileNum - 1 ]->RiftEntryCount ].OldFileRva = OldFileRva;
  502. RiftTableArray[ FileNum - 1 ]->RiftEntryArray[ RiftTableArray[ FileNum - 1 ]->RiftEntryCount ].NewFileRva = NewFileRva;
  503. RiftTableArray[ FileNum - 1 ]->RiftEntryCount++;
  504. }
  505. }
  506. }
  507. fclose( RiftFile );
  508. if ( RiftTableArray[ FileNum - 1 ]->RiftEntryCount ) {
  509. RiftTableArray[ FileNum - 1 ]->RiftEntryAlloc = RiftTableArray[ FileNum - 1 ]->RiftEntryCount;
  510. RiftTableArray[ FileNum - 1 ]->RiftUsageArray = malloc( RiftTableArray[ FileNum - 1 ]->RiftEntryCount );
  511. if ( RiftTableArray[ FileNum - 1 ]->RiftUsageArray == NULL ) {
  512. printf( "Out of memory\n" );
  513. exit( 1 );
  514. }
  515. ZeroMemory( RiftTableArray[ FileNum - 1 ]->RiftUsageArray, RiftTableArray[ FileNum - 1 ]->RiftEntryCount );
  516. }
  517. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_EXTERNAL_RIFT;
  518. }
  519. }
  520. if ( GetMpatchEnvironString( "oldsympath", TextBuffer, sizeof( TextBuffer ))) {
  521. p = TextBuffer;
  522. q = strchr( p, ',' );
  523. if ( q ) {
  524. *q = 0;
  525. }
  526. FileName = p;
  527. FileNum = 1;
  528. if ( q ) {
  529. p = q + 1;
  530. FileNum = strtoul( p, NULL, 0 );
  531. if ( FileNum == 0 ) {
  532. FileNum = 1;
  533. }
  534. }
  535. if ( FileNum <= 255 ) {
  536. OldFileSymPathArray[ FileNum - 1 ] = _strdup( FileName );
  537. }
  538. }
  539. if ( GetMpatchEnvironString( "newsympath", TextBuffer, sizeof( TextBuffer ))) {
  540. p = TextBuffer;
  541. q = strchr( p, ',' );
  542. if ( q ) {
  543. *q = 0;
  544. }
  545. FileName = p;
  546. FileNum = 1;
  547. if ( q ) {
  548. p = q + 1;
  549. FileNum = strtoul( p, NULL, 0 );
  550. if ( FileNum == 0 ) {
  551. FileNum = 1;
  552. }
  553. }
  554. if ( FileNum == 1 ) {
  555. NewFileSymPath = _strdup( FileName );
  556. }
  557. }
  558. //
  559. // Now process commandline args
  560. //
  561. for ( i = 1; i < argc; i++ ) {
  562. arg = argv[ i ];
  563. if ( strchr( arg, '?' )) {
  564. Usage();
  565. }
  566. if (( *arg == '-' ) || ( *arg == '/' )) {
  567. _strlwr( ++arg );
  568. if ( strcmp( arg, "e8" ) == 0 ) {
  569. OptionFlags &= ~PATCH_OPTION_USE_LZX_A;
  570. }
  571. else if ( strcmp( arg, "noe8" ) == 0 ) {
  572. OptionFlags &= ~PATCH_OPTION_USE_LZX_B;
  573. }
  574. else if ( strcmp( arg, "mspatch194compat" ) == 0 ) {
  575. OptionFlags &= ~PATCH_OPTION_USE_LZX_LARGE;
  576. }
  577. else if ( strcmp( arg, "nobindfix" ) == 0 ) {
  578. OptionFlags |= PATCH_OPTION_NO_BINDFIX;
  579. }
  580. else if ( strcmp( arg, "bindfix" ) == 0 ) {
  581. OptionFlags &= ~PATCH_OPTION_NO_BINDFIX;
  582. }
  583. else if ( strcmp( arg, "nolockfix" ) == 0 ) {
  584. OptionFlags |= PATCH_OPTION_NO_LOCKFIX;
  585. }
  586. else if ( strcmp( arg, "lockfix" ) == 0 ) {
  587. OptionFlags &= ~PATCH_OPTION_NO_LOCKFIX;
  588. }
  589. else if ( strcmp( arg, "norebase" ) == 0 ) {
  590. OptionFlags |= PATCH_OPTION_NO_REBASE;
  591. }
  592. else if ( strcmp( arg, "rebase" ) == 0 ) {
  593. OptionFlags &= ~PATCH_OPTION_NO_REBASE;
  594. }
  595. else if ( strcmp( arg, "norestime" ) == 0 ) {
  596. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  597. }
  598. else if ( strcmp( arg, "norestimefix" ) == 0 ) {
  599. OptionFlags |= PATCH_OPTION_NO_RESTIMEFIX;
  600. }
  601. else if ( strcmp( arg, "restime" ) == 0 ) {
  602. OptionFlags &= ~PATCH_OPTION_NO_RESTIMEFIX;
  603. }
  604. else if ( strcmp( arg, "restimefix" ) == 0 ) {
  605. OptionFlags &= ~PATCH_OPTION_NO_RESTIMEFIX;
  606. }
  607. else if ( strcmp( arg, "nostoretime" ) == 0 ) {
  608. OptionFlags |= PATCH_OPTION_NO_TIMESTAMP;
  609. }
  610. else if ( strcmp( arg, "storetime" ) == 0 ) {
  611. OptionFlags &= ~PATCH_OPTION_NO_TIMESTAMP;
  612. }
  613. else if ( strcmp( arg, "failbigger" ) == 0 ) {
  614. OptionFlags |= PATCH_OPTION_FAIL_IF_BIGGER;
  615. }
  616. else if ( strcmp( arg, "nofailbigger" ) == 0 ) {
  617. OptionFlags &= ~PATCH_OPTION_FAIL_IF_BIGGER;
  618. }
  619. else if ( strcmp( arg, "failifbigger" ) == 0 ) {
  620. OptionFlags |= PATCH_OPTION_FAIL_IF_BIGGER;
  621. }
  622. else if ( strcmp( arg, "nofailifbigger" ) == 0 ) {
  623. OptionFlags &= ~PATCH_OPTION_FAIL_IF_BIGGER;
  624. }
  625. else if ( strcmp( arg, "failifsame" ) == 0 ) {
  626. OptionFlags |= PATCH_OPTION_FAIL_IF_SAME_FILE;
  627. }
  628. else if ( strcmp( arg, "failsame" ) == 0 ) {
  629. OptionFlags |= PATCH_OPTION_FAIL_IF_SAME_FILE;
  630. }
  631. else if ( strcmp( arg, "nofailifsame" ) == 0 ) {
  632. OptionFlags &= ~PATCH_OPTION_FAIL_IF_SAME_FILE;
  633. }
  634. else if ( strcmp( arg, "nofailsame" ) == 0 ) {
  635. OptionFlags &= ~PATCH_OPTION_FAIL_IF_SAME_FILE;
  636. }
  637. else if ( strcmp( arg, "nocompare" ) == 0 ) {
  638. bNoCompare = TRUE;
  639. }
  640. else if ( strcmp( arg, "compare" ) == 0 ) {
  641. bNoCompare = FALSE;
  642. }
  643. else if ( strcmp( arg, "noprogress" ) == 0 ) {
  644. bNoProgress = TRUE;
  645. }
  646. else if ( strcmp( arg, "progress" ) == 0 ) {
  647. bNoProgress = FALSE;
  648. }
  649. else if ( strcmp( arg, "decorated" ) == 0 ) {
  650. OptionData.SymbolOptionFlags &= ~PATCH_SYMBOL_UNDECORATED_TOO;
  651. }
  652. else if ( strcmp( arg, "undecorated" ) == 0 ) {
  653. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_UNDECORATED_TOO;
  654. }
  655. else if ( strcmp( arg, "nosyms" ) == 0 ) {
  656. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_NO_IMAGEHLP;
  657. }
  658. else if ( strcmp( arg, "syms" ) == 0 ) {
  659. OptionData.SymbolOptionFlags &= ~PATCH_SYMBOL_NO_IMAGEHLP;
  660. }
  661. else if ( strcmp( arg, "nosymfail" ) == 0 ) {
  662. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_NO_FAILURES;
  663. }
  664. else if ( strcmp( arg, "symfail" ) == 0 ) {
  665. OptionData.SymbolOptionFlags &= ~PATCH_SYMBOL_NO_FAILURES;
  666. }
  667. else if ( strcmp( arg, "nosymwarn" ) == 0 ) {
  668. bNoSymWarn = TRUE;
  669. }
  670. else if ( strcmp( arg, "symwarn" ) == 0 ) {
  671. bNoSymWarn = FALSE;
  672. }
  673. else if ( strcmp( arg, "usebadsyms" ) == 0 ) {
  674. bUseBadSyms = TRUE;
  675. }
  676. else if ( strcmp( arg, "nousebadsyms" ) == 0 ) {
  677. bUseBadSyms = FALSE;
  678. }
  679. else if ( strcmp( arg, "nobadsyms" ) == 0 ) {
  680. bUseBadSyms = FALSE;
  681. }
  682. else if ( memcmp( arg, "ignore:", 7 ) == 0 ) {
  683. p = strchr( arg, ':' ) + 1;
  684. q = strchr( p, ',' );
  685. if ( q == NULL ) {
  686. Usage();
  687. }
  688. *q = 0;
  689. OldOffset = strtoul( p, NULL, 0 );
  690. p = q + 1;
  691. q = strchr( p, ',' );
  692. if ( q ) {
  693. *q = 0;
  694. }
  695. Length = strtoul( p, NULL, 0 );
  696. FileNum = 1;
  697. if ( q ) {
  698. p = q + 1;
  699. FileNum = strtoul( p, NULL, 0 );
  700. if ( FileNum == 0 ) {
  701. FileNum = 1;
  702. }
  703. }
  704. if ( FileNum > 255 ) {
  705. Usage();
  706. }
  707. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray = realloc(
  708. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray,
  709. OldFileInfo[ FileNum - 1 ].IgnoreRangeCount * sizeof( PATCH_IGNORE_RANGE ) + sizeof( PATCH_IGNORE_RANGE )
  710. );
  711. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray[ OldFileInfo[ FileNum - 1 ].IgnoreRangeCount ].OffsetInOldFile = OldOffset;
  712. OldFileInfo[ FileNum - 1 ].IgnoreRangeArray[ OldFileInfo[ FileNum - 1 ].IgnoreRangeCount ].LengthInBytes = Length;
  713. OldFileInfo[ FileNum - 1 ].IgnoreRangeCount++;
  714. }
  715. else if ( memcmp( arg, "retain:", 7 ) == 0 ) {
  716. p = strchr( arg, ':' ) + 1;
  717. q = strchr( p, ',' );
  718. if ( q == NULL ) {
  719. Usage();
  720. }
  721. *q = 0;
  722. OldOffset = strtoul( p, NULL, 0 );
  723. p = q + 1;
  724. q = strchr( p, ',' );
  725. if ( q ) {
  726. *q = 0;
  727. }
  728. Length = strtoul( p, NULL, 0 );
  729. NewOffset = OldOffset;
  730. FileNum = 1;
  731. if ( q ) {
  732. p = q + 1;
  733. q = strchr( p, ',' );
  734. if ( q ) {
  735. *q = 0;
  736. }
  737. NewOffset = strtoul( p, NULL, 0 );
  738. if ( q ) {
  739. p = q + 1;
  740. FileNum = strtoul( p, NULL, 0 );
  741. if ( FileNum == 0 ) {
  742. FileNum = 1;
  743. }
  744. }
  745. }
  746. if ( FileNum > 255 ) {
  747. Usage();
  748. }
  749. OldFileInfo[ FileNum - 1 ].RetainRangeArray = realloc(
  750. OldFileInfo[ FileNum - 1 ].RetainRangeArray,
  751. OldFileInfo[ FileNum - 1 ].RetainRangeCount * sizeof( PATCH_RETAIN_RANGE ) + sizeof( PATCH_RETAIN_RANGE )
  752. );
  753. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].OffsetInOldFile = OldOffset;
  754. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].OffsetInNewFile = NewOffset;
  755. OldFileInfo[ FileNum - 1 ].RetainRangeArray[ OldFileInfo[ FileNum - 1 ].RetainRangeCount ].LengthInBytes = Length;
  756. OldFileInfo[ FileNum - 1 ].RetainRangeCount++;
  757. }
  758. else if ( memcmp( arg, "riftinfo:", 9 ) == 0 ) {
  759. OptionData.SymbolOptionFlags |= PATCH_SYMBOL_EXTERNAL_RIFT;
  760. p = strchr( arg, ':' ) + 1;
  761. q = strchr( p, ',' );
  762. if ( q ) {
  763. *q = 0;
  764. }
  765. FileName = p;
  766. FileNum = 1;
  767. if ( q ) {
  768. p = q + 1;
  769. FileNum = strtoul( p, NULL, 0 );
  770. if ( FileNum == 0 ) {
  771. FileNum = 1;
  772. }
  773. }
  774. if ( FileNum > 255 ) {
  775. Usage();
  776. }
  777. RiftTableArray[ FileNum - 1 ] = malloc( sizeof( RIFT_TABLE ));
  778. if ( RiftTableArray[ FileNum - 1 ] == NULL ) {
  779. printf( "Out of memory\n" );
  780. exit( 1 );
  781. }
  782. RiftTableArray[ FileNum - 1 ]->RiftEntryCount = 0;
  783. RiftTableArray[ FileNum - 1 ]->RiftEntryAlloc = 0;
  784. RiftTableArray[ FileNum - 1 ]->RiftEntryArray = NULL;
  785. RiftTableArray[ FileNum - 1 ]->RiftUsageArray = NULL;
  786. RiftFile = fopen( FileName, "rt" );
  787. if ( RiftFile == NULL ) {
  788. printf( "Could not open %s\n", FileName );
  789. exit( 1 );
  790. }
  791. while ( fgets( TextBuffer, sizeof( TextBuffer ), RiftFile )) {
  792. //
  793. // Line looks like "00001456 00002345" where each number
  794. // is an RVA in hexadecimal and the first column is the
  795. // OldFileRva and the second column is the NewFileRva.
  796. // Any text beyond column 17 is considered a comment, and
  797. // any line that does not begin with a digit is ignored.
  798. //
  799. if (( isxdigit( *TextBuffer )) && ( strlen( TextBuffer ) >= 17 )) {
  800. OldFileRva = strtoul( TextBuffer, NULL, 16 );
  801. NewFileRva = strtoul( TextBuffer + 9, NULL, 16 );
  802. if (( OldFileRva + NewFileRva ) != 0 ) {
  803. RiftTableArray[ FileNum - 1 ]->RiftEntryArray = realloc(
  804. RiftTableArray[ FileNum - 1 ]->RiftEntryArray,
  805. RiftTableArray[ FileNum - 1 ]->RiftEntryCount * sizeof( RIFT_ENTRY ) + sizeof( RIFT_ENTRY )
  806. );
  807. RiftTableArray[ FileNum - 1 ]->RiftEntryArray[ RiftTableArray[ FileNum - 1 ]->RiftEntryCount ].OldFileRva = OldFileRva;
  808. RiftTableArray[ FileNum - 1 ]->RiftEntryArray[ RiftTableArray[ FileNum - 1 ]->RiftEntryCount ].NewFileRva = NewFileRva;
  809. RiftTableArray[ FileNum - 1 ]->RiftEntryCount++;
  810. }
  811. }
  812. }
  813. fclose( RiftFile );
  814. if ( RiftTableArray[ FileNum - 1 ]->RiftEntryCount ) {
  815. RiftTableArray[ FileNum - 1 ]->RiftEntryAlloc = RiftTableArray[ FileNum - 1 ]->RiftEntryCount;
  816. RiftTableArray[ FileNum - 1 ]->RiftUsageArray = malloc( RiftTableArray[ FileNum - 1 ]->RiftEntryCount );
  817. if ( RiftTableArray[ FileNum - 1 ]->RiftUsageArray == NULL ) {
  818. printf( "Out of memory\n" );
  819. exit( 1 );
  820. }
  821. ZeroMemory( RiftTableArray[ FileNum - 1 ]->RiftUsageArray, RiftTableArray[ FileNum - 1 ]->RiftEntryCount );
  822. }
  823. }
  824. else if ( memcmp( arg, "oldsympath:", 11 ) == 0 ) {
  825. p = strchr( arg, ':' ) + 1;
  826. q = strchr( p, ',' );
  827. if ( q ) {
  828. *q = 0;
  829. }
  830. FileName = p;
  831. FileNum = 1;
  832. if ( q ) {
  833. p = q + 1;
  834. FileNum = strtoul( p, NULL, 0 );
  835. if ( FileNum == 0 ) {
  836. FileNum = 1;
  837. }
  838. }
  839. if ( FileNum > 255 ) {
  840. Usage();
  841. }
  842. OldFileSymPathArray[ FileNum - 1 ] = _strdup( FileName );
  843. }
  844. else if ( memcmp( arg, "newsympath:", 11 ) == 0 ) {
  845. p = strchr( arg, ':' ) + 1;
  846. q = strchr( p, ',' );
  847. if ( q ) {
  848. *q = 0;
  849. }
  850. FileName = p;
  851. FileNum = 1;
  852. if ( q ) {
  853. p = q + 1;
  854. FileNum = strtoul( p, NULL, 0 );
  855. if ( FileNum == 0 ) {
  856. FileNum = 1;
  857. }
  858. }
  859. if ( FileNum != 1 ) {
  860. Usage();
  861. }
  862. NewFileSymPath = _strdup( FileName );
  863. }
  864. else {
  865. Usage();
  866. }
  867. }
  868. else if ( OldFileName == NULL ) {
  869. OldFileName = arg;
  870. }
  871. else if ( NewFileName == NULL ) {
  872. NewFileName = arg;
  873. }
  874. else if ( PatchFileName == NULL ) {
  875. PatchFileName = arg;
  876. }
  877. else {
  878. Usage();
  879. }
  880. }
  881. if (( OldFileName == NULL ) || ( NewFileName == NULL ) || ( PatchFileName == NULL )) {
  882. Usage();
  883. }
  884. OldFileCount = 0;
  885. p = OldFileName;
  886. q = strchr( OldFileName, ';' );
  887. while ( q ) {
  888. *q = 0;
  889. if ( *p ) {
  890. OldFileInfo[ OldFileCount ].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO_A );
  891. OldFileInfo[ OldFileCount ].OldFileName = p;
  892. OldFileCount++;
  893. }
  894. p = q + 1;
  895. q = strchr( p, ';' );
  896. }
  897. if ( *p ) {
  898. OldFileInfo[ OldFileCount ].SizeOfThisStruct = sizeof( PATCH_OLD_FILE_INFO_A );
  899. OldFileInfo[ OldFileCount ].OldFileName = p;
  900. OldFileCount++;
  901. }
  902. //
  903. // Make sure rift tables are ascending and don't contain duplicate
  904. // OldRva values (ambiguous).
  905. //
  906. for ( i = 0; i < (int)OldFileCount; i++ ) {
  907. if (( RiftTableArray[ i ] ) && ( RiftTableArray[ i ]->RiftEntryCount > 1 )) {
  908. n = RiftTableArray[ i ]->RiftEntryCount - 1;
  909. RiftQsort( &RiftTableArray[ i ]->RiftEntryArray[ 0 ], &RiftTableArray[ i ]->RiftEntryArray[ n ] );
  910. #ifdef TESTCODE
  911. for ( j = 0; j < n; j++ ) {
  912. if ( RiftTableArray[ i ]->RiftEntryArray[ j ].OldFileRva >
  913. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].OldFileRva ) {
  914. printf( "\nRift sort failed at index %d of %d\n", j, n + 1 );
  915. for ( j = 0; j <= n; j++ ) {
  916. printf( "%08X\n", RiftTableArray[ i ]->RiftEntryArray[ j ].OldFileRva );
  917. }
  918. exit( 1 );
  919. break;
  920. }
  921. }
  922. #endif // TESTCODE
  923. for ( j = 0; j < n; j++ ) {
  924. while (( j < n ) &&
  925. ( RiftTableArray[ i ]->RiftEntryArray[ j ].OldFileRva ==
  926. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].OldFileRva )) {
  927. if ( RiftTableArray[ i ]->RiftEntryArray[ j ].NewFileRva !=
  928. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].NewFileRva ) {
  929. //
  930. // This is an ambiguous entry since the OldRva values
  931. // match but the NewRva values do not. Report and
  932. // discard the former.
  933. //
  934. printf(
  935. "RiftInfo for %s contains ambiguous entries:\n"
  936. " OldRva:%08X NewRva:%08X (discarded)\n"
  937. " OldRva:%08X NewRva:%08X (kept)\n\n",
  938. OldFileInfo[ i ].OldFileName,
  939. RiftTableArray[ i ]->RiftEntryArray[ j ].OldFileRva,
  940. RiftTableArray[ i ]->RiftEntryArray[ j ].NewFileRva,
  941. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].OldFileRva,
  942. RiftTableArray[ i ]->RiftEntryArray[ j + 1 ].NewFileRva
  943. );
  944. }
  945. else {
  946. //
  947. // This is a completely duplicate entry, so just
  948. // silently remove it.
  949. //
  950. }
  951. MoveMemory(
  952. &RiftTableArray[ i ]->RiftEntryArray[ j ],
  953. &RiftTableArray[ i ]->RiftEntryArray[ j + 1 ],
  954. ( n - j ) * sizeof( RIFT_ENTRY )
  955. );
  956. --n;
  957. }
  958. }
  959. RiftTableArray[ i ]->RiftEntryCount = n + 1;
  960. }
  961. }
  962. for ( i = 0; i < (int)OldFileCount; i++ ) {
  963. if ( OldFileSymPathArray[ i ] == NULL ) {
  964. GetFullPathName( OldFileInfo[ i ].OldFileName, sizeof( TextBuffer ), TextBuffer, &FileNamePart );
  965. if (( FileNamePart > TextBuffer ) && ( *( FileNamePart - 1 ) == '\\' )) {
  966. *( FileNamePart - 1 ) = 0;
  967. }
  968. OldFileSymPathArray[ i ] = _strdup( TextBuffer );
  969. }
  970. }
  971. if ( NewFileSymPath == NULL ) {
  972. GetFullPathName( NewFileName, sizeof( TextBuffer ), TextBuffer, &FileNamePart );
  973. if (( FileNamePart > TextBuffer ) && ( *( FileNamePart - 1 ) == '\\' )) {
  974. *( FileNamePart - 1 ) = 0;
  975. }
  976. NewFileSymPath = _strdup( TextBuffer );
  977. }
  978. OptionData.NewFileSymbolPath = NewFileSymPath;
  979. OptionData.OldFileSymbolPathArray = OldFileSymPathArray;
  980. if ( OptionData.SymbolOptionFlags & PATCH_SYMBOL_EXTERNAL_RIFT ) {
  981. OptionData.OldFileSymbolPathArray = (PVOID)RiftTableArray;
  982. }
  983. OptionData.SymLoadCallback = MySymLoadCallback;
  984. OptionData.SymLoadContext = FileNameArray;
  985. FileNameArray[ 0 ] = (LPSTR)NewFileName;
  986. for ( i = 0; i < (int)OldFileCount; i++ ) {
  987. FileNameArray[ i + 1 ] = (LPSTR)OldFileInfo[ i ].OldFileName;
  988. }
  989. Success = CreatePatchFileEx(
  990. OldFileCount,
  991. OldFileInfo,
  992. NewFileName,
  993. PatchFileName,
  994. OptionFlags,
  995. &OptionData,
  996. bNoProgress ? NULL : MyProgressCallback,
  997. NULL
  998. );
  999. ErrorCode = GetLastError();
  1000. printf( "\n\n" );
  1001. if ( ! Success ) {
  1002. CHAR ErrorText[ 16 ];
  1003. sprintf( ErrorText, ( ErrorCode < 0x10000000 ) ? "%d" : "%X", ErrorCode );
  1004. printf( "Failed to create patch (%s)\n", ErrorText );
  1005. exit( 1 );
  1006. }
  1007. NewFileSize = (ULONG) GetFileSizeByName( NewFileName );
  1008. PatchFileSize = (ULONG) GetFileSizeByName( PatchFileName );
  1009. if (( NewFileSize != 0xFFFFFFFF ) && ( NewFileSize != 0 ) && ( PatchFileSize != 0xFFFFFFFF )) {
  1010. printf( "%d bytes (%3.1f%% compression, %.1f:1)\n",
  1011. PatchFileSize,
  1012. ((((LONG)NewFileSize - (LONG)PatchFileSize ) * 100.0 ) / NewFileSize ),
  1013. ((double)NewFileSize / PatchFileSize )
  1014. );
  1015. if ( ! bNoCompare ) {
  1016. CHAR TempFile1[ MAX_PATH ];
  1017. CHAR TempFile2[ MAX_PATH ];
  1018. HANDLE hFile;
  1019. GetTempPath( MAX_PATH, TempFile1 );
  1020. GetTempPath( MAX_PATH, TempFile2 );
  1021. strcat( TempFile1, "\\tt$$src.$$$" );
  1022. strcat( TempFile2, "\\tt$$pat.$$$" );
  1023. hFile = CreateFile(
  1024. TempFile1,
  1025. GENERIC_READ | GENERIC_WRITE,
  1026. FILE_SHARE_READ,
  1027. NULL,
  1028. CREATE_ALWAYS,
  1029. FILE_ATTRIBUTE_TEMPORARY,
  1030. NULL
  1031. );
  1032. if ( hFile != INVALID_HANDLE_VALUE ) {
  1033. CloseHandle( hFile );
  1034. Success = CreatePatchFile(
  1035. TempFile1,
  1036. NewFileName,
  1037. TempFile2,
  1038. OptionFlags & ~PATCH_OPTION_FAIL_IF_BIGGER,
  1039. NULL
  1040. );
  1041. if ( Success ) {
  1042. ULONG CompFileSize = (ULONG) GetFileSizeByName( TempFile2 );
  1043. if (( CompFileSize != 0xFFFFFFFF ) && ( CompFileSize != 0 )) {
  1044. if ( CompFileSize <= PatchFileSize ) {
  1045. printf( "\nWARNING: Simply compressing %s would be %d bytes smaller (%3.1f%%)\n",
  1046. NewFileName,
  1047. PatchFileSize - CompFileSize,
  1048. ((((LONG)PatchFileSize - (LONG)CompFileSize ) * 100.0 ) / CompFileSize )
  1049. );
  1050. }
  1051. else if ( NewFileSize != 0 ) {
  1052. printf( "\n%d bytes saved (%3.1f%%) over non-patching compression\n",
  1053. CompFileSize - PatchFileSize,
  1054. ((((LONG)CompFileSize - (LONG)PatchFileSize ) * 100.0 ) / NewFileSize )
  1055. );
  1056. }
  1057. }
  1058. }
  1059. }
  1060. DeleteFile( TempFile1 );
  1061. DeleteFile( TempFile2 );
  1062. }
  1063. }
  1064. else {
  1065. printf( "OK\n" );
  1066. }
  1067. exit( 0 );
  1068. }