[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