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
);
99 /* Allocate output buffer */
100 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength
);
104 return STATUS_NO_MEMORY
;
107 Status
= NtQueryValueKey(KeyHandle
,
108 &PendingOperationsString
,
109 KeyValuePartialInformation
,
110 Buffer
, StringLength
, &DataSize
);
111 if (Status
!= STATUS_BUFFER_OVERFLOW
)
116 /* If buffer was too small, then, reallocate one which is big enough */
117 StringLength
= DataSize
;
118 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
119 BufferLength
= ExistingPath
->Length
+ StringLength
+ NewPath
->Length
+ 3 * sizeof(UNICODE_NULL
);
120 /* Check we didn't overflow */
121 if (BufferLength
< StringLength
)
124 return STATUS_BUFFER_TOO_SMALL
;
128 /* Check if it existed - if not, create only IF asked to */
129 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
|| !CreateIfNotFound
))
132 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
136 if (!NT_SUCCESS(Status
))
138 /* We didn't find any - ie, we create, so use complete buffer */
139 BufferBegin
= Buffer
;
140 BufferWrite
= Buffer
;
144 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
146 /* Get data, our buffer begin and then where we should append data
147 * (- null char, this is REG_MULTI_SZ, it already includes double termination, we keep only one)
149 BufferBegin
= PartialInfo
->Data
;
150 BufferWrite
= (PWSTR
)((ULONG_PTR
)PartialInfo
->Data
+ PartialInfo
->DataLength
- sizeof(UNICODE_NULL
));
153 /* First copy existing */
154 RtlCopyMemory(BufferWrite
, ExistingPath
->Buffer
, ExistingPath
->Length
);
155 BufferWrite
+= ExistingPath
->Length
/ sizeof(WCHAR
);
156 /* And append null char */
157 *BufferWrite
= UNICODE_NULL
;
159 /* Append destination */
160 RtlCopyMemory(BufferWrite
, NewPath
->Buffer
, NewPath
->Length
);
161 BufferWrite
+= NewPath
->Length
/ sizeof(WCHAR
);
162 /* And append two null char (end of string) */
163 *BufferWrite
= UNICODE_NULL
;
165 *BufferWrite
= UNICODE_NULL
;
168 Status
= NtSetValueKey(KeyHandle
,
169 &PendingOperationsString
,
170 0, REG_MULTI_SZ
, BufferBegin
,
171 (ULONG_PTR
)BufferWrite
- (ULONG_PTR
)BufferBegin
+ sizeof(WCHAR
));
174 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
185 BasepNotifyTrackingService(IN PHANDLE ExistingHandle
,
186 IN POBJECT_ATTRIBUTES ObjectAttributes
,
188 IN PUNICODE_STRING NewPath
)
190 return STATUS_NOT_IMPLEMENTED
;
199 BasepMoveFileCopyProgress(IN LARGE_INTEGER TotalFileSize
,
200 IN LARGE_INTEGER TotalBytesTransferred
,
201 IN LARGE_INTEGER StreamSize
,
202 IN LARGE_INTEGER StreamBytesTransferred
,
203 IN DWORD dwStreamNumber
,
204 IN DWORD dwCallbackReason
,
205 IN HANDLE hSourceFile
,
206 IN HANDLE hDestinationFile
,
207 IN LPVOID lpData OPTIONAL
)
210 PCOPY_PROGRESS_CONTEXT Context
= (PCOPY_PROGRESS_CONTEXT
)lpData
;
212 if (Context
->Flags
& MOVEFILE_WRITE_THROUGH
)
214 if (!dwCallbackReason
)
216 if (StreamBytesTransferred
.QuadPart
== StreamSize
.QuadPart
)
218 FlushFileBuffers(hDestinationFile
);
223 if (Context
->UserRoutine
)
225 Ret
= Context
->UserRoutine(TotalFileSize
,
226 TotalBytesTransferred
,
228 StreamBytesTransferred
,
245 MoveFileWithProgressW(IN LPCWSTR lpExistingFileName
,
246 IN LPCWSTR lpNewFileName
,
247 IN LPPROGRESS_ROUTINE lpProgressRoutine
,
253 IO_STATUS_BLOCK IoStatusBlock
;
254 COPY_PROGRESS_CONTEXT CopyContext
;
255 OBJECT_ATTRIBUTES ObjectAttributes
;
256 PFILE_RENAME_INFORMATION RenameInfo
;
257 UNICODE_STRING NewPathU
, ExistingPathU
;
258 FILE_ATTRIBUTE_TAG_INFORMATION FileAttrTagInfo
;
259 HANDLE SourceHandle
= INVALID_HANDLE_VALUE
, NewHandle
, ExistingHandle
;
260 BOOL Ret
= FALSE
, ReplaceIfExists
, DelayUntilReboot
, AttemptReopenWithoutReparse
;
262 DPRINT("MoveFileWithProgressW(%S, %S, %p, %p, %x)\n", lpExistingFileName
, lpNewFileName
, lpProgressRoutine
, lpData
, dwFlags
);
264 NewPathU
.Buffer
= NULL
;
265 ExistingPathU
.Buffer
= NULL
;
269 /* Don't allow renaming to a disk */
270 if (lpNewFileName
&& RtlIsDosDeviceName_U(lpNewFileName
))
272 BaseSetLastNTError(STATUS_OBJECT_NAME_COLLISION
);
276 ReplaceIfExists
= !!(dwFlags
& MOVEFILE_REPLACE_EXISTING
);
279 if (!RtlDosPathNameToNtPathName_U(lpExistingFileName
, &ExistingPathU
, NULL
, NULL
))
281 BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND
);
286 DelayUntilReboot
= !!(dwFlags
& MOVEFILE_DELAY_UNTIL_REBOOT
);
287 if (DelayUntilReboot
&& (dwFlags
& MOVEFILE_CREATE_HARDLINK
))
289 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
293 /* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
294 AttemptReopenWithoutReparse
= TRUE
;
295 InitializeObjectAttributes(&ObjectAttributes
,
297 OBJ_CASE_INSENSITIVE
,
300 /* Attempt to open source file */
301 Status
= NtOpenFile(&SourceHandle
,
302 FILE_READ_ATTRIBUTES
| DELETE
| SYNCHRONIZE
,
305 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
306 FILE_OPEN_FOR_BACKUP_INTENT
| ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0));
307 if (!NT_SUCCESS(Status
))
309 /* If we failed and the file doesn't exist, don't attempt to reopen without reparse */
310 if (DelayUntilReboot
&&
311 (Status
== STATUS_SHARING_VIOLATION
|| Status
== STATUS_OBJECT_NAME_NOT_FOUND
|| Status
== STATUS_OBJECT_PATH_NOT_FOUND
))
313 /* Here we don't fail completely, as we postpone the operation to reboot
314 * File might exist afterwards, and we don't need a handle here
316 SourceHandle
= INVALID_HANDLE_VALUE
;
317 AttemptReopenWithoutReparse
= FALSE
;
319 /* If we failed for any reason than unsupported reparse, fail completely */
320 else if (Status
!= STATUS_INVALID_PARAMETER
)
322 BaseSetLastNTError(Status
);
328 /* We managed to open, so query information */
329 Status
= NtQueryInformationFile(SourceHandle
,
332 sizeof(FILE_ATTRIBUTE_TAG_INFORMATION
),
333 FileAttributeTagInformation
);
334 if (!NT_SUCCESS(Status
))
336 /* Do not tolerate any other error than something related to not supported operation */
337 if (Status
!= STATUS_NOT_IMPLEMENTED
&& Status
!= STATUS_INVALID_PARAMETER
)
339 BaseSetLastNTError(Status
);
343 /* Not a reparse point, no need to reopen, it's fine */
344 AttemptReopenWithoutReparse
= FALSE
;
346 /* Validate the reparse point (do we support it?) */
347 else if (FileAttrTagInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
&&
348 FileAttrTagInfo
.ReparseTag
!= IO_REPARSE_TAG_MOUNT_POINT
)
350 NtClose(SourceHandle
);
351 SourceHandle
= INVALID_HANDLE_VALUE
;
355 /* Simply reopen if required */
356 if (AttemptReopenWithoutReparse
)
358 Status
= NtOpenFile(&SourceHandle
,
359 DELETE
| SYNCHRONIZE
,
362 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
363 ((dwFlags
& MOVEFILE_WRITE_THROUGH
) ? FILE_WRITE_THROUGH
: 0));
364 if (!NT_SUCCESS(Status
))
366 BaseSetLastNTError(Status
);
371 /* Nullify string if we're to use it */
372 if (DelayUntilReboot
&& !lpNewFileName
)
374 RtlInitUnicodeString(&NewPathU
, 0);
376 /* Check whether path exists */
377 else if (!RtlDosPathNameToNtPathName_U(lpNewFileName
, &NewPathU
, 0, 0))
379 BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND
);
383 /* Handle postponed renaming */
384 if (DelayUntilReboot
)
386 /* If new file exists and we're allowed to replace, then mark the path with ! */
387 if (ReplaceIfExists
&& NewPathU
.Length
)
389 NewBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU
.Length
+ sizeof(WCHAR
));
390 if (NewBuffer
== NULL
)
392 BaseSetLastNTError(STATUS_NO_MEMORY
);
397 RtlCopyMemory(&NewBuffer
[1], NewPathU
.Buffer
, NewPathU
.Length
);
398 NewPathU
.Length
+= sizeof(WCHAR
);
399 NewPathU
.MaximumLength
+= sizeof(WCHAR
);
400 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU
.Buffer
);
401 NewPathU
.Buffer
= NewBuffer
;
404 /* Check whether 'copy' renaming is allowed if required */
405 if (RtlDetermineDosPathNameType_U(lpExistingFileName
) == RtlPathTypeUncAbsolute
|| dwFlags
& MOVEFILE_COPY_ALLOWED
)
407 Status
= STATUS_INVALID_PARAMETER
;
411 /* First, probe 2nd key to see whether it exists - if so, it will be appended there */
412 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 2, FALSE
);
413 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
415 /* If doesn't exist, append to first key first, creating it if it doesn't exist */
416 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 1, TRUE
);
418 if (Status
== STATUS_INSUFFICIENT_RESOURCES
)
420 /* If it failed because it's too big, then create 2nd key and put it there */
421 Status
= BasepMoveFileDelayed(&ExistingPathU
, &NewPathU
, 2, TRUE
);
426 /* If we failed at some point, return the error */
427 if (!NT_SUCCESS(Status
))
429 BaseSetLastNTError(Status
);
437 /* At that point, we MUST have a source handle */
438 ASSERT(SourceHandle
!= INVALID_HANDLE_VALUE
);
440 /* Allocate renaming buffer and fill it */
441 RenameInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU
.Length
+ sizeof(FILE_RENAME_INFORMATION
));
442 if (RenameInfo
== NULL
)
444 BaseSetLastNTError(STATUS_NO_MEMORY
);
448 RtlCopyMemory(&RenameInfo
->FileName
, NewPathU
.Buffer
, NewPathU
.Length
);
449 RenameInfo
->ReplaceIfExists
= ReplaceIfExists
;
450 RenameInfo
->RootDirectory
= 0;
451 RenameInfo
->FileNameLength
= NewPathU
.Length
;
453 /* Attempt to rename the file */
454 Status
= NtSetInformationFile(SourceHandle
,
457 NewPathU
.Length
+ sizeof(FILE_RENAME_INFORMATION
),
458 ((dwFlags
& MOVEFILE_CREATE_HARDLINK
) ? FileLinkInformation
: FileRenameInformation
));
459 RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo
);
460 if (NT_SUCCESS(Status
))
462 /* If it succeed, all fine, quit */
466 /* If we failed for any other reason than not the same device, fail
467 * If we failed because of different devices, only allow renaming if user allowed copy
469 if (Status
!= STATUS_NOT_SAME_DEVICE
|| !(dwFlags
& MOVEFILE_COPY_ALLOWED
))
471 /* ReactOS hack! To be removed once all FSD have proper renaming support
472 * Just leave status to error and leave
474 if (Status
== STATUS_NOT_IMPLEMENTED
)
476 DPRINT1("Forcing copy, renaming not supported by FSD\n");
480 BaseSetLastNTError(Status
);
485 /* Close source file */
486 NtClose(SourceHandle
);
487 SourceHandle
= INVALID_HANDLE_VALUE
;
489 /* Issue the copy of the file */
490 CopyContext
.Flags
= dwFlags
;
491 CopyContext
.UserRoutine
= lpProgressRoutine
;
492 CopyContext
.UserData
= lpData
;
493 NewHandle
= INVALID_HANDLE_VALUE
;
494 ExistingHandle
= INVALID_HANDLE_VALUE
;
496 Ret
= BasepCopyFileExW(lpExistingFileName
,
498 BasepMoveFileCopyProgress
,
501 (ReplaceIfExists
== 0) | COPY_FILE_OPEN_SOURCE_FOR_WRITE
,
507 /* If it failed, don't leak any handle */
508 if (ExistingHandle
!= INVALID_HANDLE_VALUE
)
510 CloseHandle(ExistingHandle
);
511 ExistingHandle
= INVALID_HANDLE_VALUE
;
514 else if (ExistingHandle
!= INVALID_HANDLE_VALUE
)
516 if (NewHandle
!= INVALID_HANDLE_VALUE
)
518 /* If copying succeed, notify */
519 Status
= BasepNotifyTrackingService(&ExistingHandle
, &ObjectAttributes
, NewHandle
, &NewPathU
);
520 if (!NT_SUCCESS(Status
))
522 /* Fail in case it had to succeed */
523 if (dwFlags
& MOVEFILE_FAIL_IF_NOT_TRACKABLE
)
525 if (NewHandle
!= INVALID_HANDLE_VALUE
)
526 CloseHandle(NewHandle
);
527 NewHandle
= INVALID_HANDLE_VALUE
;
528 DeleteFileW(lpNewFileName
);
530 BaseSetLastNTError(Status
);
535 CloseHandle(ExistingHandle
);
536 ExistingHandle
= INVALID_HANDLE_VALUE
;
539 /* In case copy worked, close file */
540 if (NewHandle
!= INVALID_HANDLE_VALUE
)
542 CloseHandle(NewHandle
);
543 NewHandle
= INVALID_HANDLE_VALUE
;
546 /* If it succeed, delete source file */
549 if (!DeleteFileW(lpExistingFileName
))
551 /* Reset file attributes if required */
552 SetFileAttributesW(lpExistingFileName
, FILE_ATTRIBUTE_NORMAL
);
553 DeleteFileW(lpExistingFileName
);
559 if (SourceHandle
!= INVALID_HANDLE_VALUE
)
560 NtClose(SourceHandle
);
562 RtlFreeHeap(RtlGetProcessHeap(), 0, ExistingPathU
.Buffer
);
563 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU
.Buffer
);
576 MoveFileWithProgressA(IN LPCSTR lpExistingFileName
,
577 IN LPCSTR lpNewFileName OPTIONAL
,
578 IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL
,
579 IN LPVOID lpData OPTIONAL
,
583 UNICODE_STRING ExistingFileNameW
, NewFileNameW
;
585 if (!Basep8BitStringToDynamicUnicodeString(&ExistingFileNameW
, lpExistingFileName
))
592 if (!Basep8BitStringToDynamicUnicodeString(&NewFileNameW
, lpNewFileName
))
594 RtlFreeUnicodeString(&ExistingFileNameW
);
600 NewFileNameW
.Buffer
= NULL
;
603 Ret
= MoveFileWithProgressW(ExistingFileNameW
.Buffer
, NewFileNameW
.Buffer
, lpProgressRoutine
, lpData
, dwFlags
);
605 RtlFreeUnicodeString(&ExistingFileNameW
);
606 RtlFreeUnicodeString(&NewFileNameW
);
617 MoveFileW(IN LPCWSTR lpExistingFileName
,
618 IN LPCWSTR lpNewFileName
)
620 return MoveFileWithProgressW(lpExistingFileName
,
624 MOVEFILE_COPY_ALLOWED
);
633 MoveFileExW(IN LPCWSTR lpExistingFileName
,
634 IN LPCWSTR lpNewFileName OPTIONAL
,
637 return MoveFileWithProgressW(lpExistingFileName
,
650 MoveFileA(IN LPCSTR lpExistingFileName
,
651 IN LPCSTR lpNewFileName
)
653 return MoveFileWithProgressA(lpExistingFileName
,
657 MOVEFILE_COPY_ALLOWED
);
666 MoveFileExA(IN LPCSTR lpExistingFileName
,
667 IN LPCSTR lpNewFileName OPTIONAL
,
670 return MoveFileWithProgressA(lpExistingFileName
,
682 ReplaceFileA(IN LPCSTR lpReplacedFileName
,
683 IN LPCSTR lpReplacementFileName
,
684 IN LPCSTR lpBackupFileName OPTIONAL
,
685 IN DWORD dwReplaceFlags
,
687 IN LPVOID lpReserved
)
690 UNICODE_STRING ReplacedFileNameW
, ReplacementFileNameW
, BackupFileNameW
;
692 if (!lpReplacedFileName
|| !lpReplacementFileName
|| lpExclude
|| lpReserved
|| dwReplaceFlags
& ~(REPLACEFILE_WRITE_THROUGH
| REPLACEFILE_IGNORE_MERGE_ERRORS
))
694 SetLastError(ERROR_INVALID_PARAMETER
);
698 if (!Basep8BitStringToDynamicUnicodeString(&ReplacedFileNameW
, lpReplacedFileName
))
703 if (!Basep8BitStringToDynamicUnicodeString(&ReplacementFileNameW
, lpReplacementFileName
))
705 RtlFreeUnicodeString(&ReplacedFileNameW
);
709 if (lpBackupFileName
)
711 if (!Basep8BitStringToDynamicUnicodeString(&BackupFileNameW
, lpBackupFileName
))
713 RtlFreeUnicodeString(&ReplacementFileNameW
);
714 RtlFreeUnicodeString(&ReplacedFileNameW
);
720 BackupFileNameW
.Buffer
= NULL
;
723 Ret
= ReplaceFileW(ReplacedFileNameW
.Buffer
, ReplacementFileNameW
.Buffer
, BackupFileNameW
.Buffer
, dwReplaceFlags
, 0, 0);
725 if (lpBackupFileName
)
727 RtlFreeUnicodeString(&BackupFileNameW
);
729 RtlFreeUnicodeString(&ReplacementFileNameW
);
730 RtlFreeUnicodeString(&ReplacedFileNameW
);
741 LPCWSTR lpReplacedFileName
,
742 LPCWSTR lpReplacementFileName
,
743 LPCWSTR lpBackupFileName
,
744 DWORD dwReplaceFlags
,
749 HANDLE hReplaced
= NULL
, hReplacement
= NULL
;
750 UNICODE_STRING NtReplacedName
= { 0, 0, NULL
};
751 UNICODE_STRING NtReplacementName
= { 0, 0, NULL
};
752 DWORD Error
= ERROR_SUCCESS
;
755 IO_STATUS_BLOCK IoStatusBlock
;
756 OBJECT_ATTRIBUTES ObjectAttributes
;
757 PVOID Buffer
= NULL
;
760 FIXME("Ignoring flags %x\n", dwReplaceFlags
);
762 /* First two arguments are mandatory */
763 if (!lpReplacedFileName
|| !lpReplacementFileName
)
765 SetLastError(ERROR_INVALID_PARAMETER
);
772 if(!CopyFileW(lpReplacedFileName
, lpBackupFileName
, FALSE
))
774 Error
= GetLastError();
779 /* Open the "replaced" file for reading and writing */
780 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName
, &NtReplacedName
, NULL
, NULL
)))
782 Error
= ERROR_PATH_NOT_FOUND
;
786 InitializeObjectAttributes(&ObjectAttributes
,
788 OBJ_CASE_INSENSITIVE
,
792 Status
= NtOpenFile(&hReplaced
,
793 GENERIC_READ
| GENERIC_WRITE
| DELETE
| SYNCHRONIZE
| WRITE_DAC
,
796 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
797 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
799 if (!NT_SUCCESS(Status
))
801 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
802 Error
= ERROR_FILE_NOT_FOUND
;
804 Error
= ERROR_UNABLE_TO_REMOVE_REPLACED
;
809 SetEndOfFile(hReplaced
) ;
812 * Open the replacement file for reading, writing, and deleting
813 * (deleting is needed when finished)
815 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName
, &NtReplacementName
, NULL
, NULL
)))
817 Error
= ERROR_PATH_NOT_FOUND
;
821 InitializeObjectAttributes(&ObjectAttributes
,
823 OBJ_CASE_INSENSITIVE
,
827 Status
= NtOpenFile(&hReplacement
,
828 GENERIC_READ
| DELETE
| SYNCHRONIZE
,
832 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
| FILE_DELETE_ON_CLOSE
);
834 if (!NT_SUCCESS(Status
))
836 Error
= RtlNtStatusToDosError(Status
);
840 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 0x10000) ;
843 Error
= ERROR_NOT_ENOUGH_MEMORY
;
846 while (Status
!= STATUS_END_OF_FILE
)
848 Status
= NtReadFile(hReplacement
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
, 0x10000, NULL
, NULL
) ;
849 if (NT_SUCCESS(Status
))
851 Status
= NtWriteFile(hReplaced
, NULL
, NULL
, NULL
, &IoStatusBlock
, Buffer
,
852 IoStatusBlock
.Information
, NULL
, NULL
) ;
853 if (!NT_SUCCESS(Status
))
855 Error
= RtlNtStatusToDosError(Status
);
859 else if (Status
!= STATUS_END_OF_FILE
)
861 Error
= RtlNtStatusToDosError(Status
);
868 /* Perform resource cleanup */
870 if (hReplaced
) NtClose(hReplaced
);
871 if (hReplacement
) NtClose(hReplacement
);
872 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
874 if (NtReplacementName
.Buffer
)
875 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName
.Buffer
);
876 if (NtReplacedName
.Buffer
)
877 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName
.Buffer
);
879 /* If there was an error, set the error code */
882 TRACE("ReplaceFileW failed (error=%lu)\n", Error
);
893 PrivMoveFileIdentityW(DWORD Unknown1
, DWORD Unknown2
, DWORD Unknown3
)