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 + -
显示快捷键?