[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