|
|
/*************************************************************************
* * io.c * * Functions to perform kernel level file I/O. * * Copyright (c) 1997-1999 Microsoft Corporation * * *************************************************************************/
#include <ntosp.h>
#include <ctxdd.h>
#if !defined(_GDIPLUS_)
/*=============================================================================
== Internal Functions Defined =============================================================================*/
NTSTATUS _CtxDoFileIo( IN ULONG MajorFunction, IN PFILE_OBJECT fileObject, IN PVOID Buffer, IN ULONG Length, IN PKEVENT pEvent, OUT PIO_STATUS_BLOCK pIosb, OUT PIRP *ppIrp );
NTSTATUS _CtxDeviceControlComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
/*******************************************************************************
* * CtxReadFile * * Kernel read file routine. * * ENTRY: * fileObject (input) * pointer to file object for I/O * Buffer (input) * pointer to read buffer * Length (input) * length of read buffer * pEvent (input) * pointer to I/O event (optional) * pIosb (output) * pointer to IoStatus block (optional) * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/
NTSTATUS CtxReadFile( IN PFILE_OBJECT fileObject, IN PVOID Buffer, IN ULONG Length, IN PKEVENT pEvent OPTIONAL, OUT PIO_STATUS_BLOCK pIosb OPTIONAL, OUT PIRP *ppIrp OPTIONAL ) { return( _CtxDoFileIo( IRP_MJ_READ, fileObject, Buffer, Length, pEvent, pIosb, ppIrp ) ); }
/*******************************************************************************
* * CtxWriteFile * * Kernel write file routine. * * ENTRY: * fileObject (input) * pointer to file object for I/O * Buffer (input) * pointer to write buffer * Length (input) * length of write buffer * pEvent (input) * pointer to I/O event (optional) * pIosb (output) * pointer to IoStatus block (optional) * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/
NTSTATUS CtxWriteFile( IN PFILE_OBJECT fileObject, IN PVOID Buffer, IN ULONG Length, IN PKEVENT pEvent OPTIONAL, OUT PIO_STATUS_BLOCK pIosb OPTIONAL, OUT PIRP *ppIrp OPTIONAL ) { return( _CtxDoFileIo( IRP_MJ_WRITE, fileObject, Buffer, Length, pEvent, pIosb, ppIrp ) ); }
NTSTATUS _CtxDoFileIo( IN ULONG MajorFunction, IN PFILE_OBJECT fileObject, IN PVOID Buffer, IN ULONG Length, IN PKEVENT pEvent, OUT PIO_STATUS_BLOCK pIosb, OUT PIRP *ppIrp ) { PDEVICE_OBJECT deviceObject; LARGE_INTEGER Offset; PIRP irp; PIO_STACK_LOCATION irpSp; NTSTATUS status;
KIRQL irql; extern ULONG IoReadOperationCount, IoWriteOperationCount; static IO_STATUS_BLOCK Iosb;
/*
* We don't support synchronous (i.e. locked) file I/O. */ ASSERT( !(fileObject->Flags & FO_SYNCHRONOUS_IO) ); if ( (fileObject->Flags & FO_SYNCHRONOUS_IO) ) { return( STATUS_INVALID_PARAMETER_MIX ); }
/*
* If caller specified an event, clear it before we begin. */ if ( pEvent ) { KeClearEvent( pEvent ); }
/*
* If the caller does not supply an IOSB, supply * a static one to avoid the overhead of the exception * handler in the IO completion APC. Since the caller(s) * do not care about the result, we can point all such * callers to the same one. */ if( pIosb == NULL ) { pIosb = &Iosb; }
/*
* Get the DeviceObject for this file */ deviceObject = IoGetRelatedDeviceObject( fileObject );
/*
* Build the IRP for this request */ Offset.LowPart = FILE_WRITE_TO_END_OF_FILE; Offset.HighPart = -1; irp = IoBuildAsynchronousFsdRequest( MajorFunction, deviceObject, Buffer, Length, &Offset, pIosb ); if ( irp == NULL ) return( STATUS_INSUFFICIENT_RESOURCES ); /*
* Save callers event pointer. * Also, we must set IRP_SYNCHRONOUS_API in the IRP flags so that * the I/O completion code will NOT attempt to dereference the * event object, since it is not a real object manager object. */ irp->UserEvent = pEvent; irp->Flags |= IRP_SYNCHRONOUS_API;
/*
* Reference the file object since it will be dereferenced in the * I/O completion code, and save a pointer to it in the IRP. */ ObReferenceObject( fileObject ); irp->Tail.Overlay.OriginalFileObject = fileObject; irpSp = IoGetNextIrpStackLocation( irp ); irpSp->FileObject = fileObject;
/*
* Set the address of the current thread in the packet so the * completion code will have a context to execute in. */ irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Queue the IRP to the current thread
//
IoQueueThreadIrp( irp );
//
// Call driver
//
status = IoCallDriver( deviceObject, irp );
//
// If irp->UserEvent == NULL, IO completion will set the file
// object event and status.
//
if (pEvent == NULL) {
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject( &fileObject->Event, Executive, KernelMode, // Prevent KSTACK from paging
FALSE, // Non-alertable
(PLARGE_INTEGER) NULL );
ASSERT(status != STATUS_ALERTED); ASSERT(status != STATUS_USER_APC);
status = fileObject->FinalStatus; } }
if ( pEvent != NULL && ppIrp != NULL ) { // Trap whatever driver uses this inheritly broken interface
*ppIrp = NULL; }
return( status ); }
/*******************************************************************************
* * CtxDeviceIoControlFile * * Kernel DeviceIoControl routine * * ENTRY: * fileObject (input) * pointer to file object for I/O * IoControlCode (input) * Io control code * InputBuffer (input) * pointer to input buffer (optional) * InputBufferLength (input) * length of input buffer * OutputBuffer (input) * pointer to output buffer (optional) * OutputBufferLength (input) * length of output buffer * InternalDeviceIoControl (input) * if TRUE, use IOCTL_INTERNAL_DEVICE_IO_CONTROL * pEvent (input) * pointer to I/O event (optional) * pIosb (output) * pointer to IoStatus block (optional) * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/
NTSTATUS CtxDeviceIoControlFile( IN PFILE_OBJECT fileObject, IN ULONG IoControlCode, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength, IN BOOLEAN InternalDeviceIoControl, IN PKEVENT pEvent OPTIONAL, OUT PIO_STATUS_BLOCK pIosb OPTIONAL, OUT PIRP *ppIrp OPTIONAL ) { PDEVICE_OBJECT deviceObject; PIRP irp; PIO_STACK_LOCATION irpSp; NTSTATUS status;
/*
* We don't support synchronous (i.e. locked) file I/O. */ ASSERT( !(fileObject->Flags & FO_SYNCHRONOUS_IO) ); if ( (fileObject->Flags & FO_SYNCHRONOUS_IO) ) { return( STATUS_INVALID_PARAMETER_MIX ); }
/*
* If caller specified an event, clear it before we begin. */ if ( pEvent ) { KeClearEvent( pEvent ); }
/*
* Get the DeviceObject for this file */ deviceObject = IoGetRelatedDeviceObject( fileObject );
/*
* Build the IRP for this request */ irp = IoBuildDeviceIoControlRequest( IoControlCode, deviceObject, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, InternalDeviceIoControl, pEvent, pIosb ); if ( irp == NULL ) return( STATUS_INSUFFICIENT_RESOURCES );
/*
* Reference the file object since it will be dereferenced in the * I/O completion code, and save a pointer to it in the IRP. * Also, we must set IRP_SYNCHRONOUS_API in the IRP flags so that * the I/O completion code will NOT attempt to dereference the * event object, since it is not a real object manager object. */ ObReferenceObject( fileObject ); irp->Tail.Overlay.OriginalFileObject = fileObject; irpSp = IoGetNextIrpStackLocation( irp ); irpSp->FileObject = fileObject; irp->Flags |= IRP_SYNCHRONOUS_API;
/*
* Call the driver */ status = IoCallDriver( deviceObject, irp );
/*
* If the caller did not specify a wait event and the I/O is pending, * then we must wait for the I/O to complete before we return. */ if ( pEvent == NULL ) { if ( status == STATUS_PENDING ) { status = KeWaitForSingleObject( &fileObject->Event, UserRequest, KernelMode, FALSE, NULL ); if ( status == STATUS_SUCCESS ) status = fileObject->FinalStatus; }
/*
* Caller specified a wait event. * Return the Irp pointer if the caller specified a return pointer. */ } else { if ( ppIrp ) *ppIrp = irp; }
return( status ); }
/*******************************************************************************
* * CtxInternalDeviceIoControlFile * * Kernel DeviceIoControl routine * * ENTRY: * fileObject (input) * pointer to file object for I/O * IrpParameters (input) * information to write to the parameters section of the * stack location of the IRP. * IrpParametersLength (input) * length of the parameter information. Cannot be greater than 16. * MdlBuffer (input) * if non-NULL, a buffer of nonpaged pool to be mapped * into an MDL and placed in the MdlAddress field of the IRP. * MdlBufferLength (input) * the size of the buffer pointed to by MdlBuffer. * MinorFunction (input) * the minor function code for the request. * pEvent (input) * pointer to I/O event (optional) * pIosb (output) * pointer to IoStatus block (optional) * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/
NTSTATUS CtxInternalDeviceIoControlFile( IN PFILE_OBJECT fileObject, IN PVOID IrpParameters, IN ULONG IrpParametersLength, IN PVOID MdlBuffer OPTIONAL, IN ULONG MdlBufferLength, IN UCHAR MinorFunction, IN PKEVENT pEvent OPTIONAL, OUT PIO_STATUS_BLOCK pIosb OPTIONAL, OUT PIRP *ppIrp OPTIONAL ) { PDEVICE_OBJECT deviceObject; PIRP irp; PIO_STACK_LOCATION irpSp; PMDL mdl; NTSTATUS status;
/*
* We don't support synchronous (i.e. locked) file I/O. */ ASSERT( !(fileObject->Flags & FO_SYNCHRONOUS_IO) ); if ( (fileObject->Flags & FO_SYNCHRONOUS_IO) ) { return( STATUS_INVALID_PARAMETER_MIX ); }
/*
* If caller specified an event, clear it before we begin. */ if ( pEvent ) { KeClearEvent( pEvent ); }
/*
* Get the DeviceObject for this file */ deviceObject = IoGetRelatedDeviceObject( fileObject );
/*
* Build the IRP for this request */ irp = IoBuildDeviceIoControlRequest( 0, deviceObject, NULL, 0, NULL, 0, TRUE, pEvent, pIosb ); if ( irp == NULL ) return( STATUS_INSUFFICIENT_RESOURCES );
/*
* If an MDL buffer was specified, get an MDL, map the buffer, * and place the MDL pointer in the IRP. */ if ( MdlBuffer != NULL ) {
mdl = IoAllocateMdl( MdlBuffer, MdlBufferLength, FALSE, FALSE, irp ); if ( mdl == NULL ) { IoFreeIrp( irp ); ObDereferenceObject( fileObject ); return STATUS_INSUFFICIENT_RESOURCES; }
MmBuildMdlForNonPagedPool( mdl );
} else {
irp->MdlAddress = NULL; }
/*
* Reference the file object since it will be dereferenced in the * I/O completion code, and save a pointer to it in the IRP. * Also, we must set IRP_SYNCHRONOUS_API in the IRP flags so that * the I/O completion code will NOT attempt to dereference the * event object, since it is not a real object manager object. */ ObReferenceObject( fileObject ); irp->Tail.Overlay.OriginalFileObject = fileObject; irpSp = IoGetNextIrpStackLocation( irp ); irpSp->FileObject = fileObject; irp->Flags |= IRP_SYNCHRONOUS_API;
/*
* Fill in the service-dependent parameters for the request. */ irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; irpSp->MinorFunction = MinorFunction;
ASSERT( IrpParametersLength <= sizeof(irpSp->Parameters) ); RtlCopyMemory( &irpSp->Parameters, IrpParameters, IrpParametersLength );
/*
* Set up a completion routine which we'll use to free the MDL * allocated previously. */ IoSetCompletionRoutine( irp, _CtxDeviceControlComplete, NULL, TRUE, TRUE, TRUE );
/*
* Call the driver */ status = IoCallDriver( deviceObject, irp );
/*
* If the caller did not specify a wait event and the I/O is pending, * then we must wait for the I/O to complete before we return. */ if ( pEvent == NULL ) { if ( status == STATUS_PENDING ) { status = KeWaitForSingleObject( &fileObject->Event, UserRequest, KernelMode, FALSE, NULL ); if ( status == STATUS_SUCCESS ) status = fileObject->FinalStatus; }
/*
* Caller specified a wait event. * Return the Irp pointer if the caller specified a return pointer. */ } else { if ( ppIrp ) *ppIrp = irp; }
return( status ); }
NTSTATUS _CtxDeviceControlComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) {
//
// If there was an MDL in the IRP, free it and reset the pointer to
// NULL. The IO system can't handle a nonpaged pool MDL being freed
// in an IRP, which is why we do it here.
//
if ( Irp->MdlAddress != NULL ) { IoFreeMdl( Irp->MdlAddress ); Irp->MdlAddress = NULL; }
return( STATUS_SUCCESS );
}
#endif // !defined(_GDIPLUS_)
|