/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    Misc.c

Abstract:

    This module implements the dirctrl, fileinfo and volinfo routines for the local minirdr.

Author:

    Joe Linn      [JoeLinn]      4-dec-1994

Revision History:

--*/

#include "precomp.h"
#pragma hdrstop
//#include "fsctlbuf.h"
//#include "NtDdNfs2.h"
//#include "stdio.h"

//
//  The Bug check file id for this module
//

#define BugCheckFileId                   (RDBSS_BUG_CHECK_LOCAL_MISC)

//
//  The local debug trace level
//

#undef Dbg
#define Dbg                              (DEBUG_TRACE_DIRCTRL)




PIRP
MRxLocalBuildCoreOfSyncIoRequest (
    IN PFILE_OBJECT FileObject,
    IN BOOLEAN ForceSyncApi,
    IN PDEVICE_OBJECT DeviceObject,
    IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
    IN PVOID Context
    )

/*++

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:

    FileObject - 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.

    CompletionRoutine - the IrpCompletionRoutine
    Context - context of the completion routine

Return Value:

    PIRP - Returns a pointer to the constructed IRP.

--*/

{
    RXSTATUS status;
    PIRP irp;
    PIO_STACK_LOCATION irpSp;

    PAGED_CODE( );

    irp = IoAllocateIrp( DeviceObject->StackSize, TRUE );
    if ( irp == NULL ) {
        return NULL;
    }

    //
    // Fill in the service independent parameters in the IRP.

    if (ForceSyncApi) {
        irp->Flags = (LONG)IRP_SYNCHRONOUS_API;
    }

    //
    // Put the file object pointer in the stack location.

    irpSp = IoGetNextIrpStackLocation( irp ); //ok4ioget
    irpSp->FileObject = FileObject;           //ok4->FileObj
    irpSp->DeviceObject = DeviceObject;

    {   BOOLEAN EnableCalls = CompletionRoutine!=NULL;

        IoSetCompletionRoutine(irp, CompletionRoutine, Context,
                                EnableCalls,EnableCalls,EnableCalls);
    }

    return irp;

} // BuildCoreOfSyncIoRequest


RXSTATUS
MRxLocalStartIoAndWait (
    IN PRX_CONTEXT RxContext,
    IN PIRP CalldownIrp,
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PULONG pLengthRemaining
    )

/*++

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:

    RxContext - Supplies a pointer operation context.

    CalldownIrp - Supplies a pointer to the I/O request packet.

    DeviceObject - Supplies a pointer to the target device object.

Return Value:

    RXSTATUS - 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.

--*/

{
    RXSTATUS Status;
    RxCaptureRequestPacket;
    PKEVENT Event;
    PMRX_SYNCIO_CONTEXT SyncIoContext = (PMRX_SYNCIO_CONTEXT)&RxContext->LowIoContext;
    BOOLEAN Wait = FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT)!=0;
    ULONG ReturnedInformation;

    PAGED_CODE( );

    RxDbgTrace (+1, Dbg, ("MRxLocalStartIoAndWait   IrpC= %08lx, lengthR=%d\n", RxContext,*pLengthRemaining));
    RxLog(('TSz',0));

    if (Wait) {
        SyncIoContext->SyncEvent = Event = &SyncIoContext->TheActualEvent;;
        KeInitializeEvent( Event, SynchronizationEvent, FALSE );
    } else {
        ASSERT(!"we can't handle an async call to startioandwait.......");
        SyncIoContext->SyncEvent = NULL;
    }

    Status = IoCallDriver( DeviceObject, CalldownIrp );

    if ( Status == RxStatus(PENDING) ) {

        if (Event) {

            KeWaitForSingleObject(Event, UserRequest, KernelMode, FALSE, NULL);
            Status = CalldownIrp->IoStatus.Status;

        } else {
            //store nothing.....get out
            ASSERT(!"we can't handle an async call to startioandwait.......");
            RxDbgTrace (-1, Dbg, ("MRxLocalStartIoAndWait   pending= %08lx\n", Status));
            return Status;
        }
    }

    //
    // from the point of view of the guy above we never pended! so, just store the info....
    ReturnedInformation = CalldownIrp->IoStatus.Information;
    if (pLengthRemaining) {
        RxDbgTrace (0, Dbg, ("MRxLocalStartIoAndWait before   remaining= %08lx, info=%08lx\n",
                         *pLengthRemaining, ReturnedInformation));
        *pLengthRemaining -=  ReturnedInformation;
        RxDbgTrace (0, Dbg, ("MRxLocalStartIoAndWait after   remaining= %08lx, info=%08lx\n",
                         *pLengthRemaining, ReturnedInformation));
    } else {
        capReqPacket->IoStatus.Information =  ReturnedInformation;
    }
    // don't RxContext->StoredStatus = Status;
    IoFreeIrp(CalldownIrp);

    RxDbgTrace (-1, Dbg, ("MRxLocalStartIoAndWait   status= %08lx, info=%08lx\n",
                         Status, ReturnedInformation));
    return Status;

} // StartIoAndWait


RXSTATUS
MRxLocalCalldownSyncIoCompletion (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP CalldownIrp,
    IN PVOID Context
    )

/*++

Routine Description:

    This is the I/O completion routine for calldown ios like querydirectory. the rub is that we
    turned synchronous opens into async opens. what we do here is set an event (in the case of a pended
    packet for a sync that we turned async) OR copyup the status;complete;free in the case of a call
    that was always async.

Arguments:

    DeviceObject - Pointer to target device object for the request.

    CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem

    Context - Irpcontext of the original request to the rdbss

Return Value:

    RXSTATUS - If RxStatus(MORE_PROCESSING_REQUIRED) is returned.


--*/

{
    PRX_CONTEXT RxContext = Context;
    RxCaptureRequestPacket;
    PMRX_SYNCIO_CONTEXT SyncIoContext = (PMRX_SYNCIO_CONTEXT)&RxContext->LowIoContext;

    RxDbgTrace ( 0, Dbg, ("  MRxLocalCalldownSyncIoCompletion           = %08lx\n", 0));

    if (CalldownIrp->PendingReturned){
        if (SyncIoContext->SyncEvent){
            KeSetEvent( SyncIoContext->SyncEvent, 0, FALSE );
        } else {

            // there's no one waiting.....obviously this was a async from the start so
            // we just complete the packet from here......

            capReqPacket->IoStatus = CalldownIrp->IoStatus;
            RxContext->StoredStatus = CalldownIrp->IoStatus.Status;
            RxCompleteRequest(RxContext,
                              RxContext->StoredStatus); //joejoe this is anomolous
            IoFreeIrp(CalldownIrp);
        }
    }

    return(RxStatus(MORE_PROCESSING_REQUIRED));
}


RXSTATUS
MRxLocalQueryDirectory (
    IN OUT PRX_CONTEXT            RxContext,
    IN     FILE_INFORMATION_CLASS FileInformationClass,
    IN OUT PVOID                  Buffer,
    IN OUT PULONG                 pLengthRemaining
    )

/*++

Routine Description:

    This routine just reroutes the query to the local guy.  It is responsible
    for either completing of enqueuing the input Irp. i can't handle assync yet.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    RXSTATUS - The return status for the operation

--*/

{
    RXSTATUS Status;
    RxCaptureRequestPacket;
    RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
    PMRX_SYNCIO_CONTEXT SyncIoContext = (PMRX_SYNCIO_CONTEXT)&RxContext->LowIoContext;

    PSRV_OPEN SrvOpen = capFobx->SrvOpen;
    PMRX_LOCAL_SRV_OPEN localSrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
    BOOLEAN Wait = BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT);

    PIRP CalldownIrp;
    PIO_STACK_LOCATION CalldownIrpSp;
    PDEVICE_OBJECT UnderlyingDeviceObject = localSrvOpen->UnderlyingDeviceObject;
    PFILE_OBJECT UnderlyingFileObject = localSrvOpen->UnderlyingFileObject;

    PAGED_CODE( );

    RxDbgTrace(+1, Dbg, ("MRxQueryDirectory...\n", 0));
    RxLog(('DQz',0));
    ASSERT(sizeof(MRX_SYNCIO_CONTEXT) <= sizeof(LOWIO_CONTEXT));
    ASSERT (localSrvOpen->UnderlyingFileObject);

    //
    // Allocate an IRP and fill in the service-independent parameters
    // for the request.
    //

    CalldownIrp = MRxLocalBuildCoreOfSyncIoRequest (
                   UnderlyingFileObject ,//IN PFILE_OBJECT FileObject,
                   Wait ,//IN BOOLEAN ForceSyncApi,
                   UnderlyingDeviceObject ,//IN PDEVICE_OBJECT DeviceObject,
                   MRxLocalCalldownSyncIoCompletion ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
                   RxContext  //IN PVOID Context
              );

    if ( CalldownIrp == NULL ) {

        return RxStatus(INSUFFICIENT_RESOURCES);

    }

    //
    // Fill in the service-dependent parameters for the request.
    //

    CalldownIrpSp = IoGetNextIrpStackLocation( CalldownIrp );
    CalldownIrpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
    CalldownIrpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
    CalldownIrpSp->Parameters.QueryDirectory = capPARAMS->Parameters.QueryDirectory;
    ASSERT (
           (CalldownIrpSp->Parameters.QueryDirectory.FileInformationClass == FileInformationClass)
        && (CalldownIrpSp->Parameters.QueryDirectory.Length == *pLengthRemaining)
    );
    CalldownIrpSp->Flags = capPARAMS->Flags;

    //
    // Determine whether the driver wants buffered, direct, or "neither" I/O.
    // we only support neither.

    ASSERT ( (UnderlyingDeviceObject->Flags & ( DO_BUFFERED_IO | DO_DIRECT_IO)) == 0 );

    CalldownIrp->UserBuffer = Buffer;

//    RxDbgTrace( 0, Dbg, (" ->UserBufLength   = %08lx\n", CalldownIrpSp->Parameters.QueryDirectory.Length));
//    RxDbgTrace( 0, Dbg, (" ->FileName = %08lx\n", CalldownIrpSp->Parameters.QueryDirectory.FileName));
//    IF_DEBUG {
//        if (CalldownIrpSp->Parameters.QueryDirectory.FileName) {
//            RxDbgTrace( 0, Dbg, (" ->     %wZ\n", CalldownIrpSp->Parameters.QueryDirectory.FileName ));
//    }}
//    RxDbgTrace( 0, Dbg, (" ->FileInformationClass = %08lx\n", CalldownIrpSp->Parameters.QueryDirectory.FileInformationClass));
//    RxDbgTrace( 0, Dbg, (" ->FileIndex       = %08lx\n", CalldownIrpSp->Parameters.QueryDirectory.FileIndex));
//    RxDbgTrace( 0, Dbg, (" ->UserBuffer      = %08lx\n", CalldownIrp->UserBuffer));
//    RxDbgTrace( 0, Dbg, (" ->RestartScan     = %08lx\n", FlagOn( CalldownIrpSp->Flags, SL_RESTART_SCAN )));
//    RxDbgTrace( 0, Dbg, (" ->ReturnSingleEntry = %08lx\n", FlagOn( CalldownIrpSp->Flags, SL_RETURN_SINGLE_ENTRY )));
//    RxDbgTrace( 0, Dbg, (" ->IndexSpecified  = %08lx\n", FlagOn( CalldownIrpSp->Flags, SL_INDEX_SPECIFIED )));

    //
    // Start the I/O, wait for it to complete, and return the final status.
    //

    Status = MRxLocalStartIoAndWait( RxContext, CalldownIrp, UnderlyingDeviceObject, pLengthRemaining );
    RxDbgTrace(-1, Dbg, ("MRxQueryDirectory status=%08lx\n", Status));
    //DbgBreakPoint();
    return Status;

} // MRxLocalQueryDirectory

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


//
//  The local debug trace level
//

#undef Dbg
#define Dbg                              (DEBUG_TRACE_FILEINFO)


//
//  Internal support routine
//

RXSTATUS
MRxLocalQueryFileInformation (
    IN PRX_CONTEXT RxContext,
    IN FILE_INFORMATION_CLASS FileInformationClass,
    IN OUT PVOID Buffer,
    IN OUT PULONG pLengthRemaining
    )

/*++

Routine Description:

    This routine implements the query file info call

Arguments:

Return Value:

    RXSTATUS - Returns the status for the query

--*/

{
    RXSTATUS Status;
    RxCaptureRequestPacket;
    RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
    PSRV_OPEN SrvOpen = capFobx->SrvOpen;
    PFILE_OBJECT UnderlyingFileObject = ((PMRX_LOCAL_SRV_OPEN)(SrvOpen))->UnderlyingFileObject;

    ULONG ReturnedLength = 0;

    RxDbgTrace(+1, Dbg, ("MRxLocalQueryFileInfo...\n", 0));
    RxLog(('FQz',0));

    if ( !FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT )  ){
        RxContext->PostRequest = TRUE;
        RxDbgTrace(-1, Dbg, ("MRxLocalQueryFileInfo...PENDING\n", 0));
        return(RxStatus(PENDING));
    }

    RxDbgTrace( 0, Dbg, (" ---->UserBuffer/remLength/Class = %08lx/%08lx/%08lx\n",
                             Buffer, *pLengthRemaining, FileInformationClass));
    ASSERT (UnderlyingFileObject);

    Status = IoQueryFileInformation(
                UnderlyingFileObject, //IN PFILE_OBJECT FileObject,
                FileInformationClass, //IN FILE_INFORMATION_CLASS FileInformationClass,
                *pLengthRemaining,               //IN ULONG Length,
                Buffer,               //OUT PVOID FileInformation,
                &ReturnedLength       //OUT PULONG ReturnedLength
                );


    *pLengthRemaining -= ReturnedLength;
    RxDbgTrace(-1, Dbg, (" ---->Status/remLen/retLen = %08lx\n",
                                      Status, *pLengthRemaining, ReturnedLength));
    return(Status);
}

RXSTATUS
MRxLocalSetFileInfoAtCleanup (
    IN PRX_CONTEXT RxContext,
    IN FILE_INFORMATION_CLASS FileInformationClass,
    IN OUT PVOID Buffer,
    IN ULONG Length
    )
/*++

Routine Description:

    This routine implements the set file info call called on cleanup or flush. We dont actually set the times but we do set
    the endoffile info.

Arguments:

Return Value:

    RXSTATUS - Returns the status for the set

--*/

{
    RXSTATUS Status;
    RxCaptureRequestPacket;
    RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
    PSRV_OPEN SrvOpen = capFobx->SrvOpen;
    PFILE_OBJECT UnderlyingFileObject = ((PMRX_LOCAL_SRV_OPEN)(SrvOpen))->UnderlyingFileObject;

    if (FileInformationClass == FileBasicInformation) {
        return(RxStatus(SUCCESS));
    }
    RxDbgTrace(+1, Dbg, ("MRxLocalSetFileInfoAtCleanup...\n", 0));
    RxLog(('GSz',0));
    return MRxLocalSetFileInformation(RxContext,FileInformationClass,Buffer,Length);
}



RXSTATUS
MRxLocalSetFileInformation (
    IN PRX_CONTEXT RxContext,
    IN FILE_INFORMATION_CLASS FileInformationClass,
    IN OUT PVOID Buffer,
    IN ULONG Length
    )

/*++

Routine Description:

    This routine implements the set file info call. we do not take the opportunity to set
    allocationsize correctly on a setfilesize calldown.

Arguments:

Return Value:

    RXSTATUS - Returns the status for the set

--*/

{
    RXSTATUS Status;
    RxCaptureRequestPacket;
    RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
    PSRV_OPEN SrvOpen = capFobx->SrvOpen;
    PFILE_OBJECT UnderlyingFileObject = ((PMRX_LOCAL_SRV_OPEN)(SrvOpen))->UnderlyingFileObject;

    RxDbgTrace(+1, Dbg, ("MRxLocalSetFileInfo...\n", 0));
    RxLog(('FSz',0));

    if(Length==0){
        //zero length means that this is the special calldown from the cachemanager...for now just boost
        //joejoe this should be fixed soon
        Length = sizeof(FILE_END_OF_FILE_INFORMATION);
    }

    RxDbgTrace( 0, Dbg, (" ---->UserBuffer           = %08lx\n", Buffer));
    ASSERT (UnderlyingFileObject);

    //this could be a setfileinfo that comes in from the lazywriter
    //after the underlying file has already been cleaned up
    if (UnderlyingFileObject == NULL) {
        Status = RxStatus(FILE_CLOSED);
        RxDbgTrace(-1, Dbg, (" ---->AlreadyClosed!!! Status = %08lx\n", Status));
        return(Status);
    }

    Status = IoSetInformation(
                UnderlyingFileObject,  //IN PFILE_OBJECT FileObject,
                FileInformationClass,  //IN FILE_INFORMATION_CLASS FileInformationClass,
                Length,                //IN ULONG Length,
                Buffer                 //IN PVOID FileInformation
                );

    RxDbgTrace(-1, Dbg, (" ---->Status = %08lx\n", Status));

    return(Status);
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

//
//  The local debug trace level
//

#undef Dbg
#define Dbg                              (DEBUG_TRACE_VOLINFO)


RXSTATUS
MRxLocalQueryVolumeInformation (
    IN OUT PRX_CONTEXT RxContext,
    IN     FS_INFORMATION_CLASS FsInformationClass,
    IN OUT PVOID Buffer,
    IN OUT PULONG pLengthRemaining
    )

/*++

Routine Description:

    This routine just reroutes the query to the local guy.  It is responsible
    for either completing of enqueuing the input Irp. i can't handle assync yet.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    RXSTATUS - The return status for the operation

--*/

{
    RXSTATUS Status;
    RxCaptureRequestPacket;
    RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
    PMRX_SYNCIO_CONTEXT SyncIoContext = (PMRX_SYNCIO_CONTEXT)&RxContext->LowIoContext;

    PSRV_OPEN SrvOpen = capFobx->SrvOpen;
    PMRX_LOCAL_SRV_OPEN localSrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
    BOOLEAN Wait = BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT);

    PIRP CalldownIrp;
    PIO_STACK_LOCATION CalldownIrpSp;
    PDEVICE_OBJECT UnderlyingDeviceObject = localSrvOpen->UnderlyingDeviceObject;
    PFILE_OBJECT UnderlyingFileObject = localSrvOpen->UnderlyingFileObject;

    PAGED_CODE( );

    RxDbgTrace(+1, Dbg, ("MRxQueryVolumeInfo...\n", 0));
    RxLog(('VQz',0));
    ASSERT(sizeof(MRX_SYNCIO_CONTEXT) <= sizeof(LOWIO_CONTEXT));
    ASSERT (localSrvOpen->UnderlyingFileObject);

    //
    // Allocate an IRP and fill in the service-independent parameters
    // for the request.
    //

    CalldownIrp = MRxLocalBuildCoreOfSyncIoRequest (
                   UnderlyingFileObject ,//IN PFILE_OBJECT FileObject,
                   Wait ,//IN BOOLEAN ForceSyncApi,
                   UnderlyingDeviceObject ,//IN PDEVICE_OBJECT DeviceObject,
                   MRxLocalCalldownSyncIoCompletion ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
                   RxContext  //IN PVOID Context
              );

    if ( CalldownIrp == NULL ) {

        return RxStatus(INSUFFICIENT_RESOURCES);

    }

    //
    // Fill in the service-dependent parameters for the request.
    //

    CalldownIrpSp = IoGetNextIrpStackLocation( CalldownIrp );
    CalldownIrpSp->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
    //CalldownIrpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
    CalldownIrpSp->Parameters.QueryVolume = capPARAMS->Parameters.QueryVolume;
    ASSERT (
           (CalldownIrpSp->Parameters.QueryVolume.FsInformationClass == FsInformationClass)
        && (CalldownIrpSp->Parameters.QueryVolume.Length == *pLengthRemaining)
    );
    CalldownIrpSp->Flags = capPARAMS->Flags;

    //
    // Determine whether the driver wants buffered, direct, or "neither" I/O.
    // we only support neither.

    ASSERT ( (UnderlyingDeviceObject->Flags & ( DO_BUFFERED_IO | DO_DIRECT_IO)) == 0 );

    //CalldownIrp->UserBuffer = NULL;
    CalldownIrp->AssociatedIrp.SystemBuffer = Buffer;

    //
    // Start the I/O, wait for it to complete, and return the final status.
    //

    Status = MRxLocalStartIoAndWait( RxContext, CalldownIrp, UnderlyingDeviceObject, pLengthRemaining );
    RxDbgTrace(-1, Dbg, ("MRxQueryVolumeInfo status=%08lx\n", Status));
    //DbgBreakPoint();
    return Status;

} // MRxLocalQueryVolumeInformation



//
//  The local debug trace level
//

#undef Dbg
#define Dbg                              (DEBUG_TRACE_FLUSH)


RXSTATUS
MRxLocalFlush (
    IN PRX_CONTEXT RxContext
    )

/*++

Routine Description:

    This routine just reroutes the query to the local guy.  It is responsible
    for either completing of enqueuing the input Irp. we're already sync by the time we get here.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    RXSTATUS - The return status for the operation

--*/

{
    RXSTATUS Status;
    RxCaptureRequestPacket;
    RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
    PMRX_SYNCIO_CONTEXT SyncIoContext = (PMRX_SYNCIO_CONTEXT)&RxContext->LowIoContext;

    PSRV_OPEN SrvOpen = capFobx->SrvOpen;
    PMRX_LOCAL_SRV_OPEN localSrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
    BOOLEAN Wait = BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT);

    PIRP CalldownIrp;
    PIO_STACK_LOCATION CalldownIrpSp;
    PDEVICE_OBJECT UnderlyingDeviceObject = localSrvOpen->UnderlyingDeviceObject;
    PFILE_OBJECT UnderlyingFileObject = localSrvOpen->UnderlyingFileObject;

    PAGED_CODE( );

    RxDbgTrace(+1, Dbg, ("MRxFlush...\n", 0));
    RxLog(('FFz',0));
    ASSERT(sizeof(MRX_SYNCIO_CONTEXT) <= sizeof(LOWIO_CONTEXT));
    ASSERT (localSrvOpen->UnderlyingFileObject);

    //
    // Allocate an IRP and fill in the service-independent parameters
    // for the request.
    //

    CalldownIrp = MRxLocalBuildCoreOfSyncIoRequest (
                   UnderlyingFileObject ,//IN PFILE_OBJECT FileObject,
                   Wait ,//IN BOOLEAN ForceSyncApi,
                   UnderlyingDeviceObject ,//IN PDEVICE_OBJECT DeviceObject,
                   MRxLocalCalldownSyncIoCompletion ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
                   RxContext  //IN PVOID Context
              );

    if ( CalldownIrp == NULL ) {

        return RxStatus(INSUFFICIENT_RESOURCES);

    }

    //
    // Fill in the service-dependent parameters for the request.
    //

    CalldownIrpSp = IoGetNextIrpStackLocation( CalldownIrp );
    CalldownIrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;


    //
    // Start the I/O, wait for it to complete, and return the final status.
    //

    Status = MRxLocalStartIoAndWait( RxContext, CalldownIrp, UnderlyingDeviceObject,NULL );
    RxDbgTrace(-1, Dbg, ("MRxFlush status=%08lx\n", Status));
    //DbgBreakPoint();
    return Status;

} // MRxLocalFlush


