845 lines
29 KiB
C
845 lines
29 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 - 1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
write.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the mini redirector call down routines pertaining
|
||
to write of file system objects.
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
#pragma warning(error:4101) // Unreferenced local variable
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, MRxSmbWrite)
|
||
#pragma alloc_text(PAGE, MRxSmbBuildWriteRequest)
|
||
#pragma alloc_text(PAGE, SmbPseExchangeStart_Write)
|
||
#pragma alloc_text(PAGE, MRxSmbFinishWrite)
|
||
#endif
|
||
|
||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_WRITE)
|
||
|
||
#ifndef FORCE_NO_NTWRITEANDX
|
||
#define MRxSmbForceNoNtWriteAndX FALSE
|
||
#else
|
||
BOOLEAN MRxSmbForceNoNtWriteAndX = TRUE;
|
||
#endif
|
||
|
||
#define WRITE_COPY_THRESHOLD 64
|
||
#define FORCECOPYMODE FALSE
|
||
|
||
#ifdef SETFORCECOPYMODE
|
||
#undef FORCECOPYMODE
|
||
#define FORCECOPYMODE MRxSmbForceCopyMode
|
||
ULONG MRxSmbForceCopyMode = TRUE;
|
||
#endif
|
||
|
||
NTSTATUS
|
||
SmbPseExchangeStart_Write(
|
||
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
||
);
|
||
|
||
ULONG MRxSmbWriteSendOptions = 0;
|
||
|
||
NTSTATUS
|
||
MRxSmbWrite (
|
||
IN 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 = STATUS_SUCCESS;
|
||
|
||
RxCaptureFcb;
|
||
RxCaptureFobx;
|
||
|
||
PMRX_SRV_OPEN SrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen;
|
||
|
||
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
|
||
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbWrite\n", 0 ));
|
||
|
||
if (RxContext->pFcb->pNetRoot->Type == NET_ROOT_PIPE) {
|
||
Status = STATUS_NOT_SUPPORTED;
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbWrite: Pipe write returned %lx\n",Status));
|
||
return Status;
|
||
}
|
||
|
||
if ( NodeType(capFcb) == RDBSS_NTC_MAILSLOT ) {
|
||
|
||
Status = STATUS_NOT_SUPPORTED;
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbWrite: Mailslot write returned %lx\n",Status));
|
||
return Status;
|
||
}
|
||
|
||
if(NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE) {
|
||
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
||
smbFcb->MFlags |= SMB_FCB_FLAG_WRITES_PERFORMED;
|
||
}
|
||
|
||
ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
|
||
|
||
SrvOpen = capFobx->pSrvOpen;
|
||
smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
|
||
if (smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_II &&
|
||
!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
|
||
LOWIO_READWRITEFLAG_PAGING_IO)) {
|
||
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
|
||
PMRX_SRV_CALL pSrvCall;
|
||
|
||
pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
|
||
pSrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
|
||
|
||
RxIndicateChangeOfBufferingStateForSrvOpen(
|
||
pSrvCall,
|
||
SrvOpen,
|
||
MRxSmbMakeSrvOpenKey(pVNetRootContext->TreeId,smbSrvOpen->Fid),
|
||
ULongToPtr(SMB_OPLOCK_LEVEL_NONE));
|
||
SmbCeLog(("Breaking oplock to None in Write SO %lx\n",SrvOpen));
|
||
}
|
||
|
||
do {
|
||
Status = __SmbPseCreateOrdinaryExchange(
|
||
RxContext,
|
||
capFobx->pSrvOpen->pVNetRoot,
|
||
SMBPSE_OE_FROM_WRITE,
|
||
SmbPseExchangeStart_Write,
|
||
&OrdinaryExchange);
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
|
||
|
||
return Status;
|
||
}
|
||
|
||
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
|
||
|
||
if ( Status != STATUS_PENDING ) {
|
||
BOOLEAN FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
|
||
ASSERT( FinalizationComplete );
|
||
} else {
|
||
ASSERT(BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
|
||
}
|
||
|
||
if ((Status == STATUS_RETRY) &&
|
||
BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
|
||
MRxSmbResumeAsyncReadWriteRequests(RxContext);
|
||
Status = STATUS_PENDING;
|
||
}
|
||
} while (Status == STATUS_RETRY);
|
||
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbWrite exit with status=%08lx\n", Status ));
|
||
|
||
return(Status);
|
||
} // MRxSmbWrite
|
||
|
||
|
||
NTSTATUS
|
||
MRxSmbBuildWriteRequest(
|
||
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
||
BOOLEAN IsPagingIo,
|
||
UCHAR WriteCommand,
|
||
ULONG ByteCount,
|
||
PLARGE_INTEGER ByteOffsetAsLI,
|
||
PBYTE Buffer,
|
||
PMDL BufferAsMdl)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the start routine for write.
|
||
|
||
Arguments:
|
||
|
||
pExchange - the exchange instance
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
||
PRX_CONTEXT RxContext = StufferState->RxContext;
|
||
|
||
RxCaptureFcb;
|
||
RxCaptureFobx;
|
||
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
|
||
PNT_SMB_HEADER NtSmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
|
||
|
||
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
|
||
ULONG OffsetLow,OffsetHigh;
|
||
|
||
PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
|
||
|
||
USHORT WriteMode = 0;
|
||
ULONG DataLengthLow,DataLengthHigh;
|
||
ULONG BytesRemaining = 0;
|
||
BOOLEAN AddLengthBytes = FALSE;
|
||
ULONG WriteCommandSize;
|
||
|
||
PSMBCE_SERVER pServer = SmbCeGetExchangeServer((PSMB_EXCHANGE)OrdinaryExchange);
|
||
BOOLEAN UseNtVersion;
|
||
|
||
UseNtVersion = BooleanFlagOn(pServer->DialectFlags,DF_NT_SMBS) &&
|
||
!MRxSmbForceNoNtWriteAndX;
|
||
|
||
// The data length field in SMB is a USHORT, and hence the data length given
|
||
// needs to be split up into two parts -- DataLengthHigh and DataLengthLow
|
||
DataLengthLow = (ByteCount & 0xffff);
|
||
DataLengthHigh = ((ByteCount & 0xffff0000) >> 16);
|
||
|
||
OffsetLow = ByteOffsetAsLI->LowPart;
|
||
OffsetHigh = ByteOffsetAsLI->HighPart;
|
||
|
||
switch (WriteCommand) {
|
||
case SMB_COM_WRITE_ANDX:
|
||
WriteCommandSize = SMB_REQUEST_SIZE(NT_WRITE_ANDX);
|
||
break;
|
||
case SMB_COM_WRITE:
|
||
WriteCommandSize = SMB_REQUEST_SIZE(WRITE);
|
||
break;
|
||
case SMB_COM_WRITE_PRINT_FILE:
|
||
WriteCommandSize = SMB_REQUEST_SIZE(WRITE_PRINT_FILE);
|
||
break;
|
||
}
|
||
|
||
Status = MRxSmbStartSMBCommand(
|
||
StufferState,
|
||
SetInitialSMB_Never,
|
||
WriteCommand,
|
||
WriteCommandSize,
|
||
NO_EXTRA_DATA,
|
||
NO_SPECIAL_ALIGNMENT,
|
||
RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
|
||
0,0,0,0 STUFFERTRACE(Dbg,'FC'));
|
||
|
||
MRxSmbDumpStufferState(
|
||
1000,
|
||
"SMB Write Request before stuffing",
|
||
StufferState);
|
||
|
||
switch (WriteCommand) {
|
||
case SMB_COM_WRITE_ANDX :
|
||
{
|
||
if ( UseNtVersion && IsPagingIo ) {
|
||
SmbPutAlignedUshort(
|
||
&NtSmbHeader->Flags2,
|
||
SmbGetAlignedUshort(&NtSmbHeader->Flags2)|SMB_FLAGS2_PAGING_IO );
|
||
}
|
||
|
||
//
|
||
// If the file object was opened in write through mode, set write
|
||
// through on the write operation.
|
||
if (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WRITE_THROUGH)) {
|
||
WriteMode |= SMB_WMODE_WRITE_THROUGH;
|
||
}
|
||
|
||
MRxSmbStuffSMB (
|
||
StufferState,
|
||
"XwddwwwwQ",
|
||
// X UCHAR WordCount;
|
||
// UCHAR AndXCommand;
|
||
// UCHAR AndXReserved;
|
||
// _USHORT( AndXOffset );
|
||
smbSrvOpen->Fid, // w _USHORT( Fid );
|
||
OffsetLow, // d _ULONG( Offset );
|
||
-1, // d _ULONG( Timeout );
|
||
WriteMode, // w _USHORT( WriteMode );
|
||
BytesRemaining, // w _USHORT( Remaining );
|
||
DataLengthHigh, // w _USHORT( DataLengthHigh );
|
||
DataLengthLow, // w _USHORT( DataLength );
|
||
// Q _USHORT( DataOffset );
|
||
SMB_OFFSET_CHECK(WRITE_ANDX,DataOffset)
|
||
StufferCondition(UseNtVersion), "D",
|
||
SMB_OFFSET_CHECK(NT_WRITE_ANDX,OffsetHigh)
|
||
OffsetHigh, // D NTonly _ULONG( OffsetHigh );
|
||
//
|
||
STUFFER_CTL_NORMAL, "BS5",
|
||
// B _USHORT( ByteCount );
|
||
SMB_WCT_CHECK(((UseNtVersion)?14:12))
|
||
// UCHAR Buffer[1];
|
||
// S //UCHAR Pad[];
|
||
// 5 //UCHAR Data[];
|
||
StufferCondition(AddLengthBytes), "w", LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
||
StufferCondition(Buffer!=NULL), "c!",
|
||
ByteCount,
|
||
Buffer, // c the actual data
|
||
0
|
||
);
|
||
}
|
||
break;
|
||
|
||
case SMB_COM_WRITE :
|
||
{
|
||
MRxSmbStuffSMB (
|
||
StufferState,
|
||
"0wwdwByw",
|
||
// 0 UCHAR WordCount; // Count of parameter words = 5
|
||
smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
|
||
DataLengthLow, // w _USHORT( Count ); // Number of bytes to be written
|
||
OffsetLow, // d _ULONG( Offset ); // Offset in file to begin write
|
||
BytesRemaining, // w _USHORT( Remaining ); // Bytes remaining to satisfy request
|
||
SMB_WCT_CHECK(5) // B _USHORT( ByteCount ); // Count of data bytes
|
||
// //UCHAR Buffer[1]; // Buffer containing:
|
||
0x01, // y UCHAR BufferFormat; // 0x01 -- Data block
|
||
DataLengthLow, // w _USHORT( DataLength ); // Length of data
|
||
// ULONG Buffer[1]; // Data
|
||
StufferCondition(Buffer!=NULL), "c!",
|
||
ByteCount,
|
||
Buffer, // c the actual data
|
||
0
|
||
);
|
||
}
|
||
break;
|
||
|
||
case SMB_COM_WRITE_PRINT_FILE:
|
||
{
|
||
MRxSmbStuffSMB (
|
||
StufferState,
|
||
"0wByw",
|
||
// 0 UCHAR WordCount; // Count of parameter words = 1
|
||
smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
|
||
SMB_WCT_CHECK(1) // B _USHORT( ByteCount ); // Count of data bytes; min = 4
|
||
// UCHAR Buffer[1]; // Buffer containing:
|
||
0x01, // y //UCHAR BufferFormat; // 0x01 -- Data block
|
||
DataLengthLow, // w //USHORT DataLength; // Length of data
|
||
// //UCHAR Data[]; // Data
|
||
StufferCondition(Buffer!=NULL), "c!",
|
||
ByteCount,
|
||
Buffer, // c the actual data
|
||
0
|
||
);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_UNSUCCESSFUL ;
|
||
break;
|
||
}
|
||
|
||
if ( BufferAsMdl ) {
|
||
MRxSmbStuffAppendRawData( StufferState, BufferAsMdl );
|
||
MRxSmbStuffSetByteCount( StufferState );
|
||
}
|
||
|
||
MRxSmbDumpStufferState(
|
||
700,
|
||
"SMB Write Request after stuffing",
|
||
StufferState);
|
||
|
||
if (Status==STATUS_SUCCESS) {
|
||
InterlockedIncrement(&MRxSmbStatistics.SmallWriteSmbs);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
BOOLEAN DisableLargeWrites = 0;
|
||
|
||
NTSTATUS
|
||
SmbPseExchangeStart_Write (
|
||
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the start routine for write.
|
||
|
||
Arguments:
|
||
|
||
pExchange - the exchange instance
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
ULONG StartEntryCount;
|
||
|
||
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
||
PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
|
||
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
|
||
|
||
RxCaptureFcb;
|
||
RxCaptureFobx;
|
||
|
||
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
PMRX_SMB_FCB SmbFcb = MRxSmbGetFcbExtension(capFcb);
|
||
|
||
BOOLEAN SynchronousIo, IsPagingIo;
|
||
BOOLEAN WriteToTheEnd = FALSE;
|
||
UCHAR WriteCommand;
|
||
|
||
PAGED_CODE();
|
||
RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Write\n"));
|
||
|
||
ASSERT( OrdinaryExchange->Type == ORDINARY_EXCHANGE );
|
||
|
||
ASSERT(
|
||
(
|
||
(OriginalDataMdl!=NULL) &&
|
||
(
|
||
RxMdlIsLocked(OriginalDataMdl) ||
|
||
RxMdlSourceIsNonPaged(OriginalDataMdl)
|
||
)
|
||
) ||
|
||
(
|
||
(OriginalDataMdl==NULL) &&
|
||
(LowIoContext->ParamsFor.ReadWrite.ByteCount==0)
|
||
)
|
||
);
|
||
|
||
ASSERT((OrdinaryExchange->SmbCeFlags&SMBCE_EXCHANGE_ATTEMPT_RECONNECTS) == 0 );
|
||
|
||
OrdinaryExchange->StartEntryCount++;
|
||
StartEntryCount = OrdinaryExchange->StartEntryCount;
|
||
|
||
SynchronousIo = !BooleanFlagOn(
|
||
RxContext->Flags,
|
||
RX_CONTEXT_FLAG_ASYNC_OPERATION);
|
||
|
||
IsPagingIo = BooleanFlagOn(
|
||
LowIoContext->ParamsFor.ReadWrite.Flags,
|
||
LOWIO_READWRITEFLAG_PAGING_IO);
|
||
|
||
// Ensure that the Fid is validated
|
||
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID);
|
||
|
||
for (;;) {
|
||
PSMBCE_SERVER pServer;
|
||
PSMBCE_NET_ROOT pNetRoot;
|
||
|
||
pServer = SmbCeGetExchangeServer(OrdinaryExchange);
|
||
pNetRoot = SmbCeGetExchangeNetRoot(OrdinaryExchange);
|
||
|
||
switch (OrdinaryExchange->OpSpecificState) {
|
||
case SmbPseOEInnerIoStates_Initial:
|
||
{
|
||
OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
|
||
|
||
if ( !SynchronousIo ) {
|
||
OrdinaryExchange->AsyncResumptionRoutine = SmbPseExchangeStart_Write;
|
||
}
|
||
|
||
MRxSmbSetInitialSMB( StufferState STUFFERTRACE(Dbg,'FC') );
|
||
|
||
rw->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
|
||
rw->ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
||
rw->RemainingByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
|
||
|
||
if (rw->ByteOffsetAsLI.QuadPart == -1 ) {
|
||
WriteToTheEnd = TRUE;
|
||
rw->ByteOffsetAsLI.QuadPart = smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart;
|
||
}
|
||
|
||
if (OriginalDataMdl != NULL) {
|
||
rw->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
|
||
} else {
|
||
rw->UserBufferBase = (PBYTE)1; //any nonzero value will do
|
||
}
|
||
|
||
rw->ThisBufferOffset = 0;
|
||
|
||
rw->PartialExchangeMdlInUse = FALSE;
|
||
rw->PartialDataMdlInUse = FALSE;
|
||
}
|
||
//lack of break is intentional
|
||
|
||
case SmbPseOEInnerIoStates_ReadyToSend:
|
||
{
|
||
ULONG MaximumBufferSizeThisIteration;
|
||
PCHAR Buffer = NULL;
|
||
PMDL BufferAsMdl = NULL;
|
||
|
||
OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_OperationOutstanding;
|
||
OrdinaryExchange->SendOptions = MRxSmbWriteSendOptions;
|
||
|
||
if (FlagOn(pServer->DialectFlags,DF_LANMAN10) &&
|
||
FlagOn(pServer->DialectFlags,DF_LARGE_FILES) &&
|
||
(StufferState->RxContext->pFcb->pNetRoot->Type != NET_ROOT_PRINT)) {
|
||
WriteCommand = SMB_COM_WRITE_ANDX;
|
||
} else if (StufferState->RxContext->pFcb->pNetRoot->Type == NET_ROOT_PRINT){
|
||
WriteCommand = SMB_COM_WRITE_PRINT_FILE;
|
||
} else {
|
||
WriteCommand = SMB_COM_WRITE;
|
||
}
|
||
|
||
MaximumBufferSizeThisIteration = pNetRoot->MaximumWriteBufferSize;
|
||
|
||
// There are four parameters pertaining to a write request
|
||
//
|
||
// 1. Write Length -- rw->ThisByteCount
|
||
// 2. Write Offset -- rw->ByteOffsetAsLI
|
||
// 3. Write Buffer -- Buffer
|
||
// 4. Write Buffer as a MDL -- BufferAsMdl
|
||
//
|
||
// All writes can be classified into one of the following
|
||
// categories ...
|
||
//
|
||
// 1. Extremely Small writes
|
||
// These are writes lesser than the COPY_THRESHOLD or
|
||
// we are in a debug mode that forces us to do only small
|
||
// writes.
|
||
//
|
||
// 2. Write requests against downlevel servers or non disk
|
||
// file write requests against up level servers.
|
||
// In all these cases we are constrained by the Server
|
||
// which limits the number of bytes to roughly 4k. This
|
||
// is based upon the Smb Buffer size returned during
|
||
// negotiation.
|
||
//
|
||
// 3. Write requests against uplevel (NT5+)
|
||
// servers
|
||
// These write requests can be arbitrarily large
|
||
//
|
||
|
||
|
||
if ((rw->RemainingByteCount < WRITE_COPY_THRESHOLD) ||
|
||
FORCECOPYMODE) {
|
||
if (FORCECOPYMODE &&
|
||
(rw->ThisByteCount > MaximumBufferSizeThisIteration) ) {
|
||
rw->ThisByteCount = MaximumBufferSizeThisIteration;
|
||
} else {
|
||
rw->ThisByteCount = rw->RemainingByteCount;
|
||
}
|
||
|
||
Buffer = rw->UserBufferBase + rw->ThisBufferOffset;
|
||
|
||
ASSERT( WRITE_COPY_THRESHOLD <= pNetRoot->MaximumWriteBufferSize );
|
||
} else {
|
||
rw->ThisByteCount = min(
|
||
rw->RemainingByteCount,
|
||
MaximumBufferSizeThisIteration);
|
||
|
||
if ((rw->ThisBufferOffset != 0) ||
|
||
(rw->ThisByteCount != OriginalDataMdl->ByteCount)) {
|
||
MmInitializeMdl(
|
||
&rw->PartialDataMdl,
|
||
0,
|
||
MAX_PARTIAL_DATA_MDL_BUFFER_SIZE);
|
||
|
||
IoBuildPartialMdl(
|
||
OriginalDataMdl,
|
||
&rw->PartialDataMdl,
|
||
(PCHAR)MmGetMdlVirtualAddress(OriginalDataMdl) +
|
||
rw->ThisBufferOffset,
|
||
rw->ThisByteCount );
|
||
|
||
BufferAsMdl = &rw->PartialDataMdl;
|
||
} else {
|
||
BufferAsMdl = OriginalDataMdl;
|
||
}
|
||
}
|
||
|
||
Status = MRxSmbBuildWriteRequest(
|
||
OrdinaryExchange,
|
||
IsPagingIo,
|
||
WriteCommand,
|
||
rw->ThisByteCount,
|
||
&rw->ByteOffsetAsLI,
|
||
Buffer,
|
||
BufferAsMdl);
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
RxDbgTrace(0, Dbg, ("bad write stuffer status........\n"));
|
||
goto FINALLY;
|
||
}
|
||
|
||
InterlockedIncrement(&MRxSmbStatistics.WriteSmbs);
|
||
|
||
Status = SmbPseOrdinaryExchange(
|
||
SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
|
||
SMBPSE_OETYPE_WRITE );
|
||
|
||
if ( Status == STATUS_PENDING) {
|
||
ASSERT( !SynchronousIo );
|
||
goto FINALLY;
|
||
}
|
||
}
|
||
//lack of break is intentional
|
||
|
||
case SmbPseOEInnerIoStates_OperationOutstanding:
|
||
case SmbPseOEInnerIoStates_OperationCompleted:
|
||
{
|
||
SetFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_SUBSEQUENT_OPERATION);
|
||
|
||
OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
|
||
|
||
if (rw->PartialExchangeMdlInUse) {
|
||
MmPrepareMdlForReuse(
|
||
&rw->PartialExchangeMdl);
|
||
rw->PartialDataMdlInUse = FALSE;
|
||
}
|
||
|
||
if (rw->PartialDataMdlInUse) {
|
||
MmPrepareMdlForReuse(
|
||
&rw->PartialDataMdl);
|
||
rw->PartialDataMdlInUse = FALSE;
|
||
}
|
||
|
||
Status = OrdinaryExchange->Status;
|
||
|
||
if (Status == STATUS_SMB_USE_STANDARD) {
|
||
// Send the remaining data using Restart all over again and
|
||
rw->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
|
||
rw->ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
||
rw->RemainingByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
|
||
|
||
if (rw->ByteOffsetAsLI.QuadPart == -1 ) {
|
||
WriteToTheEnd = TRUE;
|
||
rw->ByteOffsetAsLI.QuadPart = smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart;
|
||
}
|
||
|
||
rw->BytesReturned = 0;
|
||
rw->ThisByteCount = 0;
|
||
rw->ThisBufferOffset = 0;
|
||
|
||
RxContext->InformationToReturn = 0;
|
||
|
||
OrdinaryExchange->Status = STATUS_SUCCESS;
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
rw->RemainingByteCount -= rw->BytesReturned;
|
||
RxContext->InformationToReturn += rw->BytesReturned;
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
rw->ByteOffsetAsLI.QuadPart += rw->BytesReturned;
|
||
rw->ThisBufferOffset += rw->BytesReturned;
|
||
|
||
if (WriteToTheEnd) {
|
||
smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart += rw->BytesReturned;
|
||
}
|
||
}
|
||
|
||
if ((Status != STATUS_SUCCESS) ||
|
||
(rw->RemainingByteCount == 0)) {
|
||
PSMBCE_SESSION pSession = SmbCeGetExchangeSession(OrdinaryExchange);
|
||
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
(
|
||
"OE %lx TBC %lx RBC %lx BR %lx TBO %lx\n",
|
||
OrdinaryExchange,rw->ThisByteCount,
|
||
rw->RemainingByteCount,
|
||
rw->BytesReturned,
|
||
rw->ThisBufferOffset )
|
||
);
|
||
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
("Bytes written %lx\n",
|
||
RxContext->InformationToReturn)
|
||
);
|
||
|
||
goto FINALLY;
|
||
}
|
||
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
( "Next Iteration OE %lx RBC %lx TBO %lx\n",
|
||
OrdinaryExchange,
|
||
rw->RemainingByteCount,
|
||
rw->ThisBufferOffset)
|
||
);
|
||
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
("OE %lx TBC %lx, BR %lx\n",
|
||
OrdinaryExchange,
|
||
rw->ThisByteCount,
|
||
rw->BytesReturned));
|
||
|
||
MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
FINALLY:
|
||
if ( Status != STATUS_PENDING) {
|
||
if (Status != STATUS_RETRY) {
|
||
SmbPseAsyncCompletionIfNecessary(OrdinaryExchange,RxContext);
|
||
}
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Write exit w %08lx\n", Status ));
|
||
return Status;
|
||
|
||
} // SmbPseExchangeStart_Write
|
||
|
||
|
||
NTSTATUS
|
||
MRxSmbFinishWrite (
|
||
IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
||
IN PBYTE ResponseBuffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine actually gets the stuff out of the write response and finishes
|
||
the write. Everything you need is locked down... so we can finish in the
|
||
indication routine
|
||
|
||
Arguments:
|
||
|
||
OrdinaryExchange - the exchange instance
|
||
|
||
ResponseBuffer - the response
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG BytesReturned;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbFinishWrite\n"));
|
||
SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishWrite:");
|
||
|
||
switch (OrdinaryExchange->LastSmbCommand) {
|
||
case SMB_COM_WRITE_ANDX:
|
||
{
|
||
PSMBCE_SERVER pServer;
|
||
PSMBCE_NET_ROOT pNetRoot;
|
||
PRESP_WRITE_ANDX Response = (PRESP_WRITE_ANDX)ResponseBuffer;
|
||
|
||
if (Response->WordCount != 6 ||
|
||
SmbGetUshort(&Response->ByteCount) != 0) {
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
}
|
||
|
||
pServer = SmbCeGetExchangeServer((PSMB_EXCHANGE)OrdinaryExchange);
|
||
pNetRoot = SmbCeGetExchangeNetRoot((PSMB_EXCHANGE)OrdinaryExchange);
|
||
|
||
BytesReturned = SmbGetUshort( &Response->Count );
|
||
|
||
if (FlagOn(pServer->DialectFlags,DF_LARGE_WRITEX)) {
|
||
ULONG BytesReturnedHigh;
|
||
|
||
BytesReturnedHigh = SmbGetUshort(&Response->CountHigh);
|
||
|
||
BytesReturned = (BytesReturnedHigh << 16) | BytesReturned;
|
||
}
|
||
|
||
if ((OrdinaryExchange->Status == STATUS_SUCCESS) &&
|
||
(OrdinaryExchange->ReadWrite.ThisByteCount > 2) &&
|
||
(BytesReturned == 0)) {
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
}
|
||
|
||
//if we added 2 headerbytes then let's get rid of them......
|
||
if ( FlagOn(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_REDUCE_RETURNCOUNT) ) {
|
||
// BytesReturned -= sizeof(USHORT);
|
||
ClearFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_REDUCE_RETURNCOUNT);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case SMB_COM_WRITE :
|
||
{
|
||
PRESP_WRITE Response = (PRESP_WRITE)ResponseBuffer;
|
||
|
||
if (Response->WordCount != 1 ||
|
||
SmbGetUshort(&Response->ByteCount) != 0) {
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
}
|
||
|
||
BytesReturned = SmbGetUshort( &Response->Count );
|
||
}
|
||
break;
|
||
|
||
case SMB_COM_WRITE_PRINT_FILE:
|
||
{
|
||
PRESP_WRITE_PRINT_FILE Response = (PRESP_WRITE_PRINT_FILE)ResponseBuffer;
|
||
|
||
if (Response->WordCount != 0) {
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
}
|
||
|
||
//the response does not tell how many bytes were taken! get the byte count from the exchange
|
||
BytesReturned = OrdinaryExchange->ReadWrite.ThisByteCount;
|
||
}
|
||
break;
|
||
|
||
default :
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
break;
|
||
}
|
||
|
||
RxDbgTrace(0, Dbg, ("-->BytesReturned=%08lx\n", BytesReturned));
|
||
|
||
OrdinaryExchange->ReadWrite.BytesReturned = BytesReturned;
|
||
|
||
if (Status == STATUS_SUCCESS &&
|
||
OrdinaryExchange->ReadWrite.ThisByteCount > 2 &&
|
||
BytesReturned > OrdinaryExchange->ReadWrite.ThisByteCount) {
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbFinishWrite returning %08lx\n", Status ));
|
||
|
||
return Status;
|
||
} // MRxSmbFinishWrite
|
||
|
||
|
||
|
||
|