From 4a6c63e24a5a9ab22dc4e2145db16d86fe8f1895 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 8 Mar 2011 10:08:16 +0100 Subject: [PATCH] msi: Make a second pass to determine which files to install in the InstallFiles action. This is needed because the target path can still change after CostFinalize is executed. This happens in the .NET 1.1 Service Pack 1 installer where a custom action calls SetTargetPath. --- dlls/msi/action.c | 52 ++++++----------------------- dlls/msi/files.c | 83 +++++++++++++++++++++++++++++++++++++++------- dlls/msi/msipriv.h | 4 ++- 3 files changed, 85 insertions(+), 54 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 86aa33fc1c5..a003f5e1769 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -2178,7 +2178,7 @@ int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version ) return 0; } -static int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 ) +int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 ) { DWORD ms1, ms2; @@ -2190,7 +2190,7 @@ static int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 ) return 0; } -static DWORD get_disk_file_size( LPCWSTR filename ) +DWORD msi_get_disk_file_size( LPCWSTR filename ) { HANDLE file; DWORD size; @@ -2206,7 +2206,7 @@ static DWORD get_disk_file_size( LPCWSTR filename ) return size; } -static BOOL hash_matches( MSIFILE *file ) +BOOL msi_file_hash_matches( MSIFILE *file ) { UINT r; MSIFILEHASHINFO hash; @@ -2256,7 +2256,7 @@ static void set_target_path( MSIPACKAGE *package, MSIFILE *file ) TRACE("resolves to %s\n", debugstr_w(file->TargetPath)); } -static UINT set_file_install_states( MSIPACKAGE *package ) +static UINT calculate_file_cost( MSIPACKAGE *package ) { VS_FIXEDFILEINFO *file_version; WCHAR *font_version; @@ -2277,67 +2277,37 @@ static UINT set_file_install_states( MSIPACKAGE *package ) if ((comp->assembly && !comp->assembly->installed) || GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES) { - file->state = msifs_missing; comp->Cost += file->FileSize; continue; } + file_size = msi_get_disk_file_size( file->TargetPath ); + if (file->Version) { if ((file_version = msi_get_disk_file_version( file->TargetPath ))) { - TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version), - HIWORD(file_version->dwFileVersionMS), - LOWORD(file_version->dwFileVersionMS), - HIWORD(file_version->dwFileVersionLS), - LOWORD(file_version->dwFileVersionLS)); - if (msi_compare_file_versions( file_version, file->Version ) < 0) { - file->state = msifs_overwrite; - comp->Cost += file->FileSize; - } - else - { - TRACE("Destination file version equal or greater, not overwriting\n"); - file->state = msifs_present; + comp->Cost += file->FileSize - file_size; } msi_free( file_version ); continue; } else if ((font_version = font_version_from_file( file->TargetPath ))) { - TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version)); - if (msi_compare_font_versions( font_version, file->Version ) < 0) { - file->state = msifs_overwrite; - comp->Cost += file->FileSize; - } - else - { - TRACE("Destination file version equal or greater, not overwriting\n"); - file->state = msifs_present; + comp->Cost += file->FileSize - file_size; } msi_free( font_version ); continue; } } - if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize) + if (file_size != file->FileSize) { - file->state = msifs_overwrite; comp->Cost += file->FileSize - file_size; - continue; } - if (file->hash.dwFileHashInfoSize && hash_matches( file )) - { - TRACE("File hashes match, not overwriting\n"); - file->state = msifs_present; - continue; - } - file->state = msifs_overwrite; - comp->Cost += file->FileSize - file_size; } - return ERROR_SUCCESS; } @@ -2404,8 +2374,8 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) } } - TRACE("Calculating file install states\n"); - set_file_install_states( package ); + TRACE("Calculating file cost\n"); + calculate_file_cost( package ); msi_set_property( package->db, szCosting, szOne ); /* set default run level if not set */ diff --git a/dlls/msi/files.c b/dlls/msi/files.c index df765e5ed18..e88a0c6fd46 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -60,6 +60,73 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac ui_progress( package, 2, f->FileSize, 0, 0 ); } +static msi_file_state calculate_install_state( MSIFILE *file ) +{ + MSICOMPONENT *comp = file->Component; + VS_FIXEDFILEINFO *file_version; + WCHAR *font_version; + msi_file_state state; + DWORD file_size; + + if (comp->ActionRequest != INSTALLSTATE_LOCAL || !comp->Enabled || + (comp->assembly && comp->assembly->installed)) + { + TRACE("file %s is not scheduled for install\n", debugstr_w(file->File)); + return msifs_skipped; + } + if ((comp->assembly && !comp->assembly->installed) || + GetFileAttributesW( file->TargetPath ) == INVALID_FILE_ATTRIBUTES) + { + TRACE("file %s is missing\n", debugstr_w(file->File)); + return msifs_missing; + } + if (file->Version) + { + if ((file_version = msi_get_disk_file_version( file->TargetPath ))) + { + TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version), + HIWORD(file_version->dwFileVersionMS), + LOWORD(file_version->dwFileVersionMS), + HIWORD(file_version->dwFileVersionLS), + LOWORD(file_version->dwFileVersionLS)); + + if (msi_compare_file_versions( file_version, file->Version ) < 0) + state = msifs_overwrite; + else + { + TRACE("destination file version equal or greater, not overwriting\n"); + state = msifs_present; + } + msi_free( file_version ); + return state; + } + else if ((font_version = font_version_from_file( file->TargetPath ))) + { + TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version)); + + if (msi_compare_font_versions( font_version, file->Version ) < 0) + state = msifs_overwrite; + else + { + TRACE("destination file version equal or greater, not overwriting\n"); + state = msifs_present; + } + msi_free( font_version ); + return state; + } + } + if ((file_size = msi_get_disk_file_size( file->TargetPath )) != file->FileSize) + { + return msifs_overwrite; + } + if (file->hash.dwFileHashInfoSize && msi_file_hash_matches( file )) + { + TRACE("file hashes match, not overwriting\n"); + return msifs_present; + } + return msifs_overwrite; +} + static void schedule_install_files(MSIPACKAGE *package) { MSIFILE *file; @@ -68,22 +135,14 @@ static void schedule_install_files(MSIPACKAGE *package) { MSICOMPONENT *comp = file->Component; - if (comp->ActionRequest != INSTALLSTATE_LOCAL || !comp->Enabled || - (comp->assembly && comp->assembly->installed)) - { - TRACE("File %s is not scheduled for install\n", debugstr_w(file->File)); - file->state = msifs_skipped; - continue; - } - comp->Action = INSTALLSTATE_LOCAL; - ui_progress( package, 2, file->FileSize, 0, 0 ); - - if (file->state == msifs_overwrite && - (comp->Attributes & msidbComponentAttributesNeverOverwrite)) + file->state = calculate_install_state( file ); + if (file->state == msifs_overwrite && (comp->Attributes & msidbComponentAttributesNeverOverwrite)) { TRACE("not overwriting %s\n", debugstr_w(file->TargetPath)); file->state = msifs_skipped; } + comp->Action = INSTALLSTATE_LOCAL; + ui_progress( package, 2, file->FileSize, 0, 0 ); } } diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 7c25ec9926c..9ddcaeb7301 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -856,7 +856,9 @@ extern DWORD msi_version_str_to_dword(LPCWSTR p); extern void msi_parse_version_string(LPCWSTR, PDWORD, PDWORD); extern VS_FIXEDFILEINFO *msi_get_disk_file_version(LPCWSTR); extern int msi_compare_file_versions(VS_FIXEDFILEINFO *, const WCHAR *); - +extern int msi_compare_font_versions(const WCHAR *, const WCHAR *); +extern DWORD msi_get_disk_file_size(LPCWSTR); +extern BOOL msi_file_hash_matches(MSIFILE *); extern LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value ); extern LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value );