Author: pschweitzer
Date: Tue Apr 21 10:55:26 2015
New Revision: 67335
URL:
http://svn.reactos.org/svn/reactos?rev=67335&view=rev
Log:
[KERNEL32]
- Implement BasepOpenFileForMove() used by PrivMoveFileIdentityW(), with its Windows bugs
- Implement PrivMoveFileIdentityW()
Not sure yet why Windows implementation exposes a sharing violation during our API test.
Our absence of sharing violation looks more legit...
To be investigated.
Modified:
trunk/reactos/dll/win32/kernel32/client/file/move.c
trunk/reactos/dll/win32/kernel32/include/kernel32.h
Modified: trunk/reactos/dll/win32/kernel32/client/file/move.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/client/file/move.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/client/file/move.c [iso-8859-1] Tue Apr 21 10:55:26
2015
@@ -886,14 +886,379 @@
}
/*
- * @unimplemented
+ * @implemented
+ */
+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)
+{
+ RTL_RELATIVE_NAME_U RelativeName;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_ATTRIBUTE_TAG_INFORMATION TagInfo;
+ ULONG IntShareAccess;
+ BOOLEAN HasRelative = FALSE;
+
+ _SEH2_TRY
+ {
+ /* Zero output */
+ RelativeNtName->Length =
+ RelativeNtName->MaximumLength = 0;
+ RelativeNtName->Buffer = NULL;
+ *NtName = NULL;
+
+ if (!RtlDosPathNameToRelativeNtPathName_U(File, RelativeNtName, NULL,
&RelativeName))
+ {
+ Status = STATUS_OBJECT_PATH_NOT_FOUND;
+ _SEH2_LEAVE;
+ }
+
+ HasRelative = TRUE;
+ *NtName = RelativeNtName->Buffer;
+
+ if (RelativeName.RelativeName.Length)
+ {
+ RelativeNtName->Length = RelativeName.RelativeName.Length;
+ RelativeNtName->MaximumLength = RelativeName.RelativeName.MaximumLength;
+ RelativeNtName->Buffer = RelativeName.RelativeName.Buffer;
+ }
+ else
+ {
+ RelativeName.ContainingDirectory = 0;
+ }
+
+ InitializeObjectAttributes(ObjectAttributes,
+ RelativeNtName,
+ OBJ_CASE_INSENSITIVE,
+ RelativeName.ContainingDirectory,
+ NULL);
+ /* Force certain flags here, given ops we'll do */
+ IntShareAccess = ShareAccess | FILE_SHARE_READ | FILE_SHARE_WRITE;
+ OpenOptions |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT;
+
+ /* We'll try to read reparse tag */
+ Status = NtOpenFile(FileHandle,
+ DesiredAccess | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
+ ObjectAttributes,
+ &IoStatusBlock,
+ IntShareAccess,
+ OpenOptions | FILE_OPEN_REPARSE_POINT);
+ if (NT_SUCCESS(Status))
+ {
+ /* Attempt the read */
+ Status = NtQueryInformationFile(*FileHandle,
+ &IoStatusBlock,
+ &TagInfo,
+ sizeof(FILE_ATTRIBUTE_TAG_INFORMATION),
+ FileAttributeTagInformation);
+
+ /* Return if failure with a status that wouldn't mean the FSD cannot
support reparse points */
+ if (!NT_SUCCESS(Status) &&
+ (Status != STATUS_NOT_IMPLEMENTED && Status !=
STATUS_INVALID_PARAMETER))
+ {
+ _SEH2_LEAVE;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ /* This cannot happen on mount points */
+ if (TagInfo.FileAttributes & FILE_ATTRIBUTE_DEVICE ||
+ TagInfo.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ _SEH2_LEAVE;
+ }
+ }
+
+ NtClose(*FileHandle);
+ *FileHandle = INVALID_HANDLE_VALUE;
+
+ IntShareAccess = ShareAccess | FILE_SHARE_READ | FILE_SHARE_DELETE;
+ }
+ else if (Status == STATUS_INVALID_PARAMETER)
+ {
+ IntShareAccess = ShareAccess | FILE_SHARE_READ | FILE_SHARE_WRITE;
+ }
+ else
+ {
+ _SEH2_LEAVE;
+ }
+
+ /* Reattempt to open normally, following reparse point if needed */
+ Status = NtOpenFile(FileHandle,
+ DesiredAccess | SYNCHRONIZE,
+ ObjectAttributes,
+ &IoStatusBlock,
+ IntShareAccess,
+ OpenOptions);
+ }
+ _SEH2_FINALLY
+ {
+ if (HasRelative)
+ {
+ RtlReleaseRelativeName(&RelativeName);
+ }
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
+/*
+ * @implemented
*/
BOOL
WINAPI
-PrivMoveFileIdentityW(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3)
-{
- STUB;
- return FALSE;
+PrivMoveFileIdentityW(IN LPCWSTR lpSource, IN LPCWSTR lpDestination, IN DWORD dwFlags)
+{
+ ACCESS_MASK SourceAccess;
+ UNICODE_STRING NtSource, NtDestination;
+ LPWSTR RelativeSource, RelativeDestination;
+ HANDLE SourceHandle, DestinationHandle;
+ OBJECT_ATTRIBUTES ObjectAttributesSource, ObjectAttributesDestination;
+ NTSTATUS Status, OldStatus = STATUS_SUCCESS;
+ ACCESS_MASK DestAccess;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_BASIC_INFORMATION SourceInformation, DestinationInformation;
+ FILE_DISPOSITION_INFORMATION FileDispositionInfo;
+
+ DPRINT("PrivMoveFileIdentityW(%S, %S, %x)\n", lpSource, lpDestination,
dwFlags);
+
+ SourceHandle = INVALID_HANDLE_VALUE;
+ NtSource.Length =
+ NtSource.MaximumLength = 0;
+ NtSource.Buffer = NULL;
+ RelativeSource = NULL;
+ DestinationHandle = INVALID_HANDLE_VALUE;
+ NtDestination.Length =
+ NtDestination.MaximumLength = 0;
+ NtDestination.Buffer = NULL;
+ RelativeDestination = NULL;
+
+ /* FILE_WRITE_DATA is required for later on notification */
+ SourceAccess = FILE_READ_ATTRIBUTES | FILE_WRITE_DATA;
+ if (dwFlags & PRIV_DELETE_ON_SUCCESS)
+ {
+ SourceAccess |= DELETE;
+ }
+
+ _SEH2_TRY
+ {
+ /* We will loop twice:
+ * First we attempt to open with FILE_WRITE_DATA for notification
+ * If it fails and we have flag for non-trackable files, we retry
+ * without FILE_WRITE_DATA.
+ * If that one fails, then, we quit for real
+ */
+ while (TRUE)
+ {
+ Status = BasepOpenFileForMove(lpSource,
+ &NtSource,
+ &RelativeSource,
+ &SourceHandle,
+ &ObjectAttributesSource,
+ SourceAccess,
+ FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
+ FILE_OPEN_NO_RECALL);
+ if (NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ /* If we already attempted the opening without FILE_WRITE_DATA
+ * or if we cannot move on non-trackable files, fail.
+ */
+ if (!(SourceAccess & FILE_WRITE_DATA) || !(dwFlags &
PRIV_ALLOW_NON_TRACKABLE))
+ {
+ _SEH2_LEAVE;
+ }
+
+ if (RelativeSource)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSource);
+ RelativeSource = NULL;
+ }
+
+ if (SourceHandle != INVALID_HANDLE_VALUE)
+ {
+ NtClose(SourceHandle);
+ SourceHandle = INVALID_HANDLE_VALUE;
+ }
+
+ SourceAccess &= ~FILE_WRITE_DATA;
+
+ /* Remember fist failure in the path */
+ if (NT_SUCCESS(OldStatus))
+ {
+ OldStatus = Status;
+ }
+ }
+
+ DestAccess = FILE_WRITE_ATTRIBUTES;
+ /* If we could preserve FILE_WRITE_DATA for source, attempt to get it for
destination
+ * Still for notification purposes
+ */
+ if (SourceAccess & FILE_WRITE_DATA)
+ {
+ DestAccess |= FILE_WRITE_DATA;
+ }
+
+ /* cf comment for first loop */
+ while (TRUE)
+ {
+ Status = BasepOpenFileForMove(lpDestination,
+ &NtDestination,
+ &RelativeDestination,
+ &DestinationHandle,
+ &ObjectAttributesDestination,
+ DestAccess,
+ FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
+ FILE_OPEN_NO_RECALL);
+ if (NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ /* If we already attempted the opening without FILE_WRITE_DATA
+ * or if we cannot move on non-trackable files, fail.
+ */
+ if (!(DestAccess & FILE_WRITE_DATA) || !(dwFlags &
PRIV_ALLOW_NON_TRACKABLE))
+ {
+ _SEH2_LEAVE;
+ }
+
+ if (RelativeDestination)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeDestination);
+ RelativeDestination = NULL;
+ }
+
+ if (DestinationHandle != INVALID_HANDLE_VALUE)
+ {
+ NtClose(DestinationHandle);
+ DestinationHandle = INVALID_HANDLE_VALUE;
+ }
+
+ DestAccess &= ~FILE_WRITE_DATA;
+
+ /* Remember fist failure in the path */
+ if (NT_SUCCESS(OldStatus))
+ {
+ OldStatus = Status;
+ }
+ }
+
+ /* Get the creation time from source */
+ Status = NtQueryInformationFile(SourceHandle,
+ &IoStatusBlock,
+ &SourceInformation,
+ sizeof(SourceInformation),
+ FileBasicInformation);
+ if (NT_SUCCESS(Status))
+ {
+ /* Then, prepare to set it for destination */
+ RtlZeroMemory(&DestinationInformation, sizeof(DestinationInformation));
+ DestinationInformation.CreationTime.QuadPart =
SourceInformation.CreationTime.QuadPart;
+
+ /* And set it, that's all folks! */
+ Status = NtSetInformationFile(DestinationHandle,
+ &IoStatusBlock,
+ &DestinationInformation,
+ sizeof(DestinationInformation),
+ FileBasicInformation);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (!(dwFlags & PRIV_ALLOW_NON_TRACKABLE))
+ {
+ _SEH2_LEAVE;
+ }
+
+ /* Remember the failure for later notification */
+ if (NT_SUCCESS(OldStatus))
+ {
+ OldStatus = Status;
+ }
+ }
+
+ /* If we could open with FILE_WRITE_DATA both source and destination,
+ * then, notify
+ */
+ if (DestAccess & FILE_WRITE_DATA && SourceAccess &
FILE_WRITE_DATA)
+ {
+ Status = BasepNotifyTrackingService(&SourceHandle,
+ &ObjectAttributesSource,
+ DestinationHandle,
+ &NtDestination);
+#if 1 // ReactOS HACK
+ /* FIXME: To be removed once BasepNotifyTrackingService is implemented */
+ if (Status == STATUS_NOT_IMPLEMENTED)
+ Status = STATUS_SUCCESS;
+#endif
+ if (!NT_SUCCESS(Status))
+ {
+ if (dwFlags & PRIV_ALLOW_NON_TRACKABLE)
+ {
+ if (NT_SUCCESS(OldStatus))
+ OldStatus = Status;
+ }
+ }
+ }
+ }
+ _SEH2_FINALLY
+ {
+ if (RelativeSource)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSource);
+
+ if (RelativeDestination)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeDestination);
+ }
+ _SEH2_END;
+
+ /* If caller asked for source deletion, if everything succeed, proceed */
+ if (NT_SUCCESS(Status) && dwFlags & PRIV_DELETE_ON_SUCCESS)
+ {
+ FileDispositionInfo.DeleteFile = TRUE;
+
+ Status = NtSetInformationFile(SourceHandle,
+ &IoStatusBlock,
+ &FileDispositionInfo,
+ sizeof(FileDispositionInfo),
+ FileDispositionInformation);
+ }
+
+ /* Cleanup/close portion */
+ if (DestinationHandle != INVALID_HANDLE_VALUE)
+ {
+ NtClose(DestinationHandle);
+ }
+
+ if (SourceHandle != INVALID_HANDLE_VALUE)
+ {
+ NtClose(SourceHandle);
+ }
+
+ /* Set last error if any, and quit */
+ if (NT_SUCCESS(Status))
+ {
+ if (!NT_SUCCESS(OldStatus))
+ {
+ BaseSetLastNTError(OldStatus);
+ }
+ }
+ else
+ {
+ BaseSetLastNTError(Status);
+ }
+
+ return NT_SUCCESS(Status);
}
/* EOF */
Modified: trunk/reactos/dll/win32/kernel32/include/kernel32.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/include…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/include/kernel32.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/include/kernel32.h [iso-8859-1] Tue Apr 21 10:55:26
2015
@@ -142,6 +142,10 @@
#define BASEP_COPY_PUBLIC_MASK 0xF
#define BASEP_COPY_BASEP_MASK 0xFFFFFFF0
+/* Flags for PrivMoveFileIdentityW */
+#define PRIV_DELETE_ON_SUCCESS 0x1
+#define PRIV_ALLOW_NON_TRACKABLE 0x2
+
/* GLOBAL VARIABLES **********************************************************/
extern BOOL bIsFileApiAnsi;