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.
1248 lines
41 KiB
1248 lines
41 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ReadRite.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the routines for reading/writeng shadows at
|
|
the right time.
|
|
|
|
Author:
|
|
|
|
Joe Linn [JoeLinn] 5-may-1997
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#pragma code_seg("PAGE")
|
|
|
|
extern DEBUG_TRACE_CONTROLPOINT RX_DEBUG_TRACE_MRXSMBCSC;
|
|
#define Dbg (DEBUG_TRACE_MRXSMBCSC)
|
|
|
|
// The CscEnterShadowReadWriteCrit and CscLeaveShadowReadWriteCrit are defined
|
|
// as macros to allow us the ability to capture context information. In non
|
|
// debug builds these will be defined as the regular Ex routines for
|
|
// mutex acquisition/release
|
|
|
|
#if DBG
|
|
|
|
#define CscEnterShadowReadWriteCrit(pSmbFcb) \
|
|
CscpEnterShadowReadWriteCrit(pSmbFcb,__FILE__,__LINE__);
|
|
|
|
#define CscLeaveShadowReadWriteCrit(pSmbFcb) \
|
|
CscpLeaveShadowReadWriteCrit(pSmbFcb,__FILE__,__LINE__);
|
|
|
|
VOID
|
|
CscpEnterShadowReadWriteCrit(
|
|
PMRX_SMB_FCB pSmbFcb,
|
|
PCHAR FileName,
|
|
ULONG Line)
|
|
{
|
|
ExAcquireFastMutex(&pSmbFcb->CscShadowReadWriteMutex);
|
|
}
|
|
|
|
VOID
|
|
CscpLeaveShadowReadWriteCrit(
|
|
PMRX_SMB_FCB pSmbFcb,
|
|
PCHAR FileName,
|
|
ULONG Line)
|
|
{
|
|
ExReleaseFastMutex(&pSmbFcb->CscShadowReadWriteMutex);
|
|
}
|
|
#else
|
|
|
|
#define CscEnterShadowReadWriteCrit(pSmbFcb) \
|
|
ExAcquireFastMutex(&pSmbFcb->CscShadowReadWriteMutex);
|
|
|
|
#define CscLeaveShadowReadWriteCrit(pSmbFcb) \
|
|
ExReleaseFastMutex(&pSmbFcb->CscShadowReadWriteMutex);
|
|
|
|
#endif
|
|
|
|
NTSTATUS
|
|
MRxSmbCscShadowWrite (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN ULONG ByteCount,
|
|
IN ULONGLONG ShadowFileLength,
|
|
OUT PULONG LengthActuallyWritten
|
|
);
|
|
|
|
#ifdef RX_PRIVATE_BUILD
|
|
#undef IoGetTopLevelIrp
|
|
#undef IoSetTopLevelIrp
|
|
#endif //ifdef RX_PRIVATE_BUILD
|
|
|
|
|
|
NTSTATUS
|
|
MRxSmbCscReadPrologue (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
OUT SMBFCB_HOLDING_STATE *SmbFcbHoldingState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine first performs the correct read synchronization and then
|
|
looks at the shadow file and tries to do a read.
|
|
|
|
CODE.IMPROVEMENT because the minirdr is not set up to handle "the rest of
|
|
a read", we fail here if any part of the read is not in the cache. indeed,
|
|
the minirdr should be setup to continue....if it were then we could take
|
|
a prefix of the chunk here and get the rest on the net.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
ULONG iRet,ShadowFileLength;
|
|
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
|
|
BOOLEAN Disconnected;
|
|
|
|
PMRXSMBCSC_SYNC_RX_CONTEXT pRxSyncContext;
|
|
BOOLEAN ThisIsAReenter;
|
|
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
|
|
ULONGLONG ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
ULONG ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
|
|
|
|
BOOLEAN EnteredCriticalSection = FALSE;
|
|
NTSTATUS AcquireStatus;
|
|
|
|
RxDbgTrace(+1, Dbg,
|
|
("MRxSmbCscReadPrologue(%08lx)...%08lx bytes @ %08lx on handle %08lx\n",
|
|
RxContext,ByteCount,((PLARGE_INTEGER)(&ByteOffset))->LowPart,smbSrvOpen->hfShadow ));
|
|
|
|
pNetRootEntry = SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
|
|
|
|
Disconnected = MRxSmbCSCIsDisconnectedOpen(capFcb, smbSrvOpen);
|
|
|
|
pRxSyncContext = MRxSmbGetMinirdrContextForCscSync(RxContext);
|
|
|
|
ASSERT((pRxSyncContext->TypeOfAcquire == 0) ||
|
|
(FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)));
|
|
|
|
ThisIsAReenter = (pRxSyncContext->TypeOfAcquire != 0);
|
|
|
|
AcquireStatus = MRxSmbCscAcquireSmbFcb(
|
|
RxContext,
|
|
Shared_SmbFcbAcquire,
|
|
SmbFcbHoldingState);
|
|
|
|
if (AcquireStatus != STATUS_SUCCESS) {
|
|
//we couldn't acquire.....get out
|
|
Status = AcquireStatus;
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscReadPrologue couldn't acquire!!!-> %08lx %08lx\n",
|
|
Status, RxContext ));
|
|
goto FINALLY;
|
|
}
|
|
|
|
ASSERT( smbFcb->CscOutstandingReaders > 0);
|
|
|
|
//if this is a copychunk open......don't try to get it from the cache.....
|
|
if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_COPYCHUNK_OPEN)){
|
|
goto FINALLY;
|
|
}
|
|
|
|
#if 0
|
|
//if this is the agent......don't try to get it from the cache.....
|
|
//because of the way this test is done.....the agent must do all synchronous
|
|
//I/O. otherwise, we could have posted and this test will be wrong.
|
|
if (IsSpecialApp()) {
|
|
goto FINALLY;
|
|
}
|
|
#endif
|
|
|
|
// we cannot satisfy the read from here in connected mode unless
|
|
// a) we have an oplock, or
|
|
// b) our opens add up to deny write
|
|
|
|
if ((smbFcb->LastOplockLevel == SMB_OPLOCK_LEVEL_NONE) &&
|
|
(!Disconnected)) {
|
|
PSHARE_ACCESS ShareAccess;
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscReadPrologue no oplock!!!-> %08lx %08lx\n",
|
|
Status, RxContext ));
|
|
|
|
ShareAccess = &((PFCB)capFcb)->ShareAccessPerSrvOpens;
|
|
|
|
if ((ShareAccess->OpenCount > 0) &&
|
|
(ShareAccess->SharedWrite == ShareAccess->OpenCount)) {
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscReadPrologue no oplock and write access allowed!!!"
|
|
"-> %08lx %08lx\n",
|
|
Status, RxContext ));
|
|
goto FINALLY;
|
|
}
|
|
}
|
|
|
|
CscEnterShadowReadWriteCrit(smbFcb);
|
|
EnteredCriticalSection = TRUE;
|
|
|
|
// check whether we can satisfy the read locally
|
|
iRet = GetFileSizeLocal((CSCHFILE)(smbSrvOpen->hfShadow), &ShadowFileLength);
|
|
RxDbgTrace( 0, Dbg,
|
|
("MRxSmbCscReadPrologue (st=%08lx) fsize= %08lx\n",
|
|
iRet, ShadowFileLength));
|
|
|
|
if (Disconnected && (ByteOffset >= ShadowFileLength)) {
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscReadPrologue %08lx EOFdcon\n",
|
|
RxContext ));
|
|
RxContext->InformationToReturn = 0;
|
|
Status = STATUS_END_OF_FILE;
|
|
} else if ( Disconnected ||
|
|
(ByteOffset+ByteCount <= ShadowFileLength) ) {
|
|
//okay then....let's get it from cache!!!!
|
|
//CODE.IMPROVEMENT.ASHAMED we should get any part that overlaps the
|
|
// cache from cache....sigh...this is for
|
|
// connected obviously
|
|
LONG ReadLength;
|
|
IO_STATUS_BLOCK IoStatusBlockT;
|
|
|
|
ReadLength = Nt5CscReadWriteFileEx (
|
|
R0_READFILE,
|
|
(CSCHFILE)smbSrvOpen->hfShadow,
|
|
(ULONG)ByteOffset,
|
|
UserBuffer,
|
|
ByteCount,
|
|
0,
|
|
&IoStatusBlockT);
|
|
|
|
|
|
if (ReadLength >= 0)
|
|
{
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscReadPrologue %08lx read %08lx bytes\n",
|
|
RxContext, ReadLength ));
|
|
//sometimes things are good........
|
|
RxContext->InformationToReturn = ReadLength;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Status = IoStatusBlockT.Status;
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
if (EnteredCriticalSection) {
|
|
CscLeaveShadowReadWriteCrit(smbFcb);
|
|
}
|
|
|
|
if (Status==STATUS_SUCCESS) {
|
|
MRxSmbCscReleaseSmbFcb(RxContext,SmbFcbHoldingState);
|
|
}
|
|
|
|
if (ThisIsAReenter &&
|
|
(Status != STATUS_MORE_PROCESSING_REQUIRED)) {
|
|
ASSERT(Status != STATUS_PENDING);
|
|
ASSERT(FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
|
|
RxContext->StoredStatus = Status;
|
|
RxLowIoCompletion(RxContext);
|
|
Status = STATUS_PENDING;
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbCscReadPrologue -> %08lx\n", Status ));
|
|
return Status;
|
|
}
|
|
|
|
ULONG ExtendOnSurrogateOpen = 0;
|
|
|
|
VOID
|
|
MRxSmbCscReadEpilogue (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN OUT PNTSTATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the tail of a read operation for CSC. In
|
|
particular, if the read data can be used to extend the cached
|
|
prefix, then we make it so.
|
|
|
|
The status of the read operation is passed in case we someday find
|
|
things are so messed up that we want to return a failure even after
|
|
a successful read. not today however...
|
|
|
|
CODE.IMPROVEMENT.ASHAMED when we get here the buffer may overlap..we
|
|
should only write the suffix. if we do this, we will have to do some
|
|
wierd stuff in the pagingio path but it will be worth it.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS LocalStatus;
|
|
ULONG ShadowFileLength;
|
|
LONG iRet;
|
|
|
|
RxCaptureFcb;RxCaptureFobx;
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
|
|
ULONGLONG ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
ULONG ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
|
|
ULONG ReadLength = (ULONG)RxContext->InformationToReturn;
|
|
BOOLEAN EnteredCriticalSection = FALSE;
|
|
|
|
RxDbgTrace(+1, Dbg,
|
|
("MRxSmbCscReadEpilogueentry %08lx...%08lx bytes @ %08lx on handle %08lx\n",
|
|
RxContext, ByteCount,
|
|
((PLARGE_INTEGER)(&ByteOffset))->LowPart,
|
|
smbSrvOpen->hfShadow ));
|
|
|
|
if ((*Status != STATUS_SUCCESS)
|
|
|| (ReadLength ==0) ){
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCscReadEpilogue exit w/o extending -> %08lx\n", Status ));
|
|
goto FINALLY;
|
|
}
|
|
if (smbFcb->ShadowIsCorrupt) {
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCscReadEpilogue exit w/o extending sh_corrupt-> %08lx\n", Status ));
|
|
goto FINALLY;
|
|
}
|
|
|
|
// we cannot ask for the csc lock if we are not the toplevel guy......
|
|
if (!FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL)) {
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCscReadEpilogue exit w/o extending NOTTOP -> %08lx\n", Status ));
|
|
//KdPrint(("MRxSmbCscReadEpilogue exit w/o extending NOTTOP -> %08lx\n", Status ));
|
|
goto FINALLY;
|
|
}
|
|
|
|
CscEnterShadowReadWriteCrit(smbFcb);
|
|
EnteredCriticalSection = TRUE;
|
|
|
|
// check whether we are extend overlapping the prefix
|
|
iRet = GetFileSizeLocal((CSCHFILE)(smbSrvOpen->hfShadow), &ShadowFileLength);
|
|
RxDbgTrace( 0, Dbg,
|
|
("MRxSmbCscReadEpilogue %08lx (st=%08lx) fsize= %08lx, readlen=%08lx\n",
|
|
RxContext, iRet, ShadowFileLength, ReadLength));
|
|
|
|
if (iRet <0) {
|
|
goto FINALLY;
|
|
}
|
|
|
|
if ((ByteOffset <= ShadowFileLength) && (ByteOffset+ReadLength > ShadowFileLength)) {
|
|
NTSTATUS ShadowWriteStatus;
|
|
ULONG LengthActuallyWritten;
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscReadEpilogue %08lx writing %08lx bytes\n",
|
|
RxContext,ReadLength ));
|
|
|
|
if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_OPEN_SURROGATED)) {
|
|
ExtendOnSurrogateOpen++;
|
|
}
|
|
|
|
// do a write only if there is non-zero size data to be written.
|
|
if (RxContext->InformationToReturn)
|
|
{
|
|
ShadowWriteStatus = MRxSmbCscShadowWrite(
|
|
RxContext,
|
|
(ULONG)RxContext->InformationToReturn,
|
|
ShadowFileLength,
|
|
&LengthActuallyWritten);
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscReadEpilogue %08lx writing %08lx bytes %08lx written\n",
|
|
RxContext,ReadLength,LengthActuallyWritten ));
|
|
|
|
if (ShadowWriteStatus != STATUS_SUCCESS)
|
|
{
|
|
if (FlagOn(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_COPYCHUNK_OPEN)) {
|
|
|
|
// RxDbgTrace(0, Dbg, ("Copychunk failed status=%x \r\n", ShadowWriteStatus));
|
|
|
|
*Status = ShadowWriteStatus;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
if (EnteredCriticalSection) {
|
|
CscLeaveShadowReadWriteCrit(smbFcb);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbCscReadEpilogue exit -> %08lx %08lx\n", RxContext, Status ));
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MRxSmbCscWritePrologue (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
OUT SMBFCB_HOLDING_STATE *SmbFcbHoldingState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine just performs the correct write synchronization.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
NTSTATUS AcquireStatus;
|
|
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry
|
|
= SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
|
|
|
|
BOOLEAN Disconnected;
|
|
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
|
|
ULONGLONG ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
ULONG ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
|
|
|
|
RxDbgTrace(+1, Dbg,
|
|
("MRxSmbCscWritePrologue entry(%08lx)...%08lx bytes @ %08lx on handle %08lx\n",
|
|
RxContext,ByteCount,
|
|
((PLARGE_INTEGER)(&ByteOffset))->LowPart,smbSrvOpen->hfShadow ));
|
|
|
|
Disconnected = MRxSmbCSCIsDisconnectedOpen(capFcb, smbSrvOpen);
|
|
|
|
|
|
|
|
|
|
IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
|
|
ASSERT(!Disconnected);
|
|
} else {
|
|
if (Disconnected) {
|
|
Status = MRxSmbCscWriteDisconnected(RxContext);
|
|
RxDbgTrace(-1, Dbg,
|
|
("MRxSmbCscWritePrologue dcon(%08lx)... %08lx %08lx\n",
|
|
RxContext,Status,RxContext->InformationToReturn ));
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
AcquireStatus = MRxSmbCscAcquireSmbFcb(
|
|
RxContext,
|
|
Exclusive_SmbFcbAcquire,
|
|
SmbFcbHoldingState);
|
|
|
|
if (AcquireStatus != STATUS_SUCCESS) {
|
|
//we couldn't acquire.....get out
|
|
Status = AcquireStatus;
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscWritePrologue couldn't acquire!!!-> %08lx %08lx\n",
|
|
RxContext, Status ));
|
|
}
|
|
|
|
IF_DEBUG {
|
|
if (Status == STATUS_SUCCESS) {
|
|
RxCaptureFcb;
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
ASSERT( smbFcb->CscOutstandingReaders < 0);
|
|
}
|
|
}
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbCscWritePrologue exit-> %08lx %08lx\n", RxContext, Status ));
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
MRxSmbCscWriteEpilogue (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN OUT PNTSTATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the tail of a write operation for CSC. In
|
|
particular, if the written data overlaps or extends the cached prefix
|
|
then we write the data into the cache.
|
|
|
|
The status of the write operation is passed in case we someday find
|
|
things are so messed up that we want to return a failure even after
|
|
a successful read. not today however...
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS LocalStatus;
|
|
ULONG ShadowFileLength;
|
|
LONG iRet;
|
|
|
|
RxCaptureFcb;RxCaptureFobx;
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
|
|
ULONGLONG ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
ULONG ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
|
|
ULONG WriteLength = (ULONG)RxContext->InformationToReturn;
|
|
BOOLEAN EnteredCriticalSection = FALSE;
|
|
|
|
RxDbgTrace(+1, Dbg,
|
|
("MRxSmbCscWriteEpilogue entry %08lx...%08lx bytes @ %08lx on handle %08lx\n",
|
|
RxContext, ByteCount,
|
|
((PLARGE_INTEGER)(&ByteOffset))->LowPart,
|
|
smbSrvOpen->hfShadow ));
|
|
|
|
if ((*Status != STATUS_SUCCESS) || (WriteLength ==0)) {
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCscWriteEpilogue exit w/o extending -> %08lx\n", Status ));
|
|
goto FINALLY;
|
|
}
|
|
|
|
if (smbFcb->ShadowIsCorrupt) {
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCscWriteEpilogue exit w/o extending sh_corrupt-> %08lx\n", Status ));
|
|
goto FINALLY;
|
|
}
|
|
|
|
// remember that modifications have happened
|
|
// so that we can update the time stamp at close
|
|
mSetBits(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_SHADOW_DATA_MODIFIED);
|
|
|
|
CscEnterShadowReadWriteCrit(smbFcb);
|
|
EnteredCriticalSection = TRUE;
|
|
|
|
// check whether we are extend overlapping the prefix
|
|
iRet = GetFileSizeLocal((CSCHFILE)(smbSrvOpen->hfShadow), &ShadowFileLength);
|
|
RxDbgTrace( 0, Dbg,
|
|
("MRxSmbCscWriteEpilogue %08lx (st=%08lx) fsize= %08lx, writelen=%08lx\n",
|
|
RxContext, iRet, ShadowFileLength, WriteLength));
|
|
|
|
if (iRet <0) {
|
|
goto FINALLY;
|
|
}
|
|
|
|
if (!mShadowSparse(smbFcb->ShadowStatus)
|
|
|| (ByteOffset <= ShadowFileLength)) {
|
|
ULONG LengthActuallyWritten;
|
|
NTSTATUS ShadowWriteStatus;
|
|
// do a write only if there is non-zero size data to be written.
|
|
if (RxContext->InformationToReturn)
|
|
{
|
|
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscWriteEpilogue writing %08lx bytes\n", WriteLength ));
|
|
|
|
ShadowWriteStatus = MRxSmbCscShadowWrite(
|
|
RxContext,
|
|
(ULONG)RxContext->InformationToReturn,
|
|
ShadowFileLength,
|
|
&LengthActuallyWritten);
|
|
|
|
if (LengthActuallyWritten != WriteLength) {
|
|
//the localwrite has failedso the shadowis now corrupt!
|
|
smbFcb->ShadowIsCorrupt = TRUE;
|
|
RxDbgTrace(0, Dbg, ("MRxSmbCscWriteEpilogue: Shadow Is Now corrupt"
|
|
" %08lx %08lx %08lx\n",
|
|
ShadowWriteStatus,
|
|
LengthActuallyWritten,
|
|
WriteLength ));
|
|
}
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
if (EnteredCriticalSection) {
|
|
CscLeaveShadowReadWriteCrit(smbFcb);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbCscWriteEpilogue exit-> %08lx %08lx\n", RxContext, Status ));
|
|
return;
|
|
}
|
|
|
|
// this is used to do pagesized read-before-write
|
|
// CHAR xMRxSmbCscSideBuffer[PAGE_SIZE];
|
|
|
|
NTSTATUS
|
|
MRxSmbCscShadowWrite (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN ULONG ByteCount,
|
|
IN ULONGLONG ShadowFileLength,
|
|
OUT PULONG LengthActuallyWritten
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs a shadowwrite. it uses unbuffered write doing
|
|
prereads as necessary. sigh. we cannot use buffered write because such
|
|
a write could be arbitrarily deferred (as in CcCanIWrite) so that we
|
|
deadlock.
|
|
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
RxPxBuildAsynchronousRequest
|
|
|
|
Notes:
|
|
|
|
CODE.IMPROVEMENT.ASHAMED if we could get a nondeferrable cached write....we
|
|
would only have to do all this nobuffered stuff under intense memory pressure
|
|
instead of all the time.
|
|
|
|
The routine does this in (potentially) 3 phases
|
|
|
|
1) If the starting offset is not aligned on a page boundary then
|
|
- read from the earlier page boundary to the next page boundary to the starting offset
|
|
- merge the passed in buffer
|
|
- write the whole page
|
|
|
|
2) 0 or more page size writes
|
|
|
|
3) residual write of less than page size, similar to what is explained in 1) above
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
RxCaptureFobx;
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
|
|
|
|
LARGE_INTEGER ByteOffset,EndBytePlusOne;
|
|
ULONG MisAlignment,InMemoryMisAlignment;
|
|
ULONG LengthRead,BytesToCopy,BytesToWrite,LengthWritten;
|
|
CHAR *pAllocatedSideBuffer = NULL;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
BOOLEAN PagingIo = BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
|
|
LOWIO_READWRITEFLAG_PAGING_IO);
|
|
|
|
PNT5CSC_MINIFILEOBJECT MiniFileObject = (PNT5CSC_MINIFILEOBJECT)(smbSrvOpen->hfShadow);
|
|
|
|
|
|
ByteOffset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
EndBytePlusOne.QuadPart = ByteOffset.QuadPart + ByteCount;
|
|
*LengthActuallyWritten = 0;
|
|
|
|
ASSERT_MINIRDRFILEOBJECT(MiniFileObject);
|
|
|
|
pAllocatedSideBuffer = RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
PAGE_SIZE,
|
|
MRXSMB_MISC_POOLTAG );
|
|
|
|
if (pAllocatedSideBuffer == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// In attempting to do the write there are a multitude of error cases. The
|
|
// following for loop is a scoping construct to ensure that the recovery
|
|
// code can be concentrated in the tail of the routine.
|
|
|
|
try {
|
|
RxDbgTrace(
|
|
+1, Dbg,
|
|
("MRxSmbCscShadowWrite %08lx len/off=%08lx %08lx %08lx %08lx\n",
|
|
RxContext,ByteCount,ByteOffset.LowPart,UserBuffer,&pAllocatedSideBuffer[0]));
|
|
|
|
// CASE 1: byteoffset is not aligned
|
|
// we write enough to get aligned.
|
|
|
|
MisAlignment = ByteOffset.LowPart & (PAGE_SIZE - 1);
|
|
if ( MisAlignment != 0) {
|
|
LARGE_INTEGER AlignedOffset = ByteOffset;
|
|
|
|
AlignedOffset.LowPart &= ~(PAGE_SIZE - 1);
|
|
|
|
RtlZeroMemory(
|
|
&pAllocatedSideBuffer[0],
|
|
PAGE_SIZE);
|
|
|
|
//if the aligned offset is within the file, we have to read
|
|
if ((ShadowFileLength!=0) &&
|
|
(AlignedOffset.QuadPart < ((LONGLONG)(ShadowFileLength)) )) {
|
|
LengthRead = Nt5CscReadWriteFileEx (
|
|
R0_READFILE,
|
|
(CSCHFILE)MiniFileObject,
|
|
AlignedOffset.QuadPart,
|
|
&pAllocatedSideBuffer[0],
|
|
PAGE_SIZE,
|
|
NT5CSC_RW_FLAG_IRP_NOCACHE,
|
|
&IoStatusBlock
|
|
);
|
|
|
|
Status = IoStatusBlock.Status;
|
|
|
|
if ((Status != STATUS_SUCCESS) &&
|
|
(Status != STATUS_END_OF_FILE)) {
|
|
RxDbgTrace (
|
|
-1, Dbg,
|
|
(" -->Status/count after preread failed %08lx(%08lx,%08lx)\n",
|
|
RxContext,Status,*LengthActuallyWritten));
|
|
try_return(Status);
|
|
}
|
|
} else {
|
|
LengthRead = 0;
|
|
}
|
|
|
|
//copy the right bytes into the buffer
|
|
BytesToCopy = min(ByteCount,PAGE_SIZE-MisAlignment);
|
|
|
|
RtlCopyMemory(
|
|
&pAllocatedSideBuffer[0]+MisAlignment,
|
|
UserBuffer,
|
|
BytesToCopy);
|
|
|
|
BytesToWrite = MisAlignment + BytesToCopy;
|
|
|
|
if (BytesToWrite < LengthRead) {
|
|
BytesToWrite = LengthRead;
|
|
}
|
|
|
|
RxDbgTrace(
|
|
0, Dbg,
|
|
("alignwrite len/off=%08lx %08lx %08lx\n",
|
|
BytesToWrite,AlignedOffset.LowPart,0));
|
|
|
|
LengthWritten = Nt5CscReadWriteFileEx (
|
|
R0_WRITEFILE,
|
|
(CSCHFILE)MiniFileObject,
|
|
AlignedOffset.QuadPart,
|
|
&pAllocatedSideBuffer[0],
|
|
BytesToWrite,
|
|
NT5CSC_RW_FLAG_IRP_NOCACHE,
|
|
&IoStatusBlock
|
|
);
|
|
|
|
Status = IoStatusBlock.Status;
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace (
|
|
-1, Dbg,
|
|
(" -->Status/count after alingwrite failed %08lx(%08lx,%08lx)\n",
|
|
RxContext,Status,*LengthActuallyWritten));
|
|
try_return(Status);
|
|
}
|
|
|
|
*LengthActuallyWritten += BytesToCopy;
|
|
if (BytesToCopy == ByteCount) {
|
|
RxDbgTrace (-1, Dbg,
|
|
(" -->Status/count after alingwrite succeded and out %08lx(%08lx,%08lx)\n",
|
|
RxContext,Status,*LengthActuallyWritten));
|
|
try_return(Status);
|
|
}
|
|
|
|
ByteCount -= BytesToCopy;
|
|
ByteOffset.QuadPart += BytesToCopy;
|
|
UserBuffer += BytesToCopy;
|
|
}
|
|
|
|
// CASE 2 with an aligned startpointer, we write out as much as we can
|
|
// without copying. if the endpointer is aligned OR we cover the
|
|
// end of the file, then we write out everything. otherwise, we
|
|
// just write however many whole pages we have.
|
|
|
|
// we also have to back to to just writing full pages if including the
|
|
// "trailing bytes" would take us onto a new physical page of memory
|
|
// because we are doing this write under the original Mdl lock.
|
|
|
|
RxDbgTrace(
|
|
+1, Dbg,
|
|
("MRxSmbCscShadowWrite case 2 %08lx len/off=%08lx %08lx %08lx %08lx\n",
|
|
RxContext,ByteCount,ByteOffset.LowPart,UserBuffer,&pAllocatedSideBuffer[0]));
|
|
|
|
BytesToWrite = (ByteCount >> PAGE_SHIFT) << PAGE_SHIFT;
|
|
|
|
MisAlignment = EndBytePlusOne.LowPart & (PAGE_SIZE - 1);
|
|
InMemoryMisAlignment = (ULONG)((ULONG_PTR)UserBuffer) & (PAGE_SIZE - 1);
|
|
|
|
if ((InMemoryMisAlignment == 0) &&
|
|
(EndBytePlusOne.QuadPart) >= ((LONGLONG)ShadowFileLength)) {
|
|
BytesToWrite = ByteCount;
|
|
}
|
|
|
|
if ((BytesToWrite != 0)&&(BytesToWrite>=PAGE_SIZE)) {
|
|
if (((ULONG_PTR)UserBuffer & 0x3) == 0) {
|
|
RxDbgTrace(
|
|
0, Dbg,
|
|
("spaningwrite len/off=%08lx %08lx %08lx %08lx\n",
|
|
BytesToWrite,ByteCount,ByteOffset.LowPart,UserBuffer));
|
|
|
|
LengthWritten = Nt5CscReadWriteFileEx (
|
|
R0_WRITEFILE,
|
|
(CSCHFILE)MiniFileObject,
|
|
ByteOffset.QuadPart,
|
|
UserBuffer,
|
|
BytesToWrite,
|
|
NT5CSC_RW_FLAG_IRP_NOCACHE,
|
|
&IoStatusBlock
|
|
);
|
|
|
|
Status = IoStatusBlock.Status;
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace (
|
|
-1, Dbg,
|
|
(" -->Status/count after spanningingwrite failed %08lx(%08lx,%08lx)\n",
|
|
RxContext,Status,*LengthActuallyWritten));
|
|
try_return(Status);
|
|
}
|
|
|
|
*LengthActuallyWritten += BytesToWrite;
|
|
|
|
if (BytesToWrite == ByteCount) {
|
|
RxDbgTrace (
|
|
-1, Dbg,
|
|
(" -->Status/count after spanningingwrite succeded and out %08lx(%08lx,%08lx)\n",
|
|
RxContext,Status,*LengthActuallyWritten));
|
|
try_return(Status);
|
|
}
|
|
|
|
ByteCount -= BytesToWrite;
|
|
ByteOffset.QuadPart += BytesToWrite;
|
|
UserBuffer += BytesToWrite;
|
|
} else {
|
|
// This is the case when the offsets are aligned but the user supplied
|
|
// buffer is not aligned. In such cases we have to resort to copying
|
|
// the user supplied buffer onto the local buffer allocated and then
|
|
// spin out the writes
|
|
|
|
while (BytesToWrite > 0) {
|
|
ULONG BytesToWriteThisIteration;
|
|
|
|
BytesToWriteThisIteration = (BytesToWrite < PAGE_SIZE) ?
|
|
BytesToWrite :
|
|
PAGE_SIZE;
|
|
|
|
RtlCopyMemory(
|
|
&pAllocatedSideBuffer[0],
|
|
UserBuffer,
|
|
BytesToWriteThisIteration);
|
|
|
|
LengthWritten = Nt5CscReadWriteFileEx (
|
|
R0_WRITEFILE,
|
|
(CSCHFILE)MiniFileObject,
|
|
ByteOffset.QuadPart,
|
|
&pAllocatedSideBuffer[0],
|
|
BytesToWriteThisIteration,
|
|
NT5CSC_RW_FLAG_IRP_NOCACHE,
|
|
&IoStatusBlock
|
|
);
|
|
|
|
Status = IoStatusBlock.Status;
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
try_return(Status);
|
|
}
|
|
|
|
ByteCount -= LengthWritten;
|
|
ByteOffset.QuadPart += LengthWritten;
|
|
UserBuffer += LengthWritten;
|
|
|
|
*LengthActuallyWritten += LengthWritten;
|
|
|
|
BytesToWrite -= LengthWritten;
|
|
}
|
|
|
|
if (*LengthActuallyWritten == ByteCount) {
|
|
try_return(Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
// CASE 3: we don't have the whole buffer, ByteCount is less than PAGE_SIZE
|
|
|
|
RtlZeroMemory(&pAllocatedSideBuffer[0], PAGE_SIZE);
|
|
|
|
RxDbgTrace(
|
|
+1, Dbg,
|
|
("MRxSmbCscShadowWrite case 3 %08lx len/off=%08lx %08lx %08lx %08lx\n",
|
|
RxContext,ByteCount,ByteOffset.LowPart,
|
|
UserBuffer,
|
|
&pAllocatedSideBuffer[0]));
|
|
|
|
|
|
LengthRead = Nt5CscReadWriteFileEx (
|
|
R0_READFILE,
|
|
(CSCHFILE)MiniFileObject,
|
|
ByteOffset.QuadPart,
|
|
&pAllocatedSideBuffer[0],
|
|
PAGE_SIZE,
|
|
NT5CSC_RW_FLAG_IRP_NOCACHE,
|
|
&IoStatusBlock
|
|
);
|
|
|
|
Status = IoStatusBlock.Status;
|
|
if ((Status != STATUS_SUCCESS) &&
|
|
(Status != STATUS_END_OF_FILE)) {
|
|
RxDbgTrace (-1, Dbg,
|
|
(" -->Status/count after punkread failed %08lx(%08lx,%08lx)\n",
|
|
RxContext,Status,*LengthActuallyWritten));
|
|
try_return(Status);
|
|
}
|
|
|
|
RtlCopyMemory(&pAllocatedSideBuffer[0],UserBuffer,ByteCount);
|
|
BytesToWrite = ByteCount;
|
|
|
|
// here, if the ByetsToWrite is not sector aligned, it gets so
|
|
// because LeghthRead must be sector aligned
|
|
|
|
if (BytesToWrite < LengthRead) {
|
|
BytesToWrite = LengthRead;
|
|
}
|
|
|
|
RxDbgTrace(0, Dbg, ("punkwrite len/off=%08lx %08lx %08lx\n",
|
|
BytesToWrite,
|
|
ByteOffset.LowPart,
|
|
UserBuffer));
|
|
if (BytesToWrite)
|
|
{
|
|
LengthWritten = Nt5CscReadWriteFileEx (
|
|
R0_WRITEFILE,
|
|
(CSCHFILE)MiniFileObject,
|
|
ByteOffset.QuadPart,
|
|
&pAllocatedSideBuffer[0],
|
|
BytesToWrite,
|
|
NT5CSC_RW_FLAG_IRP_NOCACHE,
|
|
&IoStatusBlock
|
|
);
|
|
Status = IoStatusBlock.Status;
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace (-1, Dbg,
|
|
(" -->Status/count after punkwrite failed %08lx(%08lx,%08lx)\n",
|
|
RxContext,Status,*LengthActuallyWritten));
|
|
try_return(Status);
|
|
}
|
|
}
|
|
|
|
*LengthActuallyWritten += ByteCount;
|
|
RxDbgTrace (-1, Dbg,
|
|
(" -->Status/count after punkwrite succeded and out %08lx(%08lx,%08lx)\n",
|
|
RxContext,Status,*LengthActuallyWritten));
|
|
|
|
try_exit: NOTHING;
|
|
} finally {
|
|
ASSERT(pAllocatedSideBuffer);
|
|
RxFreePool(pAllocatedSideBuffer);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
#ifdef MRXSMB_BUILD_FOR_CSC_DCON
|
|
NTSTATUS
|
|
MRxSmbDCscExtendForCache (
|
|
IN OUT struct _RX_CONTEXT * RxContext,
|
|
IN PLARGE_INTEGER pNewFileSize,
|
|
OUT PLARGE_INTEGER pNewAllocationSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the extend-for-cache operation. if connected, the
|
|
cache is backed up by the server's disk....so we do nothing. if disconnected,
|
|
we extend on the underlying shadow file by writing a zero in a good place and then
|
|
reading back the allocation size.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry
|
|
= SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
|
|
BOOLEAN Disconnected;
|
|
|
|
ULONG Buffer = 0;
|
|
ULONG LengthActuallyWritten;
|
|
LARGE_INTEGER ByteOffset;
|
|
PNT5CSC_MINIFILEOBJECT MiniFileObject = (PNT5CSC_MINIFILEOBJECT)(smbSrvOpen->hfShadow);
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
|
|
ASSERT_MINIRDRFILEOBJECT(MiniFileObject);
|
|
|
|
Disconnected = MRxSmbCSCIsDisconnectedOpen(capFcb, smbSrvOpen);
|
|
|
|
if (!Disconnected) {
|
|
return(Status);
|
|
}
|
|
|
|
RxDbgTrace(+1, Dbg,
|
|
("MRxSmbDCscExtendForCache(%08lx)...%08lx/%08lx @ %08lx on handle %08lx\n",
|
|
RxContext,pNewFileSize->LowPart,
|
|
pNewAllocationSize->LowPart,smbSrvOpen->hfShadow ));
|
|
|
|
ByteOffset.QuadPart = pNewFileSize->QuadPart - 1;
|
|
|
|
LengthActuallyWritten = Nt5CscReadWriteFileEx (
|
|
R0_WRITEFILE,
|
|
(CSCHFILE)MiniFileObject,
|
|
ByteOffset.QuadPart,
|
|
&Buffer,
|
|
1,
|
|
0,
|
|
&IoStatusBlock
|
|
);
|
|
|
|
if (LengthActuallyWritten != 1) {
|
|
Status = IoStatusBlock.Status;
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbDCscExtendForCache(%08lx) write error... %08lx\n",RxContext,Status));
|
|
goto FINALLY;
|
|
}
|
|
|
|
//MiniFileObject->StandardInfo.EndOfFile.LowPart = 0xfffffeee;
|
|
|
|
Status = Nt5CscXxxInformation(
|
|
(PCHAR)IRP_MJ_QUERY_INFORMATION,
|
|
MiniFileObject,
|
|
FileStandardInformation,
|
|
sizeof(MiniFileObject->StandardInfo),
|
|
&MiniFileObject->StandardInfo,
|
|
&MiniFileObject->ReturnedLength
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbDCscExtendForCache(%08lx) qfi error... %08lx\n",RxContext,Status));
|
|
goto FINALLY;
|
|
}
|
|
|
|
*pNewAllocationSize = MiniFileObject->StandardInfo.AllocationSize;
|
|
|
|
FINALLY:
|
|
|
|
RxDbgTrace(-1, Dbg,
|
|
("MRxSmbDCscExtendForCache(%08lx) exit...%08lx/%08lx @ %08lx, status %08lx\n",
|
|
RxContext,pNewFileSize->LowPart,
|
|
pNewAllocationSize->LowPart,smbSrvOpen->hfShadow ));
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MRxSmbCscWriteDisconnected (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine just performs the correct write when we're disconnected. it
|
|
calls the same routine for writing (ShadowWrite) as connected mode writes.
|
|
ShadowWrite requires the filelength for its correct operation; in
|
|
disconnected mode, we just get this out of the smb!
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
|
|
|
|
PFCB wrapperFcb = (PFCB)(capFcb);
|
|
ULONGLONG ShadowFileLength;
|
|
ULONG LengthActuallyWritten;
|
|
ULONG ByteCount = RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount;
|
|
ULONGLONG ByteOffset;
|
|
BOOLEAN EnteredCriticalSection = FALSE;
|
|
PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry =
|
|
SmbCeGetAssociatedNetRootEntry(NetRoot);
|
|
#if defined(BITCOPY)
|
|
ULONG * lpByteOffset;
|
|
#endif // defined(BITCOPY)
|
|
|
|
|
|
ByteOffset = RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset;
|
|
|
|
IF_DEBUG {
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry
|
|
= SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
|
BOOLEAN Disconnected;
|
|
|
|
Disconnected = (BooleanFlagOn(
|
|
smbSrvOpen->Flags,
|
|
SMB_SRVOPEN_FLAG_DISCONNECTED_OPEN)||
|
|
SmbCeIsServerInDisconnectedMode(pServerEntry));
|
|
|
|
|
|
ASSERT(Disconnected);
|
|
}
|
|
|
|
IF_DEBUG {
|
|
ASSERT_MINIRDRFILEOBJECT((PNT5CSC_MINIFILEOBJECT)(smbSrvOpen->hfShadow));
|
|
|
|
RxDbgTrace(+1, Dbg,
|
|
("MRxSmbCscWriteDisconnected entry(%08lx)...%08lx bytes @ %08lx on handle %08lx\n",
|
|
RxContext,ByteCount,
|
|
(ULONG)ByteOffset,smbSrvOpen->hfShadow ));
|
|
}
|
|
|
|
// remember that modifications have happened
|
|
// so that we can update the time stamp at close
|
|
mSetBits(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_SHADOW_DATA_MODIFIED);
|
|
|
|
CscEnterShadowReadWriteCrit(smbFcb);
|
|
EnteredCriticalSection = TRUE;
|
|
|
|
ShadowFileLength = wrapperFcb->Header.FileSize.QuadPart;
|
|
|
|
Status = MRxSmbCscShadowWrite(
|
|
RxContext,
|
|
ByteCount,
|
|
ShadowFileLength,
|
|
&LengthActuallyWritten);
|
|
|
|
RxContext->InformationToReturn = LengthActuallyWritten;
|
|
|
|
#if defined(BITCOPY)
|
|
// Mark the bitmap, if it exists
|
|
lpByteOffset = (ULONG*)(LPVOID)&ByteOffset;
|
|
if (Status == STATUS_SUCCESS) {
|
|
CscBmpMark(smbFcb->lpDirtyBitmap,
|
|
lpByteOffset[0],
|
|
LengthActuallyWritten);
|
|
}
|
|
#endif // defined(BITCOPY)
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace(0, Dbg,
|
|
("MRxSmbCscWriteDisconnected(%08lx) write error... %08lx %08lx %08lx\n",
|
|
RxContext,Status,ByteCount,LengthActuallyWritten));
|
|
goto FINALLY;
|
|
}
|
|
else
|
|
{
|
|
// note the fact that this replica is dirty and it's data would have to merged
|
|
smbFcb->ShadowStatus |= SHADOW_DIRTY;
|
|
|
|
// if the file has gotten extended, then notify the change
|
|
if ((ByteOffset+LengthActuallyWritten) > ShadowFileLength)
|
|
{
|
|
FsRtlNotifyFullReportChange(
|
|
pNetRootEntry->NetRoot.pNotifySync,
|
|
&pNetRootEntry->NetRoot.DirNotifyList,
|
|
(PSTRING)GET_ALREADY_PREFIXED_NAME(NULL,capFcb),
|
|
(USHORT)(GET_ALREADY_PREFIXED_NAME(NULL, capFcb)->Length -
|
|
smbFcb->MinimalCscSmbFcb.LastComponentLength),
|
|
NULL,
|
|
NULL,
|
|
FILE_NOTIFY_CHANGE_SIZE,
|
|
FILE_ACTION_MODIFIED,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
|
|
FINALLY:
|
|
if (EnteredCriticalSection) {
|
|
CscLeaveShadowReadWriteCrit(smbFcb);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("MRxSmbCscWriteDisconnected exit-> %08lx %08lx\n", RxContext, Status ));
|
|
return Status;
|
|
}
|
|
|
|
#endif //ifdef MRXSMB_BUILD_FOR_CSC_DCON
|
|
|
|
|