msi: Add offsets to disk ids added by patches.
This commit is contained in:
parent
131ef6372f
commit
eee070f1e0
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
Loading…
Reference in New Issue