From: Hans Leidekker Subject: msi: Support more transform validation flags. (resend) Message-Id: <1413883748.25187.5.camel@codeweavers.com> Date: Tue, 21 Oct 2014 11:29:08 +0200 --- dlls/msi/msipriv.h | 1 + dlls/msi/package.c | 2 +- dlls/msi/patch.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 191 insertions(+), 27 deletions(-) diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index d0b2247..bf788ba 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -940,6 +940,7 @@ extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) DECL extern INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN; extern LPWSTR msi_get_suminfo_product( IStorage *stg ) DECLSPEC_HIDDEN; extern UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) DECLSPEC_HIDDEN; +extern enum platform parse_platform( const WCHAR *str ) DECLSPEC_HIDDEN; /* undocumented functions */ UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD ); diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 96de82d..2805003 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -1271,7 +1271,7 @@ UINT msi_create_empty_local_file( LPWSTR path, LPCWSTR suffix ) return ERROR_SUCCESS; } -static enum platform parse_platform( WCHAR *str ) +enum platform parse_platform( const WCHAR *str ) { if (!str[0] || !strcmpW( str, szIntel )) return PLATFORM_INTEL; else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64; diff --git a/dlls/msi/patch.c b/dlls/msi/patch.c index a3a8d32..a738de1 100644 --- a/dlls/msi/patch.c +++ b/dlls/msi/patch.c @@ -44,57 +44,220 @@ static BOOL match_language( MSIPACKAGE *package, LANGID langid ) return FALSE; } +struct transform_desc +{ + WCHAR *product_code_from; + WCHAR *product_code_to; + WCHAR *version_from; + WCHAR *version_to; + WCHAR *upgrade_code; +}; + +static void free_transform_desc( struct transform_desc *desc ) +{ + msi_free( desc->product_code_from ); + msi_free( desc->product_code_to ); + msi_free( desc->version_from ); + msi_free( desc->version_to ); + msi_free( desc->upgrade_code ); + msi_free( desc ); +} + +static struct transform_desc *parse_transform_desc( const WCHAR *str ) +{ + struct transform_desc *ret; + const WCHAR *p = str, *q; + UINT len; + + if (!(ret = msi_alloc_zero( sizeof(*ret) ))) return NULL; + + q = strchrW( p, '}' ); + if (*p != '{' || !q) goto error; + + len = q - p + 1; + if (!(ret->product_code_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->product_code_from, p, len * sizeof(WCHAR) ); + ret->product_code_from[len] = 0; + + p = q + 1; + if (!(q = strchrW( p, ';' ))) goto error; + len = q - p; + if (!(ret->version_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->version_from, p, len * sizeof(WCHAR) ); + ret->version_from[len] = 0; + + p = q + 1; + q = strchrW( p, '}' ); + if (*p != '{' || !q) goto error; + + len = q - p + 1; + if (!(ret->product_code_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->product_code_to, p, len * sizeof(WCHAR) ); + ret->product_code_to[len] = 0; + + p = q + 1; + if (!(q = strchrW( p, ';' ))) goto error; + len = q - p; + if (!(ret->version_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->version_to, p, len * sizeof(WCHAR) ); + ret->version_to[len] = 0; + + p = q + 1; + q = strchrW( p, '}' ); + if (*p != '{' || !q) goto error; + + len = q - p + 1; + if (!(ret->upgrade_code = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->upgrade_code, p, len * sizeof(WCHAR) ); + ret->upgrade_code[len] = 0; + + return ret; + +error: + free_transform_desc( ret ); + return NULL; +} + static UINT check_transform_applicable( MSIPACKAGE *package, IStorage *transform ) { + static const UINT supported_flags = + MSITRANSFORM_VALIDATE_PRODUCT | MSITRANSFORM_VALIDATE_LANGUAGE | + MSITRANSFORM_VALIDATE_PLATFORM | MSITRANSFORM_VALIDATE_MAJORVERSION | + MSITRANSFORM_VALIDATE_MINORVERSION | MSITRANSFORM_VALIDATE_UPGRADECODE; MSISUMMARYINFO *si = MSI_GetSummaryInformationW( transform, 0 ); UINT valid_flags = 0, wanted_flags = 0; + WCHAR *template, *product, *p; + struct transform_desc *desc; - if (si) wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT ); - TRACE("validation flags %x\n", wanted_flags); + if (!si) + { + WARN("no summary information!\n"); + return ERROR_FUNCTION_FAILED; + } + wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT ); + wanted_flags &= 0xffff; /* mask off error condition flags */ + TRACE("validation flags 0x%04x\n", wanted_flags); - if (wanted_flags & ~(MSITRANSFORM_VALIDATE_PRODUCT|MSITRANSFORM_VALIDATE_LANGUAGE)) - FIXME("unsupported validation flags %x\n", wanted_flags); + if (wanted_flags & ~supported_flags) + { + FIXME("unsupported validation flags 0x%04x\n", wanted_flags); + msiobj_release( &si->hdr ); + return ERROR_FUNCTION_FAILED; + } + if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE ))) + { + WARN("no template property!\n"); + msiobj_release( &si->hdr ); + return ERROR_FUNCTION_FAILED; + } + TRACE("template property: %s\n", debugstr_w(template)); + if (!(product = msi_get_suminfo_product( transform ))) + { + WARN("no product property!\n"); + msi_free( template ); + msiobj_release( &si->hdr ); + return ERROR_FUNCTION_FAILED; + } + TRACE("product property: %s\n", debugstr_w(product)); + if (!(desc = parse_transform_desc( product ))) + { + msi_free( template ); + msiobj_release( &si->hdr ); + return ERROR_FUNCTION_FAILED; + } + msi_free( product ); + if (wanted_flags & MSITRANSFORM_VALIDATE_LANGUAGE) + { + if (!template[0] || ((p = strchrW( template, ';' )) && match_language( package, atoiW( p + 1 ) ))) + { + valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE; + } + } if (wanted_flags & MSITRANSFORM_VALIDATE_PRODUCT) { - WCHAR *package_product = msi_dup_property( package->db, szProductCode ); - WCHAR *transform_product = msi_get_suminfo_product( transform ); + WCHAR *product_code_installed = msi_dup_property( package->db, szProductCode ); - TRACE("package = %s transform = %s\n", debugstr_w(package_product), debugstr_w(transform_product)); - - if (!transform_product || strstrW( transform_product, package_product )) + if (!product_code_installed) + { + msi_free( template ); + free_transform_desc( desc ); + msiobj_release( &si->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; + } + if (!strcmpW( desc->product_code_from, product_code_installed )) { valid_flags |= MSITRANSFORM_VALIDATE_PRODUCT; } - msi_free( transform_product ); - msi_free( package_product ); + msi_free( product_code_installed ); } - if (wanted_flags & MSITRANSFORM_VALIDATE_LANGUAGE) + if (wanted_flags & MSITRANSFORM_VALIDATE_PLATFORM) { - WCHAR *template; - const WCHAR *p; + if ((p = strchrW( template, ';' ))) + { + *p = 0; + if (package->platform == parse_platform( template )) + valid_flags |= MSITRANSFORM_VALIDATE_PLATFORM; + } + } + msi_free( template ); + if (wanted_flags & MSITRANSFORM_VALIDATE_MAJORVERSION) + { + WCHAR *product_version_installed = msi_dup_property( package->db, szProductVersion ); + DWORD major_installed, minor_installed, major, minor; - if (!si) + if (!product_version_installed) { - ERR("no summary information!\n"); - goto end; + free_transform_desc( desc ); + msiobj_release( &si->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; } - if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE ))) + msi_parse_version_string( product_version_installed, &major_installed, &minor_installed ); + msi_parse_version_string( desc->version_from, &major, &minor ); + + if (major_installed == major) { - ERR("no template property!\n"); - goto end; + valid_flags |= MSITRANSFORM_VALIDATE_MAJORVERSION; + wanted_flags &= ~MSITRANSFORM_VALIDATE_MINORVERSION; } - TRACE("template: %s\n", debugstr_w(template)); - if (!template[0] || ((p = strchrW( template, ';' )) && match_language( package, atoiW( p + 1 ) ))) + msi_free( product_version_installed ); + } + else if (wanted_flags & MSITRANSFORM_VALIDATE_MINORVERSION) + { + WCHAR *product_version_installed = msi_dup_property( package->db, szProductVersion ); + DWORD major_installed, minor_installed, major, minor; + + if (!product_version_installed) { - valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE; + free_transform_desc( desc ); + msiobj_release( &si->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; } - msi_free( template ); + msi_parse_version_string( product_version_installed, &major_installed, &minor_installed ); + msi_parse_version_string( desc->version_from, &major, &minor ); + + if (major_installed == major && minor_installed == minor) + valid_flags |= MSITRANSFORM_VALIDATE_MINORVERSION; + msi_free( product_version_installed ); + } + if (wanted_flags & MSITRANSFORM_VALIDATE_UPGRADECODE) + { + WCHAR *upgrade_code_installed = msi_dup_property( package->db, szUpgradeCode ); + + if (!upgrade_code_installed) + { + free_transform_desc( desc ); + msiobj_release( &si->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; + } + if (!strcmpW( desc->upgrade_code, upgrade_code_installed )) + valid_flags |= MSITRANSFORM_VALIDATE_UPGRADECODE; + msi_free( upgrade_code_installed ); } -end: + free_transform_desc( desc ); msiobj_release( &si->hdr ); - if (valid_flags & ~wanted_flags) return ERROR_FUNCTION_FAILED; + if ((valid_flags & wanted_flags) != wanted_flags) return ERROR_FUNCTION_FAILED; TRACE("applicable transform\n"); return ERROR_SUCCESS; }