ReactOS 0.4.16-dev-336-gb667d82
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 MoveFileWithProgressA (IN LPCSTR lpExistingFileName, IN LPCSTR lpNewFileName OPTIONAL, IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, IN LPVOID lpData OPTIONAL, 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 MoveFileA (IN LPCSTR lpExistingFileName, IN LPCSTR lpNewFileName)
 
BOOL WINAPI MoveFileExA (IN LPCSTR lpExistingFileName, IN LPCSTR lpNewFileName OPTIONAL, IN DWORD dwFlags)
 
BOOL WINAPI ReplaceFileA (IN LPCSTR lpReplacedFileName, IN LPCSTR lpReplacementFileName, IN LPCSTR lpBackupFileName OPTIONAL, IN DWORD dwReplaceFlags, IN LPVOID lpExclude, IN LPVOID lpReserved)
 
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
#define UNIMPLEMENTED_DBGBREAK(...)
Definition: debug.h:57
unsigned int BOOL
Definition: ntddk_ex.h:94
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
#define UNICODE_NULL
#define L(x)
Definition: ntvdm.h:50
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:3275
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define MAX_COMPUTERNAME_LENGTH
Definition: winbase.h:269
#define ERROR_BUFFER_OVERFLOW
Definition: winerror.h:185
#define ERROR_BAD_PATHNAME
Definition: winerror.h:233
_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:590
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:608
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:1182
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:1057
#define REG_OPTION_BACKUP_RESTORE
Definition: nt_native.h:1066
#define REG_MULTI_SZ
Definition: nt_native.h:1501
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:3771

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;
407 FILE_BASIC_INFORMATION FileBasicInfo;
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,
482 &FileBasicInfo,
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;
492 RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
493 FileBasicInfo.FileAttributes = FileAttributes;
494
495 /* Attempt... */
496 Status = NtSetInformationFile(*ExistingHandle,
498 &FileBasicInfo,
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 {
530
531 Status = NtSetInformationFile(*ExistingHandle,
533 &FileBasicInfo,
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
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
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:3952
#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
#define STATUS_SUCCESS
Definition: shellext.h:65
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
STRING OEM_STRING
Definition: umtypes.h:203
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: 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:4147
_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:114
#define _SEH2_END
Definition: pseh2_64.h:155
#define _SEH2_TRY
Definition: pseh2_64.h:55
#define _SEH2_LEAVE
Definition: pseh2_64.h:167
UNICODE_STRING RelativeName
Definition: rtltypes.h:1380
HANDLE ContainingDirectory
Definition: rtltypes.h:1381
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:2658
#define IO_REPARSE_TAG_MOUNT_POINT
Definition: iotypes.h:7231

Referenced by PrivMoveFileIdentityW().

◆ DEBUG_CHANNEL()

DEBUG_CHANNEL ( kernel32file  )

◆ MoveFileA()

BOOL WINAPI MoveFileA ( IN LPCSTR  lpExistingFileName,
IN LPCSTR  lpNewFileName 
)

Definition at line 1137 of file move.c.

1139{
1140 return MoveFileWithProgressA(lpExistingFileName,
1141 lpNewFileName,
1142 NULL,
1143 NULL,
1145}
BOOL WINAPI MoveFileWithProgressA(IN LPCSTR lpExistingFileName, IN LPCSTR lpNewFileName OPTIONAL, IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, IN LPVOID lpData OPTIONAL, IN DWORD dwFlags)
Definition: move.c:1059
#define MOVEFILE_COPY_ALLOWED
Definition: filesup.h:29

Referenced by DosInt21h(), mmioDosIOProc(), test_continuouscabs(), test_delete(), test_filenames(), test_FindFirstChangeNotification(), test_MoveFileA(), and VerInstallFileA().

◆ MoveFileExA()

BOOL WINAPI MoveFileExA ( IN LPCSTR  lpExistingFileName,
IN LPCSTR lpNewFileName  OPTIONAL,
IN DWORD  dwFlags 
)

Definition at line 1153 of file move.c.

1156{
1157 return MoveFileWithProgressA(lpExistingFileName,
1158 lpNewFileName,
1159 NULL,
1160 NULL,
1161 dwFlags);
1162}
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176

Referenced by cleanup_eventlog(), process_pending_renames(), and rename().

◆ MoveFileExW()

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

Definition at line 1120 of file move.c.

1123{
1124 return MoveFileWithProgressW(lpExistingFileName,
1125 lpNewFileName,
1126 NULL,
1127 NULL,
1128 dwFlags);
1129}
BOOL WINAPI MoveFileWithProgressW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN LPPROGRESS_ROUTINE lpProgressRoutine, IN LPVOID lpData, IN DWORD dwFlags)
Definition: move.c:718

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 
)

◆ MoveFileWithProgressA()

BOOL WINAPI MoveFileWithProgressA ( IN LPCSTR  lpExistingFileName,
IN LPCSTR lpNewFileName  OPTIONAL,
IN LPPROGRESS_ROUTINE lpProgressRoutine  OPTIONAL,
IN LPVOID lpData  OPTIONAL,
IN DWORD  dwFlags 
)

Definition at line 1059 of file move.c.

1064{
1065 BOOL Ret;
1066 UNICODE_STRING ExistingFileNameW, NewFileNameW;
1067
1068 if (!Basep8BitStringToDynamicUnicodeString(&ExistingFileNameW, lpExistingFileName))
1069 {
1070 return FALSE;
1071 }
1072
1073 if (lpNewFileName)
1074 {
1075 if (!Basep8BitStringToDynamicUnicodeString(&NewFileNameW, lpNewFileName))
1076 {
1077 RtlFreeUnicodeString(&ExistingFileNameW);
1078 return FALSE;
1079 }
1080 }
1081 else
1082 {
1083 NewFileNameW.Buffer = NULL;
1084 }
1085
1086 Ret = MoveFileWithProgressW(ExistingFileNameW.Buffer,
1087 NewFileNameW.Buffer,
1088 lpProgressRoutine,
1089 lpData,
1090 dwFlags);
1091
1092 RtlFreeUnicodeString(&ExistingFileNameW);
1093 RtlFreeUnicodeString(&NewFileNameW);
1094
1095 return Ret;
1096}
BOOLEAN WINAPI Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString, IN LPCSTR String)
Definition: utils.c:225
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)

Referenced by MoveFileA(), and MoveFileExA().

◆ 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;
727 COPY_PROGRESS_CONTEXT CopyContext;
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,
978 &CopyContext,
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:794
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
#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:472
#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:448
DWORD BaseSetLastNTError(IN NTSTATUS Status)
Definition: reactos.cpp:167
LPPROGRESS_ROUTINE UserRoutine
Definition: move.c:27
#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:231
#define COPY_FILE_OPEN_SOURCE_FOR_WRITE
Definition: winbase.h:233
#define MOVEFILE_FAIL_IF_NOT_TRACKABLE
Definition: winbase.h:429
#define MOVEFILE_CREATE_HARDLINK
Definition: winbase.h:428
#define MOVEFILE_DELAY_UNTIL_REBOOT
Definition: winbase.h:426

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

◆ PrivMoveFileIdentityW()

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

Definition at line 1385 of file move.c.

1386{
1387 ACCESS_MASK SourceAccess;
1388 UNICODE_STRING NtSource, NtDestination;
1389 LPWSTR RelativeSource, RelativeDestination;
1390 HANDLE SourceHandle, DestinationHandle;
1391 OBJECT_ATTRIBUTES ObjectAttributesSource, ObjectAttributesDestination;
1392 NTSTATUS Status, OldStatus = STATUS_SUCCESS;
1393 ACCESS_MASK DestAccess;
1395 FILE_BASIC_INFORMATION SourceInformation, DestinationInformation;
1396 FILE_DISPOSITION_INFORMATION FileDispositionInfo;
1397
1398 DPRINT("PrivMoveFileIdentityW(%S, %S, %x)\n", lpSource, lpDestination, dwFlags);
1399
1401 RtlInitEmptyUnicodeString(&NtSource, NULL, 0);
1402 RelativeSource = NULL;
1403 DestinationHandle = INVALID_HANDLE_VALUE;
1404 RtlInitEmptyUnicodeString(&NtDestination, NULL, 0);
1405 RelativeDestination = NULL;
1406
1407 /* FILE_WRITE_DATA is required for later on notification */
1408 SourceAccess = FILE_READ_ATTRIBUTES | FILE_WRITE_DATA;
1410 {
1411 SourceAccess |= DELETE;
1412 }
1413
1414 _SEH2_TRY
1415 {
1416 /* We will loop twice:
1417 * First we attempt to open with FILE_WRITE_DATA for notification.
1418 * If it fails and we have flag for non-trackable files, we retry
1419 * without FILE_WRITE_DATA.
1420 * If that one fails, then, we quit for real.
1421 */
1422 while (TRUE)
1423 {
1424 Status = BasepOpenFileForMove(lpSource,
1425 &NtSource,
1426 &RelativeSource,
1427 &SourceHandle,
1428 &ObjectAttributesSource,
1429 SourceAccess,
1432 if (NT_SUCCESS(Status))
1433 {
1434 break;
1435 }
1436
1437 /* If we already attempted the opening without FILE_WRITE_DATA
1438 * or if we cannot move on non-trackable files, fail.
1439 */
1440 if (!(SourceAccess & FILE_WRITE_DATA) || !(dwFlags & PRIV_ALLOW_NON_TRACKABLE))
1441 {
1443 }
1444
1445 if (RelativeSource)
1446 {
1447 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSource);
1448 RelativeSource = NULL;
1449 }
1450
1452 {
1455 }
1456
1457 SourceAccess &= ~FILE_WRITE_DATA;
1458
1459 /* Remember fist failure in the path */
1460 if (NT_SUCCESS(OldStatus))
1461 {
1462 OldStatus = Status;
1463 }
1464 }
1465
1466 DestAccess = FILE_WRITE_ATTRIBUTES;
1467 /* If we could preserve FILE_WRITE_DATA for source, attempt to
1468 * get it for destination, still for notification purposes. */
1469 if (SourceAccess & FILE_WRITE_DATA)
1470 {
1471 DestAccess |= FILE_WRITE_DATA;
1472 }
1473
1474 /* cf comment for first loop */
1475 while (TRUE)
1476 {
1477 Status = BasepOpenFileForMove(lpDestination,
1478 &NtDestination,
1479 &RelativeDestination,
1480 &DestinationHandle,
1481 &ObjectAttributesDestination,
1482 DestAccess,
1485 if (NT_SUCCESS(Status))
1486 {
1487 break;
1488 }
1489
1490 /* If we already attempted the opening without FILE_WRITE_DATA
1491 * or if we cannot move on non-trackable files, fail.
1492 */
1493 if (!(DestAccess & FILE_WRITE_DATA) || !(dwFlags & PRIV_ALLOW_NON_TRACKABLE))
1494 {
1496 }
1497
1498 if (RelativeDestination)
1499 {
1500 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeDestination);
1501 RelativeDestination = NULL;
1502 }
1503
1504 if (DestinationHandle != INVALID_HANDLE_VALUE)
1505 {
1506 NtClose(DestinationHandle);
1507 DestinationHandle = INVALID_HANDLE_VALUE;
1508 }
1509
1510 DestAccess &= ~FILE_WRITE_DATA;
1511
1512 /* Remember fist failure in the path */
1513 if (NT_SUCCESS(OldStatus))
1514 {
1515 OldStatus = Status;
1516 }
1517 }
1518
1519 /* Get the creation time from source */
1522 &SourceInformation,
1523 sizeof(SourceInformation),
1525 if (NT_SUCCESS(Status))
1526 {
1527 /* Then, prepare to set it for destination */
1528 RtlZeroMemory(&DestinationInformation, sizeof(DestinationInformation));
1529 DestinationInformation.CreationTime.QuadPart = SourceInformation.CreationTime.QuadPart;
1530
1531 /* And set it, that's all folks! */
1532 Status = NtSetInformationFile(DestinationHandle,
1534 &DestinationInformation,
1535 sizeof(DestinationInformation),
1537 }
1538
1539 if (!NT_SUCCESS(Status))
1540 {
1542 {
1544 }
1545
1546 /* Remember the failure for later notification */
1547 if (NT_SUCCESS(OldStatus))
1548 {
1549 OldStatus = Status;
1550 }
1551 }
1552
1553 /* If we could open with FILE_WRITE_DATA both source and destination,
1554 * then, notify
1555 */
1556 if (DestAccess & FILE_WRITE_DATA && SourceAccess & FILE_WRITE_DATA)
1557 {
1559 &ObjectAttributesSource,
1560 DestinationHandle,
1561 &NtDestination);
1562 if (!NT_SUCCESS(Status))
1563 {
1565 {
1566 if (NT_SUCCESS(OldStatus))
1567 OldStatus = Status;
1568
1569 /* Reset status, we allow non trackable files */
1571 }
1572 }
1573 }
1574 }
1576 {
1577 if (RelativeSource)
1578 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSource);
1579
1580 if (RelativeDestination)
1581 RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeDestination);
1582 }
1583 _SEH2_END;
1584
1585 /* If caller asked for source deletion, if everything succeed, proceed */
1587 {
1588 FileDispositionInfo.DeleteFile = TRUE;
1589
1592 &FileDispositionInfo,
1593 sizeof(FileDispositionInfo),
1595 }
1596
1597 /* Cleanup/close portion */
1598 if (DestinationHandle != INVALID_HANDLE_VALUE)
1599 {
1600 NtClose(DestinationHandle);
1601 }
1602
1604 {
1606 }
1607
1608 /* Set last error if any, and quit */
1609 if (NT_SUCCESS(Status))
1610 {
1611 if (!NT_SUCCESS(OldStatus))
1612 {
1613 BaseSetLastNTError(OldStatus);
1614 }
1615 }
1616 else
1617 {
1619 }
1620
1621 return NT_SUCCESS(Status);
1622}
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:134
#define PRIV_DELETE_ON_SUCCESS
Definition: kernel32.h:133
#define FILE_WRITE_DATA
Definition: nt_native.h:631
ULONG ACCESS_MASK
Definition: nt_native.h:40
LARGE_INTEGER CreationTime
Definition: nt_native.h:939
LONGLONG QuadPart
Definition: typedefs.h:114
WCHAR * LPWSTR
Definition: xmlstorage.h:184

◆ ReplaceFileA()

BOOL WINAPI ReplaceFileA ( IN LPCSTR  lpReplacedFileName,
IN LPCSTR  lpReplacementFileName,
IN LPCSTR lpBackupFileName  OPTIONAL,
IN DWORD  dwReplaceFlags,
IN LPVOID  lpExclude,
IN LPVOID  lpReserved 
)

Definition at line 1169 of file move.c.

1175{
1176 BOOL Ret;
1177 UNICODE_STRING ReplacedFileNameW, ReplacementFileNameW, BackupFileNameW;
1178
1179 if (!lpReplacedFileName || !lpReplacementFileName || lpExclude || lpReserved ||
1180 (dwReplaceFlags & ~(REPLACEFILE_WRITE_THROUGH | REPLACEFILE_IGNORE_MERGE_ERRORS)))
1181 {
1183 return FALSE;
1184 }
1185
1186 if (!Basep8BitStringToDynamicUnicodeString(&ReplacedFileNameW, lpReplacedFileName))
1187 {
1188 return FALSE;
1189 }
1190
1191 if (!Basep8BitStringToDynamicUnicodeString(&ReplacementFileNameW, lpReplacementFileName))
1192 {
1193 RtlFreeUnicodeString(&ReplacedFileNameW);
1194 return FALSE;
1195 }
1196
1197 if (lpBackupFileName)
1198 {
1199 if (!Basep8BitStringToDynamicUnicodeString(&BackupFileNameW, lpBackupFileName))
1200 {
1201 RtlFreeUnicodeString(&ReplacementFileNameW);
1202 RtlFreeUnicodeString(&ReplacedFileNameW);
1203 return FALSE;
1204 }
1205 }
1206 else
1207 {
1208 BackupFileNameW.Buffer = NULL;
1209 }
1210
1211 Ret = ReplaceFileW(ReplacedFileNameW.Buffer,
1212 ReplacementFileNameW.Buffer,
1213 BackupFileNameW.Buffer,
1214 dwReplaceFlags, 0, 0);
1215
1216 if (lpBackupFileName)
1217 {
1218 RtlFreeUnicodeString(&BackupFileNameW);
1219 }
1220 RtlFreeUnicodeString(&ReplacementFileNameW);
1221 RtlFreeUnicodeString(&ReplacedFileNameW);
1222
1223 return Ret;
1224}
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define SetLastError(x)
Definition: compat.h:752
BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName, LPCWSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved)
Definition: move.c:1231

◆ ReplaceFileW()

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

Definition at line 1231 of file move.c.

1239{
1240 HANDLE hReplaced = NULL, hReplacement = NULL;
1241 UNICODE_STRING NtReplacedName = { 0, 0, NULL };
1242 UNICODE_STRING NtReplacementName = { 0, 0, NULL };
1245 BOOL Ret = FALSE;
1248 PVOID Buffer = NULL ;
1249
1250 if (dwReplaceFlags)
1251 FIXME("Ignoring flags %x\n", dwReplaceFlags);
1252
1253 /* First two arguments are mandatory */
1254 if (!lpReplacedFileName || !lpReplacementFileName)
1255 {
1257 return FALSE;
1258 }
1259
1260 /* Back it up */
1261 if(lpBackupFileName)
1262 {
1263 if(!CopyFileW(lpReplacedFileName, lpBackupFileName, FALSE))
1264 {
1265 Error = GetLastError();
1266 goto Cleanup ;
1267 }
1268 }
1269
1270 /* Open the "replaced" file for reading and writing */
1271 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &NtReplacedName, NULL, NULL)))
1272 {
1274 goto Cleanup;
1275 }
1276
1278 &NtReplacedName,
1280 NULL,
1281 NULL);
1282
1283 Status = NtOpenFile(&hReplaced,
1289
1290 if (!NT_SUCCESS(Status))
1291 {
1294 else
1296 goto Cleanup;
1297 }
1298
1299 /* Blank it */
1300 SetEndOfFile(hReplaced) ;
1301
1302 /*
1303 * Open the replacement file for reading, writing, and deleting
1304 * (deleting is needed when finished)
1305 */
1306 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &NtReplacementName, NULL, NULL)))
1307 {
1309 goto Cleanup;
1310 }
1311
1313 &NtReplacementName,
1315 NULL,
1316 NULL);
1317
1318 Status = NtOpenFile(&hReplacement,
1322 0,
1324
1325 if (!NT_SUCCESS(Status))
1326 {
1328 goto Cleanup;
1329 }
1330
1331 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x10000) ;
1332 if (!Buffer)
1333 {
1335 goto Cleanup ;
1336 }
1337 while (Status != STATUS_END_OF_FILE)
1338 {
1339 Status = NtReadFile(hReplacement, NULL, NULL, NULL, &IoStatusBlock, Buffer, 0x10000, NULL, NULL) ;
1340 if (NT_SUCCESS(Status))
1341 {
1344 if (!NT_SUCCESS(Status))
1345 {
1347 goto Cleanup;
1348 }
1349 }
1350 else if (Status != STATUS_END_OF_FILE)
1351 {
1353 goto Cleanup;
1354 }
1355 }
1356
1357 Ret = TRUE;
1358
1359 /* Perform resource cleanup */
1360Cleanup:
1361 if (hReplaced) NtClose(hReplaced);
1362 if (hReplacement) NtClose(hReplacement);
1363 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1364
1365 if (NtReplacementName.Buffer)
1366 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName.Buffer);
1367 if (NtReplacedName.Buffer)
1368 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName.Buffer);
1369
1370 /* If there was an error, set the error code */
1371 if(!Ret)
1372 {
1373 TRACE("ReplaceFileW failed (error=%lu)\n", Error);
1375 }
1376 return Ret;
1377}
#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 HEAP_ZERO_MEMORY
Definition: compat.h:134
BOOL WINAPI CopyFileW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN BOOL bFailIfExists)
Definition: copy.c:439
BOOL WINAPI SetEndOfFile(HANDLE hFile)
Definition: fileinfo.c:1004
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:106
#define ERROR_UNABLE_TO_REMOVE_REPLACED
Definition: winerror.h:696

Referenced by ReplaceFileA().