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)
9 * Pierre Schweitzer (pierre@reactos.org)
13 * Fix some bugs in the add_boot_rename_entry function
16 /* INCLUDES *****************************************************************/
23 DEBUG_CHANNEL(kernel32file
);
25 /* GLOBALS *****************************************************************/
27 /* DEFINES *****************************************************************/
28 typedef struct _COPY_PROGRESS_CONTEXT
31 LPPROGRESS_ROUTINE UserRoutine
;
33 } COPY_PROGRESS_CONTEXT
, *PCOPY_PROGRESS_CONTEXT
;
35 /* FUNCTIONS ****************************************************************/
41 BasepMoveFileDelayed(IN PUNICODE_STRING ExistingPath
,
42 IN PUNICODE_STRING NewPath
,
44 IN BOOL CreateIfNotFound
)
46 #define STRING_LENGTH 0x400
49 PVOID Buffer
, BufferBegin
;
50 OBJECT_ATTRIBUTES ObjectAttributes
;
51 PWSTR PendingOperations
, BufferWrite
;
52 ULONG DataSize
, BufferLength
, StringLength
= STRING_LENGTH
;
53 UNICODE_STRING SessionManagerString
, PendingOperationsString
;
54 /* +6 because a INT shouldn't take more than 6 chars. Especially given the call path */
55 WCHAR PendingOperationsBuffer
[sizeof(L
"PendingFileRenameOperations") / sizeof(WCHAR
) + 6];
57 RtlInitUnicodeString(&SessionManagerString
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager");
59 /* Select appropriate key for adding our file */
62 PendingOperations
= L
"PendingFileRenameOperations";
66 HRESULT hr
= StringCbPrintfW(PendingOperationsBuffer
, sizeof(PendingOperationsBuffer
), L
"PendingFileRenameOperations%d", KeyId
);
67 ASSERT(SUCCEEDED(hr
));
68 PendingOperations
= PendingOperationsBuffer
;
70 RtlInitUnicodeString(&PendingOperationsString
, PendingOperations
);
72 InitializeObjectAttributes(&ObjectAttributes
,
73 &SessionManagerString
,
74 OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
78 Status
= NtCreateKey(&KeyHandle
,
79 GENERIC_READ
| GENERIC_WRITE
,
80 &ObjectAttributes
, 0, NULL
,
81 REG_OPTION_NON_VOLATILE
, NULL
);
82 if (Status
== STATUS_ACCESS_DENIED
)
84 Status
= NtCreateKey(&KeyHandle
,
85 GENERIC_READ
| GENERIC_WRITE
,
86 &ObjectAttributes
, 0, NULL
,
87 REG_OPTION_BACKUP_RESTORE
, NULL
);
90 if (!NT_SUCCESS(Status
))
95 /* Reserve enough to read previous string + to append our with required null chars */
96 BufferLength
= NewPath
->Length
+ ExistingPath
->Length
+ STRING_LENGTH
+ 3 * sizeof(WCHAR
);
97 /* Check we didn't overflow */
98 if (BufferLength
< STRING_LENGTH
)
101 return STATUS_BUFFER_TOO_SMALL
;
106 /* Allocate output buffer */
107 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength
);
111 return STATUS_NO_MEMORY
;
114 Status
= NtQueryValueKey(KeyHandle
,
115 &PendingOperationsString
,
116 KeyValuePartialInformation
,
117 Buffer
, StringLength
, &DataSize
);
118 if (Status
!= STATUS_BUFFER_OVERFLOW
)
123 /* If buffer was too small, then, reallocate one which is big enough */
124 StringLength
= DataSize
;
125 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
126 BufferLength
= ExistingPath
->Length
+ StringLength
+ NewPath
->Length
+ 3 * sizeof(WCHAR
);
127 if (BufferLength
< StringLength
)
130 return STATUS_BUFFER_TOO_SMALL
;
134 /* Check if it existed - if not, create only IF asked to */
135 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
|| !CreateIfNotFound
))
138 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
142 if (!NT_SUCCESS(Status
))
144 /* We didn't find any - ie, we create, so use complete buffer */
145 BufferBegin
= Buffer
;
146 BufferWrite
= Buffer
;
150 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
152 /* Get data, our buffer begin and then where we should append data (+ null char) */
153 BufferBegin
= PartialInfo
->Data
;
154 BufferWrite
= (PWSTR
)((ULONG_PTR
)PartialInfo
->Data
+ PartialInfo
->DataLength
+ sizeof(WCHAR
));
157 /* First copy existing */
158 RtlCopyMemory(BufferWrite
, ExistingPath
->Buffer
, ExistingPath
->Length
);
159 BufferWrite
+= ExistingPath
->Length
/ sizeof(WCHAR
);
160 /* And append null char */
161 *BufferWrite
= UNICODE_NULL
;
163 /* Append destination */
164 RtlCopyMemory(BufferWrite
, NewPath
->Buffer
, NewPath
->Length
);
165 BufferWrite
+= NewPath
->Length
/ sizeof(WCHAR
);
166 /* And append two null char (end of string) */
167 *BufferWrite
= UNICODE_NULL
;
169 *BufferWrite
= UNICODE_NULL
;
172 Status
= NtSetValueKey(KeyHandle
,
173 &PendingOperationsString
,
174 0, REG_MULTI_SZ
, BufferBegin
,
175 (ULONG_PTR
)BufferWrite
- (ULONG_PTR
)BufferBegin
+ sizeof(WCHAR
));
178 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
189 BasepNotifyTrackingService(IN PHANDLE ExistingHandle
,
190 IN POBJECT_ATTRIBUTES ObjectAttributes
,
192 IN PUNICODE_STRING NewPath
)
194 return STATUS_NOT_IMPLEMENTED
;
203 BasepMoveFileCopyProgress(IN LARGE_INTEGER TotalFileSize
,
204 IN LARGE_INTEGER TotalBytesTransferred
,
205 IN LARGE_INTEGER StreamSize
,
206 IN LARGE_INTEGER StreamBytesTransferred
,
207 IN DWORD dwStreamNumber
,
208 IN DWORD dwCallbackReason
,
209 IN HANDLE hSourceFile
,
210 IN HANDLE hDestinationFile
,
211 IN LPVOID lpData OPTIONAL
)
214 PCOPY_PROGRESS_CONTEXT Context
= (PCOPY_PROGRESS_CONTEXT
)lpData
;
216 if (Context
->Flags
& MOVEFILE_WRITE_THROUGH
)
218 if (!dwCallbackReason
)
220 if (StreamBytesTransferred
.QuadPart
== StreamSize
.QuadPart
)
222 FlushFileBuffers(hDestinationFile
);
227 if (Context
->UserRoutine
)
229 Ret
= Context
->UserRoutine(TotalFileSize
,
230 TotalBytesTransferred
,
232 StreamBytesTransferred
,
249 MoveFileWithProgressW(IN LPCWSTR lpExistingFileName
,
250 IN LPCWSTR lpNewFileName
,
251 IN LPPROGRESS_ROUTINE lpProgressRoutine
,
257 IO_STATUS_BLOCK IoStatusBlock
;
258 COPY_PROGRESS_CONTEXT CopyContext
;
259 OBJECT_ATTRIBUTES ObjectAttributes
;
260 PFILE_RENAME_INFORMATION RenameInfo
;
261 UNICODE_STRING NewPathU
, ExistingPathU
;
262 FILE_ATTRIBUTE_TAG_INFORMATION FileAttrTagInfo
;
263 HANDLE SourceHandle
= INVALID_HANDLE_VALUE
, NewHandle
, ExistingHandle
;
264 BOOL Ret
= FALSE
, ReplaceIfExists
, DelayUntilReboot
, AttemptReopenWithoutReparse
;
266 DPRINT("MoveFileWithProgressW(%S, %S, %p, %p, %x)\n", lpExistingFileName
, lpNewFileName
, lpProgressRoutine
, lpData
, dwFlags
);
268 NewPathU
.Buffer
= NULL
;
269 ExistingPathU
.Buffer
= NULL
;
273 /* Don't allow renaming to a disk */
274 if (lpNewFileName
&& RtlIsDosDeviceName_U(lpNewFileName
))
276 BaseSetLastNTError(STATUS_OBJECT_NAME_COLLISION
);
280 ReplaceIfExists
= !!(dwFlags
& MOVEFILE_REPLACE_EXISTING
);
283 if (!RtlDosPathNameToNtPathName_U(lpExistingFileName
, &ExistingPathU
, NULL
, NULL
))
285 BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND
);
290 DelayUntilReboot
= !!(dwFlags
& MOVEFILE_DELAY_UNTIL_REBOOT
);
291 if (DelayUntilReboot
&& (dwFlags
& MOVEFILE_CREATE_HARDLINK
))
293 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
297 /* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
298 AttemptReopenWithoutReparse
= TRUE
;
299 InitializeObjectAttributes(&ObjectAttributes
,
301 OBJ_CASE_INSENSITIVE
,
304 /* Attempt to open source file */
305 Status
= NtOpenFile(&SourceHandle
,
306 FILE_READ_ATTRIBUTES
| DELETE
| SYNCHRONIZE
,
309 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
310 FILE_OPEN_FOR_BACKUP_INTENT
| ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0));
311 if (!NT_SUCCESS(Status
))
313 /* If we failed and the file doesn't exist, don't attempt to reopen without reparse */
314 if (DelayUntilReboot
&&
315 (Status
== STATUS_SHARING_VIOLATION
|| Status
== STATUS_OBJECT_NAME_NOT_FOUND
|| Status
== STATUS_OBJECT_PATH_NOT_FOUND
))
317 /* Here we don't fail completely, as we postpone the operation to reboot
318 * File might exist afterwards, and we don't need a handle here
320 SourceHandle
= INVALID_HANDLE_VALUE
;
321 AttemptReopenWithoutReparse
= FALSE
;
323 /* If we failed for any reason than unsupported reparse, fail completely */
324 else if (Status
!= STATUS_INVALID_PARAMETER
)
326 BaseSetLastNTError(Status
);
332 /* We managed to open, so query information */
333 Status
= NtQueryInformationFile(SourceHandle
,
336 sizeof(FILE_ATTRIBUTE_TAG_INFORMATION
),
337 FileAttributeTagInformation
);
338 if (!NT_SUCCESS(Status
))
340 /* Do not tolerate any other error than something related to not supported operation */
341 if (Status
!= STATUS_NOT_IMPLEMENTED
&& Status
!= STATUS_INVALID_PARAMETER
)
343 BaseSetLastNTError(Status
);
347 /* Not a reparse point, no need to reopen, it's fine */
348 AttemptReopenWithoutReparse
= FALSE
;
350 /* Validate the reparse point (do we support it?) */
351 else if (FileAttrTagInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
&&
352 FileAttrTagInfo
.ReparseTag
!= IO_REPARSE_TAG_MOUNT_POINT
)
354 NtClose(SourceHandle
);
355 SourceHandle
= INVALID_HANDLE_VALUE
;
359 /* Simply reopen if required */
360 if (AttemptReopenWithoutReparse
)
362 Status
= NtOpenFile(&SourceHandle
,
363 DELETE
| SYNCHRONIZE
,
366 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
367 ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0));
368 if (!NT_SUCCESS(Status
))
370 BaseSetLastNTError(Status
);
375 /* Nullify string if we're to use it */
376 if (DelayUntilReboot
&& !lpNewFileName
)
378 RtlInitUnicodeString(&NewPathU
, 0);
380 /* Check whether path exists */
381 else if (!RtlDosPathNameToNtPathName_U(lpNewFileName
, &NewPathU
, 0, 0))
383 BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND
);
387 /* Handle postponed renaming */
388 if (DelayUntilReboot
)
390 /* If new file exists and we're allowed to replace, then mark the path with ! */
391 if (ReplaceIfExists
&& NewPathU
.Length
)
393 NewBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU
.Length
+ sizeof(WCHAR
));
394 if (NewBuffer
== NULL
)
396 BaseSetLastNTError(STATUS_NO_MEMORY
);
401 RtlCopyMemory(&NewBuffer
[1], NewPathU
.Buffer
, NewPathU
.Length
);
402 NewPathU
.Length
+= sizeof(WCHAR
);
403 NewPathU
.MaximumLength
+= sizeof(WCHAR
);
404 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU
.Buffer
);
405 NewPathU
.Buffer
= NewBuffer
;
408 /* Check whether 'copy' renaming is allowed if required */
409 if (RtlDetermineDosPathNameType_U(lpExistingFileName
) == RtlPathTypeUncAbsolute
|| dwFlags
& MOVEFILE_COPY_ALLOWED
)
411 Status
= STATUS_INVALID_PARAMETER
;
415 /* First, probe 2nd key to see whether it exists - if so, it will be appended there */
416 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 2, FALSE
);
417 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
419 /* If doesn't exist, append to first key first, creating it if it doesn't exist */
420 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 1, TRUE
);
422 if (Status
== STATUS_INSUFFICIENT_RESOURCES
)
424 /* If it failed because it's too big, then create 2nd key and put it there */
425 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 2, TRUE
);
430 /* If we failed at some point, return the error */
431 if (!NT_SUCCESS(Status
))
433 BaseSetLastNTError(Status
);
441 /* At that point, we MUST have a source handle */
442 ASSERT(SourceHandle
!= INVALID_HANDLE_VALUE
);
444 /* Allocate renaming buffer and fill it */
445 RenameInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU
.Length
+ sizeof(FILE_RENAME_INFORMATION
));
446 if (RenameInfo
== NULL
)
448 BaseSetLastNTError(STATUS_NO_MEMORY
);
452 RtlCopyMemory(&RenameInfo
->FileName
, NewPathU
.Buffer
, NewPathU
.Length
);
453 RenameInfo
->ReplaceIfExists
= ReplaceIfExists
;
454 RenameInfo
->RootDirectory
= 0;
455 RenameInfo
->FileNameLength
= NewPathU
.Length
;
457 /* Attempt to rename the file */
458 Status
= NtSetInformationFile(SourceHandle
,
461 NewPathU
.Length
+ sizeof(FILE_RENAME_INFORMATION
),
462 ((dwFlags
& MOVEFILE_CREATE_HARDLINK
) ? FileLinkInformation
: FileRenameInformation
));
463 RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo
);
464 if (NT_SUCCESS(Status
))
466 /* If it succeed, all fine, quit */
470 /* If we failed for any other reason than not the same device, fail
471 * If we failed because of different devices, only allow renaming if user allowed copy
473 if (Status
!= STATUS_NOT_SAME_DEVICE
|| !(dwFlags
& MOVEFILE_COPY_ALLOWED
))
475 /* ReactOS hack! To be removed once all FSD have proper renaming support
476 * Just leave status to error and leave
478 if (Status
== STATUS_NOT_IMPLEMENTED
)
480 DPRINT1("Forcing copy, renaming not supported by FSD\n");
484 BaseSetLastNTError(Status
);
489 /* Close source file */
490 NtClose(SourceHandle
);
491 SourceHandle
= INVALID_HANDLE_VALUE
;
493 /* Issue the copy of the file */
494 CopyContext
.Flags
= dwFlags
;
495 CopyContext
.UserRoutine
= lpProgressRoutine
;
496 CopyContext
.UserData
= lpData
;
497 NewHandle
= INVALID_HANDLE_VALUE
;
498 ExistingHandle
= INVALID_HANDLE_VALUE
;
500 Ret
= BasepCopyFileExW(lpExistingFileName
,
502 BasepMoveFileCopyProgress
,
505 (ReplaceIfExists
== 0) | COPY_FILE_OPEN_SOURCE_FOR_WRITE
,
511 /* If it failed, don't leak any handle */
512 if (ExistingHandle
!= INVALID_HANDLE_VALUE
)
514 CloseHandle(ExistingHandle
);
515 ExistingHandle
= INVALID_HANDLE_VALUE
;
518 else if (ExistingHandle
!= INVALID_HANDLE_VALUE
)
520 if (NewHandle
!= INVALID_HANDLE_VALUE
)
522 /* If copying succeed, notify */
523 Status
= BasepNotifyTrackingService(&ExistingHandle
, &ObjectAttributes
, NewHandle
, &NewPathU
);
524 if (!NT_SUCCESS(Status
))
526 /* Fail in case it had to succeed */
527 if (dwFlags
& MOVEFILE_FAIL_IF_NOT_TRACKABLE
)
529 if (NewHandle
!= INVALID_HANDLE_VALUE
)
530 CloseHandle(NewHandle
);
531 NewHandle
= INVALID_HANDLE_VALUE
;
532 DeleteFileW(lpNewFileName
);
534 BaseSetLastNTError(Status
);
539 CloseHandle(ExistingHandle
);
540 ExistingHandle
= INVALID_HANDLE_VALUE
;
543 /* In case copy worked, close file */
544 if (NewHandle
!= INVALID_HANDLE_VALUE
)
546 CloseHandle(NewHandle
);
547 NewHandle
= INVALID_HANDLE_VALUE
;
550 /* If it succeed, delete source file */
553 if (!DeleteFileW(lpExistingFileName
))
555 /* Reset file attributes if required */
556 SetFileAttributesW(lpExistingFileName
, FILE_ATTRIBUTE_NORMAL
);
557 DeleteFileW(lpExistingFileName
);
563 if (SourceHandle
!= INVALID_HANDLE_VALUE
)
564 NtClose(SourceHandle
);
566 RtlFreeHeap(RtlGetProcessHeap(), 0, ExistingPathU
.Buffer
);
567 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU
.Buffer
);
580 MoveFileWithProgressA(IN LPCSTR lpExistingFileName
,
581 IN LPCSTR lpNewFileName OPTIONAL
,
582 IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL
,
583 IN LPVOID lpData OPTIONAL
,
587 UNICODE_STRING ExistingFileNameW
, NewFileNameW
;
589 if (!Basep8BitStringToDynamicUnicodeString(&ExistingFileNameW
, lpExistingFileName
))
596 if (!Basep8BitStringToDynamicUnicodeString(&NewFileNameW
, lpNewFileName
))
598 RtlFreeUnicodeString(&ExistingFileNameW
);
604 NewFileNameW
.Buffer
= NULL
;
607 Ret
= MoveFileWithProgressW(ExistingFileNameW
.Buffer
, NewFileNameW
.Buffer
, lpProgressRoutine
, lpData
, dwFlags
);
609 RtlFreeUnicodeString(&ExistingFileNameW
);
610 RtlFreeUnicodeString(&NewFileNameW
);
621 MoveFileW(IN LPCWSTR lpExistingFileName
,
622 IN LPCWSTR lpNewFileName
)
624 return MoveFileWithProgressW(lpExistingFileName
,
628 MOVEFILE_COPY_ALLOWED
);
637 MoveFileExW(IN LPCWSTR lpExistingFileName
,
638 IN LPCWSTR lpNewFileName OPTIONAL
,
641 return MoveFileWithProgressW(lpExistingFileName
,
654 MoveFileA(IN LPCSTR lpExistingFileName
,
655 IN LPCSTR lpNewFileName
)
657 return MoveFileWithProgressA(lpExistingFileName
,
661 MOVEFILE_COPY_ALLOWED
);
670 MoveFileExA(IN LPCSTR lpExistingFileName
,
671 IN LPCSTR lpNewFileName OPTIONAL
,
674 return MoveFileWithProgressA(lpExistingFileName
,
686 ReplaceFileA(IN LPCSTR lpReplacedFileName
,
687 IN LPCSTR lpReplacementFileName
,
688 IN LPCSTR lpBackupFileName OPTIONAL
,
689 IN DWORD dwReplaceFlags
,
691 IN LPVOID lpReserved
)
694 UNICODE_STRING ReplacedFileNameW
, ReplacementFileNameW
, BackupFileNameW
;
696 if (!lpReplacedFileName
|| !lpReplacementFileName
|| lpExclude
|| lpReserved
|| dwReplaceFlags
& ~(REPLACEFILE_WRITE_THROUGH
| REPLACEFILE_IGNORE_MERGE_ERRORS
))
698 SetLastError(ERROR_INVALID_PARAMETER
);
702 if (!Basep8BitStringToDynamicUnicodeString(&ReplacedFileNameW
, lpReplacedFileName
))
707 if (!Basep8BitStringToDynamicUnicodeString(&ReplacementFileNameW
, lpReplacementFileName
))
709 RtlFreeUnicodeString(&ReplacedFileNameW
);
713 if (lpBackupFileName
)
715 if (!Basep8BitStringToDynamicUnicodeString(&BackupFileNameW
, lpBackupFileName
))
717 RtlFreeUnicodeString(&ReplacementFileNameW
);
718 RtlFreeUnicodeString(&ReplacedFileNameW
);
724 BackupFileNameW
.Buffer
= NULL
;
727 Ret
= ReplaceFileW(ReplacedFileNameW
.Buffer
, ReplacementFileNameW
.Buffer
, BackupFileNameW
.Buffer
, dwReplaceFlags
, 0, 0);
729 if (lpBackupFileName
)
731 RtlFreeUnicodeString(&BackupFileNameW
);
733 RtlFreeUnicodeString(&ReplacementFileNameW
);
734 RtlFreeUnicodeString(&ReplacedFileNameW
);
745 LPCWSTR lpReplacedFileName
,
746 LPCWSTR lpReplacementFileName
,
747 LPCWSTR lpBackupFileName
,
748 DWORD dwReplaceFlags
,
753 HANDLE hReplaced
= NULL
, hReplacement
= NULL
;
754 UNICODE_STRING NtReplacedName
= { 0, 0, NULL
};
755 UNICODE_STRING NtReplacementName
= { 0, 0, NULL
};
756 DWORD Error
= ERROR_SUCCESS
;
759 IO_STATUS_BLOCK IoStatusBlock
;
760 OBJECT_ATTRIBUTES ObjectAttributes
;
761 PVOID Buffer
= NULL
;
764 FIXME("Ignoring flags %x\n", dwReplaceFlags
);
766 /* First two arguments are mandatory */
767 if (!lpReplacedFileName
|| !lpReplacementFileName
)
769 SetLastError(ERROR_INVALID_PARAMETER
);
776 if(!CopyFileW(lpReplacedFileName
, lpBackupFileName
, FALSE
))
778 Error
= GetLastError();
783 /* Open the "replaced" file for reading and writing */
784 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName
, &NtReplacedName
, NULL
, NULL
)))
786 Error
= ERROR_PATH_NOT_FOUND
;
790 InitializeObjectAttributes(&ObjectAttributes
,
792 OBJ_CASE_INSENSITIVE
,
796 Status
= NtOpenFile(&hReplaced
,
797 GENERIC_READ
| GENERIC_WRITE
| DELETE
| SYNCHRONIZE
| WRITE_DAC
,
800 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
801 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
803 if (!NT_SUCCESS(Status
))
805 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
806 Error
= ERROR_FILE_NOT_FOUND
;
808 Error
= ERROR_UNABLE_TO_REMOVE_REPLACED
;
813 SetEndOfFile(hReplaced
) ;
816 * Open the replacement file for reading, writing, and deleting
817 * (deleting is needed when finished)
819 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName
, &NtReplacementName
, NULL
, NULL
)))
821 Error
= ERROR_PATH_NOT_FOUND
;
825 InitializeObjectAttributes(&ObjectAttributes
,
827 OBJ_CASE_INSENSITIVE
,
831 Status
= NtOpenFile(&hReplacement
,
832 GENERIC_READ
| DELETE
| SYNCHRONIZE
,
836 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
| FILE_DELETE_ON_CLOSE
);
838 if (!NT_SUCCESS(Status
))
840 Error
= RtlNtStatusToDosError(Status
);
844 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 0x10000) ;
847 Error
= ERROR_NOT_ENOUGH_MEMORY
;
850 while (Status
!= STATUS_END_OF_FILE
)
852 Status
= NtReadFile(hReplacement
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
, 0x10000, NULL
, NULL
) ;
853 if (NT_SUCCESS(Status
))
855 Status
= NtWriteFile(hReplaced
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
,
856 IoStatusBlock
.Information
, NULL
, NULL
) ;
857 if (!NT_SUCCESS(Status
))
859 Error
= RtlNtStatusToDosError(Status
);
863 else if (Status
!= STATUS_END_OF_FILE
)
865 Error
= RtlNtStatusToDosError(Status
);
872 /* Perform resource cleanup */
874 if (hReplaced
) NtClose(hReplaced
);
875 if (hReplacement
) NtClose(hReplacement
);
876 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
878 if (NtReplacementName
.Buffer
)
879 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName
.Buffer
);
880 if (NtReplacedName
.Buffer
)
881 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName
.Buffer
);
883 /* If there was an error, set the error code */
886 TRACE("ReplaceFileW failed (error=%lu)\n", Error
);
897 PrivMoveFileIdentityW(DWORD Unknown1
, DWORD Unknown2
, DWORD Unknown3
)