msi: Add offsets to file patch sequence numbers.
This commit is contained in:
parent
123428942d
commit
4c1791f53e
|
@ -1340,17 +1340,15 @@ static UINT load_patch(MSIRECORD *row, LPVOID param)
|
|||
{
|
||||
MSIPACKAGE *package = param;
|
||||
MSIFILEPATCH *patch;
|
||||
LPWSTR file_key;
|
||||
const WCHAR *file_key;
|
||||
|
||||
patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
|
||||
if (!patch)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
file_key = msi_dup_record_field( row, 1 );
|
||||
file_key = MSI_RecordGetString( row, 1 );
|
||||
patch->File = msi_get_loaded_file( package, file_key );
|
||||
msi_free(file_key);
|
||||
|
||||
if( !patch->File )
|
||||
if (!patch->File)
|
||||
{
|
||||
ERR("Failed to find target for patch in File table\n");
|
||||
msi_free(patch);
|
||||
|
@ -1358,10 +1356,6 @@ static UINT load_patch(MSIRECORD *row, LPVOID param)
|
|||
}
|
||||
|
||||
patch->Sequence = MSI_RecordGetInteger( row, 2 );
|
||||
|
||||
/* FIXME: The database should be properly transformed */
|
||||
patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
|
||||
|
||||
patch->PatchSize = MSI_RecordGetInteger( row, 3 );
|
||||
patch->Attributes = MSI_RecordGetInteger( row, 4 );
|
||||
patch->IsApplied = FALSE;
|
||||
|
@ -1371,7 +1365,7 @@ static UINT load_patch(MSIRECORD *row, LPVOID param)
|
|||
* _StreamRef - External key into MsiPatchHeaders (instead of the header field)
|
||||
*/
|
||||
|
||||
TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
|
||||
TRACE("Patch loaded (file %s sequence %u)\n", debugstr_w(patch->File->File), patch->Sequence);
|
||||
|
||||
list_add_tail( &package->filepatches, &patch->entry );
|
||||
|
||||
|
|
|
@ -192,6 +192,8 @@ typedef struct tagMSIPATCHINFO
|
|||
LPWSTR localfile;
|
||||
MSIPATCHSTATE state;
|
||||
BOOL delete_on_close;
|
||||
UINT disk_id;
|
||||
UINT last_sequence;
|
||||
} MSIPATCHINFO;
|
||||
|
||||
typedef struct tagMSIBINARY
|
||||
|
|
222
dlls/msi/patch.c
222
dlls/msi/patch.c
|
@ -411,6 +411,7 @@ struct patch_offset
|
|||
struct patch_offset_list
|
||||
{
|
||||
struct list files;
|
||||
struct list patches;
|
||||
UINT count, min, max;
|
||||
UINT offset_to_apply;
|
||||
};
|
||||
|
@ -419,6 +420,7 @@ static struct patch_offset_list *patch_offset_list_create( void )
|
|||
{
|
||||
struct patch_offset_list *pos = msi_alloc( sizeof(struct patch_offset_list) );
|
||||
list_init( &pos->files );
|
||||
list_init( &pos->patches );
|
||||
pos->count = pos->max = 0;
|
||||
pos->min = 999999;
|
||||
return pos;
|
||||
|
@ -433,10 +435,15 @@ static void patch_offset_list_free( struct patch_offset_list *pos )
|
|||
msi_free( po->name );
|
||||
msi_free( po );
|
||||
}
|
||||
LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->patches, struct patch_offset, entry )
|
||||
{
|
||||
msi_free( po->name );
|
||||
msi_free( po );
|
||||
}
|
||||
msi_free( pos );
|
||||
}
|
||||
|
||||
static void patch_offset_get_patches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
|
||||
static void patch_offset_get_filepatches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
|
||||
{
|
||||
static const WCHAR query[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
|
||||
|
@ -460,12 +467,15 @@ static void patch_offset_get_patches( MSIDATABASE *db, UINT last_sequence, struc
|
|||
|
||||
while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
|
||||
{
|
||||
UINT sequence = MSI_RecordGetInteger( rec, 2 );
|
||||
struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) );
|
||||
|
||||
/* FIXME: we only use the max/min sequence numbers for now */
|
||||
pos->min = min( pos->min, sequence );
|
||||
pos->max = max( pos->max, sequence );
|
||||
po->name = msi_dup_record_field( rec, 1 );
|
||||
po->sequence = MSI_RecordGetInteger( rec, 2 );
|
||||
pos->min = min( pos->min, po->sequence );
|
||||
pos->max = max( pos->max, po->sequence );
|
||||
list_add_tail( &pos->patches, &po->entry );
|
||||
pos->count++;
|
||||
|
||||
msiobj_release( &rec->hdr );
|
||||
}
|
||||
msiobj_release( &view->hdr );
|
||||
|
@ -512,58 +522,137 @@ static void patch_offset_get_files( MSIDATABASE *db, UINT last_sequence, struct
|
|||
msiobj_release( &view->hdr );
|
||||
}
|
||||
|
||||
static UINT patch_update_file_sequence( MSIDATABASE *db, const struct patch_offset_list *pos,
|
||||
MSIQUERY *view, MSIRECORD *rec )
|
||||
{
|
||||
struct patch_offset *po;
|
||||
const WCHAR *file = MSI_RecordGetString( rec, 1 );
|
||||
UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 8 );
|
||||
|
||||
LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
|
||||
{
|
||||
if (!strcmpiW( file, po->name ))
|
||||
{
|
||||
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 (%u)\n", debugstr_w(file), r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT patch_update_filepatch_sequence( MSIDATABASE *db, const struct patch_offset_list *pos,
|
||||
MSIQUERY *view, MSIRECORD *rec )
|
||||
{
|
||||
static const WCHAR delete_query[] = {
|
||||
'D','E','L','E','T','E',' ','F','R','O','M',' ','`','P','a','t','c','h','`',' ',
|
||||
'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','?',' ',
|
||||
'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','=',' ','?',0};
|
||||
static const WCHAR insert_query[] = {
|
||||
'I','N','S','E','R','T',' ','I','N','T','O',' ','`','P','a','t','c','h','`',' ',
|
||||
'(','`','F','i','l','e','_','`',',','`','S','e','q','u','e','n','c','e','`',',',
|
||||
'`','P','a','t','c','h','S','i','z','e','`',',','`','A','t','t','r','i','b','u','t','e','s','`',',',
|
||||
'`','H','e','a','d','e','r','`',',','`','S','t','r','e','a','m','R','e','f','_','`',')',' ',
|
||||
'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
|
||||
struct patch_offset *po;
|
||||
const WCHAR *file = MSI_RecordGetString( rec, 1 );
|
||||
UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 2 );
|
||||
|
||||
LIST_FOR_EACH_ENTRY( po, &pos->patches, struct patch_offset, entry )
|
||||
{
|
||||
if (seq == po->sequence && !strcmpiW( file, po->name ))
|
||||
{
|
||||
MSIQUERY *delete_view, *insert_view;
|
||||
MSIRECORD *rec2;
|
||||
|
||||
r = MSI_DatabaseOpenViewW( db, delete_query, &delete_view );
|
||||
if (r != ERROR_SUCCESS) return r;
|
||||
|
||||
rec2 = MSI_CreateRecord( 2 );
|
||||
MSI_RecordSetStringW( rec2, 1, po->name );
|
||||
MSI_RecordSetInteger( rec2, 2, po->sequence );
|
||||
r = MSI_ViewExecute( delete_view, rec2 );
|
||||
msiobj_release( &delete_view->hdr );
|
||||
msiobj_release( &rec2->hdr );
|
||||
if (r != ERROR_SUCCESS) return r;
|
||||
|
||||
r = MSI_DatabaseOpenViewW( db, insert_query, &insert_view );
|
||||
if (r != ERROR_SUCCESS) return r;
|
||||
|
||||
MSI_RecordSetInteger( rec, 2, po->sequence + pos->offset_to_apply );
|
||||
|
||||
r = MSI_ViewExecute( insert_view, rec );
|
||||
msiobj_release( &insert_view->hdr );
|
||||
if (r != ERROR_SUCCESS)
|
||||
ERR("Failed to update offset for filepatch %s (%u)\n", debugstr_w(file), r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT patch_offset_modify_db( MSIDATABASE *db, struct patch_offset_list *pos )
|
||||
{
|
||||
static const WCHAR query[] = {
|
||||
'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 patch_offset *po;
|
||||
static const WCHAR file_query[] = {
|
||||
'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};
|
||||
static const WCHAR patch_query[] = {
|
||||
'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','`',' ','>','=',' ','?',' ',
|
||||
'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};
|
||||
MSIRECORD *rec;
|
||||
MSIQUERY *view;
|
||||
UINT r;
|
||||
UINT r, min = pos->min, max = pos->max, r_fetch;
|
||||
|
||||
r = MSI_DatabaseOpenViewW( db, query, &view );
|
||||
r = MSI_DatabaseOpenViewW( db, file_query, &view );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
rec = MSI_CreateRecord( 2 );
|
||||
MSI_RecordSetInteger( rec, 1, pos->min );
|
||||
MSI_RecordSetInteger( rec, 2, pos->max );
|
||||
MSI_RecordSetInteger( rec, 1, min );
|
||||
MSI_RecordSetInteger( rec, 2, max );
|
||||
|
||||
r = MSI_ViewExecute( view, rec );
|
||||
msiobj_release( &rec->hdr );
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
|
||||
while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
|
||||
{
|
||||
UINT r_fetch;
|
||||
while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
|
||||
{
|
||||
const WCHAR *file = MSI_RecordGetString( rec, 1 );
|
||||
UINT seq;
|
||||
r = patch_update_file_sequence( db, pos, view, rec );
|
||||
msiobj_release( &rec->hdr );
|
||||
if (r != ERROR_SUCCESS) goto done;
|
||||
}
|
||||
msiobj_release( &view->hdr );
|
||||
|
||||
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;
|
||||
r = MSI_DatabaseOpenViewW( db, patch_query, &view );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
rec = MSI_CreateRecord( 2 );
|
||||
MSI_RecordSetInteger( rec, 1, min );
|
||||
MSI_RecordSetInteger( rec, 2, max );
|
||||
|
||||
r = MSI_ViewExecute( view, rec );
|
||||
msiobj_release( &rec->hdr );
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
|
||||
{
|
||||
r = patch_update_filepatch_sequence( db, pos, view, rec );
|
||||
msiobj_release( &rec->hdr );
|
||||
if (r != ERROR_SUCCESS) goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
msiobj_release( &view->hdr );
|
||||
return ERROR_SUCCESS;
|
||||
return r;
|
||||
}
|
||||
|
||||
static const WCHAR patch_media_query[] = {
|
||||
|
@ -583,7 +672,7 @@ struct patch_media
|
|||
WCHAR *source;
|
||||
};
|
||||
|
||||
static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
|
||||
static UINT patch_add_media( MSIPACKAGE *package, IStorage *storage, MSIPATCHINFO *patch )
|
||||
{
|
||||
static const WCHAR delete_query[] = {
|
||||
'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
|
||||
|
@ -651,7 +740,7 @@ static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
|
|||
|
||||
disk_id = package->db->media_transform_disk_id;
|
||||
TRACE("disk id %u\n", disk_id);
|
||||
TRACE("last sequence %u\n", media->last_sequence);
|
||||
TRACE("last sequence %u\n", patch->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));
|
||||
|
@ -659,7 +748,7 @@ static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
|
|||
|
||||
rec = MSI_CreateRecord( 6 );
|
||||
MSI_RecordSetInteger( rec, 1, disk_id );
|
||||
MSI_RecordSetInteger( rec, 2, media->last_sequence );
|
||||
MSI_RecordSetInteger( rec, 2, patch->last_sequence );
|
||||
MSI_RecordSetStringW( rec, 3, media->prompt );
|
||||
MSI_RecordSetStringW( rec, 4, media->cabinet );
|
||||
MSI_RecordSetStringW( rec, 5, media->volume );
|
||||
|
@ -670,9 +759,13 @@ static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
|
|||
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++;
|
||||
r = msi_add_cabinet_stream( package, disk_id, storage, media->cabinet );
|
||||
if (r != ERROR_SUCCESS) ERR("failed to add cabinet stream %u\n", r);
|
||||
else
|
||||
{
|
||||
patch->disk_id = disk_id;
|
||||
package->db->media_transform_disk_id++;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
@ -689,7 +782,7 @@ done:
|
|||
return r;
|
||||
}
|
||||
|
||||
static UINT set_patch_offsets( MSIDATABASE *db )
|
||||
static UINT patch_set_offsets( MSIDATABASE *db, MSIPATCHINFO *patch )
|
||||
{
|
||||
MSIQUERY *view;
|
||||
MSIRECORD *rec;
|
||||
|
@ -705,7 +798,7 @@ static UINT set_patch_offsets( MSIDATABASE *db )
|
|||
|
||||
while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
|
||||
{
|
||||
UINT last_sequence = MSI_RecordGetInteger( rec, 2 );
|
||||
UINT offset, last_sequence = MSI_RecordGetInteger( rec, 2 );
|
||||
struct patch_offset_list *pos;
|
||||
|
||||
/* FIXME: set/check Source field instead? */
|
||||
|
@ -716,23 +809,27 @@ static UINT set_patch_offsets( MSIDATABASE *db )
|
|||
}
|
||||
pos = patch_offset_list_create();
|
||||
patch_offset_get_files( db, last_sequence, pos );
|
||||
patch_offset_get_patches( db, last_sequence, pos );
|
||||
patch_offset_get_filepatches( db, last_sequence, pos );
|
||||
|
||||
offset = db->media_transform_offset - pos->min;
|
||||
last_sequence = offset + pos->max;
|
||||
|
||||
last_sequence += pos->min;
|
||||
pos->offset_to_apply = offset;
|
||||
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;
|
||||
if (pos->count)
|
||||
patch_offset_modify_db( db, pos );
|
||||
|
||||
MSI_RecordSetInteger( rec, 2, last_sequence );
|
||||
r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
|
||||
r = patch_offset_modify_db( db, pos );
|
||||
if (r != ERROR_SUCCESS)
|
||||
ERR("Failed to update Media table entry, expect breakage (%u)\n", r);
|
||||
db->media_transform_offset = last_sequence + 1;
|
||||
ERR("Failed to set offsets, expect breakage (%u)\n", r);
|
||||
}
|
||||
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);
|
||||
|
||||
patch->last_sequence = last_sequence;
|
||||
db->media_transform_offset = last_sequence + 1;
|
||||
|
||||
patch_offset_list_free( pos );
|
||||
msiobj_release( &rec->hdr );
|
||||
}
|
||||
|
@ -754,15 +851,18 @@ static UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIP
|
|||
r = apply_substorage_transform( package, patch_db, substorage[i] );
|
||||
if (r == ERROR_SUCCESS)
|
||||
{
|
||||
add_patch_media( package, patch_db->storage );
|
||||
set_patch_offsets( package->db );
|
||||
r = patch_set_offsets( package->db, patch );
|
||||
if (r == ERROR_SUCCESS)
|
||||
r = patch_add_media( package, patch_db->storage, patch );
|
||||
}
|
||||
}
|
||||
msi_free( substorage );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
patch_set_media_source_prop( package );
|
||||
r = patch_set_media_source_prop( package );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
patch->state = MSIPATCHSTATE_APPLIED;
|
||||
list_add_tail( &package->patches, &patch->entry );
|
||||
|
|
Loading…
Reference in New Issue