2025-04-27 07:49:33 -04:00

471 lines
14 KiB
C

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
InnerIo.c
Abstract:
This module implements the read, write, and lockctrl routines for the
reflector.
Author:
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include "webdav.h"
typedef struct _DAV_IRPCOMPLETION_CONTEXT {
KEVENT Event;
} DAV_IRPCOMPLETION_CONTEXT, *PDAV_IRPCOMPLETION_CONTEXT;
NTSTATUS
DavIrpCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP CalldownIrp,
IN PVOID Context
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, MRxDAVBuildAsynchronousRequest)
#pragma alloc_text(PAGE, DavXxxInformation)
#endif
//
// Implementation of functions begins here.
//
NTSTATUS
DavIrpCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP CalldownIrp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the calldownirp is completed.
Arguments:
DeviceObject - The DAV Device Object.
CalldownIrp - The IRP that was sent down.
Context - The callback context.
Return Value:
RXSTATUS - STATUS_MORE_PROCESSING_REQUIRED
--*/
{
PDAV_IRPCOMPLETION_CONTEXT IrpCompletionContext = NULL;
//
// This is not Pageable code.
//
IrpCompletionContext = (PDAV_IRPCOMPLETION_CONTEXT)Context;
if (CalldownIrp->PendingReturned){
KeSetEvent( &IrpCompletionContext->Event, 0, FALSE );
}
return(STATUS_MORE_PROCESSING_REQUIRED);
}
NTSTATUS
MRxDAVBuildAsynchronousRequest(
IN PRX_CONTEXT RxContext,
IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL
)
/*++
Routine Description:
This routine builds an I/O Request Packet (IRP) suitable for a File System
Driver (FSD) to use in requesting an I/O operation from a device driver.
The request (RxContext->MajorFunction) must be one of the following request
codes:
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_DIRECTORY_CONTROL
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_SHUTDOWN (not yet implemented)
Arguments:
RxContext - The RDBSS context.
CompletionRoutine - The Irp CompletionRoutine.
Return Value:
The return status of the operation.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
ULONG MajorFunction = RxContext->MajorFunction;
RxCaptureFcb;
PLOWIO_CONTEXT LowIoContext = &(RxContext->LowIoContext);
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext;
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
PWEBDAV_SRV_OPEN davSrvOpen = MRxDAVGetSrvOpenExtension(SrvOpen);
PDEVICE_OBJECT DeviceObject = davSrvOpen->UnderlyingDeviceObject;
PFILE_OBJECT FileObject = davSrvOpen->UnderlyingFileObject;
LARGE_INTEGER ZeroAsLI;
ULONG MdlLength = 0;
PAGED_CODE();
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Entering MRxDAVBuildAsynchronousRequest!!!!\n",
PsGetCurrentThreadId()));
DavDbgTrace(DAV_TRACE_CONTEXT,
("%ld: MRxDAVBuildAsynchronousRequest: RxContext: %08lx.\n",
PsGetCurrentThreadId(), RxContext));
AsyncEngineContext = (PUMRX_ASYNCENGINE_CONTEXT)RxContext->MRxContext[0];
IF_DEBUG {
RxCaptureFobx;
ASSERT (capFobx != NULL);
ASSERT (capFobx->pSrvOpen == RxContext->pRelevantSrvOpen);
}
ASSERT (davSrvOpen->UnderlyingFileObject);
if (DeviceObject->Flags & DO_BUFFERED_IO) {
//
// I cannot handled buffered_I/O devices. Sigh.
//
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVBuildAsynchronousRequest: Buffered IO.\n",
PsGetCurrentThreadId()));
return STATUS_INVALID_DEVICE_REQUEST;
}
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVBuildAsynchronousRequest: Length = %08lx, Offset "
"= %08lx.\n", PsGetCurrentThreadId(),
LowIoContext->ParamsFor.ReadWrite.ByteCount,
(ULONG)LowIoContext->ParamsFor.ReadWrite.ByteOffset));
ZeroAsLI.QuadPart = 0;
irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!irp) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVBuildAsynchronousRequest/IoAllocateIrp.\n",
PsGetCurrentThreadId()));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set current thread for IoSetHardErrorOrVerifyDevice.
//
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Get a pointer to the stack location of the first driver which will be
// invoked. This is where the function codes and the parameters are set.
//
irpSp = IoGetNextIrpStackLocation(irp);
irpSp->MajorFunction = (UCHAR) MajorFunction;
irpSp->FileObject = FileObject;
{
BOOLEAN EnableCalls = CompletionRoutine != NULL;
IoSetCompletionRoutine(irp,
CompletionRoutine,
RxContext,
EnableCalls,
EnableCalls,
EnableCalls);
}
if ( (MajorFunction == IRP_MJ_READ) || (MajorFunction == IRP_MJ_WRITE) ) {
BOOLEAN PagingIo;
PagingIo = BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
LOWIO_READWRITEFLAG_PAGING_IO);
if (PagingIo) {
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVBuildAsynchronousRequest: Paging IO.\n",
PsGetCurrentThreadId()));
}
//
// For now, never paging I/O.
//
PagingIo = FALSE;
// irp->Flags |= IRP_NOCACHE;
//
// 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.
//
ASSERT (&irpSp->Parameters.Write.Key == &irpSp->Parameters.Read.Key);
ASSERT (&irpSp->Parameters.Write.Length == &irpSp->Parameters.Read.Length);
ASSERT (&irpSp->Parameters.Write.ByteOffset == &irpSp->Parameters.Read.ByteOffset);
irpSp->Parameters.Read.Key = LowIoContext->ParamsFor.ReadWrite.Key;
irpSp->Parameters.Read.ByteOffset.QuadPart =
LowIoContext->ParamsFor.ReadWrite.ByteOffset;
irp->RequestorMode = KernelMode;
irp->UserBuffer = RxLowIoGetBufferAddress(RxContext);
MdlLength = RxContext->CurrentIrp->MdlAddress->ByteCount;
if (PagingIo) {
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVBuildAsynchronousRequest: MdlLength = %08lx.\n",
PsGetCurrentThreadId(), MdlLength));
irpSp->Parameters.Read.Length = MdlLength;
} else {
irpSp->Parameters.Read.Length = LowIoContext->ParamsFor.ReadWrite.ByteCount;
}
} else if (MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
//
// Nothing else to do!!!
//
MdlLength = 0;
} else {
FILE_INFORMATION_CLASS FileInformationClass =
RxContext->Info.FileInformationClass;
PVOID Buffer = RxContext->Info.Buffer;
PULONG pLengthRemaining = &RxContext->Info.LengthRemaining;
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
ASSERT( MajorFunction == IRP_MJ_DIRECTORY_CONTROL );
irpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
irpSp->Parameters.QueryDirectory =
RxContext->CurrentIrpSp->Parameters.QueryDirectory;
ASSERT (
(irpSp->Parameters.QueryDirectory.FileInformationClass ==
FileInformationClass)
&& (irpSp->Parameters.QueryDirectory.Length == *pLengthRemaining)
);
irpSp->Flags = RxContext->CurrentIrpSp->Flags;
irp->UserBuffer = Buffer;
MdlLength = *pLengthRemaining;
if (Wait) {
irp->Flags |= IRP_SYNCHRONOUS_API;
}
}
//
// Build an MDL if necessary.
//
if (MdlLength != 0) {
irp->MdlAddress = IoAllocateMdl(irp->UserBuffer,
MdlLength,
FALSE,
FALSE,
NULL);
if (!irp->MdlAddress) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVBuildAsynchronousRequest/IoAllocateMdl.\n",
PsGetCurrentThreadId()));
IoFreeIrp(irp);
return(STATUS_INSUFFICIENT_RESOURCES);
}
MmBuildMdlForNonPagedPool(irp->MdlAddress);
}
//
// Finally, return a pointer to the IRP.
//
AsyncEngineContext->CalldownIrp = irp;
return STATUS_SUCCESS;
}
NTSTATUS
DavXxxInformation(
IN const int xMajorFunction,
IN PFILE_OBJECT FileObject,
IN ULONG InformationClass,
IN ULONG Length,
OUT PVOID Information,
OUT PULONG ReturnedLength
)
/*++
Routine Description:
This routine returns the requested information about a specified file
or volume. The information returned is determined by the class that
is specified, and it is placed into the caller's output buffer.
Arguments:
pFileObject - Supplies a pointer to the file object about which the
requested information is returned.
FsInformationClass - Specifies the type of information which should be
returned about the file/volume.
Length - Supplies the length of the buffer in bytes.
FsInformation - Supplies a buffer to receive the requested information
returned about the file. This buffer must not be pageable
and must reside in system space.
ReturnedLength - Supplies a variable that is to receive the length of the
information written to the buffer.
FileInformation - Boolean that indicates whether the information requested
is for a file or a volume.
Return Value:
The status returned is the final completion status of the operation.
--*/
{
NTSTATUS Status;
PIRP irp,TopIrp;
PIO_STACK_LOCATION irpSp;
PDEVICE_OBJECT DeviceObject;
DAV_IRPCOMPLETION_CONTEXT IrpCompletionContext;
ULONG DummyReturnedLength;
PAGED_CODE();
if (ReturnedLength == NULL) {
ReturnedLength = &DummyReturnedLength;
}
DeviceObject = IoGetRelatedDeviceObject( FileObject );
//
// Allocate and initialize the I/O Request Packet (IRP) for this operation.
// The allocation is performed with an exception handler in case the
// caller does not have enough quota to allocate the packet.
//
irp = IoAllocateIrp( DeviceObject->StackSize, TRUE );
if (!irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
irp->Tail.Overlay.OriginalFileObject = FileObject;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->RequestorMode = KernelMode;
//
// Get a pointer to the stack location for the first driver. This will be
// used to pass the original function codes and parameters.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = (UCHAR)xMajorFunction;
irpSp->FileObject = FileObject;
IoSetCompletionRoutine(irp,
DavIrpCompletionRoutine,
&IrpCompletionContext,
TRUE,TRUE,TRUE); //call no matter what....
irp->AssociatedIrp.SystemBuffer = Information;
//
// Copy the caller's parameters to the service-specific portion of the
// IRP.
//
IF_DEBUG {
ASSERT( (irpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION)
|| (irpSp->MajorFunction == IRP_MJ_SET_INFORMATION)
|| (irpSp->MajorFunction == IRP_MJ_QUERY_VOLUME_INFORMATION) );
if (irpSp->MajorFunction == IRP_MJ_SET_INFORMATION) {
ASSERT( (InformationClass == FileAllocationInformation)
|| (InformationClass == FileEndOfFileInformation) );
}
ASSERT(&irpSp->Parameters.QueryFile.Length == &irpSp->Parameters.SetFile.Length);
ASSERT(&irpSp->Parameters.QueryFile.Length == &irpSp->Parameters.QueryVolume.Length);
ASSERT(&irpSp->Parameters.QueryFile.FileInformationClass
== &irpSp->Parameters.SetFile.FileInformationClass);
ASSERT((PVOID)&irpSp->Parameters.QueryFile.FileInformationClass
== (PVOID)&irpSp->Parameters.QueryVolume.FsInformationClass);
}
irpSp->Parameters.QueryFile.Length = Length;
irpSp->Parameters.QueryFile.FileInformationClass = InformationClass;
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
KeInitializeEvent(&IrpCompletionContext.Event,
NotificationEvent,
FALSE );
try {
TopIrp = IoGetTopLevelIrp();
IoSetTopLevelIrp(NULL); //tell the underlying guy he's all clear
Status = IoCallDriver(DeviceObject,irp);
} finally {
IoSetTopLevelIrp(TopIrp); //restore my context for unwind
}
if (Status == (STATUS_PENDING)) {
KeWaitForSingleObject( &IrpCompletionContext.Event,
Executive, KernelMode, FALSE, NULL );
Status = irp->IoStatus.Status;
}
if (Status == STATUS_SUCCESS) {
*ReturnedLength = (ULONG)irp->IoStatus.Information;
}
IoFreeIrp(irp);
return(Status);
}