[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