[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