/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    querydir.c

Abstract:

    This module implements the mini redirector call down routines pertaining to query directory.

Author:

    joelinn      [joelinn]      01-02-97

Revision History:

--*/

#include "precomp.h"
#pragma hdrstop

//
//  The local debug trace level
//

#define Dbg                              (DEBUG_TRACE_DIRCTRL)

//
// External declartions
//
NTSTATUS
MRxProxyQueryDirOrFlushContinuation(
    MRXPROXY_ASYNCENGINE_ARGUMENT_SIGNATURE
      );


RXDT_DefineCategory(DIRCTRL);
#define Dbg        (DEBUG_TRACE_DIRCTRL)

ULONG MRxProxyStopOnLoudCompletion = TRUE;
NTSTATUS
MRxProxyQueryDirectory(
    IN PRX_CONTEXT RxContext
    )
/*++

Routine Description:

   This routine handles network querydir requests.

Arguments:

    RxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb; RxCaptureFobx;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxProxyQueryDir %08lx\n", RxContext ));
    ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );

    MRxProxySetLoud("QueryDir ",RxContext,&(capFobx->UnicodeQueryTemplate));

    Status = MRxProxyAsyncEngineOuterWrapper(
                 RxContext,
                 MRXPROXY_ASYNCENG_CTX_FROM_QUERYDIR,
                 MRxProxyQueryDirOrFlushContinuation,
                 "MRxProxyQueryDir",
                 TRUE, //loudprocessing
                 (BOOLEAN)MRxProxyStopOnLoudCompletion
                 );

    RxDbgTrace(-1, Dbg, ("MRxProxyQueryDir %08lx exit with status=%08lx\n", RxContext, Status ));
    return(Status);

} // MRxProxyQueryDir

NTSTATUS
MRxProxyFlush(
    IN PRX_CONTEXT RxContext
    )
/*++

Routine Description:

   This routine handles flush requests.

Arguments:

    RxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb; RxCaptureFobx;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxProxyFlush %08lx\n", RxContext ));
    ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );

    //MRxProxySetLoud("QueryDir ",RxContext,&(capFobx->UnicodeQueryTemplate));

    Status = MRxProxyAsyncEngineOuterWrapper(
                 RxContext,
                 MRXPROXY_ASYNCENG_CTX_FROM_FLUSH,
                 MRxProxyQueryDirOrFlushContinuation,
                 "MRxProxyFlush",
                 TRUE, //loudprocessing
                 (BOOLEAN)MRxProxyStopOnLoudCompletion
                 );

    RxDbgTrace(-1, Dbg, ("MRxProxyFlush %08lx exit with status=%08lx\n", RxContext, Status ));
    return(Status);

} // MRxProxyFlush




NTSTATUS
MRxProxyQueryDirOrFlushContinuation(
    MRXPROXY_ASYNCENGINE_ARGUMENT_SIGNATURE
      )
/*++

Routine Description:

    This is the start routine for query directiry.

Arguments:


Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status; //this is initialized to proxybufstatus on a reenter
    PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
    ULONG ContinueEntryCount;

    RxCaptureFcb; RxCaptureFobx;
    PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
    BOOLEAN  SynchronousIo =
               !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxProxyQueryDirOrFlushContinuation\n", 0 ));

    ASSERT_ASYNCENG_CONTEXT(AsyncEngineContext);

    AsyncEngineContext->ContinueEntryCount++;
    ContinueEntryCount = AsyncEngineContext->ContinueEntryCount;

    IF_DEBUG {
        if (AsyncEngineContext->EntryPoint == MRXPROXY_ASYNCENG_CTX_FROM_QUERYDIR) {
            if (RxContext->LoudCompletionString) {
                PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(capFobx->pSrvOpen);
                ULONG t = InterlockedIncrement(&proxySrvOpen->NumberOfQueryDirectories);
                ASSERT(t==1);
            }
        }
    }

    for (;;) {

        //
        // Case on the current state
        //

        switch (AsyncEngineContext->OpSpecificState) {

        case MRxProxyAsyncEngOEInnerIoStates_Initial:
            AsyncEngineContext->OpSpecificState = MRxProxyAsyncEngOEInnerIoStates_ReadyToSend;

            //
            // If not a synchronous querydir, then continue here when resumed
            //
            //CODE.IMPROVEMENT  why don't we just use the flag in the rxcontext??
            if (!SynchronousIo) {
                SetFlag(AsyncEngineContext->Flags,MRXPROXY_ASYNCENG_CTX_FLAG_ASYNC_OPERATION);
            }
            ASSERT( AsyncEngineContext->Continuation == MRxProxyQueryDirOrFlushContinuation);

            //lack of break is intentional

        case MRxProxyAsyncEngOEInnerIoStates_ReadyToSend:
            AsyncEngineContext->OpSpecificState = MRxProxyAsyncEngOEInnerIoStates_OperationOutstanding;

            Status = MRxProxyBuildAsynchronousRequest(
                         RxContext,                                // IN PVOID Context
                         MRxProxyAsyncEngineCalldownIrpCompletion  // IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
                        );

            if (Status != STATUS_SUCCESS) {
                goto FINALLY;
            }

            Status = MRxProxySubmitAsyncEngRequest(
                         MRXPROXY_ASYNCENGINE_ARGUMENTS,
                         (AsyncEngineContext->EntryPoint == MRXPROXY_ASYNCENG_CTX_FROM_QUERYDIR)
                             ?MRXPROXY_ASYNCENG_AECTXTYPE_QUERYDIR
                             :MRXPROXY_ASYNCENG_AECTXTYPE_FLUSH
                         );

            //
            // If the status is PENDING, then we're done for now. We must
            // wait until we're re-entered when the receive happens.
            //

            if (Status==(STATUS_PENDING)) {
                ASSERT(FALSE); //shouldn't be coming thru here now........
                ASSERT(!SynchronousIo);
                goto FINALLY;
            }

            if ((Status!=STATUS_SUCCESS) && (RxContext->LoudCompletionString)) {
                DbgPrint("LoudFailure %08lx on %wZ\n",Status,RxContext->LoudCompletionString);
                if (MRxProxyStopOnLoudCompletion) {
                    DbgBreakPoint();
                }
            }
            AsyncEngineContext->Status = Status;
            //lack of break is intentional

        case MRxProxyAsyncEngOEInnerIoStates_OperationOutstanding:
            AsyncEngineContext->OpSpecificState = MRxProxyAsyncEngOEInnerIoStates_ReadyToSend;
            Status = AsyncEngineContext->Status;
            //RxContext->InformationToReturn += AsyncEngineContext->Information;
            if (!NT_ERROR(Status)) {
                RxContext->Info.LengthRemaining -= AsyncEngineContext->CalldownIrp->IoStatus.Information;
            }
            goto FINALLY;

            break;
        }
    }

FINALLY:
    //CODE.IMPROVEMENT QueryDirOrFlush_start and write_start and locks_start should be combined.....we use this
    //macro until then to keep the async stuff identical
    if ( Status != (STATUS_PENDING) ) {
        MRxProxyAsyncEngAsyncCompletionIfNecessary(AsyncEngineContext,RxContext);
    }

    RxDbgTrace(-1, Dbg, ("MRxProxyQueryDirOrFlushContinuation exit w %08lx\n", Status ));
    return Status;
}

