Rob Shearman : kernel32: Implement ReplaceFileW.
Alexandre Julliard
julliard at winehq.org
Tue Feb 12 16:46:16 CST 2008
Module: wine
Branch: master
Commit: c72de7bce2c4c5bda08caa61f140fb4a5358997f
URL: http://source.winehq.org/git/wine.git/?a=commit;h=c72de7bce2c4c5bda08caa61f140fb4a5358997f
Author: Rob Shearman <rob at codeweavers.com>
Date: Thu Feb 7 12:43:25 2008 +0000
kernel32: Implement ReplaceFileW.
Based on a patch by Erich Hoover.
---
dlls/kernel32/file.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 158 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index acc762b..a5da6c6 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -1524,14 +1524,167 @@ BOOL WINAPI DeleteFileA( LPCSTR path )
* ReplaceFileW (KERNEL32.@)
* ReplaceFile (KERNEL32.@)
*/
-BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
+BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName,
LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
LPVOID lpExclude, LPVOID lpReserved)
{
- FIXME("(%s,%s,%s,%08x,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
- debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
- SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
- return FALSE;
+ 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;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ OBJECT_ATTRIBUTES attr;
+
+ if (dwReplaceFlags)
+ FIXME("Ignoring flags %x\n", dwReplaceFlags);
+
+ /* First two arguments are mandatory */
+ if (!lpReplacedFileName || !lpReplacementFileName)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ 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;
+ attr.ObjectName = NULL;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ /* Open the "replaced" file for reading and writing */
+ if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &nt_replaced_name, NULL, NULL)))
+ {
+ error = ERROR_PATH_NOT_FOUND;
+ goto fail;
+ }
+ replaced_flags = lpBackupFileName ? FILE_OPEN : FILE_OPEN_IF;
+ attr.ObjectName = &nt_replaced_name;
+ status = NtOpenFile(&hReplaced, GENERIC_READ|GENERIC_WRITE|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;
+ }
+
+ /*
+ * Open the replacement file for reading, writing, and deleting
+ * (writing and deleting are needed when finished)
+ */
+ if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &nt_replacement_name, NULL, NULL)))
+ {
+ error = ERROR_PATH_NOT_FOUND;
+ goto fail;
+ }
+ 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;
+ }
+
+ /* 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,
+ &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);
+ if (status != STATUS_SUCCESS)
+ {
+ error = RtlNtStatusToDosError(status);
+ goto fail;
+ }
+
+ /* If an existing backup exists then copy over it */
+ if (rename(unix_replaced_name.Buffer, unix_backup_name.Buffer) == -1)
+ {
+ error = ERROR_UNABLE_TO_REMOVE_REPLACED; /* is this correct? */
+ goto fail;
+ }
+ }
+
+ /*
+ * 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 (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;
+ else
+ error = ERROR_UNABLE_TO_MOVE_REPLACEMENT_2;
+ goto fail;
+ }
+ /* 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;
}
More information about the wine-cvs
mailing list