windows-nt/Source/XPSP1/NT/base/fs/srv/io.c
2020-09-26 16:20:57 +08:00

3476 lines
88 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
io.c
Abstract:
!!! Need to handle inability to allocate IRP.
!!! Need to modify to accept file object pointer, not file handle,
to avoid unnecessary translations.
Author:
Chuck Lenzmeier (chuckl) 28-Oct-1989
Revision History:
--*/
#include "precomp.h"
#include "io.tmh"
#pragma hdrstop
#define BugCheckFileId SRV_FILE_IO
//
// Forward declarations
//
PIRP
BuildCoreOfSyncIoRequest (
IN HANDLE FileHandle,
IN PFILE_OBJECT FileObject OPTIONAL,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN OUT PDEVICE_OBJECT *DeviceObject
);
NTSTATUS
StartIoAndWait (
IN PIRP Irp,
IN PDEVICE_OBJECT DeviceObject,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK IoStatusBlock
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, BuildCoreOfSyncIoRequest )
#pragma alloc_text( PAGE, StartIoAndWait )
#pragma alloc_text( PAGE, SrvBuildFlushRequest )
#pragma alloc_text( PAGE, SrvBuildLockRequest )
#pragma alloc_text( PAGE, SrvBuildMailslotWriteRequest )
#pragma alloc_text( PAGE, SrvBuildReadOrWriteRequest )
#pragma alloc_text( PAGE, SrvBuildNotifyChangeRequest )
#pragma alloc_text( PAGE, SrvIssueAssociateRequest )
#pragma alloc_text( PAGE, SrvIssueDisconnectRequest )
#pragma alloc_text( PAGE, SrvIssueTdiAction )
#pragma alloc_text( PAGE, SrvIssueTdiQuery )
#pragma alloc_text( PAGE, SrvIssueQueryDirectoryRequest )
#pragma alloc_text( PAGE, SrvIssueQueryEaRequest )
#pragma alloc_text( PAGE, SrvIssueSendDatagramRequest )
#pragma alloc_text( PAGE, SrvIssueSetClientProcessRequest )
#pragma alloc_text( PAGE, SrvIssueSetEaRequest )
#pragma alloc_text( PAGE, SrvIssueSetEventHandlerRequest )
#pragma alloc_text( PAGE, SrvIssueUnlockRequest )
#pragma alloc_text( PAGE, SrvIssueUnlockSingleRequest )
#pragma alloc_text( PAGE, SrvIssueWaitForOplockBreak )
#pragma alloc_text( PAGE, SrvQuerySendEntryPoint )
#ifdef INCLUDE_SMB_IFMODIFIED
#pragma alloc_text( PAGE, SrvIssueQueryUsnInfoRequest )
#endif
#endif
#if 0
NOT PAGEABLE -- SrvBuildIoControlRequest
#endif
STATIC
PIRP
BuildCoreOfSyncIoRequest (
IN HANDLE FileHandle,
IN PFILE_OBJECT FileObject OPTIONAL,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN OUT PDEVICE_OBJECT *DeviceObject
)
/*++
Routine Description:
This (local) function builds the request-independent portion of
an I/O request packet for an I/O operation that will be performed
synchronously. It initializes a kernel event object, references
the target file object, and allocates and initializes an IRP.
Arguments:
FileHandle - Supplies a handle to the target file object.
FileObject - Optionall supplies a pointer to the target file object.
Event - Supplies a pointer to a kernel event object. This routine
initializes the event.
IoStatusBlock - Supplies a pointer to an I/O status block. This
pointer is placed in the IRP.
DeviceObject - Supplies or receives the address of the device object
associated with the target file object. This address is
subsequently used by StartIoAndWait. *DeviceObject must be
valid or NULL on entry if FileObject != NULL.
Return Value:
PIRP - Returns a pointer to the constructed IRP.
--*/
{
NTSTATUS status;
PIRP irp;
PIO_STACK_LOCATION irpSp;
PAGED_CODE();
//
// Initialize the kernel event that will signal I/O completion.
//
KeInitializeEvent( Event, SynchronizationEvent, FALSE );
//
// Get the file object corresponding to the directory's handle.
// Referencing the file object every time is necessary because the
// IO completion routine dereferneces it.
//
if ( ARGUMENT_PRESENT(FileObject) ) {
ObReferenceObject(FileObject);
} else {
*DeviceObject = NULL;
status = ObReferenceObjectByHandle(
FileHandle,
0L, // DesiredAccess
NULL, // ObjectType
KernelMode,
(PVOID *)&FileObject,
NULL
);
if ( !NT_SUCCESS(status) ) {
return NULL;
}
}
//
// Set the file object event to a non-signaled state.
//
KeClearEvent( &FileObject->Event );
//
// Attempt to allocate and initialize the I/O Request Packet (IRP)
// for this operation.
//
if ( *DeviceObject == NULL ) {
*DeviceObject = IoGetRelatedDeviceObject( FileObject );
}
irp = IoAllocateIrp( (*DeviceObject)->StackSize, TRUE );
if ( irp == NULL ) {
ULONG packetSize = sizeof(IRP) +
((*DeviceObject)->StackSize * sizeof(IO_STACK_LOCATION));
INTERNAL_ERROR(
ERROR_LEVEL_EXPECTED,
"BuildCoreOfSyncIoRequest: Failed to allocate IRP",
NULL,
NULL
);
SrvLogError(
SrvDeviceObject,
EVENT_SRV_NO_NONPAGED_POOL,
STATUS_INSUFFICIENT_RESOURCES,
&packetSize,
sizeof(ULONG),
NULL,
0
);
return NULL;
}
//
// Fill in the service independent parameters in the IRP.
//
irp->MdlAddress = NULL;
irp->Flags = (LONG)IRP_SYNCHRONOUS_API;
irp->RequestorMode = KernelMode;
irp->PendingReturned = FALSE;
irp->UserIosb = IoStatusBlock;
irp->UserEvent = Event;
irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
irp->AssociatedIrp.SystemBuffer = NULL;
irp->UserBuffer = NULL;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject = FileObject;
irp->Tail.Overlay.AuxiliaryBuffer = NULL;
irp->IoStatus.Status = 0;
irp->IoStatus.Information = 0;
//
// Put the file object pointer in the stack location.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->FileObject = FileObject;
irpSp->DeviceObject = *DeviceObject;
return irp;
} // BuildCoreOfSyncIoRequest
STATIC
NTSTATUS
StartIoAndWait (
IN PIRP Irp,
IN PDEVICE_OBJECT DeviceObject,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK IoStatusBlock
)
/*++
Routine Description:
This (local) function passes a fully built I/O request packet to the
target driver, then waits for the driver to complete the request.
Arguments:
Irp - Supplies a pointer to the I/O request packet.
DeviceObject - Supplies a pointer to the target device object.
Event - Supplies a pointer to a kernel event object. This routine
waits for the I/O to complete using this event.
IoStatusBlock - Supplies a pointer to an I/O status block. The
Status field of this structure becomes the return status of
this function.
Return Value:
NTSTATUS - Either an error status returned by the driver from
IoCallDriver, indicating that the driver rejected the request,
or the I/O status placed in the I/O status block by the driver
at I/O completion.
--*/
{
NTSTATUS status;
KIRQL oldIrql;
PAGED_CODE();
//
// Queue the IRP to the thread and pass it to the driver.
//
IoQueueThreadIrp( Irp );
status = IoCallDriver( DeviceObject, Irp );
//
// If necessary, wait for the I/O to complete.
//
if ( status == STATUS_PENDING ) {
KeWaitForSingleObject(
Event,
UserRequest,
KernelMode, // don't let stack be paged -- event is on stack!
FALSE,
NULL
);
}
//
// If the request was successfully queued, get the final I/O status.
//
if ( NT_SUCCESS(status) ) {
status = IoStatusBlock->Status;
}
return status;
} // StartIoAndWait
PIRP
SrvBuildIoControlRequest (
IN OUT PIRP Irp OPTIONAL,
IN PFILE_OBJECT FileObject OPTIONAL,
IN PVOID Context,
IN UCHAR MajorFunction,
IN ULONG IoControlCode,
IN PVOID MainBuffer,
IN ULONG InputBufferLength,
IN PVOID AuxiliaryBuffer OPTIONAL,
IN ULONG OutputBufferLength,
IN OUT PMDL Mdl OPTIONAL,
IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL
)
/*++
Routine Description:
This function builds an I/O request packet for a device or
file system I/O control request.
*** This routine sure takes a lot of arguments!
Arguments:
Irp - Supplies a pointer to an IRP. If NULL, this routine allocates
an IRP and returns its address. Otherwise, it supplies the
address of an IRP allocated by the caller.
FileObject - Supplies a pointer the file object to which this
request is directed. This pointer is copied into the IRP, so
that the called driver can find its file-based context. NOTE
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
that the file object is not deleted while the I/O operation is
in progress. The server accomplishes this by incrementing a
reference count in a local block to account for the I/O; the
local block in turn references the file object.
If this parameter is omitted, it is the responsiblity of the
calling program to load the file object address before starting
the I/O.
Context - Supplies a PVOID value that is passed to the completion
routine.
MajorFunction - The major function that we are calling. Currently
this most be one of IRP_MJ_FILE_SYSTEM_CONTROL or
IRP_MJ_DEVICE_IO_CONTROL.
IoControlCode - Supplies the control code for the operation.
MainBuffer - Supplies the address of the main buffer. This must
be a system virtual address, and the buffer must be locked in
memory. If ControlCode specifies a method 0 request, the actual
length of the buffer must be the greater of InputBufferLength
and OutputBufferLength.
InputBufferLength - Supplies the length of the input buffer.
AuxiliaryBuffer - Supplies the address of the auxiliary buffer. If the
control code method is 0, this is a buffered I/O buffer, but the
data returned by the called driver in the system buffer is not
automatically copied into the auxiliary buffer. Instead, the
auxiliary data ends up in MainBuffer. If the caller wishes the
data to be in AuxiliaryBuffer, it must copy the data at some point
after the completion routine runs.
If the control code method is 1 or 2, this parameter is ignored;
instead, the Mdl parameter is used to obtain the starting
virtual address of the buffer.
OutputBufferLength - Supplies the length of the output buffer. Note
that this parameter must be specified even when the Mdl
parameter is specified.
Mdl - If the control code method is 1 or 2, indicating direct I/O on
the "output" buffer, this parameter is used to supply a pointer
to an MDL describing a buffer. Mdl must not be NULL, and the
AuxiliaryBuffer parameter is ignored. The buffer must reside in
the system virtual address space (for the benefit of the
transport provider). If the buffer is not already locked, this
routine locks it. It is the calling program's responsibility to
unlock the buffer and (potentially) deallocate the MDL after the
I/O is complete.
This parameter is ignored if the control method is not 1 or 2.
CompletionRoutine - An optional IO completion routine. If none
is specified, SrvFsdIoCompletionRoutine is used.
Return Value:
PIRP - Returns a pointer to the constructed IRP. If the Irp
parameter was not NULL on input, the function return value will
be the same value (so it is safe to discard the return value in
this case). It is the responsibility of the calling program to
deallocate the IRP after the I/O request is complete.
--*/
{
CLONG method;
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpSp;
ASSERT( MajorFunction == IRP_MJ_DEVICE_CONTROL ||
MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL ||
MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL );
//
// Get the method with which the buffers are being passed.
//
if ((MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
(MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)) {
method = IoControlCode & 3;
} else {
method = 4;
}
if ( ARGUMENT_PRESENT(Irp) ) {
if( Irp->AssociatedIrp.SystemBuffer &&
(Irp->Flags & IRP_DEALLOCATE_BUFFER) ) {
ExFreePool( Irp->AssociatedIrp.SystemBuffer );
Irp->Flags &= ~IRP_DEALLOCATE_BUFFER;
}
}
//
// If the FileObject parameter was specified, obtain the address of
// the device object and allocate the IRP based on the stack size
// for that device. Otherwise, allocate the IRP based on the
// server's receive IRP stack size.
//
if ( ARGUMENT_PRESENT(FileObject) ) {
//
// Allocate an IRP, if necessary. The stack size is one higher
// than that of the target device, to allow for the caller's
// completion routine.
//
deviceObject = IoGetRelatedDeviceObject( FileObject );
if ( ARGUMENT_PRESENT(Irp) ) {
ASSERT( Irp->StackCount >= deviceObject->StackSize );
} else {
//
// Get the address of the target device object.
//
Irp = IoAllocateIrp( SrvReceiveIrpStackSize, FALSE );
if ( Irp == NULL ) {
//
// Unable to allocate an IRP. Inform the caller.
//
return NULL;
}
}
} else {
deviceObject = NULL;
if ( !ARGUMENT_PRESENT(Irp) ) {
Irp = IoAllocateIrp( SrvReceiveIrpStackSize, FALSE );
if ( Irp == NULL ) {
return NULL;
}
}
}
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PROCESSOR_TO_QUEUE()->IrpThread;
DEBUG Irp->RequestorMode = KernelMode;
Irp->IoStatus.Status = 0;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the next stack location. This one is used to
// hold the parameters for the device I/O control request.
//
irpSp = IoGetNextIrpStackLocation( Irp );
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
Irp,
(ARGUMENT_PRESENT( CompletionRoutine ) ?
CompletionRoutine : SrvFsdIoCompletionRoutine),
Context,
TRUE,
TRUE,
TRUE
);
irpSp->MajorFunction = MajorFunction;
irpSp->MinorFunction = 0;
if ( MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL ) {
irpSp->MinorFunction = (UCHAR)IoControlCode;
}
irpSp->FileObject = FileObject;
irpSp->DeviceObject = deviceObject;
//
// Copy the caller's parameters to the service-specific portion of the
// IRP for those parameters that are the same for all three methods.
//
if ( MajorFunction == IRP_MJ_DEVICE_CONTROL ) {
irpSp->Parameters.DeviceIoControl.OutputBufferLength =
OutputBufferLength;
irpSp->Parameters.DeviceIoControl.InputBufferLength =
InputBufferLength;
irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
} else if ( MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL ) {
if ( IoControlCode == TDI_RECEIVE ) {
PTDI_REQUEST_KERNEL_RECEIVE parameters =
(PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
parameters->ReceiveLength = OutputBufferLength;
parameters->ReceiveFlags = 0;
method = 1;
} else if ( IoControlCode == TDI_ACCEPT ) {
PTDI_REQUEST_KERNEL_ACCEPT parameters =
(PTDI_REQUEST_KERNEL_ACCEPT)&irpSp->Parameters;
parameters->RequestConnectionInformation = NULL;
parameters->ReturnConnectionInformation = NULL;
method = 0;
} else {
ASSERTMSG( "Invalid TDI request type", 0 );
}
} else {
irpSp->Parameters.FileSystemControl.OutputBufferLength =
OutputBufferLength;
irpSp->Parameters.FileSystemControl.InputBufferLength =
InputBufferLength;
irpSp->Parameters.FileSystemControl.FsControlCode = IoControlCode;
}
//
// Based on the method by which the buffers are being passed,
// describe a system buffer and optionally build an MDL.
//
switch ( method ) {
case 0:
//
// For this case, InputBuffer must be large enough to contain
// both the input and the output buffers.
//
Irp->MdlAddress = NULL;
Irp->AssociatedIrp.SystemBuffer = MainBuffer;
Irp->UserBuffer = AuxiliaryBuffer;
//
// !!! Does Irp->Flags need to be set? Isn't this only looked
// at by I/O competion, which we bypass?
//
Irp->Flags = (ULONG)IRP_BUFFERED_IO;
if ( ARGUMENT_PRESENT(AuxiliaryBuffer) ) {
Irp->Flags |= IRP_INPUT_OPERATION;
}
break;
case 1:
case 2:
//
// For these two cases, InputBuffer is the buffered I/O "system
// buffer". Build an MDL for either read or write access,
// depending on the method, for the output buffer.
//
Irp->MdlAddress = Mdl;
Irp->AssociatedIrp.SystemBuffer = MainBuffer;
// !!! Ditto above about setting Flags.
Irp->Flags = (ULONG)IRP_BUFFERED_IO;
break;
case 3:
//
// For this case, do nothing. Everything is up to the driver.
// Simply give the driver a copy of the caller's parameters and
// let the driver do everything itself.
//
Irp->MdlAddress = NULL;
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->UserBuffer = AuxiliaryBuffer;
Irp->Flags = 0;
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = MainBuffer;
break;
case 4:
//
// This is the case for file system io request. Both MainBuffer
// and AuxiliaryBuffer are locked system buffers.
//
Irp->MdlAddress = NULL;
Irp->Flags = 0;
Irp->AssociatedIrp.SystemBuffer = MainBuffer;
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = AuxiliaryBuffer;
break;
}
return Irp;
} // SrvBuildIoControlRequest
VOID
SrvBuildFlushRequest (
IN PIRP Irp,
IN PFILE_OBJECT FileObject,
IN PVOID Context OPTIONAL
)
/*++
Routine Description:
This function builds an I/O request packet for a flush request.
Arguments:
Irp - Supplies a pointer to an IRP.
FileObject - Supplies a pointer the file object to which this
request is directed. This pointer is copied into the IRP, so
that the called driver can find its file-based context. NOTE
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
that the file object is not deleted while the I/O operation is
in progress. The server accomplishes this by incrementing a
reference count in a local block to account for the I/O; the
local block in turn references the file object.
Context - Supplies a PVOID value that is passed to the completion
routine.
Return Value:
None.
--*/
{
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpSp;
PAGED_CODE( );
deviceObject = IoGetRelatedDeviceObject( FileObject );
ASSERT( Irp->StackCount >= deviceObject->StackSize );
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PROCESSOR_TO_QUEUE()->IrpThread;
DEBUG Irp->RequestorMode = KernelMode;
Irp->IoStatus.Status = 0;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the next stack location. This one is used to
// hold the parameters for the read request. Fill in the
// service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( Irp );
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
Irp,
SrvFsdIoCompletionRoutine,
Context,
TRUE,
TRUE,
TRUE
);
irpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
irpSp->FileObject = FileObject;
irpSp->DeviceObject = deviceObject;
irpSp->Flags = 0;
return;
} // SrvBuildFlushRequest
VOID
SrvBuildLockRequest (
IN PIRP Irp,
IN PFILE_OBJECT FileObject,
IN PVOID Context OPTIONAL,
IN LARGE_INTEGER ByteOffset,
IN LARGE_INTEGER Length,
IN ULONG Key,
IN BOOLEAN FailImmediately,
IN BOOLEAN ExclusiveLock
)
/*++
Routine Description:
This function builds an I/O request packet for a lock request.
Arguments:
Irp - Supplies a pointer to an IRP.
FileObject - Supplies a pointer the file object to which this
request is directed. This pointer is copied into the IRP, so
that the called driver can find its file-based context. NOTE
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
that the file object is not deleted while the I/O operation is
in progress. The server accomplishes this by incrementing a
reference count in a local block to account for the I/O; the
local block in turn references the file object.
Context - Supplies a PVOID value that is passed to the completion
routine.
StartingBlock - the block number of the beginning of the locked
range.
ByteOffset - the offset within block of the beginning of the locked
range.
Length - the length of the locked range.
Key - the key value to be associated with the lock.
Return Value:
None.
--*/
{
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpSp;
PAGED_CODE( );
deviceObject = IoGetRelatedDeviceObject( FileObject );
ASSERT( Irp->StackCount >= deviceObject->StackSize );
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PROCESSOR_TO_QUEUE()->IrpThread;
DEBUG Irp->RequestorMode = KernelMode;
Irp->IoStatus.Status = 0;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the next stack location. This one is used to
// hold the parameters for the read request. Fill in the
// service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( Irp );
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
Irp,
SrvFsdIoCompletionRoutine,
Context,
TRUE,
TRUE,
TRUE
);
irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
irpSp->MinorFunction = IRP_MN_LOCK;
irpSp->FileObject = FileObject;
irpSp->DeviceObject = deviceObject;
irpSp->Flags = 0;
if ( FailImmediately ) {
irpSp->Flags = SL_FAIL_IMMEDIATELY;
}
if ( ExclusiveLock ) {
irpSp->Flags |= SL_EXCLUSIVE_LOCK;
}
((PWORK_CONTEXT)Context)->Parameters2.LockLength = Length;
irpSp->Parameters.LockControl.Length = &((PWORK_CONTEXT)Context)->Parameters2.LockLength;
irpSp->Parameters.LockControl.Key = Key;
irpSp->Parameters.LockControl.ByteOffset = ByteOffset;
return;
} // SrvBuildLockRequest
NTSTATUS
SrvMdlCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
DeviceObject; Irp; Context;
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
SrvIssueMdlCompleteRequest (
IN PWORK_CONTEXT WorkContext OPTIONAL,
IN PFILE_OBJECT FileObject OPTIONAL,
IN PMDL Mdl,
IN UCHAR Function,
IN PLARGE_INTEGER ByteOffset,
IN ULONG Length
)
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
PFILE_OBJECT fileObject = FileObject ? FileObject : WorkContext->Rfcb->Lfcb->FileObject;
PDEVICE_OBJECT deviceObject = IoGetRelatedDeviceObject( fileObject );
KEVENT userEvent;
NTSTATUS status;
IO_STATUS_BLOCK ioStatusBlock;
if( (irp = IoAllocateIrp( deviceObject->StackSize, TRUE )) == NULL ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
// Reference the file object
ObReferenceObject( fileObject );
KeInitializeEvent( &userEvent, SynchronizationEvent, FALSE );
KeClearEvent( &userEvent );
irp->MdlAddress = Mdl;
irp->Flags = IRP_SYNCHRONOUS_API;
irp->UserEvent = &userEvent;
irp->UserIosb = &ioStatusBlock;
irp->RequestorMode = KernelMode;
irp->PendingReturned = FALSE;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject = fileObject;
irp->IoStatus.Status = 0;
irp->IoStatus.Information = 0;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->FileObject = fileObject;
irpSp->DeviceObject = deviceObject;
irpSp->Flags = 0;
irpSp->MinorFunction = IRP_MN_MDL | IRP_MN_COMPLETE;
irpSp->MajorFunction = Function;
if( Function == IRP_MJ_WRITE ) {
irpSp->Parameters.Write.ByteOffset = *ByteOffset;
irpSp->Parameters.Write.Length = Length;
} else {
irpSp->Parameters.Read.ByteOffset = *ByteOffset;
irpSp->Parameters.Read.Length = Length;
}
status = IoCallDriver( deviceObject, irp );
if (status == STATUS_PENDING) {
(VOID) KeWaitForSingleObject( &userEvent,
UserRequest,
KernelMode,
FALSE,
(PLARGE_INTEGER) NULL );
status = ioStatusBlock.Status;
}
ASSERT( status == STATUS_SUCCESS );
return status;
}
VOID
SrvBuildMailslotWriteRequest (
IN PIRP Irp,
IN PFILE_OBJECT FileObject,
IN PVOID Context OPTIONAL,
IN PVOID Buffer OPTIONAL,
IN ULONG Length
)
/*++
Routine Description:
This function builds an I/O request packet for a mailslot write
request.
Arguments:
Irp - Supplies a pointer to an IRP.
FileObject - Supplies a pointer the file object to which this
request is directed. This pointer is copied into the IRP, so
that the called driver can find its file-based context. NOTE
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
that the file object is not deleted while the I/O operation is
in progress. The server accomplishes this by incrementing a
reference count in a local block to account for the I/O; the
local block in turn references the file object.
Context - Supplies a PVOID value that is passed to the completion
routine.
Buffer - Supplies the system virtual address of the write
buffer.
Length - Supplies the length of the write.
Return Value:
None.
--*/
{
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpSp;
PAGED_CODE( );
deviceObject = IoGetRelatedDeviceObject( FileObject );
ASSERT( Irp->StackCount >= deviceObject->StackSize );
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PROCESSOR_TO_QUEUE()->IrpThread;
DEBUG Irp->RequestorMode = KernelMode;
Irp->IoStatus.Status = 0;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the next stack location. This one is used to
// hold the parameters for the read request.
//
irpSp = IoGetNextIrpStackLocation( Irp );
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
Irp,
SrvFsdIoCompletionRoutine,
Context,
TRUE,
TRUE,
TRUE
);
irpSp->MajorFunction = IRP_MJ_WRITE;
irpSp->MinorFunction = 0;
irpSp->FileObject = FileObject;
irpSp->DeviceObject = deviceObject;
//
// Set the write buffer.
//
//Irp->AssociatedIrp.SystemBuffer = Buffer;
Irp->UserBuffer = Buffer;
Irp->Flags = IRP_BUFFERED_IO;
//
// Set the write parameters.
//
irpSp->Parameters.Write.Length = Length;
return;
} // SrvBuildMailslotWriteRequest
VOID
SrvBuildReadOrWriteRequest (
IN OUT PIRP Irp,
IN PFILE_OBJECT FileObject,
IN PVOID Context OPTIONAL,
IN UCHAR MajorFunction,
IN UCHAR MinorFunction,
IN PVOID Buffer OPTIONAL,
IN ULONG Length,
IN OUT PMDL Mdl OPTIONAL,
IN LARGE_INTEGER ByteOffset,
IN ULONG Key OPTIONAL
)
/*++
Routine Description:
This function builds an I/O request packet for a read or write
request.
Arguments:
Irp - Supplies a pointer to an IRP.
FileObject - Supplies a pointer the file object to which this
request is directed. This pointer is copied into the IRP, so
that the called driver can find its file-based context. NOTE
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
that the file object is not deleted while the I/O operation is
in progress. The server accomplishes this by incrementing a
reference count in a local block to account for the I/O; the
local block in turn references the file object.
Context - Supplies a PVOID value that is passed to the completion
routine.
MajorFunction - Indicates the function to be performed. Must be
either IRP_MJ_READ or IRP_MJ_WRITE.
MinorFunction - Qualifies the function to be performed. (For
example, issued at DPC level, MDL read, etc.)
Buffer - Supplies the system virtual address of the read or write
buffer. This parameter is ignored when MinorFunction is
IRP_MN_*_MDL_*. Otherwise, the buffer must be mapped in the
system virtual address space in order to support buffered I/O
devices and other device drivers that need to look at the user
data. This routine always treats the buffer as a direct I/O
buffer, locking it for I/O with an MDL. It does, however, set
up the IRP appropriately for the device type.
If the Mdl parameter is NULL, this routine locks the buffer in
memory for the I/O. It is then the responsibility of the
calling program to unlock the buffer and deallocate the MDL
after the I/O is complete.
Length - Supplies the length of the read or write.
Mdl - This parameter is used to supply a pointer to an MDL
describing a buffer. It is ignored when MinorFunction is
IRP_MN_MDL_*. Otherwise, Mdl must not be NULL. The buffer must
reside in the system virtual address space (for the benefit of
buffered I/O devices/drivers). If the buffer is not already
locked, this routine locks it. It is the calling program's
responsibility to unlock the buffer and (potentially) deallocate
the MDL after the I/O is complete.
ByteOffset - the offset within the file of the beginning of the read
or write.
Key - the key value to be associated with the read or write.
Return Value:
None.
--*/
{
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpSp;
PAGED_CODE( );
if( Irp->AssociatedIrp.SystemBuffer &&
(Irp->Flags & IRP_DEALLOCATE_BUFFER) ) {
ExFreePool( Irp->AssociatedIrp.SystemBuffer );
Irp->Flags &= ~IRP_DEALLOCATE_BUFFER;
}
//
// Obtain the address of the device object and allocate the IRP
// based on the stack size for that device.
//
deviceObject = IoGetRelatedDeviceObject( FileObject );
ASSERT( Irp->StackCount >= deviceObject->StackSize );
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PROCESSOR_TO_QUEUE()->IrpThread;
DEBUG Irp->RequestorMode = KernelMode;
Irp->IoStatus.Status = 0;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the next stack location. This one is used to
// hold the parameters for the read request.
//
irpSp = IoGetNextIrpStackLocation( Irp );
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
Irp,
SrvFsdIoCompletionRoutine,
Context,
TRUE,
TRUE,
TRUE
);
irpSp->MajorFunction = MajorFunction;
irpSp->MinorFunction = MinorFunction;
irpSp->FileObject = FileObject;
irpSp->DeviceObject = deviceObject;
//
// This routine used to handle MDL read/write completion, but it
// doesn't now.
//
ASSERT( IRP_MN_DPC == 1 );
ASSERT( IRP_MN_MDL == 2 );
ASSERT( IRP_MN_MDL_DPC == 3 );
ASSERT( IRP_MN_COMPLETE_MDL == 6 );
ASSERT( IRP_MN_COMPLETE_MDL_DPC == 7 );
ASSERT( (MinorFunction & 4) == 0 );
//
// Set the parameters according to whether this is a read or a write
// operation. Notice that these parameters must be set even if the
// driver has not specified buffered or direct I/O.
//
if ( MajorFunction == IRP_MJ_WRITE ) {
irpSp->Parameters.Write.ByteOffset = ByteOffset;
irpSp->Parameters.Write.Length = Length;
irpSp->Parameters.Write.Key = Key;
} else {
irpSp->Parameters.Read.ByteOffset = ByteOffset;
irpSp->Parameters.Read.Length = Length;
irpSp->Parameters.Read.Key = Key;
}
//
// Indicate to the file system that this operation can be handled
// synchronously. Basically, this means that the file system can
// use the server's thread to fault pages in, etc. This avoids
// having to context switch to a file system thread.
//
Irp->Flags = IRP_SYNCHRONOUS_API;
//
// If this is the start of an MDL-based read or write, we simply
// need to put the supplied MDL address in the IRP. This optional
// MDL address can provide a partial chain for a read or write that
// was partially satisfied using the fast I/O path.
//
if ( (MinorFunction & IRP_MN_MDL) != 0 ) {
Irp->MdlAddress = Mdl;
DEBUG Irp->UserBuffer = NULL;
DEBUG Irp->AssociatedIrp.SystemBuffer = NULL;
return;
}
//
// Normal ("copy") read or write.
//
ASSERT( Buffer != NULL );
ASSERT( Mdl != NULL );
//
// If the target device does buffered I/O, load the address of the
// caller's buffer as the "system buffered I/O buffer". If the
// target device does direct I/O, load the MDL address. If it does
// neither, load both the user buffer address and the MDL address.
// (This is necessary to support file systems, such as HPFS, that
// sometimes treat the I/O as buffered and sometimes treat it as
// direct.)
//
if ( (deviceObject->Flags & DO_BUFFERED_IO) != 0 ) {
Irp->AssociatedIrp.SystemBuffer = Buffer;
if ( MajorFunction == IRP_MJ_WRITE ) {
Irp->Flags |= IRP_BUFFERED_IO;
} else {
Irp->Flags |= IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
}
} else if ( (deviceObject->Flags & DO_DIRECT_IO) != 0 ) {
Irp->MdlAddress = Mdl;
} else {
Irp->UserBuffer = Buffer;
Irp->MdlAddress = Mdl;
}
return;
} // SrvBuildReadOrWriteRequest
PIRP
SrvBuildNotifyChangeRequest (
IN OUT PIRP Irp,
IN PFILE_OBJECT FileObject,
IN PVOID Context OPTIONAL,
IN ULONG CompletionFilter,
IN PVOID Buffer,
IN ULONG BufferLength,
IN BOOLEAN WatchTree
)
/*++
Routine Description:
This function builds an I/O request packet for a notify change request.
Arguments:
Irp - Supplies a pointer to an IRP.
FileObject - Supplies a pointer the file object to which this
request is directed. This pointer is copied into the IRP, so
that the called driver can find its file-based context. NOTE
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
that the file object is not deleted while the I/O operation is
in progress. The server accomplishes this by incrementing a
reference count in a local block to account for the I/O; the
local block in turn references the file object.
Context - Supplies a PVOID value that is passed to the completion
routine.
CompletionFilter - Specifies which directory changes will cause the
File sytsem to complete the IRP.
Buffer - The buffer to receive the directory change data.
BufferLength - The size, in bytes, of the buffer.
WatchTree - If TRUE, recursively watch all subdirectories for changes.
Return Value:
PIRP - Returns a pointer to the constructed IRP. If the Irp
parameter was not NULL on input, the function return value will
be the same value (so it is safe to discard the return value in
this case). It is the responsibility of the calling program to
deallocate the IRP after the I/O request is complete.
--*/
{
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpSp;
PMDL mdl;
PAGED_CODE( );
if( Irp->AssociatedIrp.SystemBuffer &&
(Irp->Flags & IRP_DEALLOCATE_BUFFER) ) {
ExFreePool( Irp->AssociatedIrp.SystemBuffer );
Irp->Flags &= ~IRP_DEALLOCATE_BUFFER;
}
//
// Obtain the address of the device object and initialize the IRP.
//
deviceObject = IoGetRelatedDeviceObject( FileObject );
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PROCESSOR_TO_QUEUE()->IrpThread;
Irp->RequestorMode = KernelMode;
Irp->MdlAddress = NULL;
Irp->IoStatus.Status = 0;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the next stack location. This one is used to
// hold the parameters for the read request. Fill in the
// service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( Irp );
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
Irp,
SrvFsdIoCompletionRoutine,
Context,
TRUE,
TRUE,
TRUE
);
irpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
irpSp->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
irpSp->FileObject = FileObject;
irpSp->DeviceObject = deviceObject;
irpSp->Flags = 0;
if (WatchTree) {
irpSp->Flags = SL_WATCH_TREE;
}
irpSp->Parameters.NotifyDirectory.Length = BufferLength;
irpSp->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
if ( (deviceObject->Flags & DO_DIRECT_IO) != 0 ) {
mdl = IoAllocateMdl(
Buffer,
BufferLength,
FALSE,
FALSE,
Irp // stores MDL address in irp->MdlAddress
);
if ( mdl == NULL ) {
//
// Unable to allocate an MDL. Fail the I/O.
//
return NULL;
}
try {
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeMdl( mdl );
return NULL;
}
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->UserBuffer = NULL;
} else {
Irp->AssociatedIrp.SystemBuffer = Buffer;
Irp->UserBuffer = NULL;
}
//
// Return a pointer to the IRP.
//
return Irp;
} // SrvBuildNotifyChangeRequest
NTSTATUS
SrvIssueAssociateRequest (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN HANDLE AddressFileHandle
)
/*++
Routine Description:
This function issues an I/O request packet for a TdiAssociateAddress
request. It builds an I/O request packet, passes the IRP to the
driver (using IoCallDriver), and waits for the I/O to complete.
Arguments:
FileObject - pointer to file object for a connection.
DeviceObject - pointer to pointer to device object for a connection.
AddressFileHandle - handle to an address endpoint.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
PTDI_REQUEST_KERNEL_ASSOCIATE parameters;
KEVENT event;
IO_STATUS_BLOCK iosb;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the I/O.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&irpSp->Parameters;
irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
irpSp->MinorFunction = TDI_ASSOCIATE_ADDRESS;
parameters->AddressHandle = AddressFileHandle;
//
// Start the I/O, wait for it to complete, and return the final status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueAssociateRequest
NTSTATUS
SrvIssueDisconnectRequest (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN ULONG Flags
)
/*++
Routine Description:
This function issues an I/O request packet for a TdiDisconnect
request. It builds an I/O request packet, passes the IRP to the
driver (using IoCallDriver), and waits for the I/O to complete.
Arguments:
FileObject - pointer to file object for a connection.
DeviceObject - pointer to pointer to device object for a connection.
Flags -
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
PTDI_REQUEST_KERNEL parameters;
KEVENT event;
IO_STATUS_BLOCK iosb;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the I/O.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
parameters = (PTDI_REQUEST_KERNEL)&irpSp->Parameters;
irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
irpSp->MinorFunction = TDI_DISCONNECT;
parameters->RequestFlags = Flags;
//
// Start the I/O, wait for it to complete, and return the final status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueDisconnectRequest
NTSTATUS
SrvIssueTdiAction (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN PCHAR Buffer,
IN ULONG BufferLength
)
/*++
Routine Description:
This function issues an I/O request packet for a TdiQueryInformation
(Query Adapter Status) request. It builds an I/O request packet,
passes the IRP to the driver (using IoCallDriver), and waits for the
I/O to complete.
Arguments:
FileObject - pointer to file object for a connection.
DeviceObject - pointer to pointer to device object for a connection.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PMDL mdl;
PAGED_CODE( );
//
// Allocate and build an MDL that we'll use to describe the output
// buffer for the request.
//
mdl = IoAllocateMdl( Buffer, BufferLength, FALSE, FALSE, NULL );
if ( mdl == NULL ) {
return STATUS_INSUFF_SERVER_RESOURCES;
}
try {
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeMdl( mdl );
return GetExceptionCode();
}
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the I/O.
//
MmUnlockPages( mdl );
IoFreeMdl( mdl );
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
TdiBuildAction(
irp,
*DeviceObject,
FileObject,
NULL,
NULL,
mdl
);
//
// Start the I/O, wait for it to complete, and return the final status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueTdiAction
NTSTATUS
SrvIssueTdiQuery (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN PCHAR Buffer,
IN ULONG BufferLength,
IN ULONG QueryType
)
/*++
Routine Description:
This function issues an I/O request packet for a TdiQueryInformation
(Query Adapter Status) request. It builds an I/O request packet,
passes the IRP to the driver (using IoCallDriver), and waits for the
I/O to complete.
Arguments:
FileObject - pointer to file object for a connection.
DeviceObject - pointer to pointer to device object for a connection.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PMDL mdl;
PAGED_CODE( );
//
// Allocate and build an MDL that we'll use to describe the output
// buffer for the request.
//
mdl = IoAllocateMdl( Buffer, BufferLength, FALSE, FALSE, NULL );
if ( mdl == NULL ) {
return STATUS_INSUFF_SERVER_RESOURCES;
}
try {
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeMdl( mdl );
return GetExceptionCode();
}
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the I/O.
//
MmUnlockPages( mdl );
IoFreeMdl( mdl );
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
TdiBuildQueryInformation(
irp,
*DeviceObject,
FileObject,
NULL,
NULL,
QueryType,
mdl
);
//
// Start the I/O, wait for it to complete, and return the final status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueTdiQuery
NTSTATUS
SrvIssueQueryDirectoryRequest (
IN HANDLE FileHandle,
IN PCHAR Buffer,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN PUNICODE_STRING FileName OPTIONAL,
IN PULONG FileIndex OPTIONAL,
IN BOOLEAN RestartScan,
IN BOOLEAN SingleEntriesOnly
)
/*++
Routine Description:
This function issues an I/O request packet for a query directory
request. It builds an I/O request packet, passes the IRP to the
driver (using IoCallDriver), and waits for the I/O to complete.
Arguments:
FileHandle - handle to a directory open with FILE_LIST_DIRECTORY
access.
Buffer - supplies the system virtual address of the buffer. The
buffer must be in nonpaged pool.
Length - supplies the length of the buffer.
FileInformationClass - Specfies the type of information that is to be
returned about the files in the specified directory.
FileName - an optional pointer to a file name. If FileIndex is NULL,
then this is the search specification, i.e. the template that
files must match in order to be returned. If FileIndex is
non-NULL, then this is the name of a file after which to resume
a search.
FileIndex - if specified, the index of a file after which to resume
the search (first file returned is the one after the one
corresponding to the index).
RestartScan - Supplies a BOOLEAN value that, if TRUE, indicates that the
scan should be restarted from the beginning.
SingleEntriesOnly - Supplies a BOOLEAN value that, if TRUE, indicates that
the scan should ask only for one entry at a time.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
ULONG actualBufferLength;
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PDEVICE_OBJECT deviceObject;
PUNICODE_STRING fileNameString;
PMDL mdl;
PAGED_CODE( );
//
// Reject rewind requests if debugging for it. If a file index is
// specified, this must be a rewind request, so reject the request.
//
IF_DEBUG(BRUTE_FORCE_REWIND) {
if ( ARGUMENT_PRESENT( FileIndex ) ) {
return STATUS_NOT_IMPLEMENTED;
}
}
//
// Copy the file name into the end of the specified buffer, setting
// the actualBufferLength accordingly.
//
if ( !ARGUMENT_PRESENT(FileName) || FileName->Length == 0 ) {
actualBufferLength = Length;
fileNameString = NULL;
} else {
//
// *** Remember that the string must be longword-aligned!
//
actualBufferLength = (Length - FileName->Length -
sizeof(UNICODE_STRING)) & ~(sizeof(PVOID)-1);
fileNameString = (PUNICODE_STRING)( Buffer + actualBufferLength );
RtlCopyMemory(
fileNameString + 1,
FileName->Buffer,
FileName->Length
);
fileNameString->Length = FileName->Length;
fileNameString->MaximumLength = FileName->Length;
fileNameString->Buffer = (PWCH)(fileNameString + 1);
}
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
FileHandle,
NULL,
&event,
&iosb,
&deviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the I/O.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
irpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
irpSp->Parameters.QueryDirectory.FileName = (PSTRING)fileNameString;
irpSp->Parameters.QueryDirectory.FileIndex =
(ULONG)( ARGUMENT_PRESENT( FileIndex ) ? *FileIndex : 0 );
irpSp->Parameters.QueryDirectory.Length = actualBufferLength;
irpSp->Parameters.QueryDirectory.FileInformationClass =
FileInformationClass;
//
// Set the flags in the stack location.
//
irpSp->Flags = 0;
if ( ARGUMENT_PRESENT( FileIndex ) ) {
IF_DEBUG( SEARCH ) {
KdPrint(("SrvIssueQueryDirectoryRequest: SL_INDEX_SPECIFIED\n" ));
}
irpSp->Flags |= SL_INDEX_SPECIFIED;
}
if ( RestartScan ) {
IF_DEBUG( SEARCH ) {
KdPrint(("SrvIssueQueryDirectoryRequest: SL_RESTART_SCAN\n" ));
}
irpSp->Flags |= SL_RESTART_SCAN;
}
if( SingleEntriesOnly ) {
IF_DEBUG( SEARCH ) {
KdPrint(("SrvIssueQueryDirectoryRequest: SL_RETURN_SINGLE_ENTRY\n" ));
}
irpSp->Flags |= SL_RETURN_SINGLE_ENTRY;
}
//
// The file system has been updated. Determine whether the driver wants
// buffered, direct, or "neither" I/O.
//
if ( (deviceObject->Flags & DO_BUFFERED_IO) != 0 ) {
//
// The file system wants buffered I/O. Pass the address of the
// "system buffer" in the IRP. Note that we don't want the buffer
// deallocated, nor do we want the I/O system to copy to a user
// buffer, so we don't set the corresponding flags in irp->Flags.
//
irp->AssociatedIrp.SystemBuffer = Buffer;
} else if ( (deviceObject->Flags & DO_DIRECT_IO) != 0 ) {
//
// The file system wants direct I/O. Allocate an MDL and lock the
// buffer into memory.
//
mdl = IoAllocateMdl(
Buffer,
actualBufferLength,
FALSE,
FALSE,
irp // stores MDL address in irp->MdlAddress
);
if ( mdl == NULL ) {
//
// Unable to allocate an MDL. Fail the I/O.
//
IoFreeIrp( irp );
return STATUS_INSUFF_SERVER_RESOURCES;
}
try {
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeIrp( irp );
MmUnlockPages( mdl );
IoFreeMdl( mdl );
return GetExceptionCode();
}
} else {
//
// The file system wants "neither" I/O. Simply pass the address
// of the buffer.
//
// *** Note that if the file system decides to do this as buffered
// I/O, it will be wasting nonpaged pool, since our buffer is
// already in nonpaged pool. But since we're doing this as a
// synchronous request, the file system probably won't do that.
//
irp->UserBuffer = Buffer;
}
//
// Start the I/O, wait for it to complete, and return the final status.
//
return StartIoAndWait( irp, deviceObject, &event, &iosb );
} // SrvIssueQueryDirectoryRequest
NTSTATUS
SrvIssueQueryEaRequest (
IN HANDLE FileHandle,
IN PVOID Buffer,
IN ULONG Length,
IN PVOID EaList OPTIONAL,
IN ULONG EaListLength,
IN BOOLEAN RestartScan,
OUT PULONG EaErrorOffset OPTIONAL
)
/*++
Routine Description:
This function issues an I/O request packet for an EA query request.
It builds an I/O request packet, passes the IRP to the driver (using
IoCallDriver), and waits for the I/O to complete.
Arguments:
FileHandle - handle to a file open with FILE_READ_EA access.
Buffer - supplies the system virtual address of the buffer. The
buffer must be in nonpaged pool.
Length - supplies the length of the buffer.
EaList - supplies a pointer to a list of EAs to query. If omitted,
all EAs are returned.
EaListLength - supplies the length of EaList.
RestartScan - if TRUE, then the query of EAs is to start from the
beginning. Otherwise, continue from where we left off.
EaErrorOffset - if not NULL, returns the offset into EaList of an
invalid EA, if any.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
NTSTATUS status;
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PDEVICE_OBJECT deviceObject;
PMDL mdl;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
FileHandle,
NULL,
&event,
&iosb,
&deviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the i/o.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_QUERY_EA;
irpSp->MinorFunction = 0;
irpSp->Parameters.QueryEa.Length = Length;
irpSp->Parameters.QueryEa.EaList = EaList;
irpSp->Parameters.QueryEa.EaListLength = EaListLength;
irpSp->Parameters.QueryEa.EaIndex = 0L;
irpSp->Flags = (UCHAR)( RestartScan ? SL_RESTART_SCAN : 0 );
//
// The file system has been updated. Determine whether the
// driver wants buffered, direct, or "neither" I/O.
//
if ( (deviceObject->Flags & DO_BUFFERED_IO) != 0 ) {
//
// The file system wants buffered I/O. Pass the address of the
// "system buffer" in the IRP. Note that we don't want the buffer
// deallocated, nor do we want the I/O system to copy to a user
// buffer, so we don't set the corresponding flags in irp->Flags.
//
irp->AssociatedIrp.SystemBuffer = Buffer;
} else if ( (deviceObject->Flags & DO_DIRECT_IO) != 0 ) {
//
// The file system wants direct I/O. Allocate an MDL and lock the
// buffer into memory.
//
mdl = IoAllocateMdl(
Buffer,
Length,
FALSE,
FALSE,
irp // stores MDL address in irp->MdlAddress
);
if ( mdl == NULL ) {
//
// Unable to allocate an MDL. Fail the I/O.
//
IoFreeIrp( irp );
return STATUS_INSUFF_SERVER_RESOURCES;
}
try {
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeIrp( irp );
IoFreeMdl( mdl );
return GetExceptionCode();
}
} else {
//
// The file system wants "neither" I/O. Simply pass the address
// of the buffer.
//
// *** Note that if the file system decides to do this as buffered
// I/O, it will be wasting nonpaged pool, since out buffer is
// already in nonpaged pool. But since we're doing this as a
// synchronous request, the file system probably won't do that.
//
irp->UserBuffer = Buffer;
}
//
// Start the I/O, wait for it to complete, and return the final
// status.
//
status = StartIoAndWait( irp, deviceObject, &event, &iosb );
if ( ARGUMENT_PRESENT(EaErrorOffset) ) {
*EaErrorOffset = (ULONG)iosb.Information;
}
return status;
} // SrvIssueQueryEaRequest
NTSTATUS
SrvIssueSendDatagramRequest (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN PTDI_CONNECTION_INFORMATION SendDatagramInformation,
IN PVOID Buffer,
IN ULONG Length
)
/*++
Routine Description:
This function issues an I/O request packet for a TDI Send Datagram
request. It builds an I/O request packet, passes the IRP to the
driver (using IoCallDriver), and waits for the I/O to complete.
Arguments:
FileObject - pointer to file object for an endpoint.
DeviceObject - pointer to pointer to device object for an endpoint.
SendDatagramInformation - pointer to a buffer describing the
target of the datagram.
Buffer - Supplies the system virtual address of the buffer. The
buffer must be in nonpaged pool.
Length - Supplies the length of the buffer.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
PTDI_REQUEST_KERNEL_SENDDG parameters;
KEVENT event;
IO_STATUS_BLOCK iosb;
PMDL mdl;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the i/o.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
parameters = (PTDI_REQUEST_KERNEL_SENDDG)&irpSp->Parameters;
irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
irpSp->MinorFunction = TDI_SEND_DATAGRAM;
parameters->SendLength = Length;
parameters->SendDatagramInformation = SendDatagramInformation;
//
// The file system wants direct I/O. Allocate an MDL and lock the
// buffer into memory.
//
mdl = IoAllocateMdl(
Buffer,
Length,
FALSE,
FALSE,
irp // stores MDL address in irp->MdlAddress
);
if ( mdl == NULL ) {
//
// Unable to allocate an MDL. Fail the I/O.
//
IoFreeIrp( irp );
return STATUS_INSUFF_SERVER_RESOURCES;
}
try {
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeIrp( irp );
IoFreeMdl( mdl );
return GetExceptionCode();
}
//
// Start the I/O, wait for it to complete, and return the final
// status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueSendDatagramRequest
NTSTATUS
SrvIssueSetClientProcessRequest (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN PCONNECTION Connection,
IN PVOID ClientSession,
IN PVOID ClientProcess
)
/*++
Routine Description:
This function issues an I/O request packet for a named pipe Set
Client Process file system control function. It builds an I/O
request packet, passes the IRP to the driver (using IoCallDriver),
and waits for the I/O to complete.
Arguments:
FileObject - pointer to file object for a pipe.
DeviceObject - pointer to pointer to device object for a pipe.
ClientSession - A unique identifier for the client's session with
the server. Assigned by the server.
ClientProcess - A unique identifier for the client process.
Assigned by the redirector.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
FILE_PIPE_CLIENT_PROCESS_BUFFER_EX clientIdBuffer;
KEVENT event;
IO_STATUS_BLOCK iosb;
UNICODE_STRING unicodeString;
NTSTATUS status;
PAGED_CODE( );
//
// Set the client ID in the FSCTL buffer.
//
clientIdBuffer.ClientSession = ClientSession;
clientIdBuffer.ClientProcess = ClientProcess;
// Set ClientComputerName in the buffer
// The Rtl function terminates the string, so leave enough room
unicodeString.Buffer = clientIdBuffer.ClientComputerBuffer;
unicodeString.MaximumLength =
(USHORT) ((FILE_PIPE_COMPUTER_NAME_LENGTH+1) * sizeof(WCHAR));
status = RtlOemStringToUnicodeString( &unicodeString,
&Connection->OemClientMachineNameString,
FALSE );
if (!NT_SUCCESS(status)) {
// Set length to zero in case conversion fails
unicodeString.Length = 0;
}
clientIdBuffer.ClientComputerNameLength = unicodeString.Length;
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the i/o.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
irpSp->MinorFunction = IRP_MN_KERNEL_CALL;
irpSp->Parameters.FileSystemControl.OutputBufferLength = 0;
irpSp->Parameters.FileSystemControl.InputBufferLength =
sizeof( clientIdBuffer );
irpSp->Parameters.FileSystemControl.FsControlCode =
FSCTL_PIPE_SET_CLIENT_PROCESS;
irp->MdlAddress = NULL;
irp->AssociatedIrp.SystemBuffer = &clientIdBuffer;
irp->Flags |= IRP_BUFFERED_IO;
irp->UserBuffer = NULL;
//
// Start the I/O, wait for it to complete, and return the final
// status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueSetClientProcessRequest
NTSTATUS
SrvIssueSetEaRequest (
IN HANDLE FileHandle,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG EaErrorOffset OPTIONAL
)
/*++
Routine Description:
This function issues an I/O request packet for an EA set request.
It builds an I/O request packet, passes the IRP to the driver (using
IoCallDriver), and waits for the I/O to complete.
WARNING! The server must walk the list of EAs to set if it
comes directly from a client. This is because the file system
trusts that this list is legitimate and could run into problems
if the list has an error.
Arguments:
FileHandle - handle to a file open with FILE_WRITE_EA access.
Buffer - Supplies the system virtual address of the buffer. The
buffer must be in nonpaged pool.
Length - Supplies the length of the buffer.
EaErrorOffset - if not NULL, returns the offset into EaList of an
invalid EA, if any.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
NTSTATUS status;
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PDEVICE_OBJECT deviceObject;
PMDL mdl;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
FileHandle,
NULL,
&event,
&iosb,
&deviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the i/o.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_SET_EA;
irpSp->MinorFunction = 0;
irpSp->Parameters.SetEa.Length = Length;
irpSp->Flags = 0;
//
// The file system has been updated. Determine whether the driver
// wants buffered, direct, or "neither" I/O.
//
if ( (deviceObject->Flags & DO_BUFFERED_IO) != 0 ) {
//
// The file system wants buffered I/O. Pass the address of the
// "system buffer" in the IRP. Note that we don't want the buffer
// deallocated, nor do we want the I/O system to copy to a user
// buffer, so we don't set the corresponding flags in irp->Flags.
//
irp->AssociatedIrp.SystemBuffer = Buffer;
} else if ( (deviceObject->Flags & DO_DIRECT_IO) != 0 ) {
//
// The file system wants direct I/O. Allocate an MDL and lock the
// buffer into memory.
//
mdl = IoAllocateMdl(
Buffer,
Length,
FALSE,
FALSE,
irp // stores MDL address in irp->MdlAddress
);
if ( mdl == NULL ) {
//
// Unable to allocate an MDL. Fail the I/O.
//
IoFreeIrp( irp );
return STATUS_INSUFF_SERVER_RESOURCES;
}
try {
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeIrp( irp );
IoFreeMdl( mdl );
return GetExceptionCode();
}
} else {
//
// The file system wants "neither" I/O. Simply pass the address
// of the buffer.
//
// *** Note that if the file system decides to do this as buffered
// I/O, it will be wasting nonpaged pool, since our buffer is
// already in nonpaged pool. But since we're doing this as a
// synchronous request, the file system probably won't do that.
//
irp->UserBuffer = Buffer;
}
//
// Start the I/O, wait for it to complete, and return the final
// status.
//
status = StartIoAndWait( irp, deviceObject, &event, &iosb );
if ( ARGUMENT_PRESENT(EaErrorOffset) ) {
*EaErrorOffset = (ULONG)iosb.Information;
}
return status;
} // SrvIssueSetEaRequest
NTSTATUS
SrvIssueSetEventHandlerRequest (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN ULONG EventType,
IN PVOID EventHandler,
IN PVOID EventContext
)
/*++
Routine Description:
This function issues an I/O request packet for a TdiSetEventHandler
request. It builds an I/O request packet, passes the IRP to the
driver (using IoCallDriver), and waits for the I/O to complete.
Arguments:
FileObject - pointer to file object for a connection.
DeviceObject - pointer to pointer to device object for a connection.
EventType -
EventHandler -
EventContext -
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
PTDI_REQUEST_KERNEL_SET_EVENT parameters;
KEVENT event;
IO_STATUS_BLOCK iosb;
PDEVICE_OBJECT deviceObject = NULL;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the I/O.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&irpSp->Parameters;
irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
irpSp->MinorFunction = TDI_SET_EVENT_HANDLER;
parameters->EventType = EventType;
parameters->EventHandler = EventHandler;
parameters->EventContext = EventContext;
//
// Start the I/O, wait for it to complete, and return the final status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueSetEventHandlerRequest
NTSTATUS
SrvIssueUnlockRequest (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN UCHAR UnlockOperation,
IN LARGE_INTEGER ByteOffset,
IN LARGE_INTEGER Length,
IN ULONG Key
)
/*++
Routine Description:
This function issues an I/O request packet for an unlock request.
It builds an I/O request packet, passes the IRP to the driver
(using IoCallDriver), and waits for the I/O to complete.
Arguments:
FileObject - Pointer to the file object.
DeviceObject - Pointer to pointer to the related device object.
UnlockOperation - the minor function code describing the unlock
operation -- IRP_MN_UNLOCK_SINGLE or IRP_MN_UNLOCK_ALL_BY_KEY.
StartingBlock - the block number of the beginning of the locked
range. Ignored if UnlockOperation is IRP_MN_UNLOCK_ALL_BY_KEY.
ByteOffset - the offset within block of the beginning of the locked
range. Ignored if UnlockOperation is IRP_MN_UNLOCK_ALL_BY_KEY.
Length - the length of the locked range. Ignored if UnlockOperation
is IRP_MN_UNLOCK_ALL_BY_KEY.
Key - the key value used to obtain the lock.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PFAST_IO_DISPATCH fastIoDispatch;
PAGED_CODE( );
//
// Try the turbo unlock path first.
//
fastIoDispatch = (*DeviceObject)->DriverObject->FastIoDispatch;
if ( fastIoDispatch != NULL ) {
if ( (UnlockOperation == IRP_MN_UNLOCK_SINGLE) &&
(fastIoDispatch->FastIoUnlockSingle != NULL) ) {
INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastUnlocksAttempted );
if ( fastIoDispatch->FastIoUnlockSingle(
FileObject,
&ByteOffset,
&Length,
IoGetCurrentProcess(),
Key,
&iosb,
*DeviceObject
) ) {
return iosb.Status;
}
INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastUnlocksFailed );
} else if ( (UnlockOperation == IRP_MN_UNLOCK_ALL_BY_KEY) &&
(fastIoDispatch->FastIoUnlockAllByKey != NULL) ) {
INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastUnlocksAttempted );
if ( fastIoDispatch->FastIoUnlockAllByKey(
FileObject,
IoGetCurrentProcess(),
Key,
&iosb,
*DeviceObject
) ) {
return iosb.Status;
}
INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastUnlocksFailed );
}
}
//
// The turbo path failed or was unavailable. Allocate an IRP and
// fill in the service-independent parameters for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the i/o.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
irpSp->MinorFunction = UnlockOperation;
irpSp->Parameters.LockControl.Length = &Length;
irpSp->Parameters.LockControl.Key = Key;
irpSp->Parameters.LockControl.ByteOffset = ByteOffset;
//
// Start the I/O, wait for it to complete, and return the final
// status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueUnlockRequest
NTSTATUS
SrvIssueUnlockSingleRequest (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN LARGE_INTEGER ByteOffset,
IN LARGE_INTEGER Length,
IN ULONG Key
)
/*++
Routine Description:
This function issues an I/O request packet for an unlock single request.
It builds an I/O request packet, passes the IRP to the driver
(using IoCallDriver), and waits for the I/O to complete.
Arguments:
FileObject - Pointer to the file object.
DeviceObject - Pointer to pointer to the related device object.
StartingBlock - the block number of the beginning of the locked
range. Ignored if UnlockOperation is IRP_MN_UNLOCK_ALL_BY_KEY.
ByteOffset - the offset within block of the beginning of the locked
range. Ignored if UnlockOperation is IRP_MN_UNLOCK_ALL_BY_KEY.
Length - the length of the locked range. Ignored if UnlockOperation
is IRP_MN_UNLOCK_ALL_BY_KEY.
Key - the key value used to obtain the lock.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent
// parameters for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the i/o.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
irpSp->MinorFunction = IRP_MN_UNLOCK_SINGLE;
irpSp->Parameters.LockControl.Length = &Length;
irpSp->Parameters.LockControl.Key = Key;
irpSp->Parameters.LockControl.ByteOffset = ByteOffset;
//
// Start the I/O, wait for it to complete, and return the final
// status.
//
return StartIoAndWait( irp, *DeviceObject, &event, &iosb );
} // SrvIssueUnlockSingleRequest
NTSTATUS
SrvIssueWaitForOplockBreak (
IN HANDLE FileHandle,
PWAIT_FOR_OPLOCK_BREAK WaitForOplockBreak
)
/*++
Routine Description:
This function issues an I/O request packet for a wait for oplock
break request.
It builds an I/O request packet, passes the IRP to the driver
(using IoCallDriver), and waits for the I/O to complete.
Arguments:
FileHandle - handle to a file.
WaitForOplockBreak - Context information for this wait for oplock break.
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
KIRQL oldIrql;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
FileHandle,
NULL,
&event,
&iosb,
&deviceObject
);
if (irp == NULL) {
//
// Unable to allocate an IRP. Fail the i/o.
//
return STATUS_INSUFF_SERVER_RESOURCES;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
irpSp->MinorFunction = 0;
irpSp->Parameters.FileSystemControl.OutputBufferLength = 0;
irpSp->Parameters.FileSystemControl.InputBufferLength = 0;
irpSp->Parameters.FileSystemControl.FsControlCode =
FSCTL_OPLOCK_BREAK_NOTIFY;
//
// Queue the WaitForOplockBreak block on the global list.
//
// We must hold the lock that protects wait for oplock breaks
// from the time we queue this wait for oplock break on the global
// list, to the time the IRP has actually been submitted. Otherwise
// the scavenger might wake up and attempt to cancel an IRP that
// has not yet been submitted.
//
WaitForOplockBreak->Irp = irp;
ACQUIRE_LOCK( &SrvOplockBreakListLock );
SrvInsertTailList(
&SrvWaitForOplockBreakList,
&WaitForOplockBreak->ListEntry
);
//
// The following code is a duplicate of the code from StartIoAndWait().
//
// Start the I/O, wait for it to complete, and return the final
// status.
//
//
// Queue the IRP to the thread and pass it to the driver.
//
IoQueueThreadIrp( irp );
status = IoCallDriver( deviceObject, irp );
RELEASE_LOCK( &SrvOplockBreakListLock );
//
// If necessary, wait for the I/O to complete.
//
if ( status == STATUS_PENDING ) {
KeWaitForSingleObject(
&event,
UserRequest,
KernelMode, // don't let stack be paged -- event is on stack!
FALSE,
NULL
);
}
//
// If the request was successfully queued, get the final I/O status.
//
if ( NT_SUCCESS(status) ) {
status = iosb.Status;
}
return status;
} // SrvIssueWaitForOplockBreak
VOID
SrvQuerySendEntryPoint(
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT *DeviceObject,
IN ULONG IoControlCode,
IN PVOID *EntryPoint
)
/*++
Routine Description:
This function queries the transport for its send entry point.
Arguments:
FileObject - pointer to file object for a connection.
DeviceObject - pointer to pointer to device object for a connection.
EntryPoint -
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
NTSTATUS status;
PAGED_CODE( );
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
FileObject,
&event,
&iosb,
DeviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the I/O.
//
*EntryPoint = NULL;
return;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpSp->MinorFunction = 0;
irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = EntryPoint;
//
// Start the I/O, wait for it to complete, and return the final status.
//
status = StartIoAndWait( irp, *DeviceObject, &event, &iosb );
if ( !NT_SUCCESS(status) ) {
*EntryPoint = NULL;
}
return;
} // SrvQuerySendEntryPoint
#ifdef INCLUDE_SMB_IFMODIFIED
NTSTATUS
SrvIssueQueryUsnInfoRequest (
IN PRFCB Rfcb,
IN BOOLEAN SubmitClose,
OUT PLARGE_INTEGER Usn,
OUT PLARGE_INTEGER FileRefNumber
)
/*++
Routine Description:
This function issues an I/O request packet for a USN query or close
request. It builds an I/O request packet, passes the IRP to the
driver (using IoCallDriver), and waits for the I/O to complete.
Arguments:
Rfcb - pointer to handle that we're querying
SubmitClose - do we submit a close USN record or just simply a USN query?
Usn & FileRefNumber - USN record results
Return Value:
NTSTATUS - the status of the operation. Either the return value of
IoCallDriver, if the driver didn't accept the request, or the
value returned by the driver in the I/O status block.
--*/
{
PIRP irp = NULL;
PMDL mdl = NULL;
PUSN_RECORD usnRecord = NULL;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK iosb;
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
ULONG sizeRequired;
PAGED_CODE( );
//
// if the share doesn't have a USN log, don't bother with this request
//
Usn->QuadPart = 0;
FileRefNumber->QuadPart = 0;
if (! Rfcb->Lfcb->TreeConnect->Share->UsnCapable ) {
return STATUS_SUCCESS;
}
deviceObject = Rfcb->Lfcb->DeviceObject;
//
// Allocate an IRP and fill in the service-independent parameters
// for the request.
//
irp = BuildCoreOfSyncIoRequest(
NULL,
Rfcb->Lfcb->FileObject,
&event,
&iosb,
&deviceObject
);
if ( irp == NULL ) {
//
// Unable to allocate an IRP. Fail the I/O.
//
status = STATUS_INSUFF_SERVER_RESOURCES;
goto exitGetUsn;
}
// if the client opened the file with the short name, we could end up
// having a buffer that's woefully too small. We'll bump the
// allocation up to a large amount so that we don't have to
// go back and do it again.
sizeRequired = MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR);
sizeRequired += sizeof( USN_RECORD );
sizeRequired = QuadAlign( sizeRequired );
usnRecord = ALLOCATE_NONPAGED_POOL( sizeRequired, BlockTypeDataBuffer );
if ( usnRecord == NULL) {
IF_DEBUG(ERRORS) {
KdPrint(( "SrvGetUsnInfoForFile: unable to alloc block of size %u for handle 0x%x\n",
sizeRequired, Rfcb->Lfcb->FileObject ));
}
status = STATUS_INSUFF_SERVER_RESOURCES;
goto exitGetUsn;
}
//
// Fill in the service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
irpSp->MinorFunction = 0;
irpSp->Parameters.FileSystemControl.FsControlCode = SubmitClose ? FSCTL_WRITE_USN_CLOSE_RECORD : FSCTL_READ_FILE_USN_DATA;
irpSp->Parameters.FileSystemControl.OutputBufferLength = sizeRequired;
irpSp->Parameters.FileSystemControl.InputBufferLength = 0;
irpSp->Parameters.FileSystemControl.Type3InputBuffer = NULL;
irp->MdlAddress = NULL;
irp->AssociatedIrp.SystemBuffer = NULL;
irp->UserBuffer = usnRecord;
//
// The file system has been updated. Determine whether the driver wants
// buffered, direct, or "neither" I/O.
//
if ( (deviceObject->Flags & DO_BUFFERED_IO) != 0 ) {
//
// The file system wants buffered I/O. Pass the address of the
// "system buffer" in the IRP. Note that we don't want the buffer
// deallocated, nor do we want the I/O system to copy to a user
// buffer, so we don't set the corresponding flags in irp->Flags.
//
irp->AssociatedIrp.SystemBuffer = usnRecord;
} else if ( (deviceObject->Flags & DO_DIRECT_IO) != 0 ) {
//
// The file system wants direct I/O. Allocate an MDL and lock the
// buffer into memory.
//
mdl = IoAllocateMdl(
usnRecord,
sizeRequired,
FALSE,
FALSE,
irp // stores MDL address in irp->MdlAddress
);
if ( mdl == NULL ) {
//
// Unable to allocate an MDL. Fail the I/O.
//
status = STATUS_INSUFF_SERVER_RESOURCES;
goto exitGetUsn;
}
try {
MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeIrp( irp );
MmUnlockPages( mdl );
IoFreeMdl( mdl );
irp = NULL;
status = GetExceptionCode();
goto exitGetUsn;
}
} else {
//
// The file system wants "neither" I/O. Simply pass the address
// of the buffer.
//
// *** Note that if the file system decides to do this as buffered
// I/O, it will be wasting nonpaged pool, since our buffer is
// already in nonpaged pool. But since we're doing this as a
// synchronous request, the file system probably won't do that.
//
irp->UserBuffer = usnRecord;
}
//
// Start the I/O, wait for it to complete, and return the final status.
//
status = StartIoAndWait( irp, deviceObject, &event, &iosb );
irp = NULL; // it was freed by call to IoCallDriver
if (NT_SUCCESS(status)) {
status = iosb.Status;
}
if (NT_SUCCESS(status)) {
Usn->QuadPart = usnRecord->Usn;
FileRefNumber->QuadPart = usnRecord->FileReferenceNumber;
} else {
ASSERT( status != STATUS_MORE_PROCESSING_REQUIRED );
ASSERT( status != STATUS_PENDING );
IF_DEBUG(ERRORS) {
KdPrint(( "SrvGetUsnInfoForFile: Query USN info failed: 0x%X for handle %u\n",
status, Rfcb->Lfcb->FileObject ));
}
if (status == STATUS_JOURNAL_NOT_ACTIVE ||
status == STATUS_INVALID_DEVICE_REQUEST) {
Rfcb->Lfcb->TreeConnect->Share->UsnCapable = FALSE;
}
}
exitGetUsn:
if (irp != NULL) {
IoFreeIrp( irp );
}
if ( usnRecord != NULL ) {
DEALLOCATE_NONPAGED_POOL( usnRecord );
}
return status;
} // SrvIssueQueryUsnInfoRequest
#endif // def INCLUDE_SMB_IFMODIFIED