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.

1248 lines
41 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ReadRite.c
  5. Abstract:
  6. This module implements the routines for reading/writeng shadows at
  7. the right time.
  8. Author:
  9. Joe Linn [JoeLinn] 5-may-1997
  10. Revision History:
  11. Notes:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #pragma code_seg("PAGE")
  16. extern DEBUG_TRACE_CONTROLPOINT RX_DEBUG_TRACE_MRXSMBCSC;
  17. #define Dbg (DEBUG_TRACE_MRXSMBCSC)
  18. // The CscEnterShadowReadWriteCrit and CscLeaveShadowReadWriteCrit are defined
  19. // as macros to allow us the ability to capture context information. In non
  20. // debug builds these will be defined as the regular Ex routines for
  21. // mutex acquisition/release
  22. #if DBG
  23. #define CscEnterShadowReadWriteCrit(pSmbFcb) \
  24. CscpEnterShadowReadWriteCrit(pSmbFcb,__FILE__,__LINE__);
  25. #define CscLeaveShadowReadWriteCrit(pSmbFcb) \
  26. CscpLeaveShadowReadWriteCrit(pSmbFcb,__FILE__,__LINE__);
  27. VOID
  28. CscpEnterShadowReadWriteCrit(
  29. PMRX_SMB_FCB pSmbFcb,
  30. PCHAR FileName,
  31. ULONG Line)
  32. {
  33. ExAcquireFastMutex(&pSmbFcb->CscShadowReadWriteMutex);
  34. }
  35. VOID
  36. CscpLeaveShadowReadWriteCrit(
  37. PMRX_SMB_FCB pSmbFcb,
  38. PCHAR FileName,
  39. ULONG Line)
  40. {
  41. ExReleaseFastMutex(&pSmbFcb->CscShadowReadWriteMutex);
  42. }
  43. #else
  44. #define CscEnterShadowReadWriteCrit(pSmbFcb) \
  45. ExAcquireFastMutex(&pSmbFcb->CscShadowReadWriteMutex);
  46. #define CscLeaveShadowReadWriteCrit(pSmbFcb) \
  47. ExReleaseFastMutex(&pSmbFcb->CscShadowReadWriteMutex);
  48. #endif
  49. NTSTATUS
  50. MRxSmbCscShadowWrite (
  51. IN OUT PRX_CONTEXT RxContext,
  52. IN ULONG ByteCount,
  53. IN ULONGLONG ShadowFileLength,
  54. OUT PULONG LengthActuallyWritten
  55. );
  56. #ifdef RX_PRIVATE_BUILD
  57. #undef IoGetTopLevelIrp
  58. #undef IoSetTopLevelIrp
  59. #endif //ifdef RX_PRIVATE_BUILD
  60. NTSTATUS
  61. MRxSmbCscReadPrologue (
  62. IN OUT PRX_CONTEXT RxContext,
  63. OUT SMBFCB_HOLDING_STATE *SmbFcbHoldingState
  64. )
  65. /*++
  66. Routine Description:
  67. This routine first performs the correct read synchronization and then
  68. looks at the shadow file and tries to do a read.
  69. CODE.IMPROVEMENT because the minirdr is not set up to handle "the rest of
  70. a read", we fail here if any part of the read is not in the cache. indeed,
  71. the minirdr should be setup to continue....if it were then we could take
  72. a prefix of the chunk here and get the rest on the net.
  73. Arguments:
  74. RxContext - the RDBSS context
  75. Return Value:
  76. NTSTATUS - The return status for the operation
  77. Notes:
  78. --*/
  79. {
  80. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  81. ULONG iRet,ShadowFileLength;
  82. RxCaptureFcb;
  83. RxCaptureFobx;
  84. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  85. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  86. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  87. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  88. BOOLEAN Disconnected;
  89. PMRXSMBCSC_SYNC_RX_CONTEXT pRxSyncContext;
  90. BOOLEAN ThisIsAReenter;
  91. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  92. PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
  93. ULONGLONG ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  94. ULONG ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  95. BOOLEAN EnteredCriticalSection = FALSE;
  96. NTSTATUS AcquireStatus;
  97. RxDbgTrace(+1, Dbg,
  98. ("MRxSmbCscReadPrologue(%08lx)...%08lx bytes @ %08lx on handle %08lx\n",
  99. RxContext,ByteCount,((PLARGE_INTEGER)(&ByteOffset))->LowPart,smbSrvOpen->hfShadow ));
  100. pNetRootEntry = SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
  101. Disconnected = MRxSmbCSCIsDisconnectedOpen(capFcb, smbSrvOpen);
  102. pRxSyncContext = MRxSmbGetMinirdrContextForCscSync(RxContext);
  103. ASSERT((pRxSyncContext->TypeOfAcquire == 0) ||
  104. (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)));
  105. ThisIsAReenter = (pRxSyncContext->TypeOfAcquire != 0);
  106. AcquireStatus = MRxSmbCscAcquireSmbFcb(
  107. RxContext,
  108. Shared_SmbFcbAcquire,
  109. SmbFcbHoldingState);
  110. if (AcquireStatus != STATUS_SUCCESS) {
  111. //we couldn't acquire.....get out
  112. Status = AcquireStatus;
  113. RxDbgTrace(0, Dbg,
  114. ("MRxSmbCscReadPrologue couldn't acquire!!!-> %08lx %08lx\n",
  115. Status, RxContext ));
  116. goto FINALLY;
  117. }
  118. ASSERT( smbFcb->CscOutstandingReaders > 0);
  119. //if this is a copychunk open......don't try to get it from the cache.....
  120. if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_COPYCHUNK_OPEN)){
  121. goto FINALLY;
  122. }
  123. #if 0
  124. //if this is the agent......don't try to get it from the cache.....
  125. //because of the way this test is done.....the agent must do all synchronous
  126. //I/O. otherwise, we could have posted and this test will be wrong.
  127. if (IsSpecialApp()) {
  128. goto FINALLY;
  129. }
  130. #endif
  131. // we cannot satisfy the read from here in connected mode unless
  132. // a) we have an oplock, or
  133. // b) our opens add up to deny write
  134. if ((smbFcb->LastOplockLevel == SMB_OPLOCK_LEVEL_NONE) &&
  135. (!Disconnected)) {
  136. PSHARE_ACCESS ShareAccess;
  137. RxDbgTrace(0, Dbg,
  138. ("MRxSmbCscReadPrologue no oplock!!!-> %08lx %08lx\n",
  139. Status, RxContext ));
  140. ShareAccess = &((PFCB)capFcb)->ShareAccessPerSrvOpens;
  141. if ((ShareAccess->OpenCount > 0) &&
  142. (ShareAccess->SharedWrite == ShareAccess->OpenCount)) {
  143. RxDbgTrace(0, Dbg,
  144. ("MRxSmbCscReadPrologue no oplock and write access allowed!!!"
  145. "-> %08lx %08lx\n",
  146. Status, RxContext ));
  147. goto FINALLY;
  148. }
  149. }
  150. CscEnterShadowReadWriteCrit(smbFcb);
  151. EnteredCriticalSection = TRUE;
  152. // check whether we can satisfy the read locally
  153. iRet = GetFileSizeLocal((CSCHFILE)(smbSrvOpen->hfShadow), &ShadowFileLength);
  154. RxDbgTrace( 0, Dbg,
  155. ("MRxSmbCscReadPrologue (st=%08lx) fsize= %08lx\n",
  156. iRet, ShadowFileLength));
  157. if (Disconnected && (ByteOffset >= ShadowFileLength)) {
  158. RxDbgTrace(0, Dbg,
  159. ("MRxSmbCscReadPrologue %08lx EOFdcon\n",
  160. RxContext ));
  161. RxContext->InformationToReturn = 0;
  162. Status = STATUS_END_OF_FILE;
  163. } else if ( Disconnected ||
  164. (ByteOffset+ByteCount <= ShadowFileLength) ) {
  165. //okay then....let's get it from cache!!!!
  166. //CODE.IMPROVEMENT.ASHAMED we should get any part that overlaps the
  167. // cache from cache....sigh...this is for
  168. // connected obviously
  169. LONG ReadLength;
  170. IO_STATUS_BLOCK IoStatusBlockT;
  171. ReadLength = Nt5CscReadWriteFileEx (
  172. R0_READFILE,
  173. (CSCHFILE)smbSrvOpen->hfShadow,
  174. (ULONG)ByteOffset,
  175. UserBuffer,
  176. ByteCount,
  177. 0,
  178. &IoStatusBlockT);
  179. if (ReadLength >= 0)
  180. {
  181. RxDbgTrace(0, Dbg,
  182. ("MRxSmbCscReadPrologue %08lx read %08lx bytes\n",
  183. RxContext, ReadLength ));
  184. //sometimes things are good........
  185. RxContext->InformationToReturn = ReadLength;
  186. Status = STATUS_SUCCESS;
  187. }
  188. else
  189. {
  190. Status = IoStatusBlockT.Status;
  191. }
  192. }
  193. FINALLY:
  194. if (EnteredCriticalSection) {
  195. CscLeaveShadowReadWriteCrit(smbFcb);
  196. }
  197. if (Status==STATUS_SUCCESS) {
  198. MRxSmbCscReleaseSmbFcb(RxContext,SmbFcbHoldingState);
  199. }
  200. if (ThisIsAReenter &&
  201. (Status != STATUS_MORE_PROCESSING_REQUIRED)) {
  202. ASSERT(Status != STATUS_PENDING);
  203. ASSERT(FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  204. RxContext->StoredStatus = Status;
  205. RxLowIoCompletion(RxContext);
  206. Status = STATUS_PENDING;
  207. }
  208. RxDbgTrace(-1, Dbg, ("MRxSmbCscReadPrologue -> %08lx\n", Status ));
  209. return Status;
  210. }
  211. ULONG ExtendOnSurrogateOpen = 0;
  212. VOID
  213. MRxSmbCscReadEpilogue (
  214. IN OUT PRX_CONTEXT RxContext,
  215. IN OUT PNTSTATUS Status
  216. )
  217. /*++
  218. Routine Description:
  219. This routine performs the tail of a read operation for CSC. In
  220. particular, if the read data can be used to extend the cached
  221. prefix, then we make it so.
  222. The status of the read operation is passed in case we someday find
  223. things are so messed up that we want to return a failure even after
  224. a successful read. not today however...
  225. CODE.IMPROVEMENT.ASHAMED when we get here the buffer may overlap..we
  226. should only write the suffix. if we do this, we will have to do some
  227. wierd stuff in the pagingio path but it will be worth it.
  228. Arguments:
  229. RxContext - the RDBSS context
  230. Return Value:
  231. NTSTATUS - The return status for the operation
  232. Notes:
  233. --*/
  234. {
  235. NTSTATUS LocalStatus;
  236. ULONG ShadowFileLength;
  237. LONG iRet;
  238. RxCaptureFcb;RxCaptureFobx;
  239. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  240. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  241. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  242. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  243. PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
  244. ULONGLONG ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  245. ULONG ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  246. ULONG ReadLength = (ULONG)RxContext->InformationToReturn;
  247. BOOLEAN EnteredCriticalSection = FALSE;
  248. RxDbgTrace(+1, Dbg,
  249. ("MRxSmbCscReadEpilogueentry %08lx...%08lx bytes @ %08lx on handle %08lx\n",
  250. RxContext, ByteCount,
  251. ((PLARGE_INTEGER)(&ByteOffset))->LowPart,
  252. smbSrvOpen->hfShadow ));
  253. if ((*Status != STATUS_SUCCESS)
  254. || (ReadLength ==0) ){
  255. RxDbgTrace(0, Dbg, ("MRxSmbCscReadEpilogue exit w/o extending -> %08lx\n", Status ));
  256. goto FINALLY;
  257. }
  258. if (smbFcb->ShadowIsCorrupt) {
  259. RxDbgTrace(0, Dbg, ("MRxSmbCscReadEpilogue exit w/o extending sh_corrupt-> %08lx\n", Status ));
  260. goto FINALLY;
  261. }
  262. // we cannot ask for the csc lock if we are not the toplevel guy......
  263. if (!FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL)) {
  264. RxDbgTrace(0, Dbg, ("MRxSmbCscReadEpilogue exit w/o extending NOTTOP -> %08lx\n", Status ));
  265. //KdPrint(("MRxSmbCscReadEpilogue exit w/o extending NOTTOP -> %08lx\n", Status ));
  266. goto FINALLY;
  267. }
  268. CscEnterShadowReadWriteCrit(smbFcb);
  269. EnteredCriticalSection = TRUE;
  270. // check whether we are extend overlapping the prefix
  271. iRet = GetFileSizeLocal((CSCHFILE)(smbSrvOpen->hfShadow), &ShadowFileLength);
  272. RxDbgTrace( 0, Dbg,
  273. ("MRxSmbCscReadEpilogue %08lx (st=%08lx) fsize= %08lx, readlen=%08lx\n",
  274. RxContext, iRet, ShadowFileLength, ReadLength));
  275. if (iRet <0) {
  276. goto FINALLY;
  277. }
  278. if ((ByteOffset <= ShadowFileLength) && (ByteOffset+ReadLength > ShadowFileLength)) {
  279. NTSTATUS ShadowWriteStatus;
  280. ULONG LengthActuallyWritten;
  281. RxDbgTrace(0, Dbg,
  282. ("MRxSmbCscReadEpilogue %08lx writing %08lx bytes\n",
  283. RxContext,ReadLength ));
  284. if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_OPEN_SURROGATED)) {
  285. ExtendOnSurrogateOpen++;
  286. }
  287. // do a write only if there is non-zero size data to be written.
  288. if (RxContext->InformationToReturn)
  289. {
  290. ShadowWriteStatus = MRxSmbCscShadowWrite(
  291. RxContext,
  292. (ULONG)RxContext->InformationToReturn,
  293. ShadowFileLength,
  294. &LengthActuallyWritten);
  295. RxDbgTrace(0, Dbg,
  296. ("MRxSmbCscReadEpilogue %08lx writing %08lx bytes %08lx written\n",
  297. RxContext,ReadLength,LengthActuallyWritten ));
  298. if (ShadowWriteStatus != STATUS_SUCCESS)
  299. {
  300. if (FlagOn(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_COPYCHUNK_OPEN)) {
  301. // RxDbgTrace(0, Dbg, ("Copychunk failed status=%x \r\n", ShadowWriteStatus));
  302. *Status = ShadowWriteStatus;
  303. }
  304. }
  305. }
  306. }
  307. FINALLY:
  308. if (EnteredCriticalSection) {
  309. CscLeaveShadowReadWriteCrit(smbFcb);
  310. }
  311. RxDbgTrace(-1, Dbg, ("MRxSmbCscReadEpilogue exit -> %08lx %08lx\n", RxContext, Status ));
  312. return;
  313. }
  314. NTSTATUS
  315. MRxSmbCscWritePrologue (
  316. IN OUT PRX_CONTEXT RxContext,
  317. OUT SMBFCB_HOLDING_STATE *SmbFcbHoldingState
  318. )
  319. /*++
  320. Routine Description:
  321. This routine just performs the correct write synchronization.
  322. Arguments:
  323. RxContext - the RDBSS context
  324. Return Value:
  325. NTSTATUS - The return status for the operation
  326. Notes:
  327. --*/
  328. {
  329. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  330. NTSTATUS AcquireStatus;
  331. RxCaptureFcb;
  332. RxCaptureFobx;
  333. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  334. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  335. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry
  336. = SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
  337. BOOLEAN Disconnected;
  338. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  339. PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
  340. ULONGLONG ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  341. ULONG ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  342. RxDbgTrace(+1, Dbg,
  343. ("MRxSmbCscWritePrologue entry(%08lx)...%08lx bytes @ %08lx on handle %08lx\n",
  344. RxContext,ByteCount,
  345. ((PLARGE_INTEGER)(&ByteOffset))->LowPart,smbSrvOpen->hfShadow ));
  346. Disconnected = MRxSmbCSCIsDisconnectedOpen(capFcb, smbSrvOpen);
  347. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  348. ASSERT(!Disconnected);
  349. } else {
  350. if (Disconnected) {
  351. Status = MRxSmbCscWriteDisconnected(RxContext);
  352. RxDbgTrace(-1, Dbg,
  353. ("MRxSmbCscWritePrologue dcon(%08lx)... %08lx %08lx\n",
  354. RxContext,Status,RxContext->InformationToReturn ));
  355. return(Status);
  356. }
  357. }
  358. AcquireStatus = MRxSmbCscAcquireSmbFcb(
  359. RxContext,
  360. Exclusive_SmbFcbAcquire,
  361. SmbFcbHoldingState);
  362. if (AcquireStatus != STATUS_SUCCESS) {
  363. //we couldn't acquire.....get out
  364. Status = AcquireStatus;
  365. RxDbgTrace(0, Dbg,
  366. ("MRxSmbCscWritePrologue couldn't acquire!!!-> %08lx %08lx\n",
  367. RxContext, Status ));
  368. }
  369. IF_DEBUG {
  370. if (Status == STATUS_SUCCESS) {
  371. RxCaptureFcb;
  372. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  373. ASSERT( smbFcb->CscOutstandingReaders < 0);
  374. }
  375. }
  376. RxDbgTrace(-1, Dbg, ("MRxSmbCscWritePrologue exit-> %08lx %08lx\n", RxContext, Status ));
  377. return Status;
  378. }
  379. VOID
  380. MRxSmbCscWriteEpilogue (
  381. IN OUT PRX_CONTEXT RxContext,
  382. IN OUT PNTSTATUS Status
  383. )
  384. /*++
  385. Routine Description:
  386. This routine performs the tail of a write operation for CSC. In
  387. particular, if the written data overlaps or extends the cached prefix
  388. then we write the data into the cache.
  389. The status of the write operation is passed in case we someday find
  390. things are so messed up that we want to return a failure even after
  391. a successful read. not today however...
  392. Arguments:
  393. RxContext - the RDBSS context
  394. Return Value:
  395. NTSTATUS - The return status for the operation
  396. Notes:
  397. --*/
  398. {
  399. NTSTATUS LocalStatus;
  400. ULONG ShadowFileLength;
  401. LONG iRet;
  402. RxCaptureFcb;RxCaptureFobx;
  403. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  404. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  405. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  406. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  407. PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
  408. ULONGLONG ByteOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  409. ULONG ByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  410. ULONG WriteLength = (ULONG)RxContext->InformationToReturn;
  411. BOOLEAN EnteredCriticalSection = FALSE;
  412. RxDbgTrace(+1, Dbg,
  413. ("MRxSmbCscWriteEpilogue entry %08lx...%08lx bytes @ %08lx on handle %08lx\n",
  414. RxContext, ByteCount,
  415. ((PLARGE_INTEGER)(&ByteOffset))->LowPart,
  416. smbSrvOpen->hfShadow ));
  417. if ((*Status != STATUS_SUCCESS) || (WriteLength ==0)) {
  418. RxDbgTrace(0, Dbg, ("MRxSmbCscWriteEpilogue exit w/o extending -> %08lx\n", Status ));
  419. goto FINALLY;
  420. }
  421. if (smbFcb->ShadowIsCorrupt) {
  422. RxDbgTrace(0, Dbg, ("MRxSmbCscWriteEpilogue exit w/o extending sh_corrupt-> %08lx\n", Status ));
  423. goto FINALLY;
  424. }
  425. // remember that modifications have happened
  426. // so that we can update the time stamp at close
  427. mSetBits(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_SHADOW_DATA_MODIFIED);
  428. CscEnterShadowReadWriteCrit(smbFcb);
  429. EnteredCriticalSection = TRUE;
  430. // check whether we are extend overlapping the prefix
  431. iRet = GetFileSizeLocal((CSCHFILE)(smbSrvOpen->hfShadow), &ShadowFileLength);
  432. RxDbgTrace( 0, Dbg,
  433. ("MRxSmbCscWriteEpilogue %08lx (st=%08lx) fsize= %08lx, writelen=%08lx\n",
  434. RxContext, iRet, ShadowFileLength, WriteLength));
  435. if (iRet <0) {
  436. goto FINALLY;
  437. }
  438. if (!mShadowSparse(smbFcb->ShadowStatus)
  439. || (ByteOffset <= ShadowFileLength)) {
  440. ULONG LengthActuallyWritten;
  441. NTSTATUS ShadowWriteStatus;
  442. // do a write only if there is non-zero size data to be written.
  443. if (RxContext->InformationToReturn)
  444. {
  445. RxDbgTrace(0, Dbg,
  446. ("MRxSmbCscWriteEpilogue writing %08lx bytes\n", WriteLength ));
  447. ShadowWriteStatus = MRxSmbCscShadowWrite(
  448. RxContext,
  449. (ULONG)RxContext->InformationToReturn,
  450. ShadowFileLength,
  451. &LengthActuallyWritten);
  452. if (LengthActuallyWritten != WriteLength) {
  453. //the localwrite has failedso the shadowis now corrupt!
  454. smbFcb->ShadowIsCorrupt = TRUE;
  455. RxDbgTrace(0, Dbg, ("MRxSmbCscWriteEpilogue: Shadow Is Now corrupt"
  456. " %08lx %08lx %08lx\n",
  457. ShadowWriteStatus,
  458. LengthActuallyWritten,
  459. WriteLength ));
  460. }
  461. }
  462. }
  463. FINALLY:
  464. if (EnteredCriticalSection) {
  465. CscLeaveShadowReadWriteCrit(smbFcb);
  466. }
  467. RxDbgTrace(-1, Dbg, ("MRxSmbCscWriteEpilogue exit-> %08lx %08lx\n", RxContext, Status ));
  468. return;
  469. }
  470. // this is used to do pagesized read-before-write
  471. // CHAR xMRxSmbCscSideBuffer[PAGE_SIZE];
  472. NTSTATUS
  473. MRxSmbCscShadowWrite (
  474. IN OUT PRX_CONTEXT RxContext,
  475. IN ULONG ByteCount,
  476. IN ULONGLONG ShadowFileLength,
  477. OUT PULONG LengthActuallyWritten
  478. )
  479. /*++
  480. Routine Description:
  481. This routine performs a shadowwrite. it uses unbuffered write doing
  482. prereads as necessary. sigh. we cannot use buffered write because such
  483. a write could be arbitrarily deferred (as in CcCanIWrite) so that we
  484. deadlock.
  485. Arguments:
  486. RxContext - the RDBSS context
  487. Return Value:
  488. RxPxBuildAsynchronousRequest
  489. Notes:
  490. CODE.IMPROVEMENT.ASHAMED if we could get a nondeferrable cached write....we
  491. would only have to do all this nobuffered stuff under intense memory pressure
  492. instead of all the time.
  493. The routine does this in (potentially) 3 phases
  494. 1) If the starting offset is not aligned on a page boundary then
  495. - read from the earlier page boundary to the next page boundary to the starting offset
  496. - merge the passed in buffer
  497. - write the whole page
  498. 2) 0 or more page size writes
  499. 3) residual write of less than page size, similar to what is explained in 1) above
  500. --*/
  501. {
  502. NTSTATUS Status;
  503. RxCaptureFobx;
  504. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  505. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  506. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  507. PBYTE UserBuffer = RxLowIoGetBufferAddress(RxContext);
  508. LARGE_INTEGER ByteOffset,EndBytePlusOne;
  509. ULONG MisAlignment,InMemoryMisAlignment;
  510. ULONG LengthRead,BytesToCopy,BytesToWrite,LengthWritten;
  511. CHAR *pAllocatedSideBuffer = NULL;
  512. IO_STATUS_BLOCK IoStatusBlock;
  513. BOOLEAN PagingIo = BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
  514. LOWIO_READWRITEFLAG_PAGING_IO);
  515. PNT5CSC_MINIFILEOBJECT MiniFileObject = (PNT5CSC_MINIFILEOBJECT)(smbSrvOpen->hfShadow);
  516. ByteOffset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  517. EndBytePlusOne.QuadPart = ByteOffset.QuadPart + ByteCount;
  518. *LengthActuallyWritten = 0;
  519. ASSERT_MINIRDRFILEOBJECT(MiniFileObject);
  520. pAllocatedSideBuffer = RxAllocatePoolWithTag(
  521. NonPagedPool,
  522. PAGE_SIZE,
  523. MRXSMB_MISC_POOLTAG );
  524. if (pAllocatedSideBuffer == NULL) {
  525. return STATUS_INSUFFICIENT_RESOURCES;
  526. }
  527. // In attempting to do the write there are a multitude of error cases. The
  528. // following for loop is a scoping construct to ensure that the recovery
  529. // code can be concentrated in the tail of the routine.
  530. try {
  531. RxDbgTrace(
  532. +1, Dbg,
  533. ("MRxSmbCscShadowWrite %08lx len/off=%08lx %08lx %08lx %08lx\n",
  534. RxContext,ByteCount,ByteOffset.LowPart,UserBuffer,&pAllocatedSideBuffer[0]));
  535. // CASE 1: byteoffset is not aligned
  536. // we write enough to get aligned.
  537. MisAlignment = ByteOffset.LowPart & (PAGE_SIZE - 1);
  538. if ( MisAlignment != 0) {
  539. LARGE_INTEGER AlignedOffset = ByteOffset;
  540. AlignedOffset.LowPart &= ~(PAGE_SIZE - 1);
  541. RtlZeroMemory(
  542. &pAllocatedSideBuffer[0],
  543. PAGE_SIZE);
  544. //if the aligned offset is within the file, we have to read
  545. if ((ShadowFileLength!=0) &&
  546. (AlignedOffset.QuadPart < ((LONGLONG)(ShadowFileLength)) )) {
  547. LengthRead = Nt5CscReadWriteFileEx (
  548. R0_READFILE,
  549. (CSCHFILE)MiniFileObject,
  550. AlignedOffset.QuadPart,
  551. &pAllocatedSideBuffer[0],
  552. PAGE_SIZE,
  553. NT5CSC_RW_FLAG_IRP_NOCACHE,
  554. &IoStatusBlock
  555. );
  556. Status = IoStatusBlock.Status;
  557. if ((Status != STATUS_SUCCESS) &&
  558. (Status != STATUS_END_OF_FILE)) {
  559. RxDbgTrace (
  560. -1, Dbg,
  561. (" -->Status/count after preread failed %08lx(%08lx,%08lx)\n",
  562. RxContext,Status,*LengthActuallyWritten));
  563. try_return(Status);
  564. }
  565. } else {
  566. LengthRead = 0;
  567. }
  568. //copy the right bytes into the buffer
  569. BytesToCopy = min(ByteCount,PAGE_SIZE-MisAlignment);
  570. RtlCopyMemory(
  571. &pAllocatedSideBuffer[0]+MisAlignment,
  572. UserBuffer,
  573. BytesToCopy);
  574. BytesToWrite = MisAlignment + BytesToCopy;
  575. if (BytesToWrite < LengthRead) {
  576. BytesToWrite = LengthRead;
  577. }
  578. RxDbgTrace(
  579. 0, Dbg,
  580. ("alignwrite len/off=%08lx %08lx %08lx\n",
  581. BytesToWrite,AlignedOffset.LowPart,0));
  582. LengthWritten = Nt5CscReadWriteFileEx (
  583. R0_WRITEFILE,
  584. (CSCHFILE)MiniFileObject,
  585. AlignedOffset.QuadPart,
  586. &pAllocatedSideBuffer[0],
  587. BytesToWrite,
  588. NT5CSC_RW_FLAG_IRP_NOCACHE,
  589. &IoStatusBlock
  590. );
  591. Status = IoStatusBlock.Status;
  592. if (Status != STATUS_SUCCESS) {
  593. RxDbgTrace (
  594. -1, Dbg,
  595. (" -->Status/count after alingwrite failed %08lx(%08lx,%08lx)\n",
  596. RxContext,Status,*LengthActuallyWritten));
  597. try_return(Status);
  598. }
  599. *LengthActuallyWritten += BytesToCopy;
  600. if (BytesToCopy == ByteCount) {
  601. RxDbgTrace (-1, Dbg,
  602. (" -->Status/count after alingwrite succeded and out %08lx(%08lx,%08lx)\n",
  603. RxContext,Status,*LengthActuallyWritten));
  604. try_return(Status);
  605. }
  606. ByteCount -= BytesToCopy;
  607. ByteOffset.QuadPart += BytesToCopy;
  608. UserBuffer += BytesToCopy;
  609. }
  610. // CASE 2 with an aligned startpointer, we write out as much as we can
  611. // without copying. if the endpointer is aligned OR we cover the
  612. // end of the file, then we write out everything. otherwise, we
  613. // just write however many whole pages we have.
  614. // we also have to back to to just writing full pages if including the
  615. // "trailing bytes" would take us onto a new physical page of memory
  616. // because we are doing this write under the original Mdl lock.
  617. RxDbgTrace(
  618. +1, Dbg,
  619. ("MRxSmbCscShadowWrite case 2 %08lx len/off=%08lx %08lx %08lx %08lx\n",
  620. RxContext,ByteCount,ByteOffset.LowPart,UserBuffer,&pAllocatedSideBuffer[0]));
  621. BytesToWrite = (ByteCount >> PAGE_SHIFT) << PAGE_SHIFT;
  622. MisAlignment = EndBytePlusOne.LowPart & (PAGE_SIZE - 1);
  623. InMemoryMisAlignment = (ULONG)((ULONG_PTR)UserBuffer) & (PAGE_SIZE - 1);
  624. if ((InMemoryMisAlignment == 0) &&
  625. (EndBytePlusOne.QuadPart) >= ((LONGLONG)ShadowFileLength)) {
  626. BytesToWrite = ByteCount;
  627. }
  628. if ((BytesToWrite != 0)&&(BytesToWrite>=PAGE_SIZE)) {
  629. if (((ULONG_PTR)UserBuffer & 0x3) == 0) {
  630. RxDbgTrace(
  631. 0, Dbg,
  632. ("spaningwrite len/off=%08lx %08lx %08lx %08lx\n",
  633. BytesToWrite,ByteCount,ByteOffset.LowPart,UserBuffer));
  634. LengthWritten = Nt5CscReadWriteFileEx (
  635. R0_WRITEFILE,
  636. (CSCHFILE)MiniFileObject,
  637. ByteOffset.QuadPart,
  638. UserBuffer,
  639. BytesToWrite,
  640. NT5CSC_RW_FLAG_IRP_NOCACHE,
  641. &IoStatusBlock
  642. );
  643. Status = IoStatusBlock.Status;
  644. if (Status != STATUS_SUCCESS) {
  645. RxDbgTrace (
  646. -1, Dbg,
  647. (" -->Status/count after spanningingwrite failed %08lx(%08lx,%08lx)\n",
  648. RxContext,Status,*LengthActuallyWritten));
  649. try_return(Status);
  650. }
  651. *LengthActuallyWritten += BytesToWrite;
  652. if (BytesToWrite == ByteCount) {
  653. RxDbgTrace (
  654. -1, Dbg,
  655. (" -->Status/count after spanningingwrite succeded and out %08lx(%08lx,%08lx)\n",
  656. RxContext,Status,*LengthActuallyWritten));
  657. try_return(Status);
  658. }
  659. ByteCount -= BytesToWrite;
  660. ByteOffset.QuadPart += BytesToWrite;
  661. UserBuffer += BytesToWrite;
  662. } else {
  663. // This is the case when the offsets are aligned but the user supplied
  664. // buffer is not aligned. In such cases we have to resort to copying
  665. // the user supplied buffer onto the local buffer allocated and then
  666. // spin out the writes
  667. while (BytesToWrite > 0) {
  668. ULONG BytesToWriteThisIteration;
  669. BytesToWriteThisIteration = (BytesToWrite < PAGE_SIZE) ?
  670. BytesToWrite :
  671. PAGE_SIZE;
  672. RtlCopyMemory(
  673. &pAllocatedSideBuffer[0],
  674. UserBuffer,
  675. BytesToWriteThisIteration);
  676. LengthWritten = Nt5CscReadWriteFileEx (
  677. R0_WRITEFILE,
  678. (CSCHFILE)MiniFileObject,
  679. ByteOffset.QuadPart,
  680. &pAllocatedSideBuffer[0],
  681. BytesToWriteThisIteration,
  682. NT5CSC_RW_FLAG_IRP_NOCACHE,
  683. &IoStatusBlock
  684. );
  685. Status = IoStatusBlock.Status;
  686. if (Status != STATUS_SUCCESS) {
  687. try_return(Status);
  688. }
  689. ByteCount -= LengthWritten;
  690. ByteOffset.QuadPart += LengthWritten;
  691. UserBuffer += LengthWritten;
  692. *LengthActuallyWritten += LengthWritten;
  693. BytesToWrite -= LengthWritten;
  694. }
  695. if (*LengthActuallyWritten == ByteCount) {
  696. try_return(Status);
  697. }
  698. }
  699. }
  700. // CASE 3: we don't have the whole buffer, ByteCount is less than PAGE_SIZE
  701. RtlZeroMemory(&pAllocatedSideBuffer[0], PAGE_SIZE);
  702. RxDbgTrace(
  703. +1, Dbg,
  704. ("MRxSmbCscShadowWrite case 3 %08lx len/off=%08lx %08lx %08lx %08lx\n",
  705. RxContext,ByteCount,ByteOffset.LowPart,
  706. UserBuffer,
  707. &pAllocatedSideBuffer[0]));
  708. LengthRead = Nt5CscReadWriteFileEx (
  709. R0_READFILE,
  710. (CSCHFILE)MiniFileObject,
  711. ByteOffset.QuadPart,
  712. &pAllocatedSideBuffer[0],
  713. PAGE_SIZE,
  714. NT5CSC_RW_FLAG_IRP_NOCACHE,
  715. &IoStatusBlock
  716. );
  717. Status = IoStatusBlock.Status;
  718. if ((Status != STATUS_SUCCESS) &&
  719. (Status != STATUS_END_OF_FILE)) {
  720. RxDbgTrace (-1, Dbg,
  721. (" -->Status/count after punkread failed %08lx(%08lx,%08lx)\n",
  722. RxContext,Status,*LengthActuallyWritten));
  723. try_return(Status);
  724. }
  725. RtlCopyMemory(&pAllocatedSideBuffer[0],UserBuffer,ByteCount);
  726. BytesToWrite = ByteCount;
  727. // here, if the ByetsToWrite is not sector aligned, it gets so
  728. // because LeghthRead must be sector aligned
  729. if (BytesToWrite < LengthRead) {
  730. BytesToWrite = LengthRead;
  731. }
  732. RxDbgTrace(0, Dbg, ("punkwrite len/off=%08lx %08lx %08lx\n",
  733. BytesToWrite,
  734. ByteOffset.LowPart,
  735. UserBuffer));
  736. if (BytesToWrite)
  737. {
  738. LengthWritten = Nt5CscReadWriteFileEx (
  739. R0_WRITEFILE,
  740. (CSCHFILE)MiniFileObject,
  741. ByteOffset.QuadPart,
  742. &pAllocatedSideBuffer[0],
  743. BytesToWrite,
  744. NT5CSC_RW_FLAG_IRP_NOCACHE,
  745. &IoStatusBlock
  746. );
  747. Status = IoStatusBlock.Status;
  748. if (Status != STATUS_SUCCESS) {
  749. RxDbgTrace (-1, Dbg,
  750. (" -->Status/count after punkwrite failed %08lx(%08lx,%08lx)\n",
  751. RxContext,Status,*LengthActuallyWritten));
  752. try_return(Status);
  753. }
  754. }
  755. *LengthActuallyWritten += ByteCount;
  756. RxDbgTrace (-1, Dbg,
  757. (" -->Status/count after punkwrite succeded and out %08lx(%08lx,%08lx)\n",
  758. RxContext,Status,*LengthActuallyWritten));
  759. try_exit: NOTHING;
  760. } finally {
  761. ASSERT(pAllocatedSideBuffer);
  762. RxFreePool(pAllocatedSideBuffer);
  763. }
  764. return(Status);
  765. }
  766. #ifdef MRXSMB_BUILD_FOR_CSC_DCON
  767. NTSTATUS
  768. MRxSmbDCscExtendForCache (
  769. IN OUT struct _RX_CONTEXT * RxContext,
  770. IN PLARGE_INTEGER pNewFileSize,
  771. OUT PLARGE_INTEGER pNewAllocationSize
  772. )
  773. /*++
  774. Routine Description:
  775. This routine performs the extend-for-cache operation. if connected, the
  776. cache is backed up by the server's disk....so we do nothing. if disconnected,
  777. we extend on the underlying shadow file by writing a zero in a good place and then
  778. reading back the allocation size.
  779. Arguments:
  780. RxContext - the RDBSS context
  781. Return Value:
  782. NTSTATUS - The return status for the operation
  783. Notes:
  784. --*/
  785. {
  786. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  787. RxCaptureFcb;
  788. RxCaptureFobx;
  789. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  790. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  791. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  792. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry
  793. = SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
  794. BOOLEAN Disconnected;
  795. ULONG Buffer = 0;
  796. ULONG LengthActuallyWritten;
  797. LARGE_INTEGER ByteOffset;
  798. PNT5CSC_MINIFILEOBJECT MiniFileObject = (PNT5CSC_MINIFILEOBJECT)(smbSrvOpen->hfShadow);
  799. IO_STATUS_BLOCK IoStatusBlock;
  800. ASSERT_MINIRDRFILEOBJECT(MiniFileObject);
  801. Disconnected = MRxSmbCSCIsDisconnectedOpen(capFcb, smbSrvOpen);
  802. if (!Disconnected) {
  803. return(Status);
  804. }
  805. RxDbgTrace(+1, Dbg,
  806. ("MRxSmbDCscExtendForCache(%08lx)...%08lx/%08lx @ %08lx on handle %08lx\n",
  807. RxContext,pNewFileSize->LowPart,
  808. pNewAllocationSize->LowPart,smbSrvOpen->hfShadow ));
  809. ByteOffset.QuadPart = pNewFileSize->QuadPart - 1;
  810. LengthActuallyWritten = Nt5CscReadWriteFileEx (
  811. R0_WRITEFILE,
  812. (CSCHFILE)MiniFileObject,
  813. ByteOffset.QuadPart,
  814. &Buffer,
  815. 1,
  816. 0,
  817. &IoStatusBlock
  818. );
  819. if (LengthActuallyWritten != 1) {
  820. Status = IoStatusBlock.Status;
  821. RxDbgTrace(0, Dbg,
  822. ("MRxSmbDCscExtendForCache(%08lx) write error... %08lx\n",RxContext,Status));
  823. goto FINALLY;
  824. }
  825. //MiniFileObject->StandardInfo.EndOfFile.LowPart = 0xfffffeee;
  826. Status = Nt5CscXxxInformation(
  827. (PCHAR)IRP_MJ_QUERY_INFORMATION,
  828. MiniFileObject,
  829. FileStandardInformation,
  830. sizeof(MiniFileObject->StandardInfo),
  831. &MiniFileObject->StandardInfo,
  832. &MiniFileObject->ReturnedLength
  833. );
  834. if (Status != STATUS_SUCCESS) {
  835. RxDbgTrace(0, Dbg,
  836. ("MRxSmbDCscExtendForCache(%08lx) qfi error... %08lx\n",RxContext,Status));
  837. goto FINALLY;
  838. }
  839. *pNewAllocationSize = MiniFileObject->StandardInfo.AllocationSize;
  840. FINALLY:
  841. RxDbgTrace(-1, Dbg,
  842. ("MRxSmbDCscExtendForCache(%08lx) exit...%08lx/%08lx @ %08lx, status %08lx\n",
  843. RxContext,pNewFileSize->LowPart,
  844. pNewAllocationSize->LowPart,smbSrvOpen->hfShadow ));
  845. return(Status);
  846. }
  847. NTSTATUS
  848. MRxSmbCscWriteDisconnected (
  849. IN OUT PRX_CONTEXT RxContext
  850. )
  851. /*++
  852. Routine Description:
  853. This routine just performs the correct write when we're disconnected. it
  854. calls the same routine for writing (ShadowWrite) as connected mode writes.
  855. ShadowWrite requires the filelength for its correct operation; in
  856. disconnected mode, we just get this out of the smb!
  857. Arguments:
  858. RxContext - the RDBSS context
  859. Return Value:
  860. NTSTATUS - The return status for the operation
  861. Notes:
  862. --*/
  863. {
  864. NTSTATUS Status = STATUS_SUCCESS;
  865. RxCaptureFcb;
  866. RxCaptureFobx;
  867. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  868. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  869. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  870. PFCB wrapperFcb = (PFCB)(capFcb);
  871. ULONGLONG ShadowFileLength;
  872. ULONG LengthActuallyWritten;
  873. ULONG ByteCount = RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount;
  874. ULONGLONG ByteOffset;
  875. BOOLEAN EnteredCriticalSection = FALSE;
  876. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  877. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry =
  878. SmbCeGetAssociatedNetRootEntry(NetRoot);
  879. #if defined(BITCOPY)
  880. ULONG * lpByteOffset;
  881. #endif // defined(BITCOPY)
  882. ByteOffset = RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset;
  883. IF_DEBUG {
  884. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry
  885. = SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
  886. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  887. BOOLEAN Disconnected;
  888. Disconnected = (BooleanFlagOn(
  889. smbSrvOpen->Flags,
  890. SMB_SRVOPEN_FLAG_DISCONNECTED_OPEN)||
  891. SmbCeIsServerInDisconnectedMode(pServerEntry));
  892. ASSERT(Disconnected);
  893. }
  894. IF_DEBUG {
  895. ASSERT_MINIRDRFILEOBJECT((PNT5CSC_MINIFILEOBJECT)(smbSrvOpen->hfShadow));
  896. RxDbgTrace(+1, Dbg,
  897. ("MRxSmbCscWriteDisconnected entry(%08lx)...%08lx bytes @ %08lx on handle %08lx\n",
  898. RxContext,ByteCount,
  899. (ULONG)ByteOffset,smbSrvOpen->hfShadow ));
  900. }
  901. // remember that modifications have happened
  902. // so that we can update the time stamp at close
  903. mSetBits(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_SHADOW_DATA_MODIFIED);
  904. CscEnterShadowReadWriteCrit(smbFcb);
  905. EnteredCriticalSection = TRUE;
  906. ShadowFileLength = wrapperFcb->Header.FileSize.QuadPart;
  907. Status = MRxSmbCscShadowWrite(
  908. RxContext,
  909. ByteCount,
  910. ShadowFileLength,
  911. &LengthActuallyWritten);
  912. RxContext->InformationToReturn = LengthActuallyWritten;
  913. #if defined(BITCOPY)
  914. // Mark the bitmap, if it exists
  915. lpByteOffset = (ULONG*)(LPVOID)&ByteOffset;
  916. if (Status == STATUS_SUCCESS) {
  917. CscBmpMark(smbFcb->lpDirtyBitmap,
  918. lpByteOffset[0],
  919. LengthActuallyWritten);
  920. }
  921. #endif // defined(BITCOPY)
  922. if (Status != STATUS_SUCCESS) {
  923. RxDbgTrace(0, Dbg,
  924. ("MRxSmbCscWriteDisconnected(%08lx) write error... %08lx %08lx %08lx\n",
  925. RxContext,Status,ByteCount,LengthActuallyWritten));
  926. goto FINALLY;
  927. }
  928. else
  929. {
  930. // note the fact that this replica is dirty and it's data would have to merged
  931. smbFcb->ShadowStatus |= SHADOW_DIRTY;
  932. // if the file has gotten extended, then notify the change
  933. if ((ByteOffset+LengthActuallyWritten) > ShadowFileLength)
  934. {
  935. FsRtlNotifyFullReportChange(
  936. pNetRootEntry->NetRoot.pNotifySync,
  937. &pNetRootEntry->NetRoot.DirNotifyList,
  938. (PSTRING)GET_ALREADY_PREFIXED_NAME(NULL,capFcb),
  939. (USHORT)(GET_ALREADY_PREFIXED_NAME(NULL, capFcb)->Length -
  940. smbFcb->MinimalCscSmbFcb.LastComponentLength),
  941. NULL,
  942. NULL,
  943. FILE_NOTIFY_CHANGE_SIZE,
  944. FILE_ACTION_MODIFIED,
  945. NULL);
  946. }
  947. }
  948. FINALLY:
  949. if (EnteredCriticalSection) {
  950. CscLeaveShadowReadWriteCrit(smbFcb);
  951. }
  952. RxDbgTrace(-1, Dbg, ("MRxSmbCscWriteDisconnected exit-> %08lx %08lx\n", RxContext, Status ));
  953. return Status;
  954. }
  955. #endif //ifdef MRXSMB_BUILD_FOR_CSC_DCON