Use only NtCreateKey and better suited access rights.
[reactos.git] / reactos / lib / kernel32 / file / move.c
index a4193dc..2b93dc1 100644 (file)
@@ -1,10 +1,11 @@
-/* $Id: move.c,v 1.12 2004/01/23 16:37:11 ekohl Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/file/file.c
  * PURPOSE:         Directory functions
  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
+ *                  Gerhard W. Gruber (sparhawk_at_gmx.at)
  * UPDATE HISTORY:
  *                  Created 01/11/98
  */
 /* INCLUDES *****************************************************************/
 
 #include <k32.h>
+#include <malloc.h>
 
 #define NDEBUG
-#include <kernel32/kernel32.h>
-
-
-#define FILE_RENAME_SIZE  MAX_PATH +sizeof(FILE_RENAME_INFORMATION)
+#include "../include/debug.h"
 
+/* GLOBALS *****************************************************************/
 
 /* FUNCTIONS ****************************************************************/
+static BOOL
+RemoveReadOnlyAttributeW(IN LPCWSTR lpFileName)
+{
+    DWORD Attributes;
+    Attributes = GetFileAttributesW(lpFileName);
+    if (Attributes != INVALID_FILE_ATTRIBUTES)
+    {  
+        return SetFileAttributesW(lpFileName,Attributes - 
+                                             (Attributes & ~FILE_ATTRIBUTE_READONLY));
+    }
+    return FALSE;
+}
 
-/*
- * @implemented
+
+/***********************************************************************
+ *           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
+ *
  */
-BOOL
-STDCALL
-MoveFileA (
-       LPCSTR  lpExistingFileName,
-       LPCSTR  lpNewFileName
-       )
+static BOOL add_boot_rename_entry( LPCWSTR source, LPCWSTR dest, DWORD flags )
 {
-       return MoveFileExA (lpExistingFileName,
-                           lpNewFileName,
-                           MOVEFILE_COPY_ALLOWED);
+    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 = 0;
+    DWORD len1, len2;
+    DWORD DataSize = 0;
+    BYTE *Buffer = NULL;
+    WCHAR *p;
+    NTSTATUS Status;
+
+    DPRINT("Add support to smss for keys created by MOVEFILE_DELAY_UNTIL_REBOOT\n");
+
+    if (!RtlDosPathNameToNtPathName_U( source, &source_name, NULL, NULL ))
+    {
+        SetLastError( ERROR_PATH_NOT_FOUND );
+        return FALSE;
+    }
+    dest_name.Buffer = NULL;
+    if (dest && !RtlDosPathNameToNtPathName_U( dest, &dest_name, NULL, NULL ))
+    {
+        RtlFreeUnicodeString( &source_name );
+        SetLastError( ERROR_PATH_NOT_FOUND );
+        return FALSE;
+    }
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+     Status = NtCreateKey(&Reboot, 
+                          KEY_QUERY_VALUE | KEY_SET_VALUE,
+                          &ObjectAttributes,
+                          0,
+                          NULL,
+                          REG_OPTION_NON_VOLATILE,
+                          NULL);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtCreateKey() failed (Status 0x%lx)\n", Status);
+        RtlFreeUnicodeString( &source_name );
+        RtlFreeUnicodeString( &dest_name );
+        return FALSE;
+    }
+
+    len1 = source_name.Length + sizeof(WCHAR);
+    if (dest)
+    {
+        len2 = dest_name.Length + sizeof(WCHAR);
+        if (flags & MOVEFILE_REPLACE_EXISTING)
+            len2 += sizeof(WCHAR); /* Plus 1 because of the leading '!' */
+    }
+    else len2 = sizeof(WCHAR); /* minimum is the 0 characters for the empty second string */
+
+    RtlInitUnicodeString( &nameW, ValueName );
+
+    /* First we check if the key exists and if so how many bytes it already contains. */
+    if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
+                         NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
+    {
+        if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
+            goto Quit;
+        if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
+                             Buffer, DataSize, &DataSize )) 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) */
+    }
+    else
+    {
+        DataSize = info_size;
+        if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
+            goto Quit;
+    }
+
+    memcpy( Buffer + DataSize, source_name.Buffer, len1 );
+    DataSize += len1;
+    p = (WCHAR *)(Buffer + DataSize);
+    if (dest)
+    {
+        if (flags & MOVEFILE_REPLACE_EXISTING)
+            *p++ = '!';
+        memcpy( p, dest_name.Buffer, len2 );
+        DataSize += len2;
+    }
+    else
+    {
+        *p = 0;
+        DataSize += sizeof(WCHAR);
+    }
+
+    /* add final null */
+    p = (WCHAR *)(Buffer + DataSize);
+    *p = 0;
+    DataSize += sizeof(WCHAR);
+
+    rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
+
+ Quit:
+    RtlFreeUnicodeString( &source_name );
+    RtlFreeUnicodeString( &dest_name );
+    if (Reboot) NtClose(Reboot);
+    HeapFree( GetProcessHeap(), 0, Buffer );
+    return(rc);
 }
 
 
@@ -43,17 +192,421 @@ MoveFileA (
  */
 BOOL
 STDCALL
-MoveFileExA (
-       LPCSTR  lpExistingFileName,
-       LPCSTR  lpNewFileName,
-       DWORD   dwFlags
+MoveFileWithProgressW (
+       LPCWSTR                 lpExistingFileName,
+       LPCWSTR                 lpNewFileName,
+       LPPROGRESS_ROUTINE      lpProgressRoutine,
+       LPVOID                  lpData,
+       DWORD                   dwFlags
        )
 {
-       return MoveFileWithProgressA (lpExistingFileName,
-                                     lpNewFileName,
-                                     NULL,
-                                     NULL,
-                                     dwFlags);
+       HANDLE hFile = NULL;
+       IO_STATUS_BLOCK IoStatusBlock;
+       PFILE_RENAME_INFORMATION FileRename;
+       NTSTATUS errCode;
+       BOOL Result;
+       UNICODE_STRING DstPathU;
+       BOOL folder = FALSE;
+
+       DPRINT("MoveFileWithProgressW()\n");
+
+       if (dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT)
+               return add_boot_rename_entry( lpExistingFileName, lpNewFileName, dwFlags );
+
+       hFile = CreateFileW (lpExistingFileName,
+                            GENERIC_ALL,
+                            FILE_SHARE_WRITE|FILE_SHARE_READ,
+                            NULL,
+                            OPEN_EXISTING,
+                            FILE_FLAG_BACKUP_SEMANTICS,
+                            NULL);
+
+       if (hFile == INVALID_HANDLE_VALUE)
+       {
+          return FALSE;
+       }
+
+       
+        /* validate & translate the filename */
+        if (!RtlDosPathNameToNtPathName_U (lpNewFileName,
+                                          &DstPathU,
+                                          NULL,
+                                          NULL))
+        {
+           DPRINT("Invalid destination path\n");
+          CloseHandle(hFile);
+           SetLastError(ERROR_PATH_NOT_FOUND);
+           return FALSE;
+        }
+
+       FileRename = alloca(sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length);
+       if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == MOVEFILE_REPLACE_EXISTING)
+               FileRename->ReplaceIfExists = TRUE;
+       else
+               FileRename->ReplaceIfExists = FALSE;
+
+       memcpy(FileRename->FileName, DstPathU.Buffer, DstPathU.Length);
+        RtlFreeHeap (RtlGetProcessHeap (),
+                    0,
+                    DstPathU.Buffer);
+       /*
+        * FIXME:
+        *   Is the length the count of characters or the length of the buffer?
+        */
+       FileRename->FileNameLength = DstPathU.Length / sizeof(WCHAR);
+       errCode = NtSetInformationFile (hFile,
+                                       &IoStatusBlock,
+                                       FileRename,
+                                       sizeof(FILE_RENAME_INFORMATION) + DstPathU.Length,
+                                       FileRenameInformation);
+       CloseHandle(hFile);
+
+       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,
+                                     FileRename->ReplaceIfExists ? 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 (lpNewFileName2 == 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 == NULL) 
+                      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);
+                        wcscpy( &lpExistingFileName2[size],L"\0");
+
+                        if (wcsncmp(lpExistingFileName,lpExistingFileName2,size))
+                        {  
+                                  DWORD Attributes;
+
+                          FindClose(hFile);                         
+
+                                  /* delete folder */                                                                   
+                                  DPRINT("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 */
+                          
+                          DPRINT("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 */                                           
+                          DPRINT("MoveFileWithProgressW : remove readonly flag from file : %S\n",lpNewFileName2);
+                          Result = RemoveReadOnlyAttributeW(lpDeleteFile);
+                          if (Result == FALSE)
+                              break;
+
+               DPRINT("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;
+
+                    FindClose(hFile);                           
+                        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;
 }
 
 
@@ -70,52 +623,25 @@ MoveFileWithProgressA (
        DWORD                   dwFlags
        )
 {
-       UNICODE_STRING ExistingFileNameU;
-       UNICODE_STRING NewFileNameU;
-       ANSI_STRING ExistingFileName;
-       ANSI_STRING NewFileName;
-       BOOL Result;
+       PWCHAR ExistingFileNameW;
+   PWCHAR NewFileNameW;
+       BOOL ret;
 
-       RtlInitAnsiString (&ExistingFileName,
-                          (LPSTR)lpExistingFileName);
+   if (!(ExistingFileNameW = FilenameA2W(lpExistingFileName, FALSE)))
+      return FALSE;
 
-       RtlInitAnsiString (&NewFileName,
-                          (LPSTR)lpNewFileName);
+   if (!(NewFileNameW= FilenameA2W(lpNewFileName, TRUE)))
+      return FALSE;
 
-       /* convert ansi (or oem) string to unicode */
-       if (bIsFileApiAnsi)
-       {
-               RtlAnsiStringToUnicodeString (&ExistingFileNameU,
-                                             &ExistingFileName,
-                                             TRUE);
-               RtlAnsiStringToUnicodeString (&NewFileNameU,
-                                             &NewFileName,
-                                             TRUE);
-       }
-       else
-       {
-               RtlOemStringToUnicodeString (&ExistingFileNameU,
-                                            &ExistingFileName,
-                                            TRUE);
-               RtlOemStringToUnicodeString (&NewFileNameU,
-                                            &NewFileName,
-                                            TRUE);
-       }
-
-       Result = MoveFileWithProgressW (ExistingFileNameU.Buffer,
-                                       NewFileNameU.Buffer,
+   ret = MoveFileWithProgressW (ExistingFileNameW ,
+                                   NewFileNameW,
                                        lpProgressRoutine,
                                        lpData,
                                        dwFlags);
 
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    ExistingFileNameU.Buffer);
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    NewFileNameU.Buffer);
+   RtlFreeHeap (RtlGetProcessHeap (), 0, NewFileNameW);
 
-       return Result;
+       return ret;
 }
 
 
@@ -154,130 +680,19 @@ MoveFileExW (
 }
 
 
-static BOOL
-AdjustFileAttributes (
-       LPCWSTR ExistingFileName,
-       LPCWSTR NewFileName
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+MoveFileA (
+       LPCSTR  lpExistingFileName,
+       LPCSTR  lpNewFileName
        )
 {
-       IO_STATUS_BLOCK IoStatusBlock;
-       FILE_BASIC_INFORMATION ExistingInfo,
-               NewInfo;
-       HANDLE hFile;
-       DWORD Attributes;
-       NTSTATUS errCode;
-       BOOL Result = FALSE;
-
-       hFile = CreateFileW (ExistingFileName,
-                            FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
-                            FILE_SHARE_READ,
-                            NULL,
-                            OPEN_EXISTING,
-                            FILE_ATTRIBUTE_NORMAL,
-                            NULL);
-       if (INVALID_HANDLE_VALUE != hFile)
-       {
-               errCode = NtQueryInformationFile (hFile,
-                                                 &IoStatusBlock,
-                                                 &ExistingInfo,
-                                                 sizeof(FILE_BASIC_INFORMATION),
-                                                 FileBasicInformation);
-               if (NT_SUCCESS (errCode))
-               {
-                       if (0 != (ExistingInfo.FileAttributes & FILE_ATTRIBUTE_READONLY))
-                       {
-                               Attributes = ExistingInfo.FileAttributes;
-                               ExistingInfo.FileAttributes &= ~ FILE_ATTRIBUTE_READONLY;
-                               if (0 == (ExistingInfo.FileAttributes &
-                                         (FILE_ATTRIBUTE_HIDDEN |
-                                          FILE_ATTRIBUTE_SYSTEM |
-                                          FILE_ATTRIBUTE_ARCHIVE)))
-                               {
-                                       ExistingInfo.FileAttributes |= FILE_ATTRIBUTE_NORMAL;
-                               }
-                               errCode = NtSetInformationFile (hFile,
-                                                               &IoStatusBlock,
-                                                               &ExistingInfo,
-                                                               sizeof(FILE_BASIC_INFORMATION),
-                                                               FileBasicInformation);
-                               if (!NT_SUCCESS(errCode))
-                               {
-                                       DPRINT("Removing READONLY attribute from source failed with status 0x%08x\n", errCode);
-                               }
-                               ExistingInfo.FileAttributes = Attributes;
-                       }
-                       CloseHandle(hFile);
-
-                       if (NT_SUCCESS(errCode))
-                       {
-                               hFile = CreateFileW (NewFileName,
-                                                    FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
-                                                    FILE_SHARE_READ,
-                                                    NULL,
-                                                    OPEN_EXISTING,
-                                                    FILE_ATTRIBUTE_NORMAL,
-                                                    NULL);
-                               if (INVALID_HANDLE_VALUE != hFile)
-                               {
-                                       errCode = NtQueryInformationFile(hFile,
-                                                                        &IoStatusBlock,
-                                                                        &NewInfo,
-                                                                        sizeof(FILE_BASIC_INFORMATION),
-                                                                        FileBasicInformation);
-                                       if (NT_SUCCESS(errCode))
-                                       {
-                                               NewInfo.FileAttributes = (NewInfo.FileAttributes &
-                                                                         ~ (FILE_ATTRIBUTE_HIDDEN |
-                                                                            FILE_ATTRIBUTE_SYSTEM |
-                                                                            FILE_ATTRIBUTE_READONLY |
-                                                                            FILE_ATTRIBUTE_NORMAL)) |
-                                                                        (ExistingInfo.FileAttributes &
-                                                                         (FILE_ATTRIBUTE_HIDDEN |
-                                                                          FILE_ATTRIBUTE_SYSTEM |
-                                                                          FILE_ATTRIBUTE_READONLY |
-                                                                          FILE_ATTRIBUTE_NORMAL)) |
-                                                                        FILE_ATTRIBUTE_ARCHIVE;
-                                               NewInfo.CreationTime = ExistingInfo.CreationTime;
-                                               NewInfo.LastAccessTime = ExistingInfo.LastAccessTime;
-                                               NewInfo.LastWriteTime = ExistingInfo.LastWriteTime;
-                                               errCode = NtSetInformationFile (hFile,
-                                                                               &IoStatusBlock,
-                                                                               &NewInfo,
-                                                                               sizeof(FILE_BASIC_INFORMATION),
-                                                                               FileBasicInformation);
-                                               if (NT_SUCCESS(errCode))
-                                               {
-                                                       Result = TRUE;
-                                               }
-                                               else
-                                               {
-                                                       DPRINT("Setting attributes on dest file failed with status 0x%08x\n", errCode);
-                                               }
-                                       }
-                                       else
-                                       {
-                                               DPRINT("Obtaining attributes from dest file failed with status 0x%08x\n", errCode);
-                                       }
-                                       CloseHandle(hFile);
-                               }
-                               else
-                               {
-                                       DPRINT("Opening dest file to set attributes failed with code %d\n", GetLastError());
-                               }
-                       }
-               }
-               else
-               {
-                       DPRINT("Obtaining attributes from source file failed with status 0x%08x\n", errCode);
-                       CloseHandle(hFile);
-               }
-       }
-       else
-       {
-               DPRINT("Opening source file to obtain attributes failed with code %d\n", GetLastError());
-       }
-
-       return Result;
+       return MoveFileExA (lpExistingFileName,
+                           lpNewFileName,
+                           MOVEFILE_COPY_ALLOWED);
 }
 
 
@@ -286,97 +701,17 @@ AdjustFileAttributes (
  */
 BOOL
 STDCALL
-MoveFileWithProgressW (
-       LPCWSTR                 lpExistingFileName,
-       LPCWSTR                 lpNewFileName,
-       LPPROGRESS_ROUTINE      lpProgressRoutine,
-       LPVOID                  lpData,
-       DWORD                   dwFlags
+MoveFileExA (
+       LPCSTR  lpExistingFileName,
+       LPCSTR  lpNewFileName,
+       DWORD   dwFlags
        )
 {
-       HANDLE hFile = NULL;
-       IO_STATUS_BLOCK IoStatusBlock;
-       FILE_RENAME_INFORMATION *FileRename;
-       USHORT Buffer[FILE_RENAME_SIZE];
-       NTSTATUS errCode;
-       DWORD err;
-       BOOL Result;
-
-       hFile = CreateFileW (lpExistingFileName,
-                            GENERIC_ALL,
-                            FILE_SHARE_WRITE|FILE_SHARE_READ,
-                            NULL,
-                            OPEN_EXISTING,
-                            FILE_ATTRIBUTE_NORMAL,
-                            NULL);
-
-       FileRename = (FILE_RENAME_INFORMATION *)Buffer;
-       if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == MOVEFILE_REPLACE_EXISTING)
-               FileRename->Replace = TRUE;
-       else
-               FileRename->Replace = FALSE;
-
-       FileRename->FileNameLength = wcslen (lpNewFileName);
-       memcpy (FileRename->FileName,
-               lpNewFileName,
-               min(FileRename->FileNameLength, MAX_PATH));
-
-       errCode = NtSetInformationFile (hFile,
-                                       &IoStatusBlock,
-                                       FileRename,
-                                       FILE_RENAME_SIZE,
-                                       FileRenameInformation);
-       CloseHandle(hFile);
-       if (NT_SUCCESS(errCode))
-       {
-               Result = TRUE;
-       }
-       /* FIXME file rename not yet implemented in all FSDs so it will always
-        * fail, even when the move is to the same device
-        */
-#if 0
-       else if (STATUS_NOT_SAME_DEVICE == errCode &&
-                MOVEFILE_COPY_ALLOWED == (dwFlags & MOVEFILE_COPY_ALLOWED))
-#else
-       else
-#endif
-       {
-               Result = CopyFileExW (lpExistingFileName,
-                                     lpNewFileName,
-                                     lpProgressRoutine,
-                                     lpData,
-                                     NULL,
-                                     FileRename->Replace ? 0 : COPY_FILE_FAIL_IF_EXISTS) &&
-                        AdjustFileAttributes(lpExistingFileName, lpNewFileName) &&
-                        DeleteFileW (lpExistingFileName);
-               if (! Result)
-               {
-                       /* Delete of the existing file failed so the
-                        * existing file is still there. Clean up the
-                        * new file (if possible)
-                        */
-                       err = GetLastError();
-                       if (! SetFileAttributesW (lpNewFileName, FILE_ATTRIBUTE_NORMAL))
-                       {
-                               DPRINT("Removing possible READONLY attrib from new file failed with code %d\n", GetLastError());
-                       }
-                       if (! DeleteFileW (lpNewFileName))
-                       {
-                               DPRINT("Deleting new file during cleanup failed with code %d\n", GetLastError());
-                       }
-                       SetLastError (err);
-               }
-       }
-       /* See FIXME above */
-#if 0
-       else
-       {
-               SetLastErrorByStatus (errCode);
-               Result = FALSE;
-       }
-#endif
-
-       return Result;
+       return MoveFileWithProgressA (lpExistingFileName,
+                                     lpNewFileName,
+                                     NULL,
+                                     NULL,
+                                     dwFlags);
 }
 
 /* EOF */