|
|
/*++
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
|