/*++ 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); }