Source code of Windows XP (NT5)
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.

1789 lines
64 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. write.c
  5. Abstract:
  6. This module implements the mini redirector call down routines pertaining
  7. to write of file system objects.
  8. Author:
  9. Joe Linn [JoeLinn] 7-March-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #pragma warning(error:4101) // Unreferenced local variable
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, MRxSmbWrite)
  17. #pragma alloc_text(PAGE, MRxSmbWriteMailSlot)
  18. #pragma alloc_text(PAGE, MRxSmbBuildWriteRequest)
  19. #pragma alloc_text(PAGE, SmbPseExchangeStart_Write)
  20. #pragma alloc_text(PAGE, MRxSmbFinishWrite)
  21. #endif
  22. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  23. //
  24. // The local debug trace level
  25. //
  26. #define Dbg (DEBUG_TRACE_WRITE)
  27. #ifndef FORCE_NO_NTWRITEANDX
  28. #define MRxSmbForceNoNtWriteAndX FALSE
  29. #else
  30. BOOLEAN MRxSmbForceNoNtWriteAndX = TRUE;
  31. #endif
  32. #define WRITE_COPY_THRESHOLD 64
  33. #define FORCECOPYMODE FALSE
  34. #ifdef SETFORCECOPYMODE
  35. #undef FORCECOPYMODE
  36. #define FORCECOPYMODE MRxSmbForceCopyMode
  37. ULONG MRxSmbForceCopyMode = TRUE;
  38. #endif
  39. extern ULONG MaxNumOfExchangesForPipelineReadWrite;
  40. NTSTATUS
  41. SmbPseExchangeStart_Write(
  42. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  43. );
  44. NTSTATUS
  45. MRxSmbFindNextSectionForReadWrite(
  46. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
  47. PULONG NumOfOutstandingExchanges
  48. );
  49. ULONG MRxSmbWriteSendOptions = 0;
  50. NTSTATUS
  51. MRxSmbDereferenceGlobalReadWrite (
  52. PSMB_PSE_OE_READWRITE GlobalReadWrite
  53. )
  54. {
  55. ULONG RefCount;
  56. RefCount = InterlockedDecrement(&GlobalReadWrite->RefCount);
  57. SmbCeLog(("Deref GRW %x %d\n",GlobalReadWrite,RefCount));
  58. if (RefCount == 0) {
  59. RxFreePool(GlobalReadWrite);
  60. }
  61. return STATUS_SUCCESS;
  62. }
  63. NTSTATUS
  64. MRxSmbWrite (
  65. IN PRX_CONTEXT RxContext)
  66. /*++
  67. Routine Description:
  68. This routine opens a file across the network.
  69. Arguments:
  70. RxContext - the RDBSS context
  71. Return Value:
  72. NTSTATUS - The return status for the operation
  73. --*/
  74. {
  75. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  76. RxCaptureFcb;
  77. RxCaptureFobx;
  78. PMRX_SRV_OPEN SrvOpen;
  79. PMRX_SMB_SRV_OPEN smbSrvOpen;
  80. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  81. SMBFCB_HOLDING_STATE SmbFcbHoldingState = SmbFcb_NotHeld;
  82. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  83. ULONG NumberOfSections;
  84. ULONG NumOfOutstandingExchanges = 0;
  85. ULONG MaximumBufferSizeThisIteration;
  86. PSMB_PSE_OE_READWRITE GlobalReadWrite = NULL;
  87. ULONG GlobalReadWriteAllocationSize;
  88. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
  89. BOOLEAN EnablePipelineWrite = TRUE;
  90. BOOLEAN MsgModePipeOperation = FALSE;
  91. BOOLEAN ExchangePending = FALSE;
  92. PAGED_CODE();
  93. RxDbgTrace(+1, Dbg, ("MRxSmbWrite\n", 0 ));
  94. // Pipe buffer cannot be bigger than MAX_PIPE_BUFFER_SIZE, otherwise the
  95. // server has problems.
  96. if (RxContext->pFcb->pNetRoot->Type == NET_ROOT_PIPE) {
  97. if (RxContext->CurrentIrpSp->Parameters.Write.Length > MAX_PIPE_BUFFER_SIZE) {
  98. return STATUS_INVALID_BUFFER_SIZE;
  99. }
  100. }
  101. if ( NodeType(capFcb) == RDBSS_NTC_MAILSLOT ) {
  102. // This is an attempt to write on a mailslot file which is handled
  103. // differently.
  104. Status = MRxSmbWriteMailSlot(RxContext);
  105. RxDbgTrace(-1, Dbg, ("MRxSmbWrite: Mailslot write returned %lx\n",Status));
  106. return Status;
  107. }
  108. // For CSC we go ahead and mark an FCB as having been written to.
  109. // When CSC is turned ON, if this flag is set before we obtained
  110. // shadow handles, then the data corresponding to the file is
  111. // deemed stale and is truncated
  112. if (NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE) {
  113. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  114. smbFcb->MFlags |= SMB_FCB_FLAG_WRITES_PERFORMED;
  115. }
  116. ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
  117. SrvOpen = capFobx->pSrvOpen;
  118. smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  119. pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
  120. if (smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_II &&
  121. !BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
  122. LOWIO_READWRITEFLAG_PAGING_IO)) {
  123. PMRX_SRV_CALL pSrvCall;
  124. pSrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  125. RxIndicateChangeOfBufferingStateForSrvOpen(
  126. pSrvCall,
  127. SrvOpen,
  128. MRxSmbMakeSrvOpenKey(pVNetRootContext->TreeId,smbSrvOpen->Fid),
  129. ULongToPtr(SMB_OPLOCK_LEVEL_NONE));
  130. SmbCeLog(("Breaking oplock to None in Write SO %lx\n",SrvOpen));
  131. SmbLog(LOG,
  132. MRxSmbWrite,
  133. LOGPTR(SrvOpen));
  134. }
  135. IF_NOT_MRXSMB_CSC_ENABLED{
  136. ASSERT(smbSrvOpen->hfShadow == 0);
  137. } else {
  138. if (smbSrvOpen->hfShadow != 0){
  139. NTSTATUS ShadowReadNtStatus;
  140. ShadowReadNtStatus = MRxSmbCscWritePrologue(
  141. RxContext,
  142. &SmbFcbHoldingState);
  143. if (ShadowReadNtStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  144. RxDbgTrace(-1, Dbg, ("MRxSmbWrite shadow hit with status=%08lx\n", ShadowReadNtStatus ));
  145. return(ShadowReadNtStatus);
  146. } else {
  147. RxDbgTrace(0, Dbg, ("MRxSmbWrite shadowmiss with status=%08lx\n", ShadowReadNtStatus ));
  148. }
  149. }
  150. }
  151. if (capFcb->pNetRoot->Type == NET_ROOT_PIPE) {
  152. EnablePipelineWrite = FALSE;
  153. if (capFobx->PipeHandleInformation->ReadMode != FILE_PIPE_BYTE_STREAM_MODE) {
  154. MsgModePipeOperation = TRUE;
  155. }
  156. }
  157. if (!FlagOn(pVNetRootContext->pServerEntry->Server.DialectFlags,DF_LARGE_WRITEX)) {
  158. EnablePipelineWrite = FALSE;
  159. }
  160. MaximumBufferSizeThisIteration = pVNetRootContext->pNetRootEntry->NetRoot.MaximumWriteBufferSize;
  161. if (MsgModePipeOperation) {
  162. MaximumBufferSizeThisIteration -= 2;
  163. }
  164. NumberOfSections = LowIoContext->ParamsFor.ReadWrite.ByteCount / MaximumBufferSizeThisIteration;
  165. if ( (LowIoContext->ParamsFor.ReadWrite.ByteCount % MaximumBufferSizeThisIteration) ||
  166. (LowIoContext->ParamsFor.ReadWrite.ByteCount == 0) ) {
  167. NumberOfSections ++;
  168. }
  169. GlobalReadWriteAllocationSize = sizeof(SMB_PSE_OE_READWRITE) +
  170. NumberOfSections*sizeof(SMB_PSE_OE_READWRITE_STATE);
  171. GlobalReadWrite = RxAllocatePoolWithTag(
  172. NonPagedPool,
  173. GlobalReadWriteAllocationSize,
  174. MRXSMB_RW_POOLTAG);
  175. if (GlobalReadWrite == NULL) {
  176. return STATUS_INSUFFICIENT_RESOURCES;
  177. }
  178. RtlZeroMemory(GlobalReadWrite,GlobalReadWriteAllocationSize);
  179. GlobalReadWrite->MaximumBufferSize = MaximumBufferSizeThisIteration;
  180. GlobalReadWrite->TotalNumOfSections = NumberOfSections;
  181. KeInitializeEvent(
  182. &GlobalReadWrite->CompletionEvent,
  183. SynchronizationEvent,
  184. FALSE);
  185. GlobalReadWrite->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
  186. GlobalReadWrite->ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  187. GlobalReadWrite->RemainingByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  188. if (GlobalReadWrite->ByteOffsetAsLI.QuadPart == -1 ) {
  189. GlobalReadWrite->WriteToTheEnd = TRUE;
  190. GlobalReadWrite->ByteOffsetAsLI.QuadPart = smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart;
  191. }
  192. if (LowIoContext->ParamsFor.ReadWrite.Buffer != NULL) {
  193. GlobalReadWrite->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
  194. } else {
  195. GlobalReadWrite->UserBufferBase = (PBYTE)1; //any nonzero value will do
  196. }
  197. if (MRxSmbEnableCompression &&
  198. (capFcb->Attributes & FILE_ATTRIBUTE_COMPRESSED) &&
  199. (pVNetRootContext->pServerEntry->Server.Capabilities & COMPRESSED_DATA_CAPABILITY)) {
  200. GlobalReadWrite->CompressedReadOrWrite = TRUE;
  201. EnablePipelineWrite = FALSE;
  202. } else {
  203. GlobalReadWrite->CompressedReadOrWrite = FALSE;
  204. }
  205. GlobalReadWrite->ThisBufferOffset = 0;
  206. GlobalReadWrite->PartialExchangeMdlInUse = FALSE;
  207. GlobalReadWrite->PartialDataMdlInUse = FALSE;
  208. GlobalReadWrite->pCompressedDataBuffer = NULL;
  209. GlobalReadWrite->RefCount = 1;
  210. GlobalReadWrite->SmbFcbHoldingState = SmbFcbHoldingState;
  211. do {
  212. Status = SmbPseCreateOrdinaryExchange(
  213. RxContext,
  214. capFobx->pSrvOpen->pVNetRoot,
  215. SMBPSE_OE_FROM_WRITE,
  216. SmbPseExchangeStart_Write,
  217. &OrdinaryExchange);
  218. if (Status != STATUS_SUCCESS) {
  219. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  220. break;
  221. }
  222. OrdinaryExchange->AsyncResumptionRoutine = SmbPseExchangeStart_Write;
  223. OrdinaryExchange->GlobalReadWrite = GlobalReadWrite;
  224. RtlCopyMemory(&OrdinaryExchange->ReadWrite,
  225. GlobalReadWrite,
  226. sizeof(SMB_PSE_OE_READWRITE));
  227. if ((capFcb->pNetRoot->Type == NET_ROOT_PIPE) &&
  228. (capFobx->PipeHandleInformation->ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ) {
  229. SetFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_MSGMODE_PIPE_OPERATION);
  230. }
  231. ExAcquireFastMutex(&MRxSmbReadWriteMutex);
  232. Status = MRxSmbFindNextSectionForReadWrite(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  233. &NumOfOutstandingExchanges);
  234. ExReleaseFastMutex(&MRxSmbReadWriteMutex);
  235. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  236. ULONG RefCount;
  237. RefCount = InterlockedIncrement(&GlobalReadWrite->RefCount);
  238. SmbCeLog(("Ref GRW %x %d\n",GlobalReadWrite,RefCount));
  239. SmbCeLog(("Pipeline Write %x %d %d\n",OrdinaryExchange,NumberOfSections,NumOfOutstandingExchanges));
  240. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  241. NumberOfSections --;
  242. if ( Status != RX_MAP_STATUS(PENDING) ) {
  243. ExAcquireFastMutex(&MRxSmbReadWriteMutex);
  244. if (Status != STATUS_SUCCESS) {
  245. NumberOfSections ++;
  246. GlobalReadWrite->SectionState[OrdinaryExchange->ReadWrite.CurrentSection] = SmbPseOEReadWriteIoStates_Initial;
  247. SmbCeLog(("Section undo %d\n",OrdinaryExchange->ReadWrite.CurrentSection));
  248. }
  249. if (!OrdinaryExchange->ReadWrite.ReadWriteFinalized) {
  250. MRxSmbDereferenceGlobalReadWrite(GlobalReadWrite);
  251. NumOfOutstandingExchanges = InterlockedDecrement(&GlobalReadWrite->NumOfOutstandingOperations);
  252. } else {
  253. NumOfOutstandingExchanges --;
  254. }
  255. if ((Status == STATUS_TOO_MANY_COMMANDS) && (NumOfOutstandingExchanges > 0)) {
  256. Status = STATUS_SUCCESS;
  257. }
  258. if ((Status != STATUS_SUCCESS) &&
  259. (GlobalReadWrite->CompletionStatus == STATUS_SUCCESS)) {
  260. GlobalReadWrite->CompletionStatus = Status;
  261. }
  262. ExReleaseFastMutex(&MRxSmbReadWriteMutex);
  263. SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  264. }
  265. else {
  266. ExchangePending = TRUE;
  267. }
  268. if (NumOfOutstandingExchanges >= MaxNumOfExchangesForPipelineReadWrite) {
  269. break;
  270. }
  271. } else {
  272. SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  273. Status = STATUS_PENDING;
  274. break;
  275. }
  276. } while ((Status == STATUS_RETRY) ||
  277. EnablePipelineWrite &&
  278. (NumberOfSections > 0) &&
  279. (Status == STATUS_PENDING));
  280. SmbCeLog(("Pipeline Write out %x %d\n",Status,NumberOfSections));
  281. if (!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  282. if (ExchangePending) {
  283. KeWaitForSingleObject(
  284. &GlobalReadWrite->CompletionEvent,
  285. Executive,
  286. KernelMode,
  287. FALSE,
  288. NULL );
  289. Status = GlobalReadWrite->CompletionStatus;
  290. }
  291. if (SmbFcbHoldingState != SmbFcb_NotHeld) {
  292. MRxSmbCscReleaseSmbFcb(
  293. RxContext,
  294. &SmbFcbHoldingState);
  295. }
  296. } else {
  297. if (ExchangePending) {
  298. Status = STATUS_PENDING;
  299. }
  300. }
  301. MRxSmbDereferenceGlobalReadWrite(GlobalReadWrite);
  302. RxDbgTrace(-1, Dbg, ("MRxSmbWrite exit with status=%08lx\n", Status ));
  303. return(Status);
  304. } // MRxSmbWrite
  305. NTSTATUS
  306. MRxSmbWriteMailSlot(
  307. PRX_CONTEXT RxContext
  308. )
  309. /*++
  310. Routine Description:
  311. This routine processes a write smb for a mail slot.
  312. Arguments:
  313. RxContext - the RDBSS context
  314. Return Value:
  315. NTSTATUS - The return status for the operation
  316. --*/
  317. {
  318. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  319. RxCaptureFcb;
  320. RxCaptureFobx;
  321. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  322. UNICODE_STRING TransactionName;
  323. UNICODE_STRING MailSlotName;
  324. PUNICODE_STRING FcbName = &(((PFCB)(capFcb))->FcbTableEntry.Path);
  325. PUNICODE_STRING AlreadyPrefixedName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  326. PAGED_CODE();
  327. if (AlreadyPrefixedName->Length > sizeof(WCHAR)) {
  328. MailSlotName.Length = AlreadyPrefixedName->Length - sizeof(WCHAR);
  329. } else {
  330. MailSlotName.Length = 0;
  331. }
  332. MailSlotName.MaximumLength = MailSlotName.Length;
  333. MailSlotName.Buffer = AlreadyPrefixedName->Buffer + 1;
  334. TransactionName.Length = (USHORT)(s_MailSlotTransactionName.Length +
  335. MailSlotName.Length);
  336. TransactionName.MaximumLength = TransactionName.Length;
  337. TransactionName.Buffer = (PWCHAR)RxAllocatePoolWithTag(
  338. PagedPool,
  339. TransactionName.Length,
  340. MRXSMB_MAILSLOT_POOLTAG);
  341. if (TransactionName.Buffer != NULL) {
  342. USHORT Setup[3]; // Setup params for mailslot write transaction
  343. USHORT OutputParam;
  344. PBYTE pInputDataBuffer = NULL;
  345. PBYTE pOutputDataBuffer = NULL;
  346. ULONG InputDataBufferLength = 0;
  347. ULONG OutputDataBufferLength = 0;
  348. SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
  349. SMB_TRANSACTION_OPTIONS TransactionOptions;
  350. TransactionOptions = RxDefaultTransactionOptions;
  351. pInputDataBuffer = RxLowIoGetBufferAddress( RxContext );
  352. InputDataBufferLength= pLowIoContext->ParamsFor.ReadWrite.ByteCount;
  353. RtlCopyMemory(
  354. TransactionName.Buffer,
  355. s_MailSlotTransactionName.Buffer,
  356. s_MailSlotTransactionName.Length );
  357. RtlCopyMemory(
  358. (PBYTE)TransactionName.Buffer +
  359. s_MailSlotTransactionName.Length,
  360. MailSlotName.Buffer,
  361. MailSlotName.Length );
  362. RxDbgTrace(0, Dbg, ("MRxSmbWriteMailSlot: Mailslot transaction name %wZ\n",&TransactionName));
  363. Setup[0] = TRANS_MAILSLOT_WRITE;
  364. Setup[1] = 0; // Priority of write
  365. Setup[2] = 2; // Unreliable request (Second class mailslot)
  366. TransactionOptions.NtTransactFunction = 0; // TRANSACT2/TRANSACT.
  367. TransactionOptions.pTransactionName = &TransactionName;
  368. TransactionOptions.Flags = (SMB_TRANSACTION_NO_RESPONSE |
  369. SMB_XACT_FLAGS_FID_NOT_NEEDED |
  370. SMB_XACT_FLAGS_MAILSLOT_OPERATION);
  371. TransactionOptions.TimeoutIntervalInMilliSeconds =
  372. SMBCE_TRANSACTION_TIMEOUT_NOT_USED;
  373. Status = SmbCeTransact(
  374. RxContext, // RXContext for transaction
  375. &TransactionOptions, // transaction options
  376. Setup, // the setup buffer
  377. sizeof(Setup), // setup buffer length
  378. NULL, // the output setup buffer
  379. 0, // output setup buffer length
  380. NULL, // Input Param Buffer
  381. 0, // Input param buffer length
  382. &OutputParam, // Output param buffer
  383. sizeof(OutputParam), // output param buffer length
  384. pInputDataBuffer, // Input data buffer
  385. InputDataBufferLength, // Input data buffer length
  386. NULL, // output data buffer
  387. 0, // output data buffer length
  388. &ResumptionContext // the resumption context
  389. );
  390. if ( RX_MAP_STATUS(SUCCESS) == Status ) {
  391. RxContext->InformationToReturn += InputDataBufferLength;
  392. }
  393. RxFreePool( TransactionName.Buffer );
  394. } else {
  395. Status = STATUS_INSUFFICIENT_RESOURCES;
  396. }
  397. RxDbgTrace( 0, Dbg, ("MRxSmbMailSlotWrite: ...returning %lx\n",Status));
  398. return Status;
  399. } // MRxSmbWriteMailSlot
  400. NTSTATUS
  401. MRxSmbPrepareCompressedWriteRequest(
  402. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  403. PBYTE *pWriteDataBufferPointer,
  404. PMDL *pWriteDataMdlPointer)
  405. /*++
  406. Routine Description:
  407. This routine prepares the buffers for a compressed write request
  408. Arguments:
  409. pExchange - the exchange instance
  410. Return Value:
  411. NTSTATUS - The return status for the operation
  412. Notes:
  413. The write requests issued to an uplevel server for a file which is stored in
  414. a compressed fashion on the server can be classified into two categories ..
  415. 1) ALIGNED WRITE REQUESTS
  416. These requests begin at an offset in the file which is an integral
  417. multiple of the compression chunk size. If the write length is either
  418. an integral multiple of the number of chunks or the write is at the
  419. end of the file then the data can be sent as a compressed write request.
  420. 2) UNALIGNED WRITE REQUESTS
  421. These requests begin at offsets which are not an integral multiple of
  422. the compression chunk size.
  423. Any Write request submitted by the user can be decomposed into atmost two
  424. UNALIGNED WRITE REQUESTS and 0 or more ALIGNED WRITE REQUESTS.
  425. The RDR adopts a strategy of sending atmst 64K of compressed data alongwith
  426. the COMPRESSED_DATA_INFO structure in a single write request to the server.
  427. In the worst case this will involving writing the request 64k at a time
  428. ( no compression possible in the given data ) and in the best case we will
  429. be able to write using a single request.
  430. In addition to the write buffer supplied by the user we require two more
  431. buffers to complete the write request using compressed data. The first
  432. buffer is for holding the COMPRESSED_DATA_INFO structure and the second
  433. buffer is for holding the compressed data. The buffer associated with the
  434. exchange is used to hold the CDI while a separate buffer is allocated to store
  435. the compressed data. The two MDL's allocated as part of the
  436. SMB_PSE_OE_READWRITE is used as the MDLs for the compressed data buffer and
  437. the COMPRESSED_DATA_INFO structure
  438. --*/
  439. {
  440. #define COMPRESSED_DATA_BUFFER_SIZE (0x10000)
  441. NTSTATUS Status = STATUS_SUCCESS;
  442. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  443. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  444. PSMBCE_NET_ROOT pNetRoot;
  445. PCOMPRESSED_DATA_INFO pCompressedDataInfo;
  446. PUCHAR pWriteDataBuffer;
  447. ULONG WriteDataBufferLength,CompressedDataInfoLength;
  448. ULONG CompressedDataLength;
  449. USHORT NumberOfChunks;
  450. *pWriteDataBufferPointer = NULL;
  451. *pWriteDataMdlPointer = NULL;
  452. pWriteDataBuffer = rw->UserBufferBase + rw->ThisBufferOffset;
  453. pNetRoot = SmbCeGetExchangeNetRoot((PSMB_EXCHANGE)OrdinaryExchange);
  454. rw->CompressedRequestInProgress = FALSE;
  455. if (rw->RemainingByteCount < (2 * pNetRoot->ChunkSize)) {
  456. WriteDataBufferLength = rw->RemainingByteCount;
  457. } else if (rw->ByteOffsetAsLI.LowPart & (pNetRoot->ChunkSize - 1)) {
  458. // The Write request is not aligned at a chunk size. Send the unaligned
  459. // portion as an uncompressed write request
  460. WriteDataBufferLength = pNetRoot->ChunkSize -
  461. (
  462. rw->ByteOffsetAsLI.LowPart &
  463. (pNetRoot->ChunkSize - 1)
  464. );
  465. } else {
  466. PUCHAR pCompressedDataBuffer,pWorkSpaceBuffer;
  467. ULONG WorkSpaceBufferSize,WorkSpaceFragmentSize;
  468. if (rw->pCompressedDataBuffer == NULL) {
  469. rw->pCompressedDataBuffer = RxAllocatePoolWithTag(
  470. NonPagedPool,
  471. COMPRESSED_DATA_BUFFER_SIZE,
  472. MRXSMB_RW_POOLTAG);
  473. if (rw->pCompressedDataBuffer == NULL) {
  474. Status = STATUS_INSUFFICIENT_RESOURCES;
  475. }
  476. }
  477. pCompressedDataBuffer = rw->pCompressedDataBuffer;
  478. if (Status == STATUS_SUCCESS) {
  479. Status = RtlGetCompressionWorkSpaceSize(
  480. COMPRESSION_FORMAT_LZNT1,
  481. &WorkSpaceBufferSize,
  482. &WorkSpaceFragmentSize );
  483. if (Status == STATUS_SUCCESS) {
  484. pWorkSpaceBuffer = RxAllocatePoolWithTag(
  485. PagedPool,
  486. WorkSpaceBufferSize,
  487. MRXSMB_RW_POOLTAG);
  488. if (pWorkSpaceBuffer == NULL) {
  489. Status = STATUS_INSUFFICIENT_RESOURCES;
  490. }
  491. }
  492. }
  493. if (Status == STATUS_SUCCESS) {
  494. COMPRESSED_DATA_INFO CompressedChunkInfo;
  495. USHORT MaximumNumberOfChunks;
  496. ULONG CompressedChunkInfoLength;
  497. ULONG RequestByteCount;
  498. RequestByteCount = rw->RemainingByteCount -
  499. (rw->RemainingByteCount & (pNetRoot->ChunkSize - 1));
  500. CompressedChunkInfoLength = sizeof(CompressedChunkInfo);
  501. pCompressedDataInfo = (PCOMPRESSED_DATA_INFO)
  502. ROUND_UP_POINTER(
  503. (StufferState->BufferBase +
  504. sizeof(SMB_HEADER) +
  505. FIELD_OFFSET(REQ_NT_WRITE_ANDX,Buffer)),
  506. ALIGN_QUAD);
  507. CompressedDataInfoLength = (ULONG)(StufferState->BufferLimit -
  508. (PBYTE)pCompressedDataInfo);
  509. MaximumNumberOfChunks = (USHORT)(
  510. (CompressedDataInfoLength -
  511. FIELD_OFFSET(
  512. COMPRESSED_DATA_INFO,
  513. CompressedChunkSizes)) /
  514. sizeof(ULONG));
  515. if ((RequestByteCount / pNetRoot->ChunkSize) < MaximumNumberOfChunks) {
  516. MaximumNumberOfChunks = (USHORT)(RequestByteCount /
  517. pNetRoot->ChunkSize);
  518. }
  519. pCompressedDataInfo->CompressionFormatAndEngine =
  520. pNetRoot->CompressionFormatAndEngine;
  521. pCompressedDataInfo->ChunkShift =
  522. pNetRoot->ChunkShift;
  523. pCompressedDataInfo->CompressionUnitShift =
  524. pNetRoot->CompressionUnitShift;
  525. pCompressedDataInfo->ClusterShift =
  526. pNetRoot->ClusterShift;
  527. RtlCopyMemory(
  528. &CompressedChunkInfo,
  529. pCompressedDataInfo,
  530. FIELD_OFFSET(
  531. COMPRESSED_DATA_INFO,
  532. NumberOfChunks)
  533. );
  534. NumberOfChunks = 0;
  535. CompressedDataLength = 0;
  536. for (;;) {
  537. if ((COMPRESSED_DATA_BUFFER_SIZE - CompressedDataLength) <
  538. pNetRoot->ChunkSize) {
  539. if (CompressedDataLength == 0) {
  540. Status = STATUS_SMB_USE_STANDARD;
  541. }
  542. break;
  543. }
  544. Status = RtlCompressChunks(
  545. pWriteDataBuffer,
  546. pNetRoot->ChunkSize,
  547. pCompressedDataBuffer,
  548. (COMPRESSED_DATA_BUFFER_SIZE - CompressedDataLength),
  549. &CompressedChunkInfo,
  550. CompressedChunkInfoLength,
  551. pWorkSpaceBuffer);
  552. if (Status != STATUS_SUCCESS) {
  553. break;
  554. }
  555. pCompressedDataBuffer += CompressedChunkInfo.CompressedChunkSizes[0];
  556. CompressedDataLength += CompressedChunkInfo.CompressedChunkSizes[0];
  557. pCompressedDataInfo->CompressedChunkSizes[NumberOfChunks] =
  558. CompressedChunkInfo.CompressedChunkSizes[0];
  559. pWriteDataBuffer += pNetRoot->ChunkSize;
  560. if (++NumberOfChunks >= MaximumNumberOfChunks) {
  561. break;
  562. }
  563. }
  564. if (Status != STATUS_SUCCESS) {
  565. if (CompressedDataLength > 0) {
  566. Status = STATUS_SUCCESS;
  567. }
  568. }
  569. if (Status == STATUS_SUCCESS) {
  570. rw->CompressedRequestInProgress = TRUE;
  571. pWriteDataBuffer = rw->pCompressedDataBuffer;
  572. WriteDataBufferLength = CompressedDataLength;
  573. } else if (Status != STATUS_BUFFER_TOO_SMALL) {
  574. DbgPrint("Failure compressing data -- Status %lx, Switching over to uncompressed\n",Status);
  575. }
  576. if (pWorkSpaceBuffer != NULL) {
  577. RxFreePool(
  578. pWorkSpaceBuffer);
  579. }
  580. } else {
  581. Status = STATUS_INSUFFICIENT_RESOURCES;
  582. }
  583. }
  584. if (Status == STATUS_SUCCESS) {
  585. rw->PartialDataMdlInUse = TRUE;
  586. MmInitializeMdl(
  587. &rw->PartialDataMdl,
  588. pWriteDataBuffer,
  589. WriteDataBufferLength);
  590. MmBuildMdlForNonPagedPool( &rw->PartialDataMdl );
  591. if (rw->CompressedRequestInProgress) {
  592. rw->CompressedDataInfoLength = FIELD_OFFSET(
  593. COMPRESSED_DATA_INFO,
  594. CompressedChunkSizes) +
  595. NumberOfChunks * sizeof(ULONG);
  596. pCompressedDataInfo->NumberOfChunks = NumberOfChunks;
  597. rw->PartialExchangeMdlInUse = TRUE;
  598. MmInitializeMdl(
  599. &rw->PartialExchangeMdl,
  600. pCompressedDataInfo,
  601. rw->CompressedDataInfoLength);
  602. MmBuildMdlForNonPagedPool( &rw->PartialExchangeMdl );
  603. rw->ThisByteCount = pCompressedDataInfo->NumberOfChunks *
  604. pNetRoot->ChunkSize;
  605. rw->PartialExchangeMdl.Next = &rw->PartialDataMdl;
  606. *pWriteDataMdlPointer = &rw->PartialExchangeMdl;
  607. } else {
  608. rw->ThisByteCount = WriteDataBufferLength;
  609. *pWriteDataMdlPointer = &rw->PartialDataMdl;
  610. }
  611. } else {
  612. // If for whatever reason the compression fails switch over to an
  613. // uncompressed write mode.
  614. rw->CompressedReadOrWrite = FALSE;
  615. }
  616. ASSERT(
  617. !rw->CompressedReadOrWrite ||
  618. ((*pWriteDataMdlPointer != NULL) && (*pWriteDataBufferPointer == NULL)));
  619. return Status;
  620. }
  621. NTSTATUS
  622. MRxSmbBuildWriteRequest(
  623. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  624. BOOLEAN IsPagingIo,
  625. UCHAR WriteCommand,
  626. ULONG ByteCount,
  627. PLARGE_INTEGER ByteOffsetAsLI,
  628. PBYTE Buffer,
  629. PMDL BufferAsMdl)
  630. /*++
  631. Routine Description:
  632. This is the start routine for write.
  633. Arguments:
  634. pExchange - the exchange instance
  635. Return Value:
  636. NTSTATUS - The return status for the operation
  637. --*/
  638. {
  639. NTSTATUS Status;
  640. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  641. PSMB_PSE_OE_READWRITE GlobalReadWrite = OrdinaryExchange->GlobalReadWrite;
  642. PRX_CONTEXT RxContext = StufferState->RxContext;
  643. RxCaptureFcb;
  644. RxCaptureFobx;
  645. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  646. PNT_SMB_HEADER NtSmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
  647. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  648. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  649. ULONG OffsetLow,OffsetHigh;
  650. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  651. USHORT WriteMode = 0;
  652. ULONG DataLengthLow,DataLengthHigh;
  653. ULONG BytesRemaining = 0;
  654. BOOLEAN AddLengthBytes = FALSE;
  655. ULONG WriteCommandSize;
  656. PSMBCE_SERVER pServer = SmbCeGetExchangeServer((PSMB_EXCHANGE)OrdinaryExchange);
  657. BOOLEAN UseNtVersion;
  658. UseNtVersion = BooleanFlagOn(pServer->DialectFlags,DF_NT_SMBS) &&
  659. !MRxSmbForceNoNtWriteAndX;
  660. // The data length field in SMB is a USHORT, and hence the data length given
  661. // needs to be split up into two parts -- DataLengthHigh and DataLengthLow
  662. DataLengthLow = (ByteCount & 0xffff);
  663. DataLengthHigh = ((ByteCount & 0xffff0000) >> 16);
  664. OffsetLow = ByteOffsetAsLI->LowPart;
  665. OffsetHigh = ByteOffsetAsLI->HighPart;
  666. switch (WriteCommand) {
  667. case SMB_COM_WRITE_ANDX:
  668. WriteCommandSize = SMB_REQUEST_SIZE(NT_WRITE_ANDX);
  669. break;
  670. case SMB_COM_WRITE:
  671. WriteCommandSize = SMB_REQUEST_SIZE(WRITE);
  672. break;
  673. case SMB_COM_WRITE_PRINT_FILE:
  674. WriteCommandSize = SMB_REQUEST_SIZE(WRITE_PRINT_FILE);
  675. break;
  676. }
  677. Status = MRxSmbStartSMBCommand(
  678. StufferState,
  679. SetInitialSMB_Never,
  680. WriteCommand,
  681. WriteCommandSize,
  682. NO_EXTRA_DATA,
  683. NO_SPECIAL_ALIGNMENT,
  684. RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  685. 0,0,0,0 STUFFERTRACE(Dbg,'FC'));
  686. MRxSmbDumpStufferState(
  687. 1000,
  688. "SMB Write Request before stuffing",
  689. StufferState);
  690. switch (WriteCommand) {
  691. case SMB_COM_WRITE_ANDX :
  692. {
  693. if ( UseNtVersion && IsPagingIo ) {
  694. SmbPutAlignedUshort(
  695. &NtSmbHeader->Flags2,
  696. SmbGetAlignedUshort(&NtSmbHeader->Flags2)|SMB_FLAGS2_PAGING_IO );
  697. }
  698. // set the writemode correctly....mainly multismb pipe stuff but also
  699. // writethru for diskfiles
  700. if (FlagOn(
  701. OrdinaryExchange->OpSpecificFlags,
  702. OE_RW_FLAG_MSGMODE_PIPE_OPERATION) ) {
  703. //DOWNLEVEL pinball has wants a different value here....see rdr1.
  704. // We need to use the GlobalReadWrite structure here because the local one
  705. // will always have RemainingByteCount == write length. Note that pipe writes
  706. // will be broken if we do not disable pipeline writes on them..
  707. BytesRemaining = GlobalReadWrite->RemainingByteCount;
  708. // If this write takes more than one Smb then we must set WRITE_RAW.
  709. // The first Smb of the series must have START_OF_MESSAGE.
  710. if (!FlagOn(
  711. OrdinaryExchange->OpSpecificFlags,
  712. OE_RW_FLAG_SUBSEQUENT_OPERATION) ) {
  713. if ( rw->ThisByteCount < BytesRemaining ) {
  714. // First Smb in a multi SMB write.
  715. // Add a USHORT at the start of data saying how large the
  716. // write is.
  717. AddLengthBytes = TRUE;
  718. DataLengthLow += sizeof(USHORT);
  719. ASSERT(DataLengthHigh == 0);
  720. SetFlag(
  721. OrdinaryExchange->OpSpecificFlags,
  722. OE_RW_FLAG_REDUCE_RETURNCOUNT);
  723. // Tell the server that the data has the length at the start.
  724. WriteMode |= (SMB_WMODE_WRITE_RAW_NAMED_PIPE |
  725. SMB_WMODE_START_OF_MESSAGE);
  726. } else {
  727. // All fits in one Smb
  728. WriteMode |= SMB_WMODE_START_OF_MESSAGE;
  729. }
  730. } else {
  731. // any subsequent pipewrites are obviously raw and not the first
  732. WriteMode |= SMB_WMODE_WRITE_RAW_NAMED_PIPE;
  733. }
  734. } else {
  735. // If the data is to be written in a compressed fashion turn on
  736. // the compressed data bit in the header
  737. if ((rw->CompressedReadOrWrite) &&
  738. (rw->CompressedDataInfoLength > 0)) {
  739. ASSERT(UseNtVersion);
  740. SmbPutAlignedUshort(
  741. &NtSmbHeader->Flags2,
  742. SmbGetAlignedUshort(&NtSmbHeader->Flags2) | SMB_FLAGS2_COMPRESSED );
  743. // The Remaining field in NT_WRITE_ANDX also doubles as the field
  744. // in which the CDI length is sent to the server
  745. BytesRemaining = rw->CompressedDataInfoLength;
  746. }
  747. //
  748. // If the file object was opened in write through mode, set write
  749. // through on the write operation.
  750. if (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WRITE_THROUGH)) {
  751. WriteMode |= SMB_WMODE_WRITE_THROUGH;
  752. }
  753. }
  754. MRxSmbStuffSMB (
  755. StufferState,
  756. "XwddwwwwQ",
  757. // X UCHAR WordCount;
  758. // UCHAR AndXCommand;
  759. // UCHAR AndXReserved;
  760. // _USHORT( AndXOffset );
  761. smbSrvOpen->Fid, // w _USHORT( Fid );
  762. OffsetLow, // d _ULONG( Offset );
  763. -1, // d _ULONG( Timeout );
  764. WriteMode, // w _USHORT( WriteMode );
  765. BytesRemaining, // w _USHORT( Remaining );
  766. DataLengthHigh, // w _USHORT( DataLengthHigh );
  767. DataLengthLow, // w _USHORT( DataLength );
  768. // Q _USHORT( DataOffset );
  769. SMB_OFFSET_CHECK(WRITE_ANDX,DataOffset)
  770. StufferCondition(UseNtVersion), "D",
  771. SMB_OFFSET_CHECK(NT_WRITE_ANDX,OffsetHigh)
  772. OffsetHigh, // D NTonly _ULONG( OffsetHigh );
  773. //
  774. STUFFER_CTL_NORMAL, "BS5",
  775. // B _USHORT( ByteCount );
  776. SMB_WCT_CHECK(((UseNtVersion)?14:12))
  777. // UCHAR Buffer[1];
  778. // S //UCHAR Pad[];
  779. // 5 //UCHAR Data[];
  780. StufferCondition(AddLengthBytes), "w", LowIoContext->ParamsFor.ReadWrite.ByteCount,
  781. StufferCondition(Buffer!=NULL), "c!",
  782. ByteCount,
  783. Buffer, // c the actual data
  784. 0
  785. );
  786. }
  787. break;
  788. case SMB_COM_WRITE :
  789. {
  790. MRxSmbStuffSMB (
  791. StufferState,
  792. "0wwdwByw",
  793. // 0 UCHAR WordCount; // Count of parameter words = 5
  794. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  795. DataLengthLow, // w _USHORT( Count ); // Number of bytes to be written
  796. OffsetLow, // d _ULONG( Offset ); // Offset in file to begin write
  797. BytesRemaining, // w _USHORT( Remaining ); // Bytes remaining to satisfy request
  798. SMB_WCT_CHECK(5) // B _USHORT( ByteCount ); // Count of data bytes
  799. // //UCHAR Buffer[1]; // Buffer containing:
  800. 0x01, // y UCHAR BufferFormat; // 0x01 -- Data block
  801. DataLengthLow, // w _USHORT( DataLength ); // Length of data
  802. // ULONG Buffer[1]; // Data
  803. StufferCondition(Buffer!=NULL), "c!",
  804. ByteCount,
  805. Buffer, // c the actual data
  806. 0
  807. );
  808. }
  809. break;
  810. case SMB_COM_WRITE_PRINT_FILE:
  811. {
  812. MRxSmbStuffSMB (
  813. StufferState,
  814. "0wByw",
  815. // 0 UCHAR WordCount; // Count of parameter words = 1
  816. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  817. SMB_WCT_CHECK(1) // B _USHORT( ByteCount ); // Count of data bytes; min = 4
  818. // UCHAR Buffer[1]; // Buffer containing:
  819. 0x01, // y //UCHAR BufferFormat; // 0x01 -- Data block
  820. DataLengthLow, // w //USHORT DataLength; // Length of data
  821. // //UCHAR Data[]; // Data
  822. StufferCondition(Buffer!=NULL), "c!",
  823. ByteCount,
  824. Buffer, // c the actual data
  825. 0
  826. );
  827. }
  828. break;
  829. default:
  830. Status = STATUS_UNSUCCESSFUL ;
  831. break;
  832. }
  833. if ( BufferAsMdl ) {
  834. MRxSmbStuffAppendRawData( StufferState, BufferAsMdl );
  835. MRxSmbStuffSetByteCount( StufferState );
  836. }
  837. MRxSmbDumpStufferState(
  838. 700,
  839. "SMB Write Request after stuffing",
  840. StufferState);
  841. if (Status==STATUS_SUCCESS) {
  842. InterlockedIncrement(&MRxSmbStatistics.SmallWriteSmbs);
  843. }
  844. return Status;
  845. }
  846. BOOLEAN DisableLargeWrites = 0;
  847. NTSTATUS
  848. SmbPseExchangeStart_Write (
  849. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  850. )
  851. /*++
  852. Routine Description:
  853. This is the start routine for write.
  854. Arguments:
  855. pExchange - the exchange instance
  856. Return Value:
  857. NTSTATUS - The return status for the operation
  858. --*/
  859. {
  860. NTSTATUS Status;
  861. ULONG StartEntryCount;
  862. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  863. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  864. PSMB_PSE_OE_READWRITE GlobalReadWrite = OrdinaryExchange->GlobalReadWrite;
  865. ULONG NumOfOutstandingOperations;
  866. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  867. PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
  868. RxCaptureFcb;
  869. RxCaptureFobx;
  870. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  871. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  872. PMRX_SMB_FCB SmbFcb = MRxSmbGetFcbExtension(capFcb);
  873. BOOLEAN SynchronousIo, IsPagingIo;
  874. UCHAR WriteCommand;
  875. PAGED_CODE();
  876. RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Write\n"));
  877. ASSERT( OrdinaryExchange->Type == ORDINARY_EXCHANGE );
  878. ASSERT(
  879. (
  880. (OriginalDataMdl!=NULL) &&
  881. (
  882. RxMdlIsLocked(OriginalDataMdl) ||
  883. RxMdlSourceIsNonPaged(OriginalDataMdl)
  884. )
  885. ) ||
  886. (
  887. (OriginalDataMdl==NULL) &&
  888. (LowIoContext->ParamsFor.ReadWrite.ByteCount==0)
  889. )
  890. );
  891. ASSERT((OrdinaryExchange->SmbCeFlags&SMBCE_EXCHANGE_ATTEMPT_RECONNECTS) == 0 );
  892. OrdinaryExchange->StartEntryCount++;
  893. StartEntryCount = OrdinaryExchange->StartEntryCount;
  894. SynchronousIo = !BooleanFlagOn(
  895. RxContext->Flags,
  896. RX_CONTEXT_FLAG_ASYNC_OPERATION);
  897. IsPagingIo = BooleanFlagOn(
  898. LowIoContext->ParamsFor.ReadWrite.Flags,
  899. LOWIO_READWRITEFLAG_PAGING_IO);
  900. // Ensure that the Fid is validated
  901. SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID);
  902. for (;;) {
  903. PSMBCE_SERVER pServer;
  904. PSMBCE_NET_ROOT pNetRoot;
  905. pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  906. pNetRoot = SmbCeGetExchangeNetRoot(OrdinaryExchange);
  907. switch (OrdinaryExchange->OpSpecificState) {
  908. case SmbPseOEInnerIoStates_Initial:
  909. {
  910. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
  911. MRxSmbSetInitialSMB( StufferState STUFFERTRACE(Dbg,'FC') );
  912. }
  913. //lack of break is intentional
  914. case SmbPseOEInnerIoStates_ReadyToSend:
  915. {
  916. ULONG MaximumBufferSizeThisIteration;
  917. PCHAR Buffer = NULL;
  918. PMDL BufferAsMdl = NULL;
  919. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_OperationOutstanding;
  920. OrdinaryExchange->SendOptions = MRxSmbWriteSendOptions;
  921. if (FlagOn(pServer->DialectFlags,DF_LANMAN10) &&
  922. FlagOn(pServer->DialectFlags,DF_LARGE_FILES) &&
  923. (StufferState->RxContext->pFcb->pNetRoot->Type != NET_ROOT_PRINT)) {
  924. WriteCommand = SMB_COM_WRITE_ANDX;
  925. } else {
  926. WriteCommand = SMB_COM_WRITE;
  927. }
  928. MaximumBufferSizeThisIteration = rw->MaximumBufferSize;
  929. // There are four parameters pertaining to a write request
  930. //
  931. // 1. Write Length -- rw->ThisByteCount
  932. // 2. Write Offset -- rw->ByteOffsetAsLI
  933. // 3. Write Buffer -- Buffer
  934. // 4. Write Buffer as a MDL -- BufferAsMdl
  935. //
  936. // All writes can be classified into one of the following
  937. // categories ...
  938. //
  939. // 1. Extremely Small writes
  940. // These are writes lesser than the COPY_THRESHOLD or
  941. // we are in a debug mode that forces us to do only small
  942. // writes.
  943. //
  944. // 2. Write requests against downlevel servers or non disk
  945. // file write requests against up level servers.
  946. // In all these cases we are constrained by the Server
  947. // which limits the number of bytes to roughly 4k. This
  948. // is based upon the Smb Buffer size returned during
  949. // negotiation.
  950. //
  951. // 3. Write requests ( Uncompressed ) against uplevel (NT5+)
  952. // servers
  953. // These write requests can be arbitrarily large
  954. //
  955. // 4. Write requests (Compressed) against uplevel servers
  956. // In these cases the server constrains us to send
  957. // only 64k of compressed data with the added restriction
  958. // that the compressed data info structure must be less
  959. // than the SMB buffer size.
  960. //
  961. rw->CompressedDataInfoLength = 0;
  962. if ((rw->RemainingByteCount < WRITE_COPY_THRESHOLD) ||
  963. FORCECOPYMODE) {
  964. if (FORCECOPYMODE &&
  965. (rw->ThisByteCount > MaximumBufferSizeThisIteration) ) {
  966. rw->ThisByteCount = MaximumBufferSizeThisIteration;
  967. } else {
  968. rw->ThisByteCount = rw->RemainingByteCount;
  969. }
  970. Buffer = rw->UserBufferBase + rw->ThisBufferOffset;
  971. ASSERT( WRITE_COPY_THRESHOLD <= pNetRoot->MaximumWriteBufferSize );
  972. } else {
  973. if (rw->CompressedReadOrWrite) {
  974. MRxSmbPrepareCompressedWriteRequest(
  975. OrdinaryExchange,
  976. &Buffer,
  977. &BufferAsMdl);
  978. }
  979. if (!rw->CompressedReadOrWrite) {
  980. rw->ThisByteCount = min(
  981. rw->RemainingByteCount,
  982. MaximumBufferSizeThisIteration);
  983. if ((rw->ThisBufferOffset != 0) ||
  984. (rw->ThisByteCount != OriginalDataMdl->ByteCount)) {
  985. MmInitializeMdl(
  986. &rw->PartialDataMdl,
  987. 0,
  988. MAX_PARTIAL_DATA_MDL_BUFFER_SIZE);
  989. IoBuildPartialMdl(
  990. OriginalDataMdl,
  991. &rw->PartialDataMdl,
  992. (PCHAR)MmGetMdlVirtualAddress(OriginalDataMdl) +
  993. rw->ThisBufferOffset,
  994. rw->ThisByteCount );
  995. BufferAsMdl = &rw->PartialDataMdl;
  996. } else {
  997. BufferAsMdl = OriginalDataMdl;
  998. }
  999. }
  1000. }
  1001. Status = MRxSmbBuildWriteRequest(
  1002. OrdinaryExchange,
  1003. IsPagingIo,
  1004. WriteCommand,
  1005. rw->ThisByteCount,
  1006. &rw->ByteOffsetAsLI,
  1007. Buffer,
  1008. BufferAsMdl);
  1009. if (Status != STATUS_SUCCESS) {
  1010. RxDbgTrace(0, Dbg, ("bad write stuffer status........\n"));
  1011. goto FINALLY;
  1012. }
  1013. InterlockedIncrement(&MRxSmbStatistics.WriteSmbs);
  1014. Status = SmbPseOrdinaryExchange(
  1015. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1016. SMBPSE_OETYPE_WRITE );
  1017. if ( Status == STATUS_PENDING) {
  1018. goto FINALLY;
  1019. }
  1020. }
  1021. //lack of break is intentional
  1022. case SmbPseOEInnerIoStates_OperationOutstanding:
  1023. case SmbPseOEInnerIoStates_OperationCompleted:
  1024. {
  1025. NTSTATUS ExchangeStatus;
  1026. SetFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_SUBSEQUENT_OPERATION);
  1027. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
  1028. if (rw->PartialExchangeMdlInUse) {
  1029. MmPrepareMdlForReuse(
  1030. &rw->PartialExchangeMdl);
  1031. rw->PartialDataMdlInUse = FALSE;
  1032. }
  1033. if (rw->PartialDataMdlInUse) {
  1034. MmPrepareMdlForReuse(
  1035. &rw->PartialDataMdl);
  1036. rw->PartialDataMdlInUse = FALSE;
  1037. }
  1038. Status = OrdinaryExchange->Status;
  1039. ExchangeStatus = OrdinaryExchange->Status;
  1040. if (Status != STATUS_SUCCESS) {
  1041. PSMBCE_SESSION pSession = SmbCeGetExchangeSession(OrdinaryExchange);
  1042. if (Status == STATUS_RETRY) {
  1043. SmbCeUninitializeExchangeTransport((PSMB_EXCHANGE)OrdinaryExchange);
  1044. Status = SmbCeReconnect(SmbCeGetExchangeVNetRoot(OrdinaryExchange));
  1045. if (Status == STATUS_SUCCESS) {
  1046. OrdinaryExchange->Status = STATUS_SUCCESS;
  1047. OrdinaryExchange->SmbStatus = STATUS_SUCCESS;
  1048. Status = SmbCeInitializeExchangeTransport((PSMB_EXCHANGE)OrdinaryExchange);
  1049. ASSERT(Status == STATUS_SUCCESS);
  1050. if (Status != STATUS_SUCCESS) {
  1051. goto FINALLY;
  1052. }
  1053. } else {
  1054. goto FINALLY;
  1055. }
  1056. } else if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION) &&
  1057. (smbSrvOpen->DeferredOpenContext != NULL) &&
  1058. (Status == STATUS_IO_TIMEOUT ||
  1059. Status == STATUS_BAD_NETWORK_PATH ||
  1060. Status == STATUS_NETWORK_UNREACHABLE ||
  1061. Status == STATUS_USER_SESSION_DELETED ||
  1062. Status == STATUS_REMOTE_NOT_LISTENING ||
  1063. Status == STATUS_CONNECTION_DISCONNECTED)) {
  1064. Status = SmbCeRemoteBootReconnect((PSMB_EXCHANGE)OrdinaryExchange,RxContext);
  1065. if (Status == STATUS_SUCCESS) {
  1066. // Resume the write from the previous offset.
  1067. OrdinaryExchange->SmbStatus = STATUS_SUCCESS;
  1068. SmbCeInitializeExchangeTransport((PSMB_EXCHANGE)OrdinaryExchange);
  1069. } else {
  1070. Status = STATUS_RETRY;
  1071. }
  1072. }
  1073. }
  1074. ExAcquireFastMutex(&MRxSmbReadWriteMutex);
  1075. if (ExchangeStatus == STATUS_SUCCESS) {
  1076. rw->RemainingByteCount -= rw->BytesReturned;
  1077. RxContext->InformationToReturn += rw->BytesReturned;
  1078. rw->ByteOffsetAsLI.QuadPart += rw->BytesReturned;
  1079. rw->ThisBufferOffset += rw->BytesReturned;
  1080. if (rw->WriteToTheEnd) {
  1081. smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart += rw->BytesReturned;
  1082. MRxSmbUpdateFileInfoCacheFileSize(RxContext, (PLARGE_INTEGER)(&smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart));
  1083. }
  1084. }
  1085. if ((Status != STATUS_SUCCESS) ||
  1086. (rw->RemainingByteCount ==0)) {
  1087. if (rw->RemainingByteCount == 0) {
  1088. RxDbgTrace(
  1089. 0,
  1090. Dbg,
  1091. (
  1092. "OE %lx TBC %lx RBC %lx BR %lx TBO %lx\n",
  1093. OrdinaryExchange,rw->ThisByteCount,
  1094. rw->RemainingByteCount,
  1095. rw->BytesReturned,
  1096. rw->ThisBufferOffset )
  1097. );
  1098. RxDbgTrace(
  1099. 0,
  1100. Dbg,
  1101. ("Bytes written %lx\n",
  1102. RxContext->InformationToReturn)
  1103. );
  1104. if (rw->pCompressedDataBuffer != NULL) {
  1105. RxFreePool(rw->pCompressedDataBuffer);
  1106. rw->pCompressedDataBuffer = NULL;
  1107. }
  1108. }
  1109. if (rw->RemainingByteCount == 0 &&
  1110. GlobalReadWrite->SectionState[rw->CurrentSection] == SmbPseOEReadWriteIoStates_OperationOutstanding) {
  1111. GlobalReadWrite->SectionState[rw->CurrentSection] = SmbPseOEReadWriteIoStates_OperationCompleted;
  1112. SmbCeLog(("Section done %d\n",rw->CurrentSection));
  1113. } else {
  1114. GlobalReadWrite->SectionState[rw->CurrentSection] = SmbPseOEReadWriteIoStates_Initial;
  1115. SmbCeLog(("Section undo %d\n",rw->CurrentSection));
  1116. }
  1117. if ((Status == STATUS_RETRY) ||
  1118. (Status == STATUS_SUCCESS) ||
  1119. (Status == STATUS_SMB_USE_STANDARD)) {
  1120. if (Status == STATUS_SMB_USE_STANDARD) {
  1121. GlobalReadWrite->CompletionStatus = STATUS_SMB_USE_STANDARD;
  1122. }
  1123. Status = MRxSmbFindNextSectionForReadWrite(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1124. &NumOfOutstandingOperations);
  1125. }
  1126. NumOfOutstandingOperations = InterlockedDecrement(&GlobalReadWrite->NumOfOutstandingOperations);
  1127. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  1128. if ((Status == STATUS_TOO_MANY_COMMANDS) && (NumOfOutstandingOperations > 0)) {
  1129. Status = STATUS_SUCCESS;
  1130. }
  1131. if (Status != STATUS_SUCCESS &&
  1132. GlobalReadWrite->CompletionStatus == STATUS_SUCCESS) {
  1133. GlobalReadWrite->CompletionStatus = Status;
  1134. }
  1135. rw->ReadWriteFinalized = TRUE;
  1136. SmbCeLog(("Pipeline Write final %x %x %d\n",OrdinaryExchange,Status,NumOfOutstandingOperations));
  1137. }
  1138. ExReleaseFastMutex(&MRxSmbReadWriteMutex);
  1139. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  1140. goto FINALLY;
  1141. }
  1142. } else {
  1143. ExReleaseFastMutex(&MRxSmbReadWriteMutex);
  1144. }
  1145. RxDbgTrace(
  1146. 0,
  1147. Dbg,
  1148. ( "Next Iteration OE %lx RBC %lx TBO %lx\n",
  1149. OrdinaryExchange,
  1150. rw->RemainingByteCount,
  1151. rw->ThisBufferOffset)
  1152. );
  1153. RxDbgTrace(
  1154. 0,
  1155. Dbg,
  1156. ("OE %lx TBC %lx, BR %lx\n",
  1157. OrdinaryExchange,
  1158. rw->ThisByteCount,
  1159. rw->BytesReturned));
  1160. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
  1161. }
  1162. break;
  1163. }
  1164. }
  1165. FINALLY:
  1166. if (Status != STATUS_PENDING) {
  1167. BOOLEAN ReadWriteOutStanding = FALSE;
  1168. PSMB_PSE_OE_READWRITE GlobalReadWrite = OrdinaryExchange->GlobalReadWrite;
  1169. if (!rw->ReadWriteFinalized) {
  1170. ExAcquireFastMutex(&MRxSmbReadWriteMutex);
  1171. if (rw->RemainingByteCount == 0 &&
  1172. GlobalReadWrite->SectionState[rw->CurrentSection] == SmbPseOEReadWriteIoStates_OperationOutstanding) {
  1173. GlobalReadWrite->SectionState[rw->CurrentSection] = SmbPseOEReadWriteIoStates_OperationCompleted;
  1174. SmbCeLog(("Section done %d\n",rw->CurrentSection));
  1175. } else {
  1176. GlobalReadWrite->SectionState[rw->CurrentSection] = SmbPseOEReadWriteIoStates_Initial;
  1177. SmbCeLog(("Section undo %d\n",rw->CurrentSection));
  1178. }
  1179. NumOfOutstandingOperations = InterlockedDecrement(&GlobalReadWrite->NumOfOutstandingOperations);
  1180. if ((Status == STATUS_TOO_MANY_COMMANDS) && (NumOfOutstandingOperations > 0)) {
  1181. Status = STATUS_SUCCESS;
  1182. }
  1183. if (Status != STATUS_SUCCESS &&
  1184. GlobalReadWrite->CompletionStatus == STATUS_SUCCESS) {
  1185. GlobalReadWrite->CompletionStatus = Status;
  1186. }
  1187. rw->ReadWriteFinalized = TRUE;
  1188. SmbCeLog(("Pipeline Write final %x %x %d\n",OrdinaryExchange,Status,NumOfOutstandingOperations));
  1189. ExReleaseFastMutex(&MRxSmbReadWriteMutex);
  1190. }
  1191. if (!NumOfOutstandingOperations) {
  1192. ASSERT(Status != STATUS_RETRY);
  1193. // update shadow as appropriate
  1194. // We do this here to ensure the shadow is updated only once (at IRP completion)
  1195. IF_NOT_MRXSMB_CSC_ENABLED{
  1196. ASSERT(MRxSmbGetSrvOpenExtension(SrvOpen)->hfShadow == 0);
  1197. } else {
  1198. if (MRxSmbGetSrvOpenExtension(SrvOpen)->hfShadow != 0){
  1199. MRxSmbCscWriteEpilogue(RxContext,&Status);
  1200. }
  1201. }
  1202. if (!SynchronousIo &&
  1203. (GlobalReadWrite->SmbFcbHoldingState != SmbFcb_NotHeld)) {
  1204. MRxSmbCscReleaseSmbFcb(
  1205. StufferState->RxContext,
  1206. &GlobalReadWrite->SmbFcbHoldingState);
  1207. }
  1208. Status = GlobalReadWrite->CompletionStatus;
  1209. SmbPseAsyncCompletionIfNecessary(OrdinaryExchange,RxContext);
  1210. SmbCeLog(("Write complete %x %x\n",OrdinaryExchange,Status));
  1211. if (SynchronousIo) {
  1212. KeSetEvent(
  1213. &GlobalReadWrite->CompletionEvent,
  1214. 0,
  1215. FALSE);
  1216. }
  1217. } else {
  1218. SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  1219. Status = STATUS_PENDING;
  1220. }
  1221. MRxSmbDereferenceGlobalReadWrite(GlobalReadWrite);
  1222. }
  1223. RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Write exit w %08lx\n", Status ));
  1224. return Status;
  1225. } // SmbPseExchangeStart_Write
  1226. NTSTATUS
  1227. MRxSmbFinishWrite (
  1228. IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  1229. IN PBYTE ResponseBuffer
  1230. )
  1231. /*++
  1232. Routine Description:
  1233. This routine actually gets the stuff out of the write response and finishes
  1234. the write. Everything you need is locked down... so we can finish in the
  1235. indication routine
  1236. Arguments:
  1237. OrdinaryExchange - the exchange instance
  1238. ResponseBuffer - the response
  1239. Return Value:
  1240. RXSTATUS - The return status for the operation
  1241. --*/
  1242. {
  1243. NTSTATUS Status = STATUS_SUCCESS;
  1244. ULONG BytesReturned = 0;
  1245. PAGED_CODE();
  1246. RxDbgTrace(+1, Dbg, ("MRxSmbFinishWrite\n"));
  1247. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishWrite:");
  1248. switch (OrdinaryExchange->LastSmbCommand) {
  1249. case SMB_COM_WRITE_ANDX:
  1250. {
  1251. PSMBCE_SERVER pServer;
  1252. PSMBCE_NET_ROOT pNetRoot;
  1253. PRESP_WRITE_ANDX Response = (PRESP_WRITE_ANDX)ResponseBuffer;
  1254. if (Response->WordCount != 6 ||
  1255. SmbGetUshort(&Response->ByteCount) != 0) {
  1256. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1257. }
  1258. pServer = SmbCeGetExchangeServer((PSMB_EXCHANGE)OrdinaryExchange);
  1259. pNetRoot = SmbCeGetExchangeNetRoot((PSMB_EXCHANGE)OrdinaryExchange);
  1260. BytesReturned = SmbGetUshort( &Response->Count );
  1261. if (FlagOn(pServer->DialectFlags,DF_LARGE_WRITEX)) {
  1262. ULONG BytesReturnedHigh;
  1263. BytesReturnedHigh = SmbGetUshort(&Response->CountHigh);
  1264. BytesReturned = (BytesReturnedHigh << 16) | BytesReturned;
  1265. }
  1266. if (pNetRoot->NetRootType != NET_ROOT_PIPE) {
  1267. if ((OrdinaryExchange->Status == STATUS_SUCCESS) &&
  1268. (OrdinaryExchange->ReadWrite.ThisByteCount > 2) &&
  1269. (BytesReturned == 0)) {
  1270. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1271. }
  1272. } else {
  1273. // Servers are not setting the bytes returned correctly for
  1274. // pipe writes. This enables us to gracefully handle responses
  1275. // from such servers
  1276. BytesReturned = OrdinaryExchange->ReadWrite.ThisByteCount;
  1277. }
  1278. //if we added 2 headerbytes then let's get rid of them......
  1279. if ( FlagOn(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_REDUCE_RETURNCOUNT) ) {
  1280. // BytesReturned -= sizeof(USHORT);
  1281. ClearFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_REDUCE_RETURNCOUNT);
  1282. }
  1283. }
  1284. break;
  1285. case SMB_COM_WRITE :
  1286. {
  1287. PRESP_WRITE Response = (PRESP_WRITE)ResponseBuffer;
  1288. if (Response->WordCount != 1 ||
  1289. SmbGetUshort(&Response->ByteCount) != 0) {
  1290. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1291. }
  1292. BytesReturned = SmbGetUshort( &Response->Count );
  1293. }
  1294. break;
  1295. case SMB_COM_WRITE_PRINT_FILE:
  1296. {
  1297. PRESP_WRITE_PRINT_FILE Response = (PRESP_WRITE_PRINT_FILE)ResponseBuffer;
  1298. if (Response->WordCount != 0) {
  1299. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1300. }
  1301. //the response does not tell how many bytes were taken! get the byte count from the exchange
  1302. BytesReturned = OrdinaryExchange->ReadWrite.ThisByteCount;
  1303. }
  1304. break;
  1305. default :
  1306. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1307. break;
  1308. }
  1309. RxDbgTrace(0, Dbg, ("-->BytesReturned=%08lx\n", BytesReturned));
  1310. OrdinaryExchange->ReadWrite.BytesReturned = BytesReturned;
  1311. if (Status == STATUS_SUCCESS &&
  1312. OrdinaryExchange->ReadWrite.ThisByteCount > 2 &&
  1313. BytesReturned > OrdinaryExchange->ReadWrite.ThisByteCount) {
  1314. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1315. }
  1316. // invalidate the name based file info cache since it is almost impossible
  1317. // to know the last write time of the file on the server.
  1318. MRxSmbInvalidateFileInfoCache(OrdinaryExchange->RxContext);
  1319. RxDbgTrace(-1, Dbg, ("MRxSmbFinishWrite returning %08lx\n", Status ));
  1320. return Status;
  1321. } // MRxSmbFinishWrite
  1322. NTSTATUS
  1323. MRxSmbFindNextSectionForReadWrite(
  1324. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
  1325. PULONG NumOfOutstandingExchanges
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. This routine find out the next section for the read/write operation and set up the
  1330. exchange readwrite struction accordingly.
  1331. Arguments:
  1332. RxContext - the RDBSS context
  1333. OrdinaryExchange - the exchange instance
  1334. Return Value:
  1335. RXSTATUS - The return status for the operation
  1336. --*/
  1337. {
  1338. RxCaptureFcb;
  1339. NTSTATUS Status = STATUS_SUCCESS;
  1340. ULONG Section;
  1341. BOOLEAN SectionFound = FALSE;
  1342. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  1343. PSMB_PSE_OE_READWRITE GlobalReadWrite = OrdinaryExchange->GlobalReadWrite;
  1344. PSMBCE_SERVER pServer;
  1345. pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  1346. *NumOfOutstandingExchanges = GlobalReadWrite->NumOfOutstandingOperations;
  1347. if ((GlobalReadWrite->CompletionStatus != STATUS_SUCCESS) &&
  1348. (GlobalReadWrite->CompletionStatus != STATUS_SMB_USE_STANDARD)) {
  1349. Status = GlobalReadWrite->CompletionStatus;
  1350. goto FINALLY;
  1351. }
  1352. if (GlobalReadWrite->CompletionStatus == STATUS_SMB_USE_STANDARD) {
  1353. RxContext->InformationToReturn = 0;
  1354. GlobalReadWrite->CompressedRequestInProgress = FALSE;
  1355. GlobalReadWrite->CompressedReadOrWrite = FALSE;
  1356. GlobalReadWrite->CompletionStatus = STATUS_SUCCESS;
  1357. OrdinaryExchange->Status = STATUS_SUCCESS;
  1358. for (Section=0;Section<GlobalReadWrite->TotalNumOfSections;Section++) {
  1359. switch (GlobalReadWrite->SectionState[Section]) {
  1360. case SmbPseOEReadWriteIoStates_OperationOutstanding:
  1361. GlobalReadWrite->SectionState[Section] = SmbPseOEReadWriteIoStates_OperationAbandoned;
  1362. break;
  1363. case SmbPseOEReadWriteIoStates_OperationCompleted:
  1364. GlobalReadWrite->SectionState[Section] = SmbPseOEReadWriteIoStates_Initial;
  1365. break;
  1366. }
  1367. }
  1368. }
  1369. for (Section=0;Section<GlobalReadWrite->TotalNumOfSections;Section++) {
  1370. if (GlobalReadWrite->SectionState[Section] == SmbPseOEReadWriteIoStates_Initial) {
  1371. GlobalReadWrite->SectionState[Section] = SmbPseOEReadWriteIoStates_OperationOutstanding;
  1372. SectionFound = TRUE;
  1373. break;
  1374. }
  1375. }
  1376. if (SectionFound) {
  1377. rw->ByteOffsetAsLI.QuadPart = GlobalReadWrite->ByteOffsetAsLI.QuadPart +
  1378. (ULONGLONG)GlobalReadWrite->MaximumBufferSize*Section;
  1379. if ((Section == GlobalReadWrite->TotalNumOfSections - 1) &&
  1380. (GlobalReadWrite->RemainingByteCount % GlobalReadWrite->MaximumBufferSize != 0)) {
  1381. rw->RemainingByteCount = GlobalReadWrite->RemainingByteCount % GlobalReadWrite->MaximumBufferSize;
  1382. } else if( GlobalReadWrite->RemainingByteCount != 0 ) {
  1383. rw->RemainingByteCount = GlobalReadWrite->MaximumBufferSize;
  1384. } else {
  1385. rw->RemainingByteCount = 0;
  1386. }
  1387. rw->ThisBufferOffset = GlobalReadWrite->MaximumBufferSize*Section;
  1388. rw->CurrentSection = Section;
  1389. *NumOfOutstandingExchanges = InterlockedIncrement(&GlobalReadWrite->NumOfOutstandingOperations);
  1390. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1391. SmbCeLog(("Next section found %d %x\n",Section,OrdinaryExchange));
  1392. }
  1393. FINALLY:
  1394. return Status;
  1395. }