James Hawkins : msi: Check the destination file' s hash and skip that file if the hash matches.

Alexandre Julliard julliard at winehq.org
Mon Nov 26 08:16:17 CST 2007


Module: wine
Branch: master
Commit: 4160722b07c4cdd98a46cbe93b7c059c395b8864
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=4160722b07c4cdd98a46cbe93b7c059c395b8864

Author: James Hawkins <truiken at gmail.com>
Date:   Sun Nov 25 18:01:19 2007 -0600

msi: Check the destination file's hash and skip that file if the hash matches.

---

 dlls/msi/action.c        |   37 +++++++++++++++++++++++++++++++++++++
 dlls/msi/files.c         |   22 ++++++++++++++++++++++
 dlls/msi/msipriv.h       |    1 +
 dlls/msi/tests/install.c |    5 +----
 4 files changed, 61 insertions(+), 4 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 3066308..89f7bd7 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -1394,6 +1394,41 @@ static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
     return p+1;
 }
 
+static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+        '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
+        'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
+    MSIQUERY *view = NULL;
+    MSIRECORD *row;
+    UINT r;
+
+    TRACE("%s\n", debugstr_w(file->File));
+
+    r = MSI_OpenQuery(package->db, &view, query, file->File);
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    r = MSI_ViewExecute(view, NULL);
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    r = MSI_ViewFetch(view, &row);
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
+    file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
+    file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
+    file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
+    file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
+
+done:
+    if (view) msiobj_release(&view->hdr);
+    return r;
+}
+
 static UINT load_file(MSIRECORD *row, LPVOID param)
 {
     MSIPACKAGE* package = (MSIPACKAGE*)param;
@@ -1444,6 +1479,8 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
         file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
     }
 
+    load_file_hash(package, file);
+
     TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
 
     list_add_tail( &package->files, &file->entry );
diff --git a/dlls/msi/files.c b/dlls/msi/files.c
index c50e420..6662e4a 100644
--- a/dlls/msi/files.c
+++ b/dlls/msi/files.c
@@ -733,6 +733,22 @@ static UINT copy_install_file(MSIFILE *file)
     return gle;
 }
 
+static BOOL check_dest_hash_matches(MSIFILE *file)
+{
+    MSIFILEHASHINFO hash;
+    UINT r;
+
+    if (!file->hash.dwFileHashInfoSize)
+        return FALSE;
+
+    hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
+    r = MsiGetFileHashW(file->TargetPath, 0, &hash);
+    if (r != ERROR_SUCCESS)
+        return FALSE;
+
+    return !memcmp(&hash, &file->hash, sizeof(MSIFILEHASHINFO));
+}
+
 /*
  * ACTION_InstallFiles()
  * 
@@ -776,6 +792,12 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
         if (file->state != msifs_missing && !mi->is_continuous && file->state != msifs_overwrite)
             continue;
 
+        if (check_dest_hash_matches(file))
+        {
+            TRACE("File hashes match, not overwriting\n");
+            continue;
+        }
+
         if (file->Sequence > mi->last_sequence || mi->is_continuous ||
             (file->IsCompressed && !mi->is_extracted))
         {
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 4c7565b..d541260 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -424,6 +424,7 @@ typedef struct tagMSIFILE
     LPWSTR  SourcePath;
     LPWSTR  TargetPath;
     BOOL IsCompressed;
+    MSIFILEHASHINFO hash;
 } MSIFILE;
 
 typedef struct tagMSITEMPFILE
diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c
index 34fc126..fd8184b 100644
--- a/dlls/msi/tests/install.c
+++ b/dlls/msi/tests/install.c
@@ -3540,10 +3540,7 @@ static void test_missingcab(void)
     create_pf_data("msitest\\caesar", "abcdefgh", TRUE);
 
     r = MsiInstallProductA(msifile, NULL);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
-    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
     ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n");
     ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n");
     ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n");




More information about the wine-cvs mailing list