* FILE: lib/kernel32/file/file.c
* PURPOSE: Directory functions
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
- * GetTempFileName is modified from WINE [ Alexandre Juiliard ]
+ * Pierre Schweitzer (pierre.schweitzer@reactos.org)
* UPDATE HISTORY:
* Created 01/11/98
*/
/* INCLUDES *****************************************************************/
#include <k32.h>
-#include <wine/debug.h>
-
-WINE_DEFAULT_DEBUG_CHANNEL(kernel32file);
+#define NDEBUG
+#include <debug.h>
+DEBUG_CHANNEL(kernel32file);
/* GLOBALS ******************************************************************/
{
DWORD ret;
+ /* destLen should never exceed MAX_PATH */
+ if (destLen > MAX_PATH) destLen = MAX_PATH;
+
ret = bIsFileApiAnsi? RtlUnicodeStringToAnsiSize(SourceU) : RtlUnicodeStringToOemSize(SourceU);
/* ret incl. nullchar */
if (lpReOpenBuff == NULL)
{
- return FALSE;
+ return HFILE_ERROR;
}
+ lpReOpenBuff->nErrCode = 0;
+
+ if (uStyle & OF_REOPEN) lpFileName = lpReOpenBuff->szPathName;
+
+ if (!lpFileName)
+ {
+ return HFILE_ERROR;
+ }
+
+ if (!GetFullPathNameA(lpFileName,
+ sizeof(lpReOpenBuff->szPathName),
+ lpReOpenBuff->szPathName,
+ NULL))
+ {
+ lpReOpenBuff->nErrCode = GetLastError();
+ return HFILE_ERROR;
+ }
+
+ if (uStyle & OF_PARSE)
+ {
+ lpReOpenBuff->fFixedDisk = (GetDriveTypeA(lpReOpenBuff->szPathName) != DRIVE_REMOVABLE);
+ TRACE("(%s): OF_PARSE, res = '%s'\n", lpFileName, lpReOpenBuff->szPathName);
+ return 0;
+ }
+
+ if ((uStyle & OF_EXIST) && !(uStyle & OF_CREATE))
+ {
+ DWORD dwAttributes = GetFileAttributesA(lpReOpenBuff->szPathName);
+
+ switch (dwAttributes)
+ {
+ case 0xFFFFFFFF: /* File does not exist */
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ lpReOpenBuff->nErrCode = (WORD) ERROR_FILE_NOT_FOUND;
+ return -1;
+
+ case FILE_ATTRIBUTE_DIRECTORY:
+ SetLastError(ERROR_ACCESS_DENIED);
+ lpReOpenBuff->nErrCode = (WORD) ERROR_ACCESS_DENIED;
+ return -1;
+
+ default:
+ lpReOpenBuff->cBytes = sizeof(OFSTRUCT);
+ return 1;
+ }
+ }
+ lpReOpenBuff->cBytes = sizeof(OFSTRUCT);
if ((uStyle & OF_CREATE) == OF_CREATE)
{
DWORD Sharing;
if (Len == 0 || Len > OFS_MAXPATHNAME)
{
+ lpReOpenBuff->nErrCode = GetLastError();
return (HFILE)INVALID_HANDLE_VALUE;
}
+ if (uStyle & OF_DELETE)
+ {
+ if (!DeleteFileW(PathNameW))
+ {
+ lpReOpenBuff->nErrCode = GetLastError();
+ return HFILE_ERROR;
+ }
+ TRACE("(%s): OF_DELETE return = OK\n", lpFileName);
+ return TRUE;
+ }
+
FileName.Buffer = lpReOpenBuff->szPathName;
FileName.Length = 0;
FileName.MaximumLength = OFS_MAXPATHNAME;
// FILE_SHARE_READ
// FILE_NO_INTERMEDIATE_BUFFERING
- if ((uStyle & OF_PARSE) == OF_PARSE)
- {
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- FileNameString.Buffer);
- return (HFILE)NULL;
- }
-
ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
ObjectAttributes.RootDirectory = NULL;
ObjectAttributes.ObjectName = &FileNameString;
FILE_SHARE_READ,
FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT);
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- FileNameString.Buffer);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameString.Buffer);
- lpReOpenBuff->nErrCode = (WORD)RtlNtStatusToDosError(errCode);
+ lpReOpenBuff->nErrCode = RtlNtStatusToDosError(errCode);
if (!NT_SUCCESS(errCode))
{
return (HFILE)INVALID_HANDLE_VALUE;
}
+ if (uStyle & OF_EXIST)
+ {
+ NtClose(FileHandle);
+ return (HFILE)1;
+ }
+
return (HFILE)FileHandle;
}
* @implemented
*/
BOOL WINAPI
-FlushFileBuffers(HANDLE hFile)
+FlushFileBuffers(IN HANDLE hFile)
{
- NTSTATUS errCode;
- IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
- hFile = TranslateStdHandle(hFile);
+ hFile = TranslateStdHandle(hFile);
- if (IsConsoleHandle(hFile))
- {
- return FALSE;
- }
+ if (IsConsoleHandle(hFile))
+ {
+ return FlushConsoleInputBuffer(hFile);
+ }
- errCode = NtFlushBuffersFile(hFile,
- &IoStatusBlock);
- if (!NT_SUCCESS(errCode))
- {
- SetLastErrorByStatus(errCode);
- return(FALSE);
- }
- return(TRUE);
+ Status = NtFlushBuffersFile(hFile,
+ &IoStatusBlock);
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return FALSE;
+ }
+ return TRUE;
}
*lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart;
}
- if (FilePosition.CurrentByteOffset.u.LowPart == -1)
+ if (FilePosition.CurrentByteOffset.u.LowPart == MAXDWORD)
{
/* The value of -1 is valid here, especially when the new
file position is greater than 4 GB. Since NtSetInformationFile
{
WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
PWSTR FileNameW;
- BOOL ret;
+ BOOL ret;
- if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
+ if (!lpFileName || !(FileNameW = FilenameA2W(lpFileName, FALSE)))
return INVALID_FILE_ATTRIBUTES;
ret = GetFileAttributesExW(FileNameW, GetFileExInfoStandard, &FileAttributeData);
/***********************************************************************
* GetTempFileNameA (KERNEL32.@)
*/
-UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique, LPSTR buffer)
+UINT WINAPI
+GetTempFileNameA(IN LPCSTR lpPathName,
+ IN LPCSTR lpPrefixString,
+ IN UINT uUnique,
+ OUT LPSTR lpTempFileName)
{
- WCHAR BufferW[MAX_PATH];
- PWCHAR PathW;
- WCHAR PrefixW[3+1];
- UINT ret;
-
- if (!(PathW = FilenameA2W(path, FALSE)))
- return 0;
-
- if (prefix)
- FilenameA2W_N(PrefixW, 3+1, prefix, -1);
+ UINT ID;
+ NTSTATUS Status;
+ LPWSTR lpTempFileNameW;
+ PUNICODE_STRING lpPathNameW;
+ ANSI_STRING TempFileNameStringA;
+ UNICODE_STRING lpPrefixStringW, TempFileNameStringW;
+
+ /* Convert strings */
+ lpPathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
+ if (!lpPathNameW)
+ {
+ return 0;
+ }
- ret = GetTempFileNameW(PathW, prefix ? PrefixW : NULL, unique, BufferW);
+ if (!Basep8BitStringToDynamicUnicodeString(&lpPrefixStringW, lpPrefixString))
+ {
+ return 0;
+ }
- if (ret)
- FilenameW2A_N(buffer, MAX_PATH, BufferW, -1);
+ lpTempFileNameW = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
+ if (!lpTempFileNameW)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ RtlFreeUnicodeString(&lpPrefixStringW);
+ return 0;
+ }
- return ret;
-}
+ /* Call Unicode */
+ ID = GetTempFileNameW(lpPathNameW->Buffer, lpPrefixStringW.Buffer, uUnique, lpTempFileNameW);
+ if (ID)
+ {
+ RtlInitUnicodeString(&TempFileNameStringW, lpTempFileNameW);
+ TempFileNameStringA.Buffer = lpTempFileName;
+ TempFileNameStringA.MaximumLength = MAX_PATH;
+
+ Status = BasepUnicodeStringTo8BitString(&TempFileNameStringA, &TempFileNameStringW, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ ID = 0;
+ }
+ }
-/***********************************************************************
- * GetTempFileNameW (KERNEL32.@)
- */
-UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, LPWSTR buffer )
+ /* Cleanup */
+ RtlFreeUnicodeString(&lpPrefixStringW);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, lpTempFileNameW);
+ return ID;
+ }
+
+ /***********************************************************************
+ * GetTempFileNameW (KERNEL32.@)
+ */
+UINT WINAPI
+GetTempFileNameW(IN LPCWSTR lpPathName,
+ IN LPCWSTR lpPrefixString,
+ IN UINT uUnique,
+ OUT LPWSTR lpTempFileName)
{
- static const WCHAR formatW[] = L"%x.tmp";
-
- int i;
- LPWSTR p;
+ CHAR * Let;
+ HANDLE TempFile;
+ UINT ID, Num = 0;
+ CHAR IDString[5];
+ WCHAR * TempFileName;
+ CSR_API_MESSAGE ApiMessage;
+ DWORD FileAttributes, LastError;
+ UNICODE_STRING PathNameString, PrefixString;
+ static const WCHAR Ext[] = { L'.', 't', 'm', 'p', UNICODE_NULL };
+
+ RtlInitUnicodeString(&PathNameString, lpPathName);
+ if (PathNameString.Length == 0 || PathNameString.Buffer[(PathNameString.Length / sizeof(WCHAR)) - 1] != L'\\')
+ {
+ PathNameString.Length += sizeof(WCHAR);
+ }
- if ( !path || !buffer )
+ /* lpTempFileName must be able to contain: PathName, Prefix (3), number(4), .tmp(4) & \0(1)
+ * See: http://msdn.microsoft.com/en-us/library/aa364991%28v=vs.85%29.aspx
+ */
+ if (PathNameString.Length > (MAX_PATH - 3 - 4 - 4 - 1) * sizeof(WCHAR))
{
- SetLastError( ERROR_INVALID_PARAMETER );
+ SetLastError(ERROR_BUFFER_OVERFLOW);
return 0;
}
-
- wcscpy( buffer, path );
- p = buffer + wcslen(buffer);
-
- /* add a \, if there isn't one */
- if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
-
- if ( prefix )
- for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
-
- unique &= 0xffff;
-
- if (unique) swprintf( p, formatW, unique );
- else
+
+ /* If PathName and TempFileName aren't the same buffer, move PathName to TempFileName */
+ if (lpPathName != lpTempFileName)
{
- /* get a "random" unique number and try to create the file */
- HANDLE handle;
- UINT num = GetTickCount() & 0xffff;
+ memmove(lpTempFileName, PathNameString.Buffer, PathNameString.Length);
+ }
- if (!num) num = 1;
- unique = num;
+ /* PathName MUST BE a path. Check it */
+ lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = UNICODE_NULL;
+ FileAttributes = GetFileAttributesW(lpTempFileName);
+ if (FileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ /* Append a '\' if necessary */
+ lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
+ lpTempFileName[PathNameString.Length / sizeof(WCHAR)] = UNICODE_NULL;
+ FileAttributes = GetFileAttributesW(lpTempFileName);
+ if (FileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ SetLastError(ERROR_DIRECTORY);
+ return 0;
+ }
+ }
+ if (!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ SetLastError(ERROR_DIRECTORY);
+ return 0;
+ }
+
+ /* Make sure not to mix path & prefix */
+ lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
+ RtlInitUnicodeString(&PrefixString, lpPrefixString);
+ if (PrefixString.Length > 3 * sizeof(WCHAR))
+ {
+ PrefixString.Length = 3 * sizeof(WCHAR);
+ }
+
+ /* Append prefix to path */
+ TempFileName = lpTempFileName + PathNameString.Length / sizeof(WCHAR);
+ memmove(TempFileName, PrefixString.Buffer, PrefixString.Length);
+ TempFileName += PrefixString.Length / sizeof(WCHAR);
+
+ /* Then, generate filename */
+ do
+ {
+ /* If user didn't gave any ID, ask Csrss to give one */
+ if (!uUnique)
+ {
+ CsrClientCallServer(&ApiMessage, NULL, MAKE_CSR_API(GET_TEMP_FILE, CSR_NATIVE), sizeof(CSR_API_MESSAGE));
+ if (ApiMessage.Data.GetTempFile.UniqueID == 0)
+ {
+ Num++;
+ continue;
+ }
+
+ ID = ApiMessage.Data.GetTempFile.UniqueID;
+ }
+ else
+ {
+ ID = uUnique;
+ }
+
+ /* Convert that ID to wchar */
+ RtlIntegerToChar(ID, 0x10, sizeof(IDString), IDString);
+ Let = IDString;
do
{
- swprintf( p, formatW, unique );
- handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
- if (handle != INVALID_HANDLE_VALUE)
- { /* We created it */
- TRACE("created %S\n", buffer);
- CloseHandle( handle );
- break;
+ *(TempFileName++) = RtlAnsiCharToUnicodeChar(&Let);
+ } while (*Let != 0);
+
+ /* Append extension & UNICODE_NULL */
+ memmove(TempFileName, Ext, sizeof(Ext) + sizeof(WCHAR));
+
+ /* If user provided its ID, just return */
+ if (uUnique)
+ {
+ return uUnique;
+ }
+
+ /* Then, try to create file */
+ if (!RtlIsDosDeviceName_U(lpTempFileName))
+ {
+ TempFile = CreateFileW(lpTempFileName,
+ GENERIC_READ,
+ 0,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ 0);
+ if (TempFile != INVALID_HANDLE_VALUE)
+ {
+ NtClose(TempFile);
+ DPRINT("Temp file: %S\n", lpTempFileName);
+ return ID;
}
- if (GetLastError() != ERROR_FILE_EXISTS &&
- GetLastError() != ERROR_SHARING_VIOLATION)
- break; /* No need to go on */
- if (!(++unique & 0xffff)) unique = 1;
- } while (unique != num);
- }
- TRACE("returning %S\n", buffer);
- return unique;
+ LastError = GetLastError();
+ /* There is no need to recover from those errors, they would hit next step */
+ if (LastError == ERROR_INVALID_PARAMETER || LastError == ERROR_CANNOT_MAKE ||
+ LastError == ERROR_WRITE_PROTECT || LastError == ERROR_NETWORK_ACCESS_DENIED ||
+ LastError == ERROR_DISK_FULL || LastError == ERROR_INVALID_NAME ||
+ LastError == ERROR_BAD_PATHNAME || LastError == ERROR_NO_INHERITANCE ||
+ LastError == ERROR_DISK_CORRUPT ||
+ (LastError == ERROR_ACCESS_DENIED && NtCurrentTeb()->LastStatusValue != STATUS_FILE_IS_A_DIRECTORY))
+ {
+ break;
+ }
+ }
+ Num++;
+ } while (Num & 0xFFFF);
+
+ return 0;
}
* @implemented
*/
BOOL WINAPI
-GetFileTime(HANDLE hFile,
- LPFILETIME lpCreationTime,
- LPFILETIME lpLastAccessTime,
- LPFILETIME lpLastWriteTime)
+GetFileTime(IN HANDLE hFile,
+ OUT LPFILETIME lpCreationTime OPTIONAL,
+ OUT LPFILETIME lpLastAccessTime OPTIONAL,
+ OUT LPFILETIME lpLastWriteTime OPTIONAL)
{
- IO_STATUS_BLOCK IoStatusBlock;
- FILE_BASIC_INFORMATION FileBasic;
- NTSTATUS Status;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_BASIC_INFORMATION FileBasic;
- if(IsConsoleHandle(hFile))
- {
- SetLastError(ERROR_INVALID_HANDLE);
- return FALSE;
- }
+ if(IsConsoleHandle(hFile))
+ {
+ BaseSetLastNTError(STATUS_INVALID_HANDLE);
+ return FALSE;
+ }
- Status = NtQueryInformationFile(hFile,
- &IoStatusBlock,
- &FileBasic,
- sizeof(FILE_BASIC_INFORMATION),
- FileBasicInformation);
- if (!NT_SUCCESS(Status))
- {
- SetLastErrorByStatus(Status);
- return FALSE;
- }
+ Status = NtQueryInformationFile(hFile,
+ &IoStatusBlock,
+ &FileBasic,
+ sizeof(FILE_BASIC_INFORMATION),
+ FileBasicInformation);
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return FALSE;
+ }
- if (lpCreationTime)
- memcpy(lpCreationTime, &FileBasic.CreationTime, sizeof(FILETIME));
- if (lpLastAccessTime)
- memcpy(lpLastAccessTime, &FileBasic.LastAccessTime, sizeof(FILETIME));
- if (lpLastWriteTime)
- memcpy(lpLastWriteTime, &FileBasic.LastWriteTime, sizeof(FILETIME));
+ if (lpCreationTime)
+ {
+ lpCreationTime->dwLowDateTime = FileBasic.CreationTime.LowPart;
+ lpCreationTime->dwHighDateTime = FileBasic.CreationTime.HighPart;
+ }
- return TRUE;
+ if (lpLastAccessTime)
+ {
+ lpLastAccessTime->dwLowDateTime = FileBasic.LastAccessTime.LowPart;
+ lpLastAccessTime->dwHighDateTime = FileBasic.LastAccessTime.HighPart;
+ }
+
+ if (lpLastWriteTime)
+ {
+ lpLastWriteTime->dwLowDateTime = FileBasic.LastWriteTime.LowPart;
+ lpLastWriteTime->dwHighDateTime = FileBasic.LastWriteTime.HighPart;
+ }
+
+ return TRUE;
}
* @implemented
*/
BOOL WINAPI
-SetFileTime(HANDLE hFile,
- CONST FILETIME *lpCreationTime,
- CONST FILETIME *lpLastAccessTime,
- CONST FILETIME *lpLastWriteTime)
+SetFileTime(IN HANDLE hFile,
+ CONST FILETIME *lpCreationTime OPTIONAL,
+ CONST FILETIME *lpLastAccessTime OPTIONAL,
+ CONST FILETIME *lpLastWriteTime OPTIONAL)
{
- FILE_BASIC_INFORMATION FileBasic;
- IO_STATUS_BLOCK IoStatusBlock;
- NTSTATUS Status;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_BASIC_INFORMATION FileBasic;
- if(IsConsoleHandle(hFile))
- {
- SetLastError(ERROR_INVALID_HANDLE);
- return FALSE;
- }
+ if(IsConsoleHandle(hFile))
+ {
+ BaseSetLastNTError(STATUS_INVALID_HANDLE);
+ return FALSE;
+ }
- Status = NtQueryInformationFile(hFile,
- &IoStatusBlock,
- &FileBasic,
- sizeof(FILE_BASIC_INFORMATION),
- FileBasicInformation);
- if (!NT_SUCCESS(Status))
- {
- SetLastErrorByStatus(Status);
- return FALSE;
- }
+ memset(&FileBasic, 0, sizeof(FILE_BASIC_INFORMATION));
- if (lpCreationTime)
- memcpy(&FileBasic.CreationTime, lpCreationTime, sizeof(FILETIME));
- if (lpLastAccessTime)
- memcpy(&FileBasic.LastAccessTime, lpLastAccessTime, sizeof(FILETIME));
- if (lpLastWriteTime)
- memcpy(&FileBasic.LastWriteTime, lpLastWriteTime, sizeof(FILETIME));
-
- // should i initialize changetime ???
-
- Status = NtSetInformationFile(hFile,
- &IoStatusBlock,
- &FileBasic,
- sizeof(FILE_BASIC_INFORMATION),
- FileBasicInformation);
- if (!NT_SUCCESS(Status))
- {
- SetLastErrorByStatus(Status);
- return FALSE;
- }
+ if (lpCreationTime)
+ {
+ FileBasic.CreationTime.LowPart = lpCreationTime->dwLowDateTime;
+ FileBasic.CreationTime.HighPart = lpCreationTime->dwHighDateTime;
+ }
- return TRUE;
+ if (lpLastAccessTime)
+ {
+ FileBasic.LastAccessTime.LowPart = lpLastAccessTime->dwLowDateTime;
+ FileBasic.LastAccessTime.HighPart = lpLastAccessTime->dwHighDateTime;
+ }
+
+ if (lpLastWriteTime)
+ {
+ FileBasic.LastWriteTime.LowPart = lpLastWriteTime->dwLowDateTime;
+ FileBasic.LastWriteTime.HighPart = lpLastWriteTime->dwHighDateTime;
+ }
+
+ Status = NtSetInformationFile(hFile,
+ &IoStatusBlock,
+ &FileBasic,
+ sizeof(FILE_BASIC_INFORMATION),
+ FileBasicInformation);
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return FALSE;
+ }
+
+ return TRUE;
}
return INVALID_HANDLE_VALUE;
}
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ReplaceFileA(
+ LPCSTR lpReplacedFileName,
+ LPCSTR lpReplacementFileName,
+ LPCSTR lpBackupFileName,
+ DWORD dwReplaceFlags,
+ LPVOID lpExclude,
+ LPVOID lpReserved
+ )
+{
+ WCHAR *replacedW, *replacementW, *backupW = NULL;
+ BOOL ret;
+
+ /* This function only makes sense when the first two parameters are defined */
+ if (!lpReplacedFileName || !(replacedW = FilenameA2W(lpReplacedFileName, TRUE)))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (!lpReplacementFileName || !(replacementW = FilenameA2W(lpReplacementFileName, TRUE)))
+ {
+ HeapFree(GetProcessHeap(), 0, replacedW);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ /* The backup parameter, however, is optional */
+ if (lpBackupFileName)
+ {
+ if (!(backupW = FilenameA2W(lpBackupFileName, TRUE)))
+ {
+ HeapFree(GetProcessHeap(), 0, replacedW);
+ HeapFree(GetProcessHeap(), 0, replacementW);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ }
+
+ ret = ReplaceFileW(replacedW, replacementW, backupW, dwReplaceFlags, lpExclude, lpReserved);
+ HeapFree(GetProcessHeap(), 0, replacedW);
+ HeapFree(GetProcessHeap(), 0, replacementW);
+ HeapFree(GetProcessHeap(), 0, backupW);
+
+ return ret;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+ReplaceFileW(
+ LPCWSTR lpReplacedFileName,
+ LPCWSTR lpReplacementFileName,
+ LPCWSTR lpBackupFileName,
+ DWORD dwReplaceFlags,
+ LPVOID lpExclude,
+ LPVOID lpReserved
+ )
+{
+ HANDLE hReplaced = NULL, hReplacement = NULL;
+ UNICODE_STRING NtReplacedName = { 0, 0, NULL };
+ UNICODE_STRING NtReplacementName = { 0, 0, NULL };
+ DWORD Error = ERROR_SUCCESS;
+ NTSTATUS Status;
+ BOOL Ret = FALSE;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PVOID Buffer = NULL ;
+
+ if (dwReplaceFlags)
+ FIXME("Ignoring flags %x\n", dwReplaceFlags);
+
+ /* First two arguments are mandatory */
+ if (!lpReplacedFileName || !lpReplacementFileName)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ /* Back it up */
+ if(lpBackupFileName)
+ {
+ if(!CopyFileW(lpReplacedFileName, lpBackupFileName, FALSE))
+ {
+ Error = GetLastError();
+ goto Cleanup ;
+ }
+ }
+
+ /* Open the "replaced" file for reading and writing */
+ if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &NtReplacedName, NULL, NULL)))
+ {
+ Error = ERROR_PATH_NOT_FOUND;
+ goto Cleanup;
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &NtReplacedName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&hReplaced,
+ GENERIC_READ | GENERIC_WRITE | DELETE | SYNCHRONIZE | WRITE_DAC,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+ Error = ERROR_FILE_NOT_FOUND;
+ else
+ Error = ERROR_UNABLE_TO_REMOVE_REPLACED;
+ goto Cleanup;
+ }
+
+ /* Blank it */
+ SetEndOfFile(hReplaced) ;
+
+ /*
+ * Open the replacement file for reading, writing, and deleting
+ * (deleting is needed when finished)
+ */
+ if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &NtReplacementName, NULL, NULL)))
+ {
+ Error = ERROR_PATH_NOT_FOUND;
+ goto Cleanup;
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &NtReplacementName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&hReplacement,
+ GENERIC_READ | DELETE | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ 0,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ Error = RtlNtStatusToDosError(Status);
+ goto Cleanup;
+ }
+
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x10000) ;
+ if (!Buffer)
+ {
+ Error = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup ;
+ }
+ while (Status != STATUS_END_OF_FILE)
+ {
+ Status = NtReadFile(hReplacement, NULL, NULL, NULL, &IoStatusBlock, Buffer, 0x10000, NULL, NULL) ;
+ if (NT_SUCCESS(Status))
+ {
+ Status = NtWriteFile(hReplaced, NULL, NULL, NULL, &IoStatusBlock, Buffer,
+ IoStatusBlock.Information, NULL, NULL) ;
+ if (!NT_SUCCESS(Status))
+ {
+ Error = RtlNtStatusToDosError(Status);
+ goto Cleanup;
+ }
+ }
+ else if (Status != STATUS_END_OF_FILE)
+ {
+ Error = RtlNtStatusToDosError(Status);
+ goto Cleanup;
+ }
+ }
+
+ Ret = TRUE;
+
+ /* Perform resource cleanup */
+Cleanup:
+ if (hReplaced) NtClose(hReplaced);
+ if (hReplacement) NtClose(hReplacement);
+ if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+
+ if (NtReplacementName.Buffer)
+ RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName.Buffer);
+ if (NtReplacedName.Buffer)
+ RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName.Buffer);
+
+ /* If there was an error, set the error code */
+ if(!Ret)
+ {
+ TRACE("ReplaceFileW failed (error=%d)\n", Error);
+ SetLastError(Error);
+ }
+ return Ret;
+}
+
/* EOF */