You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
8.1 KiB
300 lines
8.1 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
InnerIo.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the routines that handle the Query and Set File
|
|
Information IRPs that are sent to the kernel.
|
|
|
|
Author:
|
|
|
|
Rohan Kumar [RohanK] 10-October-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "webdav.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DavXxxInformation)
|
|
#endif
|
|
|
|
//
|
|
// The IrpCompletionContext structure that is used in the Query and Set File
|
|
// Information operations. All we need is an event on which we will wait till
|
|
// the underlying file system completes the request. This event gets signalled
|
|
// in the Completion routine that we specify.
|
|
//
|
|
typedef struct _DAV_IRPCOMPLETION_CONTEXT {
|
|
|
|
//
|
|
// The event which is signalled in the Completion routine that is passed
|
|
// to IoCallDriver in the Query and Set File Information requests.
|
|
//
|
|
KEVENT Event;
|
|
|
|
} DAV_IRPCOMPLETION_CONTEXT, *PDAV_IRPCOMPLETION_CONTEXT;
|
|
|
|
NTSTATUS
|
|
DavIrpCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP CalldownIrp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
//
|
|
// 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 Query and Set File Information IRP that was
|
|
sent to the underlying file system is completed.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The WebDav Device object.
|
|
|
|
CalldownIrp - The IRP that was created and sent to the underlying file
|
|
system.
|
|
|
|
Context - The context that was set in the IoSetCompletionRoutine function.
|
|
|
|
Return Value:
|
|
|
|
STATUS_MORE_PROCESSING_REQUIRED
|
|
|
|
--*/
|
|
{
|
|
PDAV_IRPCOMPLETION_CONTEXT IrpCompletionContext = NULL;
|
|
|
|
//
|
|
// This is not Pageable code.
|
|
//
|
|
|
|
IrpCompletionContext = (PDAV_IRPCOMPLETION_CONTEXT)Context;
|
|
|
|
//
|
|
// If the IoCallDriver routine returned pending then it will be set in the
|
|
// IRP's PendingReturned field. In this case we need to set the event on
|
|
// which the thread which issued IoCallDriver will be waiting.
|
|
//
|
|
if (CalldownIrp->PendingReturned){
|
|
KeSetEvent( &(IrpCompletionContext->Event), 0, FALSE );
|
|
}
|
|
|
|
return(STATUS_MORE_PROCESSING_REQUIRED);
|
|
}
|
|
|
|
|
|
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:
|
|
|
|
xMajorFunction - The Major Function (Query or Set File Information).
|
|
|
|
FileObject - Supplies a pointer to the file object about which the
|
|
requested information is returned.
|
|
|
|
InformationClass - Specifies the type of information which should be
|
|
returned about the file/volume.
|
|
|
|
Length - Supplies the length of the buffer in bytes.
|
|
|
|
Information - 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.
|
|
|
|
Return Value:
|
|
|
|
The status returned is the final completion status of the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PIRP Irp = NULL, TopIrp = NULL;
|
|
PIO_STACK_LOCATION IrpSp = NULL;
|
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|
DAV_IRPCOMPLETION_CONTEXT IrpCompletionContext;
|
|
ULONG DummyReturnedLength = 0;
|
|
|
|
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 == NULL) {
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: DavXxxInformation/IoAllocateIrp\n",
|
|
PsGetCurrentThreadId()));
|
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
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;
|
|
|
|
//
|
|
// Set the completion routine to be called everytime.
|
|
//
|
|
IoSetCompletionRoutine(Irp,
|
|
DavIrpCompletionRoutine,
|
|
&(IrpCompletionContext),
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
Irp->AssociatedIrp.SystemBuffer = Information;
|
|
|
|
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;
|
|
|
|
//
|
|
// Initialize the event on which we will wait after we call IoCallDriver.
|
|
// This event will be signalled in the Completion routine which will be
|
|
// called by the underlying file system after it completes the operation.
|
|
//
|
|
KeInitializeEvent(&(IrpCompletionContext.Event),
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
//
|
|
// Now is the time to call the underlying file system with the Irp that we
|
|
// just created.
|
|
//
|
|
try {
|
|
|
|
//
|
|
// Save the TopLevel Irp.
|
|
//
|
|
TopIrp = IoGetTopLevelIrp();
|
|
|
|
//
|
|
// Tell the underlying guy he's all clear.
|
|
//
|
|
IoSetTopLevelIrp(NULL);
|
|
|
|
//
|
|
// Finally, call the underlying file system to process the request.
|
|
//
|
|
NtStatus = IoCallDriver(DeviceObject, Irp);
|
|
|
|
} finally {
|
|
|
|
//
|
|
// Restore my context for unwind.
|
|
//
|
|
IoSetTopLevelIrp(TopIrp);
|
|
|
|
}
|
|
|
|
|
|
if (NtStatus == STATUS_PENDING) {
|
|
|
|
//
|
|
// If STATUS_PENDING was returned by the underlying file system then we
|
|
// wait here till the operation gets completed.
|
|
//
|
|
KeWaitForSingleObject(&(IrpCompletionContext.Event),
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
NtStatus = Irp->IoStatus.Status;
|
|
|
|
}
|
|
|
|
if (NtStatus == STATUS_SUCCESS) {
|
|
*ReturnedLength = (ULONG)Irp->IoStatus.Information;
|
|
}
|
|
|
|
EXIT_THE_FUNCTION:
|
|
|
|
if (Irp != NULL) {
|
|
IoFreeIrp(Irp);
|
|
}
|
|
|
|
return(NtStatus);
|
|
}
|
|
|