Commit eee070f1 authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

msi: Add offsets to disk ids added by patches.

parent 131ef637
......@@ -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,8 +1002,11 @@ 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 );
if (r != ERROR_SUCCESS)
......@@ -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;
}
......
......@@ -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 );
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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 );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment