Author: ion
Date: Sat Jul 8 22:17:26 2006
New Revision: 22928
URL:
http://svn.reactos.org/svn/reactos?rev=22928&view=rev
Log:
- Uber-optimize IopQueryAttributesFile by using the OPEN_PACKET mechanism to query file
attributes, instead of doing lots of slow native calls.
- Modify IopParseDevice to detect when OPEN_PACKET optimizations are in use (query or
deletion (deletion not yet implemented)) and have some codepaths be slightly different and
use DUMMY_FILE_OBJECT.
- Implement QueryOnly case in IopParseDevice to handle attribute queries.
- Add a missing dereference, and remove an extra DO reference.
Modified:
trunk/reactos/ntoskrnl/io/iomgr/file.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 (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/file.c Sat Jul 8 22:17:26 2006
@@ -38,18 +38,12 @@
PEXTENDED_IO_STACK_LOCATION StackLoc;
IO_SECURITY_CONTEXT SecurityContext;
IO_STATUS_BLOCK IoStatusBlock;
- BOOLEAN DirectOpen = FALSE;
+ BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
OBJECT_ATTRIBUTES ObjectAttributes;
- BOOLEAN OpenCancelled;
KIRQL OldIrql;
- DPRINT("IopParseDevice:\n"
- "DeviceObject : %p\n"
- "RelatedFileObject : %p\n"
- "CompleteName : %wZ, RemainingName : %wZ\n",
- ParseObject,
- Context,
- CompleteName,
- RemainingName);
+ PDUMMY_FILE_OBJECT DummyFileObject;
+ PFILE_BASIC_INFORMATION FileBasicInfo;
+ ULONG ReturnLength;
/* Assume failure */
*Object = NULL;
@@ -76,8 +70,13 @@
SeSetAccessStateGenericMapping(AccessState,
&IoFileObjectType->TypeInfo.GenericMapping);
+ /* Check if we can simply use a dummy file */
+ UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
+
/* Check if this is a direct open */
- if (!(RemainingName->Length) && !(OpenPacket->RelatedFileObject))
+ if (!(RemainingName->Length) &&
+ !(OpenPacket->RelatedFileObject) &&
+ !(UseDummyFile))
{
/* Remember this for later */
DirectOpen = TRUE;
@@ -127,74 +126,86 @@
}
}
- /* Create the actual file object */
- InitializeObjectAttributes(&ObjectAttributes,
- NULL,
- Attributes,
- NULL,
- NULL);
- Status = ObCreateObject(KernelMode,
- IoFileObjectType,
- &ObjectAttributes,
- AccessMode,
- NULL,
- sizeof(FILE_OBJECT),
- 0,
- 0,
- (PVOID*)&FileObject);
- RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
-
- /* Set the device object and reference it */
- Status = IopReferenceDeviceObject(DeviceObject);
- FileObject->DeviceObject = DeviceObject;
+ /* Check if we really need to create an object */
+ if (!UseDummyFile)
+ {
+ /* Create the actual file object */
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ Attributes,
+ NULL,
+ NULL);
+ Status = ObCreateObject(KernelMode,
+ IoFileObjectType,
+ &ObjectAttributes,
+ AccessMode,
+ NULL,
+ sizeof(FILE_OBJECT),
+ 0,
+ 0,
+ (PVOID*)&FileObject);
+ RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
+
+ /* Check if this is Synch I/O */
+ if (OpenPacket->CreateOptions &
+ (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
+ {
+ /* Set the synch flag */
+ FileObject->Flags |= FO_SYNCHRONOUS_IO;
+
+ /* Check if it's also alertable */
+ if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
+ {
+ /* It is, set the alertable flag */
+ FileObject->Flags |= FO_ALERTABLE_IO;
+ }
+ }
+
+ /* Check if the caller requested no intermediate buffering */
+ if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
+ {
+ /* Set the correct flag for the FSD to read */
+ FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
+ }
+
+ /* Check if the caller requested write through support */
+ if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
+ {
+ /* Set the correct flag for the FSD to read */
+ FileObject->Flags |= FO_WRITE_THROUGH;
+ }
+
+ /* Check if the caller says the file will be only read sequentially */
+ if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
+ {
+ /* Set the correct flag for the FSD to read */
+ FileObject->Flags |= FO_SEQUENTIAL_ONLY;
+ }
+
+ /* Check if the caller believes the file will be only read randomly */
+ if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
+ {
+ /* Set the correct flag for the FSD to read */
+ FileObject->Flags |= FO_RANDOM_ACCESS;
+ }
+ }
+ else
+ {
+ /* Use the dummy object instead */
+ DummyFileObject = OpenPacket->DummyFileObject;
+ RtlZeroMemory(DummyFileObject, sizeof(DUMMY_FILE_OBJECT));
+
+ /* Set it up */
+ FileObject = (PFILE_OBJECT)&DummyFileObject->ObjectHeader.Body;
+ DummyFileObject->ObjectHeader.Type = IoFileObjectType;
+ DummyFileObject->ObjectHeader.PointerCount = 1;
+ }
/* Setup the file header */
FileObject->Type = IO_TYPE_FILE;
FileObject->Size = sizeof(FILE_OBJECT);
FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
-
- /* Check if this is Synch I/O */
- if (OpenPacket->CreateOptions &
- (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
- {
- /* Set the synch flag */
- FileObject->Flags |= FO_SYNCHRONOUS_IO;
-
- /* Check if it's also alertable */
- if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
- {
- /* It is, set the alertable flag */
- FileObject->Flags |= FO_ALERTABLE_IO;
- }
- }
-
- /* Check if the caller requested no intermediate buffering */
- if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
- {
- /* Set the correct flag for the FSD to read */
- FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
- }
-
- /* Check if the caller requested write through support */
- if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
- {
- /* Set the correct flag for the FSD to read */
- FileObject->Flags |= FO_WRITE_THROUGH;
- }
-
- /* Check if the caller believes the file will be only read sequentially */
- if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
- {
- /* Set the correct flag for the FSD to read */
- FileObject->Flags |= FO_SEQUENTIAL_ONLY;
- }
-
- /* Check if the caller believes the file will be only read randomly */
- if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
- {
- /* Set the correct flag for the FSD to read */
- FileObject->Flags |= FO_RANDOM_ACCESS;
- }
+ FileObject->DeviceObject = DeviceObject;
/* Check if this is a direct device open */
if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
@@ -315,8 +326,11 @@
IopDereferenceDeviceObject(DeviceObject, FALSE);
if (Vpb) IopDereferenceVpb(Vpb);
- /* Clear the FO */
+ /* Clear the FO and dereference it */
FileObject->DeviceObject = NULL;
+ if (!UseDummyFile) ObDereferenceObject(FileObject);
+
+ /* Fail */
return STATUS_INSUFFICIENT_RESOURCES;
}
}
@@ -324,7 +338,7 @@
/* Copy the name */
RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
- /* Reference the file object and call the driver */
+ /* Reference the file object */
ObReferenceObject(FileObject);
/* Initialize the File Object event and set the FO */
@@ -402,7 +416,7 @@
OpenPacket->FileObject = NULL;
/* Dereference the file object */
- ObDereferenceObject(FileObject);
+ if (!UseDummyFile) ObDereferenceObject(FileObject);
/* Unless the driver canelled the open, dereference the VPB */
if (!(OpenCancelled) && (Vpb)) IopDereferenceVpb(Vpb);
@@ -417,14 +431,77 @@
KEBUGCHECK(0);
}
- /* Otherwise, we were successful. Reference the object, set status */
- ObReferenceObject(FileObject);
- OpenPacket->FinalStatus = IoStatusBlock.Status;
- OpenPacket->ParseCheck = TRUE;
-
- /* Return the object and status */
- *Object = FileObject;
- return OpenPacket->FinalStatus;
+ /* Make sure we are not using a dummy */
+ if (!UseDummyFile)
+ {
+ /* Reference the object and set the parse check */
+ ObReferenceObject(FileObject);
+ *Object = FileObject;
+ OpenPacket->FinalStatus = IoStatusBlock.Status;
+ OpenPacket->ParseCheck = TRUE;
+ return OpenPacket->FinalStatus;
+ }
+ else
+ {
+ /* Check if this was a query */
+ if (OpenPacket->QueryOnly)
+ {
+ /* Check if the caller wants basic info only */
+ if (!OpenPacket->FullAttributes)
+ {
+ /* Allocate the buffer */
+ FileBasicInfo = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(*FileBasicInfo),
+ TAG_IO);
+ if (FileBasicInfo)
+ {
+ /* Do the query */
+ Status = IoQueryFileInformation(FileObject,
+ FileBasicInformation,
+ sizeof(*FileBasicInfo),
+ FileBasicInfo,
+ &ReturnLength);
+ if (NT_SUCCESS(Status))
+ {
+ /* Copy the data */
+ RtlCopyMemory(OpenPacket->BasicInformation,
+ FileBasicInfo,
+ ReturnLength);
+ }
+
+ /* Free our buffer */
+ ExFreePool(FileBasicInfo);
+ }
+ else
+ {
+ /* Fail */
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ /* This is a full query */
+ Status = IoQueryFileInformation(
+ FileObject,
+ FileNetworkOpenInformation,
+ sizeof(FILE_NETWORK_OPEN_INFORMATION),
+ OpenPacket->NetworkInformation,
+ &ReturnLength);
+ if (!NT_SUCCESS(Status)) ASSERT(Status != STATUS_NOT_IMPLEMENTED);
+ }
+ }
+
+ /* Delete the file object */
+ IopDeleteFile(FileObject);
+
+ /* Clear out the file */
+ OpenPacket->FileObject = NULL;
+
+ /* Set and return status */
+ OpenPacket->FinalStatus = Status;
+ OpenPacket->ParseCheck = TRUE;
+ return Status;
+ }
}
NTSTATUS
@@ -957,112 +1034,119 @@
NTAPI
IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
IN FILE_INFORMATION_CLASS FileInformationClass,
+ IN ULONG FileInformationSize,
OUT PVOID FileInformation)
{
- IO_STATUS_BLOCK IoStatusBlock;
- HANDLE FileHandle;
- NTSTATUS Status;
- KPROCESSOR_MODE AccessMode;
- UNICODE_STRING ObjectName;
- OBJECT_CREATE_INFORMATION ObjectCreateInfo;
- OBJECT_ATTRIBUTES LocalObjectAttributes;
- ULONG BufferSize;
- union
- {
- FILE_BASIC_INFORMATION BasicInformation;
- FILE_NETWORK_OPEN_INFORMATION NetworkOpenInformation;
- }LocalFileInformation;
-
- if (FileInformationClass == FileBasicInformation)
- {
- BufferSize = sizeof(FILE_BASIC_INFORMATION);
- }
- else if (FileInformationClass == FileNetworkOpenInformation)
- {
- BufferSize = sizeof(FILE_NETWORK_OPEN_INFORMATION);
+ NTSTATUS Status = STATUS_SUCCESS;
+ KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
+ DUMMY_FILE_OBJECT DummyFileObject;
+ FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
+ HANDLE Handle;
+ OPEN_PACKET OpenPacket;
+ BOOLEAN IsBasic;
+ PAGED_CODE();
+
+ /* Check if the caller was user mode */
+ if (AccessMode != KernelMode)
+ {
+ /* Protect probe in SEH */
+ _SEH_TRY
+ {
+ /* Probe the buffer */
+ ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
+ }
+ _SEH_HANDLE
+ {
+ /* Get the exception code */
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ /* Fail on exception */
+ if (!NT_SUCCESS(Status))return Status;
+ }
+
+ /* Check if this is a basic or full request */
+ IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
+
+ /* Setup the Open Packet */
+ OpenPacket.Type = IO_TYPE_OPEN_PACKET;
+ OpenPacket.Size = sizeof(OPEN_PACKET);
+ OpenPacket.FileObject = NULL;
+ OpenPacket.FinalStatus = STATUS_SUCCESS;
+ OpenPacket.Information = 0;
+ OpenPacket.ParseCheck = 0;
+ OpenPacket.RelatedFileObject = NULL;
+ OpenPacket.AllocationSize.QuadPart = 0;
+ OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
+ OpenPacket.FileAttributes = 0;
+ OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ OpenPacket.EaBuffer = NULL;
+ OpenPacket.EaLength = 0;
+ OpenPacket.Options = 0;
+ OpenPacket.Disposition = FILE_OPEN;
+ OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
+ OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
+ (AccessMode != KernelMode) ?
+ &NetworkOpenInfo : FileInformation;
+ OpenPacket.CreateFileType = 0;
+ OpenPacket.MailslotOrPipeParameters = NULL;
+ OpenPacket.Override = FALSE;
+ OpenPacket.QueryOnly = TRUE;
+ OpenPacket.DeleteOnly = FALSE;
+ OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
+ OpenPacket.DummyFileObject = &DummyFileObject;
+ OpenPacket.InternalFlags = 0;
+
+ /* Update the operation count */
+ IopUpdateOperationCount(IopOtherTransfer);
+
+ /*
+ * Attempt opening the file. This will call the I/O Parse Routine for
+ * the File Object (IopParseDevice) which will use the dummy file obejct
+ * send the IRP to its device object. Note that we have two statuses
+ * to worry about: the Object Manager's status (in Status) and the I/O
+ * status, which is in the Open Packet's Final Status, and determined
+ * by the Parse Check member.
+ */
+ Status = ObOpenObjectByName(ObjectAttributes,
+ NULL,
+ AccessMode,
+ NULL,
+ FILE_READ_ATTRIBUTES,
+ &OpenPacket,
+ &Handle);
+ if (OpenPacket.ParseCheck != TRUE)
+ {
+ /* Parse failed */
+ return Status;
}
else
{
- return STATUS_INVALID_PARAMETER;
- }
-
- AccessMode = ExGetPreviousMode();
-
- if (AccessMode != KernelMode)
- {
- Status = STATUS_SUCCESS;
+ /* Use the Io status */
+ Status = OpenPacket.FinalStatus;
+ }
+
+ /* Check if we were succesful and this was user mode and a full query */
+ if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) &&
!(IsBasic))
+ {
+ /* Enter SEH for copy */
_SEH_TRY
{
- ProbeForWrite(FileInformation,
- BufferSize,
- sizeof(ULONG));
+ /* Copy the buffer back */
+ RtlMoveMemory(FileInformation,
+ &NetworkOpenInfo,
+ FileInformationSize);
}
_SEH_HANDLE
{
+ /* Get exception code */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
- if (NT_SUCCESS(Status))
- {
- Status = ObpCaptureObjectAttributes(ObjectAttributes,
- AccessMode,
- FALSE,
- &ObjectCreateInfo,
- &ObjectName);
- }
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- InitializeObjectAttributes(&LocalObjectAttributes,
- &ObjectName,
- ObjectCreateInfo.Attributes,
- ObjectCreateInfo.RootDirectory,
- ObjectCreateInfo.SecurityDescriptor);
- }
-
- /* Open the file */
- Status = ZwOpenFile(&FileHandle,
- SYNCHRONIZE | FILE_READ_ATTRIBUTES,
- AccessMode == KernelMode ? ObjectAttributes :
&LocalObjectAttributes,
- &IoStatusBlock,
- 0,
- FILE_SYNCHRONOUS_IO_NONALERT);
- if (AccessMode != KernelMode)
- {
- ObpReleaseCapturedAttributes(&ObjectCreateInfo);
- if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
- }
- if (!NT_SUCCESS (Status))
- {
- DPRINT ("ZwOpenFile() failed (Status %lx)\n", Status);
- return Status;
- }
-
- /* Get file attributes */
- Status = ZwQueryInformationFile(FileHandle,
- &IoStatusBlock,
- AccessMode == KernelMode ? FileInformation :
&LocalFileInformation,
- BufferSize,
- FileInformationClass);
- if (!NT_SUCCESS (Status))
- {
- DPRINT ("ZwQueryInformationFile() failed (Status %lx)\n", Status);
- }
- ZwClose(FileHandle);
-
- if (NT_SUCCESS(Status) && AccessMode != KernelMode)
- {
- _SEH_TRY
- {
- memcpy(FileInformation, &LocalFileInformation, BufferSize);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
+ }
+
+ /* Return status */
return Status;
}
@@ -1228,6 +1312,9 @@
OpenPacket.DummyFileObject = NULL;
OpenPacket.InternalFlags = 0;
+ /* Update the operation count */
+ IopUpdateOperationCount(IopOtherTransfer);
+
/*
* Attempt opening the file. This will call the I/O Parse Routine for
* the File Object (IopParseDevice) which will create the object and
@@ -1386,7 +1473,7 @@
sizeof(FILE_OBJECT),
0,
(PVOID*)&CreatedFileObject);
- if (!NT_SUCCESS(Status)) return (NULL);
+ if (!NT_SUCCESS(Status)) return NULL;
/* Choose Device Object */
if (FileObject) DeviceObject = FileObject->DeviceObject;
@@ -1764,8 +1851,10 @@
NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PFILE_BASIC_INFORMATION FileInformation)
{
+ /* Call the internal helper API */
return IopQueryAttributesFile(ObjectAttributes,
FileBasicInformation,
+ sizeof(FILE_BASIC_INFORMATION),
FileInformation);
}
@@ -1774,9 +1863,11 @@
NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
{
- return IopQueryAttributesFile(ObjectAttributes,
- FileNetworkOpenInformation,
- FileInformation);
+ /* Call the internal helper API */
+ return IopQueryAttributesFile(ObjectAttributes,
+ FileNetworkOpenInformation,
+ sizeof(FILE_NETWORK_OPEN_INFORMATION),
+ FileInformation);
}
/**