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.

791 lines
24 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. bulk.c
  5. Abstract:
  6. This module implements the mini redirector call down routines pertaining
  7. to bulk reads of file system objects.
  8. Author:
  9. Rod Gamache [rodga] 19-June-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #define Dbg (DEBUG_TRACE_READ)
  15. #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, ProcessReadBulkCompressed)
  18. #pragma alloc_text(PAGE, MRxSmbBuildReadBulk)
  19. #pragma alloc_text(PAGE, MRxSmbReadBulkContinuation)
  20. #endif
  21. VOID
  22. ProcessReadBulkCompressed (
  23. IN PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  24. OUT PMDL *pDataBufferPointer,
  25. IN ULONG Remain
  26. )
  27. /*++
  28. Routine Description:
  29. This routine processes a read bulk compressed message.
  30. Inputs:
  31. OrdinaryExchange - The exchange instance.
  32. pDataBufferPointer - Pointer to an RX_MEM_DESC (MDL) to receive data into.
  33. Remain - bytes remaining to send (compressed or uncompressed).
  34. Returns:
  35. NONE.
  36. Notes:
  37. If the data all fits in the SMB buffer and it's a primary response, then
  38. use the HeaderMdl to receive the data, since it points at the SMB buffer.
  39. If the data doesn't all fit, but what's left fits in the SMB buffer, then
  40. use the HeaderMdl again.
  41. Lastly, we will build a partial mdl mapping the user buffer, and chain
  42. on the PartialHeaderMdl for the remainder.
  43. --*/
  44. {
  45. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  46. PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
  47. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  48. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  49. ULONG CopyBufferLength = rw->CompressedByteCount;
  50. ULONG startOffset;
  51. ULONG partialLength;
  52. ULONG lengthNeeded;
  53. PMDL userMdl;
  54. PMDL curMdl;
  55. PMDL HeaderMdl;
  56. PMDL SubmitMdl;
  57. PCHAR startVa;
  58. //
  59. // We should appear later in FinishReadBulk (BULK.C) to actually
  60. // do the decompression.
  61. //
  62. //
  63. // Use all of the header mdl (including data buffer) for the
  64. // compressed data receive.
  65. //
  66. PAGED_CODE();
  67. HeaderMdl = StufferState->HeaderMdl;
  68. ASSERT( MmGetMdlByteCount( HeaderMdl ) >= 0x1000 );
  69. //CODE.IMPROVEMENT for 4KB (0x1000) above!
  70. //
  71. // We cannot use the HeaderPartialMdl, since it may still be in use
  72. // by the last transmit.
  73. //
  74. SubmitMdl = rw->CompressedTailMdl;
  75. //
  76. // Get the user's buffer mdl. We'll use the back part of this mdl (if
  77. // needed) for part of the receive data.
  78. //
  79. userMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
  80. ASSERT( userMdl != NULL );
  81. partialLength = MmGetMdlByteCount( userMdl );
  82. ASSERT( LowIoContext->ParamsFor.ReadWrite.ByteCount <= partialLength );
  83. //
  84. // If all of the data fits in the Header Mdl (which we put last) and
  85. // this is the first message then use the Header Mdl.
  86. //
  87. if ( ( OrdinaryExchange->SmbBufSize >= (CopyBufferLength + Remain) ) &&
  88. ( rw->Flags & READ_BULK_COMPRESSED_DATA_INFO ) ) {
  89. //
  90. // The data will all fit in the Header Mdl.
  91. //
  92. IoBuildPartialMdl(
  93. HeaderMdl,
  94. SubmitMdl,
  95. MmGetMdlVirtualAddress( HeaderMdl ),
  96. CopyBufferLength );
  97. rw->BulkOffset = 0;
  98. //
  99. // If there is data remaining (we expect a secondary message),
  100. // then prepare for that case.
  101. //
  102. if ( Remain ) {
  103. rw->PartialBytes = partialLength + CopyBufferLength;
  104. }
  105. *pDataBufferPointer = SubmitMdl;
  106. } else {
  107. //
  108. // Build a partial mdl from the HeaderMdl. We'll need all of this
  109. // mdl for receiving the data.
  110. //
  111. IoBuildPartialMdl(
  112. HeaderMdl,
  113. SubmitMdl,
  114. MmGetMdlVirtualAddress( HeaderMdl ),
  115. OrdinaryExchange->SmbBufSize );
  116. //
  117. // Generate a partial mdl based on the user's buffer mdl. We'll use
  118. // the back part of this mdl (if needed) for part of the receive data.
  119. //
  120. //
  121. // In order to know where to start receiving data, we need to know if
  122. // this is a secondary response. If this is the primary response, then
  123. // just calculate the correct position in the user buffer to receive
  124. // the data. Otherwise, for secondary responses, we need to continue
  125. // where we left off from the primary response.
  126. //
  127. if ( rw->Flags & READ_BULK_COMPRESSED_DATA_INFO ) {
  128. //
  129. // This is a primary response.
  130. //
  131. //
  132. // Calculate starting offset from start of user buffer.
  133. //
  134. startOffset = partialLength +
  135. OrdinaryExchange->SmbBufSize -
  136. rw->ThisBufferOffset -
  137. (CopyBufferLength + Remain);
  138. ASSERT( startOffset <= partialLength );
  139. //
  140. // Save the offset to start of CDI, and displacement for next
  141. // read. The start offset cannot be zero! If it is, then where
  142. // could we decompress into!
  143. //
  144. ASSERT( startOffset != 0 );
  145. rw->BulkOffset = startOffset;
  146. rw->PartialBytes = CopyBufferLength;
  147. } else {
  148. //
  149. // This is a secondary response.
  150. //
  151. ASSERT( rw->BulkOffset != 0 );
  152. //
  153. // Calculate next read address, and bump displacement.
  154. //
  155. startOffset = rw->BulkOffset + rw->PartialBytes;
  156. rw->PartialBytes += CopyBufferLength;
  157. //
  158. // If we have crossed over the user mdl and are now using the
  159. // exchange buffer, then we just need to figure out how much
  160. // of the exchange buffer we need to use. This will only happen
  161. // if the last fragment is around 4KB, but the original request
  162. // was bigger than 64KB (ie what we can fit in a single fragment).
  163. // So this should not happen very often.
  164. //
  165. if ( startOffset > partialLength ) {
  166. startOffset -= partialLength;
  167. partialLength = MmGetMdlByteCount( SubmitMdl );
  168. //
  169. // Calculate length needed from exchange buffer.
  170. //
  171. lengthNeeded = partialLength - startOffset;
  172. *pDataBufferPointer = SubmitMdl;
  173. //
  174. // Build the partial mdl.
  175. //
  176. startVa = (PCHAR)MmGetMdlVirtualAddress( SubmitMdl ) + startOffset;
  177. IoBuildPartialMdl(
  178. HeaderMdl,
  179. SubmitMdl,
  180. startVa,
  181. lengthNeeded );
  182. SubmitMdl->Next = NULL;
  183. return;
  184. }
  185. }
  186. //
  187. // Calculate length needed from user portion of Mdl.
  188. //
  189. lengthNeeded = partialLength - (startOffset + rw->ThisBufferOffset);
  190. lengthNeeded = MIN( lengthNeeded, CopyBufferLength);
  191. //
  192. // Get the temp mdl
  193. //
  194. curMdl = (PMDL)((PCHAR)rw->BulkBuffer + COMPRESSED_DATA_INFO_SIZE);
  195. *pDataBufferPointer = curMdl;
  196. //
  197. // Build the partial mdl chain.
  198. //
  199. startVa = (PCHAR)MmGetMdlVirtualAddress( userMdl ) +
  200. startOffset +
  201. rw->ThisBufferOffset;
  202. IoBuildPartialMdl(
  203. userMdl,
  204. curMdl,
  205. startVa,
  206. lengthNeeded );
  207. //
  208. // Link the submit mdl into the partial we just built.
  209. //
  210. curMdl->Next = SubmitMdl;
  211. }
  212. SubmitMdl->Next = NULL;
  213. } // ProcessReadBulkCompressed
  214. NTSTATUS
  215. MRxSmbBuildReadBulk (
  216. PSMBSTUFFER_BUFFER_STATE StufferState,
  217. PLARGE_INTEGER ByteOffsetAsLI,
  218. ULONG ByteCount,
  219. ULONG MaxMessageSize,
  220. BOOLEAN Compressed
  221. )
  222. /*++
  223. Routine Description:
  224. This routine builds a ReadBulk SMB. We don't have to worry about login id
  225. and such since that is done by the connection engine....pretty neat huh?
  226. All we have to do is to format up the bits.
  227. DOWNLEVEL This routine only works with the ntreadandX.
  228. Arguments:
  229. StufferState - the state of the smbbuffer from the stuffer's point of view
  230. Return Value:
  231. NTSTATUS
  232. SUCCESS
  233. NOT_IMPLEMENTED something in the arguments can't be handled.
  234. Notes:
  235. --*/
  236. {
  237. NTSTATUS Status;
  238. PRX_CONTEXT RxContext = StufferState->RxContext;
  239. RxCaptureFcb;RxCaptureFobx;
  240. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  241. PNT_SMB_HEADER NtSmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
  242. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  243. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  244. ULONG OffsetLow,OffsetHigh;
  245. UCHAR RequestCompressed;
  246. PAGED_CODE();
  247. RxDbgTrace(+1, Dbg, ("MRxSmbBuildReadBulk\n", 0 ));
  248. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  249. RequestCompressed = ( Compressed ? CompressionTechnologyOne :
  250. CompressionTechnologyNone );
  251. OffsetLow = ByteOffsetAsLI->LowPart;
  252. OffsetHigh = ByteOffsetAsLI->HighPart;
  253. COVERED_CALL(
  254. MRxSmbStartSMBCommand (
  255. StufferState,
  256. SetInitialSMB_Never,
  257. SMB_COM_READ_BULK,
  258. SMB_REQUEST_SIZE(READ_BULK),
  259. NO_EXTRA_DATA,
  260. NO_SPECIAL_ALIGNMENT,
  261. RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  262. 0,0,0,0 STUFFERTRACE(Dbg,'FC')) );
  263. RxDbgTrace(0, Dbg,("Bulk Read status = %lu\n",Status));
  264. MRxSmbDumpStufferState (1000,"SMB w/ READ_BULK before stuffing",StufferState);
  265. if ( FlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,LOWIO_READWRITEFLAG_PAGING_IO)) {
  266. SmbPutAlignedUshort(
  267. &NtSmbHeader->Flags2,
  268. SmbGetAlignedUshort(&NtSmbHeader->Flags2)|SMB_FLAGS2_PAGING_IO );
  269. }
  270. MRxSmbStuffSMB (StufferState,
  271. "0wwDddddB!",
  272. // 0 UCHAR WordCount; // Count of parameter words = 12
  273. smbSrvOpen->Fid, // w USHORT Fid; // File Id
  274. RequestCompressed, // w USHORT CompressionTechnology; // CompressionTechnology
  275. SMB_OFFSET_CHECK(READ_BULK, Offset)
  276. OffsetLow, OffsetHigh, // Dd LARGE_INTEGER Offset; // Offsetin file to begin read
  277. ByteCount, // d ULONG MaxCount; // Max number of bytes to return
  278. 0, // d ULONG MinCount;
  279. // Min number of bytes to return
  280. MaxMessageSize, // d ULONG MessageSize;
  281. // Max number of bytes to send per message
  282. // B USHORT ByteCount; // Count of data bytes = 0
  283. SMB_WCT_CHECK(12) 0
  284. // UCHAR Buffer[1]; // empty
  285. );
  286. MRxSmbDumpStufferState (700,"SMB w/ READ_BULK after stuffing",StufferState);
  287. FINALLY:
  288. RxDbgTraceUnIndent(-1, Dbg);
  289. return Status;
  290. } // MRxSmbBuildReadBulk
  291. NTSTATUS
  292. MRxSmbReadBulkContinuation(
  293. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange)
  294. /*++
  295. Routine Description:
  296. This routine decompresses the read data if needed.
  297. Arguments:
  298. OrdinaryExchange - the exchange instance
  299. Return Value:
  300. NTSTATUS - The return status for the operation
  301. --*/
  302. {
  303. PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
  304. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  305. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  306. PAGED_CODE();
  307. RxDbgTrace(+1, Dbg, ("MRxSmbReadBulkContinuation\n"));
  308. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbReadBulkContinuation:");
  309. ASSERT( CompressionTechnologyNone == 0 );
  310. if ( (OrdinaryExchange->Status == RX_MAP_STATUS(SUCCESS)) &&
  311. (rw->CompressionTechnology) ) {
  312. //
  313. // The data is compressed.
  314. //
  315. //CODE.IMPROVEMENT we should get the Mdls directly from the OE instead the StffState
  316. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  317. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  318. ULONG lengthNeeded;
  319. ULONG partialLength;
  320. PMDL mdl;
  321. PUCHAR cdiBuffer;
  322. PUCHAR startVa1, startVa2;
  323. ULONG length1, length2;
  324. //
  325. // Clean up any mappings for the TailMdl
  326. //
  327. MmPrepareMdlForReuse( rw->CompressedTailMdl );
  328. //
  329. // First, we must copy the CompressionDataInfo to a safe place!
  330. //
  331. lengthNeeded = rw->DataOffset;
  332. ASSERT( lengthNeeded <= COMPRESSED_DATA_INFO_SIZE );
  333. ASSERT( lengthNeeded >= 0xC );
  334. cdiBuffer = rw->BulkBuffer;
  335. //
  336. // The Mdl chain should consist of two pieces - one describing
  337. // the uncompressed buffer (in-place decompress), and one
  338. // describing the tail (at least a compression unit). Get
  339. // their addresses and lengths now.
  340. //
  341. // If we used the Header Mdl to receive all of the data, then there
  342. // is not second mdl.
  343. //
  344. if ( rw->BulkOffset == 0 ) {
  345. //
  346. // The mdl used was the CompressedTailMdl.
  347. //
  348. mdl = rw->CompressedTailMdl;
  349. startVa1 = (PCHAR)MmGetSystemAddressForMdlSafe(mdl,LowPagePriority);
  350. length1 = MmGetMdlByteCount( mdl );
  351. startVa2 = NULL;
  352. length2 = 0;
  353. } else {
  354. //
  355. // The first mdl is the user's buffer mdl.
  356. // The second mdl is the header mdl (all of it!).
  357. // The BulkOffset is from the start of the user's buffer mdl.
  358. //
  359. mdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
  360. startVa1 = (PCHAR)rw->UserBufferBase + rw->BulkOffset + rw->ThisBufferOffset;
  361. length1 = MmGetMdlByteCount( mdl ) - (rw->BulkOffset + rw->ThisBufferOffset);
  362. startVa2 = (PCHAR)MmGetSystemAddressForMdlSafe(StufferState->HeaderMdl,LowPagePriority);
  363. length2 = MmGetMdlByteCount( StufferState->HeaderMdl );
  364. }
  365. //
  366. // The CompressionDataInfo could span multiple mdl's!
  367. //
  368. do {
  369. ASSERT( mdl != NULL );
  370. partialLength = MIN( length1, lengthNeeded );
  371. RtlCopyMemory( cdiBuffer, startVa1, partialLength );
  372. cdiBuffer += partialLength;
  373. startVa1 += partialLength;
  374. mdl = mdl->Next;
  375. lengthNeeded -= partialLength;
  376. length1 -= partialLength;
  377. if (length1 == 0) {
  378. startVa1 = startVa2;
  379. length1 = length2;
  380. startVa2 = NULL;
  381. length2 = 0;
  382. }
  383. } while ( lengthNeeded != 0 );
  384. Status = RtlDecompressChunks(
  385. (PCHAR)rw->UserBufferBase + rw->ThisBufferOffset,
  386. LowIoContext->ParamsFor.ReadWrite.ByteCount,
  387. startVa1,
  388. length1,
  389. startVa2,
  390. length2,
  391. (PCOMPRESSED_DATA_INFO)rw->BulkBuffer );
  392. if (Status == STATUS_SUCCESS) {
  393. rw->BytesReturned = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  394. rw->RemainingByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  395. }
  396. }
  397. if ( rw->CompressedRequest ) {
  398. ASSERT( rw->BulkBuffer != NULL );
  399. RxFreePool( rw->BulkBuffer );
  400. IF_DEBUG rw->BulkBuffer = NULL;
  401. }
  402. RxDbgTrace(-1, Dbg, ("MRxSmbReadBulkContinuation returning %08lx\n", Status ));
  403. return Status;
  404. } // MRxSmbReadBulkContinuation
  405. UCHAR
  406. MRxSmbBulkReadHandler_NoCopy (
  407. IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  408. IN ULONG BytesIndicated,
  409. IN ULONG BytesAvailable,
  410. OUT ULONG *pBytesTaken,
  411. IN PSMB_HEADER pSmbHeader,
  412. OUT PMDL *pDataBufferPointer,
  413. OUT PULONG pDataSize,
  414. #if DBG
  415. IN UCHAR ThisIsAReenter,
  416. #endif
  417. IN PRESP_READ_ANDX Response
  418. )
  419. /*++
  420. Routine Description:
  421. This routine causes the bytes from the message to be transferred to the user's
  422. buffer. In order to do this, it takes enough bytes from the indication and
  423. then crafts up an MDL to cause the transport to do the copy.
  424. Arguments:
  425. please refer to smbpse.c...the only place from which this may be called
  426. Return Value:
  427. UCHAR - a value representing the action that OE receive routine will perform.
  428. options are discard (in case of an error), and normal
  429. --*/
  430. {
  431. NTSTATUS SmbStatus;
  432. ULONG ByteCount;
  433. ULONG Remain;
  434. ULONG CopyBufferLength;
  435. PGENERIC_ANDX CommandState;
  436. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  437. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  438. PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
  439. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  440. PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
  441. PCHAR startVa;
  442. PBYTE Buffer;
  443. ULONG BytesReturned,DataOffset;
  444. PMDL ReadMdl;
  445. PRESP_READ_BULK ReadBulkResponse;
  446. RxDbgTrace(+1, Dbg, ("MRxSmbFinishReadNoCopy\n"));
  447. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishReadNoCopy:");
  448. SmbStatus = OrdinaryExchange->SmbStatus;
  449. ReadBulkResponse = (PRESP_READ_BULK)(pSmbHeader + 1 );
  450. CommandState = &OrdinaryExchange->ParseResumeState;
  451. ASSERT( (OrdinaryExchange->OEType == SMBPSE_OETYPE_READ) );
  452. LowIoContext = &RxContext->LowIoContext;
  453. ASSERT( LowIoContext->ParamsFor.ReadWrite.Buffer != NULL );
  454. ASSERT( LowIoContext->ParamsFor.ReadWrite.ByteCount != 0 );
  455. //
  456. // Make sure we can at least read the smb header!
  457. //
  458. ASSERT( BytesIndicated >= sizeof(SMB_HEADER) +
  459. FIELD_OFFSET(RESP_READ_BULK, Buffer) );
  460. ReadBulkResponse = (PRESP_READ_BULK)(pSmbHeader + 1 );
  461. //
  462. // Get the count of bytes 'covered' by this message. This is the
  463. // number of bytes the user expects to see.
  464. //
  465. ByteCount = SmbGetUlong( &ReadBulkResponse->Count );
  466. Remain = SmbGetUlong( &ReadBulkResponse->Remaining );
  467. rw->Flags = ReadBulkResponse->Flags;
  468. rw->CompressionTechnology = ReadBulkResponse->CompressionTechnology;
  469. //
  470. // Now get the actual number of data bytes in this message.
  471. // Remember, the data may be compressed, so this total could
  472. // be less than the 'Count' field above.
  473. //
  474. CopyBufferLength = SmbGetUlong( &ReadBulkResponse->DataCount );
  475. //
  476. // If CompressionTechnology is not zero then the data is compressed
  477. // otherwise the data is uncompressed.
  478. //
  479. if ( rw->CompressionTechnology == CompressionTechnologyNone ) {
  480. //
  481. // The data is not compressed!
  482. //
  483. ASSERT( rw->Flags == 0 ); // no flags should be on
  484. //
  485. // Set up to get the data into the user's buffer.
  486. // CODE.IMPROVEMENT -we need to be able to cancel this big read!
  487. //
  488. // If ThisBufferOffset is non-zero or BytesReturned is non-zero,
  489. // then we have to partial the data back into the user's buffer.
  490. // Also if the data lengths don't match - is this needed?
  491. // Otherwise, can can take the whole user's buffer.
  492. //
  493. if ( rw->ThisBufferOffset || rw->BytesReturned ||
  494. CopyBufferLength != LowIoContext->ParamsFor.ReadWrite.ByteCount ) {
  495. //
  496. // We should NOT get any mdl chains!
  497. //
  498. ASSERT( LowIoContext->ParamsFor.ReadWrite.Buffer->Next == NULL );
  499. //
  500. // CopyBufferLength will be zero if we tried to read beyond
  501. // end of file!
  502. //
  503. if ( CopyBufferLength != 0 ) {
  504. //
  505. // Partial the data into the user's buffer.
  506. //
  507. startVa = MmGetMdlVirtualAddress(
  508. LowIoContext->ParamsFor.ReadWrite.Buffer);
  509. startVa += rw->ThisBufferOffset + rw->BulkOffset;
  510. rw->BulkOffset += CopyBufferLength;
  511. ASSERT( OrdinaryExchange->DataPartialMdl != NULL );
  512. *pDataBufferPointer = OrdinaryExchange->DataPartialMdl;
  513. MmPrepareMdlForReuse( OrdinaryExchange->DataPartialMdl );
  514. ASSERT( CopyBufferLength <= MAXIMUM_PARTIAL_BUFFER_SIZE);
  515. ASSERT( CopyBufferLength <= ByteCount );
  516. IoBuildPartialMdl(
  517. LowIoContext->ParamsFor.ReadWrite.Buffer,
  518. OrdinaryExchange->DataPartialMdl,
  519. startVa,
  520. CopyBufferLength);
  521. }
  522. } else {
  523. //
  524. // We can take the whole buffer.
  525. //
  526. *pDataBufferPointer = LowIoContext->ParamsFor.ReadWrite.Buffer;
  527. }
  528. //
  529. // Take bytes up to the start of the actual data.
  530. //
  531. *pBytesTaken = sizeof(SMB_HEADER) +
  532. FIELD_OFFSET(RESP_READ_BULK, Buffer) +
  533. (ULONG)SmbGetUshort(&ReadBulkResponse->DataOffset);
  534. ASSERT( BytesAvailable >= *pBytesTaken );
  535. } else {
  536. //
  537. // The data is compressed. We need to do more work to get the
  538. // data into the correct position within the buffer.
  539. //
  540. //
  541. // If this is a primary response, then save DataOffset.
  542. //
  543. if ( rw->Flags & READ_BULK_COMPRESSED_DATA_INFO ) {
  544. rw->DataOffset = SmbGetUshort( &ReadBulkResponse->DataOffset );
  545. ASSERT( *((PCHAR)ReadBulkResponse + FIELD_OFFSET(RESP_READ_BULK, Buffer) ) == COMPRESSION_FORMAT_LZNT1 );
  546. }
  547. rw->CompressedByteCount = CopyBufferLength;
  548. ProcessReadBulkCompressed(
  549. OrdinaryExchange,
  550. pDataBufferPointer,
  551. Remain );
  552. //
  553. // Take bytes up to the start of the actual data.
  554. //
  555. *pBytesTaken = sizeof(SMB_HEADER) +
  556. FIELD_OFFSET(RESP_READ_BULK, Buffer);
  557. ASSERT( BytesAvailable >= *pBytesTaken );
  558. }
  559. // Setup to execute the finish routine when done. We'll do the
  560. // decompression at that time (if needed).
  561. OrdinaryExchange->ContinuationRoutine = MRxSmbReadBulkContinuation;
  562. //
  563. // Reduce the number of bytes expected. If we expect more, then
  564. // put down another receive.
  565. //
  566. rw->BytesReturned += CopyBufferLength;
  567. rw->ThisByteCount = Remain;
  568. if (Remain != 0) {
  569. if ( rw->ThisByteCount ) {
  570. OrdinaryExchange->Status = SmbCeReceive((PSMB_EXCHANGE)OrdinaryExchange );
  571. }
  572. }
  573. //
  574. // Tell the VC handler that we need the following bytes read
  575. // and copied to the user's buffer.
  576. //
  577. *pDataSize = CopyBufferLength;
  578. OrdinaryExchange->OpSpecificFlags |= OE_RW_FLAG_SUCCESS_IN_COPYHANDLER;
  579. if ( CopyBufferLength != 0 ) {
  580. OrdinaryExchange->ParseResumeState = *CommandState;
  581. }
  582. RxDbgTrace(-1, Dbg, ("MRxSmbFinishReadNoCopy mdlcopy fork \n" ));
  583. return SMBPSE_NOCOPYACTION_MDLFINISH;
  584. }
  585.