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(UNICODE_NULL
);
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(UNICODE_NULL
);
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
152 * (- null char, this is REG_MULTI_SZ, it already includes double termination, we keep only one)
154 BufferBegin
= PartialInfo
->Data
;
155 BufferWrite
= (PWSTR
)((ULONG_PTR
)PartialInfo
->Data
+ PartialInfo
->DataLength
- sizeof(UNICODE_NULL
));
158 /* First copy existing */
159 RtlCopyMemory(BufferWrite
, ExistingPath
->Buffer
, ExistingPath
->Length
);
160 BufferWrite
+= ExistingPath
->Length
/ sizeof(WCHAR
);
161 /* And append null char */
162 *BufferWrite
= UNICODE_NULL
;
164 /* Append destination */
165 RtlCopyMemory(BufferWrite
, NewPath
->Buffer
, NewPath
->Length
);
166 BufferWrite
+= NewPath
->Length
/ sizeof(WCHAR
);
167 /* And append two null char (end of string) */
168 *BufferWrite
= UNICODE_NULL
;
170 *BufferWrite
= UNICODE_NULL
;
173 Status
= NtSetValueKey(KeyHandle
,
174 &PendingOperationsString
,
175 0, REG_MULTI_SZ
, BufferBegin
,
176 (ULONG_PTR
)BufferWrite
- (ULONG_PTR
)BufferBegin
+ sizeof(WCHAR
));
179 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
190 BasepNotifyTrackingService(IN PHANDLE ExistingHandle
,
191 IN POBJECT_ATTRIBUTES ObjectAttributes
,
193 IN PUNICODE_STRING NewPath
)
195 return STATUS_NOT_IMPLEMENTED
;
204 BasepMoveFileCopyProgress(IN LARGE_INTEGER TotalFileSize
,
205 IN LARGE_INTEGER TotalBytesTransferred
,
206 IN LARGE_INTEGER StreamSize
,
207 IN LARGE_INTEGER StreamBytesTransferred
,
208 IN DWORD dwStreamNumber
,
209 IN DWORD dwCallbackReason
,
210 IN HANDLE hSourceFile
,
211 IN HANDLE hDestinationFile
,
212 IN LPVOID lpData OPTIONAL
)
215 PCOPY_PROGRESS_CONTEXT Context
= (PCOPY_PROGRESS_CONTEXT
)lpData
;
217 if (Context
->Flags
& MOVEFILE_WRITE_THROUGH
)
219 if (!dwCallbackReason
)
221 if (StreamBytesTransferred
.QuadPart
== StreamSize
.QuadPart
)
223 FlushFileBuffers(hDestinationFile
);
228 if (Context
->UserRoutine
)
230 Ret
= Context
->UserRoutine(TotalFileSize
,
231 TotalBytesTransferred
,
233 StreamBytesTransferred
,
250 MoveFileWithProgressW(IN LPCWSTR lpExistingFileName
,
251 IN LPCWSTR lpNewFileName
,
252 IN LPPROGRESS_ROUTINE lpProgressRoutine
,
258 IO_STATUS_BLOCK IoStatusBlock
;
259 COPY_PROGRESS_CONTEXT CopyContext
;
260 OBJECT_ATTRIBUTES ObjectAttributes
;
261 PFILE_RENAME_INFORMATION RenameInfo
;
262 UNICODE_STRING NewPathU
, ExistingPathU
;
263 FILE_ATTRIBUTE_TAG_INFORMATION FileAttrTagInfo
;
264 HANDLE SourceHandle
= INVALID_HANDLE_VALUE
, NewHandle
, ExistingHandle
;
265 BOOL Ret
= FALSE
, ReplaceIfExists
, DelayUntilReboot
, AttemptReopenWithoutReparse
;
267 DPRINT("MoveFileWithProgressW(%S, %S, %p, %p, %x)\n", lpExistingFileName
, lpNewFileName
, lpProgressRoutine
, lpData
, dwFlags
);
269 NewPathU
.Buffer
= NULL
;
270 ExistingPathU
.Buffer
= NULL
;
274 /* Don't allow renaming to a disk */
275 if (lpNewFileName
&& RtlIsDosDeviceName_U(lpNewFileName
))
277 BaseSetLastNTError(STATUS_OBJECT_NAME_COLLISION
);
281 ReplaceIfExists
= !!(dwFlags
& MOVEFILE_REPLACE_EXISTING
);
284 if (!RtlDosPathNameToNtPathName_U(lpExistingFileName
, &ExistingPathU
, NULL
, NULL
))
286 BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND
);
291 DelayUntilReboot
= !!(dwFlags
& MOVEFILE_DELAY_UNTIL_REBOOT
);
292 if (DelayUntilReboot
&& (dwFlags
& MOVEFILE_CREATE_HARDLINK
))
294 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
298 /* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
299 AttemptReopenWithoutReparse
= TRUE
;
300 InitializeObjectAttributes(&ObjectAttributes
,
302 OBJ_CASE_INSENSITIVE
,
305 /* Attempt to open source file */
306 Status
= NtOpenFile(&SourceHandle
,
307 FILE_READ_ATTRIBUTES
| DELETE
| SYNCHRONIZE
,
310 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
311 FILE_OPEN_FOR_BACKUP_INTENT
| ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0));
312 if (!NT_SUCCESS(Status
))
314 /* If we failed and the file doesn't exist, don't attempt to reopen without reparse */
315 if (DelayUntilReboot
&&
316 (Status
== STATUS_SHARING_VIOLATION
|| Status
== STATUS_OBJECT_NAME_NOT_FOUND
|| Status
== STATUS_OBJECT_PATH_NOT_FOUND
))
318 /* Here we don't fail completely, as we postpone the operation to reboot
319 * File might exist afterwards, and we don't need a handle here
321 SourceHandle
= INVALID_HANDLE_VALUE
;
322 AttemptReopenWithoutReparse
= FALSE
;
324 /* If we failed for any reason than unsupported reparse, fail completely */
325 else if (Status
!= STATUS_INVALID_PARAMETER
)
327 BaseSetLastNTError(Status
);
333 /* We managed to open, so query information */
334 Status
= NtQueryInformationFile(SourceHandle
,
337 sizeof(FILE_ATTRIBUTE_TAG_INFORMATION
),
338 FileAttributeTagInformation
);
339 if (!NT_SUCCESS(Status
))
341 /* Do not tolerate any other error than something related to not supported operation */
342 if (Status
!= STATUS_NOT_IMPLEMENTED
&& Status
!= STATUS_INVALID_PARAMETER
)
344 BaseSetLastNTError(Status
);
348 /* Not a reparse point, no need to reopen, it's fine */
349 AttemptReopenWithoutReparse
= FALSE
;
351 /* Validate the reparse point (do we support it?) */
352 else if (FileAttrTagInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
&&
353 FileAttrTagInfo
.ReparseTag
!= IO_REPARSE_TAG_MOUNT_POINT
)
355 NtClose(SourceHandle
);
356 SourceHandle
= INVALID_HANDLE_VALUE
;
360 /* Simply reopen if required */
361 if (AttemptReopenWithoutReparse
)
363 Status
= NtOpenFile(&SourceHandle
,
364 DELETE
| SYNCHRONIZE
,
367 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
368 ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0));
369 if (!NT_SUCCESS(Status
))
371 BaseSetLastNTError(Status
);
376 /* Nullify string if we're to use it */
377 if (DelayUntilReboot
&& !lpNewFileName
)
379 RtlInitUnicodeString(&NewPathU
, 0);
381 /* Check whether path exists */
382 else if (!RtlDosPathNameToNtPathName_U(lpNewFileName
, &NewPathU
, 0, 0))
384 BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND
);
388 /* Handle postponed renaming */
389 if (DelayUntilReboot
)
391 /* If new file exists and we're allowed to replace, then mark the path with ! */
392 if (ReplaceIfExists
&& NewPathU
.Length
)
394 NewBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU
.Length
+ sizeof(WCHAR
));
395 if (NewBuffer
== NULL
)
397 BaseSetLastNTError(STATUS_NO_MEMORY
);
402 RtlCopyMemory(&NewBuffer
[1], NewPathU
.Buffer
, NewPathU
.Length
);
403 NewPathU
.Length
+= sizeof(WCHAR
);
404 NewPathU
.MaximumLength
+= sizeof(WCHAR
);
405 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU
.Buffer
);
406 NewPathU
.Buffer
= NewBuffer
;
409 /* Check whether 'copy' renaming is allowed if required */
410 if (RtlDetermineDosPathNameType_U(lpExistingFileName
) == RtlPathTypeUncAbsolute
|| dwFlags
& MOVEFILE_COPY_ALLOWED
)
412 Status
= STATUS_INVALID_PARAMETER
;
416 /* First, probe 2nd key to see whether it exists - if so, it will be appended there */
417 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 2, FALSE
);
418 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
420 /* If doesn't exist, append to first key first, creating it if it doesn't exist */
421 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 1, TRUE
);
423 if (Status
== STATUS_INSUFFICIENT_RESOURCES
)
425 /* If it failed because it's too big, then create 2nd key and put it there */
426 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 2, TRUE
);
431 /* If we failed at some point, return the error */
432 if (!NT_SUCCESS(Status
))
434 BaseSetLastNTError(Status
);
442 /* At that point, we MUST have a source handle */
443 ASSERT(SourceHandle
!= INVALID_HANDLE_VALUE
);
445 /* Allocate renaming buffer and fill it */
446 RenameInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU
.Length
+ sizeof(FILE_RENAME_INFORMATION
));
447 if (RenameInfo
== NULL
)
449 BaseSetLastNTError(STATUS_NO_MEMORY
);
453 RtlCopyMemory(&RenameInfo
->FileName
, NewPathU
.Buffer
, NewPathU
.Length
);
454 RenameInfo
->ReplaceIfExists
= ReplaceIfExists
;
455 RenameInfo
->RootDirectory
= 0;
456 RenameInfo
->FileNameLength
= NewPathU
.Length
;
458 /* Attempt to rename the file */
459 Status
= NtSetInformationFile(SourceHandle
,
462 NewPathU
.Length
+ sizeof(FILE_RENAME_INFORMATION
),
463 ((dwFlags
& MOVEFILE_CREATE_HARDLINK
) ? FileLinkInformation
: FileRenameInformation
));
464 RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo
);
465 if (NT_SUCCESS(Status
))
467 /* If it succeed, all fine, quit */
471 /* If we failed for any other reason than not the same device, fail
472 * If we failed because of different devices, only allow renaming if user allowed copy
474 if (Status
!= STATUS_NOT_SAME_DEVICE
|| !(dwFlags
& MOVEFILE_COPY_ALLOWED
))
476 /* ReactOS hack! To be removed once all FSD have proper renaming support
477 * Just leave status to error and leave
479 if (Status
== STATUS_NOT_IMPLEMENTED
)
481 DPRINT1("Forcing copy, renaming not supported by FSD\n");
485 BaseSetLastNTError(Status
);
490 /* Close source file */
491 NtClose(SourceHandle
);
492 SourceHandle
= INVALID_HANDLE_VALUE
;
494 /* Issue the copy of the file */
495 CopyContext
.Flags
= dwFlags
;
496 CopyContext
.UserRoutine
= lpProgressRoutine
;
497 CopyContext
.UserData
= lpData
;
498 NewHandle
= INVALID_HANDLE_VALUE
;
499 ExistingHandle
= INVALID_HANDLE_VALUE
;
501 Ret
= BasepCopyFileExW(lpExistingFileName
,
503 BasepMoveFileCopyProgress
,
506 (ReplaceIfExists
== 0) | COPY_FILE_OPEN_SOURCE_FOR_WRITE
,
512 /* If it failed, don't leak any handle */
513 if (ExistingHandle
!= INVALID_HANDLE_VALUE
)
515 CloseHandle(ExistingHandle
);
516 ExistingHandle
= INVALID_HANDLE_VALUE
;
519 else if (ExistingHandle
!= INVALID_HANDLE_VALUE
)
521 if (NewHandle
!= INVALID_HANDLE_VALUE
)
523 /* If copying succeed, notify */
524 Status
= BasepNotifyTrackingService(&ExistingHandle
, &ObjectAttributes
, NewHandle
, &NewPathU
);
525 if (!NT_SUCCESS(Status
))
527 /* Fail in case it had to succeed */
528 if (dwFlags
& MOVEFILE_FAIL_IF_NOT_TRACKABLE
)
530 if (NewHandle
!= INVALID_HANDLE_VALUE
)
531 CloseHandle(NewHandle
);
532 NewHandle
= INVALID_HANDLE_VALUE
;
533 DeleteFileW(lpNewFileName
);
535 BaseSetLastNTError(Status
);
540 CloseHandle(ExistingHandle
);
541 ExistingHandle
= INVALID_HANDLE_VALUE
;
544 /* In case copy worked, close file */
545 if (NewHandle
!= INVALID_HANDLE_VALUE
)
547 CloseHandle(NewHandle
);
548 NewHandle
= INVALID_HANDLE_VALUE
;
551 /* If it succeed, delete source file */
554 if (!DeleteFileW(lpExistingFileName
))
556 /* Reset file attributes if required */
557 SetFileAttributesW(lpExistingFileName
, FILE_ATTRIBUTE_NORMAL
);
558 DeleteFileW(lpExistingFileName
);
564 if (SourceHandle
!= INVALID_HANDLE_VALUE
)
565 NtClose(SourceHandle
);
567 RtlFreeHeap(RtlGetProcessHeap(), 0, ExistingPathU
.Buffer
);
568 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU
.Buffer
);
581 MoveFileWithProgressA(IN LPCSTR lpExistingFileName
,
582 IN LPCSTR lpNewFileName OPTIONAL
,
583 IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL
,
584 IN LPVOID lpData OPTIONAL
,
588 UNICODE_STRING ExistingFileNameW
, NewFileNameW
;
590 if (!Basep8BitStringToDynamicUnicodeString(&ExistingFileNameW
, lpExistingFileName
))
597 if (!Basep8BitStringToDynamicUnicodeString(&NewFileNameW
, lpNewFileName
))
599 RtlFreeUnicodeString(&ExistingFileNameW
);
605 NewFileNameW
.Buffer
= NULL
;
608 Ret
= MoveFileWithProgressW(ExistingFileNameW
.Buffer
, NewFileNameW
.Buffer
, lpProgressRoutine
, lpData
, dwFlags
);
610 RtlFreeUnicodeString(&ExistingFileNameW
);
611 RtlFreeUnicodeString(&NewFileNameW
);
622 MoveFileW(IN LPCWSTR lpExistingFileName
,
623 IN LPCWSTR lpNewFileName
)
625 return MoveFileWithProgressW(lpExistingFileName
,
629 MOVEFILE_COPY_ALLOWED
);
638 MoveFileExW(IN LPCWSTR lpExistingFileName
,
639 IN LPCWSTR lpNewFileName OPTIONAL
,
642 return MoveFileWithProgressW(lpExistingFileName
,
655 MoveFileA(IN LPCSTR lpExistingFileName
,
656 IN LPCSTR lpNewFileName
)
658 return MoveFileWithProgressA(lpExistingFileName
,
662 MOVEFILE_COPY_ALLOWED
);
671 MoveFileExA(IN LPCSTR lpExistingFileName
,
672 IN LPCSTR lpNewFileName OPTIONAL
,
675 return MoveFileWithProgressA(lpExistingFileName
,
687 ReplaceFileA(IN LPCSTR lpReplacedFileName
,
688 IN LPCSTR lpReplacementFileName
,
689 IN LPCSTR lpBackupFileName OPTIONAL
,
690 IN DWORD dwReplaceFlags
,
692 IN LPVOID lpReserved
)
695 UNICODE_STRING ReplacedFileNameW
, ReplacementFileNameW
, BackupFileNameW
;
697 if (!lpReplacedFileName
|| !lpReplacementFileName
|| lpExclude
|| lpReserved
|| dwReplaceFlags
& ~(REPLACEFILE_WRITE_THROUGH
| REPLACEFILE_IGNORE_MERGE_ERRORS
))
699 SetLastError(ERROR_INVALID_PARAMETER
);
703 if (!Basep8BitStringToDynamicUnicodeString(&ReplacedFileNameW
, lpReplacedFileName
))
708 if (!Basep8BitStringToDynamicUnicodeString(&ReplacementFileNameW
, lpReplacementFileName
))
710 RtlFreeUnicodeString(&ReplacedFileNameW
);
714 if (lpBackupFileName
)
716 if (!Basep8BitStringToDynamicUnicodeString(&BackupFileNameW
, lpBackupFileName
))
718 RtlFreeUnicodeString(&ReplacementFileNameW
);
719 RtlFreeUnicodeString(&ReplacedFileNameW
);
725 BackupFileNameW
.Buffer
= NULL
;
728 Ret
= ReplaceFileW(ReplacedFileNameW
.Buffer
, ReplacementFileNameW
.Buffer
, BackupFileNameW
.Buffer
, dwReplaceFlags
, 0, 0);
730 if (lpBackupFileName
)
732 RtlFreeUnicodeString(&BackupFileNameW
);
734 RtlFreeUnicodeString(&ReplacementFileNameW
);
735 RtlFreeUnicodeString(&ReplacedFileNameW
);
746 LPCWSTR lpReplacedFileName
,
747 LPCWSTR lpReplacementFileName
,
748 LPCWSTR lpBackupFileName
,
749 DWORD dwReplaceFlags
,
754 HANDLE hReplaced
= NULL
, hReplacement
= NULL
;
755 UNICODE_STRING NtReplacedName
= { 0, 0, NULL
};
756 UNICODE_STRING NtReplacementName
= { 0, 0, NULL
};
757 DWORD Error
= ERROR_SUCCESS
;
760 IO_STATUS_BLOCK IoStatusBlock
;
761 OBJECT_ATTRIBUTES ObjectAttributes
;
762 PVOID Buffer
= NULL
;
765 FIXME("Ignoring flags %x\n", dwReplaceFlags
);
767 /* First two arguments are mandatory */
768 if (!lpReplacedFileName
|| !lpReplacementFileName
)
770 SetLastError(ERROR_INVALID_PARAMETER
);
777 if(!CopyFileW(lpReplacedFileName
, lpBackupFileName
, FALSE
))
779 Error
= GetLastError();
784 /* Open the "replaced" file for reading and writing */
785 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName
, &NtReplacedName
, NULL
, NULL
)))
787 Error
= ERROR_PATH_NOT_FOUND
;
791 InitializeObjectAttributes(&ObjectAttributes
,
793 OBJ_CASE_INSENSITIVE
,
797 Status
= NtOpenFile(&hReplaced
,
798 GENERIC_READ
| GENERIC_WRITE
| DELETE
| SYNCHRONIZE
| WRITE_DAC
,
801 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
802 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
804 if (!NT_SUCCESS(Status
))
806 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
807 Error
= ERROR_FILE_NOT_FOUND
;
809 Error
= ERROR_UNABLE_TO_REMOVE_REPLACED
;
814 SetEndOfFile(hReplaced
) ;
817 * Open the replacement file for reading, writing, and deleting
818 * (deleting is needed when finished)
820 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName
, &NtReplacementName
, NULL
, NULL
)))
822 Error
= ERROR_PATH_NOT_FOUND
;
826 InitializeObjectAttributes(&ObjectAttributes
,
828 OBJ_CASE_INSENSITIVE
,
832 Status
= NtOpenFile(&hReplacement
,
833 GENERIC_READ
| DELETE
| SYNCHRONIZE
,
837 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
| FILE_DELETE_ON_CLOSE
);
839 if (!NT_SUCCESS(Status
))
841 Error
= RtlNtStatusToDosError(Status
);
845 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 0x10000) ;
848 Error
= ERROR_NOT_ENOUGH_MEMORY
;
851 while (Status
!= STATUS_END_OF_FILE
)
853 Status
= NtReadFile(hReplacement
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
, 0x10000, NULL
, NULL
) ;
854 if (NT_SUCCESS(Status
))
856 Status
= NtWriteFile(hReplaced
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
,
857 IoStatusBlock
.Information
, NULL
, NULL
) ;
858 if (!NT_SUCCESS(Status
))
860 Error
= RtlNtStatusToDosError(Status
);
864 else if (Status
!= STATUS_END_OF_FILE
)
866 Error
= RtlNtStatusToDosError(Status
);
873 /* Perform resource cleanup */
875 if (hReplaced
) NtClose(hReplaced
);
876 if (hReplacement
) NtClose(hReplacement
);
877 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
879 if (NtReplacementName
.Buffer
)
880 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName
.Buffer
);
881 if (NtReplacedName
.Buffer
)
882 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName
.Buffer
);
884 /* If there was an error, set the error code */
887 TRACE("ReplaceFileW failed (error=%lu)\n", Error
);
898 PrivMoveFileIdentityW(DWORD Unknown1
, DWORD Unknown2
, DWORD Unknown3
)