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