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
489f82e9
Commit
489f82e9
authored
Dec 23, 2010
by
Hans Leidekker
Committed by
Alexandre Julliard
Dec 23, 2010
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
msi: Rewrite command line parsing to handle quoted values correctly.
parent
7bc7d091
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
316 additions
and
53 deletions
+316
-53
action.c
dlls/msi/action.c
+143
-53
install.c
dlls/msi/tests/install.c
+173
-0
No files found.
dlls/msi/action.c
View file @
489f82e9
...
...
@@ -299,79 +299,167 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
msiobj_release
(
&
row
->
hdr
);
}
enum
parse_state
{
state_whitespace
,
state_token
,
state_quote
};
static
int
parse_prop
(
const
WCHAR
*
str
,
WCHAR
*
value
,
int
*
quotes
)
{
enum
parse_state
state
=
state_quote
;
const
WCHAR
*
p
;
WCHAR
*
out
=
value
;
int
ignore
,
in_quotes
=
0
,
count
=
0
,
len
=
0
;
for
(
p
=
str
;
*
p
;
p
++
)
{
ignore
=
0
;
switch
(
state
)
{
case
state_whitespace
:
switch
(
*
p
)
{
case
' '
:
if
(
!
count
)
goto
done
;
in_quotes
=
1
;
ignore
=
1
;
break
;
case
'"'
:
state
=
state_quote
;
if
(
in_quotes
)
count
--
;
else
count
++
;
break
;
default:
state
=
state_token
;
if
(
!
count
)
in_quotes
=
0
;
else
in_quotes
=
1
;
len
++
;
break
;
}
break
;
case
state_token
:
switch
(
*
p
)
{
case
'"'
:
state
=
state_quote
;
if
(
in_quotes
)
count
--
;
else
count
++
;
break
;
case
' '
:
state
=
state_whitespace
;
if
(
!
count
)
goto
done
;
in_quotes
=
1
;
break
;
default:
if
(
!
count
)
in_quotes
=
0
;
else
in_quotes
=
1
;
len
++
;
break
;
}
break
;
case
state_quote
:
switch
(
*
p
)
{
case
'"'
:
if
(
in_quotes
)
count
--
;
else
count
++
;
break
;
case
' '
:
state
=
state_whitespace
;
if
(
!
count
||
!
len
)
goto
done
;
in_quotes
=
1
;
break
;
default:
state
=
state_token
;
if
(
!
count
)
in_quotes
=
0
;
else
in_quotes
=
1
;
len
++
;
break
;
}
break
;
default:
break
;
}
if
(
!
ignore
)
*
out
++
=
*
p
;
}
done:
if
(
!
len
)
*
value
=
0
;
else
*
out
=
0
;
*
quotes
=
count
;
return
p
-
str
;
}
static
void
remove_quotes
(
WCHAR
*
str
)
{
WCHAR
*
p
=
str
;
int
len
=
strlenW
(
str
);
while
((
p
=
strchrW
(
p
,
'"'
)))
{
memmove
(
p
,
p
+
1
,
(
len
-
(
p
-
str
))
*
sizeof
(
WCHAR
)
);
p
++
;
}
}
UINT
msi_parse_command_line
(
MSIPACKAGE
*
package
,
LPCWSTR
szCommandLine
,
BOOL
preserve_case
)
{
LPCWSTR
ptr
,
ptr2
;
BOOL
quote
;
LPCWSTR
ptr
,
ptr2
;
int
quotes
;
DWORD
len
;
LPWSTR
prop
=
NULL
,
val
=
NULL
;
WCHAR
*
prop
,
*
val
;
UINT
r
;
if
(
!
szCommandLine
)
return
ERROR_SUCCESS
;
ptr
=
szCommandLine
;
while
(
*
ptr
)
{
if
(
*
ptr
==
' '
)
{
ptr
++
;
continue
;
}
while
(
*
ptr
==
' '
)
ptr
++
;
if
(
!*
ptr
)
break
;
TRACE
(
"Looking at %s
\n
"
,
debugstr_w
(
ptr
));
ptr2
=
strchrW
(
ptr
,
'='
);
if
(
!
ptr2
)
{
ERR
(
"command line contains unknown string : %s
\n
"
,
debugstr_w
(
ptr
));
break
;
}
ptr2
=
strchrW
(
ptr
,
'='
);
if
(
!
ptr2
)
return
ERROR_INVALID_COMMAND_LINE
;
quote
=
FALSE
;
len
=
ptr2
-
ptr
;
if
(
!
len
)
return
ERROR_INVALID_COMMAND_LINE
;
len
=
ptr2
-
ptr
;
prop
=
msi_alloc
((
len
+
1
)
*
sizeof
(
WCHAR
));
memcpy
(
prop
,
ptr
,
len
*
sizeof
(
WCHAR
));
prop
[
len
]
=
0
;
if
(
!
preserve_case
)
struprW
(
prop
);
prop
=
msi_alloc
(
(
len
+
1
)
*
sizeof
(
WCHAR
)
);
memcpy
(
prop
,
ptr
,
len
*
sizeof
(
WCHAR
)
);
prop
[
len
]
=
0
;
if
(
!
preserve_case
)
struprW
(
prop
);
ptr2
++
;
len
=
0
;
ptr
=
ptr2
;
while
(
*
ptr
&&
(
quote
||
(
!
quote
&&
*
ptr
!=
' '
)))
{
if
(
*
ptr
==
'"'
)
quote
=
!
quote
;
ptr
++
;
len
++
;
}
if
(
*
ptr2
==
'"'
)
while
(
*
ptr2
==
' '
)
ptr2
++
;
quotes
=
0
;
val
=
msi_alloc
(
(
strlenW
(
ptr2
)
+
1
)
*
sizeof
(
WCHAR
)
);
len
=
parse_prop
(
ptr2
,
val
,
&
quotes
);
if
(
quotes
%
2
)
{
ptr2
++
;
len
-=
2
;
WARN
(
"unbalanced quotes
\n
"
);
msi_free
(
val
);
msi_free
(
prop
);
return
ERROR_INVALID_COMMAND_LINE
;
}
val
=
msi_alloc
((
len
+
1
)
*
sizeof
(
WCHAR
));
memcpy
(
val
,
ptr2
,
len
*
sizeof
(
WCHAR
));
val
[
len
]
=
0
;
remove_quotes
(
val
);
TRACE
(
"Found commandline property %s = %s
\n
"
,
debugstr_w
(
prop
),
debugstr_w
(
val
));
if
(
lstrlenW
(
prop
)
>
0
)
{
UINT
r
=
msi_set_property
(
package
->
db
,
prop
,
val
);
r
=
msi_set_property
(
package
->
db
,
prop
,
val
);
if
(
r
==
ERROR_SUCCESS
&&
!
strcmpW
(
prop
,
cszSourceDir
))
msi_reset_folders
(
package
,
TRUE
);
TRACE
(
"Found commandline property (%s) = (%s)
\n
"
,
debugstr_w
(
prop
),
debugstr_w
(
val
)
);
msi_free
(
val
);
msi_free
(
prop
);
if
(
r
==
ERROR_SUCCESS
&&
!
strcmpW
(
prop
,
cszSourceDir
))
msi_reset_folders
(
package
,
TRUE
);
}
msi_free
(
val
);
msi_free
(
prop
);
ptr
=
ptr2
+
len
;
}
return
ERROR_SUCCESS
;
...
...
@@ -7356,7 +7444,9 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
msi_set_sourcedir_props
(
package
,
FALSE
);
}
msi_parse_command_line
(
package
,
szCommandLine
,
FALSE
);
rc
=
msi_parse_command_line
(
package
,
szCommandLine
,
FALSE
);
if
(
rc
!=
ERROR_SUCCESS
)
return
rc
;
msi_apply_transforms
(
package
);
msi_apply_patches
(
package
);
...
...
dlls/msi/tests/install.c
View file @
489f82e9
...
...
@@ -1169,6 +1169,25 @@ static const CHAR sd_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComm
"TestSourceDirProp34
\t
19
\t\t
Test 34 failed
\t\n
"
"TestSourceDirProp35
\t
19
\t\t
Test 35 failed
\t\n
"
;
static
const
CHAR
cl_custom_action_dat
[]
=
"Action
\t
Type
\t
Source
\t
Target
\t
ISComments
\n
"
"s72
\t
i2
\t
S64
\t
S0
\t
S255
\n
"
"CustomAction
\t
Action
\n
"
"TestCommandlineProp
\t
19
\t\t
Test1
\t\n
"
;
static
const
CHAR
cl_install_exec_seq_dat
[]
=
"Action
\t
Condition
\t
Sequence
\n
"
"s72
\t
S255
\t
I2
\n
"
"InstallExecuteSequence
\t
Action
\n
"
"LaunchConditions
\t\t
100
\n
"
"ValidateProductID
\t\t
700
\n
"
"CostInitialize
\t\t
800
\n
"
"FileCost
\t\t
900
\n
"
"CostFinalize
\t\t
1000
\n
"
"TestCommandlineProp
\t
P=
\"
one
\"\t
1100
\n
"
"InstallInitialize
\t\t
1500
\n
"
"ProcessComponents
\t\t
1600
\n
"
"InstallValidate
\t\t
1400
\n
"
"InstallFinalize
\t\t
5000
\n
"
;
typedef
struct
_msi_table
{
const
CHAR
*
filename
;
...
...
@@ -1835,6 +1854,19 @@ static const msi_table pv_tables[] =
ADD_TABLE
(
property
)
};
static
const
msi_table
cl_tables
[]
=
{
ADD_TABLE
(
component
),
ADD_TABLE
(
directory
),
ADD_TABLE
(
feature
),
ADD_TABLE
(
feature_comp
),
ADD_TABLE
(
file
),
ADD_TABLE
(
cl_custom_action
),
ADD_TABLE
(
cl_install_exec_seq
),
ADD_TABLE
(
media
),
ADD_TABLE
(
property
)
};
/* cabinet definitions */
/* make the max size large so there is only one cab file */
...
...
@@ -6168,6 +6200,146 @@ error:
RemoveDirectory
(
"msitest"
);
}
static
void
test_command_line_parsing
(
void
)
{
UINT
r
;
const
char
*
cmd
;
if
(
is_process_limited
())
{
skip
(
"process is limited
\n
"
);
return
;
}
create_test_files
();
create_database
(
msifile
,
cl_tables
,
sizeof
(
cl_tables
)
/
sizeof
(
msi_table
));
MsiSetInternalUI
(
INSTALLUILEVEL_NONE
,
NULL
);
cmd
=
" "
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"="
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"=="
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"one"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"=one"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P="
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
" P="
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P= "
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"\"\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P=
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=one"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INSTALL_FAILURE
,
"Expected ERROR_INSTALL_FAILURE, got %u
\n
"
,
r
);
cmd
=
"P= one"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INSTALL_FAILURE
,
"Expected ERROR_INSTALL_FAILURE, got %u
\n
"
,
r
);
cmd
=
"P=
\"
one"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P=one
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
todo_wine
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=
\"
one
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INSTALL_FAILURE
,
"Expected ERROR_INSTALL_FAILURE, got %u
\n
"
,
r
);
cmd
=
"P=
\"
one
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INSTALL_FAILURE
,
"Expected ERROR_INSTALL_FAILURE, got %u
\n
"
,
r
);
cmd
=
"P=
\"
one
\"\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"
one
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"
one
\"\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
todo_wine
ok
(
r
==
ERROR_INVALID_COMMAND_LINE
,
"Expected ERROR_INVALID_COMMAND_LINE, got %u
\n
"
,
r
);
cmd
=
"P=
\"
one two
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"\"
one
\"\"
two
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"\"
one
\"\"
two
\"
Q=three"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=
\"\"
Q=
\"
two
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
cmd
=
"P=
\"
one
\"
Q=
\"
two
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_INSTALL_FAILURE
,
"Expected ERROR_INSTALL_FAILURE, got %u
\n
"
,
r
);
cmd
=
"P=
\"
one=two
\"
"
;
r
=
MsiInstallProductA
(
msifile
,
cmd
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
DeleteFile
(
msifile
);
RemoveDirectory
(
"msitest"
);
}
START_TEST
(
install
)
{
DWORD
len
;
...
...
@@ -6257,6 +6429,7 @@ START_TEST(install)
test_icon_table
();
test_sourcedir_props
();
test_package_validation
();
test_command_line_parsing
();
DeleteFileA
(
log_file
);
...
...
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