ReactOS 0.4.16-dev-2293-g4d8327b
move.c File Reference
#include <k32.h>
#include <malloc.h>
#include <debug.h>
Include dependency graph for move.c:

Go to the source code of this file.

Classes

struct  _COPY_PROGRESS_CONTEXT
 

Macros

#define NDEBUG
 
#define STRING_LENGTH   0x400
 

Typedefs

typedef struct _COPY_PROGRESS_CONTEXT COPY_PROGRESS_CONTEXT
 
typedef struct _COPY_PROGRESS_CONTEXTPCOPY_PROGRESS_CONTEXT
 

Functions

 DEBUG_CHANNEL (kernel32file)
 
NTSTATUS WINAPI BasepMoveFileDelayed (_In_ PUNICODE_STRING ExistingPath, _In_ PUNICODE_STRING NewPath, _In_ INT KeyId, _In_ BOOL CreateIfNotFound)
 Adds an entry in the "PendingFileRenameOperations" registry value, that is parsed at boot-time by SMSS.EXE to check whether there are some files to be renamed/moved or deleted.
 
DWORD WINAPI BasepGetComputerNameFromNtPath (IN PUNICODE_STRING NewPath, IN HANDLE NewHandle, OUT PWSTR ComputerName, IN OUT PULONG ComputerNameLength)
 
NTSTATUS WINAPI BasepNotifyTrackingService (IN OUT PHANDLE ExistingHandle, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE NewHandle, IN PUNICODE_STRING NewPath)
 
NTSTATUS WINAPI BasepOpenFileForMove (IN LPCWSTR File, OUT PUNICODE_STRING RelativeNtName, OUT LPWSTR *NtName, OUT PHANDLE FileHandle, OUT POBJECT_ATTRIBUTES ObjectAttributes, IN ACCESS_MASK DesiredAccess, IN ULONG ShareAccess, IN ULONG OpenOptions)
 
DWORD WINAPI BasepMoveFileCopyProgress (IN LARGE_INTEGER TotalFileSize, IN LARGE_INTEGER TotalBytesTransferred, IN LARGE_INTEGER StreamSize, IN LARGE_INTEGER StreamBytesTransferred, IN DWORD dwStreamNumber, IN DWORD dwCallbackReason, IN HANDLE hSourceFile, IN HANDLE hDestinationFile, IN LPVOID lpData OPTIONAL)
 
BOOL WINAPI MoveFileWithProgressW (IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN LPPROGRESS_ROUTINE lpProgressRoutine, IN LPVOID lpData, IN DWORD dwFlags)
 
BOOL WINAPI MoveFileW (IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName)
 
BOOL WINAPI MoveFileExW (IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName OPTIONAL, IN DWORD dwFlags)
 
BOOL WINAPI ReplaceFileW (LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName, LPCWSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved)
 
BOOL WINAPI PrivMoveFileIdentityW (IN LPCWSTR lpSource, IN LPCWSTR lpDestination, IN DWORD dwFlags)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 17 of file move.c.

◆ STRING_LENGTH

#define STRING_LENGTH   0x400

Typedef Documentation

◆ COPY_PROGRESS_CONTEXT

◆ PCOPY_PROGRESS_CONTEXT

Function Documentation

◆ BasepGetComputerNameFromNtPath()

DWORD WINAPI BasepGetComputerNameFromNtPath ( IN PUNICODE_STRING  NewPath,
IN HANDLE  NewHandle,
OUT PWSTR  ComputerName,
IN OUT PULONG  ComputerNameLength 
)

Definition at line 236 of file move.c.

240{
241 BOOL Query = FALSE;
243 PWSTR AbsolutePath, EndOfName;
244 USHORT AbsolutePathLength, NameLength;
246 WCHAR DeviceName[] = {'A', ':', '\0'}; /* Init to something, will be set later */
247 UNICODE_STRING UncString = RTL_CONSTANT_STRING(L"\\??\\UNC\\");
248 UNICODE_STRING GlobalString = RTL_CONSTANT_STRING(L"\\??\\");
249
250 DPRINT("BasepGetComputerNameFromNtPath(%wZ, %p, %p, %lu)\n",
251 NewPath, NewHandle, ComputerName, ComputerNameLength);
252
253 /* If it's an UNC path */
254 if (RtlPrefixUnicodeString(&UncString, NewPath, TRUE))
255 {
256 /* Check for broken caller */
257 if (NewPath->Length <= UncString.Length)
258 {
259 return ERROR_BAD_PATHNAME;
260 }
261
262 /* Skip UNC prefix */
263 AbsolutePath = &NewPath->Buffer[UncString.Length / sizeof(WCHAR)];
264 AbsolutePathLength = NewPath->Length - UncString.Length;
265
266 /* And query DFS */
267 Query = TRUE;
268 }
269 /* Otherwise, we have to be in global (NT path!), with drive letter */
270 else if (RtlPrefixUnicodeString(&GlobalString, NewPath, TRUE) && NewPath->Buffer[5] == ':')
271 {
272 /* Path is like that: \??\C:\Complete Path\To File.ext */
273 /* Get the letter and upcase it if required */
274 Letter = NewPath->Buffer[4];
275 if (Letter >= 'a' && Letter <= 'z')
276 {
277 Letter -= ('a' - 'A');
278 }
279 DeviceName[0] = Letter;
280
281 /* Query the associated DOS device */
283 {
284 return GetLastError();
285 }
286
287 /* If that's a network share */
288 if (TargetDevice == wcsstr(TargetDevice, L"\\Device\\LanmanRedirector\\;"))
289 {
290 /* Path is like that: \Device\LanmanRedirector\;C:0000000000000000\Complete Path\To File.ext */
291 /* Check we have the correct drive letter */
292 if (TargetDevice[26] == DeviceName[0] &&
293 TargetDevice[27] == ':')
294 {
295 /* Check for the path begin, computer name is before */
296 PWSTR Path = wcschr(&TargetDevice[28], L'\\');
297 if (Path == NULL)
298 {
299 return ERROR_BAD_PATHNAME;
300 }
301
302 AbsolutePath = Path + 1;
303 AbsolutePathLength = sizeof(WCHAR) * (ARRAYSIZE(TargetDevice) - (AbsolutePath - TargetDevice));
304 }
305 else
306 {
307 return ERROR_BAD_PATHNAME;
308 }
309 }
310 /* If it's a local device */
311 else if (TargetDevice == wcsstr(TargetDevice, L"\\Device\\Harddisk")
312 || TargetDevice == wcsstr(TargetDevice, L"\\Device\\CdRom")
313 || TargetDevice == wcsstr(TargetDevice, L"\\Device\\Floppy"))
314 {
315 /* Just query the computer name */
316 if (!GetComputerNameW(ComputerName, ComputerNameLength))
317 {
318 return GetLastError();
319 }
320
321 return ERROR_SUCCESS;
322 }
323 /* If it's a DFS share */
324 else if (TargetDevice == wcsstr(TargetDevice, L"\\Device\\WinDfs\\"))
325 {
326 /* Obviously, query DFS */
327 Query = TRUE;
328 }
329 else
330 {
331 return ERROR_BAD_PATHNAME;
332 }
333 }
334 else
335 {
336 return ERROR_BAD_PATHNAME;
337 }
338
339 /* Query DFS, currently not implemented - shouldn't be missing in ReactOS yet ;-) */
340 if (Query)
341 {
342 UNIMPLEMENTED_DBGBREAK("Querying DFS not implemented!\n");
343 AbsolutePath = NULL;
344 AbsolutePathLength = 0;
345 }
346
347 /* Now, properly extract the computer name from the full path */
348 EndOfName = AbsolutePath;
349 if (AbsolutePathLength)
350 {
351 for (NameLength = 0; NameLength < AbsolutePathLength; NameLength += sizeof(WCHAR))
352 {
353 /* Look for the next \, it will be the end of computer name */
354 if (EndOfName[0] == L'\\')
355 {
356 break;
357 }
358 /* Computer name cannot contain ., if we get to that point, something went wrong... */
359 else if (EndOfName[0] == L'.')
360 {
361 return ERROR_BAD_PATHNAME;
362 }
363
364 ++EndOfName;
365 }
366 }
367
368 NameLength = EndOfName - AbsolutePath;
369 /* Check we didn't overflow and that our computer name isn't ill-formed */
370 if (NameLength >= AbsolutePathLength || NameLength >= MAX_COMPUTERNAME_LENGTH * sizeof(WCHAR))
371 {
372 return ERROR_BAD_PATHNAME;
373 }
374
375 /* Check we can fit */
376 if (NameLength + sizeof(UNICODE_NULL) > *ComputerNameLength * sizeof(WCHAR))
377 {
379 }
380
381 /* Write, zero and done! */
382 RtlCopyMemory(ComputerName, AbsolutePath, NameLength);
383 *ComputerNameLength = NameLength / sizeof(WCHAR);
384 ComputerName[NameLength / sizeof(WCHAR)] = UNICODE_NULL;
385
386 return ERROR_SUCCESS;
387}
WCHAR Letter
PRTL_UNICODE_STRING_BUFFER Path
BOOL Query(LPCTSTR *ServiceArgs, DWORD ArgCount, BOOL bExtended)
Definition: query.c:292
BOOL WINAPI GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
Definition: compname.c:446
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define wcschr
Definition: compat.h:17
#define MAX_PATH
Definition: compat.h:34
DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax)
Definition: dosdev.c:542
_ACRTIMP wchar_t *__cdecl wcsstr(const wchar_t *, const wchar_t *)
Definition: wcs.c:2993
#define L(x)
Definition: resources.c:13
#define UNIMPLEMENTED_DBGBREAK(...)
Definition: debug.h:57
unsigned int BOOL
Definition: ntddk_ex.h:94
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
#define UNICODE_NULL
unsigned short USHORT
Definition: pedump.c:61
#define DPRINT
Definition: sndvol32.h:73
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
uint16_t * PWSTR
Definition: typedefs.h:56
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3281
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define MAX_COMPUTERNAME_LENGTH
Definition: winbase.h:267
#define ERROR_BUFFER_OVERFLOW
Definition: winerror.h:307
#define ERROR_BAD_PATHNAME
Definition: winerror.h:355
_Must_inspect_result_ __drv_aliasesMem PDEVICE_OBJECT _In_ PDEVICE_OBJECT TargetDevice
Definition: iofuncs.h:691
__wchar_t WCHAR
Definition: xmlstorage.h:180

Referenced by BasepNotifyTrackingService().

◆ BasepMoveFileCopyProgress()

DWORD WINAPI BasepMoveFileCopyProgress ( IN LARGE_INTEGER  TotalFileSize,
IN LARGE_INTEGER  TotalBytesTransferred,
IN LARGE_INTEGER  StreamSize,
IN LARGE_INTEGER  StreamBytesTransferred,
IN DWORD  dwStreamNumber,
IN DWORD  dwCallbackReason,
IN HANDLE  hSourceFile,
IN HANDLE  hDestinationFile,
IN LPVOID lpData  OPTIONAL 
)

Definition at line 672 of file move.c.

681{
682 DWORD Ret = 0;
684
685 if (Context->Flags & MOVEFILE_WRITE_THROUGH)
686 {
687 if (!dwCallbackReason)
688 {
689 if (StreamBytesTransferred.QuadPart == StreamSize.QuadPart)
690 {
691 FlushFileBuffers(hDestinationFile);
692 }
693 }
694 }
695
696 if (Context->UserRoutine)
697 {
698 Ret = Context->UserRoutine(TotalFileSize,
699 TotalBytesTransferred,
700 StreamSize,
701 StreamBytesTransferred,
702 dwStreamNumber,
703 dwCallbackReason,
704 hSourceFile,
705 hDestinationFile,
706 Context->UserData);
707 }
708
709 return Ret;
710}
BOOL WINAPI FlushFileBuffers(IN HANDLE hFile)
Definition: fileinfo.c:25
struct _COPY_PROGRESS_CONTEXT * PCOPY_PROGRESS_CONTEXT
#define MOVEFILE_WRITE_THROUGH
Definition: filesup.h:30
unsigned long DWORD
Definition: ntddk_ex.h:95

Referenced by MoveFileWithProgressW().

◆ BasepMoveFileDelayed()

NTSTATUS WINAPI BasepMoveFileDelayed ( _In_ PUNICODE_STRING  ExistingPath,
_In_ PUNICODE_STRING  NewPath,
_In_ INT  KeyId,
_In_ BOOL  CreateIfNotFound 
)

Adds an entry in the "PendingFileRenameOperations" registry value, that is parsed at boot-time by SMSS.EXE to check whether there are some files to be renamed/moved or deleted.

Parameters
[in]ExistingPathFull NT path to the file to rename/move or delete.
[in]NewPathFull NT path to the moved/renamed file; or an empty string if the file is to be deleted.
[in]KeyIdSelects an alternate "PendingFileRenameOperationsXXX" registry value.
[in]CreateIfNotFoundTRUE if the file needs to be created if it does not already exist, FALSE if not.
Remarks
If both ExistingPath and NewPath strings are non-empty, the file is moved, otherwise it is deleted.
Note
The registry value is a list of NULL-terminated strings, which is itself terminated with an empty NULL-terminated string (single 0-byte). When a new entry is added, if NewPath is empty, then the second entry is simply a single NULL. Otherwise the second file path goes there. Each path is in NT format (e.g. path prepended with \??) and the second file path gets also a '!' as the first character if MOVEFILE_REPLACE_EXISTING is specified.

Examples:

\??\D:\test\file1[0] !\??\D:\test\file1_renamed[0] \??\D:\test\delete[0] [0] <- file is to be deleted, second string empty \??\D:\test\file2[0] !\??\D:\test\file2_renamed[0] [0] <- indicates end of strings

or:

\??\D:\test\file1[0] !\??\D:\test\file1_renamed[0] \??\D:\test\delete[0] [0] <- file is to be deleted, second string empty [0] <- indicates end of strings

@implemented

Definition at line 88 of file move.c.

93{
94#define STRING_LENGTH 0x400
97 PVOID Buffer, BufferBegin;
99 PWSTR PendingOperations, BufferWrite;
100 ULONG DataSize, BufferLength, StringLength = STRING_LENGTH;
101 UNICODE_STRING SessionManagerString, PendingOperationsString;
102 /* +6 because a INT shouldn't take more than 6 chars. Especially given the call path */
103 WCHAR PendingOperationsBuffer[sizeof(L"PendingFileRenameOperations") / sizeof(WCHAR) + 6];
104
105 RtlInitUnicodeString(&SessionManagerString,
106 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager");
107
108 /* Select appropriate key for adding our file */
109 if (KeyId == 1)
110 {
111 PendingOperations = L"PendingFileRenameOperations";
112 }
113 else
114 {
115 RtlStringCbPrintfW(PendingOperationsBuffer,
116 sizeof(PendingOperationsBuffer),
117 L"PendingFileRenameOperations%d", KeyId);
118 PendingOperations = PendingOperationsBuffer;
119 }
120 RtlInitUnicodeString(&PendingOperationsString, PendingOperations);
121
123 &SessionManagerString,
125 NULL, NULL);
126
127 /* Open parent key */
133 {
138 }
139
140 if (!NT_SUCCESS(Status))
141 {
142 return Status;
143 }
144
145 /* Reserve enough to read previous string + to append ours with required null chars */
146 BufferLength = NewPath->Length + ExistingPath->Length + STRING_LENGTH + 3 * sizeof(UNICODE_NULL);
147
148 while (TRUE)
149 {
150 /* Allocate output buffer */
151 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
152 if (Buffer == NULL)
153 {
155 return STATUS_NO_MEMORY;
156 }
157
159 &PendingOperationsString,
161 Buffer, StringLength, &DataSize);
163 {
164 break;
165 }
166
167 /* If buffer was too small, reallocate one which is big enough */
168 StringLength = DataSize;
169 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
170 BufferLength = ExistingPath->Length + StringLength + NewPath->Length + 3 * sizeof(UNICODE_NULL);
171 /* Check we didn't overflow */
172 if (BufferLength < StringLength)
173 {
176 }
177 }
178
179 /* Check if it existed; if not, create only IF asked to */
180 if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND || !CreateIfNotFound))
181 {
183 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
184 return Status;
185 }
186
187 if (!NT_SUCCESS(Status))
188 {
189 /* We didn't find any: we create, so use complete buffer */
190 BufferBegin = Buffer;
191 BufferWrite = Buffer;
192 }
193 else
194 {
196
197 /* Get data, the buffer beginning, and where data should be appended
198 * (minus NULL char: this is REG_MULTI_SZ, it already includes double
199 * termination, but we keep only one). */
200 BufferBegin = PartialInfo->Data;
201 BufferWrite = (PWSTR)((ULONG_PTR)PartialInfo->Data + PartialInfo->DataLength - sizeof(UNICODE_NULL));
202 }
203
204 /* First copy existing */
205 RtlCopyMemory(BufferWrite, ExistingPath->Buffer, ExistingPath->Length);
206 BufferWrite += ExistingPath->Length / sizeof(WCHAR);
207 /* And append null char */
208 *BufferWrite = UNICODE_NULL;
209 ++BufferWrite;
210 /* Append destination */
211 RtlCopyMemory(BufferWrite, NewPath->Buffer, NewPath->Length);
212 BufferWrite += NewPath->Length / sizeof(WCHAR);
213 /* And append two null char (end of string) */
214 *BufferWrite = UNICODE_NULL;
215 ++BufferWrite;
216 *BufferWrite = UNICODE_NULL;
217
218 /* Set new value */
220 &PendingOperationsString,
221 0, REG_MULTI_SZ, BufferBegin,
222 (ULONG_PTR)BufferWrite - (ULONG_PTR)BufferBegin + sizeof(WCHAR));
223
225 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
226
227 return Status;
228}
LONG NTSTATUS
Definition: precomp.h:26
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:616
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:634
Definition: bufpool.h:45
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define GENERIC_READ
Definition: compat.h:135
#define STRING_LENGTH
Status
Definition: gdiplustypes.h:25
#define OBJ_OPENIF
Definition: winternl.h:229
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4755
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4715
NTSYSAPI NTSTATUS NTAPI NtSetValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN ULONG TitleIndex OPTIONAL, IN ULONG Type, IN PVOID Data, IN ULONG DataSize)
Definition: ntapi.c:859
@ KeyValuePartialInformation
Definition: nt_native.h:1185
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI NTSTATUS NTAPI NtQueryValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, IN PVOID KeyValueInformation, IN ULONG Length, IN PULONG ResultLength)
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1060
#define REG_OPTION_BACKUP_RESTORE
Definition: nt_native.h:1069
#define REG_MULTI_SZ
Definition: nt_native.h:1504
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
struct _KEY_VALUE_PARTIAL_INFORMATION * PKEY_VALUE_PARTIAL_INFORMATION
#define GENERIC_WRITE
Definition: nt_native.h:90
NTSTATUS NTAPI NtCreateKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex, IN PUNICODE_STRING Class OPTIONAL, IN ULONG CreateOptions, OUT PULONG Disposition OPTIONAL)
Definition: ntapi.c:240
NTSTRSAFEVAPI RtlStringCbPrintfW(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1173
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3777

Referenced by MoveFileWithProgressW().

◆ BasepNotifyTrackingService()

NTSTATUS WINAPI BasepNotifyTrackingService ( IN OUT PHANDLE  ExistingHandle,
IN POBJECT_ATTRIBUTES  ObjectAttributes,
IN HANDLE  NewHandle,
IN PUNICODE_STRING  NewPath 
)

Definition at line 395 of file move.c.

399{
401 ULONG ComputerNameLength, FileAttributes;
402 WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
403 OEM_STRING ComputerNameStringA;
404 CHAR ComputerNameStringBuffer[MAX_PATH + 1];
405 UNICODE_STRING ComputerNameStringW;
408 HANDLE hFullWrite;
409 struct
410 {
412 CHAR Buffer[(MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR)];
413 } FileTrackingInfo;
414
415 DPRINT("BasepNotifyTrackingService(%p, %p, %p, %wZ)\n",
416 *ExistingHandle, ObjectAttributes, NewHandle, NewPath);
417
419 ComputerNameLength = ARRAYSIZE(ComputerName);
420
421 /* Attempt to get computer name of target handle */
422 if (BasepGetComputerNameFromNtPath(NewPath, NewHandle, ComputerName, &ComputerNameLength))
423 {
424 /* If we failed to get it, we will just notify with the handle */
425 FileTrackingInfo.ObjectInformationLength = 0;
426 }
427 else
428 {
429 /* Convert the retrieved computer name to ANSI and attach it to the notification */
430 RtlInitEmptyAnsiString(&ComputerNameStringA,
431 ComputerNameStringBuffer,
432 sizeof(ComputerNameStringBuffer));
433
434 RtlInitUnicodeString(&ComputerNameStringW, ComputerName);
435 Status = RtlUnicodeStringToOemString(&ComputerNameStringA, &ComputerNameStringW, FALSE);
436 if (!NT_SUCCESS(Status))
437 {
438 return Status;
439 }
440
441 RtlCopyMemory(FileTrackingInfo.ObjectInformation, ComputerNameStringA.Buffer, ComputerNameStringA.Length);
442 FileTrackingInfo.ObjectInformation[ComputerNameStringA.Length] = ANSI_NULL;
443 FileTrackingInfo.ObjectInformationLength = ComputerNameStringA.Length + 1;
444 }
445
446 /* Attach the handle we moved */
447 FileTrackingInfo.DestinationFile = NewHandle;
448
449 /* Final, notify */
450 Status = NtSetInformationFile(*ExistingHandle,
452 &FileTrackingInfo,
453 sizeof(FileTrackingInfo),
456 {
457 return Status;
458 }
459
460 /* If we get here, we got access denied error, this comes from a
461 * read-only flag. So, close the file, in order to reopen it with enough
462 * rights to remove said flag and reattempt notification.
463 */
464 CloseHandle(*ExistingHandle);
465
466 /* Reopen it, to be able to change the destination file attributes */
467 Status = NtOpenFile(ExistingHandle,
473 if (!NT_SUCCESS(Status))
474 {
475 *ExistingHandle = INVALID_HANDLE_VALUE;
476 return Status;
477 }
478
479 /* Get the file attributes */
480 Status = NtQueryInformationFile(*ExistingHandle,
483 sizeof(FileBasicInfo),
485 if (!NT_SUCCESS(Status))
486 {
487 return Status;
488 }
489
490 /* Get rid of the read only flag */
491 FileAttributes = FileBasicInfo.FileAttributes & ~FILE_ATTRIBUTE_READONLY;
493 FileBasicInfo.FileAttributes = FileAttributes;
494
495 /* Attempt... */
496 Status = NtSetInformationFile(*ExistingHandle,
499 sizeof(FileBasicInfo),
501 if (!NT_SUCCESS(Status))
502 {
503 return Status;
504 }
505
506 /* Now, reopen with maximum accesses to notify */
507 Status = NtOpenFile(&hFullWrite,
513 if (NT_SUCCESS(Status))
514 {
515 NtClose(*ExistingHandle);
516 *ExistingHandle = hFullWrite;
517
518 /* Full success, notify! */
519 Status = NtSetInformationFile(*ExistingHandle,
521 &FileTrackingInfo,
522 sizeof(FileTrackingInfo),
524 }
525
526 /* If opening with full access failed or if notify failed, restore read-only */
527 if (!NT_SUCCESS(Status))
528 {
529 FileBasicInfo.FileAttributes |= FILE_ATTRIBUTE_READONLY;
530
531 Status = NtSetInformationFile(*ExistingHandle,
534 sizeof(FileBasicInfo),
536 }
537
538 /* We're done */
539 return Status;
540}
#define CloseHandle
Definition: compat.h:739
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define FILE_SHARE_READ
Definition: compat.h:136
DWORD WINAPI BasepGetComputerNameFromNtPath(IN PUNICODE_STRING NewPath, IN HANDLE NewHandle, OUT PWSTR ComputerName, IN OUT PULONG ComputerNameLength)
Definition: move.c:236
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE _In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Out_ PIO_STATUS_BLOCK _In_opt_ PLARGE_INTEGER _In_ ULONG FileAttributes
Definition: fltkernel.h:1236
@ FileTrackingInformation
Definition: from_kernel.h:97
@ FileBasicInformation
Definition: from_kernel.h:65
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
@ FileBasicInfo
Definition: minwinbase.h:304
NTSYSAPI NTSTATUS NTAPI RtlUnicodeStringToOemString(POEM_STRING DestinationString, PCUNICODE_STRING SourceString, BOOLEAN AllocateDestinationString)
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3953
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
NTSYSAPI NTSTATUS NTAPI NtSetInformationFile(IN HANDLE hFile, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN PVOID FileInformationBuffer, IN ULONG FileInformationBufferLength, IN FILE_INFORMATION_CLASS FileInfoClass)
Definition: iofunc.c:3096
NTSYSAPI NTSTATUS NTAPI NtQueryInformationFile(IN HANDLE hFile, OUT PIO_STATUS_BLOCK pIoStatusBlock, OUT PVOID FileInformationBuffer, IN ULONG FileInformationBufferLength, IN FILE_INFORMATION_CLASS FileInfoClass)
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
#define FILE_WRITE_ATTRIBUTES
Definition: nt_native.h:649
#define ANSI_NULL
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define STATUS_SUCCESS
Definition: shellext.h:65
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
STRING OEM_STRING
Definition: umtypes.h:205
struct _FILE_TRACKING_INFORMATION FILE_TRACKING_INFORMATION
char CHAR
Definition: xmlstorage.h:175

Referenced by MoveFileWithProgressW(), and PrivMoveFileIdentityW().

◆ BasepOpenFileForMove()

NTSTATUS WINAPI BasepOpenFileForMove ( IN LPCWSTR  File,
OUT PUNICODE_STRING  RelativeNtName,
OUT LPWSTR NtName,
OUT PHANDLE  FileHandle,
OUT POBJECT_ATTRIBUTES  ObjectAttributes,
IN ACCESS_MASK  DesiredAccess,
IN ULONG  ShareAccess,
IN ULONG  OpenOptions 
)

Definition at line 548 of file move.c.

556{
557 RTL_RELATIVE_NAME_U RelativeName;
561 ULONG IntShareAccess;
562 BOOLEAN HasRelative = FALSE;
563
565 {
566 /* Zero output */
567 RtlInitEmptyUnicodeString(RelativeNtName, NULL, 0);
568 *NtName = NULL;
569
570 if (!RtlDosPathNameToRelativeNtPathName_U(File, RelativeNtName, NULL, &RelativeName))
571 {
574 }
575
576 HasRelative = TRUE;
577 *NtName = RelativeNtName->Buffer;
578
579 if (RelativeName.RelativeName.Length)
580 {
581 RelativeNtName->Length = RelativeName.RelativeName.Length;
582 RelativeNtName->MaximumLength = RelativeName.RelativeName.MaximumLength;
583 RelativeNtName->Buffer = RelativeName.RelativeName.Buffer;
584 }
585 else
586 {
587 RelativeName.ContainingDirectory = NULL;
588 }
589
591 RelativeNtName,
593 RelativeName.ContainingDirectory,
594 NULL);
595 /* Force certain flags here, given ops we'll do */
596 IntShareAccess = ShareAccess | FILE_SHARE_READ | FILE_SHARE_WRITE;
598
599 /* We'll try to read reparse tag */
604 IntShareAccess,
606 if (NT_SUCCESS(Status))
607 {
608 /* Attempt the read */
611 &TagInfo,
612 sizeof(TagInfo),
614
615 /* Return if failure with a status that wouldn't mean the FSD cannot support reparse points */
616 if (!NT_SUCCESS(Status) &&
618 {
620 }
621
622 if (NT_SUCCESS(Status))
623 {
624 /* This cannot happen on mount points */
627 {
629 }
630 }
631
634
635 IntShareAccess = ShareAccess | FILE_SHARE_READ | FILE_SHARE_DELETE;
636 }
638 {
639 IntShareAccess = ShareAccess | FILE_SHARE_READ | FILE_SHARE_WRITE;
640 }
641 else
642 {
644 }
645
646 /* Reattempt to open normally, following reparse point if needed */
651 IntShareAccess,
653 }
655 {
656 if (HasRelative)
657 {
658 RtlReleaseRelativeName(&RelativeName);
659 }
660 }
661 _SEH2_END;
662
663 return Status;
664}
unsigned char BOOLEAN
Definition: actypes.h:127
Definition: File.h:16
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING _In_ PACCESS_MASK _In_ USHORT ShareAccess
Definition: create.c:4148
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
@ FileAttributeTagInformation
Definition: from_kernel.h:96
#define FILE_OPEN_REPARSE_POINT
Definition: from_kernel.h:46
#define FILE_OPEN_FOR_BACKUP_INTENT
Definition: from_kernel.h:42
#define FILE_ATTRIBUTE_DEVICE
Definition: disk.h:27
_Must_inspect_result_ _Out_ PNDIS_STATUS _Out_ PNDIS_STATUS _Out_ PNDIS_HANDLE _Out_ PUINT _In_ UINT _In_ NDIS_HANDLE _In_ NDIS_HANDLE _In_ PNDIS_STRING _In_ UINT OpenOptions
Definition: ndis.h:6017
VOID NTAPI RtlReleaseRelativeName(_In_ PRTL_RELATIVE_NAME_U RelativeName)
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToRelativeNtPathName_U(_In_ PCWSTR DosName, _Out_ PUNICODE_STRING NtName, _Out_ PCWSTR *PartName, _Out_ PRTL_RELATIVE_NAME_U RelativeName)
#define _SEH2_FINALLY
Definition: pseh2_64.h:130
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
#define _SEH2_LEAVE
Definition: pseh2_64.h:183
UNICODE_STRING RelativeName
Definition: rtltypes.h:1374
HANDLE ContainingDirectory
Definition: rtltypes.h:1375
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2664
#define IO_REPARSE_TAG_MOUNT_POINT
Definition: iotypes.h:7234

Referenced by PrivMoveFileIdentityW().

◆ DEBUG_CHANNEL()

DEBUG_CHANNEL ( kernel32file  )

◆ MoveFileExW()

BOOL WINAPI MoveFileExW ( IN LPCWSTR  lpExistingFileName,
IN LPCWSTR lpNewFileName  OPTIONAL,
IN DWORD  dwFlags 
)

Definition at line 1074 of file move.c.

1077{
1078 return MoveFileWithProgressW(lpExistingFileName,
1079 lpNewFileName,
1080 NULL,
1081 NULL,
1082 dwFlags);
1083}
BOOL WINAPI MoveFileWithProgressW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN LPPROGRESS_ROUTINE lpProgressRoutine, IN LPVOID lpData, IN DWORD dwFlags)
Definition: move.c:718
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141

Referenced by _wrename(), BackgroundCopyJob_Complete(), DelayedMove(), do_file_copyW(), msi_move_file(), pendingRename(), and SaveDefaultUserHive().

◆ MoveFileW()

BOOL WINAPI MoveFileW ( IN LPCWSTR  lpExistingFileName,
IN LPCWSTR  lpNewFileName 
)

◆ MoveFileWithProgressW()

BOOL WINAPI MoveFileWithProgressW ( IN LPCWSTR  lpExistingFileName,
IN LPCWSTR  lpNewFileName,
IN LPPROGRESS_ROUTINE  lpProgressRoutine,
IN LPVOID  lpData,
IN DWORD  dwFlags 
)

Definition at line 718 of file move.c.

723{
725 PWSTR NewBuffer;
729 PFILE_RENAME_INFORMATION RenameInfo;
730 UNICODE_STRING NewPathU, ExistingPathU;
732 HANDLE SourceHandle = INVALID_HANDLE_VALUE, NewHandle, ExistingHandle;
733 BOOL Ret = FALSE, ReplaceIfExists, DelayUntilReboot, AttemptReopenWithoutReparse;
734
735 DPRINT("MoveFileWithProgressW(%S, %S, %p, %p, %x)\n",
736 lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags);
737
738 NewPathU.Buffer = NULL;
739 ExistingPathU.Buffer = NULL;
740
742 {
743 /* Don't allow renaming to a disk */
744 if (lpNewFileName && RtlIsDosDeviceName_U(lpNewFileName))
745 {
748 }
749
750 ReplaceIfExists = !!(dwFlags & MOVEFILE_REPLACE_EXISTING);
751
752 /* Get file path */
753 if (!RtlDosPathNameToNtPathName_U(lpExistingFileName, &ExistingPathU, NULL, NULL))
754 {
757 }
758
759 /* Sanitize input */
760 DelayUntilReboot = !!(dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT);
761 if (DelayUntilReboot && (dwFlags & MOVEFILE_CREATE_HARDLINK))
762 {
765 }
766
767 /* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
768 AttemptReopenWithoutReparse = TRUE;
770 &ExistingPathU,
772 NULL,
773 NULL);
774 /* Attempt to open source file */
781 if (!NT_SUCCESS(Status))
782 {
783 /* If we failed and the file doesn't exist, don't attempt to reopen without reparse */
784 if (DelayUntilReboot &&
786 {
787 /* Here we don't fail completely, as we postpone the operation to reboot.
788 * File might exist afterwards, and we don't need a handle here. */
790 AttemptReopenWithoutReparse = FALSE;
791 }
792 /* If we failed for any reason than unsupported reparse, fail completely */
794 {
797 }
798 }
799 else
800 {
801 /* We managed to open, so query information */
804 &TagInfo,
805 sizeof(TagInfo),
807 if (!NT_SUCCESS(Status))
808 {
809 /* Do not tolerate any other error than something related to not supported operation */
811 {
814 }
815
816 /* Not a reparse point, no need to reopen, it's fine */
817 AttemptReopenWithoutReparse = FALSE;
818 }
819 /* Validate the reparse point (do we support it?) */
820 else if ((TagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
822 {
825 }
826 else
827 {
828 /* Mount point, let's rename it */
829 AttemptReopenWithoutReparse = FALSE;
830 }
831 }
832
833 /* Simply reopen if required */
834 if (AttemptReopenWithoutReparse)
835 {
842 if (!NT_SUCCESS(Status))
843 {
846 }
847 }
848
849 /* Nullify string if we're to use it */
850 if (DelayUntilReboot && !lpNewFileName)
851 {
852 RtlInitUnicodeString(&NewPathU, NULL);
853 }
854 /* Check whether path exists */
855 else if (!RtlDosPathNameToNtPathName_U(lpNewFileName, &NewPathU, NULL, NULL))
856 {
859 }
860
861 /* Handle postponed renaming */
862 if (DelayUntilReboot)
863 {
864 /* If new file exists and we're allowed to replace, then mark the path with ! */
865 if (ReplaceIfExists && NewPathU.Length)
866 {
867 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU.Length + sizeof(WCHAR));
868 if (NewBuffer == NULL)
869 {
872 }
873
874 NewBuffer[0] = L'!';
875 RtlCopyMemory(&NewBuffer[1], NewPathU.Buffer, NewPathU.Length);
876 NewPathU.Length += sizeof(WCHAR);
877 NewPathU.MaximumLength += sizeof(WCHAR);
878 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU.Buffer);
879 NewPathU.Buffer = NewBuffer;
880 }
881
882 /* Check whether 'copy' renaming is allowed if required */
883 if ((RtlDetermineDosPathNameType_U(lpExistingFileName) == RtlPathTypeUncAbsolute) ||
885 {
887 }
888 else
889 {
890 /* First, probe 2nd key to see whether it exists - if so, it will be appended there */
891 Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 2, FALSE);
893 {
894 /* If doesn't exist, append to first key first, creating it if it doesn't exist */
895 Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 1, TRUE);
897 {
898 /* If it failed because it's too big, then create 2nd key and put it there */
899 Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 2, TRUE);
900 }
901 }
902 }
903
904 /* If we failed at some point, return the error */
905 if (!NT_SUCCESS(Status))
906 {
909 }
910
911 Ret = TRUE;
913 }
914
915 /* At that point, we MUST have a source handle */
917
918 /* Allocate renaming buffer and fill it */
919 RenameInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0,
920 NewPathU.Length + sizeof(FILE_RENAME_INFORMATION));
921 if (RenameInfo == NULL)
922 {
925 }
926
927 RtlCopyMemory(&RenameInfo->FileName, NewPathU.Buffer, NewPathU.Length);
928 RenameInfo->ReplaceIfExists = ReplaceIfExists;
929 RenameInfo->RootDirectory = NULL;
930 RenameInfo->FileNameLength = NewPathU.Length;
931
932 /* Attempt to rename the file */
935 RenameInfo,
936 NewPathU.Length + sizeof(FILE_RENAME_INFORMATION),
939 RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo);
940 if (NT_SUCCESS(Status))
941 {
942 /* If it succeed, all fine, quit */
943 Ret = TRUE;
945 }
946 /* If we failed for any other reason than not the same device, fail.
947 * If we failed because of different devices, only allow renaming if user allowed copy.
948 */
950 {
951 /* ReactOS HACK! To be removed once all FSD have proper renaming support.
952 * Just leave status to error and leave. */
954 {
955 DPRINT1("Forcing copy, renaming not supported by FSD\n");
956 }
957 else
958 {
961 }
962 }
963
964 /* Close source file */
967
968 /* Issue the copy of the file */
969 CopyContext.Flags = dwFlags;
970 CopyContext.UserRoutine = lpProgressRoutine;
971 CopyContext.UserData = lpData;
972 NewHandle = INVALID_HANDLE_VALUE;
973 ExistingHandle = INVALID_HANDLE_VALUE;
974
975 Ret = BasepCopyFileExW(lpExistingFileName,
976 lpNewFileName,
979 NULL,
980 (!ReplaceIfExists ? COPY_FILE_FAIL_IF_EXISTS : 0)
982 0,
983 &ExistingHandle,
984 &NewHandle);
985 if (!Ret)
986 {
987 /* If it failed, don't leak any handle */
988 if (ExistingHandle != INVALID_HANDLE_VALUE)
989 {
990 CloseHandle(ExistingHandle);
991 ExistingHandle = INVALID_HANDLE_VALUE;
992 }
993 }
994 else if (ExistingHandle != INVALID_HANDLE_VALUE)
995 {
996 if (NewHandle != INVALID_HANDLE_VALUE)
997 {
998 /* If copying succeed, notify */
999 Status = BasepNotifyTrackingService(&ExistingHandle,
1001 NewHandle,
1002 &NewPathU);
1003 if (!NT_SUCCESS(Status))
1004 {
1005 /* Fail in case it had to succeed */
1007 {
1008 if (NewHandle != INVALID_HANDLE_VALUE)
1009 CloseHandle(NewHandle);
1010 NewHandle = INVALID_HANDLE_VALUE;
1011 DeleteFileW(lpNewFileName);
1012 Ret = FALSE;
1014 }
1015 }
1016 }
1017
1018 CloseHandle(ExistingHandle);
1019 ExistingHandle = INVALID_HANDLE_VALUE;
1020 }
1021
1022 /* In case copy worked, close file */
1023 if (NewHandle != INVALID_HANDLE_VALUE)
1024 {
1025 CloseHandle(NewHandle);
1026 NewHandle = INVALID_HANDLE_VALUE;
1027 }
1028
1029 /* If it succeed, delete source file */
1030 if (Ret)
1031 {
1032 if (!DeleteFileW(lpExistingFileName))
1033 {
1034 /* Reset file attributes if required */
1035 SetFileAttributesW(lpExistingFileName, FILE_ATTRIBUTE_NORMAL);
1036 DeleteFileW(lpExistingFileName);
1037 }
1038 }
1039 }
1041 {
1044
1045 RtlFreeHeap(RtlGetProcessHeap(), 0, ExistingPathU.Buffer);
1046 RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU.Buffer);
1047 }
1048 _SEH2_END;
1049
1050 return Ret;
1051}
#define DPRINT1
Definition: precomp.h:8
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
BOOL BasepCopyFileExW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, IN LPVOID lpData OPTIONAL, IN LPBOOL pbCancel OPTIONAL, IN DWORD dwCopyFlags, IN DWORD dwBasepFlags, OUT LPHANDLE lpExistingHandle, OUT LPHANDLE lpNewHandle)
Definition: copy.c:202
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
Definition: fileinfo.c:778
NTSTATUS WINAPI BasepMoveFileDelayed(_In_ PUNICODE_STRING ExistingPath, _In_ PUNICODE_STRING NewPath, _In_ INT KeyId, _In_ BOOL CreateIfNotFound)
Adds an entry in the "PendingFileRenameOperations" registry value, that is parsed at boot-time by SMS...
Definition: move.c:88
DWORD WINAPI BasepMoveFileCopyProgress(IN LARGE_INTEGER TotalFileSize, IN LARGE_INTEGER TotalBytesTransferred, IN LARGE_INTEGER StreamSize, IN LARGE_INTEGER StreamBytesTransferred, IN DWORD dwStreamNumber, IN DWORD dwCallbackReason, IN HANDLE hSourceFile, IN HANDLE hDestinationFile, IN LPVOID lpData OPTIONAL)
Definition: move.c:672
NTSTATUS WINAPI BasepNotifyTrackingService(IN OUT PHANDLE ExistingHandle, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE NewHandle, IN PUNICODE_STRING NewPath)
Definition: move.c:395
BOOL WINAPI CopyContext(CONTEXT *dst, DWORD context_flags, CONTEXT *src)
Definition: memory.c:1633
#define MOVEFILE_REPLACE_EXISTING
Definition: filesup.h:28
@ FileRenameInformation
Definition: from_kernel.h:71
@ FileLinkInformation
Definition: from_kernel.h:72
#define FILE_WRITE_THROUGH
Definition: from_kernel.h:26
#define ASSERT(a)
Definition: mode.c:44
_In_ HANDLE SourceHandle
Definition: obfuncs.h:429
NTSYSAPI ULONG NTAPI RtlIsDosDeviceName_U(_In_ PCWSTR Name)
NTSYSAPI RTL_PATH_TYPE NTAPI RtlDetermineDosPathNameType_U(_In_ PCWSTR Path)
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(_In_opt_z_ PCWSTR DosPathName, _Out_ PUNICODE_STRING NtPathName, _Out_opt_ PCWSTR *NtFileNamePart, _Out_opt_ PRTL_RELATIVE_NAME_U DirectoryInfo)
@ RtlPathTypeUncAbsolute
Definition: rtltypes.h:466
#define DELETE
Definition: nt_native.h:57
#define FILE_ATTRIBUTE_REPARSE_POINT
Definition: ntifs_ex.h:381
#define STATUS_NOT_SAME_DEVICE
Definition: ntstatus.h:542
DWORD BaseSetLastNTError(IN NTSTATUS Status)
Definition: reactos.cpp:167
#define STATUS_OBJECT_NAME_COLLISION
Definition: udferr_usr.h:150
#define STATUS_SHARING_VIOLATION
Definition: udferr_usr.h:154
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define COPY_FILE_FAIL_IF_EXISTS
Definition: winbase.h:232
#define COPY_FILE_OPEN_SOURCE_FOR_WRITE
Definition: winbase.h:234
#define MOVEFILE_FAIL_IF_NOT_TRACKABLE
Definition: winbase.h:380
#define MOVEFILE_CREATE_HARDLINK
Definition: winbase.h:379
#define MOVEFILE_DELAY_UNTIL_REBOOT
Definition: winbase.h:377

Referenced by MoveFileExW(), MoveFileW(), MoveFileWithProgressA(), and SHNotifyMoveFileW().

◆ PrivMoveFileIdentityW()

BOOL WINAPI PrivMoveFileIdentityW ( IN LPCWSTR  lpSource,
IN LPCWSTR  lpDestination,
IN DWORD  dwFlags 
)

Definition at line 1244 of file move.c.

1245{
1246 ACCESS_MASK SourceAccess;
1247 UNICODE_STRING NtSource, NtDestination;
1248 LPWSTR RelativeSource, RelativeDestination;
1249 HANDLE SourceHandle, DestinationHandle;
1250 OBJECT_ATTRIBUTES ObjectAttributesSource, ObjectAttributesDestination;
1251 NTSTATUS Status, OldStatus = STATUS_SUCCESS;
1252 ACCESS_MASK DestAccess;
1254 FILE_BASIC_INFORMATION SourceInformation, DestinationInformation;
1256
1257 DPRINT("PrivMoveFileIdentityW(%S, %S, %x)\n", lpSource, lpDestination, dwFlags);
1258
1260 RtlInitEmptyUnicodeString(&NtSource, NULL, 0);
1261 RelativeSource = NULL;
1262 DestinationHandle = INVALID_HANDLE_VALUE;
1263 RtlInitEmptyUnicodeString(&NtDestination, NULL, 0);
1264 RelativeDestination = NULL;
1265
1266 /* FILE_WRITE_DATA is required for later on notification */
1267 SourceAccess = FILE_READ_ATTRIBUTES | FILE_WRITE_DATA;
1269 {
1270 SourceAccess |= DELETE;
1271 }
1272
1273 _SEH2_TRY
1274 {
1275 /* We will loop twice:
1276 * First we attempt to open with FILE_WRITE_DATA for notification.
1277 * If it fails and we have flag for non-trackable files, we retry
1278 * without FILE_WRITE_DATA.
1279 * If that one fails, then, we quit for real.
1280 */
1281 while (TRUE)
1282 {
1283 Status = BasepOpenFileForMove(lpSource,
1284 &NtSource,
1285 &RelativeSource,
1286 &SourceHandle,
1287 &ObjectAttributesSource,
1288 SourceAccess,
1291 if (NT_SUCCESS(Status))
1292 {
1293 break;
1294 }
1295
1296 /* If we already attempted the opening without FILE_WRITE_DATA
1297 * or if we cannot move on non-trackable files, fail.
1298 */
1299 if (!(SourceAccess & FILE_WRITE_DATA) || !(dwFlags & PRIV_ALLOW_NON_TRACKABLE))
1300 {
1302 }
1303
1304 if (RelativeSource)
1305 {
1306 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSource);
1307 RelativeSource = NULL;
1308 }
1309
1311 {
1314 }
1315
1316 SourceAccess &= ~FILE_WRITE_DATA;
1317
1318 /* Remember fist failure in the path */
1319 if (NT_SUCCESS(OldStatus))
1320 {
1321 OldStatus = Status;
1322 }
1323 }
1324
1325 DestAccess = FILE_WRITE_ATTRIBUTES;
1326 /* If we could preserve FILE_WRITE_DATA for source, attempt to
1327 * get it for destination, still for notification purposes. */
1328 if (SourceAccess & FILE_WRITE_DATA)
1329 {
1330 DestAccess |= FILE_WRITE_DATA;
1331 }
1332
1333 /* cf comment for first loop */
1334 while (TRUE)
1335 {
1336 Status = BasepOpenFileForMove(lpDestination,
1337 &NtDestination,
1338 &RelativeDestination,
1339 &DestinationHandle,
1340 &ObjectAttributesDestination,
1341 DestAccess,
1344 if (NT_SUCCESS(Status))
1345 {
1346 break;
1347 }
1348
1349 /* If we already attempted the opening without FILE_WRITE_DATA
1350 * or if we cannot move on non-trackable files, fail.
1351 */
1352 if (!(DestAccess & FILE_WRITE_DATA) || !(dwFlags & PRIV_ALLOW_NON_TRACKABLE))
1353 {
1355 }
1356
1357 if (RelativeDestination)
1358 {
1359 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeDestination);
1360 RelativeDestination = NULL;
1361 }
1362
1363 if (DestinationHandle != INVALID_HANDLE_VALUE)
1364 {
1365 NtClose(DestinationHandle);
1366 DestinationHandle = INVALID_HANDLE_VALUE;
1367 }
1368
1369 DestAccess &= ~FILE_WRITE_DATA;
1370
1371 /* Remember fist failure in the path */
1372 if (NT_SUCCESS(OldStatus))
1373 {
1374 OldStatus = Status;
1375 }
1376 }
1377
1378 /* Get the creation time from source */
1381 &SourceInformation,
1382 sizeof(SourceInformation),
1384 if (NT_SUCCESS(Status))
1385 {
1386 /* Then, prepare to set it for destination */
1387 RtlZeroMemory(&DestinationInformation, sizeof(DestinationInformation));
1388 DestinationInformation.CreationTime.QuadPart = SourceInformation.CreationTime.QuadPart;
1389
1390 /* And set it, that's all folks! */
1391 Status = NtSetInformationFile(DestinationHandle,
1393 &DestinationInformation,
1394 sizeof(DestinationInformation),
1396 }
1397
1398 if (!NT_SUCCESS(Status))
1399 {
1401 {
1403 }
1404
1405 /* Remember the failure for later notification */
1406 if (NT_SUCCESS(OldStatus))
1407 {
1408 OldStatus = Status;
1409 }
1410 }
1411
1412 /* If we could open with FILE_WRITE_DATA both source and destination,
1413 * then, notify
1414 */
1415 if (DestAccess & FILE_WRITE_DATA && SourceAccess & FILE_WRITE_DATA)
1416 {
1418 &ObjectAttributesSource,
1419 DestinationHandle,
1420 &NtDestination);
1421 if (!NT_SUCCESS(Status))
1422 {
1424 {
1425 if (NT_SUCCESS(OldStatus))
1426 OldStatus = Status;
1427
1428 /* Reset status, we allow non trackable files */
1430 }
1431 }
1432 }
1433 }
1435 {
1436 if (RelativeSource)
1437 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSource);
1438
1439 if (RelativeDestination)
1440 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeDestination);
1441 }
1442 _SEH2_END;
1443
1444 /* If caller asked for source deletion, if everything succeed, proceed */
1446 {
1447 FileDispositionInfo.DeleteFile = TRUE;
1448
1452 sizeof(FileDispositionInfo),
1454 }
1455
1456 /* Cleanup/close portion */
1457 if (DestinationHandle != INVALID_HANDLE_VALUE)
1458 {
1459 NtClose(DestinationHandle);
1460 }
1461
1463 {
1465 }
1466
1467 /* Set last error if any, and quit */
1468 if (NT_SUCCESS(Status))
1469 {
1470 if (!NT_SUCCESS(OldStatus))
1471 {
1472 BaseSetLastNTError(OldStatus);
1473 }
1474 }
1475 else
1476 {
1478 }
1479
1480 return NT_SUCCESS(Status);
1481}
NTSTATUS WINAPI BasepOpenFileForMove(IN LPCWSTR File, OUT PUNICODE_STRING RelativeNtName, OUT LPWSTR *NtName, OUT PHANDLE FileHandle, OUT POBJECT_ATTRIBUTES ObjectAttributes, IN ACCESS_MASK DesiredAccess, IN ULONG ShareAccess, IN ULONG OpenOptions)
Definition: move.c:548
@ FileDispositionInformation
Definition: from_kernel.h:74
#define FILE_OPEN_NO_RECALL
Definition: from_kernel.h:47
#define PRIV_ALLOW_NON_TRACKABLE
Definition: kernel32.h:131
#define PRIV_DELETE_ON_SUCCESS
Definition: kernel32.h:130
@ FileDispositionInfo
Definition: minwinbase.h:308
#define FILE_WRITE_DATA
Definition: nt_native.h:631
ULONG ACCESS_MASK
Definition: nt_native.h:40
LARGE_INTEGER CreationTime
Definition: nt_native.h:942
LONGLONG QuadPart
Definition: typedefs.h:114
WCHAR * LPWSTR
Definition: xmlstorage.h:184

◆ ReplaceFileW()

BOOL WINAPI ReplaceFileW ( LPCWSTR  lpReplacedFileName,
LPCWSTR  lpReplacementFileName,
LPCWSTR  lpBackupFileName,
DWORD  dwReplaceFlags,
LPVOID  lpExclude,
LPVOID  lpReserved 
)

Definition at line 1090 of file move.c.

1098{
1099 HANDLE hReplaced = NULL, hReplacement = NULL;
1100 UNICODE_STRING NtReplacedName = { 0, 0, NULL };
1101 UNICODE_STRING NtReplacementName = { 0, 0, NULL };
1104 BOOL Ret = FALSE;
1107 PVOID Buffer = NULL ;
1108
1109 if (dwReplaceFlags)
1110 FIXME("Ignoring flags %x\n", dwReplaceFlags);
1111
1112 /* First two arguments are mandatory */
1113 if (!lpReplacedFileName || !lpReplacementFileName)
1114 {
1116 return FALSE;
1117 }
1118
1119 /* Back it up */
1120 if(lpBackupFileName)
1121 {
1122 if(!CopyFileW(lpReplacedFileName, lpBackupFileName, FALSE))
1123 {
1124 Error = GetLastError();
1125 goto Cleanup ;
1126 }
1127 }
1128
1129 /* Open the "replaced" file for reading and writing */
1130 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &NtReplacedName, NULL, NULL)))
1131 {
1133 goto Cleanup;
1134 }
1135
1137 &NtReplacedName,
1139 NULL,
1140 NULL);
1141
1142 Status = NtOpenFile(&hReplaced,
1148
1149 if (!NT_SUCCESS(Status))
1150 {
1153 else
1155 goto Cleanup;
1156 }
1157
1158 /* Blank it */
1159 SetEndOfFile(hReplaced) ;
1160
1161 /*
1162 * Open the replacement file for reading, writing, and deleting
1163 * (deleting is needed when finished)
1164 */
1165 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &NtReplacementName, NULL, NULL)))
1166 {
1168 goto Cleanup;
1169 }
1170
1172 &NtReplacementName,
1174 NULL,
1175 NULL);
1176
1177 Status = NtOpenFile(&hReplacement,
1181 0,
1183
1184 if (!NT_SUCCESS(Status))
1185 {
1187 goto Cleanup;
1188 }
1189
1190 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x10000) ;
1191 if (!Buffer)
1192 {
1194 goto Cleanup ;
1195 }
1196 while (Status != STATUS_END_OF_FILE)
1197 {
1198 Status = NtReadFile(hReplacement, NULL, NULL, NULL, &IoStatusBlock, Buffer, 0x10000, NULL, NULL) ;
1199 if (NT_SUCCESS(Status))
1200 {
1203 if (!NT_SUCCESS(Status))
1204 {
1206 goto Cleanup;
1207 }
1208 }
1209 else if (Status != STATUS_END_OF_FILE)
1210 {
1212 goto Cleanup;
1213 }
1214 }
1215
1216 Ret = TRUE;
1217
1218 /* Perform resource cleanup */
1219Cleanup:
1220 if (hReplaced) NtClose(hReplaced);
1221 if (hReplacement) NtClose(hReplacement);
1222 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1223
1224 if (NtReplacementName.Buffer)
1225 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName.Buffer);
1226 if (NtReplacedName.Buffer)
1227 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName.Buffer);
1228
1229 /* If there was an error, set the error code */
1230 if(!Ret)
1231 {
1232 TRACE("ReplaceFileW failed (error=%lu)\n", Error);
1234 }
1235 return Ret;
1236}
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
#define FILE_DELETE_ON_CLOSE
Definition: constants.h:494
#define FIXME(fmt,...)
Definition: precomp.h:53
BOOL Error
Definition: chkdsk.c:66
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define SetLastError(x)
Definition: compat.h:752
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
BOOL WINAPI CopyFileW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN BOOL bFailIfExists)
Definition: copy.c:365
BOOL WINAPI SetEndOfFile(HANDLE hFile)
Definition: fileinfo.c:988
static const WCHAR Cleanup[]
Definition: register.c:80
NTSYSAPI ULONG WINAPI RtlNtStatusToDosError(NTSTATUS)
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
#define WRITE_DAC
Definition: nt_native.h:59
NTSYSAPI NTSTATUS NTAPI NtWriteFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN PVOID WriteBuffer, IN ULONG WriteBufferLength, IN PLARGE_INTEGER FileOffset OPTIONAL, IN PULONG LockOperationKey OPTIONAL)
#define STATUS_END_OF_FILE
Definition: shellext.h:67
NTSTATUS NTAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
#define TRACE(s)
Definition: solgame.cpp:4
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:228
#define ERROR_UNABLE_TO_REMOVE_REPLACED
Definition: winerror.h:1020

Referenced by CZipFolder::DeleteItems(), and ReplaceFileA().