Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

551 lines
15 KiB

/*************************************************************************
*
* 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_)