3476 lines
88 KiB
C
3476 lines
88 KiB
C
/*++
|
||
|
||
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
|
||
|