msi: Check the destination file's hash and skip that file if the hash matches.
This commit is contained in:
parent
6a6a218548
commit
4160722b07
|
@ -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 );
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -424,6 +424,7 @@ typedef struct tagMSIFILE
|
|||
LPWSTR SourcePath;
|
||||
LPWSTR TargetPath;
|
||||
BOOL IsCompressed;
|
||||
MSIFILEHASHINFO hash;
|
||||
} MSIFILE;
|
||||
|
||||
typedef struct tagMSITEMPFILE
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue