2025-04-27 07:49:33 -04:00

1382 lines
40 KiB
C

/*++
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.
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_CREATE)
//
// forward declarations
//
NTSTATUS
SmbPseExchangeStart_Create(
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
);
NTSTATUS
SmbPseExchangeStart_Close(
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
);
NTSTATUS
MRxSmbDownlevelCreate(
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
);
ULONG MRxSmbInitialSrvOpenFlags = 0;
#ifndef FORCE_SMALL_BUFFERS
ULONG MrxSmbLongestShortName = 0xffff; //use size calculated from the negotiated size
ULONG MrxSmbCreateTransactPacketSize = 0xffff; //use the negotiated size
#else
ULONG MrxSmbLongestShortName = 0;
ULONG MrxSmbCreateTransactPacketSize = 100;
#endif
NTSTATUS
MRxIfsCreate(
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;
RX_BLOCK_CONDITION FinalSrvOpenCondition;
PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen;
PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = NULL;
PSMBCEDB_SERVER_ENTRY pServerEntry;
ULONG DialectFlags;
PUNICODE_STRING RemainingName = &(capFcb->AlreadyPrefixedName);
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCreate\n", 0 ));
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
RxDbgTrace( 0, Dbg, (" Attempt to open %wZ\n", &(capFcb->AlreadyPrefixedName) ));
if ((NetRoot->Type == NET_ROOT_DISK) ||
(NetRoot->Type == NET_ROOT_PRINT) ||
(NetRoot->Type == NET_ROOT_WILD) ||
((NetRoot->Type != NET_ROOT_MAILSLOT) &&
(RemainingName->Length > sizeof(WCHAR)))) {
Status = STATUS_SUCCESS;
//
// Get the dialect flags from the server
//
pServerEntry = SmbCeReferenceAssociatedServerEntry(SrvCall);
ASSERT(pServerEntry != NULL);
DialectFlags = pServerEntry->Server.DialectFlags;
SmbCeDereferenceServerEntry(pServerEntry);
//get rid of nonEA guys right now
if (RxContext->Create.EaLength && !FlagOn(DialectFlags,DF_SUPPORTEA)) {
RxDbgTrace(-1, Dbg, ("EAs w/o EA support!\n"));
return((STATUS_NOT_SUPPORTED));
}
OrdinaryExchange = SmbPseCreateOrdinaryExchange(RxContext,
SrvOpen->pVNetRoot,
SMBPSE_OE_FROM_CREATE,
SmbPseExchangeStart_Create
);
if (OrdinaryExchange==NULL) {
RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
return((STATUS_INSUFFICIENT_RESOURCES));
}
//
// We don't support Eas, Sids or LongNames in this example minirdr
//
OrdinaryExchange->Create.CreateWithEasSidsOrLongName = FALSE;
// For Creates, the resources need to be reacquired after sending an
// SMB; so, do not hold onto the MIDS till finalization; instead give the MID back
// right away
OrdinaryExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_REUSE_MID;
OrdinaryExchange->SmbCeFlags |= SMBCE_EXCHANGE_ATTEMPT_RECONNECTS;
OrdinaryExchange->pSmbCeSynchronizationEvent = &RxContext->SyncEvent;
//drop the resource before you go in! the start routine will reacquire it on the way out.....
RxReleaseFcb( RxContext, capFcb );
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
ASSERT((Status != STATUS_SUCCESS) || RxIsFcbAcquiredExclusive( capFcb ));
if (!RxIsFcbAcquiredExclusive(capFcb)) {
ASSERT(!RxIsFcbAcquiredShared(capFcb));
RxAcquireExclusiveFcb( RxContext, capFcb );
}
OrdinaryExchange->pSmbCeSynchronizationEvent = NULL;
FinalSrvOpenCondition = ((Status == STATUS_SUCCESS)
? OrdinaryExchange->Create.FinalCondition
: Condition_Bad);
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
} else {
RxFinishFcbInitialization( capFcb, RDBSS_NTC_MAILSLOT, NULL);
Status = STATUS_SUCCESS;
}
ASSERT(Status != (STATUS_PENDING));
ASSERT(RxIsFcbAcquiredExclusive( capFcb ));
RxDbgTrace(-1, Dbg, ("MRxSmbCreate exit with status=%08lx\n", Status ));
return(Status);
}
NTSTATUS
MRxIfsCollapseOpen(
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;
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
MRxIfsComputeNewBufferingState(
IN OUT PMRX_SRV_OPEN pMRxSrvOpen,
IN PVOID pMRxContext,
OUT PULONG pNewBufferingState)
/*++
Routine Description:
This routine maps the SMB 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;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(pMRxSrvOpen);
ASSERT(pNewBufferingState != NULL);
OplockLevel = (ULONG)pMRxContext;
if (OplockLevel == SMB_OPLOCK_LEVEL_II) {
*pNewBufferingState = (FCB_STATE_READBUFFERING_ENABLED |
FCB_STATE_READCACHEING_ENABLED);
} else {
*pNewBufferingState = 0;
}
pMRxSrvOpen->BufferingFlags = *pNewBufferingState;
return STATUS_SUCCESS;
}
typedef struct _MRXSMB_CREATE_PARAMETERS {
UCHAR SecurityFlags;
} MRXSMB_CREATE_PARAMETERS, *PMRXSMB_CREATE_PARAMETERS;
VOID
MRxSmbAdjustCreateParameters (
PRX_CONTEXT RxContext,
PMRXSMB_CREATE_PARAMETERS smbcp
)
/*++
Routine Description:
This uses the RxContext as a base to reeach out and get the values of the NT create parameters.
It also (a) implements the SMB idea that unbuffered is translated to write-through and (b) gets
the SMB security flags.
Arguments:
Return Value:
Notes:
--*/
{
PNT_CREATE_PARAMETERS cp = &RxContext->Create.NtCreateParameters;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbAdjustCreateParameters\n"));
cp->CreateOptions = cp->CreateOptions & ~(FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT);
//the NT SMB spec says we have to change no-intermediate-buffering to write-through
if (FlagOn(cp->CreateOptions,FILE_NO_INTERMEDIATE_BUFFERING)) {
ASSERT (RxContext->CurrentIrpSp!=NULL);
if (RxContext->CurrentIrpSp!=NULL) {
PFILE_OBJECT capFileObject = RxContext->CurrentIrpSp->FileObject;
ClearFlag(cp->CreateOptions,FILE_NO_INTERMEDIATE_BUFFERING);
SetFlag(cp->CreateOptions,FILE_WRITE_THROUGH);
SetFlag(RxContext->Flags,RX_CONTEXT_FLAG_WRITE_THROUGH);
SetFlag(capFileObject->Flags,FO_WRITE_THROUGH);
}
}
smbcp->SecurityFlags = 0;
if (cp->SecurityContext->SecurityQos != NULL) {
if (cp->SecurityContext->SecurityQos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING) {
smbcp->SecurityFlags |= SMB_SECURITY_DYNAMIC_TRACKING;
}
if (cp->SecurityContext->SecurityQos->EffectiveOnly) {
smbcp->SecurityFlags |= SMB_SECURITY_EFFECTIVE_ONLY;
}
}
RxDbgTrace(-1, Dbg, ("MRxSmbAdjustCreateParameters\n"));
}
VOID
MRxSmbAdjustReturnedCreateAction(
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine repairs a bug in NT servers whereby the create action is contaminated
by an oplock break. Basically, we make sure that if the guy asked for FILE_OPEN and it
works then he does not get FILE_SUPERCEDED or FILE_CREATED as the result.
Arguments:
RxContext - the context for the operation so as to find the place where info is returned
Return Value:
none
Notes:
--*/
{
ULONG q = RxContext->Create.ReturnedCreateInformation;
if ((q==FILE_SUPERSEDED)||(q==FILE_CREATED)) {
RxContext->Create.ReturnedCreateInformation = FILE_OPENED;
}
}
NTSTATUS
MRxSmbBuildOpenAndX (
PSMBSTUFFER_BUFFER_STATE StufferState,
PMRXSMB_CREATE_PARAMETERS smbcp
)
/*++
Routine Description:
This builds an NtCreateAndX SMB. we don't have to worry about login id and such
since that is done by the connection engine....pretty neat huh? all we have to do
is to format up the bits
Arguments:
StufferState - the state of the smbbuffer from the stuffer's point of view
Return Value:
RXSTATUS
SUCCESS
NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
Notes:
--*/
{
NTSTATUS Status;
PRX_CONTEXT RxContext = StufferState->RxContext;
PNT_CREATE_PARAMETERS cp = &RxContext->Create.NtCreateParameters;
PSMB_EXCHANGE Exchange = StufferState->Exchange;
RxCaptureFcb;
PUNICODE_STRING RemainingName;
PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen;
USHORT smbDisposition;
USHORT smbSharingMode;
USHORT smbAttributes;
ULONG smbFileSize;
USHORT smbOpenMode;
USHORT OpenAndXFlags = SMB_OPEN_QUERY_INFORMATION;
USHORT SearchAttributes = SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN;
LARGE_INTEGER CurrentTime;
ULONG SecondsSince1970;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbBuildOpenAndX\n", 0 ));
smbDisposition = MRxSmbMapDisposition(cp->Disposition);
smbSharingMode = MRxSmbMapShareAccess(((USHORT)cp->ShareAccess));
smbAttributes = MRxSmbMapFileAttributes(cp->FileAttributes);
smbFileSize = cp->AllocationSize.LowPart;
smbOpenMode = MRxSmbMapDesiredAccess(cp->DesiredAccess);
smbSharingMode |= smbOpenMode;
if (cp->CreateOptions & FILE_WRITE_THROUGH) {
smbSharingMode |= SMB_DA_WRITE_THROUGH;
}
//lanman10 servers apparently don't like to get the time passed in.......
if (FlagOn(Exchange->SmbCeContext.pServerEntry->Server.DialectFlags,DF_LANMAN20)) {
KeQuerySystemTime(&CurrentTime);
MRxSmbTimeToSecondsSince1970(&CurrentTime,
MRxSmbExchangeToServer(StufferState->Exchange),
&SecondsSince1970);
} else {
SecondsSince1970 = 0;
}
RemainingName = &(capFcb->AlreadyPrefixedName);
COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_Never,
SMB_COM_OPEN_ANDX, SMB_REQUEST_SIZE(OPEN_ANDX),
NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(4,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
);
MRxSmbStuffSMB (StufferState,
"XwwwwdwDddB",
// X UCHAR WordCount; // Count of parameter words = 15
// . UCHAR AndXCommand; // Secondary (X) command; 0xFF = none
// . UCHAR AndXReserved; // Reserved (must be 0)
// . _USHORT( AndXOffset ); // Offset to next command WordCount
OpenAndXFlags, // w _USHORT( Flags ); // Additional information: bit set-
// // 0 - return additional info
// // 1 - set single user total file lock
// // 2 - server notifies consumer of
// // actions which may change file
smbSharingMode, // w _USHORT( DesiredAccess ); // File open mode
SearchAttributes, // w _USHORT( SearchAttributes );
smbAttributes, // w _USHORT( FileAttributes );
SecondsSince1970, // d _ULONG( CreationTimeInSeconds );
smbDisposition, // w _USHORT( OpenFunction );
// D _ULONG( AllocationSize ); // Bytes to reserve on create or truncate
SMB_OFFSET_CHECK(OPEN_ANDX,AllocationSize)
smbFileSize,
0xffffffff, // d _ULONG( Timeout ); // Max milliseconds to wait for resource
0, // d _ULONG( Reserved ); // Reserved (must be 0)
SMB_WCT_CHECK(15) 0 // B _USHORT( ByteCount ); // Count of data bytes; min = 1
// UCHAR Buffer[1]; // File name
);
//proceed with the stuff because we know here that the name fits
MRxSmbStuffSMB (StufferState,"z!", RemainingName);
FINALLY:
RxDbgTraceUnIndent(-1,Dbg);
return(Status);
}
NTSTATUS
MRxSmbBuildOpenPrintFile (
PSMBSTUFFER_BUFFER_STATE StufferState
)
/*++
Routine Description:
This builds an OpenPrintFile SMB. we don't have to worry about login id and such
since that is done by the connection engine....pretty neat huh? all we have to do
is to format up the bits
Arguments:
StufferState - the state of the smbbuffer from the stuffer's point of view
Return Value:
RXSTATUS
SUCCESS
NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
Notes:
--*/
{
NTSTATUS Status;
PRX_CONTEXT RxContext = StufferState->RxContext;
//RxCaptureFcb;
PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen;
WCHAR UserNameBuffer[UNLEN + 1];
WCHAR UserDomainNameBuffer[UNLEN + 1];
UNICODE_STRING UserName,UserDomainName;
//UNICODE_STRING IdString;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbOpenPrintFile\n", 0 ));
//ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
UserName.Length = UserName.MaximumLength = UNLEN * sizeof(WCHAR);
UserName.Buffer = UserNameBuffer;
UserDomainName.Length = UserDomainName.MaximumLength = UNLEN * sizeof(WCHAR);
UserDomainName.Buffer = UserDomainNameBuffer;
Status = SmbCeGetUserNameAndDomainName(
StufferState->Exchange->SmbCeContext.pSessionEntry,
&UserName,
&UserDomainName);
if (Status != STATUS_SUCCESS) {
RtlInitUnicodeString(&UserName,L"RDR2ID");
} else {
RtlUpcaseUnicodeString(&UserName,&UserName,FALSE);
}
COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_Never,
SMB_COM_OPEN_PRINT_FILE, SMB_REQUEST_SIZE(OPEN_PRINT_FILE),
NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(4,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
);
MRxSmbSetFullProcessId(RxContext,((PNT_SMB_HEADER)StufferState->BufferBase));
// note that we hardwire graphics..........
MRxSmbStuffSMB (StufferState,
"0wwB4!",
// 0 UCHAR WordCount; // Count of parameter words = 2
0, // w _USHORT( SetupLength ); // Length of printer setup data
1, // w _USHORT( Mode ); // 0 = Text mode (DOS expands TABs)
// // 1 = Graphics mode
SMB_WCT_CHECK(2) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
// UCHAR Buffer[1]; // Buffer containing:
&UserName // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
// //UCHAR IdentifierString[]; // Identifier string
);
FINALLY:
RxDbgTraceUnIndent(-1,Dbg);
return(Status);
}
NTSTATUS
SmbPseExchangeStart_Create(
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
)
/*++
Routine Description:
This is the start routine for net root construction exchanges. This initiates the
construction of the appropriate SMB's if required.
Arguments:
pExchange - the exchange instance
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = (STATUS_NOT_IMPLEMENTED);
NTSTATUS SetupStatus = STATUS_SUCCESS;
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
RxCaptureFcb;
PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen;
PBOOLEAN MustRegainExclusiveResource = &OrdinaryExchange->Create.MustRegainExclusiveResource;
BOOLEAN CreateWithEasSidsOrLongName = OrdinaryExchange->Create.CreateWithEasSidsOrLongName;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Create\n", 0 ));
ASSERT_ORDINARY_EXCHANGE(OrdinaryExchange);
MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0)); //'FC'));
*MustRegainExclusiveResource = TRUE;
if (StufferState->PreviousCommand != SMB_COM_NO_ANDX_COMMAND) {
// we have a latent session setup /tree connect command
//the status of the embedded header commands is passed back in the flags
SetupStatus = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
SMBPSE_OETYPE_LATENT_HEADEROPS
);
MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0)); //'FC'));
}
if(SetupStatus != STATUS_SUCCESS) {
Status = SetupStatus;
goto FINALLY;
}
Status = MRxSmbDownlevelCreate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
FINALLY:
if (*MustRegainExclusiveResource) {
RxAcquireExclusiveFcb( RxContext, capFcb );
}
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Create exit w %08lx\n", Status ));
return Status;
}
VOID
MRxSmbSetSrvOpenFlags (
PRX_CONTEXT RxContext,
RX_FILE_TYPE StorageType,
PMRX_SRV_OPEN SrvOpen,
PMRX_SMB_SRV_OPEN smbSrvOpen
)
{
PMRX_SRV_CALL SrvCall = (PMRX_SRV_CALL)RxContext->Create.pSrvCall;
BOOLEAN IsLoopBack = FALSE;
PSMBCEDB_SERVER_ENTRY pServerEntry;
pServerEntry = SmbCeReferenceAssociatedServerEntry(SrvCall);
ASSERT(pServerEntry != NULL);
IsLoopBack = pServerEntry->Server.IsLoopBack;
SmbCeDereferenceServerEntry(pServerEntry);
RxDbgTrace( 0, Dbg, ("MRxSmbSetSrvOpenFlags oplockstate =%08lx\n", smbSrvOpen->OplockLevel ));
switch (smbSrvOpen->OplockLevel) {
case SMB_OPLOCK_LEVEL_II:
SrvOpen->BufferingFlags |= (FCB_STATE_READBUFFERING_ENABLED |
FCB_STATE_READCACHEING_ENABLED);
break;
case SMB_OPLOCK_LEVEL_EXCLUSIVE:
case SMB_OPLOCK_LEVEL_BATCH:
{
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);
if (StorageType == FileTypeFile) {
SrvOpen->BufferingFlags |= FCB_STATE_COLLAPSING_ENABLED;
}
}
break;
default:
ASSERT(!"Valid Oplock Level for Open");
case SMB_OPLOCK_LEVEL_NONE:
SrvOpen->BufferingFlags = 0;
}
SrvOpen->Flags |= MRxSmbInitialSrvOpenFlags;
// #define MRxSmbInitialSrvOpenFlags qweeeMRxSmbInitialSrvOpenFlags
if (IsLoopBack) {
SrvOpen->Flags |= SRVOPEN_FLAG_DONTUSE_WRITE_CACHEING;
}
}
NTSTATUS
MRxSmbCreateFileSuccessTail (
PRX_CONTEXT RxContext,
PBOOLEAN MustRegainExclusiveResource,
RX_FILE_TYPE StorageType,
SMB_FILE_ID Fid,
ULONG ServerVersion,
UCHAR OplockLevel,
ULONG CreateAction,
PSMBPSE_FILEINFO_BUNDLE FileInfo
)
/*++
Routine Description:
This routine finishes the initialization of the fcb and srvopen for a successful open.
Arguments:
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
RxCaptureFcb;
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
FCB_INIT_PACKET InitPacket;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbCreateFileSuccessTail\n", 0 ));
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
ASSERT( NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT );
if (*MustRegainExclusiveResource) { //this is required because of oplock breaks
RxAcquireExclusiveFcb( RxContext, capFcb );
*MustRegainExclusiveResource = FALSE;
}
RxContext->pFobx = RxCreateNetFobx( RxContext, SrvOpen);
ASSERT ( RxIsFcbAcquiredExclusive ( capFcb ) );
RxDbgTrace( 0, Dbg, ("Storagetype %08lx/Fid %08lx/Action %08lx\n", StorageType, Fid, CreateAction ));
pNetRootEntry = SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
SrvOpen->Key = MRxIfsMakeSrvOpenKey(pNetRootEntry->NetRoot.TreeId,Fid);
smbSrvOpen->Fid = Fid; //success_tail
smbSrvOpen->Version = ServerVersion;
smbSrvOpen->OplockLevel = OplockLevel;
RxContext->Create.ReturnedCreateInformation = CreateAction;
if ( ((FileInfo->Standard.AllocationSize.HighPart == FileInfo->Standard.EndOfFile.HighPart)
&& (FileInfo->Standard.AllocationSize.LowPart < FileInfo->Standard.EndOfFile.LowPart))
|| (FileInfo->Standard.AllocationSize.HighPart < FileInfo->Standard.EndOfFile.HighPart)
) {
FileInfo->Standard.AllocationSize = FileInfo->Standard.EndOfFile;
}
RxFormInitPacket(
InitPacket,
&FileInfo->Basic.FileAttributes,
&FileInfo->Standard.NumberOfLinks,
&FileInfo->Basic.CreationTime,
&FileInfo->Basic.LastAccessTime,
&FileInfo->Basic.LastWriteTime,
&FileInfo->Basic.ChangeTime,
&FileInfo->Standard.AllocationSize,
&FileInfo->Standard.EndOfFile,
&FileInfo->Standard.EndOfFile);
if (capFcb->OpenCount == 0) {
RxFinishFcbInitialization( capFcb,
RDBSS_STORAGE_NTC(StorageType),
&InitPacket
);
} else {
ASSERT( StorageType == 0 || NodeType(capFcb) == RDBSS_STORAGE_NTC(StorageType));
}
MRxSmbSetSrvOpenFlags(RxContext,StorageType,SrvOpen,smbSrvOpen);
RxContext->pFobx->OffsetOfNextEaToReturn = 1;
//transition happens later
RxDbgTrace(-1, Dbg, ("MRxSmbFinishCreateFile returning %08lx, fcbstate =%08lx\n", Status, wrapperFcb->FcbState ));
return Status;
}
//force_t2_open doesn't work on an NT server......sigh........
#define ForceT2Open FALSE
NTSTATUS
MRxSmbZeroExtend(
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
MRxIfsTruncate(
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;
}
VOID
MRxSmbDeallocateSideBuffer(
IN OUT PRX_CONTEXT RxContext,
IN OUT PMRX_SMB_FOBX smbFobx,
IN PSZ where
);
NTSTATUS
MRxIfsCleanupFobx(
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;
PUNICODE_STRING RemainingName;
RxCaptureFcb; RxCaptureFobx;
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
PMRX_SMB_FOBX smbFobx = MRxIfsGetFileObjectExtension(capFobx);
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
BOOLEAN SearchHandleOpen = FALSE;
PAGED_CODE();
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
ASSERT ( NodeTypeIsFcb(capFcb) );
RxDbgTrace(+1, Dbg, ("MRxSmbCleanup\n", 0 ));
if (TypeOfOpen==RDBSS_NTC_STORAGE_TYPE_DIRECTORY) {
SearchHandleOpen = BooleanFlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"Cleanup");
if (smbFobx->Enumeration.ResumeInfo!=NULL) {
RxFreePool(smbFobx->Enumeration.ResumeInfo);
smbFobx->Enumeration.ResumeInfo = NULL;
}
}
if (FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED)) {
RxDbgTrace(-1, Dbg, ("File orphaned\n"));
return (STATUS_SUCCESS);
}
if ((capFcb->pNetRoot->Type != NET_ROOT_PIPE) && !SearchHandleOpen) {
RxDbgTrace(-1, Dbg, ("File not for closing at cleanup\n"));
return (STATUS_SUCCESS);
}
OrdinaryExchange = SmbPseCreateOrdinaryExchange(RxContext,
SrvOpen->pVNetRoot,
SMBPSE_OE_FROM_CLEANUPFOBX,
SmbPseExchangeStart_Close
);
if (OrdinaryExchange==NULL) {
RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
return(STATUS_INSUFFICIENT_RESOURCES);
}
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
ASSERT (Status != (STATUS_PENDING));
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
RxDbgTrace(-1, Dbg, ("MRxSmbCleanup exit with status=%08lx\n", Status ));
return(Status);
}
NTSTATUS
MRxIfsForcedClose(
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;
}
//
// The local debug trace level
//
#undef Dbg
#define Dbg (DEBUG_TRACE_CLOSE)
NTSTATUS
MRxIfsCloseSrvOpen(
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;
PUNICODE_STRING RemainingName;
RxCaptureFcb;
RxCaptureFobx;
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
PMRX_SMB_FOBX smbFobx = MRxIfsGetFileObjectExtension(capFobx);
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
BOOLEAN NeedDelete;
PAGED_CODE();
ASSERT ( NodeTypeIsFcb(capFcb) );
ASSERT ( SrvOpen->OpenCount == 0 );
RxDbgTrace(+1, Dbg, ("MRxSmbClose\n", 0 ));
if ((FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED)) ||
(capFcb->pNetRoot->Type == NET_ROOT_MAILSLOT) ||
(capFcb->pNetRoot->Type == NET_ROOT_PIPE) ) {
RxDbgTrace(-1, Dbg, ("File orphan or ipc\n"));
return (STATUS_SUCCESS);
}
if ( FlagOn(SrvOpen->Flags,SRVOPEN_FLAG_FILE_RENAMED)
|| FlagOn(SrvOpen->Flags,SRVOPEN_FLAG_FILE_DELETED) ){
RxDbgTrace(-1, Dbg, ("File already closed by ren/del\n"));
return (STATUS_SUCCESS);
}
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
ASSERT((smbSrvOpen->Fid != 0xffff));
NeedDelete = FlagOn(capFcb->FcbState,FCB_STATE_DELETE_ON_CLOSE) && (capFcb->OpenCount == 0);
if ( FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)
&& !NeedDelete ){
RxDbgTrace(-1, Dbg, ("File was not really open\n"));
return STATUS_SUCCESS;
}
OrdinaryExchange = SmbPseCreateOrdinaryExchange(RxContext,
SrvOpen->pVNetRoot,
SMBPSE_OE_FROM_CLOSESRVCALL,
SmbPseExchangeStart_Close
);
if (OrdinaryExchange==NULL) {
RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
return((STATUS_INSUFFICIENT_RESOURCES));
}
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
ASSERT (Status != (STATUS_PENDING));
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
RxDbgTrace(-1, Dbg, ("MRxSmbClose exit with status=%08lx\n", Status ));
return(Status);
}
NTSTATUS
MRxIfsBuildClose (
PSMBSTUFFER_BUFFER_STATE StufferState
)
/*++
Routine Description:
This builds a Close SMB. we don't have to worry about login id and such
since that is done by the connection engine....pretty neat huh? all we have to do
is to format up the bits.
Arguments:
StufferState - the state of the smbbuffer from the stuffer's point of view
Return Value:
RXSTATUS
SUCCESS
NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
Notes:
--*/
{
NTSTATUS Status;
PRX_CONTEXT RxContext = StufferState->RxContext;
RxCaptureFcb;RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbBuildClose\n", 0 ));
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
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'))
);
MRxSmbStuffSMB (StufferState,
"0wdB!",
// 0 UCHAR WordCount; // Count of parameter words = 3
smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
0xffffffff, // 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
);
FINALLY:
RxDbgTraceUnIndent(-1,Dbg);
return(Status);
}
NTSTATUS
MRxIfsBuildFindClose (
PSMBSTUFFER_BUFFER_STATE StufferState
)
/*++
Routine Description:
This builds a Close SMB. we don't have to worry about login id and such
since that is done by the connection engine
Arguments:
StufferState - the state of the smbbuffer from the stuffer's point of view
Return Value:
RXSTATUS
SUCCESS
NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
Notes:
--*/
{
NTSTATUS Status;
PRX_CONTEXT RxContext = StufferState->RxContext;
RxCaptureFcb;RxCaptureFobx;
PMRX_SMB_FOBX smbFobx = MRxIfsGetFileObjectExtension(capFobx);
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbBuildFindClose\n", 0 ));
COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_ForReuse, SMB_COM_FIND_CLOSE2,
SMB_REQUEST_SIZE(FIND_CLOSE2),
NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
);
MRxSmbStuffSMB (StufferState,
"0wB!",
// 0 UCHAR WordCount; // Count of parameter words = 1
// w _USHORT( Sid ); // Find handle
smbFobx->Enumeration.SearchHandle,
SMB_WCT_CHECK(1) 0 // B! _USHORT( ByteCount ); // Count of data bytes = 0
// UCHAR Buffer[1]; // empty
);
FINALLY:
RxDbgTraceUnIndent(-1,Dbg);
return(Status);
}
NTSTATUS
MRxSmbCoreDeleteForSupercedeOrClose(
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
BOOLEAN DeleteDirectory
);
NTSTATUS
SmbPseExchangeStart_Close(
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
)
/*++
Routine Description:
This is the start routine for close.
Arguments:
pExchange - the exchange instance
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
RxCaptureFcb;
RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
PMRX_SMB_FCB smbFcb = MRxIfsGetFcbExtension(capFcb);
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
PMRX_SMB_FOBX smbFobx = MRxIfsGetFileObjectExtension(capFobx);
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Close\n", 0 ));
ASSERT(OrdinaryExchange->Type == ORDINARY_EXCHANGE);
MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
if(TypeOfOpen==RDBSS_NTC_STORAGE_TYPE_DIRECTORY){
if (FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN)) {
// we have a search handle open.....close it
Status = MRxIfsBuildFindClose(StufferState);
if (Status == STATUS_SUCCESS) {
// Ensure that the searchhandle is valid
if (smbFobx->Enumeration.Version == OrdinaryExchange->SmbCeContext.pServerEntry->Server.Version) {
NTSTATUS InnerStatus;
InnerStatus = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
SMBPSE_OETYPE_FINDCLOSE
);
} else {
DbgPrint("HANDLE VERSION IN FINDCLOSE MISMATCH!!!!");
}
}
// if this didn't work, there's nothing you can do............
ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
}
}
if ((OrdinaryExchange->EntryPoint == SMBPSE_OE_FROM_CLEANUPFOBX)
&& (capFcb->pNetRoot->Type != NET_ROOT_PIPE) ) {
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Close exit after searchhandle close %08lx\n", Status ));
return Status;
}
if ( !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) ) {
Status = MRxIfsBuildClose(StufferState);
if (Status == STATUS_SUCCESS) {
// Ensure that the Fid is validated
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID);
Status = SmbPseOrdinaryExchange(
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
SMBPSE_OETYPE_CLOSE
);
// Ensure that the Fid validation is disabled
ClearFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID);
}
//even if it didn't work there's nothing i can do......keep going
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN);
}
if ( (Status!=STATUS_SUCCESS)
|| (capFcb->OpenCount > 0)
|| !FlagOn(capFcb->FcbState,FCB_STATE_DELETE_ON_CLOSE)
|| FlagOn((smbFcb)->MFlags,SMB_FCB_FLAG_SENT_DISPOSITION_INFO) ) {
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Close exit w %08lx\n", Status ));
return Status;
}
RxDbgTrace(0, Dbg, ("SmbPseExchangeStart_Close delete on close\n" ));
//no need for setinitsmb here because coredelete does a int-on-resuse.....
OrdinaryExchange->pPathArgument1 = &capFcb->AlreadyPrefixedName;
MRxSmbCoreDeleteForSupercedeOrClose(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
((BOOLEAN)( NodeType(capFcb)==RDBSS_NTC_STORAGE_TYPE_DIRECTORY ))
);
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Close exit w %08lx\n", Status ));
return Status;
}
NTSTATUS
MRxSmbFinishClose (
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
PRESP_CLOSE Response
)
/*++
Routine Description:
This routine actually gets the stuff out of the Close response and finishes the close.
Arguments:
OrdinaryExchange - the exchange instance
Response - the response
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
RxCaptureFcb; RxCaptureFobx;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbFinishClose(orClosePrintFile)\n", 0 ));
SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishClose:");
ASSERT( (Response->WordCount==0));
ASSERT( (SmbGetUshort(&Response->ByteCount)==0));
if (OrdinaryExchange->OEType == SMBPSE_OETYPE_CLOSE) {
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxIfsGetSrvOpenExtension(SrvOpen);
smbSrvOpen->Fid = 0xffff;
}
RxDbgTrace(-1, Dbg, ("MRxSmbFinishClose returning %08lx\n", Status ));
return Status;
}