[PATCH] kernel32: Implement ReplaceFileW.

Erich Hoover ehoover at mines.edu
Mon Apr 1 04:43:04 CST 2002


---
 dlls/kernel32/file.c |  170 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 165 insertions(+), 5 deletions(-)

diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index 0a67d4c..c69cd41 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -1524,14 +1524,174 @@ 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 ntReplacedFileName, ntReplacementFileName, ntBackupFileName;
+    ANSI_STRING uReplacedFileName, uReplacementFileName, uBackupFileName;
+    HANDLE hReplaced = NULL, hReplacement = NULL, hBackup = NULL;
+    BY_HANDLE_FILE_INFORMATION ifoReplaced, ifoReplacement;
+    DWORD error = GetLastError();
+    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, &ntReplacedFileName, NULL, NULL)))
+    {
+        error = ERROR_PATH_NOT_FOUND;
+        goto replace_fail_1;
+    }
+    replaced_flags = lpBackupFileName ? FILE_OPEN : FILE_OPEN_IF;
+    status = wine_nt_to_unix_file_name(&ntReplacedFileName, &uReplacedFileName, replaced_flags, FALSE);
+    RtlFreeUnicodeString(&ntReplacedFileName);
+    if (status != STATUS_SUCCESS)
+    {
+        error = ERROR_FILE_NOT_FOUND;
+        goto replace_fail_2;
+    }
+    if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &ntReplacementFileName, NULL, NULL)))
+    {
+        error = ERROR_PATH_NOT_FOUND;
+        goto replace_fail_2;
+    }
+    status = wine_nt_to_unix_file_name(&ntReplacementFileName, &uReplacementFileName, FILE_OPEN, FALSE);
+    RtlFreeUnicodeString(&ntReplacementFileName);
+    if (status != STATUS_SUCCESS)
+    {
+        error = ERROR_FILE_NOT_FOUND;
+        goto replace_fail_3;
+    }
+    if (lpBackupFileName)
+    {
+        if (!(RtlDosPathNameToNtPathName_U(lpBackupFileName, &ntBackupFileName, NULL, NULL)))
+        {
+            error = ERROR_PATH_NOT_FOUND;
+            goto replace_fail_3;
+        }
+        status = wine_nt_to_unix_file_name(&ntBackupFileName, &uBackupFileName, FILE_OPEN_IF, FALSE);
+        RtlFreeUnicodeString(&ntBackupFileName);
+        if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
+        {
+            error = ERROR_FILE_NOT_FOUND;
+            goto replace_fail_4;
+        }
+    }
+    /*
+     * 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 replace_fail_4;
+    }
+    /* Obtain the file attributes from the replacement file */
+    if (!GetFileInformationByHandle( hReplacement, &ifoReplacement ))
+    {
+        WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(lpReplacementFileName));
+        goto replace_fail_5;
+    }
+    /* 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();
+        if (error == ERROR_FILE_NOT_FOUND)
+        {
+            /* 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 replace_fail_5;
+        }
+        else
+        {
+            /* Inappropriate permissions to remove "replaced" */
+            error = ERROR_UNABLE_TO_REMOVE_REPLACED;
+            goto replace_fail_5;
+        }
+    }
+    /* 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 replace_fail_6;
+        }
+        /* 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 replace_fail_6;
+        }
+        /* If an existing backup exists then copy over it */
+        if (rename(uReplacedFileName.Buffer, uBackupFileName.Buffer) == -1)
+        {
+            error = ERROR_UNABLE_TO_REMOVE_REPLACED; /* is this correct? */
+            goto replace_fail_7;
+        }
+    }
+    /*
+     * Now that the backup has been performed (if requested), copy the replacement
+     * into place
+     */
+    if (rename(uReplacementFileName.Buffer, uReplacedFileName.Buffer) == -1)
+    {
+        if (errno == EACCES)
+        {
+            /* Inappropriate permissions on "replaced", rename will fail */
+            error = ERROR_UNABLE_TO_REMOVE_REPLACED;
+            goto replace_fail_7;
+        }
+        /* 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 replace_fail_7;
+    }
+    /* Success! */
+    ret = TRUE;
+    
+    /* Perform resource cleanup */
+replace_fail_7:
+    if(hBackup)
+        CloseHandle(hBackup);
+replace_fail_6:
+    CloseHandle(hReplaced);
+replace_fail_5:
+    CloseHandle(hReplacement);
+replace_fail_4:
+    if(lpBackupFileName)
+        RtlFreeAnsiString(&uBackupFileName);
+replace_fail_3:
+    RtlFreeAnsiString(&uReplacementFileName);
+replace_fail_2:
+    RtlFreeAnsiString(&uReplacedFileName);
+replace_fail_1:
+    /* If there was an error, set the error code */
+    if(!ret)
+        SetLastError(error);
+    return ret;
 }
 
 
-- 
1.5.3.GIT


--------------050202080309050307030800--



More information about the wine-patches mailing list