Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
fed6e521
Commit
fed6e521
authored
Mar 22, 2011
by
David Hedberg
Committed by
Alexandre Julliard
Mar 29, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
msi: Add an offset to sequence numbers belonging to files added by a patch.
parent
39988204
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
333 additions
and
0 deletions
+333
-0
action.c
dlls/msi/action.c
+251
-0
database.c
dlls/msi/database.c
+2
-0
msipriv.h
dlls/msi/msipriv.h
+3
-0
patch.c
dlls/msi/tests/patch.c
+77
-0
No files found.
dlls/msi/action.c
View file @
fed6e521
...
...
@@ -625,6 +625,253 @@ UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
return
r
;
}
struct
msi_patch_offset
{
struct
list
entry
;
LPWSTR
Name
;
UINT
Sequence
;
};
struct
msi_patch_offset_list
{
struct
list
files
;
UINT
count
,
min
,
max
;
UINT
offset_to_apply
;
};
static
struct
msi_patch_offset_list
*
msi_patch_offset_list_create
(
void
)
{
struct
msi_patch_offset_list
*
pos
=
msi_alloc
(
sizeof
(
struct
msi_patch_offset_list
));
list_init
(
&
pos
->
files
);
pos
->
count
=
pos
->
max
=
0
;
pos
->
min
=
999999
;
return
pos
;
}
static
void
msi_patch_offset_list_free
(
struct
msi_patch_offset_list
*
pos
)
{
struct
msi_patch_offset
*
po
,
*
po2
;
LIST_FOR_EACH_ENTRY_SAFE
(
po
,
po2
,
&
pos
->
files
,
struct
msi_patch_offset
,
entry
)
{
msi_free
(
po
->
Name
);
msi_free
(
po
);
}
msi_free
(
pos
);
}
static
void
msi_patch_offset_get_patches
(
MSIDATABASE
*
db
,
UINT
last_sequence
,
struct
msi_patch_offset_list
*
pos
)
{
MSIQUERY
*
view
;
MSIRECORD
*
rec
;
UINT
r
;
static
const
WCHAR
query_patch
[]
=
{
'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'
,
' '
,
'<'
,
'='
,
' '
,
'?'
,
' '
,
'O'
,
'R'
,
'D'
,
'E'
,
'R'
,
' '
,
'B'
,
'Y'
,
' '
,
'S'
,
'e'
,
'q'
,
'u'
,
'e'
,
'n'
,
'c'
,
'e'
,
0
};
r
=
MSI_DatabaseOpenViewW
(
db
,
query_patch
,
&
view
);
if
(
r
!=
ERROR_SUCCESS
)
return
;
rec
=
MSI_CreateRecord
(
1
);
MSI_RecordSetInteger
(
rec
,
1
,
last_sequence
);
r
=
MSI_ViewExecute
(
view
,
rec
);
msiobj_release
(
&
rec
->
hdr
);
if
(
r
!=
ERROR_SUCCESS
)
return
;
while
(
MSI_ViewFetch
(
view
,
&
rec
)
==
ERROR_SUCCESS
)
{
UINT
sequence
=
MSI_RecordGetInteger
(
rec
,
2
);
/* FIXME:
* We only use the max/min sequence numbers for now.
*/
pos
->
min
=
min
(
pos
->
min
,
sequence
);
pos
->
max
=
max
(
pos
->
max
,
sequence
);
pos
->
count
++
;
msiobj_release
(
&
rec
->
hdr
);
}
msiobj_release
(
&
view
->
hdr
);
}
static
void
msi_patch_offset_get_files
(
MSIDATABASE
*
db
,
UINT
last_sequence
,
struct
msi_patch_offset_list
*
pos
)
{
MSIQUERY
*
view
;
MSIRECORD
*
rec
;
UINT
r
;
static
const
WCHAR
query_files
[]
=
{
'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
};
r
=
MSI_DatabaseOpenViewW
(
db
,
query_files
,
&
view
);
if
(
r
!=
ERROR_SUCCESS
)
return
;
rec
=
MSI_CreateRecord
(
1
);
MSI_RecordSetInteger
(
rec
,
1
,
last_sequence
);
r
=
MSI_ViewExecute
(
view
,
rec
);
msiobj_release
(
&
rec
->
hdr
);
if
(
r
!=
ERROR_SUCCESS
)
return
;
while
(
MSI_ViewFetch
(
view
,
&
rec
)
==
ERROR_SUCCESS
)
{
UINT
attributes
=
MSI_RecordGetInteger
(
rec
,
7
);
if
(
attributes
&
msidbFileAttributesPatchAdded
)
{
struct
msi_patch_offset
*
po
=
msi_alloc
(
sizeof
(
struct
msi_patch_offset
));
po
->
Name
=
msi_dup_record_field
(
rec
,
1
);
po
->
Sequence
=
MSI_RecordGetInteger
(
rec
,
8
);
pos
->
min
=
min
(
pos
->
min
,
po
->
Sequence
);
pos
->
max
=
max
(
pos
->
max
,
po
->
Sequence
);
list_add_tail
(
&
pos
->
files
,
&
po
->
entry
);
pos
->
count
++
;
}
msiobj_release
(
&
rec
->
hdr
);
}
msiobj_release
(
&
view
->
hdr
);
}
static
UINT
msi_patch_offset_modify_db
(
MSIDATABASE
*
db
,
struct
msi_patch_offset_list
*
pos
)
{
static
const
WCHAR
query_files
[]
=
{
'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
msi_patch_offset
*
po
;
MSIQUERY
*
view
;
MSIRECORD
*
rec
;
UINT
r
;
r
=
MSI_DatabaseOpenViewW
(
db
,
query_files
,
&
view
);
if
(
r
!=
ERROR_SUCCESS
)
return
ERROR_SUCCESS
;
rec
=
MSI_CreateRecord
(
2
);
MSI_RecordSetInteger
(
rec
,
1
,
pos
->
min
);
MSI_RecordSetInteger
(
rec
,
2
,
pos
->
max
);
r
=
MSI_ViewExecute
(
view
,
rec
);
msiobj_release
(
&
rec
->
hdr
);
if
(
r
!=
ERROR_SUCCESS
)
goto
done
;
LIST_FOR_EACH_ENTRY
(
po
,
&
pos
->
files
,
struct
msi_patch_offset
,
entry
)
{
UINT
r_fetch
;
while
(
(
r_fetch
=
MSI_ViewFetch
(
view
,
&
rec
))
==
ERROR_SUCCESS
)
{
LPCWSTR
file
=
MSI_RecordGetString
(
rec
,
1
);
UINT
seq
;
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
;
}
done:
msiobj_release
(
&
view
->
hdr
);
return
ERROR_SUCCESS
;
}
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
;
MSIRECORD
*
rec
=
NULL
;
UINT
r
;
r
=
MSI_DatabaseOpenViewW
(
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
);
struct
msi_patch_offset_list
*
pos
;
/* FIXME: Set/Check Source field instead? */
if
(
last_sequence
>=
MSI_INITIAL_MEDIA_TRANSFORM_OFFSET
)
{
msiobj_release
(
&
rec
->
hdr
);
continue
;
}
pos
=
msi_patch_offset_list_create
();
msi_patch_offset_get_files
(
db
,
last_sequence
,
pos
);
msi_patch_offset_get_patches
(
db
,
last_sequence
,
pos
);
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
;
msi_patch_offset_modify_db
(
db
,
pos
);
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
);
db
->
media_transform_offset
=
last_sequence
+
1
;
}
msi_patch_offset_list_free
(
pos
);
msiobj_release
(
&
rec
->
hdr
);
}
done:
msiobj_release
(
&
view
->
hdr
);
return
r
;
}
UINT
msi_apply_patch_db
(
MSIPACKAGE
*
package
,
MSIDATABASE
*
patch_db
,
MSIPATCHINFO
*
patch
)
{
UINT
i
,
r
=
ERROR_SUCCESS
;
...
...
@@ -633,7 +880,11 @@ UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINF
/* apply substorage transforms */
substorage
=
msi_split_string
(
patch
->
transforms
,
';'
);
for
(
i
=
0
;
substorage
&&
substorage
[
i
]
&&
r
==
ERROR_SUCCESS
;
i
++
)
{
r
=
msi_apply_substorage_transform
(
package
,
patch_db
,
substorage
[
i
]
);
if
(
r
==
ERROR_SUCCESS
)
msi_set_patch_offsets
(
package
->
db
);
}
msi_free
(
substorage
);
if
(
r
!=
ERROR_SUCCESS
)
...
...
dlls/msi/database.c
View file @
fed6e521
...
...
@@ -417,6 +417,8 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
db
->
path
=
strdupW
(
path
);
db
->
media_transform_offset
=
MSI_INITIAL_MEDIA_TRANSFORM_OFFSET
;
if
(
TRACE_ON
(
msi
)
)
enum_stream_names
(
stg
);
...
...
dlls/msi/msipriv.h
View file @
fed6e521
...
...
@@ -75,6 +75,8 @@ struct tagMSIOBJECTHDR
msihandledestructor
destructor
;
};
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000
typedef
struct
tagMSIDATABASE
{
MSIOBJECTHDR
hdr
;
...
...
@@ -85,6 +87,7 @@ typedef struct tagMSIDATABASE
LPWSTR
deletefile
;
LPWSTR
localfile
;
LPCWSTR
mode
;
UINT
media_transform_offset
;
struct
list
tables
;
struct
list
transforms
;
struct
list
streams
;
...
...
dlls/msi/tests/patch.c
View file @
fed6e521
...
...
@@ -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"
);
todo_wine
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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment