- 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.

svn path=/trunk/; revision=22928
This commit is contained in:
Alex Ionescu 2006-07-08 18:17:26 +00:00
parent 8ac94d67d0
commit 6555616bb6

View file

@ -38,18 +38,12 @@ IopParseDevice(IN PVOID ParseObject,
PEXTENDED_IO_STACK_LOCATION StackLoc; PEXTENDED_IO_STACK_LOCATION StackLoc;
IO_SECURITY_CONTEXT SecurityContext; IO_SECURITY_CONTEXT SecurityContext;
IO_STATUS_BLOCK IoStatusBlock; IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN DirectOpen = FALSE; BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
BOOLEAN OpenCancelled;
KIRQL OldIrql; KIRQL OldIrql;
DPRINT("IopParseDevice:\n" PDUMMY_FILE_OBJECT DummyFileObject;
"DeviceObject : %p\n" PFILE_BASIC_INFORMATION FileBasicInfo;
"RelatedFileObject : %p\n" ULONG ReturnLength;
"CompleteName : %wZ, RemainingName : %wZ\n",
ParseObject,
Context,
CompleteName,
RemainingName);
/* Assume failure */ /* Assume failure */
*Object = NULL; *Object = NULL;
@ -76,8 +70,13 @@ IopParseDevice(IN PVOID ParseObject,
SeSetAccessStateGenericMapping(AccessState, SeSetAccessStateGenericMapping(AccessState,
&IoFileObjectType->TypeInfo.GenericMapping); &IoFileObjectType->TypeInfo.GenericMapping);
/* Check if we can simply use a dummy file */
UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
/* Check if this is a direct open */ /* Check if this is a direct open */
if (!(RemainingName->Length) && !(OpenPacket->RelatedFileObject)) if (!(RemainingName->Length) &&
!(OpenPacket->RelatedFileObject) &&
!(UseDummyFile))
{ {
/* Remember this for later */ /* Remember this for later */
DirectOpen = TRUE; DirectOpen = TRUE;
@ -127,74 +126,86 @@ IopParseDevice(IN PVOID ParseObject,
} }
} }
/* Create the actual file object */ /* Check if we really need to create an object */
InitializeObjectAttributes(&ObjectAttributes, if (!UseDummyFile)
NULL, {
Attributes, /* Create the actual file object */
NULL, InitializeObjectAttributes(&ObjectAttributes,
NULL); NULL,
Status = ObCreateObject(KernelMode, Attributes,
IoFileObjectType, NULL,
&ObjectAttributes, NULL);
AccessMode, Status = ObCreateObject(KernelMode,
NULL, IoFileObjectType,
sizeof(FILE_OBJECT), &ObjectAttributes,
0, AccessMode,
0, NULL,
(PVOID*)&FileObject); sizeof(FILE_OBJECT),
RtlZeroMemory(FileObject, sizeof(FILE_OBJECT)); 0,
0,
(PVOID*)&FileObject);
RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
/* Set the device object and reference it */ /* Check if this is Synch I/O */
Status = IopReferenceDeviceObject(DeviceObject); if (OpenPacket->CreateOptions &
FileObject->DeviceObject = DeviceObject; (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 */ /* Setup the file header */
FileObject->Type = IO_TYPE_FILE; FileObject->Type = IO_TYPE_FILE;
FileObject->Size = sizeof(FILE_OBJECT); FileObject->Size = sizeof(FILE_OBJECT);
FileObject->RelatedFileObject = OpenPacket->RelatedFileObject; FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
FileObject->DeviceObject = DeviceObject;
/* 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;
}
/* Check if this is a direct device open */ /* Check if this is a direct device open */
if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN; if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
@ -315,8 +326,11 @@ IopParseDevice(IN PVOID ParseObject,
IopDereferenceDeviceObject(DeviceObject, FALSE); IopDereferenceDeviceObject(DeviceObject, FALSE);
if (Vpb) IopDereferenceVpb(Vpb); if (Vpb) IopDereferenceVpb(Vpb);
/* Clear the FO */ /* Clear the FO and dereference it */
FileObject->DeviceObject = NULL; FileObject->DeviceObject = NULL;
if (!UseDummyFile) ObDereferenceObject(FileObject);
/* Fail */
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
} }
@ -324,7 +338,7 @@ IopParseDevice(IN PVOID ParseObject,
/* Copy the name */ /* Copy the name */
RtlCopyUnicodeString(&FileObject->FileName, RemainingName); RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
/* Reference the file object and call the driver */ /* Reference the file object */
ObReferenceObject(FileObject); ObReferenceObject(FileObject);
/* Initialize the File Object event and set the FO */ /* Initialize the File Object event and set the FO */
@ -402,7 +416,7 @@ IopParseDevice(IN PVOID ParseObject,
OpenPacket->FileObject = NULL; OpenPacket->FileObject = NULL;
/* Dereference the file object */ /* Dereference the file object */
ObDereferenceObject(FileObject); if (!UseDummyFile) ObDereferenceObject(FileObject);
/* Unless the driver canelled the open, dereference the VPB */ /* Unless the driver canelled the open, dereference the VPB */
if (!(OpenCancelled) && (Vpb)) IopDereferenceVpb(Vpb); if (!(OpenCancelled) && (Vpb)) IopDereferenceVpb(Vpb);
@ -417,14 +431,77 @@ IopParseDevice(IN PVOID ParseObject,
KEBUGCHECK(0); KEBUGCHECK(0);
} }
/* Otherwise, we were successful. Reference the object, set status */ /* Make sure we are not using a dummy */
ObReferenceObject(FileObject); if (!UseDummyFile)
OpenPacket->FinalStatus = IoStatusBlock.Status; {
OpenPacket->ParseCheck = TRUE; /* 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);
}
/* Return the object and status */ /* Free our buffer */
*Object = FileObject; ExFreePool(FileBasicInfo);
return OpenPacket->FinalStatus; }
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 NTSTATUS
@ -957,112 +1034,119 @@ NTSTATUS
NTAPI NTAPI
IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
IN FILE_INFORMATION_CLASS FileInformationClass, IN FILE_INFORMATION_CLASS FileInformationClass,
IN ULONG FileInformationSize,
OUT PVOID FileInformation) OUT PVOID FileInformation)
{ {
IO_STATUS_BLOCK IoStatusBlock; NTSTATUS Status = STATUS_SUCCESS;
HANDLE FileHandle; KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
NTSTATUS Status; DUMMY_FILE_OBJECT DummyFileObject;
KPROCESSOR_MODE AccessMode; FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
UNICODE_STRING ObjectName; HANDLE Handle;
OBJECT_CREATE_INFORMATION ObjectCreateInfo; OPEN_PACKET OpenPacket;
OBJECT_ATTRIBUTES LocalObjectAttributes; BOOLEAN IsBasic;
ULONG BufferSize; PAGED_CODE();
union
{
FILE_BASIC_INFORMATION BasicInformation;
FILE_NETWORK_OPEN_INFORMATION NetworkOpenInformation;
}LocalFileInformation;
if (FileInformationClass == FileBasicInformation) /* Check if the caller was user mode */
if (AccessMode != KernelMode)
{ {
BufferSize = sizeof(FILE_BASIC_INFORMATION); /* 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;
} }
else if (FileInformationClass == FileNetworkOpenInformation)
/* 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)
{ {
BufferSize = sizeof(FILE_NETWORK_OPEN_INFORMATION); /* Parse failed */
return Status;
} }
else else
{ {
return STATUS_INVALID_PARAMETER; /* Use the Io status */
Status = OpenPacket.FinalStatus;
} }
AccessMode = ExGetPreviousMode(); /* Check if we were succesful and this was user mode and a full query */
if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
if (AccessMode != KernelMode)
{ {
Status = STATUS_SUCCESS; /* Enter SEH for copy */
_SEH_TRY _SEH_TRY
{ {
ProbeForWrite(FileInformation, /* Copy the buffer back */
BufferSize, RtlMoveMemory(FileInformation,
sizeof(ULONG)); &NetworkOpenInfo,
} FileInformationSize);
_SEH_HANDLE
{
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 _SEH_HANDLE
{ {
/* Get exception code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
} }
/* Return status */
return Status; return Status;
} }
@ -1228,6 +1312,9 @@ IoCreateFile(OUT PHANDLE FileHandle,
OpenPacket.DummyFileObject = NULL; OpenPacket.DummyFileObject = NULL;
OpenPacket.InternalFlags = 0; OpenPacket.InternalFlags = 0;
/* Update the operation count */
IopUpdateOperationCount(IopOtherTransfer);
/* /*
* Attempt opening the file. This will call the I/O Parse Routine for * Attempt opening the file. This will call the I/O Parse Routine for
* the File Object (IopParseDevice) which will create the object and * the File Object (IopParseDevice) which will create the object and
@ -1386,7 +1473,7 @@ IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
sizeof(FILE_OBJECT), sizeof(FILE_OBJECT),
0, 0,
(PVOID*)&CreatedFileObject); (PVOID*)&CreatedFileObject);
if (!NT_SUCCESS(Status)) return (NULL); if (!NT_SUCCESS(Status)) return NULL;
/* Choose Device Object */ /* Choose Device Object */
if (FileObject) DeviceObject = FileObject->DeviceObject; if (FileObject) DeviceObject = FileObject->DeviceObject;
@ -1764,8 +1851,10 @@ STDCALL
NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PFILE_BASIC_INFORMATION FileInformation) OUT PFILE_BASIC_INFORMATION FileInformation)
{ {
/* Call the internal helper API */
return IopQueryAttributesFile(ObjectAttributes, return IopQueryAttributesFile(ObjectAttributes,
FileBasicInformation, FileBasicInformation,
sizeof(FILE_BASIC_INFORMATION),
FileInformation); FileInformation);
} }
@ -1774,9 +1863,11 @@ STDCALL
NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation) OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
{ {
return IopQueryAttributesFile(ObjectAttributes, /* Call the internal helper API */
FileNetworkOpenInformation, return IopQueryAttributesFile(ObjectAttributes,
FileInformation); FileNetworkOpenInformation,
sizeof(FILE_NETWORK_OPEN_INFORMATION),
FileInformation);
} }
/** /**