ReactOS  0.4.14-dev-297-g23e575c
mspatcha_main.c
Go to the documentation of this file.
1 /*
2  * PatchAPI
3  *
4  * Copyright 2011 David Hedberg for CodeWeavers
5  * Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define WIN32_NO_STATUS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "ndk/rtlfuncs.h"
27 #include "patchapi.h"
28 #include "lzx.h"
29 #include "wine/debug.h"
30 
31 static const char szHexString[] = "0123456789abcdef";
32 #define SIGNATURE_MIN_SIZE 9
33 
34 #define UNKNOWN_FLAGS_COMBINATION 0x00c40001
35 
36 
38 
39 
40 typedef struct _SAFE_READ
41 {
46 
47 
58 {
59  if (pRead->Ptr + sizeof(BYTE) <= (pRead->Root + pRead->Size))
60  {
61  BYTE Value = *(PBYTE)pRead->Ptr;
62  pRead->Ptr += sizeof(BYTE);
63  return Value;
64  }
65  pRead->Ptr = pRead->Root + pRead->Size;
66  return 0;
67 }
68 
79 {
80  if (pRead->Ptr + sizeof(USHORT) <= (pRead->Root + pRead->Size))
81  {
82  USHORT Value = *(PUSHORT)pRead->Ptr;
83  pRead->Ptr += sizeof(USHORT);
84  return Value;
85  }
86  pRead->Ptr = pRead->Root + pRead->Size;
87  return 0;
88 }
89 
100 {
101  if (pRead->Ptr + sizeof(DWORD) <= (pRead->Root + pRead->Size))
102  {
103  DWORD Value = *(PDWORD)pRead->Ptr;
104  pRead->Ptr += sizeof(DWORD);
105  return Value;
106  }
107  pRead->Ptr = pRead->Root + pRead->Size;
108  return 0;
109 }
110 
121 {
122  UINT Result = 0, offset;
123 
124  for (offset = 0; offset < 32; offset += 7)
125  {
126  DWORD val = ReadByte(pRead);
127  Result |= ((val & 0x7f) << offset);
128  if (val & 0x80)
129  break;
130  }
131 
132  return Result;
133 }
134 
135 
146 {
147  INT Result = 0, offset;
148 
149  for (offset = 0; offset < 32; offset += 6)
150  {
151  INT val = (INT)(DWORD)ReadByte(pRead);
152  Result |= ((val & 0x3f) << offset);
153  if (val & 0x80)
154  {
155  if (val & 0x40)
156  Result *= -1;
157  break;
158  }
159  }
160 
161  return Result;
162 }
163 
164 
165 typedef struct _PATCH_HEADER
166 {
168 
171 
174 
177  DWORD DataSize; // Payload after the patch header
178 
179 } PATCH_HEADER;
180 
181 
195 {
196  HANDLE hMap;
197  PVOID pView;
198 
201  if (hMap != INVALID_HANDLE_VALUE)
202  {
203  pView = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
204  CloseHandle(hMap);
205  return pView;
206  }
207 
208  return NULL;
209 }
210 
211 
212 /*****************************************************
213  * DllMain (MSPATCHA.@)
214  */
216 {
217  switch (fdwReason)
218  {
219  case DLL_PROCESS_ATTACH:
220  DisableThreadLibraryCalls(hinstDLL);
221  break;
222  }
223 
224  return TRUE;
225 }
226 
227 /*****************************************************
228  * ApplyPatchToFileA (MSPATCHA.1)
229  */
230 BOOL WINAPI ApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, LPCSTR new_file, ULONG apply_flags)
231 {
232  BOOL ret = FALSE;
233  HANDLE hPatch, hOld, hNew;
234 
237  if (hPatch != INVALID_HANDLE_VALUE)
238  {
241  if (hOld != INVALID_HANDLE_VALUE)
242  {
245  if (hNew != INVALID_HANDLE_VALUE)
246  {
247  ret = ApplyPatchToFileByHandles(hPatch, hOld, hNew, apply_flags);
248  CloseHandle(hNew);
249  }
250  CloseHandle(hOld);
251  }
252  CloseHandle(hPatch);
253  }
254 
255  return ret;
256 }
257 
258 
273 {
274  DWORD Crc, Unknown;
275  int Delta;
276 
277  ZeroMemory(Header, sizeof(*Header));
278 
279  /* Validate the patch */
280  Crc = RtlComputeCrc32(0, Patch->Root, Patch->Size);
281  if (Crc != ~0)
282  return ERROR_PATCH_CORRUPT;
283 
284  if (ReadDWord(Patch) != '91AP')
286 
287  /* Read the flags, warn about an unknown combination */
288  Header->Flags = ReadDWord(Patch);
289  if (Header->Flags ^ UNKNOWN_FLAGS_COMBINATION)
290  ERR("Unknown flags: 0x%x, patch will most likely fail\n", Header->Flags ^ UNKNOWN_FLAGS_COMBINATION);
291 
292  /* 0x5bb3284e, 0x5bb33562, 0x5bb357b1 */
294  TRACE("Unknown: 0x%x\n", Unknown);
295 
296  Header->OutputSize = DecodeDWord(Patch);
297  Header->OutputCrc = ReadDWord(Patch);
298 
300  if (Unknown != 1)
301  ERR("Field after CRC is not 1 but %u\n", Unknown);
302 
303  Delta = DecodeInt(Patch);
304  Header->OldSize = Header->OutputSize + Delta;
305  Header->OldCrc = ReadDWord(Patch);
306 
308  if (Unknown != 0)
309  ERR("Field1 after OldCrc is not 0 but %u\n", Unknown);
310 
312  if (Unknown != 0)
313  ERR("Field2 after OldCrc is not 0 but %u\n", Unknown);
314 
315  Header->DataSize = DecodeDWord(Patch);
316  /* Remaining data, minus the CRC appended */
317  if (Header->DataSize != (Patch->Size - (Patch->Ptr - Patch->Root) - sizeof(DWORD)))
318  {
319  ERR("Unable to read header, check previous logging!\n");
321  }
322  return STATUS_SUCCESS;
323 }
324 
341 {
342  SAFE_READ NewFile;
343  HANDLE hMap;
344  USHORT BlockSize;
345  DWORD dwStatus;
346  struct LZXstate* state;
347  int lzxResult;
348 
349  hMap = CreateFileMappingW(new_file, NULL, PAGE_READWRITE, 0, Header->OutputSize, NULL);
350  if (hMap == INVALID_HANDLE_VALUE)
352 
353  NewFile.Root = NewFile.Ptr = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
354  CloseHandle(hMap);
355  NewFile.Size = Header->OutputSize;
356 
357  if (!NewFile.Root)
359 
360  /* At this point Patch->Ptr should point to the payload */
361  BlockSize = ReadUShort(Patch);
362 
363  /* This window size does not work on all files (for example, MS SQL Express 2008 setup) */
364  state = LZXinit(17);
365  if (state)
366  {
367  lzxResult = LZXdecompress(state, Patch->Ptr, NewFile.Ptr, BlockSize, NewFile.Size);
369 
370  if (lzxResult == DECR_OK)
372  else
374  }
375  else
376  {
378  }
379 
380  UnmapViewOfFile(NewFile.Root);
381  return dwStatus;
382 }
383 
384 
385 /*****************************************************
386  * ApplyPatchToFileByHandles (MSPATCHA.2)
387  */
389 {
390  SAFE_READ Patch, OldFile;
391  DWORD dwStatus;
393 
394  Patch.Root = Patch.Ptr = MapFile(patch_file, &Patch.Size);
395  if (!Patch.Root)
396  {
398  return FALSE;
399  }
400 
401  /* Let's decode the header */
403  if (dwStatus != STATUS_SUCCESS)
404  {
405  UnmapViewOfFile(Patch.Root);
407  return FALSE;
408  }
409 
410  OldFile.Root = OldFile.Ptr = MapFile(old_file, &OldFile.Size);
411  if (OldFile.Root)
412  {
413  DWORD dwCrc;
414 
415  /* Verify the input file */
416  dwCrc = RtlComputeCrc32(0, OldFile.Root, OldFile.Size);
417  if (OldFile.Size == Header.OldSize && dwCrc == Header.OldCrc)
418  {
419  if (apply_flags & APPLY_OPTION_TEST_ONLY)
421  else
423  }
424  else
425  {
427  }
428  UnmapViewOfFile(OldFile.Root);
429  }
430  else
431  {
433  if (dwStatus == STATUS_SUCCESS)
435  }
436 
437  UnmapViewOfFile(Patch.Root);
439  return dwStatus == STATUS_SUCCESS;
440 }
441 
442 /*****************************************************
443  * ApplyPatchToFileW (MSPATCHA.6)
444  */
446 {
447  BOOL ret = FALSE;
448  HANDLE hPatch, hOld, hNew;
449 
452  if (hPatch != INVALID_HANDLE_VALUE)
453  {
456  if (hOld != INVALID_HANDLE_VALUE)
457  {
460  if (hNew != INVALID_HANDLE_VALUE)
461  {
462  ret = ApplyPatchToFileByHandles(hPatch, hOld, hNew, apply_flags);
463  CloseHandle(hNew);
464  }
465  CloseHandle(hOld);
466  }
467  CloseHandle(hPatch);
468  }
469 
470  return ret;
471 }
472 
473 /*****************************************************
474  * GetFilePatchSignatureA (MSPATCHA.7)
475  */
477  PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count,
479 {
480  BOOL ret = FALSE;
481  HANDLE hFile;
482 
486  {
487  ret = GetFilePatchSignatureByHandle(hFile, flags, data, ignore_range_count, ignore_range,
488  retain_range_count, retain_range, bufsize, buffer);
490  }
491 
492  return ret;
493 }
494 
495 /*****************************************************
496  * GetFilePatchSignatureA (MSPATCHA.7)
497  */
499  PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count,
501 {
502  BOOL ret = FALSE;
503  DWORD dwSize, ulCrc;
504  PBYTE pData;
505 
506  if (flags)
507  FIXME("Unhandled flags 0x%x\n", flags);
508  if (ignore_range_count)
509  FIXME("Unhandled ignore_range_count %u\n", ignore_range_count);
510  if (retain_range_count)
511  FIXME("Unhandled ignore_range_count %u\n", retain_range_count);
512 
513  if ((pData = MapFile(hFile, &dwSize)))
514  {
515  if (dwSize >= 2 && *(PWORD)pData == IMAGE_DOS_SIGNATURE)
516  {
517  FIXME("Potentially unimplemented case, normalized signature\n");
518  }
519 
520  ulCrc = RtlComputeCrc32(0, pData, dwSize);
522  {
523  char *pBuffer = buffer;
524  pBuffer[8] = '\0';
525  for (dwSize = 0; dwSize < 8; ++dwSize)
526  {
527  pBuffer[7 - dwSize] = szHexString[ulCrc & 0xf];
528  ulCrc >>= 4;
529  }
530  ret = TRUE;
531  }
533 
536  }
537 
538  return ret;
539 }
540 
541 /*****************************************************
542  * GetFilePatchSignatureW (MSPATCHA.9)
543  */
545  PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count,
547 {
548  CHAR LocalBuf[SIGNATURE_MIN_SIZE];
549  BOOL ret = FALSE;
550  HANDLE hFile;
551 
555  {
556  ret = GetFilePatchSignatureByHandle(hFile, flags, data, ignore_range_count, ignore_range,
557  retain_range_count, retain_range, sizeof(LocalBuf), LocalBuf);
559 
560  if (bufsize < (SIGNATURE_MIN_SIZE * sizeof(WCHAR)))
561  {
563  return FALSE;
564  }
565  if (ret)
566  {
567  MultiByteToWideChar(CP_ACP, 0, LocalBuf, -1, buffer, bufsize / sizeof(WCHAR));
568  }
569  }
570 
571  return ret;
572 }
573 
574 /*****************************************************
575  * TestApplyPatchToFileA (MSPATCHA.10)
576  */
578 {
579  BOOL ret = FALSE;
580  HANDLE hPatch, hOld;
581 
584  if (hPatch != INVALID_HANDLE_VALUE)
585  {
588  if (hOld != INVALID_HANDLE_VALUE)
589  {
590  ret = TestApplyPatchToFileByHandles(hPatch, hOld, apply_flags);
591  CloseHandle(hOld);
592  }
593  CloseHandle(hPatch);
594  }
595 
596  return ret;
597 }
598 
599 /*****************************************************
600  * TestApplyPatchToFileByHandles (MSPATCHA.11)
601  */
603 {
605 }
606 
607 /*****************************************************
608  * TestApplyPatchToFileW (MSPATCHA.12)
609  */
611 {
612  BOOL ret = FALSE;
613  HANDLE hPatch, hOld;
614 
617  if (hPatch != INVALID_HANDLE_VALUE)
618  {
621  if (hOld != INVALID_HANDLE_VALUE)
622  {
623  ret = TestApplyPatchToFileByHandles(hPatch, hOld, apply_flags);
624  CloseHandle(hOld);
625  }
626  CloseHandle(hPatch);
627  }
628 
629  return ret;
630 }
DWORD ImageTimeStamp
_In_opt_ ULONG _Out_ PULONG Value
Definition: rtlfuncs.h:2343
static const char szHexString[]
Definition: mspatcha_main.c:31
BYTE ReadByte(PSAFE_READ pRead)
Definition: mspatcha_main.c:57
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
struct LZXstate * LZXinit(int wndsize)
Definition: lzx.c:172
#define MapViewOfFile
Definition: compat.h:402
DWORD ReadDWord(PSAFE_READ pRead)
Definition: mspatcha_main.c:99
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
BOOL WINAPI GetFilePatchSignatureW(LPCWSTR filename, ULONG flags, PVOID data, ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, PVOID buffer)
struct _PATCH_HEADER PATCH_HEADER
#define CP_ACP
Definition: compat.h:99
BOOL WINAPI GetFilePatchSignatureByHandle(HANDLE hFile, ULONG flags, PVOID data, ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, PVOID buffer)
char CHAR
Definition: xmlstorage.h:175
#define INT
Definition: polytest.cpp:20
GLintptr offset
Definition: glext.h:5920
void LZXteardown(struct LZXstate *pState)
Definition: lzx.c:209
BOOL WINAPI DisableThreadLibraryCalls(IN HMODULE hLibModule)
Definition: loader.c:85
#define APPLY_OPTION_TEST_ONLY
Definition: patchapi.h:28
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1642
GLuint buffer
Definition: glext.h:5915
struct _Patch Patch
#define DLL_PROCESS_ATTACH
Definition: compat.h:120
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
GLenum GLuint GLsizei bufsize
Definition: glext.h:7473
const char * filename
Definition: ioapi.h:135
BOOL WINAPI ApplyPatchToFileByHandles(HANDLE patch_file, HANDLE old_file, HANDLE new_file, ULONG apply_flags)
int32_t INT
Definition: typedefs.h:56
static IN DWORD IN LPVOID lpvReserved
#define FILE_SHARE_READ
Definition: compat.h:125
DWORD CreateNewFileFromPatch(PATCH_HEADER *Header, SAFE_READ *Patch, HANDLE new_file)
struct _SAFE_READ SAFE_READ
#define IMAGE_DOS_SIGNATURE
Definition: pedump.c:89
#define DECR_OK
Definition: mszip.h:79
Definition: patch.h:62
Definition: Header.h:8
unsigned int BOOL
Definition: ntddk_ex.h:94
BOOL WINAPI TestApplyPatchToFileByHandles(HANDLE patch_file, HANDLE old_file, ULONG apply_flags)
#define GENERIC_WRITE
Definition: nt_native.h:90
#define FIXME(fmt,...)
Definition: debug.h:110
smooth NULL
Definition: ftsmooth.c:416
PVOID pBuffer
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
struct _SAFE_READ * PSAFE_READ
#define FILE_MAP_READ
Definition: compat.h:427
const char * LPCSTR
Definition: xmlstorage.h:183
#define OPEN_EXISTING
Definition: compat.h:426
GLuint GLfloat * val
Definition: glext.h:7180
#define SIGNATURE_MIN_SIZE
Definition: mspatcha_main.c:32
WORD * PWORD
Definition: pedump.c:67
#define ERROR_PATCH_NOT_AVAILABLE
Definition: patchapi.h:40
BOOL WINAPI ApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, LPCSTR new_file, ULONG apply_flags)
#define TRACE(s)
Definition: solgame.cpp:4
static PBYTE MapFile(HANDLE hFile, DWORD *dwSize)
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define CreateFileMappingW(a, b, c, d, e, f)
Definition: compat.h:401
#define FILE_MAP_WRITE
Definition: winbase.h:154
USHORT ReadUShort(PSAFE_READ pRead)
Definition: mspatcha_main.c:78
#define WINAPI
Definition: msvc.h:8
BOOL WINAPI ApplyPatchToFileW(LPCWSTR patch_file, LPCWSTR old_file, LPCWSTR new_file, ULONG apply_flags)
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:481
#define SetLastError(x)
Definition: compat.h:409
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLbitfield flags
Definition: glext.h:7161
int ret
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
DWORD ParseHeader(SAFE_READ *Patch, PATCH_HEADER *Header)
static int state
Definition: maze.c:121
unsigned char BYTE
Definition: mem.h:68
BOOL WINAPI TestApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, ULONG apply_flags)
#define GENERIC_READ
Definition: compat.h:124
#define ERROR_PATCH_DECODE_FAILURE
Definition: patchapi.h:35
_In_ HANDLE hFile
Definition: mswsock.h:90
#define ERROR_PATCH_CORRUPT
Definition: patchapi.h:36
#define ERR(fmt,...)
Definition: debug.h:109
WINE_DEFAULT_DEBUG_CHANNEL(mspatcha)
#define CREATE_ALWAYS
Definition: disk.h:72
DWORD dwStatus
Definition: mediaobj.idl:95
NTSYSAPI ULONG NTAPI RtlComputeCrc32(_In_ ULONG InitialCrc, _In_ PUCHAR Buffer, _In_ ULONG Length)
unsigned short USHORT
Definition: pedump.c:61
#define FILE_FLAG_SEQUENTIAL_SCAN
Definition: disk.h:43
static ULONG Delta
Definition: xboxvideo.c:32
BOOL WINAPI GetFilePatchSignatureA(LPCSTR filename, ULONG flags, PVOID data, ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, PVOID buffer)
DWORD DecodeDWord(PSAFE_READ pRead)
unsigned int UINT
Definition: ndis.h:50
#define PAGE_READONLY
Definition: compat.h:127
DWORD * PDWORD
Definition: pedump.c:68
#define MultiByteToWideChar
Definition: compat.h:100
#define CreateFileW
Definition: compat.h:400
INT DecodeInt(PSAFE_READ pRead)
unsigned int ULONG
Definition: retypes.h:1
int LZXdecompress(struct LZXstate *pState, unsigned char *inpos, unsigned char *outpos, int inlen, int outlen)
Definition: lzx.c:461
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:399
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1827
#define ERROR_PATCH_WRONG_FILE
Definition: patchapi.h:38
return STATUS_SUCCESS
Definition: btrfs.c:2966
#define UnmapViewOfFile
Definition: compat.h:403
BOOL WINAPI TestApplyPatchToFileW(LPCWSTR patch_file, LPCWSTR old_file, ULONG apply_flags)
BYTE * PBYTE
Definition: pedump.c:66
#define UNKNOWN_FLAGS_COMBINATION
Definition: mspatcha_main.c:34
unsigned short * PUSHORT
Definition: retypes.h:2
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:54
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
static UINT patch_file(MSIPACKAGE *package, MSIFILEPATCH *patch)
Definition: files.c:505