[PATCH 3/3] msi: Add an offset to sequence numbers belonging to files added by a patch.
David Hedberg
dhedberg at codeweavers.com
Wed Mar 9 19:20:58 CST 2011
---
dlls/msi/action.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++
dlls/msi/tests/patch.c | 77 +++++++++++++++++++++++
2 files changed, 234 insertions(+), 0 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index a003f5e..9a27415 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -625,6 +625,162 @@ UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
return r;
}
+static UINT msi_get_column_min_max(MSIDATABASE *db, LPCWSTR table, LPCWSTR column, INT *min, INT *max)
+{
+ static const WCHAR fmt[] = {
+ 'S','E','L','E','C','T',' ','`','%','s','`',' ',
+ 'F','R','O','M',' ','`','%','s','`',' ','O','R','D','E','R',' ','B','Y',' ',
+ '`','%','s','`',0};
+ WCHAR query[MAX_PATH];
+ MSIQUERY *view;
+ MSIRECORD *rec;
+ BOOL min_is_fetched = FALSE;
+ UINT r;
+
+ sprintfW( query, fmt, column, table, column );
+
+ r = MSI_DatabaseOpenViewW( db, query, &view );
+ if (r != ERROR_SUCCESS)
+ {
+ ERR("MSI_DatabaseOpenViewW failed: %d\n", r);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ r = MSI_ViewExecute( view, 0 );
+ if (r != ERROR_SUCCESS )
+ {
+ ERR("MSI_ViewExecute failed: %d\n", r);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ *max = 0;
+ while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
+ {
+ *max = MSI_RecordGetInteger( rec, 1 );
+ if (!min_is_fetched)
+ {
+ *min = *max;
+ min_is_fetched = TRUE;
+ }
+ msiobj_release( &rec->hdr );
+ }
+
+ MSI_ViewClose( view );
+ msiobj_release( &view->hdr );
+
+ if (!min_is_fetched)
+ return ERROR_FUNCTION_FAILED;
+
+ return ERROR_SUCCESS;
+}
+
+static UINT msi_add_offsets(MSIDATABASE *db, UINT *last_sequence, UINT offset, UINT patch_min)
+{
+ static const WCHAR query_file[] = {
+ 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
+ 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<',' ','?',' ',
+ 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e', 0};
+ MSIQUERY *view;
+ MSIRECORD *rec, *cond;
+ UINT r;
+ INT min = -1;
+
+ if(!*last_sequence)
+ *last_sequence = 32767;
+
+ r = MSI_DatabaseOpenViewW( db, query_file, &view );
+ if (r != ERROR_SUCCESS)
+ ERR("MSI_DatabaseOpenViewW failed: %d\n", r);
+
+ cond = MSI_CreateRecord( 1 );
+ MSI_RecordSetInteger( cond, 1, *last_sequence );
+
+ r = MSI_ViewExecute( view, cond );
+ if (r != ERROR_SUCCESS)
+ ERR("MSI_ViewExecute failed: %d\n", r);
+
+ msiobj_release( &cond->hdr );
+
+ while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
+ {
+ UINT attributes = MSI_RecordGetInteger( rec, 7 );
+
+ if (attributes & msidbFileAttributesPatchAdded)
+ {
+ UINT sequence = MSI_RecordGetInteger( rec, 8 );
+
+ if(min == -1)
+ min = min( sequence, patch_min );
+
+ MSI_RecordSetInteger( rec, 8, sequence + offset - min);
+ MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
+
+ *last_sequence = sequence;
+ }
+ msiobj_release( &rec->hdr );
+ }
+
+ MSI_ViewClose( view );
+ msiobj_release( &view->hdr );
+
+ /* FIXME:
+ * The Patch table sequence numbers should be offset in the same manner.
+ */
+
+ *last_sequence = *last_sequence - min;
+ return ERROR_SUCCESS;
+}
+
+static UINT msi_set_patch_offsets(MSIPACKAGE *package)
+{
+ static const WCHAR query_media[] = {
+ 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','M','e','d','i','a',' ',
+ 'W','H','E','R','E',' ','S','o','u','r','c','e',' ','I','S',' ','N','O','T',' ','N','U','L','L',0};
+ static const WCHAR szFile[] = {'F','i','l','e',0};
+ static const WCHAR szPatch[] = {'P','a','t','c','h',0};
+ static const WCHAR szSequence[] = {'S','e','q','u','e','n','c','e',0};
+ MSIQUERY *view = NULL;
+ MSIRECORD *rec = NULL;
+ UINT r, offset = 10000;
+ INT min_file_sq = 0, max_file_sq = 0;
+ INT min_patch_sq = 999999, max_patch_sq = 0;
+
+ r = msi_get_column_min_max( package->db, szFile, szSequence, &min_file_sq, &max_file_sq );
+ if (r == ERROR_SUCCESS)
+ offset = max(max_file_sq + 1, offset);
+
+ r = msi_get_column_min_max( package->db, szPatch, szSequence, &min_patch_sq, &max_patch_sq );
+ if (r == ERROR_SUCCESS)
+ offset = max(max_patch_sq + 1, offset);
+
+ r = MSI_DatabaseOpenViewW( package->db, query_media, &view );
+ if (r != ERROR_SUCCESS)
+ return r;
+
+ r = MSI_ViewExecute( view, 0 );
+ if (r != ERROR_SUCCESS)
+ goto done;
+
+ while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
+ {
+ UINT last_sequence = MSI_RecordGetInteger( rec, 2 );
+
+ msi_add_offsets( package->db, &last_sequence, offset, min_patch_sq );
+ MSI_RecordSetInteger( rec, 2, last_sequence + offset );
+ r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
+ msiobj_release( &rec->hdr );
+
+ if (r != ERROR_SUCCESS)
+ ERR("Failed to update Media table offsets.\n");
+ }
+
+done:
+ MSI_ViewClose( view );
+ msiobj_release( &view->hdr );
+
+ return r;
+}
+
UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
{
UINT i, r = ERROR_SUCCESS;
@@ -640,6 +796,7 @@ UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINF
return r;
msi_set_media_source_prop( package );
+ msi_set_patch_offsets( package );
/*
* There might be a CAB file in the patch package,
diff --git a/dlls/msi/tests/patch.c b/dlls/msi/tests/patch.c
index 4cad4eb..f33c926 100644
--- a/dlls/msi/tests/patch.c
+++ b/dlls/msi/tests/patch.c
@@ -957,11 +957,76 @@ static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
return r;
}
+static INT get_integer( MSIHANDLE hdb, UINT field, const char *query)
+{
+ UINT r;
+ INT ret = -1;
+ MSIHANDLE hview, hrec;
+
+ r = MsiDatabaseOpenView( hdb, query, &hview );
+ ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
+
+ r = MsiViewExecute( hview, 0 );
+ ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
+
+ r = MsiViewFetch( hview, &hrec );
+ ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
+ if (r == ERROR_SUCCESS)
+ {
+ UINT r_tmp;
+ ret = MsiRecordGetInteger( hrec, field );
+
+ r_tmp = MsiViewFetch( hview, &hrec );
+ ok( r_tmp == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
+ }
+
+ MsiViewClose( hview );
+ MsiCloseHandle( hview );
+ MsiCloseHandle( hrec );
+
+ return ret;
+}
+
+static char *get_string( MSIHANDLE hdb, UINT field, const char *query)
+{
+ UINT r;
+ static char ret[MAX_PATH];
+ MSIHANDLE hview, hrec;
+
+ ret[0] = '\0';
+
+ r = MsiDatabaseOpenView( hdb, query, &hview );
+ ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
+
+ r = MsiViewExecute( hview, 0 );
+ ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
+
+ r = MsiViewFetch( hview, &hrec );
+ ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
+ if (r == ERROR_SUCCESS)
+ {
+ UINT size = MAX_PATH;
+ r = MsiRecordGetStringA( hrec, field, ret, &size );
+ ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
+
+ r = MsiViewFetch( hview, &hrec );
+ ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
+ }
+
+ MsiViewClose( hview );
+ MsiCloseHandle( hview );
+ MsiCloseHandle( hrec );
+
+ return ret;
+}
+
static void test_system_tables( void )
{
UINT r;
+ char *cr;
const char *query;
MSIHANDLE hproduct, hdb, hview, hrec;
+ static const char patchsource[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
if (!pMsiApplyPatchA)
{
@@ -1106,6 +1171,18 @@ static void test_system_tables( void )
r = find_entry( hdb, "_Tables", "PatchPackage" );
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
+ cr = get_string( hdb, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
+ todo_wine ok( !strcmp(cr, patchsource), "Expected %s, got %s\n", patchsource, cr );
+
+ r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
+ todo_wine ok( r == 100, "Got %u\n", r );
+
+ r = get_integer( hdb, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
+ ok( r == 10000, "Got %u\n", r );
+
+ r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
+ ok( r == 10000, "Got %u\n", r );
+
MsiCloseHandle( hrec );
MsiViewClose( hview );
MsiCloseHandle( hview );
--
1.7.4.1
More information about the wine-patches
mailing list