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
9c8b83ce
Commit
9c8b83ce
authored
Oct 01, 2009
by
Hans Leidekker
Committed by
Alexandre Julliard
Oct 01, 2009
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
msi: Schedule a rename operation when the file to overwrite is in use.
parent
93c949eb
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
208 additions
and
43 deletions
+208
-43
action.c
dlls/msi/action.c
+3
-0
files.c
dlls/msi/files.c
+36
-3
media.c
dlls/msi/media.c
+42
-5
msipriv.h
dlls/msi/msipriv.h
+1
-0
install.c
dlls/msi/tests/install.c
+126
-35
No files found.
dlls/msi/action.c
View file @
9c8b83ce
...
...
@@ -880,6 +880,9 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
/* finish up running custom actions */
ACTION_FinishCustomActions
(
package
);
if
(
rc
==
ERROR_SUCCESS
&&
package
->
need_reboot
)
return
ERROR_SUCCESS_REBOOT_REQUIRED
;
return
rc
;
}
...
...
dlls/msi/files.c
View file @
9c8b83ce
...
...
@@ -139,7 +139,7 @@ static UINT copy_file(MSIFILE *file, LPWSTR source)
return
ERROR_SUCCESS
;
}
static
UINT
copy_install_file
(
MSIFILE
*
file
,
LPWSTR
source
)
static
UINT
copy_install_file
(
MSI
PACKAGE
*
package
,
MSI
FILE
*
file
,
LPWSTR
source
)
{
UINT
gle
;
...
...
@@ -153,7 +153,7 @@ static UINT copy_install_file(MSIFILE *file, LPWSTR source)
if
(
gle
==
ERROR_ALREADY_EXISTS
&&
file
->
state
==
msifs_overwrite
)
{
TRACE
(
"overwriting existing file
\n
"
);
gle
=
ERROR_SUCCESS
;
return
ERROR_SUCCESS
;
}
else
if
(
gle
==
ERROR_ACCESS_DENIED
)
{
...
...
@@ -162,6 +162,39 @@ static UINT copy_install_file(MSIFILE *file, LPWSTR source)
gle
=
copy_file
(
file
,
source
);
TRACE
(
"Overwriting existing file: %d
\n
"
,
gle
);
}
if
(
gle
==
ERROR_SHARING_VIOLATION
)
{
static
const
WCHAR
msiW
[]
=
{
'm'
,
's'
,
'i'
,
0
};
static
const
WCHAR
slashW
[]
=
{
'\\'
,
0
};
WCHAR
tmpfileW
[
MAX_PATH
],
*
pathW
,
*
p
;
DWORD
len
;
TRACE
(
"file in use, scheduling rename operation
\n
"
);
GetTempFileNameW
(
slashW
,
msiW
,
0
,
tmpfileW
);
len
=
strlenW
(
file
->
TargetPath
)
+
strlenW
(
tmpfileW
)
+
1
;
if
(
!
(
pathW
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
))))
return
ERROR_OUTOFMEMORY
;
strcpyW
(
pathW
,
file
->
TargetPath
);
if
((
p
=
strrchrW
(
pathW
,
'\\'
)))
*
p
=
0
;
strcatW
(
pathW
,
tmpfileW
);
if
(
CopyFileW
(
source
,
pathW
,
FALSE
)
&&
MoveFileExW
(
file
->
TargetPath
,
NULL
,
MOVEFILE_DELAY_UNTIL_REBOOT
)
&&
MoveFileExW
(
pathW
,
file
->
TargetPath
,
MOVEFILE_DELAY_UNTIL_REBOOT
))
{
file
->
state
=
msifs_installed
;
package
->
need_reboot
=
1
;
gle
=
ERROR_SUCCESS
;
}
else
{
gle
=
GetLastError
();
WARN
(
"failed to schedule rename operation: %d)
\n
"
,
gle
);
}
HeapFree
(
GetProcessHeap
(),
0
,
pathW
);
}
return
gle
;
}
...
...
@@ -296,7 +329,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
debugstr_w
(
file
->
TargetPath
));
msi_file_update_ui
(
package
,
file
,
szInstallFiles
);
rc
=
copy_install_file
(
file
,
source
);
rc
=
copy_install_file
(
package
,
file
,
source
);
if
(
rc
!=
ERROR_SUCCESS
)
{
ERR
(
"Failed to copy %s to %s (%d)
\n
"
,
debugstr_w
(
source
),
...
...
dlls/msi/media.c
View file @
9c8b83ce
...
...
@@ -338,15 +338,52 @@ static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint,
if
(
handle
==
INVALID_HANDLE_VALUE
)
{
DWORD
err
=
GetLastError
();
DWORD
attrs
=
GetFileAttributesW
(
path
);
DWORD
attrs
2
=
GetFileAttributesW
(
path
);
if
(
attrs
==
INVALID_FILE_ATTRIBUTES
)
if
(
attrs2
==
INVALID_FILE_ATTRIBUTES
)
{
ERR
(
"failed to create %s (error %d)
\n
"
,
debugstr_w
(
path
),
err
);
else
if
(
err
==
ERROR_ACCESS_DENIED
&&
(
attrs
&
FILE_ATTRIBUTE_READONLY
))
goto
done
;
}
else
if
(
err
==
ERROR_ACCESS_DENIED
&&
(
attrs2
&
FILE_ATTRIBUTE_READONLY
))
{
TRACE
(
"removing read-only attribute on %s
\n
"
,
debugstr_w
(
path
));
SetFileAttributesW
(
path
,
attrs
&
~
FILE_ATTRIBUTE_READONLY
);
handle
=
CreateFileW
(
path
,
GENERIC_READ
|
GENERIC_WRITE
,
0
,
NULL
,
CREATE_ALWAYS
,
attrs
,
NULL
);
SetFileAttributesW
(
path
,
attrs2
&
~
FILE_ATTRIBUTE_READONLY
);
handle
=
CreateFileW
(
path
,
GENERIC_READ
|
GENERIC_WRITE
,
0
,
NULL
,
CREATE_ALWAYS
,
attrs2
,
NULL
);
if
(
handle
!=
INVALID_HANDLE_VALUE
)
goto
done
;
err
=
GetLastError
();
}
if
(
err
==
ERROR_SHARING_VIOLATION
)
{
static
const
WCHAR
msiW
[]
=
{
'm'
,
's'
,
'i'
,
0
};
static
const
WCHAR
slashW
[]
=
{
'\\'
,
0
};
WCHAR
tmpfileW
[
MAX_PATH
],
*
tmppathW
,
*
p
;
DWORD
len
;
TRACE
(
"file in use, scheduling rename operation
\n
"
);
GetTempFileNameW
(
slashW
,
msiW
,
0
,
tmpfileW
);
len
=
strlenW
(
path
)
+
strlenW
(
tmpfileW
)
+
1
;
if
(
!
(
tmppathW
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
))))
return
ERROR_OUTOFMEMORY
;
strcpyW
(
tmppathW
,
path
);
if
((
p
=
strrchrW
(
tmppathW
,
'\\'
)))
*
p
=
0
;
strcatW
(
tmppathW
,
tmpfileW
);
handle
=
CreateFileW
(
tmppathW
,
GENERIC_READ
|
GENERIC_WRITE
,
0
,
NULL
,
CREATE_ALWAYS
,
attrs
,
NULL
);
if
(
handle
!=
INVALID_HANDLE_VALUE
&&
MoveFileExW
(
path
,
NULL
,
MOVEFILE_DELAY_UNTIL_REBOOT
)
&&
MoveFileExW
(
tmppathW
,
path
,
MOVEFILE_DELAY_UNTIL_REBOOT
))
{
data
->
package
->
need_reboot
=
1
;
}
else
WARN
(
"failed to schedule rename operation %s (error %d)
\n
"
,
debugstr_w
(
path
),
GetLastError
());
HeapFree
(
GetProcessHeap
(),
0
,
tmppathW
);
}
else
WARN
(
"failed to create %s (error %d)
\n
"
,
debugstr_w
(
path
),
err
);
...
...
dlls/msi/msipriv.h
View file @
9c8b83ce
...
...
@@ -340,6 +340,7 @@ typedef struct tagMSIPACKAGE
unsigned
char
scheduled_action_running
:
1
;
unsigned
char
commit_action_running
:
1
;
unsigned
char
rollback_action_running
:
1
;
unsigned
char
need_reboot
:
1
;
}
MSIPACKAGE
;
typedef
struct
tagMSIPREVIEW
...
...
dlls/msi/tests/install.c
View file @
9c8b83ce
...
...
@@ -1551,6 +1551,18 @@ static const msi_table fiu_tables[] =
ADD_TABLE
(
property
),
};
static
const
msi_table
fiuc_tables
[]
=
{
ADD_TABLE
(
rof_component
),
ADD_TABLE
(
directory
),
ADD_TABLE
(
rof_feature
),
ADD_TABLE
(
rof_feature_comp
),
ADD_TABLE
(
rofc_file
),
ADD_TABLE
(
pp_install_exec_seq
),
ADD_TABLE
(
rofc_media
),
ADD_TABLE
(
property
),
};
/* cabinet definitions */
/* make the max size large so there is only one cab file */
...
...
@@ -6689,20 +6701,74 @@ static void test_installed_prop(void)
delete_test_files
();
}
static
char
session_manager
[]
=
"System
\\
CurrentControlSet
\\
Control
\\
Session Manager"
;
static
char
rename_ops
[]
=
"PendingFileRenameOperations"
;
static
void
process_pending_renames
(
HKEY
hkey
)
{
char
*
buf
,
*
src
,
*
dst
;
DWORD
size
;
LONG
ret
;
ret
=
RegQueryValueExA
(
hkey
,
rename_ops
,
NULL
,
NULL
,
NULL
,
&
size
);
buf
=
HeapAlloc
(
GetProcessHeap
(),
0
,
size
);
buf
[
0
]
=
0
;
ret
=
RegQueryValueExA
(
hkey
,
rename_ops
,
NULL
,
NULL
,
(
LPBYTE
)
buf
,
&
size
);
ok
(
!
ret
,
"RegQueryValueExA failed %d (%u)
\n
"
,
ret
,
GetLastError
());
ok
(
strstr
(
buf
,
"msitest
\\
maximus"
)
!=
NULL
,
"Unexpected value
\"
%s
\"\n
"
,
buf
);
for
(
src
=
buf
;
*
src
;
src
=
dst
+
strlen
(
dst
)
+
1
)
{
DWORD
flags
=
MOVEFILE_COPY_ALLOWED
;
dst
=
src
+
strlen
(
src
)
+
1
;
if
(
*
dst
==
'!'
)
{
flags
|=
MOVEFILE_REPLACE_EXISTING
;
dst
++
;
}
if
(
src
[
0
]
==
'\\'
&&
src
[
1
]
==
'?'
&&
src
[
2
]
==
'?'
&&
src
[
3
]
==
'\\'
)
src
+=
4
;
if
(
*
dst
)
{
if
(
dst
[
0
]
==
'\\'
&&
dst
[
1
]
==
'?'
&&
dst
[
2
]
==
'?'
&&
dst
[
3
]
==
'\\'
)
dst
+=
4
;
ok
(
MoveFileExA
(
src
,
dst
,
flags
),
"Failed to move file %s -> %s (%u)
\n
"
,
src
,
dst
,
GetLastError
());
}
else
ok
(
DeleteFileA
(
src
),
"Failed to delete file %s (%u)
\n
"
,
src
,
GetLastError
());
}
HeapFree
(
GetProcessHeap
(),
0
,
buf
);
RegDeleteValueA
(
hkey
,
rename_ops
);
}
static
BOOL
file_matches_data
(
LPCSTR
file
,
LPCSTR
data
)
{
DWORD
len
,
data_len
=
strlen
(
data
);
HANDLE
handle
;
char
buf
[
128
];
handle
=
CreateFile
(
file
,
GENERIC_READ
,
FILE_SHARE_READ
,
NULL
,
OPEN_EXISTING
,
0
,
NULL
);
ok
(
handle
!=
INVALID_HANDLE_VALUE
,
"failed to open %s (%u)
\n
"
,
file
,
GetLastError
());
if
(
ReadFile
(
handle
,
buf
,
sizeof
(
buf
),
&
len
,
NULL
)
&&
len
>=
data_len
)
{
CloseHandle
(
handle
);
return
!
memcmp
(
buf
,
data
,
data_len
);
}
CloseHandle
(
handle
);
return
FALSE
;
}
static
void
test_file_in_use
(
void
)
{
UINT
r
;
DWORD
size
;
HANDLE
file
;
HKEY
hkey
;
LONG
ret
;
char
path
[
MAX_PATH
],
*
buf
,
*
src
,
*
dst
;
static
char
key
[]
=
"System
\\
CurrentControlSet
\\
Control
\\
Session Manager"
;
static
char
value
[]
=
"PendingFileRenameOperations"
;
char
path
[
MAX_PATH
];
RegOpenKeyExA
(
HKEY_LOCAL_MACHINE
,
key
,
0
,
KEY_ALL_ACCESS
,
&
hkey
);
if
(
!
RegQueryValueExA
(
hkey
,
value
,
NULL
,
NULL
,
NULL
,
&
size
))
RegOpenKeyExA
(
HKEY_LOCAL_MACHINE
,
session_manager
,
0
,
KEY_ALL_ACCESS
,
&
hkey
);
if
(
!
RegQueryValueExA
(
hkey
,
rename_ops
,
NULL
,
NULL
,
NULL
,
&
size
))
{
skip
(
"Pending file rename operations, skipping test
\n
"
);
return
;
...
...
@@ -6722,48 +6788,72 @@ static void test_file_in_use(void)
file
=
CreateFileA
(
path
,
GENERIC_READ
,
FILE_SHARE_READ
,
NULL
,
CREATE_NEW
,
FILE_ATTRIBUTE_NORMAL
,
NULL
);
r
=
MsiInstallProductA
(
msifile
,
"REBOOT=ReallySuppress FULL=1"
);
todo_wine
ok
(
r
==
ERROR_SUCCESS_REBOOT_REQUIRED
,
"Expected ERROR_SUCCESS_REBOOT_REQUIRED got %u
\n
"
,
r
);
ok
(
!
file_matches
(
path
),
"Expected file not to match
\n
"
);
ok
(
r
==
ERROR_SUCCESS_REBOOT_REQUIRED
,
"Expected ERROR_SUCCESS_REBOOT_REQUIRED got %u
\n
"
,
r
);
ok
(
!
file_matches
_data
(
path
,
"msitest
\\
maximus"
),
"Expected file not to match
\n
"
);
CloseHandle
(
file
);
ok
(
!
file_matches_data
(
path
,
"msitest
\\
maximus"
),
"Expected file not to match
\n
"
);
ret
=
RegQueryValueExA
(
hkey
,
value
,
NULL
,
NULL
,
NULL
,
&
size
);
buf
=
HeapAlloc
(
GetProcessHeap
(),
0
,
size
);
process_pending_renames
(
hkey
);
RegCloseKey
(
hkey
);
buf
[
0
]
=
0
;
ret
=
RegQueryValueExA
(
hkey
,
value
,
NULL
,
NULL
,
(
LPBYTE
)
buf
,
&
size
);
todo_wine
ok
(
!
ret
,
"RegQueryValueExA failed %d (%u)
\n
"
,
ret
,
GetLastError
());
todo_wine
ok
(
strstr
(
buf
,
"msitest
\\
maximus"
)
!=
NULL
,
"Unexpected value
\"
%s
\"\n
"
,
buf
);
ok
(
file_matches_data
(
path
,
"msitest
\\
maximus"
),
"Expected file to match
\n
"
);
ok
(
delete_pf
(
"msitest
\\
maximus"
,
TRUE
),
"File not present
\n
"
);
ok
(
delete_pf
(
"msitest"
,
FALSE
),
"Directory not present or not empty
\n
"
);
for
(
src
=
buf
;
*
src
;
src
=
dst
+
strlen
(
dst
)
+
1
)
{
DWORD
flags
=
MOVEFILE_COPY_ALLOWED
;
r
=
MsiInstallProductA
(
msifile
,
"REMOVE=ALL"
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
dst
=
src
+
strlen
(
src
)
+
1
;
if
(
*
dst
==
'!'
)
{
flags
|=
MOVEFILE_REPLACE_EXISTING
;
dst
++
;
}
src
+=
strlen
(
"
\\
??
\\
"
);
if
(
*
dst
)
delete_test_files
();
}
static
void
test_file_in_use_cab
(
void
)
{
UINT
r
;
DWORD
size
;
HANDLE
file
;
HKEY
hkey
;
char
path
[
MAX_PATH
];
RegOpenKeyExA
(
HKEY_LOCAL_MACHINE
,
session_manager
,
0
,
KEY_ALL_ACCESS
,
&
hkey
);
if
(
!
RegQueryValueExA
(
hkey
,
rename_ops
,
NULL
,
NULL
,
NULL
,
&
size
))
{
dst
+=
strlen
(
"
\\
??
\\
"
);
ok
(
MoveFileExA
(
src
,
dst
,
flags
),
"Failed to move file %s -> %s (%u)
\n
"
,
src
,
dst
,
GetLastError
());
}
else
ok
(
DeleteFileA
(
src
),
"Failed to delete file %s (%u)
\n
"
,
src
,
GetLastError
());
skip
(
"Pending file rename operations, skipping test
\n
"
);
return
;
}
HeapFree
(
GetProcessHeap
(),
0
,
buf
);
RegDeleteValueA
(
hkey
,
value
);
CreateDirectoryA
(
"msitest"
,
NULL
);
create_file
(
"maximus"
,
500
);
create_cab_file
(
"test1.cab"
,
MEDIA_SIZE
,
"maximus
\0
"
);
DeleteFile
(
"maximus"
);
create_database
(
msifile
,
fiuc_tables
,
sizeof
(
fiuc_tables
)
/
sizeof
(
msi_table
));
MsiSetInternalUI
(
INSTALLUILEVEL_NONE
,
NULL
);
lstrcpy
(
path
,
PROG_FILES_DIR
);
lstrcat
(
path
,
"
\\
msitest"
);
CreateDirectoryA
(
path
,
NULL
);
lstrcat
(
path
,
"
\\
maximus"
);
file
=
CreateFileA
(
path
,
GENERIC_READ
,
FILE_SHARE_READ
,
NULL
,
CREATE_NEW
,
FILE_ATTRIBUTE_NORMAL
,
NULL
);
r
=
MsiInstallProductA
(
msifile
,
"REBOOT=ReallySuppress FULL=1"
);
ok
(
r
==
ERROR_SUCCESS_REBOOT_REQUIRED
,
"Expected ERROR_SUCCESS_REBOOT_REQUIRED got %u
\n
"
,
r
);
ok
(
!
file_matches_data
(
path
,
"maximus"
),
"Expected file not to match
\n
"
);
CloseHandle
(
file
);
ok
(
!
file_matches_data
(
path
,
"maximus"
),
"Expected file not to match
\n
"
);
process_pending_renames
(
hkey
);
RegCloseKey
(
hkey
);
todo_wine
ok
(
file_matches
(
path
),
"Expected file to match
\n
"
);
ok
(
file_matches_data
(
path
,
"maximus"
),
"Expected file to match
\n
"
);
ok
(
delete_pf
(
"msitest
\\
maximus"
,
TRUE
),
"File not present
\n
"
);
ok
(
delete_pf
(
"msitest"
,
FALSE
),
"Directory not present
\n
"
);
ok
(
delete_pf
(
"msitest"
,
FALSE
),
"Directory not present
or not empty
\n
"
);
r
=
MsiInstallProductA
(
msifile
,
"REMOVE=ALL"
);
ok
(
r
==
ERROR_SUCCESS
,
"Expected ERROR_SUCCESS, got %u
\n
"
,
r
);
delete_cab_files
();
delete_test_files
();
}
...
...
@@ -6854,6 +6944,7 @@ START_TEST(install)
test_preselected
();
test_installed_prop
();
test_file_in_use
();
test_file_in_use_cab
();
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