[6/6] msi: Add offsets to disk ids added by patches.
Hans Leidekker
hans at codeweavers.com
Thu Apr 14 07:42:48 CDT 2011
---
dlls/msi/action.c | 172 ++++++++++++++++++++++++++++++++++++++++++++----
dlls/msi/database.c | 2 +-
dlls/msi/files.c | 2 +-
dlls/msi/media.c | 64 +++++++++---------
dlls/msi/msipriv.h | 2 +
dlls/msi/tests/patch.c | 11 +++-
6 files changed, 204 insertions(+), 49 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 8267aa9..7bed12f 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -806,18 +806,137 @@ done:
return ERROR_SUCCESS;
}
+static const WCHAR patch_media_query[] = {
+ '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};
+
+struct patch_media
+{
+ struct list entry;
+ UINT disk_id;
+ UINT last_sequence;
+ WCHAR *prompt;
+ WCHAR *cabinet;
+ WCHAR *volume;
+ WCHAR *source;
+};
+
+static UINT msi_add_patch_media( MSIPACKAGE *package, IStorage *patch )
+{
+ static const WCHAR delete_query[] = {
+ 'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
+ 'W','H','E','R','E',' ','`','D','i','s','k','I','d','`','=','?',0};
+ static const WCHAR insert_query[] = {
+ 'I','N','S','E','R','T',' ','I','N','T','O',' ','`','M','e','d','i','a','`',' ',
+ '(','`','D','i','s','k','I','d','`',',','`','L','a','s','t','S','e','q','u','e','n','c','e','`',',',
+ '`','D','i','s','k','P','r','o','m','p','t','`',',','`','C','a','b','i','n','e','t','`',',',
+ '`','V','o','l','u','m','e','L','a','b','e','l','`',',','`','S','o','u','r','c','e','`',')',' ',
+ 'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
+ MSIQUERY *view;
+ MSIRECORD *rec = NULL;
+ UINT r, disk_id;
+ struct list media_list;
+ struct patch_media *media, *next;
+
+ r = MSI_DatabaseOpenViewW( package->db, patch_media_query, &view );
+ if (r != ERROR_SUCCESS) return r;
+
+ r = MSI_ViewExecute( view, 0 );
+ if (r != ERROR_SUCCESS)
+ {
+ msiobj_release( &view->hdr );
+ TRACE("query failed %u\n", r);
+ return r;
+ }
+
+ list_init( &media_list );
+ while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
+ {
+ disk_id = MSI_RecordGetInteger( rec, 1 );
+ TRACE("disk_id %u\n", disk_id);
+ if (disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
+ {
+ msiobj_release( &rec->hdr );
+ continue;
+ }
+ if (!(media = msi_alloc( sizeof( *media )))) goto done;
+ media->disk_id = disk_id;
+ media->last_sequence = MSI_RecordGetInteger( rec, 2 );
+ media->prompt = msi_dup_record_field( rec, 3 );
+ media->cabinet = msi_dup_record_field( rec, 4 );
+ media->volume = msi_dup_record_field( rec, 5 );
+ media->source = msi_dup_record_field( rec, 6 );
+
+ list_add_tail( &media_list, &media->entry );
+ msiobj_release( &rec->hdr );
+ }
+ LIST_FOR_EACH_ENTRY( media, &media_list, struct patch_media, entry )
+ {
+ MSIQUERY *delete_view, *insert_view;
+
+ r = MSI_DatabaseOpenViewW( package->db, delete_query, &delete_view );
+ if (r != ERROR_SUCCESS) goto done;
+
+ rec = MSI_CreateRecord( 1 );
+ MSI_RecordSetInteger( rec, 1, media->disk_id );
+
+ r = MSI_ViewExecute( delete_view, rec );
+ msiobj_release( &delete_view->hdr );
+ msiobj_release( &rec->hdr );
+ if (r != ERROR_SUCCESS) goto done;
+
+ r = MSI_DatabaseOpenViewW( package->db, insert_query, &insert_view );
+ if (r != ERROR_SUCCESS) goto done;
+
+ disk_id = package->db->media_transform_disk_id;
+ TRACE("disk id %u\n", disk_id);
+ TRACE("last sequence %u\n", media->last_sequence);
+ TRACE("prompt %s\n", debugstr_w(media->prompt));
+ TRACE("cabinet %s\n", debugstr_w(media->cabinet));
+ TRACE("volume %s\n", debugstr_w(media->volume));
+ TRACE("source %s\n", debugstr_w(media->source));
+
+ rec = MSI_CreateRecord( 6 );
+ MSI_RecordSetInteger( rec, 1, disk_id );
+ MSI_RecordSetInteger( rec, 2, media->last_sequence );
+ MSI_RecordSetStringW( rec, 3, media->prompt );
+ MSI_RecordSetStringW( rec, 4, media->cabinet );
+ MSI_RecordSetStringW( rec, 5, media->volume );
+ MSI_RecordSetStringW( rec, 6, media->source );
+
+ r = MSI_ViewExecute( insert_view, rec );
+ msiobj_release( &insert_view->hdr );
+ msiobj_release( &rec->hdr );
+ if (r != ERROR_SUCCESS) goto done;
+
+ r = msi_add_cabinet_stream( package, disk_id, patch, media->cabinet );
+ if (r != ERROR_SUCCESS) WARN("failed to add cabinet stream %u\n", r);
+ package->db->media_transform_disk_id++;
+ }
+
+done:
+ msiobj_release( &view->hdr );
+ LIST_FOR_EACH_ENTRY_SAFE( media, next, &media_list, struct patch_media, entry )
+ {
+ list_remove( &media->entry );
+ msi_free( media->prompt );
+ msi_free( media->cabinet );
+ msi_free( media->volume );
+ msi_free( media->source );
+ msi_free( media );
+ }
+ return r;
+}
+
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;
+ MSIQUERY *view;
MSIRECORD *rec = NULL;
UINT r;
- r = MSI_DatabaseOpenViewW( db, query_media, &view );
+ r = MSI_DatabaseOpenViewW( db, patch_media_query, &view );
if (r != ERROR_SUCCESS)
return r;
@@ -869,7 +988,6 @@ static UINT msi_set_patch_offsets(MSIDATABASE *db)
done:
msiobj_release( &view->hdr );
-
return r;
}
@@ -884,7 +1002,10 @@ UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINF
{
r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
if (r == ERROR_SUCCESS)
+ {
+ msi_add_patch_media( package, patch_db->storage );
msi_set_patch_offsets( package->db );
+ }
}
msi_free( substorage );
@@ -893,12 +1014,6 @@ UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINF
msi_set_media_source_prop( package );
- /*
- * There might be a CAB file in the patch package,
- * so append it to the list of storages to search for streams.
- */
- append_storage_to_db( package->db, patch_db->storage );
-
patch->state = MSIPATCHSTATE_APPLIED;
list_add_tail( &package->patches, &patch->entry );
return ERROR_SUCCESS;
@@ -1848,6 +1963,34 @@ static UINT load_all_files(MSIPACKAGE *package)
return ERROR_SUCCESS;
}
+static UINT load_media( MSIRECORD *row, LPVOID param )
+{
+ MSIPACKAGE *package = param;
+ UINT disk_id = MSI_RecordGetInteger( row, 1 );
+ const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
+
+ /* FIXME: load external cabinets and directory sources too */
+ if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
+ msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
+ return ERROR_SUCCESS;
+}
+
+static UINT load_all_media( MSIPACKAGE *package )
+{
+ static const WCHAR query[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
+ 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
+ MSIQUERY *view;
+ UINT r;
+
+ r = MSI_DatabaseOpenViewW( package->db, query, &view );
+ if (r != ERROR_SUCCESS) return ERROR_SUCCESS;
+
+ MSI_IterateRecords( view, NULL, load_media, package );
+ msiobj_release( &view->hdr );
+ return ERROR_SUCCESS;
+}
+
static UINT load_patch(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE *package = param;
@@ -2018,6 +2161,7 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
load_all_features( package );
load_all_files( package );
load_all_patches( package );
+ load_all_media( package );
return ERROR_SUCCESS;
}
diff --git a/dlls/msi/database.c b/dlls/msi/database.c
index fe97069..2cb9ec4 100644
--- a/dlls/msi/database.c
+++ b/dlls/msi/database.c
@@ -416,8 +416,8 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
lstrcpyW( path, save_path );
db->path = strdupW( path );
-
db->media_transform_offset = MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
+ db->media_transform_disk_id = MSI_INITIAL_MEDIA_TRANSFORM_DISKID;
if( TRACE_ON( msi ) )
enum_stream_names( stg );
diff --git a/dlls/msi/files.c b/dlls/msi/files.c
index a4fe8ff..53ed2ab 100644
--- a/dlls/msi/files.c
+++ b/dlls/msi/files.c
@@ -364,7 +364,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
}
msi_free(source);
}
- else if (file->state != msifs_installed)
+ else if (file->state != msifs_installed && !(file->Attributes & msidbFileAttributesPatchAdded))
{
ERR("compressed file wasn't installed (%s)\n", debugstr_w(file->TargetPath));
rc = ERROR_INSTALL_FAILURE;
diff --git a/dlls/msi/media.c b/dlls/msi/media.c
index c699ecc..c261d7c 100644
--- a/dlls/msi/media.c
+++ b/dlls/msi/media.c
@@ -198,27 +198,40 @@ static LONG CDECL cabinet_seek(INT_PTR hf, LONG dist, int seektype)
return SetFilePointer(handle, dist, NULL, seektype);
}
-struct cab_stream
+struct package_disk
{
- MSIDATABASE *db;
- WCHAR *name;
+ MSIPACKAGE *package;
+ UINT id;
};
-static struct cab_stream cab_stream;
+static struct package_disk package_disk;
static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode )
{
- UINT r;
- IStream *stm;
+ MSICABINETSTREAM *cab;
+ IStream *stream;
+ WCHAR *encoded;
+ HRESULT hr;
- r = db_get_raw_stream( cab_stream.db, cab_stream.name, &stm );
- if (r != ERROR_SUCCESS)
+ cab = msi_get_cabinet_stream( package_disk.package, package_disk.id );
+ if (!cab)
{
- WARN("Failed to get cabinet stream %u\n", r);
+ WARN("failed to get cabinet stream\n");
return 0;
}
-
- return (INT_PTR)stm;
+ if (!cab->stream[0] || !(encoded = encode_streamname( FALSE, cab->stream + 1 )))
+ {
+ WARN("failed to encode stream name\n");
+ return 0;
+ }
+ hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
+ msi_free( encoded );
+ if (FAILED(hr))
+ {
+ WARN("failed to open stream 0x%08x\n", hr);
+ return 0;
+ }
+ return (INT_PTR)stream;
}
static UINT CDECL cabinet_read_stream( INT_PTR hf, void *pv, UINT cb )
@@ -378,14 +391,9 @@ static INT_PTR cabinet_next_cabinet_stream( FDINOTIFICATIONTYPE fdint,
ERR("Failed to get next cabinet information: %u\n", rc);
return -1;
}
+ package_disk.id = mi->disk_id;
- msi_free( cab_stream.name );
- cab_stream.name = encode_streamname( FALSE, mi->cabinet + 1 );
- if (!cab_stream.name)
- return -1;
-
- TRACE("next cabinet is %s\n", debugstr_w(mi->cabinet));
-
+ TRACE("next cabinet is %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
return 0;
}
@@ -553,7 +561,7 @@ static BOOL extract_cabinet( MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data
ERF erf;
BOOL ret = FALSE;
- TRACE("Extracting %s\n", debugstr_w(mi->cabinet));
+ TRACE("extracting %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
hfdi = FDICreate( cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
cabinet_write, cabinet_close, cabinet_seek, 0, &erf );
@@ -593,7 +601,7 @@ static BOOL extract_cabinet_stream( MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOI
ERF erf;
BOOL ret = FALSE;
- TRACE("Extracting %s\n", debugstr_w(mi->cabinet));
+ TRACE("extracting %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
hfdi = FDICreate( cabinet_alloc, cabinet_free, cabinet_open_stream, cabinet_read_stream,
cabinet_write, cabinet_close_stream, cabinet_seek_stream, 0, &erf );
@@ -603,22 +611,14 @@ static BOOL extract_cabinet_stream( MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOI
return FALSE;
}
- cab_stream.db = package->db;
- cab_stream.name = encode_streamname( FALSE, mi->cabinet + 1 );
- if (!cab_stream.name)
- goto done;
+ package_disk.package = package;
+ package_disk.id = mi->disk_id;
ret = FDICopy( hfdi, filename, NULL, 0, cabinet_notify_stream, NULL, data );
- if (!ret)
- ERR("FDICopy failed\n");
+ if (!ret) ERR("FDICopy failed\n");
-done:
FDIDestroy( hfdi );
- msi_free( cab_stream.name );
-
- if (ret)
- mi->is_extracted = TRUE;
-
+ if (ret) mi->is_extracted = TRUE;
return ret;
}
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index fead8ea..c132477 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -76,6 +76,7 @@ struct tagMSIOBJECTHDR
};
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000
+#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID 10000
typedef struct tagMSIDATABASE
{
@@ -88,6 +89,7 @@ typedef struct tagMSIDATABASE
LPWSTR localfile;
LPCWSTR mode;
UINT media_transform_offset;
+ UINT media_transform_disk_id;
struct list tables;
struct list transforms;
struct list streams;
diff --git a/dlls/msi/tests/patch.c b/dlls/msi/tests/patch.c
index 23aac2d..4c6db56 100644
--- a/dlls/msi/tests/patch.c
+++ b/dlls/msi/tests/patch.c
@@ -1095,6 +1095,9 @@ static void test_system_tables( void )
r = find_entry( hdb, "_Tables", "Media" );
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
+ r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
+ ok( r == 1, "Got %u\n", r );
+
r = find_entry( hdb, "_Tables", "_Property" );
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
@@ -1170,7 +1173,7 @@ static void test_system_tables( void )
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 );
+ 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 );
@@ -1178,6 +1181,12 @@ static void test_system_tables( void )
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, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
+ ok( r == 1, "Got %u\n", r );
+
+ cr = get_string( hdb, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
+ ok( !strcmp(cr, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr );
+
r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
ok( r == 10000, "Got %u\n", r );
--
1.7.4.1
More information about the wine-patches
mailing list