[PATCH] kernel32: Implement ReplaceFileW.
Erich Hoover (none)
ehoover at mediaserver.
Mon Apr 1 04:43:04 CST 2002
---
dlls/kernel32/file.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 168 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index 0a67d4c..363ddf7 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -1524,14 +1524,177 @@ 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, nt_backup_name;
+ ANSI_STRING unix_replaced_name, unix_replacement_name, unix_backup_name;
+ HANDLE hReplaced = NULL, hReplacement = NULL, hBackup = NULL;
+ BY_HANDLE_FILE_INFORMATION ifoReplaced, ifoReplacement;
+ DWORD error = ERROR_SUCCESS;
+ UINT replaced_flags;
+ BOOL ret = FALSE;
+ NTSTATUS status;
+
+ if (dwReplaceFlags)
+ FIXME("Ignoring flags %x\n", dwReplaceFlags);
+
+ /* First two arguments are mandatory */
+ if (!lpReplacedFileName || !lpReplacementFileName)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ /* Convert pathnames and ensure the paths and files exist */
+ if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &nt_replaced_name, NULL, NULL)))
+ {
+ error = ERROR_PATH_NOT_FOUND;
+ goto exit;
+ }
+ replaced_flags = lpBackupFileName ? FILE_OPEN : FILE_OPEN_IF;
+ status = wine_nt_to_unix_file_name(&nt_replaced_name, &unix_replaced_name, replaced_flags, FALSE);
+ RtlFreeUnicodeString(&nt_replaced_name);
+ if (status != STATUS_SUCCESS)
+ {
+ error = ERROR_FILE_NOT_FOUND;
+ goto exit;
+ }
+
+ if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &nt_replacement_name, NULL, NULL)))
+ {
+ error = ERROR_PATH_NOT_FOUND;
+ RtlFreeAnsiString(&unix_replaced_name);
+ goto exit;
+ }
+ 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 = ERROR_FILE_NOT_FOUND;
+ RtlFreeAnsiString(&unix_replaced_name);
+ goto exit;
+ }
+
+ if (lpBackupFileName)
+ {
+ if (!(RtlDosPathNameToNtPathName_U(lpBackupFileName, &nt_backup_name, NULL, NULL)))
+ {
+ error = ERROR_PATH_NOT_FOUND;
+ RtlFreeAnsiString(&unix_replaced_name);
+ RtlFreeAnsiString(&unix_replacement_name);
+ goto exit;
+ }
+ 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 && status != STATUS_NO_SUCH_FILE)
+ {
+ error = ERROR_FILE_NOT_FOUND;
+ RtlFreeAnsiString(&unix_replaced_name);
+ RtlFreeAnsiString(&unix_replacement_name);
+ goto exit;
+ }
+ }
+
+ /*
+ * Open the replacement file for reading, writing, and deleting
+ * (writing and deleting are needed when finished)
+ */
+ if ((hReplacement = CreateFileW(lpReplacementFileName,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
+ {
+ error = GetLastError(); /* Use error returned by CreateFileW */
+ goto fail;
+ }
+ /* Obtain the file attributes from the replacement file */
+ if (!GetFileInformationByHandle( hReplacement, &ifoReplacement ))
+ {
+ WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(lpReplacementFileName));
+ goto fail;
+ }
+
+ /* Open the "replaced" file for reading and writing */
+ if ((hReplaced = CreateFileW(lpReplacedFileName, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ ifoReplacement.dwFileAttributes, hReplacement)) == INVALID_HANDLE_VALUE)
+ {
+ error = GetLastError();
+ /* Inappropriate permissions to remove "replaced" */
+ if (error != ERROR_FILE_NOT_FOUND) error = ERROR_UNABLE_TO_REMOVE_REPLACED;
+
+ /* If "replaced" does not exist and a backup is specified then FAIL, this
+ * functionality is not specified in the documentation but was tested and
+ * found to occur on windows xp.
+ */
+ goto fail;
+ }
+
+ /* If the user wants a backup then that needs to be performed first */
+ if (lpBackupFileName)
+ {
+ /* Obtain the file attributes from the "replaced" file */
+ if (!GetFileInformationByHandle(hReplaced, &ifoReplaced))
+ {
+ WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(lpReplacedFileName));
+ error = GetLastError();
+ goto fail;
+ }
+ /* Open the backup with permissions to write over it */
+ if ((hBackup = CreateFileW(lpBackupFileName, GENERIC_WRITE,
+ FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, ifoReplaced.dwFileAttributes,
+ hReplaced)) == INVALID_HANDLE_VALUE)
+ {
+ error = GetLastError();
+ 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);
+
+ if (lpBackupFileName) RtlFreeAnsiString(&unix_backup_name);
+ RtlFreeAnsiString(&unix_replacement_name);
+ RtlFreeAnsiString(&unix_replaced_name);
+
+exit:
+ /* If there was an error, set the error code */
+ if(!ret)
+ SetLastError(error);
+ return ret;
}
--
1.5.3.GIT
--------------030402090309020002000200--
More information about the wine-patches
mailing list