[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / file / file.c
index a0b84cf..7f0c044 100644 (file)
@@ -5,7 +5,7 @@
  * 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
  */
@@ -13,9 +13,9 @@
 /* INCLUDES *****************************************************************/
 
 #include <k32.h>
-#include <wine/debug.h>
-
-WINE_DEFAULT_DEBUG_CHANNEL(kernel32file);
+#define NDEBUG
+#include <debug.h>
+DEBUG_CHANNEL(kernel32file);
 
 /* GLOBALS ******************************************************************/
 
@@ -72,6 +72,9 @@ FilenameU2A_FitOrFail(
 {
    DWORD ret;
 
+   /* destLen should never exceed MAX_PATH */
+   if (destLen > MAX_PATH) destLen = MAX_PATH;
+
    ret = bIsFileApiAnsi? RtlUnicodeStringToAnsiSize(SourceU) : RtlUnicodeStringToOemSize(SourceU);
    /* ret incl. nullchar */
 
@@ -236,9 +239,56 @@ OpenFile(LPCSTR lpFileName,
 
        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;
@@ -280,9 +330,21 @@ OpenFile(LPCSTR lpFileName,
 
        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;
@@ -306,14 +368,6 @@ OpenFile(LPCSTR lpFileName,
        // 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;
@@ -328,11 +382,9 @@ OpenFile(LPCSTR lpFileName,
                              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))
        {
@@ -340,6 +392,12 @@ OpenFile(LPCSTR lpFileName,
                return (HFILE)INVALID_HANDLE_VALUE;
        }
 
+       if (uStyle & OF_EXIST)
+       {
+               NtClose(FileHandle);
+               return (HFILE)1;
+       }
+
        return (HFILE)FileHandle;
 }
 
@@ -348,26 +406,26 @@ OpenFile(LPCSTR lpFileName,
  * @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;
 }
 
 
@@ -479,7 +537,7 @@ SetFilePointer(HANDLE hFile,
         *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
@@ -941,9 +999,9 @@ GetFileAttributesA(LPCSTR lpFileName)
 {
    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);
@@ -1154,83 +1212,205 @@ SetFileAttributesW(LPCWSTR lpFileName,
 /***********************************************************************
  *           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;
 }
 
 
@@ -1241,40 +1421,51 @@ UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, LPWSTR
  * @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;
 }
 
 
@@ -1282,53 +1473,53 @@ GetFileTime(HANDLE hFile,
  * @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;
 }
 
 
@@ -1785,4 +1976,208 @@ OpenFileById(IN HANDLE hFile,
     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 */