/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    DownLvlO.c

Abstract:

    This module implements downlevel opens.

Author:

    Joe Linn      [JoeLi]      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
//

#ifdef  ALLOC_PRAGMA
#pragma alloc_text(PAGE, MRxSmbGetFileAttributes)
#pragma alloc_text(PAGE, MRxSmbCoreDeleteForSupercedeOrClose)
#pragma alloc_text(PAGE, MRxSmbCoreCheckPath)
#pragma alloc_text(PAGE, MRxSmbCoreOpen)
#pragma alloc_text(PAGE, MRxSmbSetFileAttributes)
#pragma alloc_text(PAGE, MRxSmbCoreCreateDirectory)
#pragma alloc_text(PAGE, MRxSmbCoreCreate)
#pragma alloc_text(PAGE, MRxSmbCloseAfterCoreCreate)
#pragma alloc_text(PAGE, MRxSmbCoreTruncate)
#pragma alloc_text(PAGE, MRxSmbDownlevelCreate)
#pragma alloc_text(PAGE, MRxSmbFinishGFA)
#pragma alloc_text(PAGE, MRxSmbFinishCoreCreate)
#pragma alloc_text(PAGE, MRxSmbPopulateFileInfoInOE)
#pragma alloc_text(PAGE, MRxSmbFinishCoreOpen)
#pragma alloc_text(PAGE, MRxSmbPseudoOpenTailFromCoreCreateDirectory)
#pragma alloc_text(PAGE, MRxSmbPseudoOpenTailFromFakeGFAResponse)
#pragma alloc_text(PAGE, MRxSmbPseudoOpenTailFromGFAResponse)
#pragma alloc_text(PAGE, MRxSmbConvertSmbTimeToTime)
#pragma alloc_text(PAGE, MRxSmbConvertTimeToSmbTime)
#pragma alloc_text(PAGE, MRxSmbTimeToSecondsSince1970)
#pragma alloc_text(PAGE, MRxSmbSecondsSince1970ToTime)
#pragma alloc_text(PAGE, MRxSmbMapSmbAttributes)
#pragma alloc_text(PAGE, MRxSmbMapDisposition)
#pragma alloc_text(PAGE, MRxSmbUnmapDisposition)
#pragma alloc_text(PAGE, MRxSmbMapDesiredAccess)
#pragma alloc_text(PAGE, MRxSmbMapShareAccess)
#pragma alloc_text(PAGE, MRxSmbMapFileAttributes)
#endif

#define Dbg                              (DEBUG_TRACE_CREATE)

#pragma warning(error:4101)   // Unreferenced local variable

VOID
MRxSmbPopulateFileInfoInOE(
    PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
    USHORT FileAttributes,
    ULONG LastWriteTimeInSeconds,
    ULONG FileSize
    );

PVOID
MRxSmbPopulateFcbInitPacketForCore(void);


NTSTATUS
MRxSmbPseudoOpenTailFromGFAResponse (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange
      );
NTSTATUS
MRxSmbPseudoOpenTailFromFakeGFAResponse (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      RX_FILE_TYPE StorageType
      );
NTSTATUS
MRxSmbPseudoOpenTailFromCoreCreateDirectory (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      USHORT Attributes
      );

//CODE.IMPROVEMENT all of these routines that do a single core operation are to
// be rolled up into a single routine......
// for this reason, we shouldn't worry about the commonality...the more the better!

NTSTATUS
MRxSmbGetFileAttributes(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
    )
/*++

Routine Description:

   This routine does a GetFileAttributes and remembers the reponse. This routine also
   does the cache for the file information.

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


--*/
{
    NTSTATUS Status;

    RxCaptureFcb;
    RxCaptureFobx;

    PMRX_SRV_OPEN     SrvOpen    = NULL;
    PMRX_SMB_SRV_OPEN smbSrvOpen = NULL;

    PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
    PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(Exchange);

    PSMBSTUFFER_BUFFER_STATE StufferState;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbSynchronousGetFileAttributes entering.......OE=%08lx\n",OrdinaryExchange));

    if (FsRtlDoesNameContainWildCards(RemainingName)) {
        Status = RX_MAP_STATUS(OBJECT_NAME_INVALID);
        goto FINALLY;
    }

    if (MRxSmbIsFileNotFoundCached(RxContext)) {
        Status = STATUS_OBJECT_NAME_NOT_FOUND;
        goto FINALLY;
    }

    // Try to find the cached file infomation
    if (MRxSmbIsFileInfoCacheFound(RxContext,
                                   &OrdinaryExchange->Create.FileInfo,
                                   &Status,
                                   NULL)){
        goto FINALLY;
    }

    // If the file has already been opened a QUERY_INFORMATION2 can be issued while
    // QUERY_INFORMATION can only be issued against pseudo opened and not yet
    // opened files.

    if (capFobx != NULL) {
        SrvOpen = capFobx->pSrvOpen;
        if (SrvOpen != NULL)
            smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
    }

    StufferState = &OrdinaryExchange->AssociatedStufferState;

    if (pServerEntry->Server.Dialect > PCNET1_DIALECT &&
        (smbSrvOpen != NULL) &&
        (!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) &&
         !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN)   &&
         (NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE))) {
        COVERED_CALL(
            MRxSmbStartSMBCommand(
                StufferState,
                SetInitialSMB_ForReuse,
                SMB_COM_QUERY_INFORMATION2,
                SMB_REQUEST_SIZE(QUERY_INFORMATION2),
                NO_EXTRA_DATA,
                SMB_BEST_ALIGNMENT(1,0),
                RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                0,0,0,0 STUFFERTRACE(Dbg,'FC'))
            );

        MRxSmbDumpStufferState (1100,"SMB w/ GFA before stuffing",StufferState);

        MRxSmbStuffSMB (
            StufferState,
            "0wB!",
                                        //  0         UCHAR WordCount;
            smbSrvOpen->Fid,            //  w         _USHORT(Fid);
            SMB_WCT_CHECK(1)  0         //  B         _USHORT( ByteCount );               // Count of data bytes; min = 2
                                        //            UCHAR Buffer[1];                    // Buffer containing:
            );

        MRxSmbDumpStufferState (700,"SMB w/ GFA after stuffing",StufferState);
    } else {
        COVERED_CALL(
            MRxSmbStartSMBCommand(
                StufferState,
                SetInitialSMB_ForReuse,
                SMB_COM_QUERY_INFORMATION,
                SMB_REQUEST_SIZE(QUERY_INFORMATION),
                NO_EXTRA_DATA,
                SMB_BEST_ALIGNMENT(1,0),
                RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                0,0,0,0 STUFFERTRACE(Dbg,'FC'))
            );

        MRxSmbDumpStufferState (1100,"SMB w/ GFA before stuffing",StufferState);

        //CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
        //                 otherwise, we don't need to copy the name here, we can just Mdl like in writes
        MRxSmbStuffSMB (
            StufferState,
            "0B4!",
                                        //  0         UCHAR WordCount;                    // Count of parameter words = 0
            SMB_WCT_CHECK(0)            //  B         _USHORT( ByteCount );               // Count of data bytes; min = 2
                                        //            UCHAR Buffer[1];                    // Buffer containing:
            RemainingName
                                        //  4         //UCHAR BufferFormat;               //  0x04 -- ASCII
                                        //            //UCHAR FileName[];                 //  File name
            );

        MRxSmbDumpStufferState (700,"SMB w/ GFA after stuffing",StufferState);
    }

    Status = SmbPseOrdinaryExchange(
                 SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                 SMBPSE_OETYPE_GFA
                 );

    if (NT_SUCCESS(Status)) {
        MRxSmbCreateFileInfoCache(RxContext,
                                  &OrdinaryExchange->Create.FileInfo,
                                  pServerEntry,
                                  Status);
    } else {
        if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
            Status == STATUS_OBJECT_PATH_NOT_FOUND) {
             // create the name based file not found cache
            MRxSmbCacheFileNotFound(RxContext);
        } else {
             // invalid the name based file not found cache if other error happens
            MRxSmbInvalidateFileNotFoundCache(RxContext);
        }
    }

FINALLY:

    if (NT_SUCCESS(Status)) {
        OrdinaryExchange->Create.StorageTypeFromGFA =
            OrdinaryExchange->Create.FileInfo.Standard.Directory ?
            FileTypeDirectory : FileTypeFile;
    }

    RxDbgTrace(-1, Dbg, ("MRxSmbSynchronousGetFileAttributes exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}


NTSTATUS
MRxSmbCoreDeleteForSupercedeOrClose(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
    BOOLEAN DeleteDirectory
    )
/*++

Routine Description:

   This routine does a GetFileAttributes and remembers the reponse.

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


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

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;

    PSMBSTUFFER_BUFFER_STATE StufferState;

    PMRX_SRV_OPEN     SrvOpen    = capFobx->pSrvOpen;
    PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbCoreDeleteForSupercede entering.......OE=%08lx\n",OrdinaryExchange));

    StufferState = &OrdinaryExchange->AssociatedStufferState;

    ASSERT( StufferState );
    ASSERT( OrdinaryExchange->pPathArgument1 != NULL );

    //
    if (!DeleteDirectory) {
        ULONG SearchAttributes = SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN;  // a la rdr1

        COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_DELETE,
                                    SMB_REQUEST_SIZE(DELETE),
                                    NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                    0,0,0,0 STUFFERTRACE(Dbg,'FC'))
                     );

        MRxSmbDumpStufferState (1100,"SMB w/ del before stuffing",StufferState);

        //CODE.IMPROVEMENT if this is truly core, we have to copy the name since it's in UNICODE
        //                 otherwise, we don't need to copy the name here, we can just Mdl like in writes
        //                 on the other hand, if it's NT<-->NT we don't do it here anyway
        MRxSmbStuffSMB (StufferState,
             "0wB4!",
                                        //  0         UCHAR WordCount;                    // Count of parameter words = 1
                    SearchAttributes,   //  w         _USHORT( SearchAttributes );
                    SMB_WCT_CHECK(1)    //  B         _USHORT( ByteCount );               // Count of data bytes; min = 2
                                        //            UCHAR Buffer[1];                    // Buffer containing:
                    OrdinaryExchange->pPathArgument1
                                        //  4         //UCHAR BufferFormat;               //  0x04 -- ASCII
                                        //            //UCHAR FileName[];                 //  File name
                 );
    } else {


        COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_DELETE_DIRECTORY,
                                    SMB_REQUEST_SIZE(DELETE_DIRECTORY),
                                    NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                    0,0,0,0 STUFFERTRACE(Dbg,'FC'))
                     );

        MRxSmbDumpStufferState (1100,"SMB w/ rmdir before stuffing",StufferState);

        //CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
        //                 otherwise, we don't need to copy the name here, we can just Mdl like in writes
        MRxSmbStuffSMB (StufferState,
             "0B4!",
                                        //  0         UCHAR WordCount;                    // Count of parameter words = 0
                    SMB_WCT_CHECK(0)    //  B         _USHORT( ByteCount );               // Count of data bytes; min = 2
                                        //            UCHAR Buffer[1];                    // Buffer containing:
                    OrdinaryExchange->pPathArgument1
                                        //  4         //UCHAR BufferFormat;               //  0x04 -- ASCII
                                        //            //UCHAR FileName[];                 //  File name
                 );
    }


    MRxSmbDumpStufferState (700,"SMB w/ del/rmdir after stuffing",StufferState);

    Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                    SMBPSE_OETYPE_DELETEFORSUPERSEDEORCLOSE
                                    );

    if (Status == STATUS_SUCCESS) {
        // invalid the name based file info cache
        MRxSmbInvalidateFileInfoCache(RxContext);
        

        MRxSmbInvalidateInternalFileInfoCache(RxContext);
        MRxSmbCacheFileNotFound(RxContext);

        SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_FILE_DELETED);
    } else {
        RxLog(("Delete File: %x %wZ\n",Status,OrdinaryExchange->pPathArgument1));
        SmbLog(LOG,
               MRxSmbCoreDeleteForSupercedeOrClose,
               LOGULONG(Status)
               LOGUSTR(*OrdinaryExchange->pPathArgument1));
    }

FINALLY:
    RxDbgTrace(-1, Dbg, ("MRxSmbCoreDeleteForSupercede exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}

NTSTATUS
MRxSmbCoreCheckPath(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
    )
/*++

Routine Description:

   This routine does a GetFileAttributes and remembers the reponse.

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


--*/
{
    NTSTATUS Status;
    FILE_BASIC_INFORMATION FileInfoBasic;

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;

    PSMBSTUFFER_BUFFER_STATE StufferState;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbCoreCheckPath entering.......OE=%08lx\n",
                                                            OrdinaryExchange));
    // Try to find the cached file infomation
    if (MRxSmbIsBasicFileInfoCacheFound(RxContext,
                                        &FileInfoBasic,
                                        &Status,
                                        OrdinaryExchange->pPathArgument1)){

        if (Status == STATUS_SUCCESS) {
            if (!(FileInfoBasic.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                Status = STATUS_NOT_A_DIRECTORY;
            }

            goto FINALLY;
        }
    }
    
    StufferState = &OrdinaryExchange->AssociatedStufferState;

    ASSERT( StufferState );


    COVERED_CALL(MRxSmbStartSMBCommand
                                (StufferState,SetInitialSMB_ForReuse,
                                SMB_COM_CHECK_DIRECTORY,
                                SMB_REQUEST_SIZE(CHECK_DIRECTORY),
                                NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),
                                RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                0,0,0,0 STUFFERTRACE(Dbg,'FC'))
                 );

    MRxSmbDumpStufferState (1100,"SMB w/ chkdir before stuffing",StufferState);

    //CODE.IMPROVEMENT many of these single argument guys can be rooled up
    MRxSmbStuffSMB (StufferState,
         "0B4!",
         //         UCHAR WordCount;       // Count of parameter words = 0
         SMB_WCT_CHECK(0)
         //  B    _USHORT( ByteCount );    // Count of data bytes; min = 2
         //       UCHAR Buffer[1];         // Buffer containing:
         OrdinaryExchange->pPathArgument1
         //  4    UCHAR BufferFormat;      //  0x04 -- ASCII
         //       UCHAR FileName[];        //  File name
    );


    MRxSmbDumpStufferState (700,"SMB w/ chkdir after stuffing",StufferState);

    Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                    SMBPSE_OETYPE_CORECHECKDIRECTORY
                                    );

FINALLY:
    RxDbgTrace(-1, Dbg,
                ("MRxSmbCoreCheckPath exiting.......OE=%08lx, st=%08lx\n",
                 OrdinaryExchange,Status)
              );
    return(Status);
}

NTSTATUS
MRxSmbCoreOpen(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
    ULONG    OpenShareMode,
    ULONG    Attribute
    )
/*++

Routine Description:

   This routine does a core open.

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb; //RxCaptureFobx;
    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
    PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
    PSMBCE_SERVER pServer = SmbCeGetExchangeServer(Exchange);

    PSMBSTUFFER_BUFFER_STATE StufferState;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbCoreOpen entering.......OE=%08lx\n",OrdinaryExchange));

    StufferState = &OrdinaryExchange->AssociatedStufferState;

    ASSERT( StufferState );
    ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
    ASSERT( RxContext->MajorFunction == IRP_MJ_CREATE );

    COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_OPEN,
                                SMB_REQUEST_SIZE(OPEN),
                                NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                0,0,0,0 STUFFERTRACE(Dbg,'FC'))
                 );

    MRxSmbDumpStufferState (1100,"SMB w/ coreopen before stuffing",StufferState);

    //CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
    //                 otherwise, we don't need to copy the name here, we can just Mdl like in writes
    MRxSmbStuffSMB (StufferState,
         "0wwB4!",
                                    //  0         UCHAR WordCount;                    // Count of parameter words = 2
                OpenShareMode,      //  w         _USHORT( DesiredAccess );           // Mode - read/write/share
                Attribute,          //  w         _USHORT( SearchAttributes );
                SMB_WCT_CHECK(2)    //  B         _USHORT( ByteCount );               // Count of data bytes; min = 2
                                    //            UCHAR Buffer[1];                    // Buffer containing:
                RemainingName
                                    //  4         //UCHAR BufferFormat;               //  0x04 -- ASCII
                                    //            //UCHAR FileName[];                 //  File name
             );


    MRxSmbDumpStufferState (700,"SMB w/ coreopen after stuffing",StufferState);
    //ASSERT(!"Now it's stuffed");

    Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                    SMBPSE_OETYPE_COREOPEN
                                    );

FINALLY:
    RxDbgTrace(-1, Dbg, ("MRxSmbCoreOpen exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}

NTSTATUS
MRxSmbSetFileAttributes(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
    ULONG SmbAttributes
    )
/*++

Routine Description:

   This routine does a core create directory.....

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb;
    RxCaptureFobx;
    PMRX_SRV_OPEN     SrvOpen     = NULL;
    PMRX_SMB_SRV_OPEN smbSrvOpen  = NULL;
    PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;

    ULONG LastWriteTime = 0;
    ULONG FileAttributes = 0;
    PLARGE_INTEGER pCreationTime = NULL;
    PLARGE_INTEGER pLastWriteTime = NULL;
    PLARGE_INTEGER pLastAccessTime = NULL;
    SMB_TIME SmbCreationTime;
    SMB_DATE SmbCreationDate;
    SMB_TIME SmbLastWriteTime;
    SMB_DATE SmbLastWriteDate;
    SMB_TIME SmbLastAccessTime;
    SMB_DATE SmbLastAccessDate;
    
    PSMBSTUFFER_BUFFER_STATE StufferState;
    BOOLEAN TimeSpecified = FALSE;
    
    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbSetFileAttributes entering.......OE=%08lx\n",OrdinaryExchange));
    StufferState = &OrdinaryExchange->AssociatedStufferState;

    ASSERT( StufferState );

    if (capFobx != NULL) {
        SrvOpen = capFobx->pSrvOpen;
        if (SrvOpen != NULL)
            smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
    }

    SmbCreationTime.Ushort = 0;
    SmbCreationDate.Ushort = 0;
    SmbLastWriteTime.Ushort = 0;
    SmbLastWriteDate.Ushort = 0;
    SmbLastAccessTime.Ushort = 0;
    SmbLastAccessDate.Ushort = 0;

    if (RxContext->MajorFunction == IRP_MJ_SET_INFORMATION) {
        BOOLEAN GoodTime;
        
        FileAttributes = ((PFILE_BASIC_INFORMATION)OrdinaryExchange->Info.Buffer)->FileAttributes;
        pCreationTime = &((PFILE_BASIC_INFORMATION)OrdinaryExchange->Info.Buffer)->CreationTime;
        pLastWriteTime = &((PFILE_BASIC_INFORMATION)OrdinaryExchange->Info.Buffer)->LastWriteTime;
        pLastAccessTime = &((PFILE_BASIC_INFORMATION)OrdinaryExchange->Info.Buffer)->LastAccessTime;

        if (pLastWriteTime->QuadPart != 0) {
            GoodTime = MRxSmbTimeToSecondsSince1970(
                           pLastWriteTime,
                           SmbCeGetExchangeServer(OrdinaryExchange),
                           &LastWriteTime);

            if (!GoodTime) {
                Status = STATUS_INVALID_PARAMETER;
                goto FINALLY;
            }

            GoodTime = MRxSmbConvertTimeToSmbTime(pLastWriteTime,
                                       (PSMB_EXCHANGE)OrdinaryExchange,
                                       &SmbLastWriteTime,
                                       &SmbLastWriteDate);
        
            if (!GoodTime) {
                Status = STATUS_INVALID_PARAMETER;
                goto FINALLY;
            }
            
            TimeSpecified = TRUE;
        }
    
        if (pLastAccessTime->QuadPart != 0) {
            GoodTime = MRxSmbConvertTimeToSmbTime(pLastAccessTime,
                                       (PSMB_EXCHANGE)OrdinaryExchange,
                                       &SmbLastAccessTime,
                                       &SmbLastAccessDate);
            
            if (!GoodTime) {
                Status = STATUS_INVALID_PARAMETER;
                goto FINALLY;
            }
            
            TimeSpecified = TRUE;
        }
    
        if (pCreationTime->QuadPart != 0) {
            GoodTime = MRxSmbConvertTimeToSmbTime(pCreationTime,
                                       (PSMB_EXCHANGE)OrdinaryExchange,
                                       &SmbCreationTime,
                                       &SmbCreationDate);
            
            if (!GoodTime) {
                Status = STATUS_INVALID_PARAMETER;
                goto FINALLY;
            }
            
            TimeSpecified = TRUE;
        }

                
        if (!TimeSpecified && (FileAttributes == 0))
        {
            // caller didn't specify anything worth doing. Return success
            // 442486
        
            Status = STATUS_SUCCESS;
            goto FINALLY;
        }
    }

    if (smbSrvOpen == NULL ||
        FileAttributes != 0 ||
        RxContext->MajorFunction != IRP_MJ_SET_INFORMATION ||
        FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN) ||
        FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) ||
        (pLastWriteTime->QuadPart == 0 && pLastAccessTime->QuadPart == 0 && pCreationTime->QuadPart == 0)) {
        
        COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,
                                    SMB_COM_SET_INFORMATION,
                                    SMB_REQUEST_SIZE(SET_INFORMATION),
                                    NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                    0,0,0,0 STUFFERTRACE(Dbg,'FC')));

        MRxSmbDumpStufferState (1100,"SMB w/ sfa before stuffing",StufferState);

        //CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
        //                 otherwise, we don't need to copy the name here, we can just Mdl like in writes
        MRxSmbStuffSMB (StufferState,
             "0wdwwwwwB4!",
                                        //  0         UCHAR WordCount;                    // Count of parameter words = 8
                    SmbAttributes,      //  w         _USHORT( FileAttributes );
                    LastWriteTime,      //  d         _ULONG( LastWriteTimeInSeconds );
                    0,0,0,0,0,          //  5*w       _USHORT( Reserved )[5];             // Reserved (must be 0)
                    SMB_WCT_CHECK(8)    //  B         _USHORT( ByteCount );               // Count of data bytes; min = 2
                                        //            UCHAR Buffer[1];                    // Buffer containing:
                    RemainingName
                                        //  4         //UCHAR BufferFormat;               //  0x04 -- ASCII
                                        //            //UCHAR FileName[];                 //  File name
                 );


        MRxSmbDumpStufferState (700,"SMB w/ sfa after stuffing",StufferState);
        //ASSERT(!"Now it's stuffed");

        Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                        SMBPSE_OETYPE_SFA);
    } else {
        COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,
                                    SMB_COM_SET_INFORMATION2,
                                    SMB_REQUEST_SIZE(SET_INFORMATION2),
                                    NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                    0,0,0,0 STUFFERTRACE(Dbg,'FC')));

        MRxSmbDumpStufferState (1100,"SMB w/ sfa 2 before stuffing",StufferState);

        MRxSmbStuffSMB (StufferState,
             "0wwwwwwwB!",
                                               //  0         UCHAR WordCount;                    // Count of parameter words = 8
             smbSrvOpen->Fid,                  //  w         _USHORT( Fid );                     // File handle
             SmbCreationDate.Ushort,           //  w         SMB_TIME CreationDate;
             SmbCreationTime.Ushort,           //  w         SMB_TIME CreationTime;
             SmbLastAccessDate.Ushort,         //  w         SMB_TIME LastAccessDate;
             SmbLastAccessTime.Ushort,         //  w         SMB_TIME LastAccessTime;
             SmbLastWriteDate.Ushort,          //  w         SMB_TIME LastWriteDate;
             SmbLastWriteTime.Ushort,          //  w         SMB_TIME LastWriteTime;
             SMB_WCT_CHECK(7) 0                //            _USHORT( ByteCount );               // Count of data bytes; min = 0
                                               //            UCHAR Buffer[1];                    // Reserved buffer
             );


        MRxSmbDumpStufferState (700,"SMB w/ sfa 2 after stuffing",StufferState);
        //ASSERT(!"Now it's stuffed");

        Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                        SMBPSE_OETYPE_SFA2);
    }

    if (Status == STATUS_SUCCESS) {
        if (RxContext->MajorFunction != IRP_MJ_SET_INFORMATION) {
            FileAttributes = MRxSmbMapSmbAttributes((USHORT)SmbAttributes);
        }

        MRxSmbUpdateBasicFileInfoCache(RxContext,
                                       FileAttributes,
                                       pLastWriteTime);

        MRxSmbUpdateStandardFileInfoCache(RxContext,
                                          NULL,
                                          (BOOLEAN)(FileAttributes & FILE_ATTRIBUTE_DIRECTORY));

        MRxSmbInvalidateFileNotFoundCache(RxContext);
    

    } else {
        if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
            Status == STATUS_OBJECT_PATH_NOT_FOUND) {
             // create the name based file not found cache
            MRxSmbCacheFileNotFound(RxContext);
        } else {
             // invalid the name based file not found cache if other error happens
            MRxSmbInvalidateFileNotFoundCache(RxContext);
        }

        // invalid the name based file info cache
        MRxSmbInvalidateFileInfoCache(RxContext);
    
    }

FINALLY:
    RxDbgTrace(-1, Dbg, ("MRxSmbSFAAfterCreateDirectory exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}


NTSTATUS
MRxSmbCoreCreateDirectory(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
    )
/*++

Routine Description:

   This routine does a core create directory.....

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


--*/
{
    NTSTATUS Status;
    RxCaptureFcb; //RxCaptureFobx;
    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
    PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;

    PSMBSTUFFER_BUFFER_STATE StufferState;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbCoreCreateDirectory entering.......OE=%08lx\n",OrdinaryExchange));
    StufferState = &OrdinaryExchange->AssociatedStufferState;

    ASSERT( StufferState );
    ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
    ASSERT( RxContext->MajorFunction == IRP_MJ_CREATE );

    COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse,
                                SMB_COM_CREATE_DIRECTORY,
                                SMB_REQUEST_SIZE(CREATE_DIRECTORY),
                                NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                0,0,0,0 STUFFERTRACE(Dbg,'FC'))
                 );

    MRxSmbDumpStufferState (1100,"SMB w/ corecreatedir before stuffing",StufferState);

    //CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
    //                 otherwise, we don't need to copy the name here, we can just Mdl like in writes
    MRxSmbStuffSMB (StufferState,
         "0B4!",
                                    //  0         UCHAR WordCount;                    // Count of parameter words = 0
                SMB_WCT_CHECK(0)    //  B         _USHORT( ByteCount );               // Count of data bytes; min = 2
                                    //            UCHAR Buffer[1];                    // Buffer containing:
                RemainingName
                                    //  4         //UCHAR BufferFormat;               //  0x04 -- ASCII
                                    //            //UCHAR FileName[];                 //  File name
             );


    MRxSmbDumpStufferState (700,"SMB w/ corecreatedir after stuffing",StufferState);
    //ASSERT(!"Now it's stuffed");

    Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                    SMBPSE_OETYPE_CORECREATEDIRECTORY
                                    );

FINALLY:
    RxDbgTrace(-1, Dbg, ("MRxSmbCoreCreateDirectory exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}


NTSTATUS
MRxSmbCoreCreate(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
    ULONG    Attribute,
    BOOLEAN CreateNew
    )
/*++

Routine Description:

   This routine does a core create.....if the flag is set we use create new.

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


--*/
{
    NTSTATUS Status;
    RxCaptureFcb; //RxCaptureFobx;
    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
    PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;

    PSMBSTUFFER_BUFFER_STATE StufferState;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbCoreCreate entering.......OE=%08lx\n",OrdinaryExchange));
    StufferState = &OrdinaryExchange->AssociatedStufferState;

    ASSERT( StufferState );
    ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
    ASSERT( RxContext->MajorFunction == IRP_MJ_CREATE );

    COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse,
                                (UCHAR)(CreateNew?SMB_COM_CREATE_NEW:SMB_COM_CREATE),
                                SMB_REQUEST_SIZE(CREATE),
                                NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                0,0,0,0 STUFFERTRACE(Dbg,'FC'))
                 );

    MRxSmbDumpStufferState (1100,"SMB w/ coreopen before stuffing",StufferState);

    //CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
    //                 otherwise, we don't need to copy the name here, we can just Mdl like in writes
    MRxSmbStuffSMB (StufferState,
         "0wdB4!",
                                    //  0         UCHAR WordCount;                    // Count of parameter words = 3
                Attribute,          //  w         _USHORT( FileAttributes );          // New file attributes
                0,                  //  d         _ULONG( CreationTimeInSeconds );        // Creation time
                SMB_WCT_CHECK(3)    //  B         _USHORT( ByteCount );               // Count of data bytes; min = 2
                                    //            UCHAR Buffer[1];                    // Buffer containing:
                RemainingName
                                    //  4         //UCHAR BufferFormat;               //  0x04 -- ASCII
                                    //            //UCHAR FileName[];                 //  File name
             );


    MRxSmbDumpStufferState (700,"SMB w/ corecreate after stuffing",StufferState);
    //ASSERT(!"Now it's stuffed");

    Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                    SMBPSE_OETYPE_CORECREATE
                                    );

FINALLY:
    RxDbgTrace(-1, Dbg, ("MRxSmbCoreCreate exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}


NTSTATUS
MRxSmbCloseAfterCoreCreate(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
    )
/*++

Routine Description:

   This routine does a close.....

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


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

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;

    PSMBSTUFFER_BUFFER_STATE StufferState;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbCloseAfterCoreCreate entering.......OE=%08lx\n",OrdinaryExchange));
    StufferState = &OrdinaryExchange->AssociatedStufferState;

    ASSERT( StufferState );

    COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse,
                                SMB_COM_CLOSE,
                                SMB_REQUEST_SIZE(CLOSE),
                                NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                0,0,0,0 STUFFERTRACE(Dbg,'FC'))
                 );

    MRxSmbDumpStufferState (1100,"SMB w/ closeaftercorecreate before stuffing",StufferState);

    MRxSmbStuffSMB (StufferState,
         "0wdB!",
                                    //  0         UCHAR WordCount;                    // Count of parameter words = 3
                                    //  w         _USHORT( Fid );                     // File handle
             OrdinaryExchange->Create.FidReturnedFromCreate,
             0,                     //  d         _ULONG( LastWriteTimeInSeconds );   // Time of last write, low and high
             SMB_WCT_CHECK(3) 0     //  B         _USHORT( ByteCount );               // Count of data bytes = 0
                                    //            UCHAR Buffer[1];                    // empty
             );


    MRxSmbDumpStufferState (700,"SMB w/ closeaftercorecreate after stuffing",StufferState);
    //ASSERT(!"Now it's stuffed");

    Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                    SMBPSE_OETYPE_CLOSEAFTERCORECREATE
                                    );

FINALLY:
    RxDbgTrace(-1, Dbg, ("MRxSmbCloseAfterCoreCreate exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}


NTSTATUS
MRxSmbCoreTruncate(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
    ULONG Fid,
    ULONG FileTruncationPoint
    )
/*++

Routine Description:

   This routine does a truncate to implement FILE_OVERWRITE and FILE_OVERWRITE_IF.....
   it is also used in the "extend-for-cached-write" path.

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:


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

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;

    PSMBSTUFFER_BUFFER_STATE StufferState;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbCoreTruncate entering.......OE=%08lx\n",OrdinaryExchange));
    StufferState = &OrdinaryExchange->AssociatedStufferState;

    ASSERT( StufferState );

    COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse,
                                SMB_COM_WRITE,
                                SMB_REQUEST_SIZE(WRITE),
                                NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
                                0,0,0,0  STUFFERTRACE(Dbg,'FC'))
                 )

    MRxSmbDumpStufferState (1100,"SMB w/ coretruncate before stuffing",StufferState);

    MRxSmbStuffSMB (StufferState,
         "0wwdwByw!",
                                    //  0   UCHAR WordCount;                    // Count of parameter words = 5
             Fid,                   //  w   _USHORT( Fid );                     // File handle
             0,                     //  w   _USHORT( Count );                   // Number of bytes to be written
             FileTruncationPoint,   //  d   _ULONG( Offset );                   // Offset in file to begin write
             0,                     //  w   _USHORT( Remaining );               // Bytes remaining to satisfy request
             SMB_WCT_CHECK(5)       //  B   _USHORT( ByteCount );               // Count of data bytes
                                    //      //UCHAR Buffer[1];                  // Buffer containing:
             0x01,                  //  y     UCHAR BufferFormat;               //  0x01 -- Data block
             0                      //  w     _USHORT( DataLength );            //  Length of data
                                    //        ULONG Buffer[1];                  //  Data
             );


    MRxSmbDumpStufferState (700,"SMB w/ coretruncate after stuffing",StufferState);
    //ASSERT(!"Now it's stuffed");

    Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                    SMBPSE_OETYPE_CORETRUNCATE
                                    );

    if (Status == STATUS_SUCCESS) {
        LARGE_INTEGER FileSize;

        FileSize.HighPart = 0;
        FileSize.LowPart = FileTruncationPoint;

        MRxSmbUpdateFileInfoCacheFileSize(RxContext, &FileSize);
    } else {
        if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
            Status == STATUS_OBJECT_PATH_NOT_FOUND) {
             // create the name based file not found cache
            MRxSmbCacheFileNotFound(RxContext);
        } else {
             // invalid the name based file not found cache if other error happens
            MRxSmbInvalidateFileNotFoundCache(RxContext);

        }

        // invalid the name based file info cache
        MRxSmbInvalidateFileInfoCache(RxContext);

    }

FINALLY:
    RxDbgTrace(-1, Dbg, ("MRxSmbCoreTruncate exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}


NTSTATUS
MRxSmbDownlevelCreate(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
    )
/*++

Routine Description:

   This routine implements downlevel creates.

Arguments:

    OrdinaryExchange  - an exchange to be used for conducting this open.

Return Value:

    RXSTATUS - The return status for the operation

Notes:

    For core, in particular, this is pretty painful because a different smb must be used
    for different dispositions. In addition, we cannot really open a directory.

    By in large, we will follow a strategy similar to rdr1. If the openmode maps into something that
    a downlevel server won't understand then we don't really open the file.....we just do a GFA to ensure
    that it's there and hope that we can do path-based ops for the duration.

--*/
{
    NTSTATUS Status = RX_MAP_STATUS(NOT_IMPLEMENTED);

    RxCaptureFcb; //RxCaptureFobx;
    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
    PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
    PUNICODE_STRING PathName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
    PNT_CREATE_PARAMETERS cp = &RxContext->Create.NtCreateParameters;

    ULONG CreateOptions = cp->CreateOptions;
    ULONG FileAttributes =  cp->FileAttributes;
    ACCESS_MASK   DesiredAccess = cp->DesiredAccess;
    USHORT        ShareAccess = (USHORT)(cp->ShareAccess);
    ULONG         Disposition = cp->Disposition;

    USHORT mappedDisposition = MRxSmbMapDisposition(Disposition);
    USHORT mappedSharingMode = MRxSmbMapShareAccess(ShareAccess);
    USHORT mappedAttributes  = MRxSmbMapFileAttributes(FileAttributes);
    USHORT mappedOpenMode    = MRxSmbMapDesiredAccess(DesiredAccess);

    LARGE_INTEGER AllocationSize = cp->AllocationSize;

    PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);

    PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
    PSMBCE_SERVER pServer = SmbCeGetExchangeServer(Exchange);

    PSMBSTUFFER_BUFFER_STATE StufferState;

    BOOLEAN MustBeAFile = (MustBeFile(CreateOptions)!=0);
    BOOLEAN MustBeADirectory = (MustBeDirectory(CreateOptions)!=0)
                                    || BooleanFlagOn(RxContext->Create.Flags,RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH);
    BOOLEAN ItsADirectory = FALSE;
    BOOLEAN ItsTheShareRoot = FALSE;

    PAGED_CODE();
    
    // Down level protocols don't have the execute mode.
    if (mappedOpenMode == (USHORT)SMB_DA_ACCESS_EXECUTE)
        mappedOpenMode = (USHORT)SMB_DA_ACCESS_READ;

    RxDbgTrace(+1, Dbg, ("MRxSmbDownlevelCreate entering.......OE=%08lx\n",OrdinaryExchange));
    RxDbgTrace( 0, Dbg, ("mapAtt,Shr,Disp,OM %04lx,%04lx,%04lx,%04lx\n",
                                  mappedAttributes,mappedSharingMode,mappedDisposition,mappedOpenMode));

    SmbPseOEAssertConsistentLinkageFromOE("Downlevel Create:");

    StufferState = &OrdinaryExchange->AssociatedStufferState;

    if (OrdinaryExchange->Create.CreateWithEasSidsOrLongName) {
        Status = RX_MAP_STATUS(NOT_SUPPORTED);
        goto FINALLY;
    }

    if (AllocationSize.HighPart != 0) {
        //CODE.IMPROVEMENT why is the above a not-supported while this is a invalid-param??? joejoe
        Status = RX_MAP_STATUS(INVALID_PARAMETER);
        goto FINALLY;
    }


    ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
    OrdinaryExchange->Create.smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
    OrdinaryExchange->pPathArgument1 = PathName;

    //
    // we know that the root a share exists and that it's a directory....the catch is that GetFileAttributes
    // will return a NO_SUCH_FILE error for the root if it's really a root on the server. record this and use it
    // to our advantage later.
    if ((PathName->Length == 0)
           || ((PathName->Length == sizeof(WCHAR)) && (PathName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))  ) {
        //if must be a file, it's an error.........
        if (MustBeAFile) {
            Status = RX_MAP_STATUS(FILE_IS_A_DIRECTORY);
            goto FINALLY;
        }

        //
        //if it's the right kind of open, i can just finish up now. these opens are common for GetFSInfo

        if ((Disposition == FILE_OPEN) || (Disposition == FILE_OPEN_IF)) {
            Status = MRxSmbPseudoOpenTailFromFakeGFAResponse ( OrdinaryExchange, FileTypeDirectory );
            goto FINALLY;
        }
        MustBeADirectory = TRUE;   // we know it's a directory!
        ItsTheShareRoot = TRUE;
    }

    //// if all the user wants is attributes and it's a FILE_OPEN, don't do the open now....
    //// rather, we'll send pathbased ops later (or do a deferred open if necessary)...
    
    if (Disposition == FILE_OPEN && 
        (MustBeADirectory || 
         !(cp->DesiredAccess & ~(SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES)))) {
        Status = MRxSmbPseudoOpenTailFromFakeGFAResponse(OrdinaryExchange, MustBeADirectory?FileTypeDirectory:FileTypeFile);
        
        if (Status == STATUS_SUCCESS) {
            Status = MRxSmbQueryFileInformationFromPseudoOpen(
                         SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                         FileBasicInformation);

            if (Status == STATUS_SUCCESS) {
                if (MustBeADirectory && 
                    !OrdinaryExchange->Create.FileInfo.Standard.Directory) {
                    Status = STATUS_NOT_A_DIRECTORY;
                }

                if (MustBeAFile &&
                    OrdinaryExchange->Create.FileInfo.Standard.Directory) {
                    Status = STATUS_FILE_IS_A_DIRECTORY;
                }
            }

            if (Status != STATUS_SUCCESS) {
                RxFreePool(smbSrvOpen->DeferredOpenContext);
                smbSrvOpen->DeferredOpenContext = NULL;
            }
        }

        goto FINALLY;
    }

    if ( (mappedOpenMode == ((USHORT)-1)) ||
         (Disposition == FILE_SUPERSEDE) ||
         (!MustBeAFile)
       ) {

        //
        // go find out what's there.......

        Status = MRxSmbGetFileAttributes(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);

        if (Status == STATUS_SUCCESS && 
            MustBeADirectory &&
            !OrdinaryExchange->Create.FileInfo.Standard.Directory) {
            Status = STATUS_NOT_A_DIRECTORY;
            goto FINALLY;
        }
        
        RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate GFAorCPstatus=%08lx\n",Status));

        if (NT_SUCCESS(Status)) {
            ULONG Attributes = SmbGetUshort(&OrdinaryExchange->Create.FileInfo.Basic.FileAttributes);
            ItsADirectory = BooleanFlagOn(Attributes,SMB_FILE_ATTRIBUTE_DIRECTORY);
            RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate attributes=%08lx\n",Attributes));
            if ((Disposition==FILE_CREATE)) {
                Status = STATUS_OBJECT_NAME_COLLISION;
                goto FINALLY;
            }
            if (MustBeADirectory && !ItsADirectory && (Disposition!=FILE_SUPERSEDE)) {
                if (Disposition == FILE_OPEN) {
                    // This fix is required for the DFS driver which seems to handle
                    // STATUS_OBJECT_TYPE_MISMATCH in a special way.
                    // DFS should be fixed.
                    Status = STATUS_OBJECT_NAME_COLLISION;
                } else {
                    Status = STATUS_OBJECT_TYPE_MISMATCH;
                }
                goto FINALLY;
            }
            if (MustBeAFile && ItsADirectory && (Disposition!=FILE_SUPERSEDE)) {
                if (Disposition == FILE_OPEN) {
                    // This fix is required for the DFS driver which seems to handle
                    // STATUS_OBJECT_TYPE_MISMATCH in a special way.
                    // DFS should be fixed.
                    Status = STATUS_FILE_IS_A_DIRECTORY;
                } else {
                    Status = STATUS_OBJECT_TYPE_MISMATCH;
                }
                goto FINALLY;
            }
            //if (!MustBeAFile && ItsADirectory && (Disposition==FILE_OPEN)){
            if (Disposition==FILE_OPEN || Disposition==FILE_OPEN_IF){
                //we're done except to finish AND to set the flags in the srvopen
                MRxSmbPseudoOpenTailFromGFAResponse ( OrdinaryExchange );
                goto FINALLY;
            }
        } else if ( (Status!=STATUS_NO_SUCH_FILE)
                           && (Status!=STATUS_OBJECT_PATH_NOT_FOUND) ) {
            goto FINALLY;
        } else if ((Disposition==FILE_CREATE)
                     || (Disposition==FILE_OPEN_IF)
                     || (Disposition==FILE_OVERWRITE_IF)
                     || (Disposition==FILE_SUPERSEDE)) {
            //CODE.IMPROVEMENT doing this with four compares is ineficient; we should have a
            //                 table or something
            NOTHING;
        } else if (ItsTheShareRoot) {
            PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
            PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
            //here we have run into a true root....so we can't get attributes. fill in a fake
            //response and finish. also, flip the bit that says we can't gfa this guy.
            Status = MRxSmbPseudoOpenTailFromFakeGFAResponse ( OrdinaryExchange, FileTypeDirectory );
            smbSrvOpen->Flags |= SMB_SRVOPEN_FLAG_CANT_GETATTRIBS;
            goto FINALLY;
        } else {
            goto FINALLY;
        }
    }


    SmbCeResetExchange(&OrdinaryExchange->Exchange);  //must reset!

    if (NT_SUCCESS(Status) &&(Disposition == FILE_SUPERSEDE)) {
        //
        //we have to get rid of the existing entity...using a delete or a rmdir as appropriate
        Status = MRxSmbCoreDeleteForSupercedeOrClose(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                                      OrdinaryExchange->Create.FileInfo.Standard.Directory
                                                     );
        if (!NT_SUCCESS(Status)) {
            RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate could notsupersede st=%08lx\n",Status));
            goto FINALLY;
        }
        SmbCeResetExchange(&OrdinaryExchange->Exchange);  //must reset!
                                                                   //CODE.IMPROVEMENT there should be some way
                                                                   //that is more automatic than this
    }

    if (MustBeADirectory || (ItsADirectory &&(Disposition == FILE_SUPERSEDE)) ) {

        ASSERT (Disposition!=FILE_OPEN);
        Status = MRxSmbCoreCreateDirectory(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
        if (!NT_SUCCESS(Status)) {
            RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate couldn't mkdir st=%08lx\n",Status));
            goto FINALLY;
        }

        if ((mappedAttributes &
             (SMB_FILE_ATTRIBUTE_READONLY |
              SMB_FILE_ATTRIBUTE_HIDDEN   |
              SMB_FILE_ATTRIBUTE_SYSTEM   |
              SMB_FILE_ATTRIBUTE_ARCHIVE)) != 0) {
            //
            //we have to set the attributes
            Status = MRxSmbSetFileAttributes(
                         SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                         mappedAttributes);

            if (!NT_SUCCESS(Status)) {
                RxDbgTrace(0, Dbg, ("MRxSmbDownlevelCreate couldn't sfa st=%08lx\n",Status));
            }
        }

        MRxSmbPseudoOpenTailFromCoreCreateDirectory( OrdinaryExchange, mappedAttributes );

        goto FINALLY;
    }


    //if ( (mappedOpenMode != -1) && !MustBeADirectory) {
    //no pseudoOpens yet
    if ( TRUE ) {

        ULONG workingDisposition = Disposition;
        ULONG iterationcount;
        BOOLEAN MayNeedATruncate = FALSE;

       //
       // we use the disposition as a state and case out.....some are hard and some are easy
       //     for example, if it's CREATE then we use the CREATE_NEW to create the file but
       //                  the resulting open is no good so we close it and open it again using the
       //                  open. for OPEN_IF  we assume that the file will be there
       //                  and drop into create if it's not.

       for (iterationcount=0;;iterationcount++) {
           switch (workingDisposition) {
           case FILE_OVERWRITE:
           case FILE_OVERWRITE_IF:
               MayNeedATruncate = TRUE;
               //lack of break intentional
           case FILE_OPEN_IF:
           case FILE_OPEN:
               Status = MRxSmbCoreOpen(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                           mappedOpenMode|mappedSharingMode,
                                           mappedAttributes);
               //if (Status==RxStatus(NO_SUCH_FILE)) {
               //    DbgPrint("%08lx %08lx %08lx\n",Status,workingDisposition,iterationcount);
               //    DbgBreakPoint();
               //}
               if (!((workingDisposition == FILE_OPEN_IF) || (workingDisposition == FILE_OVERWRITE_IF))
                    || (Status!=RX_MAP_STATUS(NO_SUCH_FILE))
                    || (iterationcount>6)
                    )break;
               SmbCeResetExchange(&OrdinaryExchange->Exchange);  //must reset!
           case FILE_SUPERSEDE:
           case FILE_CREATE:
               Status = MRxSmbCoreCreate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                           mappedAttributes,TRUE); //(workingDisposition==FILE_CREATE));
               if (!NT_SUCCESS(Status)) {
                    RxDbgTrace(-1, Dbg, ("MRxSmbDownlevelCreate exiting.......createnew failed st=%08lx\n",Status));
                    break;
               }

               //now, we have a network handle. BUT, it's a compatibility-mode open. since we don't want that we
               //     need to close and reopen with the parameters specified. there is a window here! what can i do??

               Status = MRxSmbCloseAfterCoreCreate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
               if (!NT_SUCCESS(Status)) {
                    RxDbgTrace(-1, Dbg, ("MRxSmbDownlevelCreate exiting.......closeaftercreatenew failed st=%08lx\n",Status));
                    break;
               }

               workingDisposition = FILE_OPEN_IF;
               continue;     // this wraps back to the switch with a new disposition
               //break;
           //case FILE_SUPERSEDE:
           //    Status = RxStatus(NOT_SUPPORTED);
           //    break;
           default :
               ASSERT(!"Bad Disposition");
               Status = RX_MAP_STATUS(INVALID_PARAMETER);
           }
           break; //exit the loop
       }
       if (!NT_SUCCESS(Status))goto FINALLY;
       //we may need a truncate....this is different from rdr1.
       if (MayNeedATruncate
                 && !OrdinaryExchange->Create.FileWasCreated
                 && (OrdinaryExchange->Create.FileSizeReturnedFromOpen!=0)  ) {
           Status = MRxSmbCoreTruncate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
                                       OrdinaryExchange->Create.FidReturnedFromOpen,
                                       0
           );
       }
        
       goto FINALLY;
    }

FINALLY:
    RxDbgTrace(-1, Dbg, ("MRxSmbDownlevelCreate exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
    return(Status);
}

NTSTATUS
MRxSmbFinishGFA (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      PBYTE                       Response
      )
/*++

Routine Description:

    This routine copies the response to the GetFileAttributes SMB. But, it must be called synchronously.

Arguments:

    OrdinaryExchange - the exchange instance
    Response - the response

Return Value:

    RXSTATUS - The return status for the operation

Notes:

    what we do here is to put the data into the ordinary exchange...it's locked down do
    we could do this at DPC level

--*/
{
    NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
    PFILE_BASIC_INFORMATION BasicInformation = &OrdinaryExchange->Create.FileInfo.Basic;
    PFILE_STANDARD_INFORMATION StandardInformation = &OrdinaryExchange->Create.FileInfo.Standard;

    PSMB_PARAMS pSmbParams = (PSMB_PARAMS)Response;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbFinishGFA\n", 0 ));
    SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishGFA:");

    if (pSmbParams->WordCount == 10) {
        PRESP_QUERY_INFORMATION pQueryInformationResponse;

        pQueryInformationResponse = (PRESP_QUERY_INFORMATION)Response;

        //what we do here is to put the data into the ordinary exchange...it's locked down do
        //we wcould do this at DPC level

        MRxSmbPopulateFileInfoInOE(
            OrdinaryExchange,
            SmbGetUshort(&pQueryInformationResponse->FileAttributes),
            SmbGetUlong(&pQueryInformationResponse->LastWriteTimeInSeconds),
            SmbGetUlong(&pQueryInformationResponse->FileSize)
            );

    } else if (pSmbParams->WordCount == 11) {
        PRESP_QUERY_INFORMATION2 pQueryInformation2Response;
        SMB_TIME                 LastWriteSmbTime;
        SMB_DATE                 LastWriteSmbDate;
        LARGE_INTEGER            LastWriteTime;
        ULONG                    LastWriteTimeInSeconds;

        pQueryInformation2Response = (PRESP_QUERY_INFORMATION2)Response;

        RtlCopyMemory(
            &LastWriteSmbTime,
            &pQueryInformation2Response->LastWriteTime,
            sizeof(SMB_TIME));

        RtlCopyMemory(
            &LastWriteSmbDate,
            &pQueryInformation2Response->LastWriteDate,
            sizeof(SMB_DATE));

        LastWriteTime = MRxSmbConvertSmbTimeToTime(NULL,LastWriteSmbTime,LastWriteSmbDate);

        MRxSmbTimeToSecondsSince1970(
            &LastWriteTime,
            NULL,
            &LastWriteTimeInSeconds);

        MRxSmbPopulateFileInfoInOE(
            OrdinaryExchange,
            SmbGetUshort(&pQueryInformation2Response->FileAttributes),
            LastWriteTimeInSeconds,
            SmbGetUlong(&pQueryInformation2Response->FileDataSize)
            );
    }

    RxDbgTrace(-1, Dbg, ("MRxSmbFinishGFA   returning %08lx\n", Status ));
    return Status;
}

//CODE.IMPROVEMENT shouldn't this be in a .h file.....
NTSTATUS
MRxSmbCreateFileSuccessTail (
    PRX_CONTEXT  RxContext,
    PBOOLEAN MustRegainExclusiveResource,
    SMBFCB_HOLDING_STATE *SmbFcbHoldingState,
    RX_FILE_TYPE StorageType,
    SMB_FILE_ID Fid,
    ULONG ServerVersion,
    UCHAR OplockLevel,
    ULONG CreateAction,
    PSMBPSE_FILEINFO_BUNDLE FileInfo
    );

NTSTATUS
MRxSmbFinishCoreCreate (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      PRESP_CREATE                Response
      )
/*++

Routine Description:

    This routine copies the fid from a core create response. it does not finish the fcb......if a compatibility
    mode open is acceptable then it could.

Arguments:

    OrdinaryExchange - the exchange instance
    Response - the response

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = RX_MAP_STATUS(SUCCESS);

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbFinishCoreCreate\n", 0 ));
    SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishCoreCreate:");

    if (Response->WordCount != 1 ||
        SmbGetUshort(&Response->ByteCount) != 0) {
        Status = STATUS_INVALID_NETWORK_RESPONSE;
        OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
    } else {
        OrdinaryExchange->Create.FidReturnedFromCreate = SmbGetUshort(&Response->Fid);
        OrdinaryExchange->Create.FileWasCreated = TRUE;
        //notice that we didn't finish here! we should IFF a compatibilty-mode open is okay
    }

    RxDbgTrace(-1, Dbg, ("MRxSmbFinishCoreCreate   returning %08lx\n", Status ));
    return Status;
}

#define JUST_USE_THE_STUFF_IN_THE_OE (0xfbad)
VOID
MRxSmbPopulateFileInfoInOE(
    PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
    USHORT FileAttributes,
    ULONG LastWriteTimeInSeconds,
    ULONG FileSize
    )
{
    PFILE_BASIC_INFORMATION BasicInformation = &OrdinaryExchange->Create.FileInfo.Basic;
    PFILE_STANDARD_INFORMATION StandardInformation = &OrdinaryExchange->Create.FileInfo.Standard;

    BasicInformation->FileAttributes = MRxSmbMapSmbAttributes(FileAttributes);
    StandardInformation->NumberOfLinks = 1;
    BasicInformation->CreationTime.QuadPart = 0;
    BasicInformation->LastAccessTime.QuadPart = 0;
    MRxSmbSecondsSince1970ToTime(LastWriteTimeInSeconds,
                                 SmbCeGetExchangeServer(OrdinaryExchange),
                                 &BasicInformation->LastWriteTime);
    BasicInformation->ChangeTime.QuadPart = 0;
    StandardInformation->AllocationSize.QuadPart = FileSize; //rdr1 actually rounds up based of svr disk attribs
    StandardInformation->EndOfFile.QuadPart = FileSize;
    StandardInformation->Directory = BooleanFlagOn(BasicInformation->FileAttributes,FILE_ATTRIBUTE_DIRECTORY);
}


NTSTATUS
MRxSmbFinishCoreOpen (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      PRESP_OPEN                  Response
      )
/*++

Routine Description:

    This routine finishes a core open.

Arguments:

    OrdinaryExchange - the exchange instance
    Response - the response

Return Value:

    RXSTATUS - The return status for the operation

--*/
{

    NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
    PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
    PMRX_SRV_OPEN        SrvOpen = RxContext->pRelevantSrvOpen;
    PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
    PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;

    RX_FILE_TYPE StorageType;
    SMB_FILE_ID Fid;
    ULONG CreateAction;

    ULONG FileSize;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbFinishCoreOpen\n", 0 ));
    SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishCoreOpen:");

    if (Response->WordCount != 7 ||
        SmbGetUshort(&Response->ByteCount) != 0) {
        Status = STATUS_INVALID_NETWORK_RESPONSE;
        OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
        goto FINALLY;
    }

    StorageType = FileTypeFile;
    Fid = SmbGetUshort(&Response->Fid);
    OrdinaryExchange->Create.FidReturnedFromOpen = Fid;
    FileSize = OrdinaryExchange->Create.FileSizeReturnedFromOpen = SmbGetUlong(&Response->DataSize);

    CreateAction = (OrdinaryExchange->Create.FileWasCreated)?FILE_CREATED
                        : (OrdinaryExchange->Create.FileWasTruncated)?FILE_OVERWRITTEN
                        :FILE_OPENED;

    MRxSmbPopulateFileInfoInOE(
        OrdinaryExchange,
        SmbGetUshort(&Response->FileAttributes),
        SmbGetUlong(&Response->LastWriteTimeInSeconds),
        FileSize
        );

    pFileInfo->Basic.FileAttributes    = OrdinaryExchange->Create.FileInfo.Basic.FileAttributes;
    pFileInfo->Basic.CreationTime      = OrdinaryExchange->Create.FileInfo.Basic.CreationTime;
    pFileInfo->Basic.LastAccessTime    = OrdinaryExchange->Create.FileInfo.Basic.LastAccessTime;
    pFileInfo->Basic.LastWriteTime     = OrdinaryExchange->Create.FileInfo.Basic.LastWriteTime;
    pFileInfo->Basic.ChangeTime        = OrdinaryExchange->Create.FileInfo.Basic.ChangeTime;
    pFileInfo->Standard.NumberOfLinks  = OrdinaryExchange->Create.FileInfo.Standard.NumberOfLinks;
    pFileInfo->Standard.AllocationSize = OrdinaryExchange->Create.FileInfo.Standard.AllocationSize;
    pFileInfo->Standard.EndOfFile      = OrdinaryExchange->Create.FileInfo.Standard.EndOfFile;
    pFileInfo->Standard.Directory      = FALSE;

    //CODE.IMPROVEMENT we could save a bit of stack space by wrapping a struc around the args below....
    MRxSmbCreateFileSuccessTail (   RxContext,
                                    &OrdinaryExchange->Create.MustRegainExclusiveResource,
                                    &OrdinaryExchange->SmbFcbHoldingState,
                                    StorageType,
                                    Fid,
                                    OrdinaryExchange->ServerVersion,
                                    SMB_OPLOCK_LEVEL_NONE,
                                    CreateAction,
                                    pFileInfo);

FINALLY:
    IF_DEBUG{
        RxCaptureFcb;
        RxDbgTrace(-1, Dbg, ("MRxSmbFinishCoreOpen   returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState ));
    }
    return Status;
}

NTSTATUS
MRxSmbPseudoOpenTailFromCoreCreateDirectory (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      USHORT Attributes
      )
/*++

Routine Description:

    This routine finishes a core create directory. but, it is not called from the receive routine......

Arguments:

    OrdinaryExchange - the exchange instance

Return Value:

    RXSTATUS - The return status for the operation

--*/
{

    NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
    PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
    RxCaptureFobx;
    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
    PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
    PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;

    RX_FILE_TYPE StorageType;
    SMB_FILE_ID Fid;
    ULONG CreateAction;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbFinishCoreCreateDirectory\n", 0 ));
    SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishCoreCreateDirectory:");

    StorageType = FileTypeDirectory;
    Fid = 0xbadd;

    CreateAction = FILE_CREATED;
    MRxSmbPopulateFileInfoInOE(
        OrdinaryExchange,
        Attributes,
        0,
        0
        );

    pFileInfo->Basic.FileAttributes    = OrdinaryExchange->Create.FileInfo.Basic.FileAttributes;
    pFileInfo->Basic.CreationTime      = OrdinaryExchange->Create.FileInfo.Basic.CreationTime;
    pFileInfo->Basic.LastAccessTime    = OrdinaryExchange->Create.FileInfo.Basic.LastAccessTime;
    pFileInfo->Basic.LastWriteTime     = OrdinaryExchange->Create.FileInfo.Basic.LastWriteTime;
    pFileInfo->Basic.ChangeTime        = OrdinaryExchange->Create.FileInfo.Basic.ChangeTime;
    pFileInfo->Standard.NumberOfLinks  = OrdinaryExchange->Create.FileInfo.Standard.NumberOfLinks;
    pFileInfo->Standard.AllocationSize = OrdinaryExchange->Create.FileInfo.Standard.AllocationSize;
    pFileInfo->Standard.EndOfFile      = OrdinaryExchange->Create.FileInfo.Standard.EndOfFile;
    pFileInfo->Standard.Directory      = TRUE;

    //CODE.IMPROVEMENT we could save a bit of stack space by wrapping a struc around the args below....
    smbSrvOpen->Flags |=  SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN;  //this indicates a pseudoopen to success tail
    MRxSmbCreateFileSuccessTail (   RxContext,
                                    &OrdinaryExchange->Create.MustRegainExclusiveResource,
                                    &OrdinaryExchange->SmbFcbHoldingState,
                                    StorageType,
                                    Fid,
                                    OrdinaryExchange->ServerVersion,
                                    SMB_OPLOCK_LEVEL_NONE,
                                    CreateAction,
                                    pFileInfo);

    IF_DEBUG{
        RxCaptureFcb;
        RxDbgTrace(-1, Dbg, ("MRxSmbFinishCoreCreateDirectory   returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState ));
    }
    return Status;
}

NTSTATUS
MRxSmbPseudoOpenTailFromFakeGFAResponse (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      RX_FILE_TYPE StorageType
      )
/*++

Routine Description:

    This routine finishes a pseudoopen from faked up information. Basically, we fill in
    the information that would have been obtained on a GET_FILE_ATTRIBUTES smb and then call
    the PseudoOpenFromGFA routine

Arguments:

    OrdinaryExchange - the exchange instance
    StorageType - the type of thing that this is supposed to be. If it's supposed to be
                  a directory then we set the attributes bit in the GFA info.

Return Value:

    RXSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
    USHORT Attributes = 0;

    PAGED_CODE();

    RtlZeroMemory(
        &OrdinaryExchange->Create.FileInfo,
        sizeof(OrdinaryExchange->Create.FileInfo));

    if (StorageType == FileTypeDirectory) {
        Attributes = SMB_FILE_ATTRIBUTE_DIRECTORY;
    }

    MRxSmbPopulateFileInfoInOE(OrdinaryExchange,Attributes,0,0);
    OrdinaryExchange->Create.StorageTypeFromGFA = StorageType;

    return( MRxSmbPseudoOpenTailFromGFAResponse (OrdinaryExchange) );
}


NTSTATUS
MRxSmbPseudoOpenTailFromGFAResponse (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange
      )
/*++

Routine Description:

    This routine finishes a pseudoopen from the information obtained on a
    GET_FILE_ATTRIBUTES smb.

Arguments:

    OrdinaryExchange - the exchange instance

Return Value:

    RXSTATUS - The return status for the operation

--*/
{

    NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
    PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
    PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
    PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;

    SMB_FILE_ID Fid;
    ULONG CreateAction;

    PAGED_CODE();

    RxDbgTrace(+1, Dbg, ("MRxSmbFinishPseudoOpenFromGFAResponse\n"));
    SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishPseudoOpenFromGFAResponse:");

    Fid = 0xbadd;

    CreateAction = FILE_OPENED;

    pFileInfo->Basic.FileAttributes    = OrdinaryExchange->Create.FileInfo.Basic.FileAttributes;
    pFileInfo->Basic.CreationTime      = OrdinaryExchange->Create.FileInfo.Basic.CreationTime;
    pFileInfo->Basic.LastAccessTime    = OrdinaryExchange->Create.FileInfo.Basic.LastAccessTime;
    pFileInfo->Basic.LastWriteTime     = OrdinaryExchange->Create.FileInfo.Basic.LastWriteTime;
    pFileInfo->Basic.ChangeTime        = OrdinaryExchange->Create.FileInfo.Basic.ChangeTime;
    pFileInfo->Standard.NumberOfLinks  = OrdinaryExchange->Create.FileInfo.Standard.NumberOfLinks;
    pFileInfo->Standard.AllocationSize = OrdinaryExchange->Create.FileInfo.Standard.AllocationSize;
    pFileInfo->Standard.EndOfFile      = OrdinaryExchange->Create.FileInfo.Standard.EndOfFile;
    pFileInfo->Standard.Directory      = (OrdinaryExchange->Create.StorageTypeFromGFA == FileTypeDirectory);

    //CODE.IMPROVEMENT we could save a bit of stack space by wrapping a struc around the args below....
    //  it seems to me that everything but the fid coudl be done that way and the success tail routine
    //  moved to the wrapper
    smbSrvOpen->Flags |=  SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN;  //this indicates a pseudoopen to success tail
    MRxSmbCreateFileSuccessTail (   RxContext,
                                    &OrdinaryExchange->Create.MustRegainExclusiveResource,
                                    &OrdinaryExchange->SmbFcbHoldingState,
                                    OrdinaryExchange->Create.StorageTypeFromGFA,
                                    Fid,
                                    OrdinaryExchange->ServerVersion,
                                    SMB_OPLOCK_LEVEL_NONE,
                                    CreateAction,
                                    pFileInfo);

    if (smbSrvOpen->DeferredOpenContext == NULL) {
        // if it is a remote boot server file, it already has a deferred open context created
        // on MRxSmbCreateFileSuccessTail
        Status = MRxSmbConstructDeferredOpenContext(RxContext);
    } else {
        // The flag has been cleared when a deferred open context was created for a remote boot server file.
        SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN);
    }

    if (Status!=STATUS_SUCCESS) {
        RxDbgTrace(-1, Dbg, ("MRxSmbFinishPseudoOpenFromGFAResponse construct dfo failed %08lx \n",Status));
    }

    IF_DEBUG{
        RxCaptureFcb;
        RxDbgTrace(-1, Dbg, ("MRxSmbFinishPseudoOpenFromGFAResponse   returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState ));
    }
    return Status;
}

LARGE_INTEGER
MRxSmbConvertSmbTimeToTime (
    //IN PSMB_EXCHANGE Exchange OPTIONAL,
    IN PSMBCE_SERVER Server OPTIONAL,
    IN SMB_TIME Time,
    IN SMB_DATE Date
    )

/*++

Routine Description:

    This routine converts an SMB time to an NT time structure.

Arguments:

    IN SMB_TIME Time - Supplies the time of day to convert
    IN SMB_DATE Date - Supplies the day of the year to convert
    IN supplies the server for tz bias.

Return Value:

    LARGE_INTEGER - Time structure describing input time.


--*/

{
    TIME_FIELDS TimeFields;
    LARGE_INTEGER OutputTime;

    PAGED_CODE();

    //
    // This routine cannot be paged because it is called from both the
    // MRxSmbFileDiscardableSection and the MRxSmbVCDiscardableSection.
    //

    if (SmbIsTimeZero(&Date) && SmbIsTimeZero(&Time)) {
        OutputTime.LowPart = OutputTime.HighPart = 0;
    } else {
        TimeFields.Year = Date.Struct.Year + (USHORT )1980;
        TimeFields.Month = Date.Struct.Month;
        TimeFields.Day = Date.Struct.Day;

        TimeFields.Hour = Time.Struct.Hours;
        TimeFields.Minute = Time.Struct.Minutes;
        TimeFields.Second = Time.Struct.TwoSeconds*(USHORT )2;
        TimeFields.Milliseconds = 0;

        //
        //  Make sure that the times specified in the SMB are reasonable
        //  before converting them.
        //

        if (TimeFields.Year < 1601) {
            TimeFields.Year = 1601;
        }

        if (TimeFields.Month > 12) {
            TimeFields.Month = 12;
        }

        if (TimeFields.Hour >= 24) {
            TimeFields.Hour = 23;
        }
        if (TimeFields.Minute >= 60) {
            TimeFields.Minute = 59;
        }
        if (TimeFields.Second >= 60) {
            TimeFields.Second = 59;

        }

        if (!RtlTimeFieldsToTime(&TimeFields, &OutputTime)) {
            OutputTime.HighPart = 0;
            OutputTime.LowPart = 0;

            return OutputTime;
        }

#ifndef WIN9X
        if (ARGUMENT_PRESENT(Server)) {
            OutputTime.QuadPart = OutputTime.QuadPart + Server->TimeZoneBias.QuadPart;
        }

        ExLocalTimeToSystemTime(&OutputTime, &OutputTime);
#else
        OutputTime.HighPart = 0;
        OutputTime.LowPart = 0;
#endif

    }

    return OutputTime;

}

BOOLEAN
MRxSmbConvertTimeToSmbTime (
    IN PLARGE_INTEGER InputTime,
    IN PSMB_EXCHANGE Exchange OPTIONAL,
    OUT PSMB_TIME Time,
    OUT PSMB_DATE Date
    )

/*++

Routine Description:

    This routine converts an NT time structure to an SMB time.

Arguments:

    IN LARGE_INTEGER InputTime - Supplies the time to convert.
    OUT PSMB_TIME Time - Returns the converted time of day.
    OUT PSMB_DATE Date - Returns the converted day of the year.


Return Value:

    BOOLEAN - TRUE if input time could be converted.


--*/

{
    TIME_FIELDS TimeFields;

    PAGED_CODE();

    if (InputTime->LowPart == 0 && InputTime->HighPart == 0) {
        Time->Ushort = Date->Ushort = 0;
    } else {
        LARGE_INTEGER LocalTime;

        ExSystemTimeToLocalTime(InputTime, &LocalTime);

        if (ARGUMENT_PRESENT(Exchange)) {
            PSMBCE_SERVER Server = SmbCeGetExchangeServer(Exchange);
            LocalTime.QuadPart -= Server->TimeZoneBias.QuadPart;
        }

        RtlTimeToTimeFields(&LocalTime, &TimeFields);

        if (TimeFields.Year < 1980) {
            return FALSE;
        }

        Date->Struct.Year = (USHORT )(TimeFields.Year - 1980);
        Date->Struct.Month = TimeFields.Month;
        Date->Struct.Day = TimeFields.Day;

        Time->Struct.Hours = TimeFields.Hour;
        Time->Struct.Minutes = TimeFields.Minute;

        //
        //  When converting from a higher granularity time to a lesser
        //  granularity time (seconds to 2 seconds), always round up
        //  the time, don't round down.
        //

        Time->Struct.TwoSeconds = (TimeFields.Second + (USHORT)1) / (USHORT )2;

    }

    return TRUE;
}


BOOLEAN
MRxSmbTimeToSecondsSince1970 (
    IN PLARGE_INTEGER CurrentTime,
    IN PSMBCE_SERVER Server OPTIONAL,
    OUT PULONG SecondsSince1970
    )
/*++

Routine Description:

    This routine returns the CurrentTime in UTC and returns the
    equivalent current time in the servers timezone.


Arguments:

    IN PLARGE_INTEGER CurrentTime - Supplies the current system time in UTC.

    IN PSMBCE_SERVER Server       - Supplies the difference in timezones between
                                    the server and the workstation. If not supplied
                                    then the assumption is that they are in the
                                    same timezone.

    OUT PULONG SecondsSince1970   - Returns the # of seconds since 1970 in
                                    the servers timezone or MAXULONG if conversion
                                    fails.

Return Value:

    BOOLEAN - TRUE if the time could be converted.

--*/
{
    LARGE_INTEGER ServerTime;
    LARGE_INTEGER TempTime;
    BOOLEAN ReturnValue;

    PAGED_CODE();

    if (ARGUMENT_PRESENT(Server) &&
        ((*CurrentTime).QuadPart != 0)) {

        TempTime.QuadPart = (*CurrentTime).QuadPart - Server->TimeZoneBias.QuadPart;

        ExSystemTimeToLocalTime(&TempTime, &ServerTime);
    } else {
        ExSystemTimeToLocalTime(CurrentTime, &ServerTime);
    }

    ReturnValue = RtlTimeToSecondsSince1970(&ServerTime, SecondsSince1970);

    if ( ReturnValue == FALSE ) {
        //
        //  We can't represent the time legally, peg it at
        //  the max legal time.
        //

        *SecondsSince1970 = MAXULONG;
    }

    return ReturnValue;
}

VOID
MRxSmbSecondsSince1970ToTime (
    IN ULONG SecondsSince1970,
    //IN PSMB_EXCHANGE Exchange OPTIONAL,
    IN PSMBCE_SERVER Server,
    OUT PLARGE_INTEGER CurrentTime
    )
/*++

Routine Description:

    This routine returns the Local system time derived from a time
    in seconds in the servers timezone.


Arguments:

    IN ULONG SecondsSince1970 - Supplies the # of seconds since 1970 in
                                servers timezone.

    IN PSMB_EXCHANGE Exchange - Supplies the difference in timezones between
                                the server and the workstation. If not supplied
                                then the assumption is that they are in the
                                same timezone.

    OUT PLARGE_INTEGER CurrentTime - Returns the current system time in UTC.

Return Value:

    None.


--*/

{
    LARGE_INTEGER LocalTime;

    PAGED_CODE();

    RtlSecondsSince1970ToTime (SecondsSince1970, &LocalTime);

    ExLocalTimeToSystemTime(&LocalTime, CurrentTime);

    if (ARGUMENT_PRESENT(Server)) {
        (*CurrentTime).QuadPart = (*CurrentTime).QuadPart + Server->TimeZoneBias.QuadPart;
    }

    return;

}

ULONG
MRxSmbMapSmbAttributes (
    IN USHORT SmbAttribs
    )

/*++

Routine Description:

    This routine maps an SMB (DOS/OS2) file attribute into an NT
    file attribute.


Arguments:

    IN USHORT SmbAttribs - Supplies the SMB attribute to map.


Return Value:

    ULONG - NT Attribute mapping SMB attribute


--*/

{
    ULONG Attributes = 0;

    PAGED_CODE();

    if (SmbAttribs==0) {
        Attributes = FILE_ATTRIBUTE_NORMAL;
    } else {

        ASSERT (SMB_FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY);
        ASSERT (SMB_FILE_ATTRIBUTE_HIDDEN == FILE_ATTRIBUTE_HIDDEN);
        ASSERT (SMB_FILE_ATTRIBUTE_SYSTEM == FILE_ATTRIBUTE_SYSTEM);
        ASSERT (SMB_FILE_ATTRIBUTE_ARCHIVE == FILE_ATTRIBUTE_ARCHIVE);
        ASSERT (SMB_FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY);

        Attributes = SmbAttribs & FILE_ATTRIBUTE_VALID_FLAGS;
    }
    return Attributes;
}

USHORT
MRxSmbMapDisposition (
    IN ULONG Disposition
    )

/*++

Routine Description:

    This routine takes an NT disposition, and maps it into an OS/2
    CreateAction to be put into an SMB.


Arguments:

    IN ULONG Disposition - Supplies the NT disposition to map.


Return Value:

    USHORT - OS/2 Access mapping that maps NT access

--*/

{
    PAGED_CODE();

    switch (Disposition) {
    case FILE_OVERWRITE_IF:
    case FILE_SUPERSEDE:
        return SMB_OFUN_OPEN_TRUNCATE | SMB_OFUN_CREATE_CREATE;
        break;

    case FILE_CREATE:
        return SMB_OFUN_OPEN_FAIL | SMB_OFUN_CREATE_CREATE;
        break;

    case FILE_OVERWRITE:
        return SMB_OFUN_OPEN_TRUNCATE | SMB_OFUN_CREATE_FAIL;
        break;

    case FILE_OPEN:
        return SMB_OFUN_OPEN_OPEN | SMB_OFUN_CREATE_FAIL;
        break;

    case FILE_OPEN_IF:
        return SMB_OFUN_OPEN_OPEN | SMB_OFUN_CREATE_CREATE;
        break;

    default:
        //InternalError(("Unknown disposition passed to MRxSmbMapDisposition"));
        //MRxSmbInternalError(EVENT_RDR_DISPOSITION);
        return 0;
        break;
    }
}


ULONG
MRxSmbUnmapDisposition (
    IN USHORT SmbDisposition,
    ULONG     Disposition
    )

/*++

Routine Description:

    This routine takes an OS/2 disposition and maps it into an NT
    disposition.

Arguments:

    IN USHORT SmbDisposition - Supplies the OS/2 disposition to map.

Return Value:

    ULONG - NT disposition mapping OS/2 disposition

--*/

{
    ULONG MapDisposition;

    PAGED_CODE();

    //
    //  Mask off oplocked bit.
    //

    switch (SmbDisposition & 0x7fff) {

    case SMB_OACT_OPENED:
        MapDisposition = FILE_OPENED;
        break;

    case SMB_OACT_CREATED:
        MapDisposition = FILE_CREATED;
        break;

    case SMB_OACT_TRUNCATED:
        MapDisposition = FILE_OVERWRITTEN;
        break;

    default:
        MapDisposition = Disposition;
    }

    return MapDisposition;
}


USHORT
MRxSmbMapDesiredAccess (
    IN ULONG DesiredAccess
    )

/*++

Routine Description:

    This routine takes an NT DesiredAccess value and converts it
    to an OS/2 access mode.


Arguments:

    IN ULONG DesiredAccess - Supplies the NT desired access to map.

Return Value:

    USHORT - The mapped OS/2 access mode that compares to the NT code
        specified.  If there is no mapping for the NT code, we return
        -1 as the access mode.

--*/

{
    PAGED_CODE();

    //
    //  If the user asked for both read and write access, return read/write.
    //

    if ((DesiredAccess & FILE_READ_DATA)&&(DesiredAccess & FILE_WRITE_DATA)) {
        return SMB_DA_ACCESS_READ_WRITE;
    }

    //
    //  If the user requested WRITE_DATA, return write.
    //

    if (DesiredAccess & FILE_WRITE_DATA) {
        return SMB_DA_ACCESS_WRITE;
    }

    //
    //  If the user requested READ_DATA, return read.
    //
    if (DesiredAccess & FILE_READ_DATA) {
        return SMB_DA_ACCESS_READ;
    }

    //
    //  If the user requested ONLY execute access, then request execute
    //  access.  Execute access is the "weakest" of the possible desired
    //  accesses, so it takes least precedence.
    //

    if (DesiredAccess & FILE_EXECUTE) {
        return  SMB_DA_ACCESS_EXECUTE;
    }

    //
    //  If we couldn't figure out what we were doing, return -1
    //
    //  Among the attributes that we do not map are:
    //
    //          FILE_READ_ATTRIBUTES
    //          FILE_WRITE_ATTRIBUTES
    //          FILE_READ_EAS
    //          FILE_WRITE_EAS
    //

//    dprintf(DPRT_ERROR, ("Could not map DesiredAccess of %08lx\n", DesiredAccess));

    return (USHORT)0;
}

USHORT
MRxSmbMapShareAccess (
    IN USHORT ShareAccess
    )

/*++

Routine Description:

    This routine takes an NT ShareAccess value and converts it to an
    OS/2 sharing mode.


Arguments:

    IN USHORT ShareAccess - Supplies the OS/2 share access to map.

Return Value:

    USHORT - The mapped OS/2 sharing mode that compares to the NT code
        specified

--*/

{
    USHORT ShareMode =  SMB_DA_SHARE_EXCLUSIVE;

    PAGED_CODE();

    if ((ShareAccess & (FILE_SHARE_READ | FILE_SHARE_WRITE)) ==
                       (FILE_SHARE_READ | FILE_SHARE_WRITE)) {
        ShareMode = SMB_DA_SHARE_DENY_NONE;
    } else if (ShareAccess & FILE_SHARE_READ) {
        ShareMode = SMB_DA_SHARE_DENY_WRITE;
    } else if (ShareAccess & FILE_SHARE_WRITE) {
        ShareMode = SMB_DA_SHARE_DENY_READ;
    }

//    else if (ShareAccess & FILE_SHARE_DELETE) {
//      InternalError(("Support for FILE_SHARE_DELETE NYI\n"));
//    }

    return ShareMode;

}

USHORT
MRxSmbMapFileAttributes (
    IN ULONG FileAttributes
    )

/*++

Routine Description:

    This routine takes an NT file attribute mapping and converts it into
    an OS/2 file attribute definition.


Arguments:

    IN ULONG FileAttributes - Supplies the file attributes to map.


Return Value:

USHORT

--*/

{
    USHORT ResultingAttributes = 0;

    PAGED_CODE();

    if (FileAttributes==FILE_ATTRIBUTE_NORMAL) {
        return ResultingAttributes;
    }

    if (FileAttributes & FILE_ATTRIBUTE_READONLY) {
        ResultingAttributes |= SMB_FILE_ATTRIBUTE_READONLY;
    }

    if (FileAttributes & FILE_ATTRIBUTE_HIDDEN) {
        ResultingAttributes |= SMB_FILE_ATTRIBUTE_HIDDEN;
    }

    if (FileAttributes & FILE_ATTRIBUTE_SYSTEM) {
        ResultingAttributes |= SMB_FILE_ATTRIBUTE_SYSTEM;
    }
    if (FileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
        ResultingAttributes |= SMB_FILE_ATTRIBUTE_ARCHIVE;
    }
    return ResultingAttributes;
}

