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.

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