mirror of
https://github.com/reactos/reactos.git
synced 2024-07-13 08:05:12 +00:00
- 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:
parent
8ac94d67d0
commit
6555616bb6
|
@ -38,18 +38,12 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
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 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
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,6 +126,9 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
}
|
||||
}
|
||||
|
||||
/* Check if we really need to create an object */
|
||||
if (!UseDummyFile)
|
||||
{
|
||||
/* Create the actual file object */
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
NULL,
|
||||
|
@ -144,15 +146,6 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
(PVOID*)&FileObject);
|
||||
RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
|
||||
|
||||
/* Set the device object and reference it */
|
||||
Status = IopReferenceDeviceObject(DeviceObject);
|
||||
FileObject->DeviceObject = DeviceObject;
|
||||
|
||||
/* 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))
|
||||
|
@ -182,7 +175,7 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
FileObject->Flags |= FO_WRITE_THROUGH;
|
||||
}
|
||||
|
||||
/* Check if the caller believes the file will be only read sequentially */
|
||||
/* 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 */
|
||||
|
@ -195,6 +188,24 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
/* 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;
|
||||
FileObject->DeviceObject = DeviceObject;
|
||||
|
||||
/* Check if this is a direct device open */
|
||||
if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
|
||||
|
@ -315,8 +326,11 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
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 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
/* 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 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
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,15 +431,78 @@ IopParseDevice(IN PVOID ParseObject,
|
|||
KEBUGCHECK(0);
|
||||
}
|
||||
|
||||
/* Otherwise, we were successful. Reference the object, set status */
|
||||
/* 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 the object and status */
|
||||
*Object = FileObject;
|
||||
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
|
||||
NTAPI
|
||||
|
@ -957,112 +1034,119 @@ NTSTATUS
|
|||
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;
|
||||
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();
|
||||
|
||||
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));
|
||||
}
|
||||
else if (FileInformationClass == FileNetworkOpenInformation)
|
||||
_SEH_HANDLE
|
||||
{
|
||||
BufferSize = sizeof(FILE_NETWORK_OPEN_INFORMATION);
|
||||
/* 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;
|
||||
/* Use the Io status */
|
||||
Status = OpenPacket.FinalStatus;
|
||||
}
|
||||
|
||||
AccessMode = ExGetPreviousMode();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
/* Check if we were succesful and this was user mode and a full query */
|
||||
if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
|
||||
{
|
||||
Status = STATUS_SUCCESS;
|
||||
/* Enter SEH for copy */
|
||||
_SEH_TRY
|
||||
{
|
||||
ProbeForWrite(FileInformation,
|
||||
BufferSize,
|
||||
sizeof(ULONG));
|
||||
}
|
||||
_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);
|
||||
/* Copy the buffer back */
|
||||
RtlMoveMemory(FileInformation,
|
||||
&NetworkOpenInfo,
|
||||
FileInformationSize);
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
/* Get exception code */
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
}
|
||||
|
||||
/* Return status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -1228,6 +1312,9 @@ IoCreateFile(OUT PHANDLE FileHandle,
|
|||
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 @@ IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
|
|||
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 @@ STDCALL
|
|||
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,8 +1863,10 @@ STDCALL
|
|||
NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
|
||||
{
|
||||
/* Call the internal helper API */
|
||||
return IopQueryAttributesFile(ObjectAttributes,
|
||||
FileNetworkOpenInformation,
|
||||
sizeof(FILE_NETWORK_OPEN_INFORMATION),
|
||||
FileInformation);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue