/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    openclos.c

Abstract:

    This module implements the mini redirector call down routines pertaining to opening/
    closing of file/directories.

Author:

    Balan Sethu Raman      [SethuR]      7-March-1995

Revision History:

--*/

#include "precomp.h"
#pragma hdrstop

////
////  The Bug check file id for this module
////
//
//#define BugCheckFileId                   (RDBSS_BUG_CHECK_LOCAL_CREATE)

//
//  The debug trace level
//

#define Dbg                              (DEBUG_TRACE_CREATE)

#ifdef RX_PRIVATE_BUILD
ULONG MRxProxyDbgPrintF = 1; //0; //1;
#endif //ifdef RX_PRIVATE_BUILD

#ifdef RX_PRIVATE_BUILD
#undef IoGetTopLevelIrp
#undef IoSetTopLevelIrp
#endif //ifdef RX_PRIVATE_BUILD

NTSTATUS
MRxProxySyncIrpCompletionRoutine (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP CalldownIrp,
    IN PVOID Context
    )
/*++

Routine Description:

    This routine is called when the calldownirp is completed.

Arguments:

    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP CalldownIrp,
    IN PVOID Context

Return Value:

    RXSTATUS - STATUS_MORE_PROCESSING_REQUIRED

--*/
{
    PRX_CONTEXT RxContext = (PRX_CONTEXT)Context;
    PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext);

    if (CalldownIrp->PendingReturned){
        //pMRxProxyContext->SyncCallDownIoStatus = CalldownIrp->IoStatus;
        RxSignalSynchronousWaiter(RxContext);
    }
    return(STATUS_MORE_PROCESSING_REQUIRED);
}


//not on the stack...just in case
ULONG DummyReturnedLengthForXxxInfo;

NTSTATUS
MRxProxySyncXxxInformation(
    IN OUT PRX_CONTEXT RxContext,
    IN UCHAR MajorFunction,
    IN PFILE_OBJECT FileObject,
    IN ULONG InformationClass,
    IN ULONG Length,
    OUT PVOID Information,
    OUT PULONG ReturnedLength OPTIONAL
    )

/*++

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:

    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;

    //ULONG SetFileInfoInfo;

    PAGED_CODE();

    if (ReturnedLength==NULL) {
        ReturnedLength = &DummyReturnedLengthForXxxInfo;
    }


    ASSERT (FileObject);
    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    ASSERT (DeviceObject);

    //
    // 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 = MajorFunction;
    irpSp->FileObject = FileObject;
    IoSetCompletionRoutine(irp,
                           MRxProxySyncIrpCompletionRoutine,
                           RxContext,
                           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) {
            //IF_LOUD_DOWNCALLS(MiniFileObject) {
            //    SetFileInfoInfo =  ((PFILE_END_OF_FILE_INFORMATION)Information)->EndOfFile.LowPart;
            //}
        }

        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(&irpSp->Parameters.QueryFile.FileInformationClass
                                          == &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( &RxContext->SyncEvent,
                       NotificationEvent,
                       FALSE );

    //LoudCallsDbgPrint("Ready to",
    //                        MiniFileObject,
    //                        irpSp->MajorFunction,
    //                        irpSp->Parameters.QueryFile.FileInformationClass,
    //                        irpSp->Parameters.QueryFile.Length,
    //                        SetFileInfoInfo,0,0
    //                        );

    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
    }


    //RxDbgTrace (0, Dbg, ("  -->Status after iocalldriver %08lx(%08lx)\n",RxContext,Status));

    if (Status == (STATUS_PENDING)) {
        RxWaitSync(RxContext);
        Status = irp->IoStatus.Status;
    }

    //LoudCallsDbgPrint("Back from",
    //                        MiniFileObject,
    //                        irpSp->MajorFunction,
    //                        irpSp->Parameters.QueryFile.FileInformationClass,
    //                        irpSp->Parameters.QueryFile.Length,
    //                        SetFileInfoInfo,
    //                        Status,irp->IoStatus.Information
    //                        );

    if (Status==STATUS_SUCCESS) {
        *ReturnedLength = irp->IoStatus.Information;
        RxDbgTrace( 0, Dbg, ("MRxProxySyncXxxInformation(%x)Info<%x> %x bytes@%x returns %08lx/%08lx\n",
                    RxContext,MajorFunction,
                    Status,*ReturnedLength));
    }

    IoFreeIrp(irp);
    return(Status);

}

NTSTATUS
MRxProxyShouldTryToCollapseThisOpen (
    IN PRX_CONTEXT RxContext
    )
/*++

Routine Description:

   This routine determines if the mini knows of a good reason not
   to try collapsing on this open. Presently, the only reason would
   be if this were a copychunk open.

Arguments:

    RxContext - the RDBSS context

Return Value:

    NTSTATUS - The return status for the operation
        SUCCESS --> okay to try collapse
        other (MORE_PROCESSING_REQUIRED) --> dont collapse

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;

    PAGED_CODE();

    return Status;
}


VOID
MRxProxyMungeBufferingIfWriteOnlyHandles (
    ULONG WriteOnlySrvOpenCount,
    PMRX_SRV_OPEN SrvOpen
    )
/*++

Routine Description:

   This routine modifies the buffering flags on a srvopen so that
   no cacheing will be allowed if there are any write-only handles
   to the file.  CODE.IMPROVEMENT this should be inlined.

Arguments:

    WriteOnlySrvOpenCount - the number of writeonly srvopens
    SrvOpen - the srvopen whose buffring flags are to be munged

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    BOOLEAN IsLoopBack = FALSE;
    PMRX_SRV_CALL pSrvCall;
    //PSMBCEDB_SERVER_ENTRY pServerEntry;

    pSrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;

#if 0
    pServerEntry = SmbCeReferenceAssociatedServerEntry(pSrvCall);
    ASSERT(pServerEntry != NULL);
    IsLoopBack = pServerEntry->Server.IsLoopBack;
    SmbCeDereferenceServerEntry(pServerEntry);
#endif

    if (!IsLoopBack && (WriteOnlySrvOpenCount==0)) {
        return;
    }
    SrvOpen->BufferingFlags &=
       ~( FCB_STATE_WRITECACHEING_ENABLED  |
          FCB_STATE_FILESIZECACHEING_ENABLED |
          FCB_STATE_FILETIMECACHEING_ENABLED |
          FCB_STATE_LOCK_BUFFERING_ENABLED |
          FCB_STATE_READCACHEING_ENABLED |
          FCB_STATE_COLLAPSING_ENABLED
        );
}

ULONG MRxProxyLoudStringTableSize = 0;
UNICODE_STRING MRxProxyLoudStrings[50];

VOID
MRxProxySetLoud(
    IN PBYTE Msg,
    IN PRX_CONTEXT RxContext,
    IN PUNICODE_STRING s
    )
{
    ULONG i;
    UNICODE_STRING temp;
    for (i=0;i<MRxProxyLoudStringTableSize;i++) {
        PUNICODE_STRING t = &(MRxProxyLoudStrings[i]);
        ((PBYTE)temp.Buffer) = ((PBYTE)s->Buffer) + s->Length - t->Length;
        temp.Length = t->Length;
        //DbgPrint("%s %lx Comparing %wZ with %wZ from %wZ\n",Msg,t->Length,&temp,t,s);
        if (RtlEqualUnicodeString(&temp,t,TRUE)) {
            DbgPrint("%s Found %wZ from %wZ\n",Msg,t,s);
            RxContext->LoudCompletionString = t;
            break;
        }
    }
}

VOID
MRxProxyInitializeLoudStrings(
    void
    )
{
    RtlInitUnicodeString(&MRxProxyLoudStrings[0],L"xsync.exe");
    //RtlInitUnicodeString(&MRxProxyLoudStrings[1],L"calc.exe");
    //RtlInitUnicodeString(&MRxProxyLoudStrings[2],L"ecco.exe");
    MRxProxyLoudStringTableSize = 1;
}



#define MustBeDirectory(co) ((co) & FILE_DIRECTORY_FILE)
#define MustBeFile(co)      ((co) & FILE_NON_DIRECTORY_FILE)

// define structures for posting of open and close calls so that they end up in the
// system process.

typedef
NTSTATUS
(*PMRX_PROXY_POSTABLE_OPERATION) (
    IN OUT PRX_CONTEXT RxContext
    );

#if 0
typedef struct _MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT_LOWER {
    PRX_CONTEXT RxContext;
    union {
        NTSTATUS PostReturnStatus;
        RX_WORK_QUEUE_ITEM  WorkQueueItem;
    };
    KEVENT PostEvent;
} MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT_LOWER;

typedef struct _MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT {
    union {
        MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT_LOWER;
        MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT_LOWER PostedOpContext;
    };
} MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT, *PMRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT;;

typedef struct _MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT {
    MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT;
} MRX_PROXY_POSTED_CREATE_CONTEXT, *PMRX_PROXY_POSTED_CREATE_CONTEXT;

typedef struct _MRX_PROXY_POSTED_CLOSE_CONTEXT {
    MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT;
} MRX_PROXY_POSTED_CLOSE_CONTEXT, *PMRX_PROXY_POSTED_CLOSE_CONTEXT;
#endif


NTSTATUS
MRxProxyPostOperation (
    IN OUT PRX_CONTEXT RxContext,
    IN OUT PVOID PostedOpContext,
    IN     PMRX_PROXY_POSTABLE_OPERATION Operation
    )
{
    NTSTATUS Status,PostStatus;
    PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext);

    KeInitializeEvent( &RxContext->SyncEvent,
                       NotificationEvent,
                       FALSE );
    pMRxProxyContext->PostedOpContext = PostedOpContext;

    IF_DEBUG {
        //fill the workqueue structure with deadbeef....all the better to diagnose
        //a failed post
        ULONG i;
        for (i=0;i+sizeof(ULONG)-1<sizeof(RxContext->WorkQueueItem);i+=sizeof(ULONG)) {
            PBYTE BytePtr = ((PBYTE)&RxContext->WorkQueueItem)+i;
            PULONG UlongPtr = (PULONG)BytePtr;
            *UlongPtr = 0xdeadbeef;
        }
    }

    PostStatus = RxPostToWorkerThread(
                     &MRxProxyDeviceObject->RxDeviceObject,
                     DelayedWorkQueue,
                     &RxContext->WorkQueueItem,
                     Operation,
                     RxContext);

    ASSERT(PostStatus == STATUS_SUCCESS);

    RxWaitSync(RxContext);
    Status = pMRxProxyContext->PostedOpStatus;
    return(Status);
}

NTSTATUS
MRxProxyPostedCreate (
    IN OUT PRX_CONTEXT RxContext
    )
/*++

Routine Description:

   This routine opens a file across the network

Arguments:

    RxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status;
    PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext);

    RxCaptureFcb;
    PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb);

    PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen;
    PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen);
    PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
    PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
    PUNICODE_STRING RemainingName = &(capFcb->AlreadyPrefixedName);

    PNT_CREATE_PARAMETERS CreateParameters = &RxContext->Create.NtCreateParameters;
    ULONG Disposition = CreateParameters->Disposition;
    ACCESS_MASK DesiredAccess = CreateParameters->DesiredAccess  & 0x1FF;

    OBJECT_ATTRIBUTES ObjectAttributes;
    IO_STATUS_BLOCK IoStatusBlock;
    HANDLE handle;
    ULONG FilteredCreateOptions;

    PAGED_CODE();
    RxDbgTrace(+1, Dbg, ("MRxProxyPostedCreate %08lx\n", RxContext ));

    ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );

    RxDbgTrace( 0, Dbg, ("     Attempt to open %wZ\n", &(capFcb->AlreadyPrefixedName) ));

    MRxProxySetLoud("Create ",RxContext,&(capFcb->AlreadyPrefixedName));

#if 0
    // we cannot have a file cached on a write only handle. so we have to behave a little
    // differently if this is a write-only open. remember this in the proxysrvopen

    if (  ((DesiredAccess & (FILE_EXECUTE  | FILE_READ_DATA)) == 0) &&
          ((DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0)
       ) {

        //SetFlag(proxySrvOpen->Flags,PROXY_SRVOPEN_FLAG_WRITE_ONLY_HANDLE);
        //SrvOpen->Flags |= SRVOPEN_FLAG_DONTUSE_WRITE_CACHEING;
        DesiredAccess |= FILE_READ_DATA;
    }
#endif
    // we cannot have a file cached on a write only handle. so if write_data is
    // specified then so is read data

    if (  ((DesiredAccess & (FILE_EXECUTE  | FILE_READ_DATA)) == 0) &&
          ((DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0)
       ) {

        //SetFlag(proxySrvOpen->Flags,PROXY_SRVOPEN_FLAG_WRITE_ONLY_HANDLE);
        //SrvOpen->Flags |= SRVOPEN_FLAG_DONTUSE_WRITE_CACHEING;
        DesiredAccess |= FILE_READ_DATA;
    }

    if ( ( DesiredAccess
                      &~ (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE) )
                  == 0 ){
        SetFlag(SrvOpen->Flags,SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE);
    }

    InitializeObjectAttributes(
        &ObjectAttributes,
        RemainingName,
        OBJ_CASE_INSENSITIVE,  // !!! can we do this? probably need a flag BUGBUG
        0,
        NULL                   // !!! Security     BUGBUG
        );

    FilteredCreateOptions = CreateParameters->CreateOptions;
    if (!MustBeDirectory(FilteredCreateOptions)) {
        FilteredCreateOptions &= ~(FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT); //always async
    }
    FilteredCreateOptions |= FILE_NO_INTERMEDIATE_BUFFERING;
    RxDbgTrace( 0, Dbg, (" ---->FilteredCreateOptions           = %08lx\n", FilteredCreateOptions));
    RxLog(("-->FilteredOptions/oc %lx %lx",FilteredCreateOptions,capFcb->OpenCount));

    Status = IoCreateFile(
                 &handle,
                 DesiredAccess,
                 &ObjectAttributes,
                 &IoStatusBlock,
                 &CreateParameters->AllocationSize,
                 CreateParameters->FileAttributes,
                 CreateParameters->ShareAccess,
                 CreateParameters->Disposition,
                 FilteredCreateOptions,
                 RxContext->Create.EaBuffer,
                 RxContext->Create.EaLength,
                 CreateFileTypeNone,
                 NULL,               // extra parameters
                 IO_NO_PARAMETER_CHECKING
                 );

    if (NT_SUCCESS(Status)) {
        Status = ObReferenceObjectByHandle( handle,
                                            0L,
                                            NULL,
                                            KernelMode,
                                            (PVOID *) &proxySrvOpen->UnderlyingFileObject,
                                            NULL );
        if (Status == STATUS_SUCCESS) {
            proxySrvOpen->UnderlyingHandle = handle;
            proxySrvOpen->UnderlyingDeviceObject = IoGetRelatedDeviceObject( proxySrvOpen->UnderlyingFileObject );
        } else {
            ZwClose(handle);
        }
    }


    RxDbgTrace( 0, Dbg, ("Status of underlying open %08lx\n", Status ));
    RxLog(("--->UnderlyingOpen %lx",Status));
//    DbgBreakPoint();


    RxDbgTrace(-1, Dbg, ("MRxProxyPostedCreate %08lx exit with status=%08lx\n", RxContext, Status ));
    if (NT_SUCCESS(Status)) {
        RxContext->Create.ReturnedCreateInformation = IoStatusBlock.Information;
    }
    pMRxProxyContext->PostedOpStatus = Status;
    RxSignalSynchronousWaiter(RxContext);
    return(STATUS_SUCCESS);
}

NTSTATUS
MRxProxyPostedCloseHandle (
    IN OUT PRX_CONTEXT RxContext
    )
/*++

Routine Description:


Arguments:

    RxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    //NTSTATUS Status;
    PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext);

    //RxCaptureFcb;
    //PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb);

    PMRX_SRV_OPEN SrvOpen = (PMRX_SRV_OPEN)(pMRxProxyContext->PostedOpContext);
    PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen);
    //HANDLE handle;

    PAGED_CODE();
    RxDbgTrace(+1, Dbg, ("MRxProxyPostedCloseHandle %08lx %08lx\n", RxContext, SrvOpen ));

    ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );

    ZwClose(proxySrvOpen->UnderlyingHandle);

    RxDbgTrace(-1, Dbg, ("MRxProxyPostedCloseHandle %08lx exit\n", RxContext ));
    pMRxProxyContext->PostedOpStatus = STATUS_SUCCESS;
    RxSignalSynchronousWaiter(RxContext);
    return(STATUS_SUCCESS);
}


NTSTATUS
MRxProxyCreate (
    IN OUT PRX_CONTEXT RxContext
    )
/*++

Routine Description:

   This routine opens a file across the network

Arguments:

    RxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status;

    RxCaptureFcb;
    PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb);

    PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen;
    PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen);

    BOOLEAN MustRegainExclusiveResource = FALSE;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxProxyCreate %08lx\n", RxContext ));

    //do this BEFORE you drop the resource
    SetFlag(SrvOpen->Flags,SRVOPEN_FLAG_COLLAPSING_DISABLED);

    Status = MRxProxyPostOperation ( RxContext,
                                     NULL,
                                     MRxProxyPostedCreate );

    //this Boolean should be passed......
    if (MustRegainExclusiveResource) {        //this is required if we do oplock breaks
        RxAcquireExclusiveFcb( RxContext, capFcb );
    }

    if (NT_SUCCESS(Status)) {

        RX_FILE_TYPE StorageType;
        FILE_BASIC_INFORMATION BasicInformation;
        FILE_STANDARD_INFORMATION StandardInformation;
        NTSTATUS InfoStatus;
        FCB_INIT_PACKET InitPacket;

        ASSERT  ( RxIsFcbAcquiredExclusive ( capFcb )  );
        StorageType = RxInferFileType(RxContext);
        RxDbgTrace( 0, Dbg, ("Storagetype %08lx\n", StorageType ));

        // if we have never obtained the characteristics, we have to get them.

        if ((capFcb->OpenCount == 0)
            || !FlagOn(capFcb->FcbState,FCB_STATE_TIME_AND_SIZE_ALREADY_SET) ) {

            InfoStatus = MRxProxySyncXxxInformation(
                                RxContext,                  //IN OUT PRX_CONTEXT RxContext,
                                IRP_MJ_QUERY_INFORMATION,   //IN UCHAR MajorFunction,
                                proxySrvOpen->UnderlyingFileObject,//IN PFILE_OBJECT FileObject,
                                FileBasicInformation,       //IN ULONG InformationClass,
                                sizeof(BasicInformation),   //IN ULONG Length,
                                &BasicInformation,          //OUT PVOID Information,
                                NULL);                      //OUT PULONG ReturnedLength OPTIONAL

            ASSERT (NT_SUCCESS(InfoStatus));   //BUGBUG what if not@!

            InfoStatus = MRxProxySyncXxxInformation(
                                RxContext,                  //IN OUT PRX_CONTEXT RxContext,
                                IRP_MJ_QUERY_INFORMATION,   //IN UCHAR MajorFunction,
                                proxySrvOpen->UnderlyingFileObject,//IN PFILE_OBJECT FileObject,
                                FileStandardInformation,    //IN ULONG InformationClass,
                                sizeof(StandardInformation),//IN ULONG Length,
                                &StandardInformation,       //OUT PVOID Information,
                                NULL);                      //OUT PULONG ReturnedLength OPTIONAL
            ASSERT (NT_SUCCESS(InfoStatus));

            if (StorageType == 0) {
                StorageType = StandardInformation.Directory?(FileTypeDirectory)
                                                           :(FileTypeFile);
                RxDbgTrace( 0, Dbg, ("ChangedStoragetype %08lx\n", StorageType ));
            }
            RxDbgTrace( 0, Dbg, ("FileSize %08lx\n", StandardInformation.EndOfFile.LowPart ));

            RxFinishFcbInitialization(
                                capFcb,
                                RDBSS_STORAGE_NTC(StorageType),
                                RxFormInitPacket(
                                    InitPacket, //note no &
                                    &BasicInformation.FileAttributes,
                                    &StandardInformation.NumberOfLinks,
                                    &BasicInformation.CreationTime,
                                    &BasicInformation.LastAccessTime,
                                    &BasicInformation.LastWriteTime,
                                    &BasicInformation.ChangeTime,
                                    &StandardInformation.AllocationSize,
                                    &StandardInformation.EndOfFile,
                                    &StandardInformation.EndOfFile)
                                 );

            //if (!MRxLocalNoOplocks) MRxLocalRequestOplock(SrvOpen,MRxOplockRequestType,MRxRequestLevelII);
            //RxDbgTrace( 0, Dbg, ("MRxLocalCreate      oplockstate =%08lx\n", localSrvOpen->OplockState ));
            //SrvOpen->BufferingFlags = MRxLocalTranslateStateToBufferMode[localSrvOpen->OplockState];

            SrvOpen->BufferingFlags |= FCB_STATE_COLLAPSING_ENABLED; //this can be turned off in the write path

        }
    }


    if (Status == STATUS_SUCCESS) {
        RxContext->pFobx = RxCreateNetFobx( RxContext, SrvOpen);
        if (!RxContext->pFobx) {
            NTSTATUS PostedCloseStatus;
            PostedCloseStatus = MRxProxyPostOperation(
                                       RxContext,
                                       ((PVOID)SrvOpen),
                                       MRxProxyPostedCloseHandle );
            ObDereferenceObject(proxySrvOpen->UnderlyingFileObject);
        }
    }

    //note.........collapsing IS enabled on fcb but not on any srvopen........
    SrvOpen->BufferingFlags |= (FCB_STATE_WRITECACHEING_ENABLED  |
                               FCB_STATE_FILESIZECACHEING_ENABLED |
                               FCB_STATE_FILETIMECACHEING_ENABLED |
                               FCB_STATE_WRITEBUFFERING_ENABLED |
                               FCB_STATE_LOCK_BUFFERING_ENABLED |
                               FCB_STATE_READBUFFERING_ENABLED  |
                               FCB_STATE_READCACHEING_ENABLED );

    ASSERT(Status != (STATUS_PENDING));
    ASSERT(RxIsFcbAcquiredExclusive( capFcb ));

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

NTSTATUS
MRxProxyCollapseOpen(
      IN OUT PRX_CONTEXT RxContext
      )
/*++

Routine Description:

   This routine collapses a open locally

Arguments:

    RxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status;

    RxCaptureFcb;

    //RX_BLOCK_CONDITION FinalSrvOpenCondition;

    PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen;
    PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
    PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;

    ASSERT(FALSE);

    RxContext->pFobx = (PMRX_FOBX)RxCreateNetFobx( RxContext, SrvOpen);

    if (RxContext->pFobx != NULL) {
       ASSERT  ( RxIsFcbAcquiredExclusive ( capFcb )  );
       RxContext->pFobx->OffsetOfNextEaToReturn = 1;
       Status = STATUS_SUCCESS;
    } else {
       Status = (STATUS_INSUFFICIENT_RESOURCES);
       //DbgBreakPoint();
    }

    return Status;
}

NTSTATUS
MRxProxyComputeNewBufferingState(
   IN OUT PMRX_SRV_OPEN   pMRxSrvOpen,
   IN     PVOID           pMRxContext,
      OUT PULONG          pNewBufferingState)
/*++

Routine Description:

   This routine maps the PROXY specific oplock levels into the appropriate RDBSS
   buffering state flags

Arguments:

   pMRxSrvOpen - the MRX SRV_OPEN extension

   pMRxContext - the context passed to RDBSS at Oplock indication time

   pNewBufferingState - the place holder for the new buffering state

Return Value:


Notes:

--*/
{
    //ULONG OplockLevel;
    ULONG NewBufferingState;

    PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(pMRxSrvOpen);
    PMRX_PROXY_FCB      proxyFcb     = MRxProxyGetFcbExtension(pMRxSrvOpen->pFcb);

    ASSERT(pNewBufferingState != NULL);

#if 0
    OplockLevel = (ULONG)pMRxContext;

    if (OplockLevel == PROXY_OPLOCK_LEVEL_II) {
        NewBufferingState = (FCB_STATE_READBUFFERING_ENABLED  |
                               FCB_STATE_READCACHEING_ENABLED);
    } else {
        NewBufferingState = 0;
    }
#endif //0

    NewBufferingState = 0;

    pMRxSrvOpen->BufferingFlags = NewBufferingState;

    MRxProxyMungeBufferingIfWriteOnlyHandles(
          proxyFcb->WriteOnlySrvOpenCount,
          pMRxSrvOpen);

    *pNewBufferingState = pMRxSrvOpen->BufferingFlags;

    return STATUS_SUCCESS;
}

//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------


NTSTATUS
MRxProxyZeroExtend(
      IN PRX_CONTEXT pRxContext)
/*++

Routine Description:

   This routine extends the data stream of a file system object

Arguments:

    pRxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
   return STATUS_NOT_IMPLEMENTED;
}

NTSTATUS
MRxProxyTruncate(
      IN PRX_CONTEXT pRxContext)
/*++

Routine Description:

   This routine truncates the contents of a file system object

Arguments:

    pRxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
   ASSERT(!"Found a truncate");
   return STATUS_NOT_IMPLEMENTED;
}

NTSTATUS
MRxProxyCleanupFobx(
      IN PRX_CONTEXT RxContext)
/*++

Routine Description:

   This routine cleansup a file system object...normally a noop. unless it's a pipe in which case
   we do the close at cleanup time and mark the file as being not open.

Arguments:

    pRxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb; RxCaptureFobx;
    PUNICODE_STRING RemainingName = &(capFcb->AlreadyPrefixedName);

    NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);

    PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
    PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen);
    //PMRX_PROXY_FCB  proxyFcb  = MRxProxyGetFcbExtension(capFcb);
    //PMRX_PROXY_FOBX proxyFobx = MRxProxyGetFileObjectExtension(capFobx);

    PAGED_CODE();

    ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
    ASSERT ( NodeTypeIsFcb(capFcb) );
    ASSERT (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT));
    ASSERT (proxySrvOpen->UnderlyingFileObject);


    //if (FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED)) {
    //   RxDbgTrace(-1, Dbg, ("File orphaned\n"));
    //   return (STATUS_SUCCESS);
    //}


    //
    // if more fobxs are using this srvopen then just get out.
    // otherwise close the handle to trigger the underlying cleanup

    if (SrvOpen->UncleanFobxCount > 1) {  return Status; }

    RxDbgTrace(+1, Dbg, ("MRxProxyCleanup %wZ\n", RemainingName ));
    RxLog(("ProxyCleanup %lx",SrvOpen));

    //because we only have one handle onthe file....we do nothing for each
    //individual handle being closed. in this way we avoid doing paging ios!
    //we close the handle when the final close for the fcb comes down.


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

    return(Status);

}

NTSTATUS
MRxProxyForcedClose(
      IN PMRX_SRV_OPEN pSrvOpen)
/*++

Routine Description:

   This routine closes a file system object

Arguments:

    pSrvOpen - the instance to be closed

Return Value:

    RXSTATUS - The return status for the operation

Notes:



--*/
{
   return STATUS_NOT_IMPLEMENTED;
}

//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//------------close close close close close close close  --------------------------------
//------------close close close close close close close  --------------------------------
//------------close close close close close close close  --------------------------------
//------------close close close close close close close  --------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//
//  The local debug trace level
//

#undef  Dbg
#define Dbg                              (DEBUG_TRACE_CLOSE)

NTSTATUS
MRxProxyCloseSrvOpen(
      IN     PRX_CONTEXT   RxContext
      )
/*++

Routine Description:

   This routine closes a file across the network

Arguments:

    RxContext - the RDBSS context

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb;
    RxCaptureFobx;
    PUNICODE_STRING RemainingName = &(capFcb->AlreadyPrefixedName);
    NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);

    PMRX_SRV_OPEN       SrvOpen    = capFobx->pSrvOpen;
    PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen);
    //PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb);
    //PMRX_PROXY_FOBX     proxyFobx    = MRxProxyGetFileObjectExtension(capFobx);

    //IO_STATUS_BLOCK Iosb;
    //PMINIRDR_OPLOCK_COMPLETION_CONTEXT cc = localSrvOpen->Mocc;
    //KIRQL oldIrql;
    //BOOLEAN OplockBreakPending;

    PAGED_CODE();

    ASSERT ( NodeTypeIsFcb(capFcb) );
    ASSERT ( SrvOpen->OpenCount == 0 );
    ASSERT (proxySrvOpen->UnderlyingFileObject);

    //if (capFcb->OpenCount > 0) { return STATUS_SUCCESS;}

    RxDbgTrace(+1, Dbg, ("MRxProxyClose   %wZ\n", RemainingName ));
    RxLog(("ProxyClose fobx=%lx",capFobx));

    //if (proxySrvOpen->DeferredOpenContext != NULL) {
    //    RxFreePool(proxySrvOpen->DeferredOpenContext);
    //}
    //if ((FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED))) {
    //   RxDbgTrace(-1, Dbg, ("File orphan\n"));
    //   return (STATUS_SUCCESS);
    //}

    ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );

#if 0
IF WE REENABLE THIS, DONT USE IOSETINFO...USE MRxProxySyncXxxInformation INSTEAD
    // first we set the real filesize.....our pagingIos may have extended it
    // to a page boundary.........

    if ( NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE ) {
        FILE_END_OF_FILE_INFORMATION EndOfFileInformation;

        EndOfFileInformation.EndOfFile = capFcb->Header.FileSize;
        Status = IxxoSetInformation(
                    proxySrvOpen->UnderlyingFileObject,  //IN PFILE_OBJECT FileObject,
                    FileEndOfFileInformation,        //IN FILE_INFORMATION_CLASS FileInformationClass,
                    sizeof(EndOfFileInformation),    //IN ULONG Length,
                    &EndOfFileInformation            //IN PVOID FileInformation
                    );
    }

    //if bad status....keep going anyway........
#endif

    // next, we close our handle..........

    Status = MRxProxyPostOperation(
                  RxContext,
                  ((PVOID)SrvOpen),
                  MRxProxyPostedCloseHandle );

    // then, we remove our reference..........

    if (proxySrvOpen->UnderlyingFileObject) {

        RxDbgTrace( 0, Dbg, ("ProxyClose Attempt to close %wZ\n", &(capFcb->AlreadyPrefixedName) ));

        //if (cc) {
        //    ASSERTMSG("Joejoe the right way to do this would be to CANCEL!!!!!!!!",FALSE);
        //    //since this is a force closed, we get rid of a pending break
        //    KeAcquireSpinLock( &MrxLocalOplockSpinLock, &oldIrql );
        //    OplockBreakPending = cc->OplockBreakPending;
        //    if (!OplockBreakPending) {
        //        cc->SrvOpen = NULL;
        //    }
        //    KeReleaseSpinLock( &MrxLocalOplockSpinLock, oldIrql );
        //    if (!OplockBreakPending) {
        //        //gotta lose the spinlock befoer the call
        //        RxDereferenceSrvOpen(SrvOpen); //elim ref!
        //    }
        //} else {
        //    ASSERT (localSrvOpen->OplockState == OplockStateNone);
        //}

        RxLog(("MRxProxyClose %lx %lx",capFcb,capFobx));
        //DbgPrint("MRxProxyClose %lx %lx\n",capFcb,capFobx);

        ObDereferenceObject(proxySrvOpen->UnderlyingFileObject);

        proxySrvOpen->UnderlyingFileObject = NULL;

    }

    Status = STATUS_SUCCESS;

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

    return(Status);

}

