You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3427 lines
110 KiB
3427 lines
110 KiB
/*++
|
|
|
|
Copyright (c) 1989 - 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
openclos.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the mini redirector call down routines pertaining to opening/
|
|
closing of file/directories.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, MRxSmbMungeBufferingIfWriteOnlyHandles)
|
|
#pragma alloc_text(PAGE, IsReconnectRequired)
|
|
#pragma alloc_text(PAGE, MRxSmbIsCreateWithEasSidsOrLongName)
|
|
#pragma alloc_text(PAGE, MRxSmbShouldTryToCollapseThisOpen)
|
|
#pragma alloc_text(PAGE, MRxSmbCreate)
|
|
#pragma alloc_text(PAGE, MRxSmbDeferredCreate)
|
|
#pragma alloc_text(PAGE, MRxSmbCollapseOpen)
|
|
#pragma alloc_text(PAGE, MRxSmbComputeNewBufferingState)
|
|
#pragma alloc_text(PAGE, MRxSmbConstructDeferredOpenContext)
|
|
#pragma alloc_text(PAGE, MRxSmbAdjustCreateParameters)
|
|
#pragma alloc_text(PAGE, MRxSmbAdjustReturnedCreateAction)
|
|
#pragma alloc_text(PAGE, MRxSmbBuildNtCreateAndX)
|
|
#pragma alloc_text(PAGE, MRxSmbBuildOpenAndX)
|
|
#pragma alloc_text(PAGE, SmbPseExchangeStart_Create)
|
|
#pragma alloc_text(PAGE, MRxSmbSetSrvOpenFlags)
|
|
#pragma alloc_text(PAGE, MRxSmbCreateFileSuccessTail)
|
|
#pragma alloc_text(PAGE, MRxSmbFinishNTCreateAndX)
|
|
#pragma alloc_text(PAGE, MRxSmbFinishOpenAndX)
|
|
#pragma alloc_text(PAGE, MRxSmbFinishT2OpenFile)
|
|
#pragma alloc_text(PAGE, MRxSmbT2OpenFile)
|
|
#pragma alloc_text(PAGE, MRxSmbFinishLongNameCreateFile)
|
|
#pragma alloc_text(PAGE, MRxSmbCreateWithEasSidsOrLongName)
|
|
#pragma alloc_text(PAGE, MRxSmbZeroExtend)
|
|
#pragma alloc_text(PAGE, MRxSmbTruncate)
|
|
#pragma alloc_text(PAGE, MRxSmbCleanupFobx)
|
|
#pragma alloc_text(PAGE, MRxSmbForcedClose)
|
|
#pragma alloc_text(PAGE, MRxSmbCloseSrvOpen)
|
|
#pragma alloc_text(PAGE, MRxSmbBuildClose)
|
|
#pragma alloc_text(PAGE, MRxSmbBuildFindClose)
|
|
#pragma alloc_text(PAGE, SmbPseExchangeStart_Close)
|
|
#pragma alloc_text(PAGE, MRxSmbFinishClose)
|
|
#endif
|
|
|
|
|
|
//
|
|
// The debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_CREATE)
|
|
|
|
// forwards
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeStart_Create(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
|
);
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeStart_Close(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxSmbCreateWithEasSidsOrLongName(
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxSmbDownlevelCreate(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
|
);
|
|
|
|
ULONG MRxSmbInitialSrvOpenFlags = 0;
|
|
|
|
BOOLEAN MRxSmbDeferredOpensEnabled = TRUE; //this is regedit-able
|
|
BOOLEAN MRxSmbOplocksDisabled = FALSE; //this is regedit-able
|
|
|
|
extern LIST_ENTRY MRxSmbPagingFilesSrvOpenList;
|
|
|
|
#ifndef FORCE_NO_NTCREATE
|
|
#define MRxSmbForceNoNtCreate FALSE
|
|
#else
|
|
BOOLEAN MRxSmbForceNoNtCreate = TRUE;
|
|
#endif
|
|
|
|
|
|
#ifdef RX_PRIVATE_BUILD
|
|
//#define FORCE_SMALL_BUFFERS
|
|
#endif //#ifdef RX_PRIVATE_BUILD
|
|
|
|
#ifndef FORCE_SMALL_BUFFERS
|
|
|
|
//use size calculated from the negotiated size
|
|
ULONG MrxSmbLongestShortName = 0xffff;
|
|
|
|
//use the negotiated size
|
|
ULONG MrxSmbCreateTransactPacketSize = 0xffff;
|
|
|
|
#else
|
|
|
|
ULONG MrxSmbLongestShortName = 0;
|
|
ULONG MrxSmbCreateTransactPacketSize = 100;
|
|
|
|
#endif
|
|
|
|
|
|
LONG MRxSmbNumberOfSrvOpens = 0;
|
|
|
|
INLINE VOID
|
|
MRxSmbIncrementSrvOpenCount(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
PMRX_SRV_OPEN SrvOpen)
|
|
{
|
|
LONG NumberOfSrvOpens;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
if (!FlagOn(smbSrvOpen->FileInfo.Basic.FileAttributes,
|
|
FILE_ATTRIBUTE_DIRECTORY)) {
|
|
ASSERT(!smbSrvOpen->NumOfSrvOpenAdded);
|
|
smbSrvOpen->NumOfSrvOpenAdded = TRUE;
|
|
|
|
InterlockedIncrement(&pServerEntry->Server.NumberOfSrvOpens);
|
|
|
|
NumberOfSrvOpens = InterlockedIncrement(&MRxSmbNumberOfSrvOpens);
|
|
|
|
if (NumberOfSrvOpens == 1) {
|
|
PoRegisterSystemState(
|
|
MRxSmbPoRegistrationState,
|
|
(ES_SYSTEM_REQUIRED | ES_CONTINUOUS));
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MRxSmbDecrementSrvOpenCount(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
LONG SrvOpenServerVersion,
|
|
PMRX_SRV_OPEN SrvOpen)
|
|
{
|
|
LONG NumberOfSrvOpens;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
if (!FlagOn(smbSrvOpen->FileInfo.Basic.FileAttributes,
|
|
FILE_ATTRIBUTE_DIRECTORY)) {
|
|
ASSERT(smbSrvOpen->NumOfSrvOpenAdded);
|
|
smbSrvOpen->NumOfSrvOpenAdded = FALSE;
|
|
|
|
if (SrvOpenServerVersion == (LONG)pServerEntry->Server.Version) {
|
|
ASSERT(pServerEntry->Server.NumberOfSrvOpens > 0);
|
|
|
|
InterlockedDecrement(&pServerEntry->Server.NumberOfSrvOpens);
|
|
}
|
|
|
|
NumberOfSrvOpens = InterlockedDecrement(&MRxSmbNumberOfSrvOpens);
|
|
|
|
if (NumberOfSrvOpens == 0) {
|
|
PoRegisterSystemState(
|
|
MRxSmbPoRegistrationState,
|
|
ES_CONTINUOUS);
|
|
}
|
|
}
|
|
}
|
|
|
|
INLINE VOID
|
|
MRxSmbMungeBufferingIfWriteOnlyHandles (
|
|
ULONG WriteOnlySrvOpenCount,
|
|
PMRX_SRV_OPEN SrvOpen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine modifies the buffering flags on a srvopen so that
|
|
no cacheing will be allowed if there are any write-only handles
|
|
to the file.
|
|
|
|
Arguments:
|
|
|
|
WriteOnlySrvOpenCount - the number of writeonly srvopens
|
|
|
|
SrvOpen - the srvopen whose buffring flags are to be munged
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN IsLoopBack = FALSE;
|
|
PMRX_SRV_CALL pSrvCall;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
pSrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
|
|
|
|
pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall);
|
|
|
|
IsLoopBack = pServerEntry->Server.IsLoopBack;
|
|
|
|
if (IsLoopBack || (WriteOnlySrvOpenCount != 0)) {
|
|
SrvOpen->BufferingFlags &=
|
|
~( FCB_STATE_WRITECACHING_ENABLED |
|
|
FCB_STATE_FILESIZECACHEING_ENABLED |
|
|
FCB_STATE_FILETIMECACHEING_ENABLED |
|
|
FCB_STATE_LOCK_BUFFERING_ENABLED |
|
|
FCB_STATE_READCACHING_ENABLED |
|
|
FCB_STATE_COLLAPSING_ENABLED
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
INLINE BOOLEAN
|
|
IsReconnectRequired(
|
|
PMRX_SRV_CALL SrvCall)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if a reconnect is required to a given server
|
|
|
|
Arguments:
|
|
|
|
SrvCall - the SRV_CALL instance
|
|
|
|
Return Value:
|
|
|
|
TRUE if a reconnect is required
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN ReconnectRequired = FALSE;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
pServerEntry = SmbCeGetAssociatedServerEntry(SrvCall);
|
|
if (pServerEntry != NULL) {
|
|
ReconnectRequired = (pServerEntry->Header.State != SMBCEDB_ACTIVE);
|
|
}
|
|
|
|
return ReconnectRequired;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
MRxSmbIsCreateWithEasSidsOrLongName(
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
OUT PULONG DialectFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the create operation involves EA's or security
|
|
desriptors. In such cases a separate protocol is required
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RX_CONTEXT instance
|
|
|
|
DialectFlags - the dialect flags associated with the server
|
|
|
|
Return Value:
|
|
|
|
TRUE if a reconnect is required
|
|
|
|
--*/
|
|
{
|
|
RxCaptureFcb;
|
|
|
|
ULONG LongestShortName,LongestShortNameFromSrvBufSize;
|
|
|
|
PMRX_SRV_CALL SrvCall = (PMRX_SRV_CALL)RxContext->Create.pSrvCall;
|
|
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
|
|
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
pServerEntry = SmbCeGetAssociatedServerEntry(SrvCall);
|
|
|
|
ASSERT(pServerEntry != NULL);
|
|
|
|
*DialectFlags = pServerEntry->Server.DialectFlags;
|
|
|
|
|
|
// DOWN.LEVEL if the server takes OEM names or we use a different protocol
|
|
// this would have to be different. maybe a switch or a precompute.
|
|
|
|
LongestShortNameFromSrvBufSize =
|
|
MAXIMUM_SMB_BUFFER_SIZE -
|
|
QuadAlign(sizeof(NT_SMB_HEADER) +
|
|
FIELD_OFFSET(REQ_NT_CREATE_ANDX,Buffer[0])
|
|
);
|
|
|
|
LongestShortName = min(MrxSmbLongestShortName,LongestShortNameFromSrvBufSize);
|
|
|
|
return (RxContext->Create.EaLength ||
|
|
RxContext->Create.SdLength ||
|
|
RemainingName->Length > LongestShortName);
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbShouldTryToCollapseThisOpen (
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the mini knows of a good reason not
|
|
to try collapsing on this open.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
SUCCESS --> okay to try collapse
|
|
other (MORE_PROCESSING_REQUIRED) --> dont collapse
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
RxCaptureFcb;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (SrvOpen)
|
|
{
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)(RxContext->Create.pSrvCall->Context);
|
|
|
|
if (smbSrvOpen->Version != pServerEntry->Server.Version)
|
|
{
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbCreate (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a file across the network
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
RxCaptureFcb;
|
|
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)SrvCall->Context;
|
|
PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
|
|
PMRX_V_NET_ROOT pVNetRoot = SrvOpen->pVNetRoot;
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
|
|
PSMBCEDB_SESSION_ENTRY pSessionEntry ;
|
|
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = NULL;
|
|
|
|
BOOLEAN ReconnectRequired;
|
|
BOOLEAN CreateWithEasSidsOrLongName = FALSE;
|
|
ULONG DialectFlags;
|
|
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
|
|
|
|
PNT_CREATE_PARAMETERS CreateParameters = &RxContext->Create.NtCreateParameters;
|
|
ULONG Disposition = CreateParameters->Disposition;
|
|
|
|
PAGED_CODE();
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbCreate\n", 0 ));
|
|
|
|
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
|
|
|
RxDbgTrace( 0, Dbg, (" Attempt to open %wZ\n", RemainingName ));
|
|
|
|
if (FlagOn( capFcb->FcbState, FCB_STATE_PAGING_FILE )) {
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_STATUS) &&
|
|
MRxSmbIsStreamFile(RemainingName,NULL)) {
|
|
// The Samba server return file system type NTFS but doesn't support stream
|
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
|
}
|
|
|
|
RxContext->Create.NtCreateParameters.CreateOptions &= 0xfffff;
|
|
|
|
if( NetRoot->Type == NET_ROOT_PRINT ) {
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
// we cannot have a file cached on a write only handle. so we have to behave a little
|
|
// differently if this is a write-only open. remember this in the smbsrvopen
|
|
|
|
if ( ((CreateParameters->DesiredAccess & (FILE_EXECUTE | FILE_READ_DATA)) == 0) &&
|
|
((CreateParameters->DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0)
|
|
) {
|
|
|
|
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_WRITE_ONLY_HANDLE);
|
|
SrvOpen->Flags |= SRVOPEN_FLAG_DONTUSE_WRITE_CACHING;
|
|
}
|
|
|
|
//the way that SMBs work, there is no buffering effect if we open for attributes-only
|
|
//so set that up immediately.
|
|
|
|
if ((CreateParameters->DesiredAccess
|
|
& ~(FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE))
|
|
== 0 ){
|
|
SetFlag(SrvOpen->Flags,SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE);
|
|
}
|
|
|
|
if (NetRoot->Type == NET_ROOT_MAILSLOT) {
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (NetRoot->Type == NET_ROOT_PIPE) {
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
// Get the control struct for the file not found name cache.
|
|
//
|
|
pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
|
|
|
|
// assume Reconnection to be trivially successful
|
|
Status = STATUS_SUCCESS;
|
|
|
|
CreateWithEasSidsOrLongName = MRxSmbIsCreateWithEasSidsOrLongName(RxContext,&DialectFlags);
|
|
|
|
if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
|
|
CreateWithEasSidsOrLongName = FALSE;
|
|
}
|
|
|
|
ReconnectRequired = IsReconnectRequired((PMRX_SRV_CALL)SrvCall);
|
|
|
|
//get rid of nonEA guys right now
|
|
if (RxContext->Create.EaLength && !FlagOn(DialectFlags,DF_SUPPORTEA)) {
|
|
RxDbgTrace(-1, Dbg, ("EAs w/o EA support!\n"));
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
goto FINALLY;
|
|
}
|
|
|
|
if (ReconnectRequired || !CreateWithEasSidsOrLongName) {
|
|
Status = __SmbPseCreateOrdinaryExchange(
|
|
RxContext,
|
|
SrvOpen->pVNetRoot,
|
|
SMBPSE_OE_FROM_CREATE,
|
|
SmbPseExchangeStart_Create,
|
|
&OrdinaryExchange);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
|
|
goto FINALLY;
|
|
}
|
|
OrdinaryExchange->Create.CreateWithEasSidsOrLongName = CreateWithEasSidsOrLongName;
|
|
|
|
// 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 |
|
|
SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION);
|
|
OrdinaryExchange->pSmbCeSynchronizationEvent = &RxContext->SyncEvent;
|
|
|
|
// drop the resource before you go in!
|
|
// the start routine will reacquire it on the way out.....
|
|
RxReleaseFcbResourceInMRx( capFcb );
|
|
|
|
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
|
|
|
|
ASSERT((Status != STATUS_SUCCESS) || RxIsFcbAcquiredExclusive( capFcb ));
|
|
|
|
OrdinaryExchange->pSmbCeSynchronizationEvent = NULL;
|
|
|
|
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
|
|
|
|
if (!RxIsFcbAcquiredExclusive(capFcb)) {
|
|
ASSERT(!RxIsFcbAcquiredShared(capFcb));
|
|
RxAcquireExclusiveFcbResourceInMRx( capFcb );
|
|
}
|
|
}
|
|
|
|
if (CreateWithEasSidsOrLongName && (Status == STATUS_SUCCESS)) {
|
|
Status = MRxSmbCreateWithEasSidsOrLongName(RxContext);
|
|
|
|
}
|
|
|
|
// There are certain downlevel servers(OS/2 servers) that return the error
|
|
// STATUS_OPEN_FAILED. This is a context sensitive error code that needs to
|
|
// be interpreted in conjunction with the disposition specified for the OPEN.
|
|
|
|
if (Status == STATUS_OPEN_FAILED) {
|
|
switch (Disposition) {
|
|
|
|
//
|
|
// If we were asked to create the file, and got OPEN_FAILED,
|
|
// this implies that the file already exists.
|
|
//
|
|
|
|
case FILE_CREATE:
|
|
Status = STATUS_OBJECT_NAME_COLLISION;
|
|
break;
|
|
|
|
//
|
|
// If we were asked to open the file, and got OPEN_FAILED,
|
|
// this implies that the file doesn't exist.
|
|
//
|
|
|
|
case FILE_OPEN:
|
|
case FILE_SUPERSEDE:
|
|
case FILE_OVERWRITE:
|
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
break;
|
|
|
|
//
|
|
// If there is an error from either FILE_OPEN_IF or
|
|
// FILE_OVERWRITE_IF, it indicates the user is trying to
|
|
// open a file on a read-only share, so return the
|
|
// correct error for that.
|
|
//
|
|
|
|
case FILE_OPEN_IF:
|
|
case FILE_OVERWRITE_IF:
|
|
Status = STATUS_NETWORK_ACCESS_DENIED;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
ASSERT(Status != (STATUS_PENDING));
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_SUCCESSFUL_OPEN);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbCreate exit with status=%08lx\n", Status ));
|
|
RxLog(("MRxSmbCreate exits %lx\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbDeferredCreate (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine constructs a rxcontext from saved information and then calls
|
|
MRxSmbCreate.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
|
|
PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PMRX_SMB_DEFERRED_OPEN_CONTEXT DeferredOpenContext = smbSrvOpen->DeferredOpenContext;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
|
|
|
PRX_CONTEXT OpenRxContext,oc;
|
|
|
|
PAGED_CODE();
|
|
|
|
if ((!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)
|
|
|| !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN))) {
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto FINALLY;
|
|
}
|
|
|
|
if (DeferredOpenContext == NULL) {
|
|
if (FlagOn(SrvOpen->Flags,SRVOPEN_FLAG_CLOSED)) {
|
|
Status = STATUS_FILE_CLOSED;
|
|
goto FINALLY;
|
|
} else {
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
|
|
ASSERT(RxIsFcbAcquiredExclusive(capFcb));
|
|
|
|
SmbCeAcquireResource();
|
|
|
|
if (!smbSrvOpen->DeferredOpenInProgress) {
|
|
PLIST_ENTRY pListHead;
|
|
PLIST_ENTRY pListEntry;
|
|
|
|
smbSrvOpen->DeferredOpenInProgress = TRUE;
|
|
InitializeListHead(&smbSrvOpen->DeferredOpenSyncContexts);
|
|
|
|
SmbCeReleaseResource();
|
|
|
|
OpenRxContext = RxAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(RX_CONTEXT),
|
|
MRXSMB_RXCONTEXT_POOLTAG);
|
|
if (OpenRxContext==NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RtlZeroMemory(
|
|
OpenRxContext,
|
|
sizeof(RX_CONTEXT));
|
|
|
|
RxInitializeContext(
|
|
NULL,
|
|
RxContext->RxDeviceObject,
|
|
0,
|
|
OpenRxContext );
|
|
|
|
oc = OpenRxContext;
|
|
oc->pFcb = capFcb;
|
|
oc->pFobx = capFobx;
|
|
oc->NonPagedFcb = RxContext->NonPagedFcb;
|
|
oc->MajorFunction = IRP_MJ_CREATE;
|
|
oc->pRelevantSrvOpen = SrvOpen;
|
|
oc->Create.pVNetRoot = SrvOpen->pVNetRoot;
|
|
oc->Create.pNetRoot = oc->Create.pVNetRoot->pNetRoot;
|
|
oc->Create.pSrvCall = oc->Create.pNetRoot->pSrvCall;
|
|
|
|
oc->Flags = DeferredOpenContext->RxContextFlags;
|
|
oc->Flags |= RX_CONTEXT_FLAG_MINIRDR_INITIATED|RX_CONTEXT_FLAG_WAIT|RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
|
|
oc->Create.Flags = DeferredOpenContext->RxContextCreateFlags;
|
|
oc->Create.NtCreateParameters = DeferredOpenContext->NtCreateParameters;
|
|
|
|
Status = MRxSmbCreate(oc);
|
|
|
|
if (Status==STATUS_SUCCESS) {
|
|
if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
|
|
MRxSmbIncrementSrvOpenCount(pServerEntry,SrvOpen);
|
|
} else {
|
|
ASSERT(smbSrvOpen->NumOfSrvOpenAdded);
|
|
}
|
|
|
|
ClearFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN);
|
|
}
|
|
|
|
RxLog(("DeferredOpen %lx %lx %lx %lx\n", capFcb, capFobx, RxContext, Status));
|
|
|
|
ASSERT(oc->ReferenceCount==1);
|
|
|
|
RxFreePool(oc);
|
|
}
|
|
|
|
if (FlagOn(SrvOpen->Flags,SRVOPEN_FLAG_CLOSED) ||
|
|
FlagOn(SrvOpen->Flags,SRVOPEN_FLAG_ORPHANED)) {
|
|
RxFreePool(smbSrvOpen->DeferredOpenContext);
|
|
smbSrvOpen->DeferredOpenContext = NULL;
|
|
RxDbgTrace(0, Dbg, ("Free deferred open context for file %wZ %lX\n",GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext),smbSrvOpen));
|
|
}
|
|
|
|
SmbCeAcquireResource();
|
|
smbSrvOpen->DeferredOpenInProgress = FALSE;
|
|
|
|
pListHead = &smbSrvOpen->DeferredOpenSyncContexts;
|
|
pListEntry = pListHead->Flink;
|
|
|
|
while (pListEntry != pListHead) {
|
|
PDEFERRED_OPEN_SYNC_CONTEXT pWaitingContext;
|
|
|
|
pWaitingContext = (PDEFERRED_OPEN_SYNC_CONTEXT)CONTAINING_RECORD(
|
|
pListEntry,
|
|
DEFERRED_OPEN_SYNC_CONTEXT,
|
|
ListHead);
|
|
|
|
pListEntry = pListEntry->Flink;
|
|
RemoveHeadList(&pWaitingContext->ListHead);
|
|
|
|
pWaitingContext->Status = Status;
|
|
|
|
//DbgPrint("Signal RxContext %x after deferred open\n",pWaitingContext->RxContext);
|
|
RxSignalSynchronousWaiter(pWaitingContext->RxContext);
|
|
}
|
|
|
|
SmbCeReleaseResource();
|
|
|
|
} else {
|
|
DEFERRED_OPEN_SYNC_CONTEXT WaitingContext;
|
|
BOOLEAN AcquireExclusive = RxIsFcbAcquiredExclusive(capFcb);
|
|
BOOLEAN AcquireShare = RxIsFcbAcquiredShared(capFcb) > 0;
|
|
|
|
// put the RxContext on the waiting list
|
|
WaitingContext.RxContext = RxContext;
|
|
InitializeListHead(&WaitingContext.ListHead);
|
|
|
|
InsertTailList(
|
|
&smbSrvOpen->DeferredOpenSyncContexts,
|
|
&WaitingContext.ListHead);
|
|
|
|
SmbCeReleaseResource();
|
|
|
|
if (AcquireExclusive || AcquireShare) {
|
|
RxReleaseFcbResourceInMRx( capFcb );
|
|
}
|
|
|
|
RxWaitSync(RxContext);
|
|
|
|
Status = WaitingContext.Status;
|
|
|
|
KeInitializeEvent(
|
|
&RxContext->SyncEvent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (AcquireExclusive) {
|
|
RxAcquireExclusiveFcbResourceInMRx(capFcb);
|
|
} else if (AcquireShare) {
|
|
RxAcquireSharedFcbResourceInMRx(capFcb);
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxSmbCollapseOpen(
|
|
IN OUT PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine collapses a open locally
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
RxCaptureFcb;
|
|
|
|
RX_BLOCK_CONDITION FinalSrvOpenCondition;
|
|
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall;
|
|
PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
|
|
|
|
PAGED_CODE();
|
|
|
|
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;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbComputeNewBufferingState(
|
|
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,NewBufferingState;
|
|
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(pMRxSrvOpen);
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(pMRxSrvOpen->pFcb);
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(pNewBufferingState != NULL);
|
|
|
|
OplockLevel = PtrToUlong(pMRxContext);
|
|
|
|
if (OplockLevel == SMB_OPLOCK_LEVEL_II) {
|
|
NewBufferingState = (FCB_STATE_READBUFFERING_ENABLED |
|
|
FCB_STATE_READCACHING_ENABLED);
|
|
} else {
|
|
NewBufferingState = 0;
|
|
}
|
|
|
|
pMRxSrvOpen->BufferingFlags = NewBufferingState;
|
|
|
|
MRxSmbMungeBufferingIfWriteOnlyHandles(
|
|
smbFcb->WriteOnlySrvOpenCount,
|
|
pMRxSrvOpen);
|
|
|
|
*pNewBufferingState = pMRxSrvOpen->BufferingFlags;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbConstructDeferredOpenContext (
|
|
PRX_CONTEXT RxContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine saves enough state that we can come back later and really do an
|
|
open if needed. We only do this for NT servers.
|
|
|
|
Arguments:
|
|
|
|
OrdinaryExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureFobx;
|
|
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)RxContext->Create.pSrvCall->Context;
|
|
PSMBCE_SERVER pServer = &pServerEntry->Server;
|
|
|
|
PMRX_SMB_DEFERRED_OPEN_CONTEXT DeferredOpenContext;
|
|
PDFS_NAME_CONTEXT pDNC=NULL;
|
|
DWORD cbSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbConstructDeferredOpenContext\n"));
|
|
|
|
ASSERT(smbSrvOpen->DeferredOpenContext == NULL);
|
|
|
|
cbSize = sizeof(MRX_SMB_DEFERRED_OPEN_CONTEXT);
|
|
|
|
// if there is a dfs name context, we need to allocate memory
|
|
// fot aht too, because the name that is included in the
|
|
// context is deallocated by DFS when it returns from the create call
|
|
|
|
if(pDNC = RxContext->Create.NtCreateParameters.DfsNameContext)
|
|
{
|
|
cbSize += (sizeof(DFS_NAME_CONTEXT)+pDNC->UNCFileName.MaximumLength+sizeof(DWORD));
|
|
}
|
|
|
|
DeferredOpenContext = RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
cbSize,
|
|
MRXSMB_DEFROPEN_POOLTAG);
|
|
|
|
if (DeferredOpenContext == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
|
|
smbSrvOpen->DeferredOpenContext = DeferredOpenContext;
|
|
DeferredOpenContext->NtCreateParameters = RxContext->Create.NtCreateParameters;
|
|
DeferredOpenContext->RxContextCreateFlags = RxContext->Create.Flags;
|
|
DeferredOpenContext->RxContextFlags = RxContext->Flags;
|
|
DeferredOpenContext->NtCreateParameters.SecurityContext = NULL;
|
|
MRxSmbAdjustCreateParameters(RxContext, &DeferredOpenContext->SmbCp);
|
|
|
|
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_DEFERRED_OPEN);
|
|
if (pDNC)
|
|
{
|
|
PDFS_NAME_CONTEXT pDNCDeferred=NULL;
|
|
|
|
// point the dfs name context after the rxcontext
|
|
|
|
pDNCDeferred = (PDFS_NAME_CONTEXT)((PBYTE)DeferredOpenContext+sizeof(MRX_SMB_DEFERRED_OPEN_CONTEXT));
|
|
DeferredOpenContext->NtCreateParameters.DfsNameContext = pDNCDeferred;
|
|
|
|
// copy the info
|
|
*pDNCDeferred = *pDNC;
|
|
|
|
if (pDNC->UNCFileName.Length)
|
|
{
|
|
ASSERT(pDNC->UNCFileName.Buffer);
|
|
|
|
// point the name buffer after deferredcontext+dfs_name_context
|
|
|
|
pDNCDeferred->UNCFileName.Buffer = (PWCHAR)((PBYTE)pDNCDeferred+sizeof(DFS_NAME_CONTEXT));
|
|
|
|
memcpy(pDNCDeferred->UNCFileName.Buffer,
|
|
pDNC->UNCFileName.Buffer,
|
|
pDNC->UNCFileName.Length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
FINALLY:
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbConstructDeferredOpenContext, Status=%08lx\n",Status));
|
|
return Status;
|
|
}
|
|
|
|
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"));
|
|
|
|
if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MINIRDR_INITIATED)) {
|
|
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->Pid = RxGetRequestorProcessId(RxContext);
|
|
smbcp->SecurityFlags = 0;
|
|
if (cp->SecurityContext != NULL) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//here, we have a defered open!!!
|
|
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
//the parameters have already been adjusted...BUT null the security context.......
|
|
cp->SecurityContext = NULL;
|
|
*smbcp = smbSrvOpen->DeferredOpenContext->SmbCp;
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbAdjustCreateParameters\n"));
|
|
}
|
|
|
|
INLINE 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;
|
|
|
|
PAGED_CODE();
|
|
|
|
if ((q==FILE_SUPERSEDED)||(q==FILE_CREATED)||(q >FILE_MAXIMUM_DISPOSITION)) {
|
|
RxContext->Create.ReturnedCreateInformation = FILE_OPENED;
|
|
}
|
|
}
|
|
|
|
UNICODE_STRING UnicodeBackslash = {2,4,L"\\"};
|
|
|
|
NTSTATUS
|
|
MRxSmbBuildNtCreateAndX (
|
|
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:
|
|
|
|
NTSTATUS
|
|
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;
|
|
|
|
RxCaptureFcb;
|
|
|
|
ACCESS_MASK DesiredAccess;
|
|
ULONG OplockFlags;
|
|
|
|
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
|
|
|
|
PSMBCE_SERVER pServer;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbBuildNtCreateAndX\n", 0 ));
|
|
|
|
pServer = SmbCeGetExchangeServer(StufferState->Exchange);
|
|
|
|
if (!(cp->CreateOptions & FILE_DIRECTORY_FILE) &&
|
|
(cp->DesiredAccess & (FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE )) &&
|
|
!MRxSmbOplocksDisabled) {
|
|
|
|
DesiredAccess = cp->DesiredAccess & ~SYNCHRONIZE;
|
|
OplockFlags = (NT_CREATE_REQUEST_OPLOCK | NT_CREATE_REQUEST_OPBATCH);
|
|
|
|
} else {
|
|
|
|
DesiredAccess = cp->DesiredAccess;
|
|
OplockFlags = 0;
|
|
|
|
}
|
|
|
|
if ((RemainingName->Length==0)
|
|
&& (FlagOn(RxContext->Create.Flags,RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH)) ) {
|
|
RemainingName = &UnicodeBackslash;
|
|
}
|
|
COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_Never,
|
|
SMB_COM_NT_CREATE_ANDX, SMB_REQUEST_SIZE(NT_CREATE_ANDX),
|
|
NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(4,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
|
|
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
|
|
);
|
|
SmbCeSetFullProcessIdInHeader(
|
|
StufferState->Exchange,
|
|
smbcp->Pid,
|
|
((PNT_SMB_HEADER)StufferState->BufferBase));
|
|
|
|
MRxSmbStuffSMB (StufferState,
|
|
"XmwdddDdddDddyB",
|
|
// X UCHAR WordCount; // Count of parameter words = 24
|
|
// . UCHAR AndXCommand; // Secondary command; 0xFF = None
|
|
// . UCHAR AndXReserved; // MBZ
|
|
// . _USHORT( AndXOffset ); // Offset to next command wordcount
|
|
// m UCHAR Reserved; // MBZ
|
|
BooleanFlagOn(pServer->DialectFlags,DF_UNICODE)?
|
|
RemainingName->Length:RtlxUnicodeStringToOemSize(RemainingName),
|
|
// w _USHORT( NameLength ); // Length of Name[] in bytes
|
|
OplockFlags, // d _ULONG( Flags ); // Create flags
|
|
0, //not used // d _ULONG( RootDirectoryFid ); // If non-zero, open is relative to this directory
|
|
DesiredAccess, // d ACCESS_MASK DesiredAccess; // NT access desired
|
|
// Dd LARGE_INTEGER AllocationSize; // Initial allocation size
|
|
SMB_OFFSET_CHECK(NT_CREATE_ANDX,AllocationSize)
|
|
cp->AllocationSize.LowPart, cp->AllocationSize.HighPart,
|
|
cp->FileAttributes, // d _ULONG( FileAttributes ); // File attributes for creation
|
|
cp->ShareAccess, // d _ULONG( ShareAccess ); // Type of share access
|
|
// D _ULONG( CreateDisposition ); // Action to take if file exists or not
|
|
SMB_OFFSET_CHECK(NT_CREATE_ANDX,CreateDisposition)
|
|
cp->Disposition,
|
|
cp->CreateOptions, // d _ULONG( CreateOptions ); // Options to use if creating a file
|
|
cp->ImpersonationLevel,// d _ULONG( ImpersonationLevel ); // Security QOS information
|
|
smbcp->SecurityFlags, // y UCHAR SecurityFlags; // Security QOS information
|
|
SMB_WCT_CHECK(24) 0 // B _USHORT( ByteCount ); // Length of byte parameters
|
|
// . UCHAR Buffer[1];
|
|
// . //UCHAR Name[]; // File to open or create
|
|
);
|
|
|
|
//proceed with the stuff because we know here that the name fits
|
|
|
|
MRxSmbStuffSMB(StufferState,
|
|
BooleanFlagOn(pServer->DialectFlags,DF_UNICODE)?"u!":"z!",
|
|
RemainingName);
|
|
|
|
MRxSmbDumpStufferState (700,"SMB w/ NTOPEN&X after stuffing",StufferState);
|
|
|
|
FINALLY:
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxSmbBuildOpenAndX (
|
|
PSMBSTUFFER_BUFFER_STATE StufferState,
|
|
PMRXSMB_CREATE_PARAMETERS smbcp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This builds an OpenAndX 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;
|
|
|
|
PSMBCE_SERVER pServer;
|
|
|
|
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
|
|
|
|
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 ));
|
|
|
|
pServer = SmbCeGetExchangeServer(Exchange);
|
|
|
|
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(pServer->DialectFlags,DF_LANMAN20)) {
|
|
|
|
KeQuerySystemTime(&CurrentTime);
|
|
MRxSmbTimeToSecondsSince1970(&CurrentTime,
|
|
pServer,
|
|
&SecondsSince1970);
|
|
} else {
|
|
SecondsSince1970 = 0;
|
|
}
|
|
|
|
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);
|
|
|
|
MRxSmbDumpStufferState (700,"SMB w/ OPEN&X after stuffing",StufferState);
|
|
|
|
FINALLY:
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
typedef enum _SMBPSE_CREATE_METHOD {
|
|
CreateAlreadyDone,
|
|
CreateUseCore,
|
|
CreateUseNT
|
|
} SMBPSE_CREATE_METHOD;
|
|
|
|
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:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = (STATUS_NOT_IMPLEMENTED);
|
|
NTSTATUS SetupStatus = STATUS_SUCCESS;
|
|
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
|
SMBPSE_CREATE_METHOD CreateMethod = CreateAlreadyDone;
|
|
PSMBCE_SERVER pServer;
|
|
ULONG DialectFlags;
|
|
|
|
RxCaptureFcb;
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
PBOOLEAN MustRegainExclusiveResource = &OrdinaryExchange->Create.MustRegainExclusiveResource;
|
|
BOOLEAN CreateWithEasSidsOrLongName = OrdinaryExchange->Create.CreateWithEasSidsOrLongName;
|
|
BOOLEAN fRetryCore = FALSE;
|
|
|
|
PAGED_CODE();
|
|
RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Create\n", 0 ));
|
|
|
|
ASSERT_ORDINARY_EXCHANGE(OrdinaryExchange);
|
|
|
|
pServer = SmbCeGetExchangeServer(OrdinaryExchange);
|
|
DialectFlags = pServer->DialectFlags;
|
|
|
|
COVERED_CALL(MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0)));
|
|
|
|
*MustRegainExclusiveResource = TRUE;
|
|
|
|
if (!FlagOn(DialectFlags,DF_NT_SMBS)) {
|
|
OEM_STRING OemString;
|
|
PUNICODE_STRING PathName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
|
|
|
|
if (PathName->Length != 0) {
|
|
Status = RtlUnicodeStringToOemString(&OemString, PathName, TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto FINALLY;
|
|
}
|
|
|
|
//
|
|
// If we are canonicalizing as FAT, use FAT rules, otherwise use
|
|
// HPFS rules.
|
|
//
|
|
|
|
if (!FlagOn(DialectFlags,DF_LANMAN20)) {
|
|
if (!FsRtlIsFatDbcsLegal(OemString, FALSE, TRUE, TRUE)) {
|
|
RtlFreeOemString(&OemString);
|
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|
goto FINALLY;
|
|
}
|
|
} else if (!FsRtlIsHpfsDbcsLegal(OemString, FALSE, TRUE, TRUE)) {
|
|
RtlFreeOemString(&OemString);
|
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|
goto FINALLY;
|
|
}
|
|
|
|
RtlFreeOemString(&OemString);
|
|
}
|
|
}
|
|
|
|
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
|
|
);
|
|
|
|
if(SetupStatus != STATUS_SUCCESS) {
|
|
Status = SetupStatus;
|
|
goto FINALLY;
|
|
}
|
|
|
|
// Turn off reconnect attempts now that we have successfully established
|
|
// the session and net root.
|
|
OrdinaryExchange->SmbCeFlags &= ~(SMBCE_EXCHANGE_ATTEMPT_RECONNECTS);
|
|
|
|
COVERED_CALL(MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0)));
|
|
}
|
|
|
|
|
|
if (!CreateWithEasSidsOrLongName) {
|
|
PUNICODE_STRING AlreadyPrefixedName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
|
|
PMRXSMB_CREATE_PARAMETERS SmbCp = &OrdinaryExchange->Create.SmbCp;
|
|
PNT_CREATE_PARAMETERS cp = &RxContext->Create.NtCreateParameters;
|
|
USHORT mappedOpenMode;
|
|
|
|
MRxSmbAdjustCreateParameters(RxContext,SmbCp);
|
|
mappedOpenMode = MRxSmbMapDesiredAccess(cp->DesiredAccess);
|
|
|
|
if ((!MRxSmbForceNoNtCreate)
|
|
&& FlagOn(DialectFlags,DF_NT_SMBS)) {
|
|
|
|
BOOLEAN SecurityIsNULL =
|
|
(cp->SecurityContext == NULL) ||
|
|
(cp->SecurityContext->AccessState == NULL) ||
|
|
(cp->SecurityContext->AccessState->SecurityDescriptor == NULL);
|
|
|
|
CreateMethod = CreateUseNT;
|
|
|
|
//now catch the cases where we want to pseudoopen the file
|
|
|
|
if ( MRxSmbDeferredOpensEnabled &&
|
|
!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MINIRDR_INITIATED) &&
|
|
(capFcb->pNetRoot->Type == NET_ROOT_DISK) &&
|
|
SecurityIsNULL) {
|
|
|
|
ASSERT( RxContext->CurrentIrp != 0 );
|
|
|
|
if ((cp->Disposition==FILE_OPEN) &&
|
|
!BooleanFlagOn(cp->CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT) &&
|
|
(MustBeDirectory(cp->CreateOptions) ||
|
|
!(cp->DesiredAccess & ~(SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES)))){
|
|
|
|
// NT apps expect that you will not succeed the create and then fail the attribs;
|
|
// if we had some way of identifying win32 apps then we could defer these (except
|
|
// for DFS). since we have no way to get that information (and don't even have
|
|
// a good SMB to send..........)
|
|
|
|
// we don't need to send the open for DELETE and FILE_READ_ATTRIBUTES requests since
|
|
// there are path basied SMB operations.
|
|
|
|
// we can also pseudoopen directories for file_open at the root of the
|
|
// share but otherwise we have to at least check that the directory
|
|
// exists. we might have to push out the open later. BTW, we wouldn't be
|
|
// in here if the name was too long for a GFA or CheckPath
|
|
|
|
Status = MRxSmbPseudoOpenTailFromFakeGFAResponse(
|
|
OrdinaryExchange,
|
|
MustBeDirectory(cp->CreateOptions)?FileTypeDirectory:FileTypeFile);
|
|
|
|
if (Status == STATUS_SUCCESS && AlreadyPrefixedName->Length > 0) {
|
|
// send query path information to make sure the file exists on the server
|
|
Status = MRxSmbQueryFileInformationFromPseudoOpen(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
if (MustBeDirectory(cp->CreateOptions) &&
|
|
!OrdinaryExchange->Create.FileInfo.Standard.Directory) {
|
|
Status = STATUS_NOT_A_DIRECTORY;
|
|
}
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxFreePool(smbSrvOpen->DeferredOpenContext);
|
|
smbSrvOpen->DeferredOpenContext = NULL;
|
|
}
|
|
}
|
|
|
|
CreateMethod = CreateAlreadyDone;
|
|
}
|
|
}
|
|
|
|
//if no pseudoopen case was hit, do a real open
|
|
|
|
if (CreateMethod == CreateUseNT) {
|
|
|
|
//use NT_CREATE&X
|
|
COVERED_CALL(MRxSmbBuildNtCreateAndX(StufferState,SmbCp));
|
|
|
|
Status = SmbPseOrdinaryExchange(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
|
SMBPSE_OETYPE_CREATE
|
|
);
|
|
|
|
if (Status == STATUS_SUCCESS && RxContext->pFobx == NULL) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
|
|
if ((Status == STATUS_SUCCESS) && (cp->Disposition == FILE_OPEN)) {
|
|
MRxSmbAdjustReturnedCreateAction(RxContext);
|
|
}
|
|
}
|
|
} else if (FlagOn(DialectFlags, DF_LANMAN10) &&
|
|
(mappedOpenMode != ((USHORT)-1)) &&
|
|
!MustBeDirectory(cp->CreateOptions)) {
|
|
|
|
if (MRxSmbDeferredOpensEnabled &&
|
|
capFcb->pNetRoot->Type == NET_ROOT_DISK &&
|
|
!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MINIRDR_INITIATED) &&
|
|
(cp->Disposition==FILE_OPEN) &&
|
|
((cp->DesiredAccess & ~(SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES)) == 0) ){
|
|
|
|
// we don't need to send the open for DELETE and FILE_READ_ATTRIBUTES requests since
|
|
// there are path basied SMB operations.
|
|
// we should do pseudo open for FILE_WRITE_ATTRIBUTES. Othewise the server will return
|
|
// sharing violation
|
|
|
|
|
|
// send query path information to make sure the file exists on the server
|
|
|
|
Status = MRxSmbPseudoOpenTailFromFakeGFAResponse(
|
|
OrdinaryExchange,
|
|
MustBeDirectory(cp->CreateOptions)?FileTypeDirectory:FileTypeFile);
|
|
|
|
if (Status == STATUS_SUCCESS && AlreadyPrefixedName->Length > 0) {
|
|
Status = MRxSmbQueryFileInformationFromPseudoOpen(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxFreePool(smbSrvOpen->DeferredOpenContext);
|
|
smbSrvOpen->DeferredOpenContext = NULL;
|
|
}
|
|
}
|
|
|
|
CreateMethod = CreateAlreadyDone;
|
|
} else {
|
|
//use OPEN&X
|
|
COVERED_CALL(MRxSmbBuildOpenAndX(StufferState,SmbCp));
|
|
|
|
Status = SmbPseOrdinaryExchange(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
|
SMBPSE_OETYPE_CREATE
|
|
);
|
|
|
|
if (Status == STATUS_ACCESS_DENIED && !FlagOn(DialectFlags,DF_NT_SMBS)) {
|
|
CreateMethod = CreateUseCore;
|
|
fRetryCore = TRUE;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
CreateMethod = CreateUseCore;
|
|
}
|
|
|
|
if (CreateMethod == CreateUseCore) {
|
|
|
|
Status = MRxSmbDownlevelCreate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
|
|
|
|
// put back the real error code if we are retrying open&x
|
|
if ((Status != STATUS_SUCCESS) && fRetryCore)
|
|
{
|
|
Status = STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
|
|
if (*MustRegainExclusiveResource) {
|
|
RxAcquireExclusiveFcbResourceInMRx( capFcb );
|
|
}
|
|
|
|
// now that we have the fcb exclusive, we can do some updates
|
|
|
|
if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_WRITE_ONLY_HANDLE)) {
|
|
smbFcb->WriteOnlySrvOpenCount++;
|
|
}
|
|
|
|
MRxSmbMungeBufferingIfWriteOnlyHandles(
|
|
smbFcb->WriteOnlySrvOpenCount,
|
|
SrvOpen
|
|
);
|
|
|
|
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
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( 0, Dbg, ("MRxSmbSetSrvOpenFlags oplockstate =%08lx\n", smbSrvOpen->OplockLevel ));
|
|
|
|
SrvOpen->BufferingFlags = 0;
|
|
|
|
switch (smbSrvOpen->OplockLevel) {
|
|
case SMB_OPLOCK_LEVEL_II:
|
|
SrvOpen->BufferingFlags |= (FCB_STATE_READBUFFERING_ENABLED |
|
|
FCB_STATE_READCACHING_ENABLED);
|
|
break;
|
|
|
|
case SMB_OPLOCK_LEVEL_BATCH:
|
|
if (StorageType == FileTypeFile) {
|
|
SrvOpen->BufferingFlags |= FCB_STATE_COLLAPSING_ENABLED;
|
|
}
|
|
// lack of break intentional
|
|
|
|
case SMB_OPLOCK_LEVEL_EXCLUSIVE:
|
|
SrvOpen->BufferingFlags |= (FCB_STATE_WRITECACHING_ENABLED |
|
|
FCB_STATE_FILESIZECACHEING_ENABLED |
|
|
FCB_STATE_FILETIMECACHEING_ENABLED |
|
|
FCB_STATE_WRITEBUFFERING_ENABLED |
|
|
FCB_STATE_LOCK_BUFFERING_ENABLED |
|
|
FCB_STATE_READBUFFERING_ENABLED |
|
|
FCB_STATE_READCACHING_ENABLED);
|
|
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Valid Oplock Level for Open");
|
|
|
|
case SMB_OPLOCK_LEVEL_NONE:
|
|
break;
|
|
}
|
|
|
|
SrvOpen->Flags |= MRxSmbInitialSrvOpenFlags;
|
|
}
|
|
|
|
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:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureFcb;
|
|
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)RxContext->Create.pSrvCall->Context;
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
|
|
|
|
BOOLEAN ThisIsAPseudoOpen;
|
|
|
|
FCB_INIT_PACKET LocalInitPacket, *InitPacket;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbCreateFileSuccessTail\n", 0 ));
|
|
|
|
smbSrvOpen->Fid = Fid;
|
|
smbSrvOpen->Version = ServerVersion;
|
|
|
|
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
|
ASSERT( NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT );
|
|
|
|
if (*MustRegainExclusiveResource) {
|
|
//this is required because of oplock breaks
|
|
|
|
RxAcquireExclusiveFcbResourceInMRx( capFcb );
|
|
*MustRegainExclusiveResource = FALSE;
|
|
}
|
|
|
|
if (RxContext->pFobx==NULL) {
|
|
RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen);
|
|
}
|
|
|
|
ASSERT ( RxIsFcbAcquiredExclusive ( capFcb ) );
|
|
RxDbgTrace(
|
|
0, Dbg,
|
|
("Storagetype %08lx/Fid %08lx/Action %08lx\n", StorageType, Fid, CreateAction ));
|
|
|
|
pVNetRootContext = SmbCeGetAssociatedVNetRootContext(SrvOpen->pVNetRoot);
|
|
SrvOpen->Key = MRxSmbMakeSrvOpenKey(pVNetRootContext->TreeId,Fid);
|
|
|
|
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;
|
|
}
|
|
|
|
smbFcb->dwFileAttributes = FileInfo->Basic.FileAttributes;
|
|
|
|
if (smbSrvOpen->OplockLevel > smbFcb->LastOplockLevel) {
|
|
ClearFlag(
|
|
capFcb->FcbState,
|
|
FCB_STATE_TIME_AND_SIZE_ALREADY_SET);
|
|
}
|
|
|
|
smbFcb->LastOplockLevel = smbSrvOpen->OplockLevel;
|
|
|
|
//the thing is this: if we have good info (not a pseudoopen) then we make the
|
|
//finish call passing the init packet; otherwise, we make the call NOT passing an init packet
|
|
|
|
ThisIsAPseudoOpen = BooleanFlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN);
|
|
|
|
if (!ThisIsAPseudoOpen) {
|
|
MRxSmbIncrementSrvOpenCount(pServerEntry,SrvOpen);
|
|
}
|
|
|
|
if ((capFcb->OpenCount == 0) ||
|
|
(!ThisIsAPseudoOpen &&
|
|
!FlagOn(capFcb->FcbState,FCB_STATE_TIME_AND_SIZE_ALREADY_SET))) {
|
|
if (!ThisIsAPseudoOpen) {
|
|
RxFormInitPacket(
|
|
LocalInitPacket,
|
|
&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);
|
|
InitPacket = &LocalInitPacket;
|
|
|
|
} else {
|
|
InitPacket = NULL;
|
|
}
|
|
|
|
RxFinishFcbInitialization( capFcb,
|
|
RDBSS_STORAGE_NTC(StorageType),
|
|
InitPacket
|
|
);
|
|
|
|
if (FlagOn( capFcb->FcbState, FCB_STATE_PAGING_FILE )) {
|
|
PPAGING_FILE_CONTEXT PagingFileContext;
|
|
|
|
ASSERT(FALSE);
|
|
PagingFileContext = RxAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(PAGING_FILE_CONTEXT),
|
|
MRXSMB_MISC_POOLTAG);
|
|
|
|
if (PagingFileContext != NULL) {
|
|
PagingFileContext->pSrvOpen = SrvOpen;
|
|
PagingFileContext->pFobx = RxContext->pFobx;
|
|
|
|
InsertHeadList(
|
|
&MRxSmbPagingFilesSrvOpenList,
|
|
&PagingFileContext->ContextList);
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
|
|
MRxSmbSetSrvOpenFlags(RxContext,StorageType,SrvOpen,smbSrvOpen);
|
|
|
|
//(wrapperFcb->Condition) = Condition_Good;
|
|
|
|
RxContext->pFobx->OffsetOfNextEaToReturn = 1;
|
|
//transition happens later
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbFinishCreateFile returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState ));
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbFinishNTCreateAndX (
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
|
PRESP_NT_CREATE_ANDX Response
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine actually gets the stuff out of the NTCreate_AndX response.
|
|
|
|
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;
|
|
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(OrdinaryExchange);
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetExchangeNetRootEntry(OrdinaryExchange);
|
|
|
|
RX_FILE_TYPE StorageType;
|
|
SMB_FILE_ID Fid;
|
|
ULONG CreateAction;
|
|
|
|
PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbFinishNTCreateAndX\n", 0 ));
|
|
ASSERT( NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT );
|
|
|
|
if (RxContext->Create.NtCreateParameters.CreateOptions & FILE_DELETE_ON_CLOSE) {
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
SetFlag((smbFcb)->MFlags,SMB_FCB_FLAG_SENT_DISPOSITION_INFO);
|
|
}
|
|
|
|
StorageType = RxInferFileType(RxContext);
|
|
if (StorageType == 0) {
|
|
StorageType = Response->Directory
|
|
?(FileTypeDirectory)
|
|
:(FileTypeFile);
|
|
RxDbgTrace( 0, Dbg, ("ChangedStoragetype %08lx\n", StorageType ));
|
|
}
|
|
|
|
Fid = SmbGetUshort(&Response->Fid);
|
|
|
|
CreateAction = SmbGetUlong(&Response->CreateAction);
|
|
|
|
pFileInfo->Basic.FileAttributes = SmbGetUlong(&Response->FileAttributes);
|
|
pFileInfo->Standard.NumberOfLinks = 1;
|
|
pFileInfo->Basic.CreationTime.LowPart = SmbGetUlong(&Response->CreationTime.LowPart);
|
|
pFileInfo->Basic.CreationTime.HighPart = SmbGetUlong(&Response->CreationTime.HighPart);
|
|
pFileInfo->Basic.LastAccessTime.LowPart = SmbGetUlong(&Response->LastAccessTime.LowPart);
|
|
pFileInfo->Basic.LastAccessTime.HighPart = SmbGetUlong(&Response->LastAccessTime.HighPart);
|
|
pFileInfo->Basic.LastWriteTime.LowPart = SmbGetUlong(&Response->LastWriteTime.LowPart);
|
|
pFileInfo->Basic.LastWriteTime.HighPart = SmbGetUlong(&Response->LastWriteTime.HighPart);
|
|
pFileInfo->Basic.ChangeTime.LowPart = SmbGetUlong(&Response->ChangeTime.LowPart);
|
|
pFileInfo->Basic.ChangeTime.HighPart = SmbGetUlong(&Response->ChangeTime.HighPart);
|
|
pFileInfo->Standard.AllocationSize.LowPart = SmbGetUlong(&Response->AllocationSize.LowPart);
|
|
pFileInfo->Standard.AllocationSize.HighPart = SmbGetUlong(&Response->AllocationSize.HighPart);
|
|
pFileInfo->Standard.EndOfFile.LowPart = SmbGetUlong(&Response->EndOfFile.LowPart);
|
|
pFileInfo->Standard.EndOfFile.HighPart = SmbGetUlong(&Response->EndOfFile.HighPart);
|
|
pFileInfo->Standard.Directory = Response->Directory;
|
|
|
|
|
|
// If the NT_CREATE_ANDX was to a downlevel server the access rights
|
|
// information is not available. Currently we default to maximum
|
|
// access for the current user and no access to other users in the
|
|
// disconnected mode for such files
|
|
|
|
smbSrvOpen->MaximalAccessRights = FILE_ALL_ACCESS;
|
|
|
|
smbSrvOpen->GuestMaximalAccessRights = 0;
|
|
|
|
if (Response->OplockLevel > SMB_OPLOCK_LEVEL_NONE) {
|
|
smbSrvOpen->FileStatusFlags = Response->FileStatusFlags;
|
|
smbSrvOpen->IsNtCreate = TRUE;
|
|
}
|
|
|
|
MRxSmbCreateFileSuccessTail (
|
|
RxContext,
|
|
&OrdinaryExchange->Create.MustRegainExclusiveResource,
|
|
StorageType,
|
|
Fid,
|
|
OrdinaryExchange->ServerVersion,
|
|
Response->OplockLevel,
|
|
CreateAction,
|
|
pFileInfo
|
|
);
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbFinishNTCreateAndX returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState ));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbFinishOpenAndX (
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
|
PRESP_OPEN_ANDX Response
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine actually gets the stuff out of the NTCreate_AndX response.
|
|
|
|
Arguments:
|
|
|
|
OrdinaryExchange - the exchange instance
|
|
|
|
Response - the response
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
|
|
ULONG Disposition = RxContext->Create.NtCreateParameters.Disposition;
|
|
|
|
RxCaptureFcb;
|
|
|
|
RX_FILE_TYPE StorageType;
|
|
SMB_FILE_ID Fid;
|
|
UCHAR OplockLevel = SMB_OPLOCK_LEVEL_NONE;
|
|
ULONG CreateAction;
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbFinishOpenAndX\n", 0 ));
|
|
ASSERT( NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT );
|
|
|
|
StorageType = RxInferFileType(RxContext);
|
|
if (StorageType == 0) {
|
|
StorageType = FileTypeFile;
|
|
RxDbgTrace( 0, Dbg, ("ChangedStoragetype %08lx\n", StorageType ));
|
|
}
|
|
|
|
ASSERT (StorageType == FileTypeFile);
|
|
|
|
Fid = SmbGetUshort(&Response->Fid);
|
|
|
|
if (SmbGetUshort(&Response->Action) & SMB_OACT_OPLOCK) {
|
|
OplockLevel = SMB_OPLOCK_LEVEL_BATCH; //we only ever ask for batch currently!!!
|
|
}
|
|
|
|
CreateAction = MRxSmbUnmapDisposition(SmbGetUshort(&Response->Action),Disposition);
|
|
|
|
pFileInfo->Basic.FileAttributes =
|
|
MRxSmbMapSmbAttributes(SmbGetUshort(&Response->FileAttributes));
|
|
|
|
// This is a downlevel server, the access rights
|
|
// information is not available. Currently we default to maximum
|
|
// access for the current user and no access to other users in the
|
|
// disconnected mode for such files
|
|
|
|
smbSrvOpen->MaximalAccessRights = FILE_ALL_ACCESS;
|
|
|
|
smbSrvOpen->GuestMaximalAccessRights = 0;
|
|
|
|
MRxSmbSecondsSince1970ToTime(
|
|
SmbGetUlong(&Response->LastWriteTimeInSeconds),
|
|
SmbCeGetExchangeServer(OrdinaryExchange),
|
|
&pFileInfo->Basic.LastWriteTime);
|
|
|
|
pFileInfo->Standard.NumberOfLinks = 1;
|
|
pFileInfo->Basic.CreationTime.HighPart = 0;
|
|
pFileInfo->Basic.CreationTime.LowPart = 0;
|
|
pFileInfo->Basic.LastAccessTime.HighPart = 0;
|
|
pFileInfo->Basic.LastAccessTime.LowPart = 0;
|
|
pFileInfo->Basic.ChangeTime.HighPart = 0;
|
|
pFileInfo->Basic.ChangeTime.LowPart = 0;
|
|
pFileInfo->Standard.EndOfFile.HighPart = 0;
|
|
pFileInfo->Standard.EndOfFile.LowPart = SmbGetUlong(&Response->DataSize);
|
|
pFileInfo->Standard.AllocationSize.QuadPart = pFileInfo->Standard.EndOfFile.QuadPart;
|
|
pFileInfo->Standard.Directory = (StorageType == FileTypeDirectory);
|
|
|
|
MRxSmbCreateFileSuccessTail (
|
|
RxContext,
|
|
&OrdinaryExchange->Create.MustRegainExclusiveResource,
|
|
StorageType,
|
|
Fid,
|
|
OrdinaryExchange->ServerVersion,
|
|
OplockLevel,
|
|
CreateAction,
|
|
pFileInfo );
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbFinishOpenAndX returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState ));
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxSmbFinishT2OpenFile (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN PRESP_OPEN2 Response,
|
|
IN OUT PBOOLEAN MustRegainExclusiveResource,
|
|
IN ULONG ServerVersion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine actually gets the stuff out of the T2/Open response.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the context of the operation being performed
|
|
|
|
Response - the response
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
RX_FILE_TYPE StorageType;
|
|
SMB_FILE_ID Fid;
|
|
ULONG CreateAction;
|
|
ULONG Disposition = RxContext->Create.NtCreateParameters.Disposition;
|
|
|
|
ULONG FileAttributes;
|
|
|
|
PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbFinishT2OpenFile\n", 0 ));
|
|
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
|
ASSERT( NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT );
|
|
|
|
FileAttributes = MRxSmbMapSmbAttributes(Response->FileAttributes);
|
|
|
|
StorageType = RxInferFileType(RxContext);
|
|
if (StorageType == 0) {
|
|
StorageType = (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
? FileTypeDirectory
|
|
: FileTypeFile;
|
|
}
|
|
|
|
if ((capFcb->OpenCount != 0) &&
|
|
(StorageType != 0) &&
|
|
(NodeType(capFcb) != RDBSS_STORAGE_NTC(StorageType))) {
|
|
return STATUS_OBJECT_TYPE_MISMATCH;
|
|
}
|
|
|
|
Fid = Response->Fid;
|
|
CreateAction = MRxSmbUnmapDisposition(Response->Action,Disposition);
|
|
RxDbgTrace( 0, Dbg, ("Storagetype %08lx/Fid %08lx/Action %08lx\n", StorageType, Fid, CreateAction ));
|
|
|
|
if (Response->Action & SMB_OACT_OPLOCK) {
|
|
smbSrvOpen->OplockLevel = SMB_OPLOCK_LEVEL_BATCH; //we only ever ask for batch currently!!!
|
|
}
|
|
|
|
RxContext->Create.ReturnedCreateInformation = CreateAction;
|
|
|
|
if (capFcb->OpenCount == 0) {
|
|
//
|
|
// Please note that we mask off the low bit on the time stamp here.
|
|
//
|
|
// We do this since the time stamps returned from other smbs (notably SmbGetAttrE and
|
|
// T2QueryDirectory) have a granularity of 2 seconds, while this
|
|
// time stamp has a granularity of 1 second. In order to make these
|
|
// two times consistant, we mask off the low order second in the
|
|
// timestamp. this idea was lifted from rdr1.
|
|
//
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
pServerEntry = SmbCeReferenceAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
|
ASSERT(pServerEntry != NULL);
|
|
MRxSmbSecondsSince1970ToTime(Response->CreationTimeInSeconds&0xfffffffe,
|
|
&pServerEntry->Server,
|
|
&pFileInfo->Basic.CreationTime);
|
|
SmbCeDereferenceServerEntry(pServerEntry);
|
|
}
|
|
|
|
pFileInfo->Basic.FileAttributes = FileAttributes;
|
|
pFileInfo->Basic.LastAccessTime.QuadPart = 0;
|
|
pFileInfo->Basic.LastWriteTime.QuadPart = 0;
|
|
pFileInfo->Basic.ChangeTime.QuadPart = 0;
|
|
|
|
pFileInfo->Standard.NumberOfLinks = 1;
|
|
pFileInfo->Standard.AllocationSize.QuadPart =
|
|
pFileInfo->Standard.EndOfFile.QuadPart = Response->DataSize;
|
|
pFileInfo->Standard.Directory = (StorageType == FileTypeDirectory);
|
|
|
|
MRxSmbCreateFileSuccessTail(
|
|
RxContext,
|
|
MustRegainExclusiveResource,
|
|
StorageType,
|
|
Fid,
|
|
ServerVersion,
|
|
smbSrvOpen->OplockLevel,
|
|
CreateAction,
|
|
pFileInfo);
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbFinishT2OpenFile returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState ));
|
|
|
|
return Status;
|
|
}
|
|
|
|
//#define MULTI_EA_MDL
|
|
|
|
NTSTATUS
|
|
MRxSmbT2OpenFile(
|
|
IN OUT PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a file across the network that has
|
|
1) EAs,
|
|
2) a name so long that it wont fit in an ordinary packet
|
|
|
|
We silently ignore it if SDs are specified.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
RxCaptureFcb;
|
|
USHORT Setup = TRANS2_OPEN2;
|
|
|
|
BOOLEAN MustRegainExclusiveResource = FALSE;
|
|
|
|
SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
|
|
SMB_TRANSACTION_SEND_PARAMETERS SendParameters;
|
|
SMB_TRANSACTION_RECEIVE_PARAMETERS ReceiveParameters;
|
|
SMB_TRANSACTION_OPTIONS TransactionOptions;
|
|
|
|
PREQ_OPEN2 pCreateRequest = NULL;
|
|
RESP_OPEN2 CreateResponse;
|
|
|
|
PBYTE SendParamsBuffer,ReceiveParamsBuffer;
|
|
ULONG SendParamsBufferLength,ReceiveParamsBufferLength;
|
|
|
|
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
|
|
MRXSMB_CREATE_PARAMETERS SmbCp;
|
|
PNT_CREATE_PARAMETERS cp = &RxContext->Create.NtCreateParameters;
|
|
USHORT smbDisposition;
|
|
USHORT smbSharingMode;
|
|
USHORT smbAttributes;
|
|
ULONG smbFileSize;
|
|
USHORT smbOpenMode;
|
|
USHORT OpenFlags = SMB_OPEN_QUERY_INFORMATION;
|
|
USHORT SearchAttributes = SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN;
|
|
ULONG SecondsSince1970;
|
|
BOOLEAN IsUnicode;
|
|
|
|
ULONG OS2_EaLength = 0;
|
|
PFEALIST ServerEaList = NULL;
|
|
|
|
ULONG EaLength = RxContext->Create.EaLength;
|
|
PFILE_FULL_EA_INFORMATION EaBuffer = RxContext->Create.EaBuffer;
|
|
|
|
ULONG FileNameLength,AllocationLength;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(0, Dbg, ("MRxSmbT2Open---\n"));
|
|
DbgPrint("MRxSmbT2Open---%08lx %08lx\n",EaBuffer,EaLength);
|
|
MRxSmbAdjustCreateParameters(RxContext,&SmbCp);
|
|
|
|
FileNameLength = RemainingName->Length;
|
|
|
|
AllocationLength = WordAlign(FIELD_OFFSET(REQ_OPEN2,Buffer[0])) +
|
|
FileNameLength+sizeof(WCHAR);
|
|
|
|
pCreateRequest = (PREQ_OPEN2)
|
|
RxAllocatePoolWithTag(
|
|
PagedPool,
|
|
AllocationLength,
|
|
'bmsX' );
|
|
|
|
if (pCreateRequest==NULL) {
|
|
RxDbgTrace(0, Dbg, (" --> Couldn't get the pCreateRequest!\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (capFcb->pNetRoot->Type == NET_ROOT_DISK) {
|
|
OpenFlags |= (SMB_OPEN_OPLOCK | SMB_OPEN_OPBATCH);
|
|
}
|
|
|
|
{
|
|
BOOLEAN GoodTime;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
LARGE_INTEGER CurrentTime;
|
|
|
|
pServerEntry = SmbCeReferenceAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
|
ASSERT(pServerEntry != NULL);
|
|
IsUnicode = BooleanFlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE);
|
|
|
|
KeQuerySystemTime(&CurrentTime);
|
|
|
|
GoodTime = MRxSmbTimeToSecondsSince1970(
|
|
&CurrentTime,
|
|
&pServerEntry->Server,
|
|
&SecondsSince1970
|
|
);
|
|
|
|
SmbCeDereferenceServerEntry(pServerEntry);
|
|
|
|
if (!GoodTime) {
|
|
SecondsSince1970 = 0;
|
|
}
|
|
}
|
|
|
|
pCreateRequest->Flags = OpenFlags; // Creation flags
|
|
pCreateRequest->DesiredAccess = smbSharingMode;
|
|
pCreateRequest->SearchAttributes = SearchAttributes;
|
|
pCreateRequest->FileAttributes = smbAttributes;
|
|
pCreateRequest->CreationTimeInSeconds = SecondsSince1970;
|
|
pCreateRequest->OpenFunction = smbDisposition;
|
|
pCreateRequest->AllocationSize = smbFileSize;
|
|
|
|
RtlZeroMemory(
|
|
&pCreateRequest->Reserved[0],
|
|
sizeof(pCreateRequest->Reserved));
|
|
|
|
{
|
|
NTSTATUS StringStatus;
|
|
PBYTE NameBuffer = &pCreateRequest->Buffer[0];
|
|
ULONG OriginalLengthRemaining = FileNameLength+sizeof(WCHAR);
|
|
ULONG LengthRemaining = OriginalLengthRemaining;
|
|
if (IsUnicode) {
|
|
StringStatus = SmbPutUnicodeString(&NameBuffer,RemainingName,&LengthRemaining);
|
|
} else {
|
|
StringStatus = SmbPutUnicodeStringAsOemString(&NameBuffer,RemainingName,&LengthRemaining);
|
|
DbgPrint("This is the name <%s>\n",&pCreateRequest->Buffer[0]);
|
|
}
|
|
ASSERT(StringStatus==STATUS_SUCCESS);
|
|
SendParamsBufferLength = FIELD_OFFSET(REQ_OPEN2,Buffer[0])
|
|
+OriginalLengthRemaining-LengthRemaining;
|
|
}
|
|
|
|
|
|
SendParamsBuffer = (PBYTE)pCreateRequest;
|
|
//SendParamsBufferLength = qweee;
|
|
ReceiveParamsBuffer = (PBYTE)&CreateResponse;
|
|
ReceiveParamsBufferLength = sizeof(CreateResponse);
|
|
|
|
if (EaLength!=0) {
|
|
//
|
|
// Convert Nt format FEALIST to OS/2 format
|
|
//
|
|
DbgPrint("MRxSmbT2Open again---%08lx %08lx\n",EaBuffer,EaLength);
|
|
OS2_EaLength = MRxSmbNtFullEaSizeToOs2 ( EaBuffer );
|
|
if ( OS2_EaLength > 0x0000ffff ) {
|
|
Status = STATUS_EA_TOO_LARGE;
|
|
goto FINALLY;
|
|
}
|
|
|
|
ServerEaList = RxAllocatePoolWithTag (PagedPool, OS2_EaLength, 'Ebms');
|
|
if ( ServerEaList == NULL ) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
|
|
MRxSmbNtFullListToOs2 ( EaBuffer, ServerEaList );
|
|
} else {
|
|
OS2_EaLength = 0;
|
|
ServerEaList = NULL;
|
|
}
|
|
|
|
RxDbgTrace(0, Dbg, ("MRxSmbT2Open---os2ea %d buf %x\n", OS2_EaLength,ServerEaList));
|
|
DbgPrint("MRxSmbT2Open OS2 eastuff---%08lx %08lx\n",ServerEaList,OS2_EaLength);
|
|
|
|
TransactionOptions = RxDefaultTransactionOptions;
|
|
TransactionOptions.Flags |= SMB_XACT_FLAGS_FID_NOT_NEEDED;
|
|
|
|
if (BooleanFlagOn(capFcb->pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT) &&
|
|
(RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT))) {
|
|
TransactionOptions.Flags |= SMB_XACT_FLAGS_DFS_AWARE;
|
|
}
|
|
|
|
ASSERT (MrxSmbCreateTransactPacketSize>=100); //don't try something strange
|
|
TransactionOptions.MaximumTransmitSmbBufferSize = MrxSmbCreateTransactPacketSize;
|
|
|
|
RxReleaseFcbResourceInMRx( capFcb );
|
|
MustRegainExclusiveResource = TRUE;
|
|
|
|
Status = SmbCeTransact(
|
|
RxContext,
|
|
&TransactionOptions,
|
|
&Setup,
|
|
sizeof(Setup),
|
|
NULL,
|
|
0,
|
|
SendParamsBuffer,
|
|
SendParamsBufferLength,
|
|
ReceiveParamsBuffer,
|
|
ReceiveParamsBufferLength,
|
|
ServerEaList,
|
|
OS2_EaLength,
|
|
NULL,
|
|
0,
|
|
&ResumptionContext);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
MRxSmbFinishT2OpenFile (
|
|
RxContext,
|
|
&CreateResponse,
|
|
&MustRegainExclusiveResource,
|
|
ResumptionContext.ServerVersion);
|
|
|
|
if (cp->Disposition == FILE_OPEN) {
|
|
MRxSmbAdjustReturnedCreateAction(RxContext);
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
ASSERT (Status != (STATUS_PENDING));
|
|
|
|
if (pCreateRequest != NULL) {
|
|
RxFreePool(pCreateRequest);
|
|
}
|
|
|
|
if (ServerEaList != NULL) {
|
|
RxFreePool(ServerEaList);
|
|
}
|
|
|
|
if (MustRegainExclusiveResource) {
|
|
//this is required because of oplock breaks
|
|
RxAcquireExclusiveFcbResourceInMRx(capFcb );
|
|
}
|
|
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbFinishLongNameCreateFile (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN PRESP_CREATE_WITH_SD_OR_EA Response,
|
|
IN PBOOLEAN MustRegainExclusiveResource,
|
|
IN ULONG ServerVersion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine actually gets the stuff out of the NTTransact/NTCreateWithEAsOrSDs response.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the context of the operation being performed
|
|
Response - the response
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
|
|
|
|
RX_FILE_TYPE StorageType;
|
|
SMB_FILE_ID Fid;
|
|
ULONG CreateAction;
|
|
|
|
PSMBPSE_FILEINFO_BUNDLE pFileInfo = &smbSrvOpen->FileInfo;
|
|
|
|
FCB_INIT_PACKET InitPacket;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbFinishLongNameCreateFile\n", 0 ));
|
|
|
|
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
|
ASSERT( NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT );
|
|
|
|
if (RxContext->Create.NtCreateParameters.CreateOptions & FILE_DELETE_ON_CLOSE) {
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
SetFlag((smbFcb)->MFlags,SMB_FCB_FLAG_SENT_DISPOSITION_INFO);
|
|
}
|
|
|
|
StorageType = RxInferFileType(RxContext);
|
|
|
|
if (StorageType == 0) {
|
|
StorageType = Response->Directory
|
|
?FileTypeDirectory
|
|
:FileTypeFile;
|
|
RxDbgTrace( 0, Dbg, ("ChangedStoragetype %08lx\n", StorageType ));
|
|
}
|
|
|
|
if ((capFcb->OpenCount != 0) &&
|
|
(StorageType != 0) &&
|
|
(NodeType(capFcb) != RDBSS_STORAGE_NTC(StorageType))) {
|
|
return STATUS_OBJECT_TYPE_MISMATCH;
|
|
}
|
|
|
|
Fid = SmbGetUshort(&Response->Fid);
|
|
|
|
CreateAction = SmbGetUlong(&Response->CreateAction);
|
|
|
|
pFileInfo->Basic.FileAttributes = Response->FileAttributes;
|
|
pFileInfo->Basic.CreationTime = Response->CreationTime;
|
|
pFileInfo->Basic.LastAccessTime = Response->LastAccessTime;
|
|
pFileInfo->Basic.LastWriteTime = Response->LastWriteTime;
|
|
pFileInfo->Basic.ChangeTime = Response->ChangeTime;
|
|
pFileInfo->Standard.NumberOfLinks = 1;
|
|
pFileInfo->Standard.AllocationSize = Response->AllocationSize;
|
|
pFileInfo->Standard.EndOfFile = Response->EndOfFile;
|
|
pFileInfo->Standard.Directory = Response->Directory;
|
|
|
|
if (((pFileInfo->Standard.AllocationSize.HighPart == pFileInfo->Standard.EndOfFile.HighPart) &&
|
|
(pFileInfo->Standard.AllocationSize.LowPart < pFileInfo->Standard.EndOfFile.LowPart)) ||
|
|
(pFileInfo->Standard.AllocationSize.HighPart < pFileInfo->Standard.EndOfFile.HighPart)) {
|
|
pFileInfo->Standard.AllocationSize = pFileInfo->Standard.EndOfFile;
|
|
}
|
|
|
|
smbSrvOpen->MaximalAccessRights = (USHORT)0x1ff;
|
|
|
|
smbSrvOpen->GuestMaximalAccessRights = (USHORT)0;
|
|
|
|
MRxSmbCreateFileSuccessTail(
|
|
RxContext,
|
|
MustRegainExclusiveResource,
|
|
StorageType,
|
|
Fid,
|
|
ServerVersion,
|
|
Response->OplockLevel,
|
|
CreateAction,
|
|
pFileInfo);
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbFinishLongNameCreateFile returning %08lx, fcbstate =%08lx\n", Status, capFcb->FcbState ));
|
|
return Status;
|
|
}
|
|
|
|
|
|
//force_t2_open doesn't work on an NT server......sigh........
|
|
#define ForceT2Open FALSE
|
|
|
|
NTSTATUS
|
|
MRxSmbCreateWithEasSidsOrLongName (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a file across the network that has
|
|
1) EAs,
|
|
2) SIDs, or
|
|
3) a name so long that it wont fit in an ordinary packet
|
|
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
RxCaptureFcb;
|
|
|
|
BOOLEAN MustRegainExclusiveResource = FALSE;
|
|
|
|
SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
|
|
SMB_TRANSACTION_SEND_PARAMETERS SendParameters;
|
|
SMB_TRANSACTION_RECEIVE_PARAMETERS ReceiveParameters;
|
|
SMB_TRANSACTION_OPTIONS TransactionOptions;
|
|
|
|
PREQ_CREATE_WITH_SD_OR_EA pCreateRequest = NULL;
|
|
|
|
PBYTE SendParamsBuffer,ReceiveParamsBuffer,SendDataBuffer;
|
|
ULONG SendParamsBufferLength,ReceiveParamsBufferLength,SendDataBufferLength;
|
|
|
|
PRESP_CREATE_WITH_SD_OR_EA CreateResponse;
|
|
|
|
PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
|
PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
|
|
MRXSMB_CREATE_PARAMETERS SmbCp;
|
|
PNT_CREATE_PARAMETERS cp = &RxContext->Create.NtCreateParameters;
|
|
|
|
|
|
ULONG EaLength,SdLength,PadLength,TotalLength;
|
|
PBYTE CombinedBuffer = NULL;
|
|
#ifdef MULTI_EA_MDL
|
|
PRX_BUFFER EaMdl2 = NULL;
|
|
PRX_BUFFER EaMdl3 = NULL;
|
|
#endif
|
|
PMDL EaMdl = NULL;
|
|
PMDL SdMdl = NULL; BOOLEAN SdMdlLocked = FALSE;
|
|
PMDL PadMdl = NULL;
|
|
PMDL DataMdl = NULL;
|
|
|
|
ULONG FileNameLength,AllocationLength;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(0, Dbg, ("!!MRxSmbCreateWithEasSidsOrLongName---\n"));
|
|
|
|
{
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
BOOLEAN DoesNtSmbs;
|
|
|
|
pServerEntry = SmbCeReferenceAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
|
ASSERT(pServerEntry != NULL);
|
|
DoesNtSmbs = BooleanFlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS);
|
|
|
|
SmbCeDereferenceServerEntry(pServerEntry);
|
|
if (!DoesNtSmbs || ForceT2Open) {
|
|
Status = MRxSmbT2OpenFile(RxContext);
|
|
if (ForceT2Open && (Status!=STATUS_SUCCESS)) {
|
|
DbgPrint("BadStatus = %08lx\n",Status);
|
|
}
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
|
|
MRxSmbAdjustCreateParameters(RxContext,&SmbCp);
|
|
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCreateWithEasSidsOrLongName---\n"));
|
|
FileNameLength = RemainingName->Length;
|
|
|
|
AllocationLength = WordAlign(FIELD_OFFSET(REQ_CREATE_WITH_SD_OR_EA,Buffer[0]))
|
|
+FileNameLength;
|
|
|
|
pCreateRequest = (PREQ_CREATE_WITH_SD_OR_EA)RxAllocatePoolWithTag( PagedPool,
|
|
AllocationLength,'bmsX' );
|
|
if (pCreateRequest==NULL) {
|
|
RxDbgTrace(0, Dbg, (" --> Couldn't get the pCreateRequest!\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
|
|
RtlCopyMemory((PBYTE)WordAlignPtr(&pCreateRequest->Buffer[0]),RemainingName->Buffer,FileNameLength);
|
|
|
|
EaLength = RxContext->Create.EaLength;
|
|
SdLength = RxContext->Create.SdLength;
|
|
|
|
pCreateRequest->Flags = 0; //norelopen // Optional directory for relative open
|
|
pCreateRequest->RootDirectoryFid = 0; //norelopen // Optional directory for relative open
|
|
pCreateRequest->DesiredAccess = cp->DesiredAccess; // Desired access (NT format)
|
|
pCreateRequest->AllocationSize = cp->AllocationSize; // The initial allocation size in bytes
|
|
pCreateRequest->FileAttributes = cp->FileAttributes; // The file attributes
|
|
pCreateRequest->ShareAccess = cp->ShareAccess; // The share access
|
|
pCreateRequest->CreateDisposition = cp->Disposition; // Action to take if file exists or not
|
|
pCreateRequest->CreateOptions = cp->CreateOptions; // Options for creating a new file
|
|
pCreateRequest->SecurityDescriptorLength = SdLength; // Length of SD in bytes
|
|
pCreateRequest->EaLength = EaLength; // Length of EA in bytes
|
|
pCreateRequest->NameLength = FileNameLength; // Length of name in characters
|
|
pCreateRequest->ImpersonationLevel = cp->ImpersonationLevel; // Security QOS information
|
|
pCreateRequest->SecurityFlags = SmbCp.SecurityFlags; // Security QOS information
|
|
// UCHAR Buffer[1];
|
|
// //UCHAR Name[]; // The name of the file (not NUL terminated)
|
|
|
|
SendParamsBuffer = (PBYTE)pCreateRequest;
|
|
SendParamsBufferLength = AllocationLength;
|
|
ReceiveParamsBuffer = (PBYTE)&CreateResponse;
|
|
ReceiveParamsBufferLength = sizeof(CreateResponse);
|
|
|
|
if ((EaLength==0)||(SdLength==0)) {
|
|
PadLength = 0;
|
|
if (EaLength) {
|
|
// the EaBuffer is in nonpaged pool...so we dont lock or unlock
|
|
PBYTE EaBuffer = RxContext->Create.EaBuffer;
|
|
#ifdef MULTI_EA_MDL
|
|
ULONG EaLength0,EaLength2,EaLength3;
|
|
PBYTE EaBuffer2,EaBuffer3;
|
|
ASSERT(EaLength>11);
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCreateWithEasSidsOrLongName--MULTIEAMDL\n"));
|
|
EaLength0 = (EaLength - 4)>>1;
|
|
EaBuffer2 = EaBuffer + EaLength0;
|
|
EaLength2 = 4;
|
|
EaBuffer3 = EaBuffer2 + EaLength2;
|
|
EaLength3 = EaLength - (EaBuffer3 - EaBuffer);
|
|
EaMdl = RxAllocateMdl(EaBuffer,EaLength0);
|
|
EaMdl2 = RxAllocateMdl(EaBuffer2,EaLength2);
|
|
EaMdl3 = RxAllocateMdl(EaBuffer3,EaLength3);
|
|
if ( (EaMdl==NULL) || (EaMdl2==NULL) || (EaMdl3==NULL) ) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
MmBuildMdlForNonPagedPool(EaMdl);
|
|
MmBuildMdlForNonPagedPool(EaMdl2);
|
|
MmBuildMdlForNonPagedPool(EaMdl3);
|
|
EaMdl3->Next = NULL;
|
|
EaMdl2->Next = EaMdl3;
|
|
EaMdl->Next = EaMdl2;
|
|
#else
|
|
EaMdl = RxAllocateMdl(EaBuffer,EaLength);
|
|
if (EaMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
MmBuildMdlForNonPagedPool(EaMdl);
|
|
EaMdl->Next = NULL;
|
|
#endif
|
|
DataMdl = EaMdl;
|
|
}
|
|
|
|
if (SdLength) {
|
|
SdMdl = RxAllocateMdl(cp->SecurityContext->AccessState->SecurityDescriptor,SdLength);
|
|
if (SdMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RxProbeAndLockPages(SdMdl,KernelMode,IoModifyAccess,Status);
|
|
}
|
|
if (!NT_SUCCESS(Status)) goto FINALLY;
|
|
SdMdlLocked = TRUE;
|
|
PadLength = LongAlign(SdLength) - SdLength;
|
|
if (PadLength && EaLength) {
|
|
PadMdl = RxAllocateMdl(0,(sizeof(DWORD) + PAGE_SIZE - 1));
|
|
if (PadMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
RxBuildPaddingPartialMdl(PadMdl,PadLength);
|
|
PadMdl->Next = DataMdl;
|
|
DataMdl = PadMdl;
|
|
}
|
|
SdMdl->Next = DataMdl;
|
|
DataMdl = SdMdl;
|
|
}
|
|
} else {
|
|
ULONG EaOffset = LongAlign(SdLength);
|
|
ULONG CombinedBufferLength = EaOffset + EaLength;
|
|
CombinedBuffer = RxAllocatePoolWithTag(PagedPool,CombinedBufferLength,'bms');
|
|
if (CombinedBuffer==NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
SdMdl = RxAllocateMdl(CombinedBuffer,CombinedBufferLength);
|
|
if (SdMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RxProbeAndLockPages(SdMdl,KernelMode,IoModifyAccess,Status);
|
|
}
|
|
if (!NT_SUCCESS(Status)) goto FINALLY;
|
|
SdMdlLocked = TRUE;
|
|
RtlCopyMemory(CombinedBuffer,cp->SecurityContext->AccessState->SecurityDescriptor,SdLength);
|
|
RtlZeroMemory(CombinedBuffer+SdLength,EaOffset-SdLength);
|
|
RtlCopyMemory(CombinedBuffer+EaOffset,RxContext->Create.EaBuffer,EaLength);
|
|
DataMdl = SdMdl;
|
|
}
|
|
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCreateWithEasSidsOrLongName---s,p,ea %d,%d,%d buf %x\n",
|
|
SdLength,PadLength,EaLength,RxContext->Create.EaBuffer));
|
|
|
|
TransactionOptions = RxDefaultTransactionOptions;
|
|
TransactionOptions.NtTransactFunction = NT_TRANSACT_CREATE;
|
|
TransactionOptions.Flags |= SMB_XACT_FLAGS_FID_NOT_NEEDED;
|
|
//dfs is only for nt servers........
|
|
//if (BooleanFlagOn(capFcb->pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT)
|
|
// && (RxContext->Create.NtCreateParameters.DfsContext == (PVOID)DFS_OPEN_CONTEXT)) {
|
|
// TransactionOptions.Flags |= SMB_XACT_FLAGS_DFS_AWARE;
|
|
//}
|
|
|
|
|
|
ASSERT (MrxSmbCreateTransactPacketSize>=100); //don't try something strange
|
|
TransactionOptions.MaximumTransmitSmbBufferSize = MrxSmbCreateTransactPacketSize;
|
|
|
|
if (DataMdl!=NULL) {
|
|
SendDataBuffer = MmGetSystemAddressForMdlSafe(DataMdl,LowPagePriority);
|
|
|
|
if (SendDataBuffer == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto FINALLY;
|
|
}
|
|
|
|
SendDataBufferLength = EaLength+SdLength+PadLength;
|
|
} else {
|
|
SendDataBuffer = NULL;
|
|
SendDataBufferLength = 0;
|
|
}
|
|
|
|
RxReleaseFcbResourceInMRx(capFcb );
|
|
MustRegainExclusiveResource = TRUE;
|
|
|
|
Status = SmbCeTransact(
|
|
RxContext,
|
|
&TransactionOptions,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
SendParamsBuffer,
|
|
SendParamsBufferLength,
|
|
ReceiveParamsBuffer,
|
|
ReceiveParamsBufferLength,
|
|
SendDataBuffer,
|
|
SendDataBufferLength,
|
|
NULL,
|
|
0,
|
|
&ResumptionContext);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
MRxSmbFinishLongNameCreateFile (
|
|
RxContext,
|
|
(PRESP_CREATE_WITH_SD_OR_EA)&CreateResponse,
|
|
&MustRegainExclusiveResource,
|
|
ResumptionContext.ServerVersion);
|
|
|
|
if (cp->Disposition == FILE_OPEN) {
|
|
MRxSmbAdjustReturnedCreateAction(RxContext);
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
ASSERT (Status != (STATUS_PENDING));
|
|
|
|
|
|
if (SdMdlLocked) MmUnlockPages(SdMdl);
|
|
if (EaMdl != NULL) { IoFreeMdl(EaMdl); }
|
|
#ifdef MULTI_EA_MDL
|
|
if (EaMdl2 != NULL) { IoFreeMdl(EaMdl2); }
|
|
if (EaMdl3 != NULL) { IoFreeMdl(EaMdl3); }
|
|
#endif
|
|
if (PadMdl != NULL) { IoFreeMdl(PadMdl); }
|
|
if (SdMdl != NULL) { IoFreeMdl(SdMdl); }
|
|
|
|
if (pCreateRequest != NULL) {
|
|
RxFreePool(pCreateRequest);
|
|
}
|
|
|
|
if (CombinedBuffer != NULL) {
|
|
RxFreePool(CombinedBuffer);
|
|
}
|
|
|
|
if (MustRegainExclusiveResource) {
|
|
//this is required because of oplock breaks
|
|
RxAcquireExclusiveFcbResourceInMRx(capFcb );
|
|
}
|
|
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
return Status;
|
|
}
|
|
|
|
|
|
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
|
|
MRxSmbTruncate(
|
|
IN PRX_CONTEXT pRxContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine truncates the contents of a file system object
|
|
|
|
Arguments:
|
|
|
|
pRxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
ASSERT(!"Found a truncate");
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbCleanupFobx(
|
|
IN PRX_CONTEXT RxContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine cleansup a file system object...normally a noop.
|
|
|
|
Arguments:
|
|
|
|
pRxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PUNICODE_STRING RemainingName;
|
|
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
|
|
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
|
|
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
|
ASSERT ( NodeTypeIsFcb(capFcb) );
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbCleanup\n", 0 ));
|
|
|
|
MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"Cleanup");
|
|
|
|
if (FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED)) {
|
|
RxDbgTrace(-1, Dbg, ("File orphaned\n"));
|
|
} else {
|
|
RxDbgTrace(-1, Dbg, ("File not for closing at cleanup\n"));
|
|
}
|
|
return (STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbForcedClose(
|
|
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:
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
#undef Dbg
|
|
#define Dbg (DEBUG_TRACE_CLOSE)
|
|
|
|
NTSTATUS
|
|
MRxSmbCloseSrvOpen(
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes a file across the network
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PUNICODE_STRING RemainingName;
|
|
|
|
RxCaptureFcb;
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
|
|
RxCaptureFobx;
|
|
|
|
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
|
|
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
|
|
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)(capFcb->pNetRoot->pSrvCall->Context);
|
|
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
|
|
|
|
BOOLEAN NeedDelete;
|
|
BOOLEAN SearchHandleOpen = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT ( NodeTypeIsFcb(capFcb) );
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbClose\n", 0 ));
|
|
|
|
if (TypeOfOpen==RDBSS_NTC_STORAGE_TYPE_DIRECTORY) {
|
|
SearchHandleOpen = BooleanFlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
|
|
MRxSmbDeallocateSideBuffer(RxContext,smbFobx,"Close");
|
|
if (smbFobx->Enumeration.ResumeInfo!=NULL) {
|
|
RxFreePool(smbFobx->Enumeration.ResumeInfo);
|
|
smbFobx->Enumeration.ResumeInfo = NULL;
|
|
}
|
|
}
|
|
|
|
if (!smbSrvOpen->DeferredOpenInProgress &&
|
|
smbSrvOpen->DeferredOpenContext != NULL) {
|
|
RxFreePool(smbSrvOpen->DeferredOpenContext);
|
|
smbSrvOpen->DeferredOpenContext = NULL;
|
|
RxDbgTrace(0, Dbg, ("Free deferred open context for file %wZ %lX\n",GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext),smbSrvOpen));
|
|
}
|
|
|
|
//Remove the open context from the list if it is a paging file
|
|
if (FlagOn( capFcb->FcbState, FCB_STATE_PAGING_FILE )) {
|
|
PLIST_ENTRY pListHead = &MRxSmbPagingFilesSrvOpenList;
|
|
PLIST_ENTRY pListEntry = pListHead->Flink;
|
|
|
|
ASSERT(FALSE);
|
|
while (pListEntry != pListHead) {
|
|
PPAGING_FILE_CONTEXT PagingFileContext;
|
|
|
|
PagingFileContext = (PPAGING_FILE_CONTEXT)CONTAINING_RECORD(pListEntry,PAGING_FILE_CONTEXT,ContextList);
|
|
if (PagingFileContext->pSrvOpen == SrvOpen) {
|
|
RemoveEntryList(pListEntry);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED)) {
|
|
RxDbgTrace(-1, Dbg, ("File orphan\n"));
|
|
goto FINALLY;
|
|
}
|
|
|
|
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"));
|
|
goto FINALLY;
|
|
}
|
|
|
|
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
|
|
|
if (smbSrvOpen->Fid == 0xffff) {
|
|
// File has already been closed on the server.
|
|
goto FINALLY;
|
|
}
|
|
|
|
NeedDelete = FlagOn(capFcb->FcbState,FCB_STATE_DELETE_ON_CLOSE) && (capFcb->OpenCount == 0);
|
|
|
|
if (!NeedDelete &&
|
|
!SearchHandleOpen &&
|
|
FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)){
|
|
RxDbgTrace(-1, Dbg, ("File was not really open\n"));
|
|
goto FINALLY;
|
|
}
|
|
|
|
if (smbSrvOpen->Version == pServerEntry->Server.Version) {
|
|
Status = SmbPseCreateOrdinaryExchange(
|
|
RxContext,
|
|
SrvOpen->pVNetRoot,
|
|
SMBPSE_OE_FROM_CLOSESRVCALL,
|
|
SmbPseExchangeStart_Close,
|
|
&OrdinaryExchange
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
|
|
goto FINALLY;
|
|
}
|
|
|
|
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
|
|
|
|
ASSERT (Status != (STATUS_PENDING));
|
|
|
|
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbClose exit with status=%08lx\n", Status ));
|
|
|
|
FINALLY:
|
|
|
|
if (!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) &&
|
|
(pServerEntry != NULL)) {
|
|
|
|
MRxSmbDecrementSrvOpenCount(
|
|
pServerEntry,
|
|
smbSrvOpen->Version,
|
|
SrvOpen);
|
|
|
|
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxSmbBuildClose (
|
|
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 = MRxSmbGetSrvOpenExtension(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'))
|
|
);
|
|
|
|
MRxSmbDumpStufferState (1100,"SMB w/ CLOSE before stuffing",StufferState);
|
|
|
|
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
|
|
);
|
|
MRxSmbDumpStufferState (700,"SMB w/ close after stuffing",StufferState);
|
|
|
|
FINALLY:
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
return(Status);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbBuildFindClose (
|
|
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_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(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'))
|
|
);
|
|
|
|
MRxSmbDumpStufferState (1100,"SMB w/ CLOSE before stuffing",StufferState);
|
|
|
|
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
|
|
);
|
|
MRxSmbDumpStufferState (700,"SMB w/ FindClose2 after stuffing",StufferState);
|
|
|
|
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 = MRxSmbGetFcbExtension(capFcb);
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
|
|
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry= SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
|
|
|
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 = MRxSmbBuildFindClose(StufferState);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
PSMBCE_SERVER pServer;
|
|
// Ensure that the searchhandle is valid
|
|
|
|
pServer = SmbCeGetExchangeServer(OrdinaryExchange);
|
|
|
|
if (smbFobx->Enumeration.Version == pServer->Version) {
|
|
NTSTATUS InnerStatus;
|
|
InnerStatus = SmbPseOrdinaryExchange(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
|
SMBPSE_OETYPE_FINDCLOSE
|
|
);
|
|
}
|
|
}
|
|
|
|
// if this didn't work, there's nothing you can do............
|
|
ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
|
|
ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST);
|
|
}
|
|
}
|
|
|
|
if (OrdinaryExchange->EntryPoint == SMBPSE_OE_FROM_CLEANUPFOBX) {
|
|
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Close exit after searchhandle close %08lx\n", Status ));
|
|
return Status;
|
|
}
|
|
|
|
if ( !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN) ) {
|
|
//even if it didn't work there's nothing i can do......keep going
|
|
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN);
|
|
|
|
MRxSmbDecrementSrvOpenCount(pServerEntry,pServerEntry->Server.Version,SrvOpen);
|
|
|
|
Status = MRxSmbBuildClose(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);
|
|
|
|
if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_WRITE_ONLY_HANDLE)) {
|
|
smbFcb->WriteOnlySrvOpenCount--;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((Status!=STATUS_SUCCESS) ||
|
|
(capFcb->OpenCount > 0) ||
|
|
!FlagOn(capFcb->FcbState,FCB_STATE_DELETE_ON_CLOSE)) {
|
|
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Close exit w %08lx\n", Status ));
|
|
return Status;
|
|
}
|
|
|
|
RxDbgTrace(0, Dbg, ("SmbPseExchangeStart_Close delete on close\n" ));
|
|
|
|
if ( !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_FILE_DELETED)) {
|
|
if (!FlagOn(smbFcb->MFlags,SMB_FCB_FLAG_SENT_DISPOSITION_INFO)) {
|
|
//no need for setinitsmb here because coredelete does a init-on-resuse.....
|
|
//it's not good to pass the name this way...........
|
|
OrdinaryExchange->pPathArgument1 = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
|
|
Status = MRxSmbCoreDeleteForSupercedeOrClose(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
|
((BOOLEAN)( NodeType(capFcb)==RDBSS_NTC_STORAGE_TYPE_DIRECTORY )));
|
|
|
|
if (Status == STATUS_FILE_IS_A_DIRECTORY) {
|
|
Status = MRxSmbCoreDeleteForSupercedeOrClose(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
|
TRUE);
|
|
}
|
|
} else {
|
|
SetFlag(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_FILE_DELETED);
|
|
}
|
|
}
|
|
|
|
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:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
|
|
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbFinishClose\n", 0 ));
|
|
|
|
SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishClose:");
|
|
|
|
if (Response->WordCount != 0 ||
|
|
SmbGetUshort(&Response->ByteCount) !=0) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
} else {
|
|
if (OrdinaryExchange->OEType == SMBPSE_OETYPE_CLOSE) {
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
smbSrvOpen->Fid = 0xffff;
|
|
}
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbFinishClose returning %08lx\n", Status ));
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
MRxSmbIsStreamFile(
|
|
PUNICODE_STRING FileName,
|
|
PUNICODE_STRING AdjustFileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if it is a stream file and return the root file name if true.
|
|
|
|
Arguments:
|
|
|
|
FileName - the file name needs to be parsed
|
|
AdjustFileName - the file name contains only root name of the stream
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - stream file
|
|
|
|
--*/
|
|
{
|
|
USHORT i;
|
|
BOOLEAN IsStream = FALSE;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
for (i=0;i<FileName->Length/sizeof(WCHAR);i++) {
|
|
if (FileName->Buffer[i] == L':') {
|
|
IsStream = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (AdjustFileName != NULL) {
|
|
if (IsStream) {
|
|
AdjustFileName->Length =
|
|
AdjustFileName->MaximumLength = i * sizeof(WCHAR);
|
|
AdjustFileName->Buffer = FileName->Buffer;
|
|
} else {
|
|
AdjustFileName->Length =
|
|
AdjustFileName->MaximumLength = 0;
|
|
AdjustFileName->Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
return IsStream;
|
|
}
|
|
|