[1/4] msi: Compare file versions as numbers instead of strings.

Hans Leidekker hans at codeweavers.com
Fri Jun 11 08:19:15 CDT 2010


Fix for http://bugs.winehq.org/show_bug.cgi?id=19319
---
 dlls/msi/action.c    |   55 +++++++++++++++++++++++++++----------------------
 dlls/msi/appsearch.c |    6 ++--
 dlls/msi/files.c     |   35 ++++++++++--------------------
 dlls/msi/msipriv.h   |    5 ++++
 4 files changed, 50 insertions(+), 51 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 48948fb..7ae8286 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -1964,16 +1964,12 @@ static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
     return ERROR_SUCCESS;
 }
 
-static LPWSTR get_disk_file_version( LPCWSTR filename )
+VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
 {
-    static const WCHAR name_fmt[] =
-        {'%','u','.','%','u','.','%','u','.','%','u',0};
     static const WCHAR name[] = {'\\',0};
-    VS_FIXEDFILEINFO *lpVer;
-    WCHAR filever[0x100];
+    VS_FIXEDFILEINFO *ret;
     LPVOID version;
-    DWORD versize;
-    DWORD handle;
+    DWORD versize, handle;
     UINT sz;
 
     TRACE("%s\n", debugstr_w(filename));
@@ -1983,23 +1979,32 @@ static LPWSTR get_disk_file_version( LPCWSTR filename )
         return NULL;
 
     version = msi_alloc( versize );
+    if (!version)
+        return NULL;
+
     GetFileVersionInfoW( filename, 0, versize, version );
 
-    if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
+    if (!VerQueryValueW( version, name, (LPVOID *)&ret, &sz ))
     {
         msi_free( version );
         return NULL;
     }
 
-    sprintfW( filever, name_fmt,
-        HIWORD(lpVer->dwFileVersionMS),
-        LOWORD(lpVer->dwFileVersionMS),
-        HIWORD(lpVer->dwFileVersionLS),
-        LOWORD(lpVer->dwFileVersionLS));
-
     msi_free( version );
+    return ret;
+}
 
-    return strdupW( filever );
+int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
+{
+    DWORD ms, ls;
+
+    msi_parse_version_string( version, &ms, &ls );
+
+    if (fi->dwFileVersionMS > ms) return 1;
+    else if (fi->dwFileVersionMS < ms) return -1;
+    else if (fi->dwFileVersionLS > ls) return 1;
+    else if (fi->dwFileVersionLS < ls) return -1;
+    return 0;
 }
 
 static DWORD get_disk_file_size( LPCWSTR filename )
@@ -2033,7 +2038,7 @@ static BOOL hash_matches( MSIFILE *file )
 
 static UINT set_file_install_states( MSIPACKAGE *package )
 {
-    LPWSTR file_version;
+    VS_FIXEDFILEINFO *file_version;
     MSIFILE *file;
 
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
@@ -2050,18 +2055,14 @@ static UINT set_file_install_states( MSIPACKAGE *package )
 
         /* calculate target */
         p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
-
         msi_free(file->TargetPath);
 
-        TRACE("file %s is named %s\n",
-               debugstr_w(file->File), debugstr_w(file->FileName));
+        TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
 
         file->TargetPath = build_directory_name(2, p, file->FileName);
-
         msi_free(p);
 
-        TRACE("file %s resolves to %s\n",
-               debugstr_w(file->File), debugstr_w(file->TargetPath));
+        TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
 
         if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
         {
@@ -2069,11 +2070,15 @@ static UINT set_file_install_states( MSIPACKAGE *package )
             comp->Cost += file->FileSize;
             continue;
         }
-        if (file->Version && (file_version = get_disk_file_version( file->TargetPath )))
+        if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
         {
-            TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(file_version));
+            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 (strcmpiW(file_version, file->Version) < 0)
+            if (msi_compare_file_versions( file_version, file->Version ) < 0)
             {
                 file->state = msifs_overwrite;
                 comp->Cost += file->FileSize;
diff --git a/dlls/msi/appsearch.c b/dlls/msi/appsearch.c
index 336bfca..34130b6 100644
--- a/dlls/msi/appsearch.c
+++ b/dlls/msi/appsearch.c
@@ -50,7 +50,7 @@ typedef struct tagMSISIGNATURE
     LPWSTR   Languages;
 }MSISIGNATURE;
 
-static void ACTION_VerStrToInteger(LPCWSTR verStr, PDWORD ms, PDWORD ls)
+void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls)
 {
     const WCHAR *ptr;
     int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
@@ -109,13 +109,13 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
     minVersion = msi_dup_record_field(row,3);
     if (minVersion)
     {
-        ACTION_VerStrToInteger(minVersion, &sig->MinVersionMS, &sig->MinVersionLS);
+        msi_parse_version_string( minVersion, &sig->MinVersionMS, &sig->MinVersionLS );
         msi_free( minVersion );
     }
     maxVersion = msi_dup_record_field(row,4);
     if (maxVersion)
     {
-        ACTION_VerStrToInteger(maxVersion, &sig->MaxVersionMS, &sig->MaxVersionLS);
+        msi_parse_version_string( maxVersion, &sig->MaxVersionMS, &sig->MaxVersionLS );
         msi_free( maxVersion );
     }
     sig->MinSize = MSI_RecordGetInteger(row,5);
diff --git a/dlls/msi/files.c b/dlls/msi/files.c
index f21cd28..79d7814 100644
--- a/dlls/msi/files.c
+++ b/dlls/msi/files.c
@@ -60,24 +60,6 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac
     ui_progress( package, 2, f->FileSize, 0, 0 );
 }
 
-/* compares the version of a file read from the filesystem and
- * the version specified in the File table
- */
-static int msi_compare_file_version(MSIFILE *file)
-{
-    WCHAR version[MAX_PATH];
-    DWORD size;
-    UINT r;
-
-    size = MAX_PATH;
-    version[0] = '\0';
-    r = MsiGetFileVersionW(file->TargetPath, version, &size, NULL, NULL);
-    if (r != ERROR_SUCCESS)
-        return 0;
-
-    return lstrcmpW(version, file->Version);
-}
-
 static void schedule_install_files(MSIPACKAGE *package)
 {
     MSIFILE *file;
@@ -981,6 +963,7 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
     {
         MSIRECORD *uirow;
         LPWSTR dir, p;
+        VS_FIXEDFILEINFO *ver;
 
         if ( file->state == msifs_installed )
             ERR("removing installed file %s\n", debugstr_w(file->TargetPath));
@@ -989,11 +972,17 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
              file->Component->Installed == INSTALLSTATE_SOURCE )
             continue;
 
-        /* don't remove a file if the old file
-         * is strictly newer than the version to be installed
-         */
-        if ( msi_compare_file_version( file ) < 0 )
-            continue;
+        if (file->Version)
+        {
+            ver = msi_get_disk_file_version( file->TargetPath );
+            if (ver && msi_compare_file_versions( ver, file->Version ) > 0)
+            {
+                TRACE("newer version detected, not removing file\n");
+                msi_free( ver );
+                continue;
+            }
+            msi_free( ver );
+        }
 
         TRACE("removing %s\n", debugstr_w(file->File) );
         if (!DeleteFileW( file->TargetPath ))
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 819d8bc..9f029f3 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -32,6 +32,7 @@
 #include "objbase.h"
 #include "objidl.h"
 #include "winnls.h"
+#include "winver.h"
 #include "wine/list.h"
 #include "wine/debug.h"
 
@@ -811,6 +812,10 @@ extern LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name );
 extern BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val);
 
 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 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.0.4







More information about the wine-patches mailing list