[PATCH 1/3] msi: Add an offset to sequence numbers belonging to files added by a patch. (try 2)
David Hedberg
dhedberg at codeweavers.com
Tue Mar 22 14:45:09 CDT 2011
try2: Replaced previous _init function with a _create function.
---
dlls/msi/action.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++
dlls/msi/database.c | 2 +
dlls/msi/msipriv.h | 3 +
dlls/msi/tests/patch.c | 77 +++++++++++++++
4 files changed, 333 insertions(+), 0 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index f806f18..145a1a6 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -625,6 +625,253 @@ UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
return r;
}
+struct msi_patch_offset
+{
+ struct list entry;
+ LPWSTR Name;
+ UINT Sequence;
+};
+
+struct msi_patch_offset_list
+{
+ struct list files;
+ UINT count, min, max;
+ UINT offset_to_apply;
+};
+
+static struct msi_patch_offset_list *msi_patch_offset_list_create(void)
+{
+ struct msi_patch_offset_list *pos = msi_alloc(sizeof(struct msi_patch_offset_list));
+ list_init( &pos->files );
+ pos->count = pos->max = 0;
+ pos->min = 999999;
+
+ return pos;
+}
+
+static void msi_patch_offset_list_free(struct msi_patch_offset_list *pos)
+{
+ struct msi_patch_offset *po, *po2;
+
+ LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->files, struct msi_patch_offset, entry )
+ {
+ msi_free( po->Name );
+ msi_free( po );
+ }
+
+ msi_free( pos );
+}
+
+static void msi_patch_offset_get_patches(MSIDATABASE *db, UINT last_sequence, struct msi_patch_offset_list *pos)
+{
+ MSIQUERY *view;
+ MSIRECORD *rec;
+ UINT r;
+ static const WCHAR query_patch[] = {
+ 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
+ '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};
+
+ r = MSI_DatabaseOpenViewW( db, query_patch, &view );
+ if (r != ERROR_SUCCESS)
+ return;
+
+ rec = MSI_CreateRecord( 1 );
+ MSI_RecordSetInteger(rec, 1, last_sequence);
+
+ r = MSI_ViewExecute( view, rec );
+ msiobj_release( &rec->hdr );
+ if (r != ERROR_SUCCESS)
+ return;
+
+ while (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
+ {
+ UINT sequence = MSI_RecordGetInteger( rec, 2 );
+
+ /* FIXME:
+ * We only use the max/min sequence numbers for now.
+ */
+
+ pos->min = min(pos->min, sequence);
+ pos->max = max(pos->max, sequence);
+ pos->count++;
+
+ msiobj_release( &rec->hdr );
+ }
+
+ msiobj_release( &view->hdr );
+}
+
+static void msi_patch_offset_get_files(MSIDATABASE *db, UINT last_sequence, struct msi_patch_offset_list *pos)
+{
+ MSIQUERY *view;
+ MSIRECORD *rec;
+ UINT r;
+ static const WCHAR query_files[] = {
+ '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};
+
+ r = MSI_DatabaseOpenViewW( db, query_files, &view );
+ if (r != ERROR_SUCCESS)
+ return;
+
+ rec = MSI_CreateRecord( 1 );
+ MSI_RecordSetInteger(rec, 1, last_sequence);
+
+ r = MSI_ViewExecute( view, rec );
+ msiobj_release( &rec->hdr );
+ if (r != ERROR_SUCCESS)
+ return;
+
+ while (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
+ {
+ UINT attributes = MSI_RecordGetInteger( rec, 7 );
+ if (attributes & msidbFileAttributesPatchAdded)
+ {
+ struct msi_patch_offset *po = msi_alloc(sizeof(struct msi_patch_offset));
+
+ po->Name = msi_dup_record_field( rec, 1 );
+ po->Sequence = MSI_RecordGetInteger( rec, 8 );
+
+ pos->min = min(pos->min, po->Sequence);
+ pos->max = max(pos->max, po->Sequence);
+
+ list_add_tail( &pos->files, &po->entry );
+ pos->count++;
+ }
+ msiobj_release( &rec->hdr );
+ }
+
+ msiobj_release( &view->hdr );
+}
+
+static UINT msi_patch_offset_modify_db(MSIDATABASE *db, struct msi_patch_offset_list *pos)
+{
+ static const WCHAR query_files[] =
+ {'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',' ','>','=',' ','?',' ',
+ 'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
+ 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
+ struct msi_patch_offset *po;
+ MSIQUERY *view;
+ MSIRECORD *rec;
+ UINT r;
+
+ r = MSI_DatabaseOpenViewW( db, query_files, &view );
+ if (r != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ rec = MSI_CreateRecord( 2 );
+ MSI_RecordSetInteger( rec, 1, pos->min );
+ MSI_RecordSetInteger( rec, 2, pos->max );
+
+ r = MSI_ViewExecute( view, rec );
+ msiobj_release( &rec->hdr );
+ if (r != ERROR_SUCCESS)
+ goto done;
+
+ LIST_FOR_EACH_ENTRY( po, &pos->files, struct msi_patch_offset, entry )
+ {
+ UINT r_fetch;
+ while ( (r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS )
+ {
+ LPCWSTR file = MSI_RecordGetString( rec, 1 );
+ UINT seq;
+
+ if (!strcmpiW(file, po->Name))
+ {
+ /* Update record */
+ seq = MSI_RecordGetInteger( rec, 8 );
+ MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
+ r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
+ if (r != ERROR_SUCCESS)
+ ERR("Failed to update offset for file %s.\n", debugstr_w(file));
+
+ msiobj_release( &rec->hdr );
+ break;
+ }
+
+ msiobj_release( &rec->hdr );
+ }
+
+ if (r_fetch != ERROR_SUCCESS)
+ break;
+ }
+
+done:
+ msiobj_release( &view->hdr );
+
+ return ERROR_SUCCESS;
+}
+
+static UINT msi_set_patch_offsets(MSIDATABASE *db)
+{
+ 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',
+ ' ','A','N','D',' ','C','a','b','i','n','e','t',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
+ 'O','R','D','E','R',' ','B','Y',' ','D','i','s','k','I','d',0};
+ MSIQUERY *view = NULL;
+ MSIRECORD *rec = NULL;
+ UINT r;
+
+ r = MSI_DatabaseOpenViewW( 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 );
+ struct msi_patch_offset_list *pos;
+
+ /* FIXME: Set/Check Source field instead? */
+ if (last_sequence >= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET)
+ {
+ msiobj_release( &rec->hdr );
+ continue;
+ }
+
+ pos = msi_patch_offset_list_create();
+
+ msi_patch_offset_get_files( db, last_sequence, pos );
+ msi_patch_offset_get_patches( db, last_sequence, pos );
+
+ if (pos->count)
+ {
+ UINT offset = db->media_transform_offset - pos->min;
+ last_sequence = offset + pos->max;
+
+ /* FIXME:
+ * This is for the patch table, which is not yet properly transformed.
+ */
+ last_sequence += pos->min;
+
+ pos->offset_to_apply = offset;
+ msi_patch_offset_modify_db( db, pos );
+
+ MSI_RecordSetInteger( rec, 2, last_sequence );
+ r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
+ if (r != ERROR_SUCCESS)
+ ERR("Failed to update Media table entry, expect breakage (%u).\n", r);
+
+ db->media_transform_offset = last_sequence + 1;
+ }
+
+ msi_patch_offset_list_free( pos );
+ msiobj_release( &rec->hdr );
+ }
+
+done:
+ msiobj_release( &view->hdr );
+
+ return r;
+}
+
UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
{
UINT i, r = ERROR_SUCCESS;
@@ -633,7 +880,11 @@ UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINF
/* apply substorage transforms */
substorage = msi_split_string( patch->transforms, ';' );
for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
+ {
r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
+ if (r == ERROR_SUCCESS)
+ msi_set_patch_offsets( package->db );
+ }
msi_free( substorage );
if (r != ERROR_SUCCESS)
diff --git a/dlls/msi/database.c b/dlls/msi/database.c
index 598d7a8..fe97069 100644
--- a/dlls/msi/database.c
+++ b/dlls/msi/database.c
@@ -417,6 +417,8 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
db->path = strdupW( path );
+ db->media_transform_offset = MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
+
if( TRACE_ON( msi ) )
enum_stream_names( stg );
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 096678c..1a0bee0 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -75,6 +75,8 @@ struct tagMSIOBJECTHDR
msihandledestructor destructor;
};
+#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000
+
typedef struct tagMSIDATABASE
{
MSIOBJECTHDR hdr;
@@ -85,6 +87,7 @@ typedef struct tagMSIDATABASE
LPWSTR deletefile;
LPWSTR localfile;
LPCWSTR mode;
+ UINT media_transform_offset;
struct list tables;
struct list transforms;
struct list streams;
diff --git a/dlls/msi/tests/patch.c b/dlls/msi/tests/patch.c
index 4cad4eb..ee712bb 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");
+ todo_wine 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