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.
845 lines
29 KiB
845 lines
29 KiB
/*++
|
|
|
|
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
|
|
|
|
|
|
|
|
|