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
5e218fe7
Commit
5e218fe7
authored
Mar 12, 2020
by
Zebediah Figura
Committed by
Alexandre Julliard
Mar 13, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernel32: Reimplement ReplaceFile() on top of MoveFileEx().
Signed-off-by:
Zebediah Figura
<
zfigura@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
dca6461e
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
35 additions
and
105 deletions
+35
-105
file.c
dlls/kernel32/file.c
+35
-105
No files found.
dlls/kernel32/file.c
View file @
5e218fe7
...
...
@@ -423,11 +423,7 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
LPVOID
lpExclude
,
LPVOID
lpReserved
)
{
UNICODE_STRING
nt_replaced_name
,
nt_replacement_name
;
ANSI_STRING
unix_replaced_name
,
unix_replacement_name
,
unix_backup_name
;
HANDLE
hReplaced
=
NULL
,
hReplacement
=
NULL
,
hBackup
=
NULL
;
DWORD
error
=
ERROR_SUCCESS
;
UINT
replaced_flags
;
BOOL
ret
=
FALSE
;
HANDLE
hReplacement
=
NULL
;
NTSTATUS
status
;
IO_STATUS_BLOCK
io
;
OBJECT_ATTRIBUTES
attr
;
...
...
@@ -447,10 +443,6 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
return
FALSE
;
}
unix_replaced_name
.
Buffer
=
NULL
;
unix_replacement_name
.
Buffer
=
NULL
;
unix_backup_name
.
Buffer
=
NULL
;
attr
.
Length
=
sizeof
(
attr
);
attr
.
RootDirectory
=
0
;
attr
.
Attributes
=
OBJ_CASE_INSENSITIVE
;
...
...
@@ -461,39 +453,21 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
/* Open the "replaced" file for reading */
if
(
!
(
RtlDosPathNameToNtPathName_U
(
lpReplacedFileName
,
&
nt_replaced_name
,
NULL
,
NULL
)))
{
error
=
ERROR_PATH_NOT_FOUND
;
goto
fail
;
SetLastError
(
ERROR_PATH_NOT_FOUND
)
;
return
FALSE
;
}
replaced_flags
=
lpBackupFileName
?
FILE_OPEN
:
FILE_OPEN_IF
;
attr
.
ObjectName
=
&
nt_replaced_name
;
status
=
NtOpenFile
(
&
hReplaced
,
GENERIC_READ
|
DELETE
|
SYNCHRONIZE
,
&
attr
,
&
io
,
FILE_SHARE_READ
|
FILE_SHARE_WRITE
|
FILE_SHARE_DELETE
,
FILE_SYNCHRONOUS_IO_NONALERT
|
FILE_NON_DIRECTORY_FILE
);
if
(
status
==
STATUS_SUCCESS
)
status
=
wine_nt_to_unix_file_name
(
&
nt_replaced_name
,
&
unix_replaced_name
,
replaced_flags
,
FALSE
);
RtlFreeUnicodeString
(
&
nt_replaced_name
);
if
(
status
!=
STATUS_SUCCESS
)
{
if
(
status
==
STATUS_OBJECT_NAME_NOT_FOUND
)
error
=
ERROR_FILE_NOT_FOUND
;
else
error
=
ERROR_UNABLE_TO_REMOVE_REPLACED
;
goto
fail
;
}
/* Replacement should fail if replaced is READ_ONLY */
status
=
NtQueryInformationFile
(
hReplaced
,
&
io
,
&
info
,
sizeof
(
info
),
FileBasicInformation
);
status
=
NtQueryAttributesFile
(
&
attr
,
&
info
);
RtlFreeUnicodeString
(
&
nt_replaced_name
);
if
(
status
!=
STATUS_SUCCESS
)
{
error
=
RtlNtStatusToDosError
(
status
);
goto
fail
;
}
return
set_ntstatus
(
status
);
if
(
info
.
FileAttributes
&
FILE_ATTRIBUTE_READONLY
)
{
error
=
ERROR_ACCESS_DENIED
;
goto
fail
;
SetLastError
(
ERROR_ACCESS_DENIED
)
;
return
FALSE
;
}
/*
...
...
@@ -502,65 +476,41 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
*/
if
(
!
(
RtlDosPathNameToNtPathName_U
(
lpReplacementFileName
,
&
nt_replacement_name
,
NULL
,
NULL
)))
{
error
=
ERROR_PATH_NOT_FOUND
;
goto
fail
;
SetLastError
(
ERROR_PATH_NOT_FOUND
)
;
return
FALSE
;
}
attr
.
ObjectName
=
&
nt_replacement_name
;
status
=
NtOpenFile
(
&
hReplacement
,
GENERIC_READ
|
GENERIC_WRITE
|
DELETE
|
WRITE_DAC
|
SYNCHRONIZE
,
&
attr
,
&
io
,
0
,
FILE_SYNCHRONOUS_IO_NONALERT
|
FILE_NON_DIRECTORY_FILE
);
if
(
status
==
STATUS_SUCCESS
)
status
=
wine_nt_to_unix_file_name
(
&
nt_replacement_name
,
&
unix_replacement_name
,
FILE_OPEN
,
FALSE
);
RtlFreeUnicodeString
(
&
nt_replacement_name
);
if
(
status
!=
STATUS_SUCCESS
)
{
error
=
RtlNtStatusToDosError
(
status
);
goto
fail
;
}
return
set_ntstatus
(
status
);
NtClose
(
hReplacement
);
/* If the user wants a backup then that needs to be performed first */
if
(
lpBackupFileName
)
{
UNICODE_STRING
nt_backup_name
;
FILE_BASIC_INFORMATION
replaced_info
;
/* Obtain the file attributes from the "replaced" file */
status
=
NtQueryInformationFile
(
hReplaced
,
&
io
,
&
replaced_info
,
sizeof
(
replaced_info
),
FileBasicInformation
);
if
(
status
!=
STATUS_SUCCESS
)
{
error
=
RtlNtStatusToDosError
(
status
);
goto
fail
;
}
if
(
!
(
RtlDosPathNameToNtPathName_U
(
lpBackupFileName
,
&
nt_backup_name
,
NULL
,
NULL
)))
{
error
=
ERROR_PATH_NOT_FOUND
;
goto
fail
;
}
attr
.
ObjectName
=
&
nt_backup_name
;
/* Open the backup with permissions to write over it */
status
=
NtCreateFile
(
&
hBackup
,
GENERIC_WRITE
|
SYNCHRONIZE
,
&
attr
,
&
io
,
NULL
,
replaced_info
.
FileAttributes
,
FILE_SHARE_WRITE
,
FILE_OPEN_IF
,
FILE_SYNCHRONOUS_IO_NONALERT
|
FILE_NON_DIRECTORY_FILE
,
NULL
,
0
);
if
(
status
==
STATUS_SUCCESS
)
status
=
wine_nt_to_unix_file_name
(
&
nt_backup_name
,
&
unix_backup_name
,
FILE_OPEN_IF
,
FALSE
);
RtlFreeUnicodeString
(
&
nt_backup_name
);
if
(
status
!=
STATUS_SUCCESS
)
{
error
=
RtlNtStatusToDosError
(
status
);
goto
fail
;
}
if
(
!
MoveFileExW
(
lpReplacedFileName
,
lpBackupFileName
,
MOVEFILE_REPLACE_EXISTING
))
return
FALSE
;
}
else
{
/* ReplaceFile() can replace an open target. To do this, we need to move
* it out of the way first. */
static
const
WCHAR
prefixW
[]
=
{
'r'
,
'f'
,
0
};
WCHAR
temp_path
[
MAX_PATH
],
temp_file
[
MAX_PATH
];
if
(
!
GetTempPathW
(
ARRAY_SIZE
(
temp_path
),
temp_path
)
||
!
GetTempFileNameW
(
temp_path
,
prefixW
,
0
,
temp_file
)
||
!
MoveFileExW
(
lpReplacedFileName
,
temp_file
,
MOVEFILE_REPLACE_EXISTING
))
return
FALSE
;
/* If an existing backup exists then copy over it */
if
(
rename
(
unix_replaced_name
.
Buffer
,
unix_backup_name
.
Buffer
)
==
-
1
)
if
(
!
DeleteFileW
(
temp_file
))
{
error
=
ERROR_UNABLE_TO_REMOVE_REPLACED
;
/* is this correct? */
goto
fail
;
SetLastError
(
ERROR_UNABLE_TO_REMOVE_REPLACED
);
return
FALSE
;
}
}
...
...
@@ -568,37 +518,17 @@ BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileNa
* Now that the backup has been performed (if requested), copy the replacement
* into place
*/
if
(
rename
(
unix_replacement_name
.
Buffer
,
unix_replaced_name
.
Buffer
)
==
-
1
)
if
(
!
MoveFileExW
(
lpReplacementFileName
,
lpReplacedFileName
,
0
)
)
{
if
(
errno
==
EACCES
)
{
/* Inappropriate permissions on "replaced", rename will fail */
error
=
ERROR_UNABLE_TO_REMOVE_REPLACED
;
goto
fail
;
}
/* on failure we need to indicate whether a backup was made */
if
(
!
lpBackupFileName
)
error
=
ERROR_UNABLE_TO_MOVE_REPLACEMENT
;
SetLastError
(
ERROR_UNABLE_TO_MOVE_REPLACEMENT
)
;
else
error
=
ERROR_UNABLE_TO_MOVE_REPLACEMENT_2
;
goto
fail
;
SetLastError
(
ERROR_UNABLE_TO_MOVE_REPLACEMENT_2
)
;
return
FALSE
;
}
/* Success! */
ret
=
TRUE
;
/* Perform resource cleanup */
fail:
if
(
hBackup
)
CloseHandle
(
hBackup
);
if
(
hReplaced
)
CloseHandle
(
hReplaced
);
if
(
hReplacement
)
CloseHandle
(
hReplacement
);
RtlFreeAnsiString
(
&
unix_backup_name
);
RtlFreeAnsiString
(
&
unix_replacement_name
);
RtlFreeAnsiString
(
&
unix_replaced_name
);
/* If there was an error, set the error code */
if
(
!
ret
)
SetLastError
(
error
);
return
ret
;
return
TRUE
;
}
...
...
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