[KERNEL32] ReplaceFileW:
[reactos.git] / reactos / dll / win32 / kernel32 / file / file.c
index 7efdbc2..cdbafd0 100644 (file)
@@ -177,7 +177,7 @@ FilenameW2A_N(
  * @implemented
  */
 VOID
-STDCALL
+WINAPI
 SetFileApisToOEM(VOID)
 {
     /* Set the correct Base Api */
@@ -192,7 +192,7 @@ SetFileApisToOEM(VOID)
  * @implemented
  */
 VOID
-STDCALL
+WINAPI
 SetFileApisToANSI(VOID)
 {
     /* Set the correct Base Api */
@@ -206,7 +206,7 @@ SetFileApisToANSI(VOID)
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 AreFileApisANSI(VOID)
 {
    return bIsFileApiAnsi;
@@ -216,7 +216,7 @@ AreFileApisANSI(VOID)
 /*
  * @implemented
  */
-HFILE STDCALL
+HFILE WINAPI
 OpenFile(LPCSTR lpFileName,
         LPOFSTRUCT lpReOpenBuff,
         UINT uStyle)
@@ -236,9 +236,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 +327,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 +365,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 +379,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 +389,12 @@ OpenFile(LPCSTR lpFileName,
                return (HFILE)INVALID_HANDLE_VALUE;
        }
 
+       if (uStyle & OF_EXIST)
+       {
+               NtClose(FileHandle);
+               return (HFILE)1;
+       }
+
        return (HFILE)FileHandle;
 }
 
@@ -347,12 +402,14 @@ OpenFile(LPCSTR lpFileName,
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 FlushFileBuffers(HANDLE hFile)
 {
    NTSTATUS errCode;
    IO_STATUS_BLOCK IoStatusBlock;
 
+   hFile = TranslateStdHandle(hFile);
+
    if (IsConsoleHandle(hFile))
    {
       return FALSE;
@@ -372,11 +429,11 @@ FlushFileBuffers(HANDLE hFile)
 /*
  * @implemented
  */
-DWORD STDCALL
+DWORD WINAPI
 SetFilePointer(HANDLE hFile,
-              LONG lDistanceToMove,
-              PLONG lpDistanceToMoveHigh,
-              DWORD dwMoveMethod)
+           LONG lDistanceToMove,
+           PLONG lpDistanceToMoveHigh,
+           DWORD dwMoveMethod)
 {
    FILE_POSITION_INFORMATION FilePosition;
    FILE_STANDARD_INFORMATION FileStandard;
@@ -385,12 +442,12 @@ SetFilePointer(HANDLE hFile,
    LARGE_INTEGER Distance;
 
    TRACE("SetFilePointer(hFile %x, lDistanceToMove %d, dwMoveMethod %d)\n",
-         hFile,lDistanceToMove,dwMoveMethod);
+      hFile,lDistanceToMove,dwMoveMethod);
 
    if(IsConsoleHandle(hFile))
    {
      SetLastError(ERROR_INVALID_HANDLE);
-     return -1;
+     return INVALID_SET_FILE_POINTER;
    }
 
    if (lpDistanceToMoveHigh)
@@ -406,34 +463,48 @@ SetFilePointer(HANDLE hFile,
    switch(dwMoveMethod)
    {
      case FILE_CURRENT:
-       NtQueryInformationFile(hFile,
-                              &IoStatusBlock,
-                              &FilePosition,
-                              sizeof(FILE_POSITION_INFORMATION),
-                              FilePositionInformation);
-       FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
-       break;
+    errCode = NtQueryInformationFile(hFile,
+                   &IoStatusBlock,
+                   &FilePosition,
+                   sizeof(FILE_POSITION_INFORMATION),
+                   FilePositionInformation);
+    FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
+    if (!NT_SUCCESS(errCode))
+    {
+      if (lpDistanceToMoveHigh != NULL)
+          *lpDistanceToMoveHigh = -1;
+      SetLastErrorByStatus(errCode);
+      return INVALID_SET_FILE_POINTER;
+    }
+    break;
      case FILE_END:
-       NtQueryInformationFile(hFile,
+    errCode = NtQueryInformationFile(hFile,
                                &IoStatusBlock,
                                &FileStandard,
                                sizeof(FILE_STANDARD_INFORMATION),
                                FileStandardInformation);
-        FilePosition.CurrentByteOffset.QuadPart =
+    FilePosition.CurrentByteOffset.QuadPart =
                   FileStandard.EndOfFile.QuadPart + Distance.QuadPart;
-       break;
+    if (!NT_SUCCESS(errCode))
+    {
+      if (lpDistanceToMoveHigh != NULL)
+          *lpDistanceToMoveHigh = -1;
+      SetLastErrorByStatus(errCode);
+      return INVALID_SET_FILE_POINTER;
+    }
+    break;
      case FILE_BEGIN:
         FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart;
-       break;
+    break;
      default:
         SetLastError(ERROR_INVALID_PARAMETER);
-       return -1;
+    return INVALID_SET_FILE_POINTER;
    }
 
    if(FilePosition.CurrentByteOffset.QuadPart < 0)
    {
      SetLastError(ERROR_NEGATIVE_SEEK);
-     return -1;
+     return INVALID_SET_FILE_POINTER;
    }
 
    if (lpDistanceToMoveHigh == NULL && FilePosition.CurrentByteOffset.HighPart != 0)
@@ -441,21 +512,21 @@ SetFilePointer(HANDLE hFile,
      /* If we're moving the pointer outside of the 32 bit boundaries but
         the application only passed a 32 bit value we need to bail out! */
      SetLastError(ERROR_INVALID_PARAMETER);
-     return -1;
+     return INVALID_SET_FILE_POINTER;
    }
 
    errCode = NtSetInformationFile(hFile,
-                                 &IoStatusBlock,
-                                 &FilePosition,
-                                 sizeof(FILE_POSITION_INFORMATION),
-                                 FilePositionInformation);
+                  &IoStatusBlock,
+                  &FilePosition,
+                  sizeof(FILE_POSITION_INFORMATION),
+                  FilePositionInformation);
    if (!NT_SUCCESS(errCode))
      {
        if (lpDistanceToMoveHigh != NULL)
            *lpDistanceToMoveHigh = -1;
 
        SetLastErrorByStatus(errCode);
-       return -1;
+       return INVALID_SET_FILE_POINTER;
      }
 
    if (lpDistanceToMoveHigh != NULL)
@@ -463,7 +534,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
@@ -481,7 +552,7 @@ SetFilePointer(HANDLE hFile,
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 SetFilePointerEx(HANDLE hFile,
                 LARGE_INTEGER liDistanceToMove,
                 PLARGE_INTEGER lpNewFilePointer,
@@ -553,7 +624,7 @@ SetFilePointerEx(HANDLE hFile,
 /*
  * @implemented
  */
-DWORD STDCALL
+DWORD WINAPI
 GetFileType(HANDLE hFile)
 {
   FILE_FS_DEVICE_INFORMATION DeviceInfo;
@@ -561,20 +632,7 @@ GetFileType(HANDLE hFile)
   NTSTATUS Status;
 
   /* Get real handle */
-  switch ((ULONG)hFile)
-    {
-      case STD_INPUT_HANDLE:
-       hFile = NtCurrentPeb()->ProcessParameters->StandardInput;
-       break;
-
-      case STD_OUTPUT_HANDLE:
-       hFile = NtCurrentPeb()->ProcessParameters->StandardOutput;
-       break;
-
-      case STD_ERROR_HANDLE:
-       hFile = NtCurrentPeb()->ProcessParameters->StandardError;
-       break;
-    }
+  hFile = TranslateStdHandle(hFile);
 
   /* Check for console handle */
   if (IsConsoleHandle(hFile))
@@ -628,7 +686,7 @@ GetFileType(HANDLE hFile)
 /*
  * @implemented
  */
-DWORD STDCALL
+DWORD WINAPI
 GetFileSize(HANDLE hFile,
            LPDWORD lpFileSizeHigh)
 {
@@ -664,7 +722,7 @@ GetFileSize(HANDLE hFile,
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 GetFileSizeEx(
     HANDLE hFile,
     PLARGE_INTEGER lpFileSize
@@ -694,7 +752,7 @@ GetFileSizeEx(
 /*
  * @implemented
  */
-DWORD STDCALL
+DWORD WINAPI
 GetCompressedFileSizeA(LPCSTR lpFileName,
                       LPDWORD lpFileSizeHigh)
 {
@@ -710,7 +768,7 @@ GetCompressedFileSizeA(LPCSTR lpFileName,
 /*
  * @implemented
  */
-DWORD STDCALL
+DWORD WINAPI
 GetCompressedFileSizeW(LPCWSTR lpFileName,
                       LPDWORD lpFileSizeHigh)
 {
@@ -755,7 +813,7 @@ GetCompressedFileSizeW(LPCWSTR lpFileName,
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 GetFileInformationByHandle(HANDLE hFile,
                           LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
 {
@@ -849,7 +907,7 @@ GetFileInformationByHandle(HANDLE hFile,
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 GetFileAttributesExW(LPCWSTR lpFileName,
                     GET_FILEEX_INFO_LEVELS fInfoLevelId,
                     LPVOID lpFileInformation)
@@ -916,7 +974,7 @@ GetFileAttributesExW(LPCWSTR lpFileName,
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 GetFileAttributesExA(LPCSTR lpFileName,
                     GET_FILEEX_INFO_LEVELS fInfoLevelId,
                     LPVOID lpFileInformation)
@@ -933,14 +991,14 @@ GetFileAttributesExA(LPCSTR lpFileName,
 /*
  * @implemented
  */
-DWORD STDCALL
+DWORD WINAPI
 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);
@@ -952,7 +1010,7 @@ GetFileAttributesA(LPCSTR lpFileName)
 /*
  * @implemented
  */
-DWORD STDCALL
+DWORD WINAPI
 GetFileAttributesW(LPCWSTR lpFileName)
 {
   WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
@@ -969,7 +1027,7 @@ GetFileAttributesW(LPCWSTR lpFileName)
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 GetFileAttributesByHandle(IN HANDLE hFile,
                           OUT LPDWORD dwFileAttributes,
                           IN DWORD dwFlags)
@@ -1005,7 +1063,7 @@ GetFileAttributesByHandle(IN HANDLE hFile,
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 SetFileAttributesByHandle(IN HANDLE hFile,
                           IN DWORD dwFileAttributes,
                           IN DWORD dwFlags)
@@ -1051,7 +1109,7 @@ SetFileAttributesByHandle(IN HANDLE hFile,
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 SetFileAttributesA(
    LPCSTR lpFileName,
        DWORD dwFileAttributes)
@@ -1068,7 +1126,7 @@ SetFileAttributesA(
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 SetFileAttributesW(LPCWSTR lpFileName,
                   DWORD dwFileAttributes)
 {
@@ -1231,162 +1289,13 @@ UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, LPWSTR
 }
 
 
-/*
- * @unimplemented
- */
-BOOL
-STDCALL
-ReplaceFileW(
-    LPCWSTR lpReplacedFileName,
-    LPCWSTR lpReplacementFileName,
-    LPCWSTR lpBackupFileName,
-    DWORD   dwReplaceFlags,
-    LPVOID  lpExclude,
-    LPVOID  lpReserved
-    )
-{
-    UNICODE_STRING nt_replaced_name, nt_replacement_name;
-    HANDLE hReplaced = NULL, hReplacement = NULL;
-    DWORD error = ERROR_SUCCESS;
-    UINT replaced_flags;
-    BOOL ret = FALSE;
-    NTSTATUS status;
-    IO_STATUS_BLOCK io;
-    OBJECT_ATTRIBUTES attr;
-
-    if (dwReplaceFlags)
-        FIXME("Ignoring flags %x\n", dwReplaceFlags);
-
-    /* First two arguments are mandatory */
-    if (!lpReplacedFileName || !lpReplacementFileName)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    attr.Length = sizeof(attr);
-    attr.RootDirectory = 0;
-    attr.Attributes = OBJ_CASE_INSENSITIVE;
-    attr.ObjectName = NULL;
-    attr.SecurityDescriptor = NULL;
-    attr.SecurityQualityOfService = NULL;
-
-    /* Open the "replaced" file for reading and writing */
-    if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &nt_replaced_name, NULL, NULL)))
-    {
-        error = ERROR_PATH_NOT_FOUND;
-        goto fail;
-    }
-
-    replaced_flags = lpBackupFileName ? FILE_OPEN : FILE_OPEN_IF;
-    attr.ObjectName = &nt_replaced_name;
-
-    status = NtOpenFile(&hReplaced, GENERIC_READ | GENERIC_WRITE | DELETE | SYNCHRONIZE,
-                        &attr, &io,
-                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                        FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
-
-    if (status != STATUS_SUCCESS)
-    {
-        error = RtlNtStatusToDosError(status);
-        goto fail;
-    }
-    
-    RtlFreeUnicodeString(&nt_replaced_name);
-
-    /*
-     * Open the replacement file for reading, writing, and deleting
-     * (writing and deleting are needed when finished)
-     */
-    if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &nt_replacement_name, NULL, NULL)))
-    {
-        error = ERROR_PATH_NOT_FOUND;
-        goto fail;
-    }
-
-    attr.ObjectName = &nt_replacement_name;
-    status = NtOpenFile(&hReplacement,
-                        GENERIC_READ | GENERIC_WRITE | DELETE | WRITE_DAC | SYNCHRONIZE,
-                        &attr, &io, 0,
-                        FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
-
-    if (status != STATUS_SUCCESS)
-    {
-        error = RtlNtStatusToDosError(status);
-        goto fail;
-    }
-
-    RtlFreeUnicodeString(&nt_replacement_name);
-
-    /* Perform resource cleanup */
-fail:
-    if (hReplaced) CloseHandle(hReplaced);
-    if (hReplacement) CloseHandle(hReplacement);
 
-    /* If there was an error, set the error code */
-    if(!ret)
-        SetLastError(error);
-    return ret;
-}
 
 
 /*
  * @implemented
  */
-BOOL
-STDCALL
-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;
-}
-
-
-/*
- * @implemented
- */
-BOOL STDCALL
+BOOL WINAPI
 GetFileTime(HANDLE hFile,
            LPFILETIME lpCreationTime,
            LPFILETIME lpLastAccessTime,
@@ -1427,7 +1336,7 @@ GetFileTime(HANDLE hFile,
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 SetFileTime(HANDLE hFile,
            CONST FILETIME *lpCreationTime,
            CONST FILETIME *lpLastAccessTime,
@@ -1483,7 +1392,7 @@ SetFileTime(HANDLE hFile,
  *
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 SetEndOfFile(HANDLE hFile)
 {
        IO_STATUS_BLOCK  IoStatusBlock;
@@ -1560,7 +1469,7 @@ SetEndOfFile(HANDLE hFile)
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 SetFileValidData(
     HANDLE hFile,
     LONGLONG ValidDataLength
@@ -1594,7 +1503,7 @@ SetFileValidData(
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 SetFileShortNameW(
   HANDLE hFile,
   LPCWSTR lpShortName)
@@ -1650,7 +1559,7 @@ SetFileShortNameW(
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 SetFileShortNameA(
     HANDLE hFile,
     LPCSTR lpShortName
@@ -1681,7 +1590,7 @@ SetFileShortNameA(
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 CheckNameLegalDOS8Dot3W(
     LPCWSTR lpName,
     LPSTR lpOemName OPTIONAL,
@@ -1722,7 +1631,7 @@ CheckNameLegalDOS8Dot3W(
  * @implemented
  */
 BOOL
-STDCALL
+WINAPI
 CheckNameLegalDOS8Dot3A(
     LPCSTR lpName,
     LPSTR lpOemName OPTIONAL,
@@ -1931,4 +1840,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 */