2025-04-27 07:49:33 -04:00

542 lines
16 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989 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
#define MIN_CHUNK_SIZE 0x1000
#define MAX(a,b) ((a) > (b) ? (a) : (b))
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_WRITE)
//#define FORCE_NO_NTWRITEANDX
#ifndef FORCE_NO_NTWRITEANDX
#define MRxSmbForceNoNtWriteAndX FALSE
#else
BOOLEAN MRxSmbForceNoNtWriteAndX = TRUE;
#endif
#define WRITE_COPY_THRESHOLD 64
#define FORCECOPYMODE FALSE
//#define SETFORCECOPYMODE
#ifdef SETFORCECOPYMODE
#undef FORCECOPYMODE
#define FORCECOPYMODE MRxSmbForceCopyMode
ULONG MRxSmbForceCopyMode = TRUE;
#endif //SETFORCECOPYMODE
NTSTATUS
SmbPseExchangeStart_Write(
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
);
ULONG MRxSmbSrvWriteBufSize = 0xffff; //use the negotiated size
ULONG MRxSmbWriteSendOptions = 0;
//
// External declarations
//
NTSTATUS
MRxIfsWrite (
IN PRX_CONTEXT RxContext)
/*++
Routine Description:
This routine opens a file across the network.
Arguments:
RxContext - the RDBSS context
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
RxCaptureFcb; RxCaptureFobx;
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbWrite\n", 0 ));
OrdinaryExchange = SmbPseCreateOrdinaryExchange(RxContext,
capFobx->pSrvOpen->pVNetRoot,
SMBPSE_OE_FROM_WRITE,
SmbPseExchangeStart_Write
);
if (OrdinaryExchange==NULL) {
RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
return(STATUS_INSUFFICIENT_RESOURCES);
}
Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
if ( Status != STATUS_PENDING ) {
BOOLEAN FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
ASSERT( FinalizationComplete );
} else {
ASSERT(BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
}
RxDbgTrace(-1, Dbg, ("MRxSmbWrite exit with status=%08lx\n", Status ));
return(Status);
} // MRxSmbWrite
NTSTATUS
MRxSmbBuildCoreWrite (
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState,
IN PLARGE_INTEGER ByteOffsetAsLI,
IN PBYTE Buffer,
IN ULONG ByteCount,
IN PMDL BufferAsMdl
)
/*++
Routine Description:
This routine builds a core write 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.
The buffer is passed into this routine in one of two ways:
1. As an MDL
2. As buffer/bytecount.
This routine acts accordingly.
Arguments:
StufferState - the state of the smbbuffer from the stuffer's point of view
ByteOffsetAsLI - the byte offset in the file where we want to read
Buffer - the buffer where the data resides OR NULL!
ByteCount - the length of the Buffer described by Buffer
BufferAsMdl - an MDL describing the data OR NULL!
Return Value:
RXSTATUS
SUCCESS
NOT_IMPLEMENTED something in the arguments can't be handled
Notes:
--*/
{
NTSTATUS Status;
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 = MRxIfsGetSrvOpenExtension(SrvOpen);
ULONG OffsetLow,OffsetHigh;
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange =
(PSMB_PSE_ORDINARY_EXCHANGE)(StufferState->Exchange);
PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
ULONG DataLength = ByteCount;
ULONG BytesRemaining = 0;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbBuildCoreWrite\n", 0 ));
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
ASSERT( !(Buffer&&BufferAsMdl) );
ASSERT( (Buffer || BufferAsMdl) );
OffsetLow = ByteOffsetAsLI->LowPart;
OffsetHigh = ByteOffsetAsLI->HighPart;
ASSERT(OffsetHigh==0);
COVERED_CALL(MRxSmbStartSMBCommand( StufferState, SetInitialSMB_Never,
SMB_COM_WRITE,
SMB_REQUEST_SIZE(WRITE),
NO_EXTRA_DATA,
NO_SPECIAL_ALIGNMENT,
RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
);
MRxSmbStuffSMB (StufferState,
"0wwdwByw",
// 0 UCHAR WordCount; // Count of parameter words = 5
smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
DataLength, // 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
DataLength, // w _USHORT( DataLength ); // Length of data
// ULONG Buffer[1]; // Data
StufferCondition(Buffer!=NULL), "c!",
ByteCount,Buffer, // c the actual data
0
);
if ( BufferAsMdl ) {
MRxSmbStuffAppendRawData( StufferState, BufferAsMdl );
MRxSmbStuffSetByteCount( StufferState );
}
IF_DEBUG{
PREQ_WRITE req = (PREQ_WRITE)(NtSmbHeader+1);
ULONG ByteCount = SmbGetUshort( &req->ByteCount );
RxDbgTrace(0, Dbg, ("BuildCoreWrite bc=%08lx\n", ByteCount ));
ASSERT(ByteCount!=0);
}
FINALLY:
RxDbgTraceUnIndent(-1, Dbg);
return(Status);
} // MRxSmbBuildCoreWrite
NTSTATUS
SmbPseExchangeStart_Write (
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
)
/*++
Routine Description:
This is the start routine for write.
Arguments:
pExchange - the exchange instance
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;// no longer instead async gets status from exchange->smbstatus
// = RxStatus(SUCCESS); // this must be success if we are
// reentered as on on an async write
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
ULONG StartEntryCount;
PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
PMDL DataPartialMdl = OrdinaryExchange->DataPartialMdl;
PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
RxCaptureFcb; RxCaptureFobx;
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
BOOLEAN SynchronousIo =
!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
BOOLEAN VestigialSmbBuf = BooleanFlagOn( OrdinaryExchange->Flags, SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_SMBBUF );
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Write\n"));
ASSERT( OrdinaryExchange->Type == ORDINARY_EXCHANGE );
ASSERT( ((OriginalDataMdl!=NULL) && RxMdlIsLocked(OriginalDataMdl))
|| ((OriginalDataMdl==NULL) && (LowIoContext->ParamsFor.ReadWrite.ByteCount==0)) );
ASSERT( (OrdinaryExchange->SmbCeFlags&SMBCE_EXCHANGE_ATTEMPT_RECONNECTS) == 0 );
OrdinaryExchange->StartEntryCount++;
StartEntryCount = OrdinaryExchange->StartEntryCount;
// Ensure that the Fid is validated
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID);
for (;;) {
PSMBCE_SERVER pServer = &OrdinaryExchange->SmbCeContext.pServerEntry->Server;
ULONG MaximumBufferSizeThisIteration;
switch ( OrdinaryExchange->OpSpecificState ) {
case SmbPseOEInnerIoStates_Initial:
OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
if ( !SynchronousIo ) {
OrdinaryExchange->Continuation = SmbPseExchangeStart_Write;
}
MRxSmbSetInitialSMB( StufferState STUFFERTRACE(Dbg,'FC') );
rw->MaximumSmbBufferSize =
min(MRxSmbSrvWriteBufSize,
pServer->MaximumBufferSize -
QuadAlign(sizeof(SMB_HEADER) +
FIELD_OFFSET(REQ_NT_WRITE_ANDX,Buffer[0])));
if (VestigialSmbBuf) {
rw->MaximumSmbBufferSize = min(rw->MaximumSmbBufferSize,PAGE_SIZE);
}
rw->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
rw->ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
rw->RemainingByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
if (OriginalDataMdl!=NULL) {
rw->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
} else {
rw->UserBufferBase = (PBYTE)1; //any nonzero value will do
}
//record if this is a msgmode/pipe operation......
if ( (capFcb->pNetRoot->Type == NET_ROOT_PIPE)
&& (capFobx->PipeHandleInformation->ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ) {
SetFlag(OrdinaryExchange->OpSpecificFlags,OE_READ_FLAG_MSGMODE_PIPE_OPERATION);
}
rw->ThisBufferOffset = 0;
rw->PartialBytes = 0;
//lack of break is intentional
case SmbPseOEInnerIoStates_ReadyToSend:
OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_OperationOutstanding;
OrdinaryExchange->SendOptions = MRxSmbWriteSendOptions;
MaximumBufferSizeThisIteration =
rw->MaximumSmbBufferSize -
( (FlagOn(OrdinaryExchange->OpSpecificFlags,OE_READ_FLAG_MSGMODE_PIPE_OPERATION)
&& !FlagOn(OrdinaryExchange->OpSpecificFlags,OE_READ_FLAG_SUBSEQUENT_OPERATION))
?2:0 );
//
// If the write is small enough, we can just copy it into the
// write request smb.
//
ASSERT( WRITE_COPY_THRESHOLD <= rw->MaximumSmbBufferSize );
// In 3 out of 4 cases, the following assignment is correct...
rw->ThisByteCount = rw->RemainingByteCount;
{
PCHAR Buffer;
if (rw->ThisByteCount > rw->MaximumSmbBufferSize )
{
rw->ThisByteCount = MaximumBufferSizeThisIteration;
}
Buffer = rw->UserBufferBase + rw->ThisBufferOffset;
Status = MRxSmbBuildCoreWrite( StufferState,
&rw->ByteOffsetAsLI,
Buffer,
rw->ThisByteCount,
NULL );
}
if (Status != STATUS_SUCCESS) {
RxDbgTrace(0, Dbg, ("bad write stuffer status........\n"));
goto FINALLY;
}
InterlockedIncrement(&MRxIfsStatistics.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:
SetFlag(OrdinaryExchange->OpSpecificFlags,OE_READ_FLAG_SUBSEQUENT_OPERATION);
OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
rw->RemainingByteCount -= rw->BytesReturned;
RxContext->InformationToReturn += rw->BytesReturned;
Status = OrdinaryExchange->SmbStatus;
if ( (Status != STATUS_SUCCESS)
|| (rw->BytesReturned < rw->ThisByteCount)
|| (rw->RemainingByteCount == 0) ) {
goto FINALLY;
}
rw->ByteOffsetAsLI.QuadPart += rw->BytesReturned;
rw->ThisBufferOffset += rw->BytesReturned;
MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
break;
}
}
FINALLY:
if ( Status != STATUS_PENDING ) {
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 PRESP_WRITE_ANDX Response
)
/*++
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
Response - 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:");
ASSERT( (Response->WordCount==6) );
ASSERT( (SmbGetUshort(&Response->ByteCount)==0) );
BytesReturned = SmbGetUshort( &Response->Count );
//if we added 2 headerbytes then let's get rid of them......
if ( FlagOn(OrdinaryExchange->OpSpecificFlags,OE_READ_FLAG_REDUCE_RETURNCOUNT) ) {
BytesReturned -= sizeof(USHORT);
ClearFlag(OrdinaryExchange->OpSpecificFlags,OE_READ_FLAG_REDUCE_RETURNCOUNT);
}
RxDbgTrace(0, Dbg, ("-->BytesReturned=%08lx\n", BytesReturned));
OrdinaryExchange->ReadWrite.BytesReturned = BytesReturned;
RxDbgTrace(-1, Dbg, ("MRxSmbFinishWrite returning %08lx\n", Status ));
return Status;
} // MRxSmbFinishWrite
NTSTATUS
MRxSmbFinishCoreWrite (
IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
IN PRESP_WRITE Response
)
/*++
Routine Description:
This routine actually gets the stuff out of the write response and finishes
the core write. Everything you need is locked down... so we can finish in the
indication routine
Arguments:
OrdinaryExchange - the exchange instance
Response - the response
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG BytesReturned;
//PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxSmbFinishCoreWrite\n"));
SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishCoreWrite:");
ASSERT( (Response->WordCount==1) );
ASSERT( (SmbGetUshort(&Response->ByteCount)==0) );
BytesReturned = SmbGetUshort( &Response->Count );
RxDbgTrace(0, Dbg, ("-->BytesReturned=%08lx\n", BytesReturned));
OrdinaryExchange->ReadWrite.BytesReturned = BytesReturned;
RxDbgTrace(-1, Dbg, ("MRxSmbFinishCoreWrite returning %08lx\n", Status ));
return Status;
} // MRxSmbFinishCoreWrite