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.

1184 lines
44 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. read.c
  5. Abstract:
  6. This module implements the mini redirector call down routines pertaining to
  7. read of file system objects.
  8. Author:
  9. Joe Linn [JoeLi] 7-March-1995
  10. Revision History:
  11. Balan Sethu Raman [SethuR] 7-October-1997
  12. Notes:
  13. The READ adn WRITE paths in the mini redirector have to contend with a number
  14. of different variations based on the kind of the server and the capabilities
  15. of the server.
  16. Currently there are atleast four variations of the read operation that needs
  17. to be supported.
  18. 1) SMB_COM_READ
  19. This is the read operation of choice against all servers which
  20. support old dialects of the SMB protocol ( < DF_LANMAN10 )
  21. 2) SMB_COM_READ_ANDX
  22. This is the read operation of choice against all servers which
  23. support read extensions in the new dialects of the SMB protocol
  24. However READ_ANDX itself can be further customized based upon the
  25. server capabilities. There are two dimensions in which this
  26. change can occur -- large sized reads being supported and compressed
  27. reads.
  28. In addition the SMB protocol supports the following flavours of a READ
  29. operation which are not supported in the redirector
  30. 1) SMB_COM_READ_RAW
  31. This is used to initiate large transfers to a server. However this
  32. ties up the VC exclusively for this operation. The large READ_ANDX
  33. overcomes this by providing for large read operations which can
  34. be multiplexed on the VC.
  35. 2) SMB_COM_READ_MPX,SMB_COM_READ_MPX_SECONDARY,
  36. These operations were designed for a direct host client. The NT
  37. redriector does not use these operations because the recent
  38. changes to NetBt allows us to go directly over a TCP connection.
  39. The implementation of a read operation in the RDR hinges upon two decisions --
  40. selecting the type of command to use and decomposing the original read
  41. operation into a number of smaller read operations while adhering to
  42. protocol/server restrictions.
  43. The exchange engine provides the facility for sending a packet to the server
  44. and picking up the associated response. Based upon the amount of data to be
  45. read a number of such operations need to be initiated.
  46. This module is organized as follows ---
  47. MRxSmbRead --
  48. This represents the top level entry point in the dispatch vector for
  49. read operations associated with this mini redirector.
  50. MRxSmbBuildReadRequest --
  51. This routine is used for formatting the read command to be sent to
  52. the server. We will require a new routine for each new type of read
  53. operation that we would like to support
  54. SmbPseExchangeStart_Read --
  55. This routine is the heart of the read engine. It farms out the
  56. necessary number of read operations and ensures the continuation
  57. of the local operation on completion for both synchronous and
  58. asynchronous reads.
  59. All the state information required for the read operation is captured in an
  60. instance of SMB_PSE_ORDINARY_EXCHANGE. This state information can be split
  61. into two parts - the generic state information and the state information
  62. specific to the read operation. The read operation specific state information
  63. has been encapsulated in SMB_PSE_OE_READWRITE field in the exchange instance.
  64. The read operation begins with the instantiation of an exchange in MRxSmbRead
  65. and is driven through the various stages based upon a state diagram. The
  66. state diagram is encoded in the OpSpecificState field in the ordinary
  67. exchange.
  68. The state diagram associated with the read exchange is as follows
  69. SmbPseOEInnerIoStates_Initial
  70. |
  71. |
  72. |
  73. V
  74. ---->SmbPseOEInnerIoStates_ReadyToSend
  75. | |
  76. | |
  77. | |
  78. | V
  79. ---SmbPseOEInnerIoStates_OperationOutstanding
  80. |
  81. |
  82. |
  83. V
  84. SmbPseOEInnerIoStates_OperationCompleted
  85. --*/
  86. #include "precomp.h"
  87. #pragma hdrstop
  88. #pragma warning(error:4101) // Unreferenced local variable
  89. #ifdef ALLOC_PRAGMA
  90. #pragma alloc_text(PAGE, MRxSmbRead)
  91. #pragma alloc_text(PAGE, MRxSmbBuildReadAndX)
  92. #pragma alloc_text(PAGE, MRxSmbBuildCoreRead)
  93. #pragma alloc_text(PAGE, MRxSmbBuildSmallRead)
  94. #pragma alloc_text(PAGE, SmbPseExchangeStart_Read)
  95. #pragma alloc_text(PAGE, MRxSmbFinishNoCopyRead)
  96. #endif
  97. //
  98. // The local debug trace level
  99. //
  100. #define Dbg (DEBUG_TRACE_READ)
  101. ULONG MRxSmbSrvReadBufSize = 0xffff; //use the negotiated size
  102. ULONG MRxSmbReadSendOptions = 0; //use the default options
  103. #define MIN_CHUNK_SIZE (0x1000)
  104. NTSTATUS
  105. MRxSmbBuildReadRequest(
  106. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange);
  107. #if DBG
  108. VOID
  109. MRxSmbValidateCompressedDataInfo(
  110. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange);
  111. #else
  112. INLINE VOID
  113. MRxSmbValidateCompressedDataInfo(
  114. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange)
  115. {
  116. UNREFERENCED_PARAMETER(OrdinaryExchange);
  117. }
  118. #endif
  119. NTSTATUS
  120. MRxSmbRead(
  121. IN PRX_CONTEXT RxContext
  122. )
  123. /*++
  124. Routine Description:
  125. This routine handles network read requests.
  126. Arguments:
  127. RxContext - the RDBSS context
  128. Return Value:
  129. NTSTATUS - The return status for the operation
  130. --*/
  131. {
  132. NTSTATUS Status = STATUS_SUCCESS;
  133. RxCaptureFcb;
  134. RxCaptureFobx;
  135. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  136. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  137. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  138. PMRX_V_NET_ROOT VNetRootToUse = capFobx->pSrvOpen->pVNetRoot;
  139. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  140. SMBFCB_HOLDING_STATE SmbFcbHoldingState = SmbFcb_NotHeld;
  141. PAGED_CODE();
  142. RxDbgTrace(+1, Dbg, ("MRxSmbRead\n", 0 ));
  143. ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
  144. do {
  145. IF_NOT_MRXSMB_CSC_ENABLED{
  146. ASSERT(smbSrvOpen->hfShadow == 0);
  147. } else {
  148. if (smbSrvOpen->hfShadow != 0){
  149. NTSTATUS ShadowReadNtStatus;
  150. if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_OPEN_SURROGATED)) {
  151. if (smbFcb->SurrogateSrvOpen == NULL) {
  152. //whoops....my surrogate closed.....
  153. RxDbgTrace(-1, Dbg, ("MRxSmbRead surrogate closed!! rxc=%08lx\n", RxContext ));
  154. return(STATUS_UNSUCCESSFUL);
  155. }
  156. VNetRootToUse = smbFcb->SurrogateSrvOpen->pVNetRoot;
  157. } else if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  158. //whoops again........someone closed my handle!
  159. RxDbgTrace(-1, Dbg, ("MRxSmbRead thruopen closed!! rxc=%08lx\n", RxContext ));
  160. return(STATUS_UNSUCCESSFUL);
  161. }
  162. ShadowReadNtStatus = MRxSmbCscReadPrologue(RxContext,&SmbFcbHoldingState);
  163. if (ShadowReadNtStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  164. RxDbgTrace(-1, Dbg, ("MRxSmbRead shadow hit with status=%08lx\n", ShadowReadNtStatus ));
  165. return(ShadowReadNtStatus);
  166. } else {
  167. RxDbgTrace(0, Dbg, ("MRxSmbRead shadowmiss with status=%08lx\n", ShadowReadNtStatus ));
  168. }
  169. }
  170. }
  171. Status = SmbPseCreateOrdinaryExchange(
  172. RxContext,
  173. VNetRootToUse,
  174. SMBPSE_OE_FROM_READ,
  175. SmbPseExchangeStart_Read,
  176. &OrdinaryExchange );
  177. if (Status != STATUS_SUCCESS) {
  178. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  179. goto FINALLY;
  180. }
  181. OrdinaryExchange->SmbFcbHoldingState = SmbFcbHoldingState;
  182. OrdinaryExchange->pSmbCeSynchronizationEvent = &RxContext->SyncEvent;
  183. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  184. if (Status != STATUS_PENDING) {
  185. BOOLEAN FinalizationComplete;
  186. SmbFcbHoldingState = OrdinaryExchange->SmbFcbHoldingState;
  187. FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  188. ASSERT(FinalizationComplete);
  189. } else {
  190. // let the exchange engine take care it
  191. SmbFcbHoldingState = SmbFcb_NotHeld;
  192. }
  193. if ((Status == STATUS_RETRY) &&
  194. BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  195. MRxSmbResumeAsyncReadWriteRequests(RxContext);
  196. Status = STATUS_PENDING;
  197. }
  198. } while (Status == STATUS_RETRY);
  199. FINALLY:
  200. RxDbgTrace(-1, Dbg, ("MRxSmbRead exit with status=%08lx\n", Status ));
  201. if (SmbFcbHoldingState != SmbFcb_NotHeld) {
  202. MRxSmbCscReleaseSmbFcb(
  203. RxContext,
  204. &SmbFcbHoldingState);
  205. }
  206. return(Status);
  207. } // MRxSmbRead
  208. NTSTATUS
  209. SmbPseExchangeStart_Read(
  210. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  211. )
  212. /*++
  213. Routine Description:
  214. This is the start routine for read.
  215. Arguments:
  216. RxContext - the local context
  217. OrdinaryExchange - the exchange instance
  218. Return Value:
  219. NTSTATUS - The return status for the operation
  220. --*/
  221. {
  222. NTSTATUS Status;
  223. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  224. ULONG StartEntryCount;
  225. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  226. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  227. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(OrdinaryExchange);
  228. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  229. PSMBCE_NET_ROOT pNetRoot = SmbCeGetExchangeNetRoot(OrdinaryExchange);
  230. RxCaptureFcb;
  231. RxCaptureFobx;
  232. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  233. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  234. PMRX_SMB_FCB SmbFcb = MRxSmbGetFcbExtension(capFcb);
  235. PSMBCE_SESSION pSession = SmbCeGetExchangeSession(OrdinaryExchange);
  236. BOOLEAN SynchronousIo =
  237. !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
  238. PAGED_CODE();
  239. RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Read\n", 0 ));
  240. ASSERT( (OrdinaryExchange->SmbCeFlags&SMBCE_EXCHANGE_ATTEMPT_RECONNECTS) == 0 );
  241. ASSERT(OrdinaryExchange->Type == ORDINARY_EXCHANGE);
  242. OrdinaryExchange->StartEntryCount++;
  243. StartEntryCount = OrdinaryExchange->StartEntryCount;
  244. // Ensure that the Fid is validated
  245. SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID);
  246. for (;;) {
  247. switch (OrdinaryExchange->OpSpecificState) {
  248. case SmbPseOEInnerIoStates_Initial:
  249. {
  250. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
  251. // If not a synchronous read, then continue here when resumed
  252. if (!SynchronousIo) {
  253. OrdinaryExchange->AsyncResumptionRoutine = SmbPseExchangeStart_Read;
  254. }
  255. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  256. rw->UserBufferBase = RxLowIoGetBufferAddress(RxContext);
  257. rw->ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  258. rw->RemainingByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  259. //record if this is a msgmode/pipe operation......
  260. if ((capFcb->pNetRoot->Type == NET_ROOT_PIPE) &&
  261. (capFobx->PipeHandleInformation->ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ) {
  262. SetFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_MSGMODE_PIPE_OPERATION);
  263. }
  264. rw->ThisBufferOffset = 0;
  265. rw->CompressedReadOrWrite = FALSE;
  266. rw->PartialDataMdlInUse = FALSE;
  267. rw->PartialExchangeMdlInUse = FALSE;
  268. rw->UserBufferPortionLength = 0;
  269. rw->ExchangeBufferPortionLength = 0;
  270. }
  271. //lack of break is intentional
  272. case SmbPseOEInnerIoStates_ReadyToSend:
  273. {
  274. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_OperationOutstanding;
  275. ClearFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_SUCCESS_IN_COPYHANDLER);
  276. OrdinaryExchange->SendOptions = MRxSmbReadSendOptions;
  277. Status = MRxSmbBuildReadRequest(
  278. OrdinaryExchange);
  279. if (Status != STATUS_SUCCESS) {
  280. RxDbgTrace(0, Dbg, ("bad read stuffer status........\n"));
  281. goto FINALLY;
  282. }
  283. if (FlagOn(
  284. LowIoContext->ParamsFor.ReadWrite.Flags,
  285. LOWIO_READWRITEFLAG_PAGING_IO)) {
  286. RxLog(
  287. ("PagingIoRead: rxc/offset/length %lx/%lx/%lx",
  288. RxContext,
  289. &rw->ByteOffsetAsLI,
  290. rw->ThisByteCount
  291. )
  292. );
  293. SmbLog(LOG,
  294. SmbPseExchangeStart_Read,
  295. LOGPTR(RxContext)
  296. LOGULONG(rw->ByteOffsetAsLI.LowPart)
  297. LOGULONG(rw->ThisByteCount));
  298. }
  299. InterlockedIncrement(&MRxSmbStatistics.ReadSmbs);
  300. Status = SmbPseOrdinaryExchange(
  301. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  302. SMBPSE_OETYPE_READ );
  303. // If the status is PENDING, then we're done for now. We must
  304. // wait until we're re-entered when the receive happens.
  305. if (Status == STATUS_PENDING) {
  306. ASSERT(!SynchronousIo);
  307. goto FINALLY;
  308. }
  309. }
  310. //lack of break is intentional
  311. case SmbPseOEInnerIoStates_OperationOutstanding:
  312. {
  313. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
  314. OrdinaryExchange->Status = OrdinaryExchange->SmbStatus;
  315. if (OrdinaryExchange->SmbStatus == STATUS_RETRY) {
  316. SmbCeUninitializeExchangeTransport((PSMB_EXCHANGE)OrdinaryExchange);
  317. Status = SmbCeReconnect(SmbCeGetExchangeVNetRoot(OrdinaryExchange));
  318. if (Status == STATUS_SUCCESS) {
  319. rw->BytesReturned = 0;
  320. OrdinaryExchange->SmbStatus = STATUS_SUCCESS;
  321. Status = SmbCeInitializeExchangeTransport((PSMB_EXCHANGE)OrdinaryExchange);
  322. ASSERT(Status == STATUS_SUCCESS);
  323. if (Status != STATUS_SUCCESS) {
  324. goto FINALLY;
  325. }
  326. } else {
  327. goto FINALLY;
  328. }
  329. } else if (OrdinaryExchange->SmbStatus != STATUS_SUCCESS &&
  330. FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
  331. switch (OrdinaryExchange->SmbStatus) {
  332. case STATUS_IO_TIMEOUT:
  333. case STATUS_BAD_NETWORK_PATH:
  334. case STATUS_NETWORK_UNREACHABLE:
  335. case STATUS_REMOTE_NOT_LISTENING:
  336. case STATUS_USER_SESSION_DELETED:
  337. case STATUS_CONNECTION_DISCONNECTED:
  338. ASSERT(smbSrvOpen->DeferredOpenContext != NULL);
  339. Status = SmbCeRemoteBootReconnect((PSMB_EXCHANGE)OrdinaryExchange, RxContext);
  340. OrdinaryExchange->Status = STATUS_RETRY;
  341. if (Status == STATUS_SUCCESS) {
  342. // Resume the read from the previous offset.
  343. OrdinaryExchange->SmbStatus = STATUS_SUCCESS;
  344. SmbCeInitializeExchangeTransport((PSMB_EXCHANGE)OrdinaryExchange);
  345. rw->BytesReturned = 0;
  346. } else {
  347. Status = STATUS_RETRY;
  348. OrdinaryExchange->SmbStatus = STATUS_RETRY;
  349. goto FINALLY;
  350. }
  351. break;
  352. }
  353. }
  354. if (rw->BytesReturned > 0) {
  355. if (rw->CompressedReadOrWrite) {
  356. // The Server sent back a compressed response.
  357. PUCHAR UserBufferPortion,ExchangeBufferPortion;
  358. ULONG UserBufferPortionLength,ExchangeBufferPortionLength;
  359. PUCHAR CompressedBuffer,CompressedTailBuffer;
  360. ULONG CompressedBufferLength,CompressedTailBufferLength;
  361. PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
  362. UserBufferPortionLength = rw->UserBufferPortionLength;
  363. ExchangeBufferPortionLength = rw->ExchangeBufferPortionLength;
  364. rw->UserBufferPortionLength = 0;
  365. if (rw->PartialDataMdlInUse) {
  366. MmPrepareMdlForReuse(
  367. &rw->PartialDataMdl);
  368. rw->PartialDataMdlInUse = FALSE;
  369. }
  370. rw->ExchangeBufferPortionLength = 0;
  371. if (rw->PartialExchangeMdlInUse) {
  372. MmPrepareMdlForReuse(
  373. &rw->PartialExchangeMdl);
  374. rw->PartialExchangeMdlInUse = FALSE;
  375. }
  376. if (UserBufferPortionLength > 0) {
  377. UserBufferPortion = (PCHAR)rw->UserBufferBase +
  378. MmGetMdlByteCount(OriginalDataMdl) -
  379. UserBufferPortionLength;
  380. } else {
  381. UserBufferPortion = NULL;
  382. }
  383. if (ExchangeBufferPortionLength > 0) {
  384. ExchangeBufferPortion = StufferState->BufferBase;
  385. } else {
  386. ExchangeBufferPortion = NULL;
  387. }
  388. if (UserBufferPortionLength >= rw->CompressedDataInfoLength) {
  389. RtlCopyMemory(
  390. &rw->CompressedDataInfo,
  391. UserBufferPortion,
  392. rw->CompressedDataInfoLength);
  393. UserBufferPortion += rw->CompressedDataInfoLength;
  394. UserBufferPortionLength -= rw->CompressedDataInfoLength;
  395. } else {
  396. RtlCopyMemory(
  397. &rw->CompressedDataInfo,
  398. UserBufferPortion,
  399. UserBufferPortionLength);
  400. RtlCopyMemory(
  401. ((PUCHAR)&rw->CompressedDataInfo + UserBufferPortionLength),
  402. ExchangeBufferPortion,
  403. rw->CompressedDataInfoLength - UserBufferPortionLength);
  404. ExchangeBufferPortionLength -= (rw->CompressedDataInfoLength
  405. - UserBufferPortionLength);
  406. ExchangeBufferPortion += (rw->CompressedDataInfoLength
  407. - UserBufferPortionLength);
  408. UserBufferPortionLength = 0;
  409. }
  410. if (UserBufferPortionLength > 0) {
  411. CompressedBuffer = UserBufferPortion;
  412. CompressedBufferLength = UserBufferPortionLength;
  413. CompressedTailBuffer = ExchangeBufferPortion;
  414. CompressedTailBufferLength = ExchangeBufferPortionLength;
  415. } else {
  416. CompressedBuffer = ExchangeBufferPortion;
  417. CompressedBufferLength = ExchangeBufferPortionLength;
  418. CompressedTailBuffer = NULL;
  419. CompressedTailBufferLength = 0;
  420. }
  421. MRxSmbValidateCompressedDataInfo(
  422. OrdinaryExchange);
  423. OrdinaryExchange->Status =
  424. RtlDecompressChunks(
  425. (PCHAR)rw->UserBufferBase + rw->ThisBufferOffset,
  426. LowIoContext->ParamsFor.ReadWrite.ByteCount - rw->ThisBufferOffset,
  427. CompressedBuffer,
  428. CompressedBufferLength,
  429. CompressedTailBuffer,
  430. CompressedTailBufferLength,
  431. &rw->CompressedDataInfo);
  432. rw->BytesReturned = rw->CompressedDataInfo.NumberOfChunks * MIN_CHUNK_SIZE;
  433. {
  434. LARGE_INTEGER Offset = rw->ByteOffsetAsLI;
  435. Offset.QuadPart += rw->BytesReturned;
  436. if (Offset.QuadPart > capFcb->Header.FileSize.QuadPart) {
  437. DbgPrint("Truncating read size from %lx",
  438. rw->BytesReturned);
  439. rw->BytesReturned = (ULONG)( capFcb->Header.FileSize.QuadPart -
  440. rw->ByteOffsetAsLI.QuadPart);
  441. DbgPrint(" to %lx\n",rw->BytesReturned);
  442. }
  443. }
  444. } else {
  445. if (rw->PartialDataMdlInUse) {
  446. MmPrepareMdlForReuse(
  447. &rw->PartialDataMdl);
  448. rw->PartialDataMdlInUse = FALSE;
  449. }
  450. }
  451. } else {
  452. if (OrdinaryExchange->Status == STATUS_SUCCESS) {
  453. if (capFcb->pNetRoot->Type == NET_ROOT_PIPE){
  454. OrdinaryExchange->Status = STATUS_PIPE_EMPTY;
  455. } else {
  456. OrdinaryExchange->Status = STATUS_END_OF_FILE;
  457. }
  458. }
  459. }
  460. rw->RemainingByteCount -= rw->BytesReturned;
  461. if ((OrdinaryExchange->Status == STATUS_END_OF_FILE) &&
  462. (RxContext->InformationToReturn > 0)) {
  463. OrdinaryExchange->Status = STATUS_SUCCESS;
  464. rw->RemainingByteCount = 0;
  465. }
  466. RxContext->InformationToReturn += rw->BytesReturned;
  467. Status = OrdinaryExchange->Status;
  468. if (Status != STATUS_RETRY) {
  469. if (NT_ERROR(Status) || (rw->RemainingByteCount==0)) {
  470. goto FINALLY;
  471. }
  472. if (capFcb->pNetRoot->Type != NET_ROOT_DISK) {
  473. if (Status != STATUS_BUFFER_OVERFLOW) {
  474. goto FINALLY;
  475. } else {
  476. ASSERT (rw->BytesReturned == rw->ThisByteCount);
  477. }
  478. }
  479. }
  480. //reset the smbstatus.....
  481. rw->ByteOffsetAsLI.QuadPart += rw->BytesReturned;
  482. rw->ThisBufferOffset += rw->BytesReturned;
  483. rw->BytesReturned = 0;
  484. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  485. break;
  486. }
  487. }
  488. }
  489. FINALLY:
  490. if ( Status != STATUS_PENDING) {
  491. // update shadow as appropriate............
  492. IF_NOT_MRXSMB_CSC_ENABLED{
  493. ASSERT(MRxSmbGetSrvOpenExtension(SrvOpen)->hfShadow == 0);
  494. } else {
  495. if (MRxSmbGetSrvOpenExtension(SrvOpen)->hfShadow != 0){
  496. MRxSmbCscReadEpilogue(RxContext,&Status);
  497. }
  498. }
  499. if (Status != STATUS_RETRY) {
  500. if (OrdinaryExchange->SmbFcbHoldingState != SmbFcb_NotHeld) {
  501. MRxSmbCscReleaseSmbFcb(
  502. StufferState->RxContext,
  503. &OrdinaryExchange->SmbFcbHoldingState);
  504. }
  505. SmbPseAsyncCompletionIfNecessary(OrdinaryExchange,RxContext);
  506. } else {
  507. // the exchange will be left hanging if STATUS_PENDING has been returned
  508. ASSERT(!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  509. RxContext->InformationToReturn = 0;
  510. }
  511. }
  512. RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Read exit w %08lx\n", Status ));
  513. return Status;
  514. } // SmbPseExchangeStart_Read
  515. NTSTATUS
  516. MRxSmbFinishNoCopyRead (
  517. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange
  518. )
  519. {
  520. PAGED_CODE();
  521. return(OrdinaryExchange->NoCopyFinalStatus);
  522. }
  523. UCHAR
  524. MRxSmbReadHandler_NoCopy (
  525. IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  526. IN ULONG BytesIndicated,
  527. IN ULONG BytesAvailable,
  528. OUT ULONG *pBytesTaken,
  529. IN PSMB_HEADER pSmbHeader,
  530. OUT PMDL *pDataBufferPointer,
  531. OUT PULONG pDataSize,
  532. #if DBG
  533. IN UCHAR ThisIsAReenter,
  534. #endif
  535. IN PRESP_READ_ANDX Response
  536. )
  537. /*++
  538. Routine Description:
  539. This routine causes the bytes from the message to be transferred to the user's
  540. buffer. In order to do this, it takes enough bytes from the indication and
  541. then crafts up an MDL to cause the transport to do the copy.
  542. Arguments:
  543. please refer to smbpse.c...the only place from which this may be called
  544. Return Value:
  545. UCHAR - a value representing the action that OE receive routine will perform.
  546. options are discard (in case of an error),
  547. copy_for_resume (never called after this is all debugged),
  548. and normal
  549. --*/
  550. {
  551. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  552. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  553. PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
  554. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  555. PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
  556. PBYTE UserBuffer,ExchangeBuffer;
  557. ULONG BytesReturned,DataOffset,CompressedDataBytesReturned = 0;
  558. ULONG UserBufferLength;
  559. ULONG StartingOffsetInUserBuffer;
  560. UCHAR ContinuationCode;
  561. RxDbgTrace(+1, Dbg, ("MRxSmbFinishReadNoCopy\n"));
  562. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishReadNoCopy:");
  563. rw->CompressedReadOrWrite = BooleanFlagOn(pSmbHeader->Flags2,SMB_FLAGS2_COMPRESSED);
  564. if (rw->CompressedReadOrWrite && !MRxSmbEnableCompression) {
  565. rw->CompressedReadOrWrite = FALSE;
  566. }
  567. UserBufferLength = MmGetMdlByteCount(OriginalDataMdl);
  568. UserBuffer = rw->UserBufferBase + rw->ThisBufferOffset;
  569. ExchangeBuffer = StufferState->BufferBase;
  570. switch (OrdinaryExchange->LastSmbCommand) {
  571. case SMB_COM_READ_ANDX:
  572. {
  573. if (Response->WordCount != 12) {
  574. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  575. ContinuationCode = SMBPSE_NOCOPYACTION_DISCARD;
  576. goto FINALLY;
  577. }
  578. BytesReturned = SmbGetUshort(&Response->DataLength);
  579. DataOffset = SmbGetUshort(&Response->DataOffset);
  580. if (rw->CompressedReadOrWrite) {
  581. rw->CompressedDataInfoLength = SmbGetUshort(&Response->CdiLength);
  582. CompressedDataBytesReturned = SmbGetUshort(&Response->ByteCount);
  583. }
  584. }
  585. if (DataOffset > sizeof(SMB_HEADER)+sizeof(RESP_READ_ANDX)) {
  586. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  587. ContinuationCode = SMBPSE_NOCOPYACTION_DISCARD;
  588. goto FINALLY;
  589. }
  590. break;
  591. case SMB_COM_READ:
  592. {
  593. PRESP_READ CoreResponse = (PRESP_READ)Response; //recast response for core read
  594. ASSERT(!rw->CompressedReadOrWrite);
  595. if (Response->WordCount != 5) {
  596. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  597. ContinuationCode = SMBPSE_NOCOPYACTION_DISCARD;
  598. goto FINALLY;
  599. }
  600. BytesReturned = SmbGetUshort(&CoreResponse->DataLength);
  601. DataOffset = sizeof(SMB_HEADER)+FIELD_OFFSET(RESP_READ,Buffer[0]);
  602. }
  603. break;
  604. }
  605. if ( BytesReturned > rw->ThisByteCount ) {
  606. //cut back if we got a bad response
  607. BytesReturned = rw->ThisByteCount;
  608. }
  609. RxDbgTrace(0, Dbg, ("-->ByteCount,Offset,Returned,DOffset,Buffer=%08lx/%08lx/%08lx/%08lx/%08lx\n",
  610. rw->ThisByteCount,
  611. rw->ThisBufferOffset,
  612. BytesReturned,DataOffset,UserBuffer
  613. ));
  614. OrdinaryExchange->ContinuationRoutine = MRxSmbFinishNoCopyRead;
  615. OrdinaryExchange->ReadWrite.BytesReturned = BytesReturned;
  616. // now, move the data to the user's buffer If enough is showing, just copy it in.
  617. if (rw->CompressedReadOrWrite) {
  618. // The compressed data needs to be copied such that an inplace decompress
  619. // can be attempted. In order to do so we exploit the fact that we have
  620. // a preallocated SMB buffer as part of the exchange which spans one chunk
  621. //
  622. // This is accomplished by copying the compressed data returned at an offset
  623. // greater than one chunk in the user buffer. The data returned from the
  624. // server is copied to the tail portion of the user buffer using the
  625. // preallocated buffer in the exchange if required.
  626. //
  627. // This leads to two possibilities
  628. //
  629. // 1) The compressed data returned from the server fits into
  630. // the preallocated buffer in the exchange
  631. //
  632. // or alternatively
  633. //
  634. // 2) the compressed data returned from the server spans the tail
  635. // portion of the user buffer and the preallocated buffer in the exchange
  636. rw->ExchangeBufferPortionLength = min(
  637. CompressedDataBytesReturned,
  638. OrdinaryExchange->SmbBufSize);
  639. rw->UserBufferPortionLength = CompressedDataBytesReturned -
  640. rw->ExchangeBufferPortionLength;
  641. StartingOffsetInUserBuffer = UserBufferLength -
  642. rw->UserBufferPortionLength;
  643. } else {
  644. StartingOffsetInUserBuffer = rw->ThisBufferOffset;
  645. rw->UserBufferPortionLength = BytesReturned;
  646. rw->ExchangeBufferPortionLength = 0;
  647. }
  648. if (BytesIndicated >= (DataOffset +
  649. rw->UserBufferPortionLength +
  650. rw->ExchangeBufferPortionLength)) {
  651. if (rw->CompressedReadOrWrite) {
  652. if (rw->UserBufferPortionLength > 0) {
  653. RtlCopyMemory(
  654. UserBuffer,
  655. ((PBYTE)pSmbHeader)+DataOffset,
  656. rw->UserBufferPortionLength);
  657. }
  658. if (rw->ExchangeBufferPortionLength > 0) {
  659. RtlCopyMemory(
  660. ExchangeBuffer,
  661. ((PBYTE)pSmbHeader) + DataOffset + rw->UserBufferPortionLength,
  662. rw->ExchangeBufferPortionLength);
  663. }
  664. } else {
  665. RtlCopyMemory(
  666. UserBuffer,
  667. ((PBYTE)pSmbHeader)+DataOffset,
  668. rw->UserBufferPortionLength);
  669. }
  670. *pBytesTaken = DataOffset +
  671. rw->UserBufferPortionLength +
  672. rw->ExchangeBufferPortionLength;
  673. RxDbgTrace(-1, Dbg, ("MRxSmbFinishReadNoCopy copy fork\n" ));
  674. ContinuationCode = SMBPSE_NOCOPYACTION_NORMALFINISH;
  675. } else {
  676. // otherwise, MDL it in. we use the smbbuf as an Mdl!
  677. if (BytesIndicated < DataOffset) {
  678. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  679. ContinuationCode = SMBPSE_NOCOPYACTION_DISCARD;
  680. goto FINALLY;
  681. }
  682. if (rw->UserBufferPortionLength > 0) {
  683. rw->PartialDataMdlInUse = TRUE;
  684. MmInitializeMdl(
  685. &rw->PartialDataMdl,
  686. 0,
  687. PAGE_SIZE + rw->UserBufferPortionLength);
  688. IoBuildPartialMdl(
  689. OriginalDataMdl,
  690. &rw->PartialDataMdl,
  691. (PCHAR)MmGetMdlVirtualAddress(OriginalDataMdl) + StartingOffsetInUserBuffer,
  692. rw->UserBufferPortionLength);
  693. }
  694. if (rw->ExchangeBufferPortionLength > 0) {
  695. rw->PartialExchangeMdlInUse = TRUE;
  696. MmInitializeMdl(
  697. &rw->PartialExchangeMdl,
  698. 0,
  699. PAGE_SIZE + rw->ExchangeBufferPortionLength);
  700. IoBuildPartialMdl(
  701. StufferState->HeaderMdl,
  702. &rw->PartialExchangeMdl,
  703. MmGetMdlVirtualAddress( StufferState->HeaderMdl ),
  704. rw->ExchangeBufferPortionLength);
  705. }
  706. if (rw->PartialDataMdlInUse) {
  707. if (rw->PartialExchangeMdlInUse) {
  708. rw->PartialDataMdl.Next = &rw->PartialExchangeMdl;
  709. }
  710. *pDataBufferPointer = &rw->PartialDataMdl;
  711. } else {
  712. *pDataBufferPointer = &rw->PartialExchangeMdl;
  713. }
  714. *pDataSize = rw->UserBufferPortionLength +
  715. rw->ExchangeBufferPortionLength;
  716. *pBytesTaken = DataOffset;
  717. RxDbgTrace(-1, Dbg, ("MRxSmbFinishReadNoCopy mdlcopy fork \n" ));
  718. ContinuationCode = SMBPSE_NOCOPYACTION_MDLFINISH;
  719. }
  720. FINALLY:
  721. return ContinuationCode;
  722. }
  723. NTSTATUS
  724. MRxSmbBuildReadRequest(
  725. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange)
  726. /*++
  727. Routine Description:
  728. This routine formats the appropriate type of read request issued to the
  729. server
  730. Arguments:
  731. OrdinaryExchange - the exchange instance encapsulating the information
  732. Return Value:
  733. STATUS_SUCCESS if successful
  734. --*/
  735. {
  736. NTSTATUS Status;
  737. UCHAR SmbCommand;
  738. ULONG SmbCommandSize;
  739. BOOLEAN CompressedReadRequest;
  740. ULONG OffsetLow,OffsetHigh;
  741. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  742. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(OrdinaryExchange);
  743. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  744. PSMBCE_NET_ROOT pNetRoot = SmbCeGetExchangeNetRoot(OrdinaryExchange);
  745. PMRX_V_NET_ROOT pVNetRoot = SmbCeGetExchangeVNetRoot(OrdinaryExchange);
  746. PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
  747. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  748. RxCaptureFcb;
  749. RxCaptureFobx;
  750. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  751. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  752. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  753. rw->ThisByteCount = min(rw->RemainingByteCount,pNetRoot->MaximumReadBufferSize);
  754. OffsetLow = rw->ByteOffsetAsLI.LowPart;
  755. OffsetHigh = rw->ByteOffsetAsLI.HighPart;
  756. CompressedReadRequest = FALSE;
  757. if (FlagOn(pServer->DialectFlags,DF_LANMAN10)) {
  758. SmbCommand = SMB_COM_READ_ANDX;
  759. SmbCommandSize = SMB_REQUEST_SIZE(NT_READ_ANDX);
  760. if (MRxSmbEnableCompression &&
  761. (pServer->Capabilities & COMPRESSED_DATA_CAPABILITY) &&
  762. (capFcb->Attributes & FILE_ATTRIBUTE_COMPRESSED) &&
  763. ((rw->ThisByteCount & 0xfff) == 0 ) &&
  764. ((rw->ByteOffsetAsLI.LowPart & 0xfff) == 0 )) {
  765. CompressedReadRequest = TRUE;
  766. }
  767. } else {
  768. SmbCommandSize = SMB_REQUEST_SIZE(READ);
  769. SmbCommand = SMB_COM_READ;
  770. }
  771. MRxSmbDumpStufferState(
  772. 1000,
  773. "SMB w/ READ before stuffing",
  774. StufferState);
  775. Status = MRxSmbStartSMBCommand (
  776. StufferState,
  777. SetInitialSMB_Never,
  778. SmbCommand,
  779. SmbCommandSize,
  780. NO_EXTRA_DATA,
  781. NO_SPECIAL_ALIGNMENT,
  782. RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  783. 0,0,0,0 STUFFERTRACE(Dbg,'FC'));
  784. if (Status != STATUS_SUCCESS) {
  785. return Status;
  786. }
  787. switch (SmbCommand) {
  788. case SMB_COM_READ:
  789. {
  790. // below, we just set mincount==maxcount. rdr1 did this.......
  791. MRxSmbStuffSMB (
  792. StufferState,
  793. "0wwdwB!",
  794. // 0 UCHAR WordCount;
  795. smbSrvOpen->Fid, // w _USHORT( Fid );
  796. rw->ThisByteCount, // w _USHORT( Count );
  797. OffsetLow, // d _ULONG( Offset );
  798. rw->RemainingByteCount, // w _USHORT( Remaining );
  799. // B! _USHORT( ByteCount );
  800. SMB_WCT_CHECK(5) 0
  801. // UCHAR Buffer[1];
  802. );
  803. }
  804. break;
  805. case SMB_COM_READ_ANDX:
  806. {
  807. PNT_SMB_HEADER NtSmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
  808. BOOLEAN UseNtVersion;
  809. ULONG Timeout = 0;
  810. if (pVNetRoot->pNetRoot->Type == NET_ROOT_PIPE) {
  811. Timeout = (ULONG)-1;
  812. }
  813. UseNtVersion = BooleanFlagOn(pServer->DialectFlags,DF_NT_SMBS);
  814. if (UseNtVersion &&
  815. FlagOn(
  816. LowIoContext->ParamsFor.ReadWrite.Flags,
  817. LOWIO_READWRITEFLAG_PAGING_IO)) {
  818. SmbPutAlignedUshort(
  819. &NtSmbHeader->Flags2,
  820. SmbGetAlignedUshort(&NtSmbHeader->Flags2) | SMB_FLAGS2_PAGING_IO );
  821. }
  822. if (UseNtVersion &&
  823. CompressedReadRequest) {
  824. SmbPutAlignedUshort(
  825. &NtSmbHeader->Flags2,
  826. SmbGetAlignedUshort(&NtSmbHeader->Flags2) | SMB_FLAGS2_COMPRESSED);
  827. }
  828. IF_NOT_MRXSMB_CSC_ENABLED{
  829. ASSERT(!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_OPEN_SURROGATED));
  830. } else {
  831. if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_OPEN_SURROGATED)) {
  832. SmbPutAlignedUshort(
  833. &NtSmbHeader->Flags2,
  834. SmbGetAlignedUshort(&NtSmbHeader->Flags2)|SMB_FLAGS2_PAGING_IO );
  835. }
  836. }
  837. // below, we just set mincount==maxcount. rdr1 did this.......
  838. MRxSmbStuffSMB (
  839. StufferState,
  840. "XwdwWdw",
  841. // X UCHAR WordCount;
  842. // UCHAR AndXCommand;
  843. // UCHAR AndXReserved;
  844. // _USHORT( AndXOffset );
  845. smbSrvOpen->Fid, // w _USHORT( Fid );
  846. OffsetLow, // d _ULONG( Offset );
  847. rw->ThisByteCount, // w _USHORT( MaxCount );
  848. SMB_OFFSET_CHECK(READ_ANDX,MinCount)
  849. rw->ThisByteCount, // W _USHORT( MinCount );
  850. Timeout, // d _ULONG( Timeout );
  851. rw->RemainingByteCount, // w _USHORT( Remaining );
  852. StufferCondition(UseNtVersion), "D",
  853. SMB_OFFSET_CHECK(NT_READ_ANDX,OffsetHigh)
  854. OffsetHigh, // D NTonly _ULONG( OffsetHigh );
  855. //
  856. STUFFER_CTL_NORMAL, "B!",
  857. // B! _USHORT( ByteCount );
  858. SMB_WCT_CHECK(((UseNtVersion)?12:10)) 0
  859. // UCHAR Buffer[1];
  860. );
  861. }
  862. break;
  863. default:
  864. break;
  865. }
  866. if (Status == STATUS_SUCCESS) {
  867. MRxSmbDumpStufferState(
  868. 700,
  869. "SMB w/ READ after stuffing",
  870. StufferState);
  871. InterlockedIncrement(&MRxSmbStatistics.SmallReadSmbs);
  872. }
  873. return Status;
  874. }
  875. #if DBG
  876. VOID
  877. MRxSmbValidateCompressedDataInfo(
  878. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange)
  879. /*++
  880. Routine Description:
  881. This routine validated the Compressed data info structure returned from the
  882. server
  883. Arguments:
  884. OrdinaryExchange - the exchange instance encapsulating the information
  885. --*/
  886. {
  887. PSMBCE_NET_ROOT pNetRoot;
  888. PSMB_PSE_OE_READWRITE rw;
  889. PCOMPRESSED_DATA_INFO pCompressedDataInfo;
  890. ULONG RequestedReadLength,CompressedDataLength;
  891. ULONG NumberOfChunks,ChunkSize;
  892. USHORT i;
  893. pNetRoot = SmbCeGetExchangeNetRoot(OrdinaryExchange);
  894. rw = &OrdinaryExchange->ReadWrite;
  895. pCompressedDataInfo = &rw->CompressedDataInfo;
  896. RequestedReadLength = rw->ThisByteCount;
  897. if ((pCompressedDataInfo->ChunkShift == 0) ||
  898. (pCompressedDataInfo->ClusterShift == 0) ||
  899. (pCompressedDataInfo->CompressionUnitShift == 0)) {
  900. DbgPrint("Invalid CDI:%lx\n",pCompressedDataInfo);
  901. //DbgBreakPoint();
  902. }
  903. ChunkSize = (1 << pCompressedDataInfo->ChunkShift);
  904. if (ChunkSize == 0) {
  905. DbgPrint("CDI: %lx Invalid Chunk Size\n",pCompressedDataInfo);
  906. //DbgBreakPoint();
  907. }
  908. NumberOfChunks = RequestedReadLength / ChunkSize;
  909. if ((pCompressedDataInfo->NumberOfChunks == 0) ||
  910. (pCompressedDataInfo->NumberOfChunks > NumberOfChunks)){
  911. DbgPrint("CDI: %lx, Invalid number Of Chunks returned\n",pCompressedDataInfo);
  912. }
  913. CompressedDataLength = 0;
  914. for (i = 0; i < pCompressedDataInfo->NumberOfChunks; i++) {
  915. CompressedDataLength += pCompressedDataInfo->CompressedChunkSizes[i];
  916. }
  917. if (CompressedDataLength > RequestedReadLength) {
  918. DbgPrint("CDI: %lx, More data returned than requested\n",pCompressedDataInfo);
  919. //DbgBreakPoint();
  920. }
  921. }
  922. #endif
  923.