2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/file.c
5 * PURPOSE: Directory functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Gerhard W. Gruber (sparhawk_at_gmx.at)
8 * Dmitry Philippov (shedon@mail.ru)
12 * Fix some bugs in the add_boot_rename_entry function
15 /* INCLUDES *****************************************************************/
21 DEBUG_CHANNEL(kernel32file
);
23 /* GLOBALS *****************************************************************/
25 /* FUNCTIONS ****************************************************************/
27 RemoveReadOnlyAttributeW(IN LPCWSTR lpFileName
)
30 Attributes
= GetFileAttributesW(lpFileName
);
31 if (Attributes
!= INVALID_FILE_ATTRIBUTES
)
33 return SetFileAttributesW(lpFileName
,Attributes
-
34 (Attributes
& ~FILE_ATTRIBUTE_READONLY
));
41 /***********************************************************************
42 * add_boot_rename_entry
44 * Adds an entry to the registry that is loaded when windows boots and
45 * checks if there are some files to be removed or renamed/moved.
46 * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
47 * non-NULL then the file is moved, otherwise it is deleted. The
48 * entry of the registrykey is always appended with two zero
49 * terminated strings. If <fn2> is NULL then the second entry is
50 * simply a single 0-byte. Otherwise the second filename goes
51 * there. The entries are prepended with \??\ before the path and the
52 * second filename gets also a '!' as the first character if
53 * MOVEFILE_REPLACE_EXISTING is set. After the final string another
54 * 0-byte follows to indicate the end of the strings.
56 * \??\D:\test\file1[0]
57 * !\??\D:\test\file1_renamed[0]
58 * \??\D:\Test|delete[0]
59 * [0] <- file is to be deleted, second string empty
60 * \??\D:\test\file2[0]
61 * !\??\D:\test\file2_renamed[0]
62 * [0] <- indicates end of strings
65 * \??\D:\test\file1[0]
66 * !\??\D:\test\file1_renamed[0]
67 * \??\D:\Test|delete[0]
68 * [0] <- file is to be deleted, second string empty
69 * [0] <- indicates end of strings
72 static BOOL
add_boot_rename_entry( LPCWSTR source
, LPCWSTR dest
, DWORD flags
)
74 static const WCHAR ValueName
[] = {'P','e','n','d','i','n','g',
75 'F','i','l','e','R','e','n','a','m','e',
76 'O','p','e','r','a','t','i','o','n','s',0};
78 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager");
80 static const int info_size
= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
82 OBJECT_ATTRIBUTES ObjectAttributes
;
83 UNICODE_STRING nameW
, source_name
, dest_name
;
84 KEY_VALUE_PARTIAL_INFORMATION
*info
;
94 TRACE("add_boot_rename_entry( %S, %S, %d ) \n", source
, dest
, flags
);
97 DestLen
= wcslen(dest
);
99 if (!RtlDosPathNameToNtPathName_U( source
, &source_name
, NULL
, NULL
))
101 SetLastError( ERROR_PATH_NOT_FOUND
);
104 dest_name
.Buffer
= NULL
;
105 if (DestLen
&& !RtlDosPathNameToNtPathName_U( dest
, &dest_name
, NULL
, NULL
))
107 RtlFreeHeap( RtlGetProcessHeap(), 0, source_name
.Buffer
);
108 SetLastError( ERROR_PATH_NOT_FOUND
);
112 InitializeObjectAttributes(&ObjectAttributes
,
114 OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
118 Status
= NtCreateKey(&Reboot
,
119 KEY_QUERY_VALUE
| KEY_SET_VALUE
,
123 REG_OPTION_NON_VOLATILE
,
126 if (Status
== STATUS_ACCESS_DENIED
)
128 Status
= NtCreateKey(
130 KEY_QUERY_VALUE
| KEY_SET_VALUE
,
134 REG_OPTION_BACKUP_RESTORE
,
138 if (!NT_SUCCESS(Status
))
140 WARN("NtCreateKey() failed (Status 0x%lx)\n", Status
);
141 if (source_name
.Buffer
)
142 RtlFreeHeap(RtlGetProcessHeap(), 0, source_name
.Buffer
);
143 if (dest_name
.Buffer
)
144 RtlFreeHeap(RtlGetProcessHeap(), 0, dest_name
.Buffer
);
148 len1
= source_name
.Length
+ sizeof(WCHAR
);
151 len2
= dest_name
.Length
+ sizeof(WCHAR
);
152 if (flags
& MOVEFILE_REPLACE_EXISTING
)
153 len2
+= sizeof(WCHAR
); /* Plus 1 because of the leading '!' */
157 len2
= sizeof(WCHAR
); /* minimum is the 0 characters for the empty second string */
160 RtlInitUnicodeString( &nameW
, ValueName
);
162 /* First we check if the key exists and if so how many bytes it already contains. */
163 Status
= NtQueryValueKey(
166 KeyValuePartialInformation
,
170 if ((Status
== STATUS_BUFFER_OVERFLOW
) ||
171 (Status
== STATUS_BUFFER_TOO_SMALL
))
173 if (!(Buffer
= HeapAlloc(GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
))))
175 Status
= NtQueryValueKey(Reboot
, &nameW
, KeyValuePartialInformation
,
176 Buffer
, DataSize
, &DataSize
);
177 if(!NT_SUCCESS(Status
))
179 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)Buffer
;
180 if (info
->Type
!= REG_MULTI_SZ
) goto Quit
;
181 if (DataSize
> sizeof(info
)) DataSize
-= sizeof(WCHAR
); /* remove terminating null (will be added back later) */
185 DataSize
= info_size
;
186 if (!(Buffer
= HeapAlloc( GetProcessHeap(), 0, DataSize
+ len1
+ len2
+ sizeof(WCHAR
) )))
190 memcpy( Buffer
+ DataSize
, source_name
.Buffer
, len1
);
192 p
= (WCHAR
*)(Buffer
+ DataSize
);
195 if (flags
& MOVEFILE_REPLACE_EXISTING
)
197 memcpy( p
, dest_name
.Buffer
, len2
);
203 DataSize
+= sizeof(WCHAR
);
207 p
= (WCHAR
*)(Buffer
+ DataSize
);
209 DataSize
+= sizeof(WCHAR
);
211 rc
= NT_SUCCESS(NtSetValueKey(Reboot
, &nameW
, 0, REG_MULTI_SZ
, Buffer
+ info_size
, DataSize
- info_size
));
214 RtlFreeHeap(RtlGetProcessHeap(), 0, source_name
.Buffer
);
215 if (dest_name
.Buffer
)
216 RtlFreeHeap(RtlGetProcessHeap(), 0, dest_name
.Buffer
);
219 HeapFree(GetProcessHeap(), 0, Buffer
);
229 MoveFileWithProgressW (
230 LPCWSTR lpExistingFileName
,
231 LPCWSTR lpNewFileName
,
232 LPPROGRESS_ROUTINE lpProgressRoutine
,
237 HANDLE hFile
= NULL
, hNewFile
= NULL
;
238 IO_STATUS_BLOCK IoStatusBlock
;
239 OBJECT_ATTRIBUTES ObjectAttributes
;
240 PFILE_RENAME_INFORMATION FileRename
;
243 UNICODE_STRING DstPathU
;
246 TRACE("MoveFileWithProgressW()\n");
248 if (dwFlags
& MOVEFILE_DELAY_UNTIL_REBOOT
)
249 return add_boot_rename_entry( lpExistingFileName
, lpNewFileName
, dwFlags
);
251 // if (dwFlags & MOVEFILE_WRITE_THROUGH)
252 // FIXME("MOVEFILE_WRITE_THROUGH unimplemented\n");
255 return DeleteFileW(lpExistingFileName
);
257 /* validate & translate the filename */
258 if (!RtlDosPathNameToNtPathName_U (lpNewFileName
,
263 WARN("Invalid destination path\n");
264 SetLastError(ERROR_PATH_NOT_FOUND
);
268 InitializeObjectAttributes(&ObjectAttributes
,
270 OBJ_CASE_INSENSITIVE
,
274 errCode
= NtOpenFile( &hNewFile
,
275 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
279 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
|
280 ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0) );
282 if (NT_SUCCESS(errCode
)) /* Destination exists */
286 if (!(dwFlags
& MOVEFILE_REPLACE_EXISTING
))
288 SetLastError(ERROR_ALREADY_EXISTS
);
291 else if (GetFileAttributesW(lpNewFileName
) & FILE_ATTRIBUTE_DIRECTORY
)
293 SetLastError(ERROR_ACCESS_DENIED
);
298 hFile
= CreateFileW (lpExistingFileName
,
300 FILE_SHARE_WRITE
|FILE_SHARE_READ
,
303 FILE_FLAG_BACKUP_SEMANTICS
|
304 ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_FLAG_WRITE_THROUGH
: 0),
307 if (hFile
== INVALID_HANDLE_VALUE
)
312 FileRename
= RtlAllocateHeap(
315 sizeof(FILE_RENAME_INFORMATION
) + DstPathU
.Length
);
318 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
321 if( dwFlags
& MOVEFILE_REPLACE_EXISTING
) {
322 FileRename
->ReplaceIfExists
= TRUE
;
325 FileRename
->ReplaceIfExists
= FALSE
;
329 memcpy(FileRename
->FileName
, DstPathU
.Buffer
, DstPathU
.Length
);
330 RtlFreeHeap (RtlGetProcessHeap (),
334 FileRename
->FileNameLength
= DstPathU
.Length
;
335 errCode
= NtSetInformationFile (hFile
,
338 sizeof(FILE_RENAME_INFORMATION
) + DstPathU
.Length
,
339 FileRenameInformation
);
341 RtlFreeHeap(RtlGetProcessHeap(), 0, FileRename
);
343 if (GetFileAttributesW(lpExistingFileName
) & FILE_ATTRIBUTE_DIRECTORY
)
351 * Fail now move the folder
352 * Before we fail at CreateFileW
356 if (NT_SUCCESS(errCode
))
364 Result
= CopyFileExW (lpExistingFileName
,
369 (dwFlags
& MOVEFILE_REPLACE_EXISTING
) ? 0 : COPY_FILE_FAIL_IF_EXISTS
);
372 /* Cleanup the source file */
373 Result
= DeleteFileW (lpExistingFileName
);
378 /* move folder code start */
379 WIN32_FIND_DATAW findBuffer
;
380 LPWSTR lpExistingFileName2
= NULL
;
381 LPWSTR lpNewFileName2
= NULL
;
382 LPWSTR lpDeleteFile
= NULL
;
387 INT max_size
= MAX_PATH
;
390 /* Build the string */
391 size
= wcslen(lpExistingFileName
);
392 if (size
+6> max_size
)
395 lpDeleteFile
= (LPWSTR
) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,max_size
* sizeof(WCHAR
));
396 if (lpDeleteFile
== NULL
)
399 lpNewFileName2
= (LPWSTR
) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,max_size
* sizeof(WCHAR
));
400 if (lpNewFileName2
== NULL
)
402 HeapFree(GetProcessHeap(),0,(VOID
*) lpDeleteFile
);
406 lpExistingFileName2
= (LPWSTR
) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,max_size
* sizeof(WCHAR
));
407 if (lpExistingFileName2
== NULL
)
409 HeapFree(GetProcessHeap(),0,(VOID
*) lpNewFileName2
);
410 HeapFree(GetProcessHeap(),0,(VOID
*) lpDeleteFile
);
414 wcscpy( (WCHAR
*)lpExistingFileName2
,lpExistingFileName
);
415 wcscpy( (WCHAR
*)&lpExistingFileName2
[size
],L
"\\*.*\0");
417 /* Get the file name */
418 memset(&findBuffer
,0,sizeof(WIN32_FIND_DATAW
));
419 hFile
= FindFirstFileW(lpExistingFileName2
, &findBuffer
);
420 if (hFile
== INVALID_HANDLE_VALUE
)
423 if (findBuffer
.cFileName
[0] == L
'\0')
428 * remove readonly flag from source folder and do not set the readonly flag to dest folder
430 RemoveReadOnlyAttributeW(lpExistingFileName
);
431 RemoveReadOnlyAttributeW(lpNewFileName
);
432 //CreateDirectoryExW(lpExistingFileName,lpNewFileName,NULL);
433 CreateDirectoryW(lpNewFileName
, NULL
);
435 /* search the files/folders and move them */
440 if ((!wcscmp(findBuffer
.cFileName
,L
"..")) || (!wcscmp(findBuffer
.cFileName
,L
".")))
442 loop
= FindNextFileW(hFile
, &findBuffer
);
446 size
= wcslen(lpExistingFileName2
)-4;
448 hFile
= INVALID_HANDLE_VALUE
;
450 wcscpy( &lpExistingFileName2
[size
],L
"\0");
452 if (wcsncmp(lpExistingFileName
,lpExistingFileName2
,size
))
457 TRACE("MoveFileWithProgressW : Delete folder : %S\n",lpDeleteFile
);
459 /* remove system folder flag other wise we can not delete the folder */
460 Attributes
= GetFileAttributesW(lpExistingFileName2
);
461 if (Attributes
!= INVALID_FILE_ATTRIBUTES
)
463 SetFileAttributesW(lpExistingFileName2
,(Attributes
& ~FILE_ATTRIBUTE_SYSTEM
));
466 RemoveReadOnlyAttributeW(lpExistingFileName2
);
468 Result
= RemoveDirectoryW(lpExistingFileName2
);
473 size
= wcslen(lpExistingFileName
);
477 if (lpNewFileName2
!= NULL
)
478 HeapFree(GetProcessHeap(),0,(VOID
*) lpNewFileName2
);
480 if (lpExistingFileName2
!= NULL
)
481 HeapFree(GetProcessHeap(),0,(VOID
*) lpExistingFileName2
);
483 if (lpDeleteFile
!= NULL
)
484 HeapFree(GetProcessHeap(),0,(VOID
*) lpDeleteFile
);
489 wcscpy( lpExistingFileName2
,lpExistingFileName
);
490 wcscpy( &lpExistingFileName2
[size
],L
"\\*.*\0");
492 /* Get the file name */
493 memset(&findBuffer
,0,sizeof(WIN32_FIND_DATAW
));
494 hFile
= FindFirstFileW(lpExistingFileName2
, &findBuffer
);
500 if (findBuffer
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
503 /* Build the new src string */
504 size
= wcslen(findBuffer
.cFileName
);
505 size2
= wcslen(lpExistingFileName2
);
507 if (size2
+size
+6>max_size
)
511 if (lpNewFileName2
!= NULL
)
512 HeapFree(GetProcessHeap(),0,(VOID
*) lpNewFileName2
);
514 if (lpExistingFileName2
!= NULL
)
515 HeapFree(GetProcessHeap(),0,(VOID
*) lpExistingFileName2
);
517 if (lpDeleteFile
!= NULL
)
518 HeapFree(GetProcessHeap(),0,(VOID
*) lpDeleteFile
);
523 wcscpy( &lpExistingFileName2
[size2
-3],findBuffer
.cFileName
);
524 wcscpy( &lpExistingFileName2
[size2
+size
-3],L
"\0");
528 wcscpy( lpDeleteFile
,lpExistingFileName2
);
529 wcscpy( &lpExistingFileName2
[size2
+size
-3],L
"\\*.*\0");
532 /* Build the new dst string */
533 size
= wcslen(lpExistingFileName2
) + wcslen(lpNewFileName
);
534 size2
= wcslen(lpExistingFileName
);
540 if (lpNewFileName2
!= NULL
)
541 HeapFree(GetProcessHeap(),0,(VOID
*) lpNewFileName2
);
543 if (lpExistingFileName2
!= NULL
)
544 HeapFree(GetProcessHeap(),0,(VOID
*) lpExistingFileName2
);
546 if (lpDeleteFile
!= NULL
)
547 HeapFree(GetProcessHeap(),0,(VOID
*) lpDeleteFile
);
552 wcscpy( lpNewFileName2
,lpNewFileName
);
553 size
= wcslen(lpNewFileName
);
554 wcscpy( &lpNewFileName2
[size
], &lpExistingFileName2
[size2
]);
555 size
= wcslen(lpNewFileName2
);
556 wcscpy( &lpNewFileName2
[size
-4],L
"\0");
561 * remove readonly flag from source folder and do not set the readonly flag to dest folder
563 RemoveReadOnlyAttributeW(lpDeleteFile
);
564 RemoveReadOnlyAttributeW(lpNewFileName2
);
566 CreateDirectoryW(lpNewFileName2
,NULL
);
567 //CreateDirectoryExW(lpDeleteFile, lpNewFileName2,NULL);
570 /* set new search path from src string */
572 memset(&findBuffer
,0,sizeof(WIN32_FIND_DATAW
));
573 hFile
= FindFirstFileW(lpExistingFileName2
, &findBuffer
);
578 /* Build the new string */
579 size
= wcslen(findBuffer
.cFileName
);
580 size2
= wcslen(lpExistingFileName2
);
581 wcscpy( lpDeleteFile
,lpExistingFileName2
);
582 wcscpy( &lpDeleteFile
[size2
-3],findBuffer
.cFileName
);
584 /* Build dest string */
585 size
= wcslen(lpDeleteFile
) + wcslen(lpNewFileName
);
586 size2
= wcslen(lpExistingFileName
);
592 if (lpNewFileName2
!= NULL
)
593 HeapFree(GetProcessHeap(),0,(VOID
*) lpNewFileName2
);
595 if (lpExistingFileName2
!= NULL
)
596 HeapFree(GetProcessHeap(),0,(VOID
*) lpExistingFileName2
);
598 if (lpDeleteFile
!= NULL
)
599 HeapFree(GetProcessHeap(),0,(VOID
*) lpDeleteFile
);
604 wcscpy( lpNewFileName2
,lpNewFileName
);
605 size
= wcslen(lpNewFileName
);
606 wcscpy(&lpNewFileName2
[size
],&lpDeleteFile
[size2
]);
609 /* overrite existsen file, if the file got the flag have readonly
610 * we need reomve that flag
615 TRACE("MoveFileWithProgressW : Copy file : %S to %S\n",lpDeleteFile
, lpNewFileName2
);
616 RemoveReadOnlyAttributeW(lpDeleteFile
);
617 RemoveReadOnlyAttributeW(lpNewFileName2
);
619 Result
= CopyFileExW (lpDeleteFile
,
630 TRACE("MoveFileWithProgressW : remove readonly flag from file : %S\n",lpNewFileName2
);
631 Result
= RemoveReadOnlyAttributeW(lpDeleteFile
);
635 TRACE("MoveFileWithProgressW : Delete file : %S\n",lpDeleteFile
);
636 Result
= DeleteFileW(lpDeleteFile
);
641 loop
= FindNextFileW(hFile
, &findBuffer
);
645 /* Remove last folder */
646 if ((loop
== FALSE
) && (Result
!= FALSE
))
650 Attributes
= GetFileAttributesW(lpDeleteFile
);
651 if (Attributes
!= INVALID_FILE_ATTRIBUTES
)
653 SetFileAttributesW(lpDeleteFile
,(Attributes
& ~FILE_ATTRIBUTE_SYSTEM
));
656 Result
= RemoveDirectoryW(lpExistingFileName
);
662 if (lpNewFileName2
!= NULL
)
664 HeapFree(GetProcessHeap(),0,(VOID
*) lpNewFileName2
);
665 lpNewFileName2
= NULL
;
668 if (lpExistingFileName2
!= NULL
)
670 HeapFree(GetProcessHeap(),0,(VOID
*) lpExistingFileName2
);
671 lpExistingFileName2
= NULL
;
674 if (lpDeleteFile
!= NULL
)
676 HeapFree(GetProcessHeap(),0,(VOID
*) lpDeleteFile
);
682 // end move folder code
696 MoveFileWithProgressA (
697 LPCSTR lpExistingFileName
,
698 LPCSTR lpNewFileName
,
699 LPPROGRESS_ROUTINE lpProgressRoutine
,
704 PWCHAR ExistingFileNameW
;
708 if (!(ExistingFileNameW
= FilenameA2W(lpExistingFileName
, FALSE
)))
711 if (!(NewFileNameW
= FilenameA2W(lpNewFileName
, TRUE
)))
714 ret
= MoveFileWithProgressW (ExistingFileNameW
,
720 RtlFreeHeap (RtlGetProcessHeap (), 0, NewFileNameW
);
732 LPCWSTR lpExistingFileName
,
733 LPCWSTR lpNewFileName
736 return MoveFileExW (lpExistingFileName
,
738 MOVEFILE_COPY_ALLOWED
);
748 LPCWSTR lpExistingFileName
,
749 LPCWSTR lpNewFileName
,
753 return MoveFileWithProgressW (lpExistingFileName
,
767 LPCSTR lpExistingFileName
,
771 return MoveFileExA (lpExistingFileName
,
773 MOVEFILE_COPY_ALLOWED
);
783 LPCSTR lpExistingFileName
,
784 LPCSTR lpNewFileName
,
788 return MoveFileWithProgressA (lpExistingFileName
,
801 LPCSTR lpReplacedFileName
,
802 LPCSTR lpReplacementFileName
,
803 LPCSTR lpBackupFileName
,
804 DWORD dwReplaceFlags
,
809 WCHAR
*replacedW
, *replacementW
, *backupW
= NULL
;
812 /* This function only makes sense when the first two parameters are defined */
813 if (!lpReplacedFileName
|| !(replacedW
= FilenameA2W(lpReplacedFileName
, TRUE
)))
815 SetLastError(ERROR_INVALID_PARAMETER
);
819 if (!lpReplacementFileName
|| !(replacementW
= FilenameA2W(lpReplacementFileName
, TRUE
)))
821 HeapFree(GetProcessHeap(), 0, replacedW
);
822 SetLastError(ERROR_INVALID_PARAMETER
);
826 /* The backup parameter, however, is optional */
827 if (lpBackupFileName
)
829 if (!(backupW
= FilenameA2W(lpBackupFileName
, TRUE
)))
831 HeapFree(GetProcessHeap(), 0, replacedW
);
832 HeapFree(GetProcessHeap(), 0, replacementW
);
833 SetLastError(ERROR_INVALID_PARAMETER
);
838 ret
= ReplaceFileW(replacedW
, replacementW
, backupW
, dwReplaceFlags
, lpExclude
, lpReserved
);
839 HeapFree(GetProcessHeap(), 0, replacedW
);
840 HeapFree(GetProcessHeap(), 0, replacementW
);
841 HeapFree(GetProcessHeap(), 0, backupW
);
852 LPCWSTR lpReplacedFileName
,
853 LPCWSTR lpReplacementFileName
,
854 LPCWSTR lpBackupFileName
,
855 DWORD dwReplaceFlags
,
860 HANDLE hReplaced
= NULL
, hReplacement
= NULL
;
861 UNICODE_STRING NtReplacedName
= { 0, 0, NULL
};
862 UNICODE_STRING NtReplacementName
= { 0, 0, NULL
};
863 DWORD Error
= ERROR_SUCCESS
;
866 IO_STATUS_BLOCK IoStatusBlock
;
867 OBJECT_ATTRIBUTES ObjectAttributes
;
868 PVOID Buffer
= NULL
;
871 FIXME("Ignoring flags %x\n", dwReplaceFlags
);
873 /* First two arguments are mandatory */
874 if (!lpReplacedFileName
|| !lpReplacementFileName
)
876 SetLastError(ERROR_INVALID_PARAMETER
);
883 if(!CopyFileW(lpReplacedFileName
, lpBackupFileName
, FALSE
))
885 Error
= GetLastError();
890 /* Open the "replaced" file for reading and writing */
891 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName
, &NtReplacedName
, NULL
, NULL
)))
893 Error
= ERROR_PATH_NOT_FOUND
;
897 InitializeObjectAttributes(&ObjectAttributes
,
899 OBJ_CASE_INSENSITIVE
,
903 Status
= NtOpenFile(&hReplaced
,
904 GENERIC_READ
| GENERIC_WRITE
| DELETE
| SYNCHRONIZE
| WRITE_DAC
,
907 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
908 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
910 if (!NT_SUCCESS(Status
))
912 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
913 Error
= ERROR_FILE_NOT_FOUND
;
915 Error
= ERROR_UNABLE_TO_REMOVE_REPLACED
;
920 SetEndOfFile(hReplaced
) ;
923 * Open the replacement file for reading, writing, and deleting
924 * (deleting is needed when finished)
926 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName
, &NtReplacementName
, NULL
, NULL
)))
928 Error
= ERROR_PATH_NOT_FOUND
;
932 InitializeObjectAttributes(&ObjectAttributes
,
934 OBJ_CASE_INSENSITIVE
,
938 Status
= NtOpenFile(&hReplacement
,
939 GENERIC_READ
| DELETE
| SYNCHRONIZE
,
943 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
| FILE_DELETE_ON_CLOSE
);
945 if (!NT_SUCCESS(Status
))
947 Error
= RtlNtStatusToDosError(Status
);
951 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 0x10000) ;
954 Error
= ERROR_NOT_ENOUGH_MEMORY
;
957 while (Status
!= STATUS_END_OF_FILE
)
959 Status
= NtReadFile(hReplacement
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
, 0x10000, NULL
, NULL
) ;
960 if (NT_SUCCESS(Status
))
962 Status
= NtWriteFile(hReplaced
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
,
963 IoStatusBlock
.Information
, NULL
, NULL
) ;
964 if (!NT_SUCCESS(Status
))
966 Error
= RtlNtStatusToDosError(Status
);
970 else if (Status
!= STATUS_END_OF_FILE
)
972 Error
= RtlNtStatusToDosError(Status
);
979 /* Perform resource cleanup */
981 if (hReplaced
) NtClose(hReplaced
);
982 if (hReplacement
) NtClose(hReplacement
);
983 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
985 if (NtReplacementName
.Buffer
)
986 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName
.Buffer
);
987 if (NtReplacedName
.Buffer
)
988 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName
.Buffer
);
990 /* If there was an error, set the error code */
993 TRACE("ReplaceFileW failed (error=%d)\n", Error
);
1004 PrivMoveFileIdentityW(DWORD Unknown1
, DWORD Unknown2
, DWORD Unknown3
)