write.c
来自「winddk src目录下的文件系统驱动源码压缩!」· C语言 代码 · 共 846 行 · 第 1/2 页
C
846 行
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 = 0;
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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?