Leaked source code of windows server 2003
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

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