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.
This commit is contained in:
Hans Leidekker 2011-03-08 10:08:16 +01:00 committed by Alexandre Julliard
parent afcfb51055
commit 4a6c63e24a
3 changed files with 85 additions and 54 deletions

View File

@ -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 */

View File

@ -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 );
}
}

View File

@ -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 );