Author: pschweitzer
Date: Sun Dec 7 17:59:58 2014
New Revision: 65584
URL:
http://svn.reactos.org/svn/reactos?rev=65584&view=rev
Log:
[NTOSKRNL]
Implement support for (some) reparse points in Io manager. Ob should be already fine.
- Implement the IopDoNameTransmogrify() function. This one is responsible for checking the
correct data for the reparse point and to update the path name in the file object. It will
also free the memory buffer allocated by the driver to communicate the reparse
information.
- Fix the support for reparse points in IopCompleteRequest(). If we receive reparse status
+ reparse tag we know, we call IopDoNameTransmogrify() to update file objet.
- Fix the support for reparse points in IopParseDevice() (oh! you again? :-)). When we
complete the IRP ourselves, act as in IopCompleteRequest(). Then, we properly update
objects manipulated by Io for the create request and we return STATUS_REPARSE so that Ob
can update and recall us afterwards so that we complete.
Some parts are left unimplemented when it comes to reparse tags which are not
IO_REPARSE_TAG_MOUNT_POINT. But still less than previously ;-).
Modified:
trunk/reactos/ntoskrnl/io/iomgr/file.c
trunk/reactos/ntoskrnl/io/iomgr/irp.c
Modified: trunk/reactos/ntoskrnl/io/iomgr/file.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/file.c?r…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/file.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/file.c [iso-8859-1] Sun Dec 7 17:59:58 2014
@@ -160,6 +160,107 @@
InterlockedIncrement(&DeviceObject->ReferenceCount);
return STATUS_SUCCESS;
}
+}
+
+VOID
+NTAPI
+IopDoNameTransmogrify(IN PIRP Irp,
+ IN PFILE_OBJECT FileObject,
+ IN PREPARSE_DATA_BUFFER DataBuffer)
+{
+ PWSTR Buffer;
+ USHORT Length;
+ USHORT RequiredLength;
+ PWSTR NewBuffer;
+
+ PAGED_CODE();
+
+ ASSERT(Irp->IoStatus.Status == STATUS_REPARSE);
+ ASSERT(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
+ ASSERT(DataBuffer != NULL);
+ ASSERT(DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(DataBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ ASSERT(DataBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+
+ /* First of all, validate data */
+ if (DataBuffer->ReparseDataLength < REPARSE_DATA_BUFFER_HEADER_SIZE ||
+ (DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
+ DataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0])) >
MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
+ {
+ Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
+ }
+
+ /* Everything went right */
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ /* Compute buffer & length */
+ Buffer = (PWSTR)((ULONG_PTR)DataBuffer->MountPointReparseBuffer.PathBuffer +
+
DataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
+ Length = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
+
+ /* Check we don't overflow */
+ if ((MAXUSHORT - DataBuffer->Reserved) <= (Length + sizeof(UNICODE_NULL)))
+ {
+ Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
+ }
+ else
+ {
+ /* Compute how much mem we'll need */
+ RequiredLength = DataBuffer->Reserved + Length + sizeof(UNICODE_NULL);
+
+ /* Check if FileObject can already hold what we need */
+ if (FileObject->FileName.MaximumLength >= RequiredLength)
+ {
+ NewBuffer = FileObject->FileName.Buffer;
+ }
+ else
+ {
+ /* Allocate otherwise */
+ NewBuffer = ExAllocatePoolWithTag(PagedPool, RequiredLength,
TAG_IO_NAME);
+ if (NewBuffer == NULL)
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ }
+ }
+
+ /* Everything went right */
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ /* Copy reserved */
+ if (DataBuffer->Reserved)
+ {
+ RtlMoveMemory((PWSTR)((ULONG_PTR)NewBuffer + Length),
+ (PWSTR)((ULONG_PTR)FileObject->FileName.Buffer +
FileObject->FileName.Length - DataBuffer->Reserved),
+ DataBuffer->Reserved);
+ }
+
+ /* Then, buffer */
+ if (Length)
+ {
+ RtlCopyMemory(NewBuffer, Buffer, Length);
+ }
+
+ /* And finally replace buffer if new one was allocated */
+ FileObject->FileName.Length = RequiredLength - sizeof(UNICODE_NULL);
+ if (NewBuffer != FileObject->FileName.Buffer)
+ {
+ if (FileObject->FileName.Buffer)
+ {
+ ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+ }
+
+ FileObject->FileName.Buffer = NewBuffer;
+ FileObject->FileName.MaximumLength = RequiredLength;
+ FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] =
UNICODE_NULL;
+ }
+ }
+
+ /* We don't need them anymore - it was allocated by the driver */
+ ExFreePool(DataBuffer);
}
NTSTATUS
@@ -206,6 +307,23 @@
/* Validate the open packet */
if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
+ /* Valide reparse point in case we traversed a mountpoint */
+ if (OpenPacket->TraversedMountPoint)
+ {
+ /* This is a reparse point we understand */
+ ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
+
+ /* Make sure we're dealing with correct DO */
+ if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
+ {
+ OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
+ return STATUS_IO_REPARSE_DATA_INVALID;
+ }
+ }
+
/* Check if we have a related file object */
if (OpenPacket->RelatedFileObject)
{
@@ -404,6 +522,7 @@
/* Check if we can simply use a dummy file */
UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
+#if 1
/* FIXME: Small hack still exists, have to check why...
* This is triggered multiple times by usetup and then once per boot.
*/
@@ -424,6 +543,7 @@
WRITE_DAC));
DirectOpen = TRUE;
}
+#endif
/* Check if this is a direct open */
if (!(RemainingName->Length) &&
@@ -482,6 +602,12 @@
/* Get the attached device */
DeviceObject = IoGetAttachedDevice(DeviceObject);
}
+ }
+
+ /* If we traversed a mount point, reset the information */
+ if (OpenPacket->TraversedMountPoint)
+ {
+ OpenPacket->TraversedMountPoint = FALSE;
}
/* Check if this is a secure FSD */
@@ -740,6 +866,26 @@
ASSERT(!Irp->PendingReturned);
ASSERT(!Irp->MdlAddress);
+ /* Handle name change if required */
+ if (Status == STATUS_REPARSE)
+ {
+ /* Check this is a mount point */
+ if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ PREPARSE_DATA_BUFFER ReparseData;
+
+ /* Reparse point attributes were passed by the driver in the auxiliary
buffer */
+ ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
+ ReparseData =
(PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
+
+ ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(ReparseData->ReparseDataLength <
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+
+ IopDoNameTransmogrify(Irp, FileObject, ReparseData);
+ }
+ }
+
/* Completion happens at APC_LEVEL */
KeRaiseIrql(APC_LEVEL, &OldIrql);
@@ -805,7 +951,90 @@
}
else if (Status == STATUS_REPARSE)
{
- /* FIXME: We don't handle this at all! */
+ if (OpenPacket->Information == IO_REPARSE ||
+ OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ /* Update CompleteName with reparse info which got updated in
IopDoNameTransmogrify() */
+ if (CompleteName->MaximumLength < FileObject->FileName.Length)
+ {
+ PWSTR NewCompleteName;
+
+ /* Allocate a new buffer for the string */
+ NewCompleteName = ExAllocatePoolWithTag(PagedPool,
FileObject->FileName.Length, TAG_IO_NAME);
+ if (NewCompleteName == NULL)
+ {
+ OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Release the old one */
+ if (CompleteName->Buffer != NULL)
+ {
+ ExFreePoolWithTag(CompleteName->Buffer, TAG_IO_NAME);
+ }
+
+ /* And setup the new one */
+ CompleteName->Buffer = NewCompleteName;
+ CompleteName->MaximumLength = FileObject->FileName.Length;
+ }
+
+ /* Copy our new complete name */
+ RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
+
+ if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ OpenPacket->RelatedFileObject = NULL;
+ }
+ }
+
+ /* Check if we have a name */
+ if (FileObject->FileName.Length)
+ {
+ /* Free it */
+ ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+ FileObject->FileName.Length = 0;
+ }
+
+ /* Clear its device object */
+ FileObject->DeviceObject = NULL;
+
+ /* Clear the file object in the open packet */
+ OpenPacket->FileObject = NULL;
+
+ /* Dereference the file object */
+ if (!UseDummyFile) ObDereferenceObject(FileObject);
+
+ /* Dereference the device object */
+ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+
+ /* Unless the driver cancelled the open, dereference the VPB */
+ if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
+
+ if (OpenPacket->Information != IO_REMOUNT)
+ {
+ OpenPacket->RelatedFileObject = NULL;
+
+ /* Inform we traversed a mount point for later attempt */
+ if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ OpenPacket->TraversedMountPoint = 1;
+ }
+
+ /* In case we override checks, but got this on volume open, fail hard */
+ if (OpenPacket->Override)
+ {
+ KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
+ (ULONG_PTR)OriginalDeviceObject,
+ (ULONG_PTR)DeviceObject,
+ (ULONG_PTR)CompleteName,
+ OpenPacket->Information);
+ }
+
+ /* Return to IO/OB so that information can be upgraded */
+ return STATUS_REPARSE;
+ }
+
+ /* FIXME: At that point, we should loop again and reattempt an opening */
ASSERT(FALSE);
}
Modified: trunk/reactos/ntoskrnl/io/iomgr/irp.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/irp.c?re…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/irp.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/irp.c [iso-8859-1] Sun Dec 7 17:59:58 2014
@@ -264,9 +264,15 @@
if ((Irp->IoStatus.Status == STATUS_REPARSE) &&
(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT))
{
- /* We should never get this yet */
- UNIMPLEMENTED_DBGBREAK("Reparse support not yet present!\n");
- return;
+ PREPARSE_DATA_BUFFER ReparseData;
+
+ ReparseData = (PREPARSE_DATA_BUFFER)*SystemArgument2;
+
+ ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(ReparseData->ReparseDataLength <
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+
+ IopDoNameTransmogrify(Irp, FileObject, ReparseData);
}
}