[1/3] msi: Make a second pass to determine which files to install in the InstallFiles action.

Hans Leidekker hans at codeweavers.com
Tue Mar 8 03:08:16 CST 2011


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   |   81 ++++++++++++++++++++++++++++++++++++++++++++-------
 dlls/msi/msipriv.h |    4 ++-
 3 files changed, 84 insertions(+), 53 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 86aa33f..a003f5e 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 df765e5..e88a0c6 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))
+        file->state = calculate_install_state( file );
+        if (file->state == msifs_overwrite && (comp->Attributes & msidbComponentAttributesNeverOverwrite))
         {
-            TRACE("File %s is not scheduled for install\n", debugstr_w(file->File));
+            TRACE("not overwriting %s\n", debugstr_w(file->TargetPath));
             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))
-        {
-            TRACE("not overwriting %s\n", debugstr_w(file->TargetPath));
-            file->state = msifs_skipped;
-        }
     }
 }
 
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 7c25ec9..9ddcaeb 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 );
-- 
1.7.1







More information about the wine-patches mailing list