This can patch non-executables and 64-bit executable files, but patching of 32-bit executables is not supported. They are subject to special processing which alters relocations to match with those in the old file to improve compression. To reverse this, the meaning of the decoding data must be interpreted. Details, including where to find that data in the patch file, are included in pa19.c. Interleaved decompression of large files is also not supported.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=12501 Signed-off-by: Conor McCarthy conor.mccarthy.444@gmail.com --- dlls/mspatcha/Makefile.in | 4 +- dlls/mspatcha/mspatcha.spec | 28 ++--- dlls/mspatcha/mspatcha_main.c | 244 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 233 insertions(+), 43 deletions(-)
diff --git a/dlls/mspatcha/Makefile.in b/dlls/mspatcha/Makefile.in index bd0da7d..34cf719 100644 --- a/dlls/mspatcha/Makefile.in +++ b/dlls/mspatcha/Makefile.in @@ -2,6 +2,8 @@ MODULE = mspatcha.dll IMPORTLIB = mspatcha
C_SRCS = \ - mspatcha_main.c + mspatcha_main.c \ + pa19.c \ + lzxd_dec.c
RC_SRCS = version.rc diff --git a/dlls/mspatcha/mspatcha.spec b/dlls/mspatcha/mspatcha.spec index cc8ca94..8c014b9 100644 --- a/dlls/mspatcha/mspatcha.spec +++ b/dlls/mspatcha/mspatcha.spec @@ -1,12 +1,16 @@ -1 stdcall ApplyPatchToFileA(str str str long) -2 stub ApplyPatchToFileByHandles -3 stub ApplyPatchToFileByHandlesEx -4 stub ApplyPatchToFileExA -5 stub ApplyPatchToFileExW -6 stdcall ApplyPatchToFileW(wstr wstr wstr long) -7 stdcall GetFilePatchSignatureA(str long ptr long ptr long ptr long ptr) -8 stub GetFilePatchSignatureByHandle -9 stdcall GetFilePatchSignatureW(wstr long ptr long ptr long ptr long ptr) -10 stub TestApplyPatchToFileA -11 stub TestApplyPatchToFileByHandles -12 stub TestApplyPatchToFileW +@ stdcall ApplyPatchToFileA(str str str long) +@ stdcall ApplyPatchToFileByBuffers(ptr long ptr long ptr long ptr ptr long ptr ptr) +@ stdcall ApplyPatchToFileByHandles(ptr ptr ptr long) +@ stdcall ApplyPatchToFileByHandlesEx(ptr ptr ptr long ptr ptr) +@ stdcall ApplyPatchToFileExA(str str str long ptr ptr) +@ stdcall ApplyPatchToFileExW(wstr wstr wstr long ptr ptr) +@ stdcall ApplyPatchToFileW(wstr wstr wstr long) +@ stdcall GetFilePatchSignatureA(str long ptr long ptr long ptr long str) +@ stdcall GetFilePatchSignatureByBuffer(ptr long long ptr long ptr long ptr long str) +@ stdcall GetFilePatchSignatureByHandle(ptr long ptr long ptr long ptr long str) +@ stdcall GetFilePatchSignatureW(wstr long ptr long ptr long ptr long wstr) +@ stdcall NormalizeFileForPatchSignature(ptr long long ptr long long long ptr long ptr) +@ stdcall TestApplyPatchToFileA(str str long) +@ stdcall TestApplyPatchToFileByBuffers(ptr long ptr long ptr long) +@ stdcall TestApplyPatchToFileByHandles(ptr ptr long) +@ stdcall TestApplyPatchToFileW(wstr wstr long) diff --git a/dlls/mspatcha/mspatcha_main.c b/dlls/mspatcha/mspatcha_main.c index f78b8ab..276e9e3 100644 --- a/dlls/mspatcha/mspatcha_main.c +++ b/dlls/mspatcha/mspatcha_main.c @@ -2,6 +2,7 @@ * PatchAPI * * Copyright 2011 David Hedberg for CodeWeavers + * Copyright 2019 Conor McCarthy (implementations) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,6 +17,31 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * TODO + * - Special processing of 32-bit executables is not supported, so this + * version cannot patch 32-bit .exe and .dll files. See pa19.c for details. + * - Implement interleaved decoding when PATCH_OPTION_INTERLEAVE_FILES was + * used or the old file exceeds the lzxd window size. + * - APPLY_OPTION_FAIL_IF_CLOSE is ignored. Normalization of 32-bit PE files + * is required for checking this. + * - GetFilePatchSignature* and NormalizeFileForPatchSignature require a + * solution to the above 32-bit exe problem. */
#include "config.h" @@ -28,6 +54,8 @@ #include "patchapi.h" #include "wine/debug.h"
+#include "pa19.h" + WINE_DEFAULT_DEBUG_CHANNEL(mspatcha);
/***************************************************** @@ -49,79 +77,235 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; }
-static inline WCHAR *strdupAW( const char *src ) +static WCHAR *strdupAW(const char *src) { WCHAR *dst = NULL; if (src) { - int len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); - if ((dst = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) - MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); + int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + if ((dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) + MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len); } return dst; }
/***************************************************** - * ApplyPatchToFileA (MSPATCHA.1) + * TestApplyPatchToFileA (MSPATCHA.@) */ -BOOL WINAPI ApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, LPCSTR new_file, ULONG apply_flags) +BOOL WINAPI TestApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, ULONG apply_flags) +{ + BOOL ret; + WCHAR *patch_fileW, *old_fileW = NULL; + + if (!(patch_fileW = strdupAW(patch_file))) return FALSE; + if (old_file && !(old_fileW = strdupAW(old_file))) + { + HeapFree(GetProcessHeap(), 0, patch_fileW); + return FALSE; + } + ret = apply_patch_to_file(patch_fileW, old_fileW, NULL, apply_flags, NULL, NULL, TRUE); + HeapFree(GetProcessHeap(), 0, patch_fileW); + HeapFree(GetProcessHeap(), 0, old_fileW); + return ret; +} + +BOOL WINAPI TestApplyPatchToFileW(LPCWSTR patch_file_name, LPCWSTR old_file_name, ULONG apply_option_flags) +{ + return apply_patch_to_file(patch_file_name, old_file_name, NULL, apply_option_flags, NULL, NULL, TRUE); +} + +BOOL WINAPI TestApplyPatchToFileByHandles(HANDLE patch_file_hndl, HANDLE old_file_hndl, ULONG apply_option_flags) +{ + return apply_patch_to_file_by_handles(patch_file_hndl, old_file_hndl, NULL, + apply_option_flags, NULL, NULL, TRUE); +} + +BOOL WINAPI TestApplyPatchToFileByBuffers(BYTE *patch_file_buf, ULONG patch_file_size, + BYTE *old_file_buf, ULONG old_file_size, + ULONG* new_file_size, + ULONG apply_option_flags) +{ + /* preserve last error on success as per windows */ + DWORD last = GetLastError(); + + DWORD err = apply_patch_to_file_by_buffers(patch_file_buf, patch_file_size, + old_file_buf, old_file_size, + NULL, 0, new_file_size, NULL, + apply_option_flags, + NULL, NULL, + TRUE); + + SetLastError(err == ERROR_SUCCESS ? last : err); + + return err == ERROR_SUCCESS; +} + +/***************************************************** + * ApplyPatchToFileExA (MSPATCHA.@) + */ +BOOL WINAPI ApplyPatchToFileExA(LPCSTR patch_file, LPCSTR old_file, LPCSTR new_file, ULONG apply_flags, + PPATCH_PROGRESS_CALLBACK progress_fn, PVOID progress_ctx) { BOOL ret; WCHAR *patch_fileW, *new_fileW, *old_fileW = NULL;
- if (!(patch_fileW = strdupAW( patch_file ))) return FALSE; - if (old_file && !(old_fileW = strdupAW( old_file ))) + if (!(patch_fileW = strdupAW(patch_file))) return FALSE; + if (old_file && !(old_fileW = strdupAW(old_file))) { - HeapFree( GetProcessHeap(), 0, patch_fileW ); + HeapFree(GetProcessHeap(), 0, patch_fileW); return FALSE; } - if (!(new_fileW = strdupAW( new_file ))) + if (!(new_fileW = strdupAW(new_file))) { - HeapFree( GetProcessHeap(), 0, patch_fileW ); - HeapFree( GetProcessHeap(), 0, old_fileW ); + HeapFree(GetProcessHeap(), 0, patch_fileW); + HeapFree(GetProcessHeap(), 0, old_fileW); return FALSE; } - ret = ApplyPatchToFileW( patch_fileW, old_fileW, new_fileW, apply_flags ); - HeapFree( GetProcessHeap(), 0, patch_fileW ); - HeapFree( GetProcessHeap(), 0, old_fileW ); - HeapFree( GetProcessHeap(), 0, new_fileW ); + ret = apply_patch_to_file(patch_fileW, old_fileW, new_fileW, apply_flags, progress_fn, progress_ctx, FALSE); + HeapFree(GetProcessHeap(), 0, patch_fileW); + HeapFree(GetProcessHeap(), 0, old_fileW); + HeapFree(GetProcessHeap(), 0, new_fileW); return ret; }
/***************************************************** - * ApplyPatchToFileW (MSPATCHA.6) + * ApplyPatchToFileA (MSPATCHA.@) */ -BOOL WINAPI ApplyPatchToFileW(LPCWSTR patch_file, LPCWSTR old_file, LPCWSTR new_file, ULONG apply_flags) +BOOL WINAPI ApplyPatchToFileA(LPCSTR patch_file, LPCSTR old_file, LPCSTR new_file, ULONG apply_flags) { - FIXME("stub - %s, %s, %s, %08x\n", debugstr_w(patch_file), debugstr_w(old_file), - debugstr_w(new_file), apply_flags); + return ApplyPatchToFileExA(patch_file, old_file, new_file, apply_flags, NULL, NULL); +}
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; +/***************************************************** + * ApplyPatchToFileW (MSPATCHA.@) + */ +BOOL WINAPI ApplyPatchToFileW(LPCWSTR patch_file_name, LPCWSTR old_file_name, LPCWSTR new_file_name, + ULONG apply_option_flags) +{ + return apply_patch_to_file(patch_file_name, old_file_name, new_file_name, apply_option_flags, + NULL, NULL, FALSE); +} + +/***************************************************** + * ApplyPatchToFileByHandles (MSPATCHA.@) + */ +BOOL WINAPI ApplyPatchToFileByHandles(HANDLE patch_file_hndl, HANDLE old_file_hndl, HANDLE new_file_hndl, + ULONG apply_option_flags) +{ + return apply_patch_to_file_by_handles(patch_file_hndl, old_file_hndl, new_file_hndl, + apply_option_flags, NULL, NULL, FALSE); +} + +/***************************************************** + * ApplyPatchToFileExW (MSPATCHA.@) + */ +BOOL WINAPI ApplyPatchToFileExW(LPCWSTR patch_file_name, LPCWSTR old_file_name, LPCWSTR new_file_name, + ULONG apply_option_flags, + PPATCH_PROGRESS_CALLBACK progress_fn, PVOID progress_ctx) +{ + return apply_patch_to_file(patch_file_name, old_file_name, new_file_name, apply_option_flags, + progress_fn, progress_ctx, FALSE); }
/***************************************************** - * GetFilePatchSignatureA (MSPATCHA.7) + * ApplyPatchToFileByHandlesEx (MSPATCHA.@) + */ +BOOL WINAPI ApplyPatchToFileByHandlesEx(HANDLE patch_file_hndl, HANDLE old_file_hndl, HANDLE new_file_hndl, + ULONG apply_option_flags, + PPATCH_PROGRESS_CALLBACK progress_fn, + PVOID progress_ctx) +{ + return apply_patch_to_file_by_handles(patch_file_hndl, old_file_hndl, new_file_hndl, + apply_option_flags, progress_fn, progress_ctx, FALSE); +} + +/***************************************************** + * ApplyPatchToFileByBuffers (MSPATCHA.@) + */ +BOOL WINAPI ApplyPatchToFileByBuffers(PBYTE patch_file_view, ULONG patch_file_size, + PBYTE old_file_view, ULONG old_file_size, + PBYTE* new_file_buf, ULONG new_file_buf_size, ULONG* new_file_size, + FILETIME* new_file_time, + ULONG apply_option_flags, + PPATCH_PROGRESS_CALLBACK progress_fn, PVOID progress_ctx) +{ + /* preserve last error on success as per windows */ + DWORD last = GetLastError(); + + DWORD err = apply_patch_to_file_by_buffers(patch_file_view, patch_file_size, + old_file_view, old_file_size, + new_file_buf, new_file_buf_size, new_file_size, new_file_time, + apply_option_flags, + progress_fn, progress_ctx, + FALSE); + + SetLastError(err == ERROR_SUCCESS ? last : err); + + return err == ERROR_SUCCESS; +} + +/***************************************************** + * GetFilePatchSignatureA (MSPATCHA.@) */ 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, LPSTR buffer) + PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count, + PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, LPSTR buffer) { FIXME("stub - %s, %x, %p, %u, %p, %u, %p, %u, %p\n", debugstr_a(filename), flags, data, - ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer); + ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; }
/***************************************************** - * GetFilePatchSignatureW (MSPATCHA.9) + * GetFilePatchSignatureW (MSPATCHA.@) */ 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, LPWSTR buffer) + PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count, + PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, LPWSTR buffer) { FIXME("stub - %s, %x, %p, %u, %p, %u, %p, %u, %p\n", debugstr_w(filename), flags, data, - ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer); + ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/***************************************************** + * GetFilePatchSignatureByHandle (MSPATCHA.@) + */ +BOOL WINAPI GetFilePatchSignatureByHandle(HANDLE handle, ULONG flags, PVOID options, ULONG ignore_range_count, + PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count, + PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, LPSTR buffer) +{ + FIXME("stub - %p, %x, %p, %u, %p, %u, %p, %u, %p\n", handle, flags, options, + ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/***************************************************** + * GetFilePatchSignatureByBuffer (MSPATCHA.@) + */ +BOOL WINAPI GetFilePatchSignatureByBuffer(PBYTE file_buf, ULONG file_size, ULONG flags, PVOID options, + ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range, + ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range, + ULONG bufsize, LPSTR buffer) +{ + FIXME("stub - %p, %u, %x, %p, %u, %p, %u, %p, %u, %p\n", file_buf, file_size, flags, options, + ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } + +/***************************************************** + * NormalizeFileForPatchSignature (MSPATCHA.@) + */ +INT WINAPI NormalizeFileForPatchSignature(PVOID file_buffer, ULONG file_size, ULONG flags, PATCH_OPTION_DATA *options, + ULONG new_coff_base, ULONG new_coff_time, ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range, + ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range) +{ + FIXME("stub - %p, %u, %x, %p, %u, %u, %u, %p, %u, %p\n", file_buffer, file_size, flags, options, new_coff_base, + new_coff_time, ignore_range_count, ignore_range, retain_range_count, retain_range); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +}