From: Piotr Caban Subject: [PATCH 2/2] msi: Add support for re-caching package Message-Id: <4026e812-e816-35aa-59f9-7406f8fec1b3@codeweavers.com> Date: Thu, 21 Jun 2018 21:48:56 +0200 Signed-off-by: Piotr Caban --- dlls/msi/action.c | 42 ++++++++++++++++++++++++++++++++++++++---- dlls/msi/msi.c | 27 +++++++++++++++++++++------ dlls/msi/msipriv.h | 4 +++- dlls/msi/package.c | 14 ++++++++++++-- dlls/msi/tests/package.c | 6 +++--- 5 files changed, 77 insertions(+), 16 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 9d216aba90..15f187687b 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -294,15 +294,18 @@ static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes ) default: break; } - if (!ignore) *out++ = *p; + if (!ignore && value) *out++ = *p; if (!count) in_quotes = FALSE; } done: - if (!len) *value = 0; - else *out = 0; + if (value) + { + if (!len) *value = 0; + else *out = 0; + } - *quotes = count; + if(quotes) *quotes = count; return p - str; } @@ -378,6 +381,37 @@ UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine, return ERROR_SUCCESS; } +const WCHAR *msi_get_command_line_option(const WCHAR *cmd, const WCHAR *option, UINT *len) +{ + DWORD opt_len = strlenW(option); + + if (!cmd) + return NULL; + + while (*cmd) + { + BOOL found = FALSE; + + while (*cmd == ' ') cmd++; + if (!*cmd) break; + + if(!strncmpiW(cmd, option, opt_len)) + found = TRUE; + + cmd = strchrW( cmd, '=' ); + if(!cmd) break; + cmd++; + while (*cmd == ' ') cmd++; + if (!*cmd) break; + + *len = parse_prop( cmd, NULL, NULL); + if (found) return cmd; + cmd += *len; + } + + return NULL; +} + WCHAR **msi_split_string( const WCHAR *str, WCHAR sep ) { LPCWSTR pc; diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c index 2ae4db27ac..7d805afeda 100644 --- a/dlls/msi/msi.c +++ b/dlls/msi/msi.c @@ -137,7 +137,7 @@ static UINT MSI_OpenProductW(LPCWSTR szProduct, MSIPACKAGE **package) goto done; } - r = MSI_OpenPackageW(path, package); + r = MSI_OpenPackageW(path, 0, package); done: RegCloseKey(props); @@ -236,7 +236,9 @@ end: UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) { MSIPACKAGE *package = NULL; - UINT r; + const WCHAR *reinstallmode; + DWORD options = 0; + UINT r, len; TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine)); @@ -246,7 +248,20 @@ UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) if (!*szPackagePath) return ERROR_PATH_NOT_FOUND; - r = MSI_OpenPackageW( szPackagePath, &package ); + reinstallmode = msi_get_command_line_option(szCommandLine, szReinstallMode, &len); + if (reinstallmode) + { + while (len > 0) + { + if (reinstallmode[--len] == 'v' || reinstallmode[len] == 'V') + { + options |= WINE_OPENPACKAGEFLAGS_RECACHE; + break; + } + } + } + + r = MSI_OpenPackageW( szPackagePath, options, &package ); if (r == ERROR_SUCCESS) { r = MSI_InstallPackage( package, szPackagePath, szCommandLine ); @@ -732,7 +747,7 @@ UINT WINAPI MsiDetermineApplicablePatchesW(LPCWSTR szProductPackagePath, TRACE("%s, %u, %p\n", debugstr_w(szProductPackagePath), cPatchInfo, pPatchInfo); - r = MSI_OpenPackageW( szProductPackagePath, &package ); + r = MSI_OpenPackageW( szProductPackagePath, 0, &package ); if (r != ERROR_SUCCESS) { ERR("failed to open package %u\n", r); @@ -810,7 +825,7 @@ static UINT open_package( const WCHAR *product, const WCHAR *usersid, if (GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES) return ERROR_INSTALL_SOURCE_ABSENT; - return MSI_OpenPackageW( sourcepath, package ); + return MSI_OpenPackageW( sourcepath, 0, package ); } UINT WINAPI MsiDeterminePatchSequenceW( LPCWSTR product, LPCWSTR usersid, @@ -4027,7 +4042,7 @@ UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, DWORD dw strcatW( sourcepath, filename ); if (dwReinstallMode & REINSTALLMODE_PACKAGE) - r = MSI_OpenPackageW( sourcepath, &package ); + r = MSI_OpenPackageW( sourcepath, 0, &package ); else r = MSI_OpenProductW( szProduct, &package ); diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 8043d0ab9d..789d54128b 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -799,6 +799,7 @@ extern UINT ACTION_ForceReboot(MSIPACKAGE *package) DECLSPEC_HIDDEN; extern UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable ) DECLSPEC_HIDDEN; extern UINT MSI_SetFeatureStates( MSIPACKAGE *package ) DECLSPEC_HIDDEN; extern UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine, BOOL preserve_case ) DECLSPEC_HIDDEN; +extern const WCHAR *msi_get_command_line_option( const WCHAR *cmd, const WCHAR *option, UINT *len ) DECLSPEC_HIDDEN; extern UINT msi_schedule_action( MSIPACKAGE *package, UINT script, const WCHAR *action ) DECLSPEC_HIDDEN; extern INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp ) DECLSPEC_HIDDEN; extern INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature ) DECLSPEC_HIDDEN; @@ -863,8 +864,9 @@ extern UINT msi_view_get_row(MSIDATABASE *, MSIVIEW *, UINT, MSIRECORD **) DECLS extern UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel ) DECLSPEC_HIDDEN; /* package internals */ +#define WINE_OPENPACKAGEFLAGS_RECACHE 0x80000000 extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * ) DECLSPEC_HIDDEN; -extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE **pPackage ) DECLSPEC_HIDDEN; +extern UINT MSI_OpenPackageW( LPCWSTR szPackage, DWORD dwOptions, MSIPACKAGE **pPackage ) DECLSPEC_HIDDEN; extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR ) DECLSPEC_HIDDEN; extern INT MSI_ProcessMessageVerbatim( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * ) DECLSPEC_HIDDEN; extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * ) DECLSPEC_HIDDEN; diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 46fbebaf42..d6f22d0ab4 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -1433,7 +1433,7 @@ UINT msi_set_original_database_property( MSIDATABASE *db, const WCHAR *package ) return r; } -UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) +UINT MSI_OpenPackageW(LPCWSTR szPackage, DWORD dwOptions, MSIPACKAGE **pPackage) { static const WCHAR dotmsi[] = {'.','m','s','i',0}; MSIDATABASE *db; @@ -1509,6 +1509,16 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) } delete_on_close = TRUE; } + else if (dwOptions & WINE_OPENPACKAGEFLAGS_RECACHE) + { + if (!CopyFileW( file, localfile, FALSE )) + { + r = GetLastError(); + WARN("unable to update cached package (%u)\n", r); + msiobj_release( &db->hdr ); + return r; + } + } else product_version = get_product_version( db ); msiobj_release( &db->hdr ); @@ -1662,7 +1672,7 @@ UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phP if( dwOptions ) FIXME("dwOptions %08x not supported\n", dwOptions); - ret = MSI_OpenPackageW( szPackage, &package ); + ret = MSI_OpenPackageW( szPackage, 0, &package ); if( ret == ERROR_SUCCESS ) { *phPackage = alloc_msihandle( &package->hdr ); diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c index b1c7a76783..ace9b354f9 100644 --- a/dlls/msi/tests/package.c +++ b/dlls/msi/tests/package.c @@ -3840,15 +3840,15 @@ static void test_states(void) r = MsiInstallProductA(msifile2, ""); ok(r == ERROR_PRODUCT_VERSION, "Expected ERROR_PRODUCT_VERSION, got %d\n", r); - r = MsiInstallProductA(msifile2, "REINSTALLMODE=v"); - todo_wine ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiInstallProductA(msifile2, "REINSTALLMODe=V"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); r = MsiOpenProductA("{7262AC98-EEBD-4364-8CE3-D654F6A425B9}", &hprod); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); size = MAX_PATH; r = MsiGetProductPropertyA(hprod, "ProductVersion", value, &size); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - todo_wine ok(!strcmp(value, "1.1.2"), "ProductVersion = %s\n", value); + ok(!strcmp(value, "1.1.2"), "ProductVersion = %s\n", value); MsiCloseHandle(hprod); /* major upgrade test */