* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
* Gerhard W. Gruber (sparhawk_at_gmx.at)
* Dmitry Philippov (shedon@mail.ru)
+ * Pierre Schweitzer (pierre@reactos.org)
* UPDATE HISTORY:
* Created 01/11/98
* DP (29/07/2006)
#include <k32.h>
#include <malloc.h>
+#include <strsafe.h>
#define NDEBUG
#include <debug.h>
DEBUG_CHANNEL(kernel32file);
/* GLOBALS *****************************************************************/
-/* FUNCTIONS ****************************************************************/
-static BOOL
-RemoveReadOnlyAttributeW(IN LPCWSTR lpFileName)
+/* DEFINES *****************************************************************/
+typedef struct _COPY_PROGRESS_CONTEXT
{
- DWORD Attributes;
- Attributes = GetFileAttributesW(lpFileName);
- if (Attributes != INVALID_FILE_ATTRIBUTES)
- {
- return SetFileAttributesW(lpFileName,Attributes -
- (Attributes & ~FILE_ATTRIBUTE_READONLY));
- }
-
- return FALSE;
-}
-
+ ULONG Flags;
+ LPPROGRESS_ROUTINE UserRoutine;
+ LPVOID UserData;
+} COPY_PROGRESS_CONTEXT, *PCOPY_PROGRESS_CONTEXT;
-/***********************************************************************
- * add_boot_rename_entry
- *
- * Adds an entry to the registry that is loaded when windows boots and
- * checks if there are some files to be removed or renamed/moved.
- * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
- * non-NULL then the file is moved, otherwise it is deleted. The
- * entry of the registrykey is always appended with two zero
- * terminated strings. If <fn2> is NULL then the second entry is
- * simply a single 0-byte. Otherwise the second filename goes
- * there. The entries are prepended with \??\ before the path and the
- * second filename gets also a '!' as the first character if
- * MOVEFILE_REPLACE_EXISTING is set. After the final string another
- * 0-byte follows to indicate the end of the strings.
- * i.e.:
- * \??\D:\test\file1[0]
- * !\??\D:\test\file1_renamed[0]
- * \??\D:\Test|delete[0]
- * [0] <- file is to be deleted, second string empty
- * \??\D:\test\file2[0]
- * !\??\D:\test\file2_renamed[0]
- * [0] <- indicates end of strings
- *
- * or:
- * \??\D:\test\file1[0]
- * !\??\D:\test\file1_renamed[0]
- * \??\D:\Test|delete[0]
- * [0] <- file is to be deleted, second string empty
- * [0] <- indicates end of strings
- *
+/* FUNCTIONS ****************************************************************/
+/*
+ * @implemented
*/
-static BOOL add_boot_rename_entry( LPCWSTR source, LPCWSTR dest, DWORD flags )
+NTSTATUS
+WINAPI
+BasepMoveFileDelayed(IN PUNICODE_STRING ExistingPath,
+ IN PUNICODE_STRING NewPath,
+ IN INT KeyId,
+ IN BOOL CreateIfNotFound)
{
- static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
- 'F','i','l','e','R','e','n','a','m','e',
- 'O','p','e','r','a','t','i','o','n','s',0};
-
- UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager");
-
- static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
-
- OBJECT_ATTRIBUTES ObjectAttributes;
- UNICODE_STRING nameW, source_name, dest_name;
- KEY_VALUE_PARTIAL_INFORMATION *info;
- BOOL rc = FALSE;
- HANDLE Reboot = NULL;
- DWORD len1, len2;
- DWORD DestLen = 0;
- DWORD DataSize = 0;
- BYTE *Buffer = NULL;
- WCHAR *p;
+#define STRING_LENGTH 0x400
NTSTATUS Status;
+ HANDLE KeyHandle;
+ PVOID Buffer, BufferBegin;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PWSTR PendingOperations, BufferWrite;
+ ULONG DataSize, BufferLength, StringLength = STRING_LENGTH;
+ UNICODE_STRING SessionManagerString, PendingOperationsString;
+ /* +6 because a INT shouldn't take more than 6 chars. Especially given the call path */
+ WCHAR PendingOperationsBuffer[sizeof(L"PendingFileRenameOperations") / sizeof(WCHAR) + 6];
- TRACE("add_boot_rename_entry( %S, %S, %lu ) \n", source, dest, flags);
-
- if(dest)
- DestLen = wcslen(dest);
+ RtlInitUnicodeString(&SessionManagerString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager");
- if (!RtlDosPathNameToNtPathName_U( source, &source_name, NULL, NULL ))
+ /* Select appropriate key for adding our file */
+ if (KeyId == 1)
{
- SetLastError( ERROR_PATH_NOT_FOUND );
- return FALSE;
+ PendingOperations = L"PendingFileRenameOperations";
}
- dest_name.Buffer = NULL;
- if (DestLen && !RtlDosPathNameToNtPathName_U( dest, &dest_name, NULL, NULL ))
+ else
{
- RtlFreeHeap( RtlGetProcessHeap(), 0, source_name.Buffer );
- SetLastError( ERROR_PATH_NOT_FOUND );
- return FALSE;
+ StringCbPrintfW(PendingOperationsBuffer, sizeof(PendingOperationsBuffer), L"PendingFileRenameOperations%d", KeyId);
+ PendingOperations = PendingOperationsBuffer;
}
+ RtlInitUnicodeString(&PendingOperationsString, PendingOperations);
InitializeObjectAttributes(&ObjectAttributes,
- &KeyName,
+ &SessionManagerString,
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
-
- Status = NtCreateKey(&Reboot,
- KEY_QUERY_VALUE | KEY_SET_VALUE,
- &ObjectAttributes,
- 0,
- NULL,
- REG_OPTION_NON_VOLATILE,
- NULL);
-
- if (Status == STATUS_ACCESS_DENIED)
- {
- Status = NtCreateKey(
- &Reboot,
- KEY_QUERY_VALUE | KEY_SET_VALUE,
- &ObjectAttributes,
- 0,
- NULL,
- REG_OPTION_BACKUP_RESTORE,
- NULL);
- }
+ NULL, NULL);
+
+ /* Open parent key */
+ Status = NtCreateKey(&KeyHandle,
+ GENERIC_READ | GENERIC_WRITE,
+ &ObjectAttributes, 0, NULL,
+ REG_OPTION_NON_VOLATILE, NULL);
+ if (Status == STATUS_ACCESS_DENIED)
+ {
+ Status = NtCreateKey(&KeyHandle,
+ GENERIC_READ | GENERIC_WRITE,
+ &ObjectAttributes, 0, NULL,
+ REG_OPTION_BACKUP_RESTORE, NULL);
+ }
if (!NT_SUCCESS(Status))
{
- WARN("NtCreateKey() failed (Status 0x%lx)\n", Status);
- if (source_name.Buffer)
- RtlFreeHeap(RtlGetProcessHeap(), 0, source_name.Buffer);
- if (dest_name.Buffer)
- RtlFreeHeap(RtlGetProcessHeap(), 0, dest_name.Buffer);
- return FALSE;
+ return Status;
}
- len1 = source_name.Length + sizeof(WCHAR);
- if (DestLen)
+ /* Reserve enough to read previous string + to append our with required null chars */
+ BufferLength = NewPath->Length + ExistingPath->Length + STRING_LENGTH + 3 * sizeof(UNICODE_NULL);
+ /* Check we didn't overflow */
+ if (BufferLength < STRING_LENGTH)
{
- len2 = dest_name.Length + sizeof(WCHAR);
- if (flags & MOVEFILE_REPLACE_EXISTING)
- len2 += sizeof(WCHAR); /* Plus 1 because of the leading '!' */
+ NtClose(KeyHandle);
+ return STATUS_BUFFER_TOO_SMALL;
}
- else
+
+ while (TRUE)
{
- len2 = sizeof(WCHAR); /* minimum is the 0 characters for the empty second string */
+ /* Allocate output buffer */
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
+ if (Buffer == NULL)
+ {
+ NtClose(KeyHandle);
+ return STATUS_NO_MEMORY;
+ }
+
+ Status = NtQueryValueKey(KeyHandle,
+ &PendingOperationsString,
+ KeyValuePartialInformation,
+ Buffer, StringLength, &DataSize);
+ if (Status != STATUS_BUFFER_OVERFLOW)
+ {
+ break;
+ }
+
+ /* If buffer was too small, then, reallocate one which is big enough */
+ StringLength = DataSize;
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ BufferLength = ExistingPath->Length + StringLength + NewPath->Length + 3 * sizeof(UNICODE_NULL);
+ if (BufferLength < StringLength)
+ {
+ NtClose(KeyHandle);
+ return STATUS_BUFFER_TOO_SMALL;
+ }
}
- RtlInitUnicodeString( &nameW, ValueName );
-
- /* First we check if the key exists and if so how many bytes it already contains. */
- Status = NtQueryValueKey(
- Reboot,
- &nameW,
- KeyValuePartialInformation,
- NULL,
- 0,
- &DataSize );
- if ((Status == STATUS_BUFFER_OVERFLOW) ||
- (Status == STATUS_BUFFER_TOO_SMALL))
+ /* Check if it existed - if not, create only IF asked to */
+ if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND || !CreateIfNotFound))
{
- if (!(Buffer = HeapAlloc(GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR))))
- goto Quit;
- Status = NtQueryValueKey(Reboot, &nameW, KeyValuePartialInformation,
- Buffer, DataSize, &DataSize);
- if(!NT_SUCCESS(Status))
- goto Quit;
- info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
- if (info->Type != REG_MULTI_SZ) goto Quit;
- if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
+ NtClose(KeyHandle);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ return Status;
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* We didn't find any - ie, we create, so use complete buffer */
+ BufferBegin = Buffer;
+ BufferWrite = Buffer;
}
else
{
- DataSize = info_size;
- if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
- goto Quit;
+ PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
+
+ /* Get data, our buffer begin and then where we should append data
+ * (- null char, this is REG_MULTI_SZ, it already includes double termination, we keep only one)
+ */
+ BufferBegin = PartialInfo->Data;
+ BufferWrite = (PWSTR)((ULONG_PTR)PartialInfo->Data + PartialInfo->DataLength - sizeof(UNICODE_NULL));
}
- memcpy( Buffer + DataSize, source_name.Buffer, len1 );
- DataSize += len1;
- p = (WCHAR *)(Buffer + DataSize);
- if (DestLen)
+ /* First copy existing */
+ RtlCopyMemory(BufferWrite, ExistingPath->Buffer, ExistingPath->Length);
+ BufferWrite += ExistingPath->Length / sizeof(WCHAR);
+ /* And append null char */
+ *BufferWrite = UNICODE_NULL;
+ ++BufferWrite;
+ /* Append destination */
+ RtlCopyMemory(BufferWrite, NewPath->Buffer, NewPath->Length);
+ BufferWrite += NewPath->Length / sizeof(WCHAR);
+ /* And append two null char (end of string) */
+ *BufferWrite = UNICODE_NULL;
+ ++BufferWrite;
+ *BufferWrite = UNICODE_NULL;
+
+ /* Set new value */
+ Status = NtSetValueKey(KeyHandle,
+ &PendingOperationsString,
+ 0, REG_MULTI_SZ, BufferBegin,
+ (ULONG_PTR)BufferWrite - (ULONG_PTR)BufferBegin + sizeof(WCHAR));
+
+ NtClose(KeyHandle);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+
+ return Status;
+}
+
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+WINAPI
+BasepNotifyTrackingService(IN PHANDLE ExistingHandle,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN HANDLE NewHandle,
+ IN PUNICODE_STRING NewPath)
+{
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+
+/*
+ * @implemented
+ */
+DWORD
+WINAPI
+BasepMoveFileCopyProgress(IN LARGE_INTEGER TotalFileSize,
+ IN LARGE_INTEGER TotalBytesTransferred,
+ IN LARGE_INTEGER StreamSize,
+ IN LARGE_INTEGER StreamBytesTransferred,
+ IN DWORD dwStreamNumber,
+ IN DWORD dwCallbackReason,
+ IN HANDLE hSourceFile,
+ IN HANDLE hDestinationFile,
+ IN LPVOID lpData OPTIONAL)
+{
+ DWORD Ret = 0;
+ PCOPY_PROGRESS_CONTEXT Context = (PCOPY_PROGRESS_CONTEXT)lpData;
+
+ if (Context->Flags & MOVEFILE_WRITE_THROUGH)
{
- if (flags & MOVEFILE_REPLACE_EXISTING)
- *p++ = '!';
- memcpy( p, dest_name.Buffer, len2 );
- DataSize += len2;
+ if (!dwCallbackReason)
+ {
+ if (StreamBytesTransferred.QuadPart == StreamSize.QuadPart)
+ {
+ FlushFileBuffers(hDestinationFile);
+ }
+ }
}
- else
+
+ if (Context->UserRoutine)
{
- *p = 0;
- DataSize += sizeof(WCHAR);
+ Ret = Context->UserRoutine(TotalFileSize,
+ TotalBytesTransferred,
+ StreamSize,
+ StreamBytesTransferred,
+ dwStreamNumber,
+ dwCallbackReason,
+ hSourceFile,
+ hDestinationFile,
+ Context->UserData);
}
- /* add final null */
- p = (WCHAR *)(Buffer + DataSize);
- *p = 0;
- DataSize += sizeof(WCHAR);
-
- rc = NT_SUCCESS(NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size));
-
- Quit:
- RtlFreeHeap(RtlGetProcessHeap(), 0, source_name.Buffer);
- if (dest_name.Buffer)
- RtlFreeHeap(RtlGetProcessHeap(), 0, dest_name.Buffer);
- NtClose(Reboot);
- if(Buffer)
- HeapFree(GetProcessHeap(), 0, Buffer);
- return(rc);
+ return Ret;
}
*/
BOOL
WINAPI
-MoveFileWithProgressW (
- LPCWSTR lpExistingFileName,
- LPCWSTR lpNewFileName,
- LPPROGRESS_ROUTINE lpProgressRoutine,
- LPVOID lpData,
- DWORD dwFlags
- )
+MoveFileWithProgressW(IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName,
+ IN LPPROGRESS_ROUTINE lpProgressRoutine,
+ IN LPVOID lpData,
+ IN DWORD dwFlags)
{
- HANDLE hFile = NULL, hNewFile = NULL;
- IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ PWSTR NewBuffer;
+ IO_STATUS_BLOCK IoStatusBlock;
+ COPY_PROGRESS_CONTEXT CopyContext;
OBJECT_ATTRIBUTES ObjectAttributes;
- PFILE_RENAME_INFORMATION FileRename;
- NTSTATUS errCode;
- BOOL Result;
- UNICODE_STRING DstPathU;
- BOOL folder = FALSE;
+ PFILE_RENAME_INFORMATION RenameInfo;
+ UNICODE_STRING NewPathU, ExistingPathU;
+ FILE_ATTRIBUTE_TAG_INFORMATION FileAttrTagInfo;
+ HANDLE SourceHandle = INVALID_HANDLE_VALUE, NewHandle, ExistingHandle;
+ BOOL Ret = FALSE, ReplaceIfExists, DelayUntilReboot, AttemptReopenWithoutReparse;
- TRACE("MoveFileWithProgressW()\n");
+ DPRINT("MoveFileWithProgressW(%S, %S, %p, %p, %x)\n", lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags);
- if (dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT)
- return add_boot_rename_entry( lpExistingFileName, lpNewFileName, dwFlags );
+ NewPathU.Buffer = NULL;
+ ExistingPathU.Buffer = NULL;
-// if (dwFlags & MOVEFILE_WRITE_THROUGH)
-// FIXME("MOVEFILE_WRITE_THROUGH unimplemented\n");
+ _SEH2_TRY
+ {
+ /* Don't allow renaming to a disk */
+ if (lpNewFileName && RtlIsDosDeviceName_U(lpNewFileName))
+ {
+ BaseSetLastNTError(STATUS_OBJECT_NAME_COLLISION);
+ _SEH2_LEAVE;
+ }
- if (!lpNewFileName)
- return DeleteFileW(lpExistingFileName);
+ ReplaceIfExists = !!(dwFlags & MOVEFILE_REPLACE_EXISTING);
- /* validate & translate the filename */
- if (!RtlDosPathNameToNtPathName_U (lpNewFileName,
- &DstPathU,
- NULL,
- NULL))
- {
- WARN("Invalid destination path\n");
- SetLastError(ERROR_PATH_NOT_FOUND);
- return FALSE;
- }
+ /* Get file path */
+ if (!RtlDosPathNameToNtPathName_U(lpExistingFileName, &ExistingPathU, NULL, NULL))
+ {
+ BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND);
+ _SEH2_LEAVE;
+ }
- InitializeObjectAttributes(&ObjectAttributes,
- &DstPathU,
- OBJ_CASE_INSENSITIVE,
+ /* Sanitize input */
+ DelayUntilReboot = !!(dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT);
+ if (DelayUntilReboot && (dwFlags & MOVEFILE_CREATE_HARDLINK))
+ {
+ BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+ _SEH2_LEAVE;
+ }
+
+ /* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
+ AttemptReopenWithoutReparse = TRUE;
+ InitializeObjectAttributes(&ObjectAttributes,
+ &ExistingPathU,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ /* Attempt to open source file */
+ Status = NtOpenFile(&SourceHandle,
+ FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN_FOR_BACKUP_INTENT | ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0));
+ if (!NT_SUCCESS(Status))
+ {
+ /* If we failed and the file doesn't exist, don't attempt to reopen without reparse */
+ if (DelayUntilReboot &&
+ (Status == STATUS_SHARING_VIOLATION || Status == STATUS_OBJECT_NAME_NOT_FOUND || Status == STATUS_OBJECT_PATH_NOT_FOUND))
+ {
+ /* Here we don't fail completely, as we postpone the operation to reboot
+ * File might exist afterwards, and we don't need a handle here
+ */
+ SourceHandle = INVALID_HANDLE_VALUE;
+ AttemptReopenWithoutReparse = FALSE;
+ }
+ /* If we failed for any reason than unsupported reparse, fail completely */
+ else if (Status != STATUS_INVALID_PARAMETER)
+ {
+ BaseSetLastNTError(Status);
+ _SEH2_LEAVE;
+ }
+ }
+ else
+ {
+ /* We managed to open, so query information */
+ Status = NtQueryInformationFile(SourceHandle,
+ &IoStatusBlock,
+ &FileAttrTagInfo,
+ sizeof(FILE_ATTRIBUTE_TAG_INFORMATION),
+ FileAttributeTagInformation);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Do not tolerate any other error than something related to not supported operation */
+ if (Status != STATUS_NOT_IMPLEMENTED && Status != STATUS_INVALID_PARAMETER)
+ {
+ BaseSetLastNTError(Status);
+ _SEH2_LEAVE;
+ }
+
+ /* Not a reparse point, no need to reopen, it's fine */
+ AttemptReopenWithoutReparse = FALSE;
+ }
+ /* Validate the reparse point (do we support it?) */
+ else if (FileAttrTagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
+ FileAttrTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ NtClose(SourceHandle);
+ SourceHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ /* Simply reopen if required */
+ if (AttemptReopenWithoutReparse)
+ {
+ Status = NtOpenFile(&SourceHandle,
+ DELETE | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0));
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ _SEH2_LEAVE;
+ }
+ }
+
+ /* Nullify string if we're to use it */
+ if (DelayUntilReboot && !lpNewFileName)
+ {
+ RtlInitUnicodeString(&NewPathU, 0);
+ }
+ /* Check whether path exists */
+ else if (!RtlDosPathNameToNtPathName_U(lpNewFileName, &NewPathU, 0, 0))
+ {
+ BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND);
+ _SEH2_LEAVE;
+ }
+
+ /* Handle postponed renaming */
+ if (DelayUntilReboot)
+ {
+ /* If new file exists and we're allowed to replace, then mark the path with ! */
+ if (ReplaceIfExists && NewPathU.Length)
+ {
+ NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU.Length + sizeof(WCHAR));
+ if (NewBuffer == NULL)
+ {
+ BaseSetLastNTError(STATUS_NO_MEMORY);
+ _SEH2_LEAVE;
+ }
+
+ NewBuffer[0] = L'!';
+ RtlCopyMemory(&NewBuffer[1], NewPathU.Buffer, NewPathU.Length);
+ NewPathU.Length += sizeof(WCHAR);
+ NewPathU.MaximumLength += sizeof(WCHAR);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU.Buffer);
+ NewPathU.Buffer = NewBuffer;
+ }
+
+ /* Check whether 'copy' renaming is allowed if required */
+ if (RtlDetermineDosPathNameType_U(lpExistingFileName) == RtlPathTypeUncAbsolute || dwFlags & MOVEFILE_COPY_ALLOWED)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* First, probe 2nd key to see whether it exists - if so, it will be appended there */
+ Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 2, FALSE);
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+ /* If doesn't exist, append to first key first, creating it if it doesn't exist */
+ Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 1, TRUE);
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES)
+ {
+ /* If it failed because it's too big, then create 2nd key and put it there */
+ Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 2, TRUE);
+ }
+ }
+ }
+
+ /* If we failed at some point, return the error */
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ _SEH2_LEAVE;
+ }
+
+ Ret = TRUE;
+ _SEH2_LEAVE;
+ }
+
+ /* At that point, we MUST have a source handle */
+ ASSERT(SourceHandle != INVALID_HANDLE_VALUE);
+
+ /* Allocate renaming buffer and fill it */
+ RenameInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU.Length + sizeof(FILE_RENAME_INFORMATION));
+ if (RenameInfo == NULL)
+ {
+ BaseSetLastNTError(STATUS_NO_MEMORY);
+ _SEH2_LEAVE;
+ }
+
+ RtlCopyMemory(&RenameInfo->FileName, NewPathU.Buffer, NewPathU.Length);
+ RenameInfo->ReplaceIfExists = ReplaceIfExists;
+ RenameInfo->RootDirectory = 0;
+ RenameInfo->FileNameLength = NewPathU.Length;
+
+ /* Attempt to rename the file */
+ Status = NtSetInformationFile(SourceHandle,
+ &IoStatusBlock,
+ RenameInfo,
+ NewPathU.Length + sizeof(FILE_RENAME_INFORMATION),
+ ((dwFlags & MOVEFILE_CREATE_HARDLINK) ? FileLinkInformation : FileRenameInformation));
+ RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo);
+ if (NT_SUCCESS(Status))
+ {
+ /* If it succeed, all fine, quit */
+ Ret = TRUE;
+ _SEH2_LEAVE;
+ }
+ /* If we failed for any other reason than not the same device, fail
+ * If we failed because of different devices, only allow renaming if user allowed copy
+ */
+ if (Status != STATUS_NOT_SAME_DEVICE || !(dwFlags & MOVEFILE_COPY_ALLOWED))
+ {
+ /* ReactOS hack! To be removed once all FSD have proper renaming support
+ * Just leave status to error and leave
+ */
+ if (Status == STATUS_NOT_IMPLEMENTED)
+ {
+ DPRINT1("Forcing copy, renaming not supported by FSD\n");
+ }
+ else
+ {
+ BaseSetLastNTError(Status);
+ _SEH2_LEAVE;
+ }
+ }
+
+ /* Close source file */
+ NtClose(SourceHandle);
+ SourceHandle = INVALID_HANDLE_VALUE;
+
+ /* Issue the copy of the file */
+ CopyContext.Flags = dwFlags;
+ CopyContext.UserRoutine = lpProgressRoutine;
+ CopyContext.UserData = lpData;
+ NewHandle = INVALID_HANDLE_VALUE;
+ ExistingHandle = INVALID_HANDLE_VALUE;
+
+ Ret = BasepCopyFileExW(lpExistingFileName,
+ lpNewFileName,
+ BasepMoveFileCopyProgress,
+ &CopyContext,
NULL,
- NULL);
+ (ReplaceIfExists == 0) | COPY_FILE_OPEN_SOURCE_FOR_WRITE,
+ 0,
+ &ExistingHandle,
+ &NewHandle);
+ if (!Ret)
+ {
+ /* If it failed, don't leak any handle */
+ if (ExistingHandle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(ExistingHandle);
+ ExistingHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ else if (ExistingHandle != INVALID_HANDLE_VALUE)
+ {
+ if (NewHandle != INVALID_HANDLE_VALUE)
+ {
+ /* If copying succeed, notify */
+ Status = BasepNotifyTrackingService(&ExistingHandle, &ObjectAttributes, NewHandle, &NewPathU);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail in case it had to succeed */
+ if (dwFlags & MOVEFILE_FAIL_IF_NOT_TRACKABLE)
+ {
+ if (NewHandle != INVALID_HANDLE_VALUE)
+ CloseHandle(NewHandle);
+ NewHandle = INVALID_HANDLE_VALUE;
+ DeleteFileW(lpNewFileName);
+ Ret = FALSE;
+ BaseSetLastNTError(Status);
+ }
+ }
+ }
- errCode = NtOpenFile( &hNewFile,
- GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
- &ObjectAttributes,
- &IoStatusBlock,
- 0,
- FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
- ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0) );
+ CloseHandle(ExistingHandle);
+ ExistingHandle = INVALID_HANDLE_VALUE;
+ }
- if (NT_SUCCESS(errCode)) /* Destination exists */
- {
- NtClose(hNewFile);
+ /* In case copy worked, close file */
+ if (NewHandle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(NewHandle);
+ NewHandle = INVALID_HANDLE_VALUE;
+ }
- if (!(dwFlags & MOVEFILE_REPLACE_EXISTING))
+ /* If it succeed, delete source file */
+ if (Ret)
{
- SetLastError(ERROR_ALREADY_EXISTS);
- return FALSE;
- }
- else if (GetFileAttributesW(lpNewFileName) & FILE_ATTRIBUTE_DIRECTORY)
- {
- SetLastError(ERROR_ACCESS_DENIED);
- return FALSE;
- }
+ if (!DeleteFileW(lpExistingFileName))
+ {
+ /* Reset file attributes if required */
+ SetFileAttributesW(lpExistingFileName, FILE_ATTRIBUTE_NORMAL);
+ DeleteFileW(lpExistingFileName);
+ }
+ }
}
+ _SEH2_FINALLY
+ {
+ if (SourceHandle != INVALID_HANDLE_VALUE)
+ NtClose(SourceHandle);
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ExistingPathU.Buffer);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU.Buffer);
+ }
+ _SEH2_END;
- hFile = CreateFileW (lpExistingFileName,
- GENERIC_ALL,
- FILE_SHARE_WRITE|FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS |
- ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_FLAG_WRITE_THROUGH : 0),
- NULL);
-
- if (hFile == INVALID_HANDLE_VALUE)
- {
- return FALSE;
- }
-
- FileRename = RtlAllocateHeap(
- RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length);
- if( !FileRename ) {
- CloseHandle(hFile);
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
- if( dwFlags & MOVEFILE_REPLACE_EXISTING ) {
- FileRename->ReplaceIfExists = TRUE;
- }
- else {
- FileRename->ReplaceIfExists = FALSE;
- }
-
-
- memcpy(FileRename->FileName, DstPathU.Buffer, DstPathU.Length);
- RtlFreeHeap (RtlGetProcessHeap (),
- 0,
- DstPathU.Buffer);
-
- FileRename->FileNameLength = DstPathU.Length;
- errCode = NtSetInformationFile (hFile,
- &IoStatusBlock,
- FileRename,
- sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length,
- FileRenameInformation);
- CloseHandle(hFile);
- RtlFreeHeap(RtlGetProcessHeap(), 0, FileRename);
-
- if (GetFileAttributesW(lpExistingFileName) & FILE_ATTRIBUTE_DIRECTORY)
- {
- folder = TRUE;
- }
-
-
- /*
- * FIXME:
- * Fail now move the folder
- * Before we fail at CreateFileW
- */
-
-
- if (NT_SUCCESS(errCode))
- {
- Result = TRUE;
- }
- else
- {
- if (folder==FALSE)
- {
- Result = CopyFileExW (lpExistingFileName,
- lpNewFileName,
- lpProgressRoutine,
- lpData,
- NULL,
- (dwFlags & MOVEFILE_REPLACE_EXISTING) ? 0 : COPY_FILE_FAIL_IF_EXISTS);
- if (Result)
- {
- /* Cleanup the source file */
- Result = DeleteFileW (lpExistingFileName);
- }
- }
- else
- {
- /* move folder code start */
- WIN32_FIND_DATAW findBuffer;
- LPWSTR lpExistingFileName2 = NULL;
- LPWSTR lpNewFileName2 = NULL;
- LPWSTR lpDeleteFile = NULL;
- INT size;
- INT size2;
- BOOL loop = TRUE;
- BOOL Result = FALSE;
- INT max_size = MAX_PATH;
-
-
- /* Build the string */
- size = wcslen(lpExistingFileName);
- if (size+6> max_size)
- max_size = size + 6;
-
- lpDeleteFile = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
- if (lpDeleteFile == NULL)
- return FALSE;
-
- lpNewFileName2 = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
- if (lpNewFileName2 == NULL)
- {
- HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
- return FALSE;
- }
-
- lpExistingFileName2 = (LPWSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,max_size * sizeof(WCHAR));
- if (lpExistingFileName2 == NULL)
- {
- HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
- HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
- return FALSE;
- }
-
- wcscpy( (WCHAR *)lpExistingFileName2,lpExistingFileName);
- wcscpy( (WCHAR *)&lpExistingFileName2[size],L"\\*.*\0");
-
- /* Get the file name */
- memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
- hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
- if (hFile == INVALID_HANDLE_VALUE)
- loop=FALSE;
-
- if (findBuffer.cFileName[0] == L'\0')
- loop=FALSE;
-
-
- /* FIXME
- * remove readonly flag from source folder and do not set the readonly flag to dest folder
- */
- RemoveReadOnlyAttributeW(lpExistingFileName);
- RemoveReadOnlyAttributeW(lpNewFileName);
- //CreateDirectoryExW(lpExistingFileName,lpNewFileName,NULL);
- CreateDirectoryW(lpNewFileName, NULL);
-
- /* search the files/folders and move them */
- while (loop==TRUE)
- {
- Result = TRUE;
-
- if ((!wcscmp(findBuffer.cFileName,L"..")) || (!wcscmp(findBuffer.cFileName,L".")))
- {
- loop = FindNextFileW(hFile, &findBuffer);
-
- if (!loop)
- {
- size = wcslen(lpExistingFileName2)-4;
- FindClose(hFile);
- hFile = INVALID_HANDLE_VALUE;
-
- wcscpy( &lpExistingFileName2[size],L"\0");
-
- if (wcsncmp(lpExistingFileName,lpExistingFileName2,size))
- {
- DWORD Attributes;
-
- /* delete folder */
- TRACE("MoveFileWithProgressW : Delete folder : %S\n",lpDeleteFile);
-
- /* remove system folder flag other wise we can not delete the folder */
- Attributes = GetFileAttributesW(lpExistingFileName2);
- if (Attributes != INVALID_FILE_ATTRIBUTES)
- {
- SetFileAttributesW(lpExistingFileName2,(Attributes & ~FILE_ATTRIBUTE_SYSTEM));
- }
-
- RemoveReadOnlyAttributeW(lpExistingFileName2);
-
- Result = RemoveDirectoryW(lpExistingFileName2);
- if (Result == FALSE)
- break;
-
- loop=TRUE;
- size = wcslen(lpExistingFileName);
-
- if (size+6>max_size)
- {
- if (lpNewFileName2 != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
-
- if (lpExistingFileName2 != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
-
- if (lpDeleteFile != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
-
- return FALSE;
- }
-
- wcscpy( lpExistingFileName2,lpExistingFileName);
- wcscpy( &lpExistingFileName2[size],L"\\*.*\0");
-
- /* Get the file name */
- memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
- hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
- }
- }
- continue;
- }
-
- if (findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
-
- /* Build the new src string */
- size = wcslen(findBuffer.cFileName);
- size2= wcslen(lpExistingFileName2);
-
- if (size2+size+6>max_size)
- {
- FindClose(hFile);
-
- if (lpNewFileName2 != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
-
- if (lpExistingFileName2 != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
-
- if (lpDeleteFile != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
-
- return FALSE;
- }
-
- wcscpy( &lpExistingFileName2[size2-3],findBuffer.cFileName);
- wcscpy( &lpExistingFileName2[size2+size-3],L"\0");
-
-
- /* Continue */
- wcscpy( lpDeleteFile,lpExistingFileName2);
- wcscpy( &lpExistingFileName2[size2+size-3],L"\\*.*\0");
-
-
- /* Build the new dst string */
- size = wcslen(lpExistingFileName2) + wcslen(lpNewFileName);
- size2 = wcslen(lpExistingFileName);
-
- if (size>max_size)
- {
- FindClose(hFile);
-
- if (lpNewFileName2 != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
-
- if (lpExistingFileName2 != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
-
- if (lpDeleteFile != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
-
- return FALSE;
- }
-
- wcscpy( lpNewFileName2,lpNewFileName);
- size = wcslen(lpNewFileName);
- wcscpy( &lpNewFileName2[size], &lpExistingFileName2[size2]);
- size = wcslen(lpNewFileName2);
- wcscpy( &lpNewFileName2[size-4],L"\0");
-
- /* Create Folder */
-
- /* FIXME
- * remove readonly flag from source folder and do not set the readonly flag to dest folder
- */
- RemoveReadOnlyAttributeW(lpDeleteFile);
- RemoveReadOnlyAttributeW(lpNewFileName2);
-
- CreateDirectoryW(lpNewFileName2,NULL);
- //CreateDirectoryExW(lpDeleteFile, lpNewFileName2,NULL);
-
-
- /* set new search path from src string */
- FindClose(hFile);
- memset(&findBuffer,0,sizeof(WIN32_FIND_DATAW));
- hFile = FindFirstFileW(lpExistingFileName2, &findBuffer);
- }
- else
- {
-
- /* Build the new string */
- size = wcslen(findBuffer.cFileName);
- size2= wcslen(lpExistingFileName2);
- wcscpy( lpDeleteFile,lpExistingFileName2);
- wcscpy( &lpDeleteFile[size2-3],findBuffer.cFileName);
-
- /* Build dest string */
- size = wcslen(lpDeleteFile) + wcslen(lpNewFileName);
- size2 = wcslen(lpExistingFileName);
-
- if (size>max_size)
- {
- FindClose(hFile);
-
- if (lpNewFileName2 != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
-
- if (lpExistingFileName2 != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
-
- if (lpDeleteFile != NULL)
- HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
-
- return FALSE;
- }
-
- wcscpy( lpNewFileName2,lpNewFileName);
- size = wcslen(lpNewFileName);
- wcscpy(&lpNewFileName2[size],&lpDeleteFile[size2]);
-
-
- /* overrite existsen file, if the file got the flag have readonly
- * we need reomve that flag
- */
-
- /* copy file */
-
- TRACE("MoveFileWithProgressW : Copy file : %S to %S\n",lpDeleteFile, lpNewFileName2);
- RemoveReadOnlyAttributeW(lpDeleteFile);
- RemoveReadOnlyAttributeW(lpNewFileName2);
-
- Result = CopyFileExW (lpDeleteFile,
- lpNewFileName2,
- lpProgressRoutine,
- lpData,
- NULL,
- 0);
-
- if (Result == FALSE)
- break;
-
- /* delete file */
- TRACE("MoveFileWithProgressW : remove readonly flag from file : %S\n",lpNewFileName2);
- Result = RemoveReadOnlyAttributeW(lpDeleteFile);
- if (Result == FALSE)
- break;
-
- TRACE("MoveFileWithProgressW : Delete file : %S\n",lpDeleteFile);
- Result = DeleteFileW(lpDeleteFile);
- if (Result == FALSE)
- break;
-
- }
- loop = FindNextFileW(hFile, &findBuffer);
- }
-
-
- /* Remove last folder */
- if ((loop == FALSE) && (Result != FALSE))
- {
- DWORD Attributes;
-
- Attributes = GetFileAttributesW(lpDeleteFile);
- if (Attributes != INVALID_FILE_ATTRIBUTES)
- {
- SetFileAttributesW(lpDeleteFile,(Attributes & ~FILE_ATTRIBUTE_SYSTEM));
- }
-
- Result = RemoveDirectoryW(lpExistingFileName);
- }
-
- /* Cleanup */
- FindClose(hFile);
-
- if (lpNewFileName2 != NULL)
- {
- HeapFree(GetProcessHeap(),0,(VOID *) lpNewFileName2);
- lpNewFileName2 = NULL;
- }
-
- if (lpExistingFileName2 != NULL)
- {
- HeapFree(GetProcessHeap(),0,(VOID *) lpExistingFileName2);
- lpExistingFileName2 = NULL;
- }
-
- if (lpDeleteFile != NULL)
- {
- HeapFree(GetProcessHeap(),0,(VOID *) lpDeleteFile);
- lpDeleteFile = NULL;
- }
-
- return Result;
-
- // end move folder code
- }
- }
-
-
- return Result;
+ return Ret;
}
*/
BOOL
WINAPI
-MoveFileWithProgressA (
- LPCSTR lpExistingFileName,
- LPCSTR lpNewFileName,
- LPPROGRESS_ROUTINE lpProgressRoutine,
- LPVOID lpData,
- DWORD dwFlags
- )
+MoveFileWithProgressA(IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName OPTIONAL,
+ IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
+ IN LPVOID lpData OPTIONAL,
+ IN DWORD dwFlags)
{
- PWCHAR ExistingFileNameW;
- PWCHAR NewFileNameW;
- BOOL ret;
+ BOOL Ret;
+ UNICODE_STRING ExistingFileNameW, NewFileNameW;
- if (!(ExistingFileNameW = FilenameA2W(lpExistingFileName, FALSE)))
- return FALSE;
+ if (!Basep8BitStringToDynamicUnicodeString(&ExistingFileNameW, lpExistingFileName))
+ {
+ return FALSE;
+ }
- if (!(NewFileNameW= FilenameA2W(lpNewFileName, TRUE)))
- return FALSE;
+ if (lpNewFileName)
+ {
+ if (!Basep8BitStringToDynamicUnicodeString(&NewFileNameW, lpNewFileName))
+ {
+ RtlFreeUnicodeString(&ExistingFileNameW);
+ return FALSE;
+ }
+ }
+ else
+ {
+ NewFileNameW.Buffer = NULL;
+ }
- ret = MoveFileWithProgressW (ExistingFileNameW ,
- NewFileNameW,
- lpProgressRoutine,
- lpData,
- dwFlags);
+ Ret = MoveFileWithProgressW(ExistingFileNameW.Buffer, NewFileNameW.Buffer, lpProgressRoutine, lpData, dwFlags);
- RtlFreeHeap (RtlGetProcessHeap (), 0, NewFileNameW);
+ RtlFreeUnicodeString(&ExistingFileNameW);
+ RtlFreeUnicodeString(&NewFileNameW);
- return ret;
+ return Ret;
}
*/
BOOL
WINAPI
-MoveFileW (
- LPCWSTR lpExistingFileName,
- LPCWSTR lpNewFileName
- )
+MoveFileW(IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName)
{
- return MoveFileExW (lpExistingFileName,
- lpNewFileName,
- MOVEFILE_COPY_ALLOWED);
+ return MoveFileWithProgressW(lpExistingFileName,
+ lpNewFileName,
+ NULL,
+ NULL,
+ MOVEFILE_COPY_ALLOWED);
}
*/
BOOL
WINAPI
-MoveFileExW (
- LPCWSTR lpExistingFileName,
- LPCWSTR lpNewFileName,
- DWORD dwFlags
- )
+MoveFileExW(IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName OPTIONAL,
+ IN DWORD dwFlags)
{
- return MoveFileWithProgressW (lpExistingFileName,
- lpNewFileName,
- NULL,
- NULL,
- dwFlags);
+ return MoveFileWithProgressW(lpExistingFileName,
+ lpNewFileName,
+ NULL,
+ NULL,
+ dwFlags);
}
*/
BOOL
WINAPI
-MoveFileA (
- LPCSTR lpExistingFileName,
- LPCSTR lpNewFileName
- )
+MoveFileA(IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName)
{
- return MoveFileExA (lpExistingFileName,
- lpNewFileName,
- MOVEFILE_COPY_ALLOWED);
+ return MoveFileWithProgressA(lpExistingFileName,
+ lpNewFileName,
+ NULL,
+ NULL,
+ MOVEFILE_COPY_ALLOWED);
}
*/
BOOL
WINAPI
-MoveFileExA (
- LPCSTR lpExistingFileName,
- LPCSTR lpNewFileName,
- DWORD dwFlags
- )
+MoveFileExA(IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName OPTIONAL,
+ IN DWORD dwFlags)
{
- return MoveFileWithProgressA (lpExistingFileName,
- lpNewFileName,
- NULL,
- NULL,
- dwFlags);
+ return MoveFileWithProgressA(lpExistingFileName,
+ lpNewFileName,
+ NULL,
+ NULL,
+ dwFlags);
}
/*
*/
BOOL
WINAPI
-ReplaceFileA(
- LPCSTR lpReplacedFileName,
- LPCSTR lpReplacementFileName,
- LPCSTR lpBackupFileName,
- DWORD dwReplaceFlags,
- LPVOID lpExclude,
- LPVOID lpReserved
- )
+ReplaceFileA(IN LPCSTR lpReplacedFileName,
+ IN LPCSTR lpReplacementFileName,
+ IN LPCSTR lpBackupFileName OPTIONAL,
+ IN DWORD dwReplaceFlags,
+ IN LPVOID lpExclude,
+ IN LPVOID lpReserved)
{
- WCHAR *replacedW, *replacementW, *backupW = NULL;
- BOOL ret;
+ BOOL Ret;
+ UNICODE_STRING ReplacedFileNameW, ReplacementFileNameW, BackupFileNameW;
- /* This function only makes sense when the first two parameters are defined */
- if (!lpReplacedFileName || !(replacedW = FilenameA2W(lpReplacedFileName, TRUE)))
+ if (!lpReplacedFileName || !lpReplacementFileName || lpExclude || lpReserved || dwReplaceFlags & ~(REPLACEFILE_WRITE_THROUGH | REPLACEFILE_IGNORE_MERGE_ERRORS))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- if (!lpReplacementFileName || !(replacementW = FilenameA2W(lpReplacementFileName, TRUE)))
+ if (!Basep8BitStringToDynamicUnicodeString(&ReplacedFileNameW, lpReplacedFileName))
{
- HeapFree(GetProcessHeap(), 0, replacedW);
- SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- /* The backup parameter, however, is optional */
+ if (!Basep8BitStringToDynamicUnicodeString(&ReplacementFileNameW, lpReplacementFileName))
+ {
+ RtlFreeUnicodeString(&ReplacedFileNameW);
+ return FALSE;
+ }
+
if (lpBackupFileName)
{
- if (!(backupW = FilenameA2W(lpBackupFileName, TRUE)))
+ if (!Basep8BitStringToDynamicUnicodeString(&BackupFileNameW, lpBackupFileName))
{
- HeapFree(GetProcessHeap(), 0, replacedW);
- HeapFree(GetProcessHeap(), 0, replacementW);
- SetLastError(ERROR_INVALID_PARAMETER);
+ RtlFreeUnicodeString(&ReplacementFileNameW);
+ RtlFreeUnicodeString(&ReplacedFileNameW);
return FALSE;
}
}
+ else
+ {
+ BackupFileNameW.Buffer = NULL;
+ }
- ret = ReplaceFileW(replacedW, replacementW, backupW, dwReplaceFlags, lpExclude, lpReserved);
- HeapFree(GetProcessHeap(), 0, replacedW);
- HeapFree(GetProcessHeap(), 0, replacementW);
- HeapFree(GetProcessHeap(), 0, backupW);
+ Ret = ReplaceFileW(ReplacedFileNameW.Buffer, ReplacementFileNameW.Buffer, BackupFileNameW.Buffer, dwReplaceFlags, 0, 0);
- return ret;
+ if (lpBackupFileName)
+ {
+ RtlFreeUnicodeString(&BackupFileNameW);
+ }
+ RtlFreeUnicodeString(&ReplacementFileNameW);
+ RtlFreeUnicodeString(&ReplacedFileNameW);
+
+ return Ret;
}
/*