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 StringCbPrintfW(PendingOperationsBuffer
, sizeof(PendingOperationsBuffer
), L
"PendingFileRenameOperations%d", KeyId
);
67 PendingOperations
= PendingOperationsBuffer
;
69 RtlInitUnicodeString(&PendingOperationsString
, PendingOperations
);
71 InitializeObjectAttributes(&ObjectAttributes
,
72 &SessionManagerString
,
73 OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
77 Status
= NtCreateKey(&KeyHandle
,
78 GENERIC_READ
| GENERIC_WRITE
,
79 &ObjectAttributes
, 0, NULL
,
80 REG_OPTION_NON_VOLATILE
, NULL
);
81 if (Status
== STATUS_ACCESS_DENIED
)
83 Status
= NtCreateKey(&KeyHandle
,
84 GENERIC_READ
| GENERIC_WRITE
,
85 &ObjectAttributes
, 0, NULL
,
86 REG_OPTION_BACKUP_RESTORE
, NULL
);
89 if (!NT_SUCCESS(Status
))
94 /* Reserve enough to read previous string + to append our with required null chars */
95 BufferLength
= NewPath
->Length
+ ExistingPath
->Length
+ STRING_LENGTH
+ 3 * sizeof(WCHAR
);
96 /* Check we didn't overflow */
97 if (BufferLength
< STRING_LENGTH
)
100 return STATUS_BUFFER_TOO_SMALL
;
105 /* Allocate output buffer */
106 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength
);
110 return STATUS_NO_MEMORY
;
113 Status
= NtQueryValueKey(KeyHandle
,
114 &PendingOperationsString
,
115 KeyValuePartialInformation
,
116 Buffer
, StringLength
, &DataSize
);
117 if (Status
!= STATUS_BUFFER_OVERFLOW
)
122 /* If buffer was too small, then, reallocate one which is big enough */
123 StringLength
= DataSize
;
124 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
125 BufferLength
= ExistingPath
->Length
+ StringLength
+ NewPath
->Length
+ 3 * sizeof(WCHAR
);
126 if (BufferLength
< StringLength
)
129 return STATUS_BUFFER_TOO_SMALL
;
133 /* Check if it existed - if not, create only IF asked to */
134 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
|| !CreateIfNotFound
))
137 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
141 if (!NT_SUCCESS(Status
))
143 /* We didn't find any - ie, we create, so use complete buffer */
144 BufferBegin
= Buffer
;
145 BufferWrite
= Buffer
;
149 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
151 /* Get data, our buffer begin and then where we should append data (+ null char) */
152 BufferBegin
= PartialInfo
->Data
;
153 BufferWrite
= (PWSTR
)((ULONG_PTR
)PartialInfo
->Data
+ PartialInfo
->DataLength
+ sizeof(WCHAR
));
156 /* First copy existing */
157 RtlCopyMemory(BufferWrite
, ExistingPath
->Buffer
, ExistingPath
->Length
);
158 BufferWrite
+= ExistingPath
->Length
/ sizeof(WCHAR
);
159 /* And append null char */
160 *BufferWrite
= UNICODE_NULL
;
162 /* Append destination */
163 RtlCopyMemory(BufferWrite
, NewPath
->Buffer
, NewPath
->Length
);
164 BufferWrite
+= NewPath
->Length
/ sizeof(WCHAR
);
165 /* And append two null char (end of string) */
166 *BufferWrite
= UNICODE_NULL
;
168 *BufferWrite
= UNICODE_NULL
;
171 Status
= NtSetValueKey(KeyHandle
,
172 &PendingOperationsString
,
173 0, REG_MULTI_SZ
, BufferBegin
,
174 (ULONG_PTR
)BufferWrite
- (ULONG_PTR
)BufferBegin
+ sizeof(WCHAR
));
177 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
188 BasepNotifyTrackingService(IN PHANDLE ExistingHandle
,
189 IN POBJECT_ATTRIBUTES ObjectAttributes
,
191 IN PUNICODE_STRING NewPath
)
193 return STATUS_NOT_IMPLEMENTED
;
202 BasepMoveFileCopyProgress(IN LARGE_INTEGER TotalFileSize
,
203 IN LARGE_INTEGER TotalBytesTransferred
,
204 IN LARGE_INTEGER StreamSize
,
205 IN LARGE_INTEGER StreamBytesTransferred
,
206 IN DWORD dwStreamNumber
,
207 IN DWORD dwCallbackReason
,
208 IN HANDLE hSourceFile
,
209 IN HANDLE hDestinationFile
,
210 IN LPVOID lpData OPTIONAL
)
213 PCOPY_PROGRESS_CONTEXT Context
= (PCOPY_PROGRESS_CONTEXT
)lpData
;
215 if (Context
->Flags
& MOVEFILE_WRITE_THROUGH
)
217 if (!dwCallbackReason
)
219 if (StreamBytesTransferred
.QuadPart
== StreamSize
.QuadPart
)
221 FlushFileBuffers(hDestinationFile
);
226 if (Context
->UserRoutine
)
228 Ret
= Context
->UserRoutine(TotalFileSize
,
229 TotalBytesTransferred
,
231 StreamBytesTransferred
,
248 MoveFileWithProgressW(IN LPCWSTR lpExistingFileName
,
249 IN LPCWSTR lpNewFileName
,
250 IN LPPROGRESS_ROUTINE lpProgressRoutine
,
256 IO_STATUS_BLOCK IoStatusBlock
;
257 COPY_PROGRESS_CONTEXT CopyContext
;
258 OBJECT_ATTRIBUTES ObjectAttributes
;
259 PFILE_RENAME_INFORMATION RenameInfo
;
260 UNICODE_STRING NewPathU
, ExistingPathU
;
261 FILE_ATTRIBUTE_TAG_INFORMATION FileAttrTagInfo
;
262 HANDLE SourceHandle
= INVALID_HANDLE_VALUE
, NewHandle
, ExistingHandle
;
263 BOOL Ret
= FALSE
, ReplaceIfExists
, DelayUntilReboot
, AttemptReopenWithoutReparse
;
265 DPRINT("MoveFileWithProgressW(%S, %S, %p, %p, %x)\n", lpExistingFileName
, lpNewFileName
, lpProgressRoutine
, lpData
, dwFlags
);
267 NewPathU
.Buffer
= NULL
;
268 ExistingPathU
.Buffer
= NULL
;
272 /* Don't allow renaming to a disk */
273 if (lpNewFileName
&& RtlIsDosDeviceName_U(lpNewFileName
))
275 BaseSetLastNTError(STATUS_OBJECT_NAME_COLLISION
);
279 ReplaceIfExists
= !!(dwFlags
& MOVEFILE_REPLACE_EXISTING
);
282 if (!RtlDosPathNameToNtPathName_U(lpExistingFileName
, &ExistingPathU
, NULL
, NULL
))
284 BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND
);
289 DelayUntilReboot
= !!(dwFlags
& MOVEFILE_DELAY_UNTIL_REBOOT
);
290 if (DelayUntilReboot
&& (dwFlags
& MOVEFILE_CREATE_HARDLINK
))
292 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
296 /* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
297 AttemptReopenWithoutReparse
= TRUE
;
298 InitializeObjectAttributes(&ObjectAttributes
,
300 OBJ_CASE_INSENSITIVE
,
303 /* Attempt to open source file */
304 Status
= NtOpenFile(&SourceHandle
,
305 FILE_READ_ATTRIBUTES
| DELETE
| SYNCHRONIZE
,
308 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
309 FILE_OPEN_FOR_BACKUP_INTENT
| ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0));
310 if (!NT_SUCCESS(Status
))
312 /* If we failed and the file doesn't exist, don't attempt to reopen without reparse */
313 if (DelayUntilReboot
&&
314 (Status
== STATUS_SHARING_VIOLATION
|| Status
== STATUS_OBJECT_NAME_NOT_FOUND
|| Status
== STATUS_OBJECT_PATH_NOT_FOUND
))
316 /* Here we don't fail completely, as we postpone the operation to reboot
317 * File might exist afterwards, and we don't need a handle here
319 SourceHandle
= INVALID_HANDLE_VALUE
;
320 AttemptReopenWithoutReparse
= FALSE
;
322 /* If we failed for any reason than unsupported reparse, fail completely */
323 else if (Status
!= STATUS_INVALID_PARAMETER
)
325 BaseSetLastNTError(Status
);
331 /* We managed to open, so query information */
332 Status
= NtQueryInformationFile(SourceHandle
,
335 sizeof(FILE_ATTRIBUTE_TAG_INFORMATION
),
336 FileAttributeTagInformation
);
337 if (!NT_SUCCESS(Status
))
339 /* Do not tolerate any other error than something related to not supported operation */
340 if (Status
!= STATUS_NOT_IMPLEMENTED
&& Status
!= STATUS_INVALID_PARAMETER
)
342 BaseSetLastNTError(Status
);
346 /* Not a reparse point, no need to reopen, it's fine */
347 AttemptReopenWithoutReparse
= FALSE
;
349 /* Validate the reparse point (do we support it?) */
350 else if (FileAttrTagInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
&&
351 FileAttrTagInfo
.ReparseTag
!= IO_REPARSE_TAG_MOUNT_POINT
)
353 NtClose(SourceHandle
);
354 SourceHandle
= INVALID_HANDLE_VALUE
;
358 /* Simply reopen if required */
359 if (AttemptReopenWithoutReparse
)
361 Status
= NtOpenFile(&SourceHandle
,
362 DELETE
| SYNCHRONIZE
,
365 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
366 ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0));
367 if (!NT_SUCCESS(Status
))
369 BaseSetLastNTError(Status
);
374 /* Nullify string if we're to use it */
375 if (DelayUntilReboot
&& !lpNewFileName
)
377 RtlInitUnicodeString(&NewPathU
, 0);
379 /* Check whether path exists */
380 else if (!RtlDosPathNameToNtPathName_U(lpNewFileName
, &NewPathU
, 0, 0))
382 BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND
);
386 /* Handle postponed renaming */
387 if (DelayUntilReboot
)
389 /* If new file exists and we're allowed to replace, then mark the path with ! */
390 if (ReplaceIfExists
&& NewPathU
.Length
)
392 NewBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU
.Length
+ sizeof(WCHAR
));
393 if (NewBuffer
== NULL
)
395 BaseSetLastNTError(STATUS_NO_MEMORY
);
400 RtlCopyMemory(&NewBuffer
[1], NewPathU
.Buffer
, NewPathU
.Length
);
401 NewPathU
.Length
+= sizeof(WCHAR
);
402 NewPathU
.MaximumLength
+= sizeof(WCHAR
);
403 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU
.Buffer
);
404 NewPathU
.Buffer
= NewBuffer
;
407 /* Check whether 'copy' renaming is allowed if required */
408 if (RtlDetermineDosPathNameType_U(lpExistingFileName
) == RtlPathTypeUncAbsolute
|| dwFlags
& MOVEFILE_COPY_ALLOWED
)
410 Status
= STATUS_INVALID_PARAMETER
;
414 /* First, probe 2nd key to see whether it exists - if so, it will be appended there */
415 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 2, FALSE
);
416 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
418 /* If doesn't exist, append to first key first, creating it if it doesn't exist */
419 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 1, TRUE
);
421 if (Status
== STATUS_INSUFFICIENT_RESOURCES
)
423 /* If it failed because it's too big, then create 2nd key and put it there */
424 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 2, TRUE
);
429 /* If we failed at some point, return the error */
430 if (!NT_SUCCESS(Status
))
432 BaseSetLastNTError(Status
);
440 /* At that point, we MUST have a source handle */
441 ASSERT(SourceHandle
!= INVALID_HANDLE_VALUE
);
443 /* Allocate renaming buffer and fill it */
444 RenameInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU
.Length
+ sizeof(FILE_RENAME_INFORMATION
));
445 if (RenameInfo
== NULL
)
447 BaseSetLastNTError(STATUS_NO_MEMORY
);
451 RtlCopyMemory(&RenameInfo
->FileName
, NewPathU
.Buffer
, NewPathU
.Length
);
452 RenameInfo
->ReplaceIfExists
= ReplaceIfExists
;
453 RenameInfo
->RootDirectory
= 0;
454 RenameInfo
->FileNameLength
= NewPathU
.Length
;
456 /* Attempt to rename the file */
457 Status
= NtSetInformationFile(SourceHandle
,
460 NewPathU
.Length
+ sizeof(FILE_RENAME_INFORMATION
),
461 ((dwFlags
& MOVEFILE_CREATE_HARDLINK
) ? FileLinkInformation
: FileRenameInformation
));
462 RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo
);
463 if (NT_SUCCESS(Status
))
465 /* If it succeed, all fine, quit */
469 /* If we failed for any other reason than not the same device, fail
470 * If we failed because of different devices, only allow renaming if user allowed copy
472 if (Status
!= STATUS_NOT_SAME_DEVICE
|| !(dwFlags
& MOVEFILE_COPY_ALLOWED
))
474 /* ReactOS hack! To be removed once all FSD have proper renaming support
475 * Just leave status to error and leave
477 if (Status
== STATUS_NOT_IMPLEMENTED
)
479 DPRINT1("Forcing copy, renaming not supported by FSD\n");
483 BaseSetLastNTError(Status
);
488 /* Close source file */
489 NtClose(SourceHandle
);
490 SourceHandle
= INVALID_HANDLE_VALUE
;
492 /* Issue the copy of the file */
493 CopyContext
.Flags
= dwFlags
;
494 CopyContext
.UserRoutine
= lpProgressRoutine
;
495 CopyContext
.UserData
= lpData
;
496 NewHandle
= INVALID_HANDLE_VALUE
;
497 ExistingHandle
= INVALID_HANDLE_VALUE
;
499 Ret
= BasepCopyFileExW(lpExistingFileName
,
501 BasepMoveFileCopyProgress
,
504 (ReplaceIfExists
== 0) | COPY_FILE_OPEN_SOURCE_FOR_WRITE
,
510 /* If it failed, don't leak any handle */
511 if (ExistingHandle
!= INVALID_HANDLE_VALUE
)
513 CloseHandle(ExistingHandle
);
514 ExistingHandle
= INVALID_HANDLE_VALUE
;
517 else if (ExistingHandle
!= INVALID_HANDLE_VALUE
)
519 if (NewHandle
!= INVALID_HANDLE_VALUE
)
521 /* If copying succeed, notify */
522 Status
= BasepNotifyTrackingService(&ExistingHandle
, &ObjectAttributes
, NewHandle
, &NewPathU
);
523 if (!NT_SUCCESS(Status
))
525 /* Fail in case it had to succeed */
526 if (dwFlags
& MOVEFILE_FAIL_IF_NOT_TRACKABLE
)
528 if (NewHandle
!= INVALID_HANDLE_VALUE
)
529 CloseHandle(NewHandle
);
530 NewHandle
= INVALID_HANDLE_VALUE
;
531 DeleteFileW(lpNewFileName
);
533 BaseSetLastNTError(Status
);
538 CloseHandle(ExistingHandle
);
539 ExistingHandle
= INVALID_HANDLE_VALUE
;
542 /* In case copy worked, close file */
543 if (NewHandle
!= INVALID_HANDLE_VALUE
)
545 CloseHandle(NewHandle
);
546 NewHandle
= INVALID_HANDLE_VALUE
;
549 /* If it succeed, delete source file */
552 if (!DeleteFileW(lpExistingFileName
))
554 /* Reset file attributes if required */
555 SetFileAttributesW(lpExistingFileName
, FILE_ATTRIBUTE_NORMAL
);
556 DeleteFileW(lpExistingFileName
);
562 if (SourceHandle
!= INVALID_HANDLE_VALUE
)
563 NtClose(SourceHandle
);
565 RtlFreeHeap(RtlGetProcessHeap(), 0, ExistingPathU
.Buffer
);
566 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU
.Buffer
);
579 MoveFileWithProgressA(IN LPCSTR lpExistingFileName
,
580 IN LPCSTR lpNewFileName OPTIONAL
,
581 IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL
,
582 IN LPVOID lpData OPTIONAL
,
586 UNICODE_STRING ExistingFileNameW
, NewFileNameW
;
588 if (!Basep8BitStringToDynamicUnicodeString(&ExistingFileNameW
, lpExistingFileName
))
595 if (!Basep8BitStringToDynamicUnicodeString(&NewFileNameW
, lpNewFileName
))
597 RtlFreeUnicodeString(&ExistingFileNameW
);
603 NewFileNameW
.Buffer
= NULL
;
606 Ret
= MoveFileWithProgressW(ExistingFileNameW
.Buffer
, NewFileNameW
.Buffer
, lpProgressRoutine
, lpData
, dwFlags
);
608 RtlFreeUnicodeString(&ExistingFileNameW
);
609 RtlFreeUnicodeString(&NewFileNameW
);
620 MoveFileW(IN LPCWSTR lpExistingFileName
,
621 IN LPCWSTR lpNewFileName
)
623 return MoveFileWithProgressW(lpExistingFileName
,
627 MOVEFILE_COPY_ALLOWED
);
636 MoveFileExW(IN LPCWSTR lpExistingFileName
,
637 IN LPCWSTR lpNewFileName OPTIONAL
,
640 return MoveFileWithProgressW(lpExistingFileName
,
653 MoveFileA(IN LPCSTR lpExistingFileName
,
654 IN LPCSTR lpNewFileName
)
656 return MoveFileWithProgressA(lpExistingFileName
,
660 MOVEFILE_COPY_ALLOWED
);
669 MoveFileExA(IN LPCSTR lpExistingFileName
,
670 IN LPCSTR lpNewFileName OPTIONAL
,
673 return MoveFileWithProgressA(lpExistingFileName
,
685 ReplaceFileA(IN LPCSTR lpReplacedFileName
,
686 IN LPCSTR lpReplacementFileName
,
687 IN LPCSTR lpBackupFileName OPTIONAL
,
688 IN DWORD dwReplaceFlags
,
690 IN LPVOID lpReserved
)
693 UNICODE_STRING ReplacedFileNameW
, ReplacementFileNameW
, BackupFileNameW
;
695 if (!lpReplacedFileName
|| !lpReplacementFileName
|| lpExclude
|| lpReserved
|| dwReplaceFlags
& ~(REPLACEFILE_WRITE_THROUGH
| REPLACEFILE_IGNORE_MERGE_ERRORS
))
697 SetLastError(ERROR_INVALID_PARAMETER
);
701 if (!Basep8BitStringToDynamicUnicodeString(&ReplacedFileNameW
, lpReplacedFileName
))
706 if (!Basep8BitStringToDynamicUnicodeString(&ReplacementFileNameW
, lpReplacementFileName
))
708 RtlFreeUnicodeString(&ReplacedFileNameW
);
712 if (lpBackupFileName
)
714 if (!Basep8BitStringToDynamicUnicodeString(&BackupFileNameW
, lpBackupFileName
))
716 RtlFreeUnicodeString(&ReplacementFileNameW
);
717 RtlFreeUnicodeString(&ReplacedFileNameW
);
723 BackupFileNameW
.Buffer
= NULL
;
726 Ret
= ReplaceFileW(ReplacedFileNameW
.Buffer
, ReplacementFileNameW
.Buffer
, BackupFileNameW
.Buffer
, dwReplaceFlags
, 0, 0);
728 if (lpBackupFileName
)
730 RtlFreeUnicodeString(&BackupFileNameW
);
732 RtlFreeUnicodeString(&ReplacementFileNameW
);
733 RtlFreeUnicodeString(&ReplacedFileNameW
);
744 LPCWSTR lpReplacedFileName
,
745 LPCWSTR lpReplacementFileName
,
746 LPCWSTR lpBackupFileName
,
747 DWORD dwReplaceFlags
,
752 HANDLE hReplaced
= NULL
, hReplacement
= NULL
;
753 UNICODE_STRING NtReplacedName
= { 0, 0, NULL
};
754 UNICODE_STRING NtReplacementName
= { 0, 0, NULL
};
755 DWORD Error
= ERROR_SUCCESS
;
758 IO_STATUS_BLOCK IoStatusBlock
;
759 OBJECT_ATTRIBUTES ObjectAttributes
;
760 PVOID Buffer
= NULL
;
763 FIXME("Ignoring flags %x\n", dwReplaceFlags
);
765 /* First two arguments are mandatory */
766 if (!lpReplacedFileName
|| !lpReplacementFileName
)
768 SetLastError(ERROR_INVALID_PARAMETER
);
775 if(!CopyFileW(lpReplacedFileName
, lpBackupFileName
, FALSE
))
777 Error
= GetLastError();
782 /* Open the "replaced" file for reading and writing */
783 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName
, &NtReplacedName
, NULL
, NULL
)))
785 Error
= ERROR_PATH_NOT_FOUND
;
789 InitializeObjectAttributes(&ObjectAttributes
,
791 OBJ_CASE_INSENSITIVE
,
795 Status
= NtOpenFile(&hReplaced
,
796 GENERIC_READ
| GENERIC_WRITE
| DELETE
| SYNCHRONIZE
| WRITE_DAC
,
799 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
800 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
802 if (!NT_SUCCESS(Status
))
804 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
805 Error
= ERROR_FILE_NOT_FOUND
;
807 Error
= ERROR_UNABLE_TO_REMOVE_REPLACED
;
812 SetEndOfFile(hReplaced
) ;
815 * Open the replacement file for reading, writing, and deleting
816 * (deleting is needed when finished)
818 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName
, &NtReplacementName
, NULL
, NULL
)))
820 Error
= ERROR_PATH_NOT_FOUND
;
824 InitializeObjectAttributes(&ObjectAttributes
,
826 OBJ_CASE_INSENSITIVE
,
830 Status
= NtOpenFile(&hReplacement
,
831 GENERIC_READ
| DELETE
| SYNCHRONIZE
,
835 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
| FILE_DELETE_ON_CLOSE
);
837 if (!NT_SUCCESS(Status
))
839 Error
= RtlNtStatusToDosError(Status
);
843 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 0x10000) ;
846 Error
= ERROR_NOT_ENOUGH_MEMORY
;
849 while (Status
!= STATUS_END_OF_FILE
)
851 Status
= NtReadFile(hReplacement
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
, 0x10000, NULL
, NULL
) ;
852 if (NT_SUCCESS(Status
))
854 Status
= NtWriteFile(hReplaced
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
,
855 IoStatusBlock
.Information
, NULL
, NULL
) ;
856 if (!NT_SUCCESS(Status
))
858 Error
= RtlNtStatusToDosError(Status
);
862 else if (Status
!= STATUS_END_OF_FILE
)
864 Error
= RtlNtStatusToDosError(Status
);
871 /* Perform resource cleanup */
873 if (hReplaced
) NtClose(hReplaced
);
874 if (hReplacement
) NtClose(hReplacement
);
875 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
877 if (NtReplacementName
.Buffer
)
878 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName
.Buffer
);
879 if (NtReplacedName
.Buffer
)
880 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName
.Buffer
);
882 /* If there was an error, set the error code */
885 TRACE("ReplaceFileW failed (error=%lu)\n", Error
);
896 PrivMoveFileIdentityW(DWORD Unknown1
, DWORD Unknown2
, DWORD Unknown3
)