Windows NT 4.0 source code leak
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.

3220 lines
88 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. smbraw.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs in
  7. the server FSP:
  8. Read Block Raw
  9. Write Block Raw
  10. The routines in this module generally work closely with the routines
  11. in fsdraw.c.
  12. *** There is no support here for raw writes from MS-NET 1.03 clients.
  13. There are very few of these machines in existence, and raw mode
  14. is only a performance issue, so it is not worth the trouble to
  15. add the necessary hacks for MS-NET 1.03, which sends raw write
  16. requests in a different format.
  17. Author:
  18. Chuck Lenzmeier (chuckl) 8-Sep-1990
  19. Manny Weiser (mannyw)
  20. David Treadwell (davidtr)
  21. Revision History:
  22. --*/
  23. #include "precomp.h"
  24. #pragma hdrstop
  25. #define BugCheckFileId SRV_FILE_SMBRAW
  26. //
  27. // Forward declarations
  28. //
  29. VOID SRVFASTCALL
  30. AbortRawWrite(
  31. IN OUT PWORK_CONTEXT WorkContext
  32. );
  33. VOID SRVFASTCALL
  34. PrepareRawCopyWrite (
  35. IN OUT PWORK_CONTEXT WorkContext
  36. );
  37. BOOLEAN SRVFASTCALL
  38. ReadRawPipe (
  39. IN PWORK_CONTEXT WorkContext
  40. );
  41. VOID SRVFASTCALL
  42. RestartMdlReadRawResponse (
  43. IN OUT PWORK_CONTEXT WorkContext
  44. );
  45. VOID SRVFASTCALL
  46. RestartPipeReadRawPeek (
  47. IN OUT PWORK_CONTEXT WorkContext
  48. );
  49. #ifdef ALLOC_PRAGMA
  50. #ifndef SLMDBG
  51. #pragma alloc_text( PAGE, SrvSmbWriteRaw )
  52. #endif
  53. #pragma alloc_text( PAGE, AbortRawWrite )
  54. #pragma alloc_text( PAGE, PrepareRawCopyWrite )
  55. #pragma alloc_text( PAGE, ReadRawPipe )
  56. #pragma alloc_text( PAGE, RestartMdlReadRawResponse )
  57. #pragma alloc_text( PAGE, RestartPipeReadRawPeek )
  58. #pragma alloc_text( PAGE, SrvRestartRawReceive )
  59. #pragma alloc_text( PAGE, SrvRestartReadRawComplete )
  60. #pragma alloc_text( PAGE, SrvRestartWriteCompleteResponse )
  61. #pragma alloc_text( PAGE, SrvBuildAndSendWriteCompleteResponse )
  62. #endif
  63. #if 0
  64. NOT PAGEABLE -- DumpMdlChain
  65. NOT PAGEABLE -- SrvSmbReadRaw
  66. NOT PAGEABLE -- SrvDecrementRawWriteCount
  67. #endif
  68. #if DBG
  69. VOID
  70. DumpMdlChain(
  71. IN PMDL mdl
  72. )
  73. {
  74. ULONG mdlCount = 0;
  75. ULONG length = 0;
  76. if ( mdl == NULL ) {
  77. KdPrint(( " <empty MDL chain>\n" ));
  78. return;
  79. }
  80. do {
  81. KdPrint(( " mdl %08x len %04x flags %04x sysva %08x va %08x offset %04x\n",
  82. mdl, mdl->ByteCount, mdl->MdlFlags,
  83. mdl->MappedSystemVa, mdl->StartVa, mdl->ByteOffset ));
  84. length += mdl->ByteCount;
  85. mdlCount++;
  86. mdl = mdl->Next;
  87. } while ( mdl != NULL );
  88. KdPrint(( " total of %ld bytes in %ld MDLs\n", length, mdlCount ));
  89. return;
  90. }
  91. #endif
  92. SMB_PROCESSOR_RETURN_TYPE
  93. SrvSmbReadRaw (
  94. SMB_PROCESSOR_PARAMETERS
  95. )
  96. /*++
  97. Routine Description:
  98. Processes the Read Block Raw SMB.
  99. Note that Read Block Raw cannot return an error response. When the
  100. server is unable to process the request, for whatever reason, it
  101. simply responds with a zero-length message. The client uses a
  102. normal Read SMB to determine what happened.
  103. Arguments:
  104. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description of the
  105. parameters to SMB processor routines.
  106. Return Value:
  107. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  108. --*/
  109. {
  110. PREQ_READ_RAW request;
  111. PREQ_NT_READ_RAW ntRequest;
  112. NTSTATUS status;
  113. USHORT fid;
  114. PRFCB rfcb;
  115. PLFCB lfcb;
  116. PCONNECTION connection;
  117. UCHAR minorFunction = 0;
  118. PVOID rawBuffer = NULL;
  119. CLONG readLength;
  120. PMDL mdl = NULL;
  121. ULONG key;
  122. LARGE_INTEGER offset;
  123. SHARE_TYPE shareType;
  124. KIRQL oldIrql;
  125. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawReadsAttempted );
  126. request = (PREQ_READ_RAW)WorkContext->RequestParameters;
  127. fid = SmbGetUshort( &request->Fid );
  128. IF_SMB_DEBUG(RAW1) {
  129. KdPrint(( "Read Block Raw request; FID 0x%lx, count %ld, "
  130. "offset %ld\n",
  131. fid, SmbGetUshort( &request->MaxCount ),
  132. SmbGetUlong( &request->Offset ) ));
  133. }
  134. //
  135. // If raw mode has been disabled or if the connection is unreliable,
  136. // reject the raw read. Ask the client to use standard read by
  137. // sending a zero-length response. The client will react by issuing
  138. // a normal Read SMB, which we will be able to process.
  139. //
  140. connection = WorkContext->Connection;
  141. if ( !SrvEnableRawMode || !connection->EnableRawIo ) {
  142. IF_SMB_DEBUG(RAW1) {
  143. KdPrint(( "SrvSmbReadRaw: Raw mode is disabled\n" ));
  144. }
  145. goto error_exit_no_cleanup;
  146. }
  147. //
  148. // Get the rfcb
  149. //
  150. //
  151. // Acquire the spin lock that guards the connection's file table.
  152. //
  153. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  154. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock );
  155. if ( connection->CachedFid == fid ) {
  156. rfcb = connection->CachedRfcb;
  157. } else {
  158. PTABLE_HEADER tableHeader;
  159. CSHORT index;
  160. USHORT sequence;
  161. //
  162. // Initialize local variables: obtain the connection block address
  163. // and crack the FID into its components.
  164. //
  165. index = FID_INDEX( fid );
  166. sequence = FID_SEQUENCE( fid );
  167. //
  168. // Verify that the FID is in range, is in use, and has the correct
  169. // sequence number.
  170. tableHeader = &connection->FileTable;
  171. if ( (index >= (CSHORT)tableHeader->TableSize) ||
  172. (tableHeader->Table[index].Owner == NULL) ||
  173. (tableHeader->Table[index].SequenceNumber != sequence) ) {
  174. goto error_exit_no_cleanup_locked;
  175. }
  176. rfcb = tableHeader->Table[index].Owner;
  177. if ( GET_BLOCK_STATE(rfcb) != BlockStateActive ) {
  178. goto error_exit_no_cleanup_locked;
  179. }
  180. //
  181. // If there is a write behind error, reject the raw read.
  182. //
  183. if ( !NT_SUCCESS(rfcb->SavedError) ) {
  184. goto error_exit_no_cleanup_locked;
  185. }
  186. //
  187. // Cache this rfcb
  188. //
  189. connection->CachedRfcb = rfcb;
  190. connection->CachedFid = (ULONG)fid;
  191. //
  192. // The FID is valid within the context of this connection. Verify
  193. // that the file is still active and that the owning tree connect's
  194. // TID is correct.
  195. //
  196. // Do not verify the UID for clients that do not understand it.
  197. //
  198. if ( (rfcb->Tid !=
  199. SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid )) ||
  200. ((rfcb->Uid !=
  201. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )) &&
  202. DIALECT_HONORS_UID(connection->SmbDialect)) ) {
  203. goto error_exit_no_cleanup_locked;
  204. }
  205. }
  206. //
  207. // Mark the rfcb as active
  208. //
  209. rfcb->IsActive = TRUE;
  210. //
  211. // If a raw write is active, queue this work item in the RFCB
  212. // pending completion of the raw write.
  213. //
  214. if ( rfcb->RawWriteCount != 0 ) {
  215. InsertTailList(
  216. &rfcb->RawWriteSerializationList,
  217. &WorkContext->ListEntry
  218. );
  219. //
  220. // These 2 fields must be set with the connection spinlock held
  221. // since the workitem might be picked up by another thread and
  222. // a race condition will occur.
  223. //
  224. WorkContext->FspRestartRoutine = SrvRestartSmbReceived;
  225. WorkContext->Rfcb = NULL;
  226. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  227. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  228. return SmbStatusInProgress;
  229. }
  230. //
  231. // If this is a pipe read, we do things differently.
  232. //
  233. shareType = rfcb->ShareType;
  234. if ( shareType == ShareTypePipe ) {
  235. //
  236. // Indicate that a raw read is in progress on the connection.
  237. //
  238. connection->RawReadsInProgress++;
  239. //
  240. // The raw read can be accepted. Reference the RFCB.
  241. //
  242. rfcb->BlockHeader.ReferenceCount++;
  243. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  244. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  245. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  246. WorkContext->Rfcb = rfcb;
  247. if ( !ReadRawPipe( WorkContext ) ) {
  248. goto error_exit_cleanup;
  249. }
  250. return SmbStatusInProgress;
  251. }
  252. //
  253. // If there is an oplock break in progress, return 0 bytes read. We
  254. // do this because our oplock break request SMB may have crossed on
  255. // the wire with the read raw request and it may have been received
  256. // in the client's raw read buffer. This would cause the raw data
  257. // to complete in the client's regular receive buffer and possibly
  258. // to overrun it.
  259. //
  260. // If this is not the case, the client will simply retry the read
  261. // using a different read protocol. If it is the case, the client
  262. // must detect this and break the oplock, then redo the read.
  263. //
  264. if ( connection->OplockBreaksInProgress > 0 ) {
  265. goto error_exit_no_cleanup_locked;
  266. }
  267. //
  268. // Check to see whether we got a round trip break/response. If so,
  269. // reject read raw.
  270. //
  271. if ( (LONG)(connection->LatestOplockBreakResponse -
  272. WorkContext->Timestamp) >= 0 ) {
  273. goto error_exit_no_cleanup_locked;
  274. }
  275. //
  276. // If this is the first SMB received after sending an oplock break
  277. // II to none, reject this read. We need to do this because there
  278. // is no response to such a break, so we don't know for sure if the
  279. // break crossed with the read, which would mean that the break
  280. // actually completed the client's read, which would mean that any
  281. // raw data that we sent would be incorrectly received.
  282. //
  283. if ( connection->BreakIIToNoneJustSent ) {
  284. connection->BreakIIToNoneJustSent = FALSE;
  285. goto error_exit_no_cleanup_locked;
  286. }
  287. //
  288. // Indicate that a raw read is in progress on the connection.
  289. //
  290. connection->RawReadsInProgress++;
  291. //
  292. // The raw read can be accepted. Reference the RFCB.
  293. //
  294. rfcb->BlockHeader.ReferenceCount++;
  295. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  296. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  297. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  298. WorkContext->Rfcb = rfcb;
  299. //
  300. // Verify that the client has read access to the file via the
  301. // specified handle.
  302. //
  303. lfcb = rfcb->Lfcb;
  304. if ( !rfcb->ReadAccessGranted ) {
  305. CHECK_PAGING_IO_ACCESS(
  306. WorkContext,
  307. rfcb->GrantedAccess,
  308. &status );
  309. if ( !NT_SUCCESS( status ) ) {
  310. SrvStatistics.GrantedAccessErrors++;
  311. IF_DEBUG(ERRORS) {
  312. KdPrint(( "SrvSmbReadRaw: Read access not granted.\n"));
  313. }
  314. goto error_exit_cleanup;
  315. }
  316. }
  317. //
  318. // Calculate and save the read offset.
  319. //
  320. if ( request->WordCount == 8 ) {
  321. //
  322. // The client supplied a 32-bit offset.
  323. //
  324. offset.QuadPart = SmbGetUlong( &request->Offset );
  325. } else if ( request->WordCount == 10 ) {
  326. //
  327. // The client supplied a 64-bit offset.
  328. //
  329. ntRequest = (PREQ_NT_READ_RAW)WorkContext->RequestParameters;
  330. offset.LowPart = SmbGetUlong( &ntRequest->Offset );
  331. offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh );
  332. //
  333. // Reject negative offsets
  334. //
  335. if ( offset.QuadPart < 0 ) {
  336. IF_DEBUG(ERRORS) {
  337. KdPrint(( "SrvSmbReadRaw: Negative offset rejected.\n"));
  338. }
  339. goto error_exit_cleanup;
  340. }
  341. } else {
  342. //
  343. // Invalid word count. Return 0 bytes.
  344. //
  345. goto error_exit_cleanup;
  346. }
  347. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Offset = offset;
  348. //
  349. // If this operation may block, and we're running short of
  350. // resources, or if the target is a paused comm device, reject the
  351. // request.
  352. //
  353. // !!! Implement non-blocking comm device read. (mincount = 0)
  354. //
  355. // !!! Implement the paused comm device test.
  356. //
  357. #if SRV_COMM_DEVICES
  358. if ( shareType == ShareTypeComm ) {
  359. if ( SrvReceiveBufferShortage( ) ) {
  360. //
  361. // Reject the request.
  362. //
  363. // !!! Consider routing the request to the FSP, instead.
  364. //
  365. IF_DEBUG(ERRORS) {
  366. KdPrint(( "SrvSmbReadRaw: No resources for blocking "
  367. "read\n" ));
  368. }
  369. SrvFailedBlockingIoCount++;
  370. SrvStatistics.BlockingSmbsRejected++;
  371. goto error_exit_cleanup;
  372. }
  373. //
  374. // It is okay to start a blocking operation.
  375. // SrvReceiveBufferShortage() has already incremented
  376. // SrvBlockingOpsInProgress.
  377. //
  378. WorkContext->BlockingOperation = TRUE;
  379. }
  380. #endif
  381. //
  382. // Form the lock key using the FID and the PID.
  383. //
  384. // *** The FID must be included in the key in order to account for
  385. // the folding of multiple remote compatibility mode opens into
  386. // a single local open.
  387. //
  388. key = rfcb->ShiftedFid |
  389. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  390. //
  391. // If the SMB buffer is large enough, use it to do the local read.
  392. //
  393. readLength = SmbGetUshort( &request->MaxCount );
  394. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Length = readLength;
  395. if ( //0 &&
  396. (readLength <= SrvMdlReadSwitchover) ) {
  397. do_copy_read:
  398. WorkContext->Parameters.ReadRaw.SavedResponseBuffer = NULL;
  399. WorkContext->Parameters.ReadRaw.MdlRead = FALSE;
  400. //
  401. // Try the fast I/O path first.
  402. //
  403. if ( lfcb->FastIoRead != NULL ) {
  404. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  405. if ( lfcb->FastIoRead(
  406. lfcb->FileObject,
  407. &offset,
  408. readLength,
  409. TRUE,
  410. key,
  411. WorkContext->ResponseBuffer->Buffer,
  412. &WorkContext->Irp->IoStatus,
  413. lfcb->DeviceObject
  414. ) ) {
  415. //
  416. // The fast I/O path worked. Send the data.
  417. //
  418. SrvFsdRestartReadRaw( WorkContext );
  419. return SmbStatusInProgress;
  420. }
  421. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  422. }
  423. //
  424. // The fast I/O path failed, so we need to use a regular copy
  425. // I/O request. Build an MDL describing the read buffer.
  426. //
  427. // *** Note the assumption that the response buffer already has
  428. // a valid full MDL from which a partial MDL can be built.
  429. //
  430. IoBuildPartialMdl(
  431. WorkContext->ResponseBuffer->Mdl,
  432. WorkContext->ResponseBuffer->PartialMdl,
  433. WorkContext->ResponseBuffer->Buffer,
  434. readLength
  435. );
  436. mdl = WorkContext->ResponseBuffer->PartialMdl;
  437. rawBuffer = WorkContext->ResponseHeader;
  438. ASSERT( minorFunction == 0 );
  439. } else {
  440. //
  441. // The SMB buffer isn't big enough. Does the target file system
  442. // support the cache manager routines?
  443. //
  444. if ( lfcb->FileObject->Flags & FO_CACHE_SUPPORTED ) {
  445. WorkContext->Parameters.ReadRaw.MdlRead = TRUE;
  446. //
  447. // We can use an MDL read. Try the fast I/O path first.
  448. //
  449. WorkContext->Irp->MdlAddress = NULL;
  450. WorkContext->Irp->IoStatus.Information = 0;
  451. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  452. if ( lfcb->MdlRead(
  453. lfcb->FileObject,
  454. &offset,
  455. readLength,
  456. key,
  457. &WorkContext->Irp->MdlAddress,
  458. &WorkContext->Irp->IoStatus,
  459. lfcb->DeviceObject
  460. ) ) {
  461. //
  462. // The fast I/O path worked. Send the data.
  463. //
  464. SrvFsdRestartReadRaw( WorkContext );
  465. return SmbStatusInProgress;
  466. }
  467. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  468. //
  469. // The fast I/O path failed. We need to issue a regular MDL
  470. // read request.
  471. //
  472. // The fast path may have partially succeeded, returning a
  473. // partial MDL chain. We need to adjust our read request
  474. // to account for that.
  475. //
  476. offset.QuadPart += WorkContext->Irp->IoStatus.Information;
  477. readLength -= WorkContext->Irp->IoStatus.Information;
  478. mdl = WorkContext->Irp->MdlAddress;
  479. minorFunction = IRP_MN_MDL;
  480. } else if (readLength > WorkContext->ResponseBuffer->BufferLength) {
  481. //
  482. // We have to use a normal "copy" read. We need to allocate
  483. // a separate raw buffer.
  484. //
  485. ASSERT( minorFunction == 0 );
  486. WorkContext->Parameters.ReadRaw.MdlRead = FALSE;
  487. rawBuffer = ALLOCATE_NONPAGED_POOL(
  488. readLength,
  489. BlockTypeDataBuffer
  490. );
  491. IF_SMB_DEBUG(RAW2) KdPrint(( "rawBuffer: 0x%lx\n", rawBuffer ));
  492. if ( rawBuffer == NULL ) {
  493. IF_DEBUG(ERRORS) {
  494. KdPrint(( "SrvSmbReadRaw: Unable to allocate raw "
  495. "buffer\n" ));
  496. }
  497. goto error_exit_cleanup;
  498. }
  499. //
  500. // We also need a buffer descriptor.
  501. //
  502. // *** Note: Currently, ResponseBuffer == RequestBuffer in a
  503. // WorkContext block, so we don't really have to save
  504. // the ResponseBuffer field. But we do so just to be on
  505. // the safe side.
  506. //
  507. WorkContext->Parameters.ReadRaw.SavedResponseBuffer =
  508. WorkContext->ResponseBuffer;
  509. WorkContext->ResponseBuffer = ALLOCATE_NONPAGED_POOL(
  510. sizeof(BUFFER),
  511. BlockTypeBuffer
  512. );
  513. if ( WorkContext->ResponseBuffer == NULL ) {
  514. INTERNAL_ERROR(
  515. ERROR_LEVEL_EXPECTED,
  516. "SrvSmbReadRaw: Unable to allocate %d bytes from "
  517. "nonpaged pool.",
  518. sizeof(BUFFER),
  519. NULL
  520. );
  521. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  522. WorkContext->ResponseBuffer =
  523. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  524. goto error_exit_cleanup;
  525. }
  526. WorkContext->ResponseBuffer->Buffer = rawBuffer;
  527. WorkContext->ResponseBuffer->BufferLength = readLength;
  528. //
  529. // Finally, we need an MDL to describe the raw buffer.
  530. //
  531. // *** We used to try to use the PartialMdl for the SMB
  532. // buffer here, if it was big enough. But since we
  533. // already decided that the buffer itself isn't big
  534. // enough, it's extremely likely that the MDL isn't big
  535. // enough either.
  536. //
  537. mdl = IoAllocateMdl( rawBuffer, readLength, FALSE, FALSE, NULL );
  538. if ( mdl == NULL ) {
  539. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  540. WorkContext->ResponseBuffer =
  541. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  542. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  543. goto error_exit_cleanup;
  544. }
  545. WorkContext->ResponseBuffer->Mdl = mdl;
  546. //
  547. // Build the mdl
  548. //
  549. MmBuildMdlForNonPagedPool( mdl );
  550. //
  551. // Try the fast I/O path first.
  552. //
  553. if ( lfcb->FastIoRead != NULL ) {
  554. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  555. if ( lfcb->FastIoRead(
  556. lfcb->FileObject,
  557. &offset,
  558. readLength,
  559. TRUE,
  560. key,
  561. WorkContext->ResponseBuffer->Buffer,
  562. &WorkContext->Irp->IoStatus,
  563. lfcb->DeviceObject
  564. ) ) {
  565. //
  566. // The fast I/O path worked. Send the data.
  567. //
  568. SrvFsdRestartReadRaw( WorkContext );
  569. return SmbStatusInProgress;
  570. }
  571. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  572. }
  573. //
  574. // The fast I/O path failed, so we need to use a regular copy
  575. // I/O request.
  576. //
  577. } else {
  578. goto do_copy_read;
  579. }
  580. } // read fits in SMB buffer?
  581. //
  582. // Build the read request, reusing the receive IRP.
  583. //
  584. SrvBuildReadOrWriteRequest(
  585. WorkContext->Irp, // input IRP address
  586. lfcb->FileObject, // target file object address
  587. WorkContext, // context
  588. IRP_MJ_READ, // major function code
  589. minorFunction, // minor function code
  590. rawBuffer, // buffer address
  591. readLength, // buffer length
  592. mdl, // MDL address
  593. offset, // byte offset
  594. key // lock key
  595. );
  596. //
  597. // Pass the request to the file system.
  598. //
  599. WorkContext->FsdRestartRoutine = SrvFsdRestartReadRaw;
  600. DEBUG WorkContext->FspRestartRoutine = NULL;
  601. IF_SMB_DEBUG(RAW2) {
  602. KdPrint(( "SrvSmbReadRaw: reading from file 0x%lx, "
  603. "offset %ld, length %ld, destination 0x%lx, ",
  604. lfcb->FileObject, offset.LowPart, readLength,
  605. rawBuffer ));
  606. KdPrint(( "func 0x%lx\n", minorFunction ));
  607. }
  608. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  609. //
  610. // The read has been started. When it completes, processing
  611. // resumes in the FSD at SrvFsdRestartReadRaw.
  612. //
  613. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbReadRaw complete\n" ));
  614. return SmbStatusInProgress;
  615. error_exit_no_cleanup_locked:
  616. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock );
  617. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  618. error_exit_no_cleanup:
  619. WorkContext->ResponseParameters = WorkContext->ResponseHeader;
  620. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawReadsRejected );
  621. return SmbStatusSendResponse;
  622. error_exit_cleanup:
  623. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  624. //
  625. // We are about to release the work context and possibly free the
  626. // connection. Create a referenced pointer to the connection so
  627. // that we can send delayed oplock breaks, if necessary.
  628. //
  629. SrvReferenceConnectionLocked( connection );
  630. //
  631. // Since we cannot return an error code, we return zero bytes of
  632. // data.
  633. //
  634. WorkContext->ResponseParameters = WorkContext->ResponseHeader;
  635. //
  636. // If there is an oplock break request pending, then we must go to the
  637. // FSP to initiate the break, otherwise complete processing in the FSD.
  638. //
  639. if ( IsListEmpty( &connection->OplockWorkList ) ) {
  640. connection->RawReadsInProgress--;
  641. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  642. SrvFsdSendResponse( WorkContext );
  643. } else {
  644. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  645. SrvFsdSendResponse2( WorkContext, SrvRestartReadRawComplete );
  646. }
  647. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawReadsRejected );
  648. //
  649. // Release the connection reference.
  650. //
  651. SrvDereferenceConnection( connection );
  652. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbReadRaw complete\n" ));
  653. return SmbStatusInProgress;
  654. } // SrvSmbReadRaw
  655. SMB_PROCESSOR_RETURN_TYPE
  656. SrvSmbWriteRaw (
  657. SMB_PROCESSOR_PARAMETERS
  658. )
  659. /*++
  660. Routine Description:
  661. Processes the Write Block Raw SMB.
  662. Arguments:
  663. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description of the
  664. parameters to SMB processor routines.
  665. Return Value:
  666. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  667. --*/
  668. {
  669. PREQ_WRITE_RAW request;
  670. PREQ_NT_WRITE_RAW ntRequest;
  671. NTSTATUS status;
  672. PRFCB rfcb = NULL;
  673. PLFCB lfcb;
  674. ULONG immediateLength;
  675. BOOLEAN immediateWriteDone = FALSE;
  676. USHORT fid;
  677. PCHAR writeAddress;
  678. ULONG writeLength;
  679. ULONG key;
  680. SHARE_TYPE shareType;
  681. LARGE_INTEGER offset;
  682. PWORK_CONTEXT rawWorkContext;
  683. PVOID finalResponseBuffer = NULL;
  684. PCONNECTION connection;
  685. PAGED_CODE( );
  686. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawWritesAttempted );
  687. request = (PREQ_WRITE_RAW)WorkContext->RequestParameters;
  688. ntRequest = (PREQ_NT_WRITE_RAW)WorkContext->RequestParameters;
  689. fid = SmbGetUshort( &request->Fid );
  690. //
  691. // If the client is MS-NET 1.03 or before, reject him. We don't
  692. // support raw writes from these clients.
  693. //
  694. connection = WorkContext->Connection;
  695. if ( connection->SmbDialect >= SmbDialectMsNet103 ) {
  696. IF_DEBUG(SMB_ERRORS) {
  697. KdPrint(( "Raw write request from MS-NET 1.03 client.\n" ));
  698. }
  699. status = STATUS_SMB_USE_STANDARD;
  700. goto error_exit_no_rfcb;
  701. }
  702. IF_SMB_DEBUG(RAW1) {
  703. KdPrint(( "Write Block Raw request; FID 0x%lx, count %ld, "
  704. "offset %ld, immediate length %ld\n",
  705. fid,
  706. SmbGetUshort( &request->Count ),
  707. SmbGetUlong( &request->Offset ),
  708. SmbGetUshort( &request->DataLength ) ));
  709. }
  710. immediateLength = SmbGetUshort( &request->DataLength );
  711. writeLength = SmbGetUshort( &request->Count );
  712. //
  713. // make sure the immediate length:
  714. // is not greater than the total bytes, and
  715. // does not go beyond what we are given
  716. //
  717. if ( ( immediateLength > writeLength ) ||
  718. ( immediateLength > ( WorkContext->ResponseBuffer->DataLength -
  719. SmbGetUshort(&request->DataOffset) ) )
  720. ) {
  721. status = STATUS_INVALID_SMB;
  722. goto error_exit_no_rfcb;
  723. }
  724. //
  725. // Verify the FID. If verified, the RFCB is referenced and its
  726. // address is stored in the WorkContext block, and the RFCB address
  727. // is returned. In addition, the active raw write count is
  728. // incremented.
  729. //
  730. //
  731. // See if the fid matches the cached fid.
  732. //
  733. rfcb = SrvVerifyFidForRawWrite(
  734. WorkContext,
  735. fid,
  736. &status
  737. );
  738. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  739. if ( !NT_SUCCESS( status ) ) {
  740. //
  741. // Invalid file ID or write behind error. Reject the request.
  742. //
  743. IF_DEBUG(ERRORS) {
  744. KdPrint((
  745. "SrvSmbWriteRaw: Status %X on FID: 0x%lx\n",
  746. status,
  747. SmbGetUshort( &request->Fid )
  748. ));
  749. }
  750. goto error_exit_no_rfcb;
  751. }
  752. //
  753. // The work item has been queued because a raw write is in
  754. // progress.
  755. //
  756. return SmbStatusInProgress;
  757. }
  758. lfcb = rfcb->Lfcb;
  759. shareType = rfcb->ShareType;
  760. //
  761. // Validate the word count.
  762. //
  763. if ( shareType == ShareTypePipe ) {
  764. if ( (request->WordCount != 12) && (request->WordCount != 14) ) {
  765. status = STATUS_INVALID_SMB;
  766. goto error_exit;
  767. }
  768. } else {
  769. if ( request->WordCount == 12 ) {
  770. offset.QuadPart = SmbGetUlong( &request->Offset );
  771. } else if ( request->WordCount == 14 ) {
  772. offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh ) ;
  773. offset.LowPart = SmbGetUlong( &ntRequest->Offset ) ;
  774. //
  775. // Reject negative offsets. Add the offset to the immediate
  776. // length and make sure that the result is not negative. We do the
  777. // first check ( highpart >= 0x7fffffff ) so that in most cases
  778. // we do only one check.
  779. //
  780. if ( (ULONG)offset.HighPart >= (ULONG)0x7fffffff &&
  781. ( (offset.QuadPart < 0) ||
  782. ((offset.QuadPart + immediateLength) < 0) ) ) {
  783. IF_DEBUG(ERRORS) {
  784. KdPrint(( "SrvSmbWriteRaw: Negative offset rejected.\n"));
  785. }
  786. status = STATUS_INVALID_SMB;
  787. goto error_exit;
  788. }
  789. } else {
  790. status = STATUS_INVALID_SMB;
  791. goto error_exit;
  792. }
  793. }
  794. //
  795. // Verify that the client has write access to the file via the
  796. // specified handle.
  797. //
  798. if ( !rfcb->WriteAccessGranted ) {
  799. SrvStatistics.GrantedAccessErrors++;
  800. IF_DEBUG(ERRORS) {
  801. KdPrint(( "SrvSmbWriteRaw: Read access not granted.\n"));
  802. }
  803. status = STATUS_ACCESS_DENIED;
  804. goto error_exit;
  805. }
  806. rfcb->WrittenTo = TRUE;
  807. //
  808. // If this operation may block, and we're running short of
  809. // resources, or if the target is a paused comm device, reject the
  810. // request. Note that we do NOT write immediate data -- this is the
  811. // same behavior as the OS/2 server.
  812. //
  813. // !!! Implement the pause comm device test.
  814. //
  815. #if SRV_COMM_DEVICES
  816. if ( shareType == ShareTypeComm || rfcb->BlockingModePipe ) {
  817. #else
  818. if ( rfcb->BlockingModePipe ) {
  819. #endif
  820. if ( SrvReceiveBufferShortage( ) ) {
  821. //
  822. // Reject the request.
  823. //
  824. // !!! Consider routing the request to the FSP, instead.
  825. //
  826. IF_DEBUG(ERRORS) {
  827. KdPrint(( "SrvSmbWriteRaw: No resources for blocking "
  828. "write\n" ));
  829. }
  830. SrvFailedBlockingIoCount++;
  831. SrvStatistics.BlockingSmbsRejected++;
  832. status = STATUS_SMB_USE_STANDARD;
  833. goto error_exit;
  834. } else {
  835. //
  836. // It is okay to start a blocking operation.
  837. // SrvReceiveBufferShortage() has already incremented
  838. // SrvBlockingOpsInProgress.
  839. //
  840. WorkContext->BlockingOperation = TRUE;
  841. }
  842. } else if ( shareType == ShareTypeDisk &&
  843. ( ((ULONG)request->WriteMode & SMB_WMODE_WRITE_THROUGH) << 1 !=
  844. ((ULONG)lfcb->FileMode & FILE_WRITE_THROUGH) ) ) {
  845. //
  846. // Change the write through mode of the file, if necessary.
  847. //
  848. ASSERT( SMB_WMODE_WRITE_THROUGH == 0x01 );
  849. ASSERT( FILE_WRITE_THROUGH == 0x02 );
  850. SrvSetFileWritethroughMode(
  851. lfcb,
  852. (BOOLEAN)( (SmbGetUshort( &request->WriteMode )
  853. & SMB_WMODE_WRITE_THROUGH) != 0 )
  854. );
  855. }
  856. #ifdef SLMDBG
  857. {
  858. PRFCB_TRACE entry;
  859. ULONG immediateLength, rawLength;
  860. KIRQL oldIrql;
  861. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  862. rfcb->WriteCount++;
  863. rfcb->OperationCount++;
  864. entry = &rfcb->Trace[rfcb->NextTrace];
  865. if ( ++rfcb->NextTrace == SLMDBG_TRACE_COUNT ) {
  866. rfcb->NextTrace = 0;
  867. rfcb->TraceWrapped = TRUE;
  868. }
  869. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  870. entry->Command = WorkContext->NextCommand;
  871. entry->Flags = 0;
  872. immediateLength = SmbGetUshort( &request->DataLength );
  873. rawLength = SmbGetUshort( &request->Count ) - immediateLength;
  874. if ( immediateLength != 0 ) {
  875. entry->Flags = (UCHAR)(entry->Flags | 2);
  876. }
  877. if ( ((lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) != 0)
  878. ) {
  879. entry->Flags = (UCHAR)(entry->Flags | 1);
  880. }
  881. #if 0
  882. if ( ((lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) != 0) &&
  883. (rawLength > SrvMaxCopyWriteLength) ) {
  884. entry->Flags = (UCHAR)(entry->Flags | 1);
  885. }
  886. #endif
  887. KeQuerySystemTime( &entry->Time );
  888. entry->Data.ReadWrite.Offset = SmbGetUlong( &request->Offset );
  889. entry->Data.ReadWrite.Length = SmbGetUshort( &request->Count );
  890. }
  891. #endif
  892. //
  893. // If immediate data was sent write it first.
  894. //
  895. // If this is a named pipe, do not write the data unless all of the
  896. // write data was sent in the original request. We cannot do the
  897. // write in 2 parts, in case this is a message mode pipe.
  898. //
  899. // *** Note that this is different from the OS/2 server. It turns
  900. // out to be easier for us to write the immediate data first,
  901. // rather than copying it into a staging buffer pending receipt
  902. // of the raw write data. This is largely due to using MDL
  903. // writes -- we don't allocate a staging buffer when we do an
  904. // MDL write.
  905. //
  906. //
  907. // Form the lock key using the FID and the PID.
  908. //
  909. // *** The FID must be included in the key in order to
  910. // account for the folding of multiple remote
  911. // compatibility mode opens into a single local
  912. // open.
  913. //
  914. key = rfcb->ShiftedFid |
  915. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  916. if ( immediateLength != 0 ) {
  917. if ( (shareType != ShareTypePipe) ||
  918. (SmbGetUshort( &request->Count ) == (USHORT)immediateLength) ) {
  919. if ( lfcb->FastIoWrite != NULL ) {
  920. writeAddress = (PCHAR)WorkContext->RequestHeader +
  921. SmbGetUshort( &request->DataOffset );
  922. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  923. immediateWriteDone = lfcb->FastIoWrite(
  924. lfcb->FileObject,
  925. &offset,
  926. immediateLength,
  927. TRUE,
  928. key,
  929. writeAddress,
  930. &WorkContext->Irp->IoStatus,
  931. lfcb->DeviceObject
  932. );
  933. IF_SMB_DEBUG(RAW2) {
  934. KdPrint(( "SrvSmbWriteRaw: fast immediate write %s\n",
  935. immediateWriteDone ? "worked" : "failed" ));
  936. }
  937. if ( immediateWriteDone ) {
  938. writeLength -= immediateLength;
  939. offset.QuadPart += immediateLength;
  940. } else {
  941. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  942. }
  943. }
  944. }
  945. } else {
  946. immediateWriteDone = TRUE;
  947. }
  948. //
  949. // If the remaining write length is 0 (strange but legal), send a
  950. // success response.
  951. //
  952. if ( writeLength == 0 ) {
  953. IF_SMB_DEBUG(RAW1) {
  954. KdPrint(( "PrepareRawWrite: No raw data !?!\n" ));
  955. }
  956. status = STATUS_SUCCESS;
  957. goto error_exit;
  958. }
  959. //
  960. // Reject Raw write if:
  961. // raw mode has been disabled, or
  962. // connection is unreliable, or
  963. // file is non-cached and it is a write behind and it is a disk
  964. // file (this condition is necessary to prevent a client
  965. // from getting old data back when it does a raw read
  966. // immediately after a raw write. This can result in
  967. // synchronization problems.
  968. //
  969. if ( !SrvEnableRawMode ||
  970. !connection->EnableRawIo ) {
  971. IF_SMB_DEBUG(RAW1) {
  972. KdPrint(( "SrvSmbWriteRaw: Raw mode is disabled\n" ));
  973. }
  974. //
  975. // Update server statistics.
  976. //
  977. status = STATUS_SMB_USE_STANDARD;
  978. goto error_exit;
  979. }
  980. //
  981. // Obtain a raw mode work item from the raw mode pool. If none are
  982. // available, ask the client to use a standard write request.
  983. //
  984. rawWorkContext = SrvGetRawModeWorkItem( );
  985. if ( rawWorkContext == NULL ) {
  986. IF_DEBUG(ERRORS) {
  987. KdPrint(( "SrvSmbWriteRaw: No raw mode work items "
  988. "available\n" ));
  989. }
  990. SrvOutOfRawWorkItemCount++;
  991. status = STATUS_SMB_USE_STANDARD;
  992. goto error_exit;
  993. }
  994. IF_SMB_DEBUG(RAW2) KdPrint(( "rawWorkContext: 0x%lx\n", rawWorkContext ));
  995. //
  996. // If writethough mode was specified, we'll need to send a final
  997. // response SMB. Allocate a nonpaged buffer to contain the
  998. // response. If this fails, ask the client to use a standard write
  999. // request.
  1000. //
  1001. if ( (SmbGetUshort( &request->WriteMode ) &
  1002. SMB_WMODE_WRITE_THROUGH) != 0 ) {
  1003. finalResponseBuffer = ALLOCATE_NONPAGED_POOL(
  1004. sizeof(SMB_HEADER) +
  1005. SIZEOF_SMB_PARAMS(RESP_WRITE_COMPLETE,0),
  1006. BlockTypeDataBuffer
  1007. );
  1008. IF_SMB_DEBUG(RAW2) {
  1009. KdPrint(( "finalResponseBuffer: 0x%lx\n", finalResponseBuffer ));
  1010. }
  1011. if ( finalResponseBuffer == NULL ) {
  1012. INTERNAL_ERROR(
  1013. ERROR_LEVEL_EXPECTED,
  1014. "SrvSmbWriteRaw: Unable to allocate %d bytes from "
  1015. "nonpaged pool",
  1016. sizeof(SMB_HEADER) + SIZEOF_SMB_PARAMS(RESP_WRITE_COMPLETE,0),
  1017. NULL
  1018. );
  1019. SrvRequeueRawModeWorkItem( rawWorkContext );
  1020. status = STATUS_SMB_USE_STANDARD;
  1021. goto error_exit;
  1022. }
  1023. }
  1024. //
  1025. // Save necessary context information in the additional work context
  1026. // block.
  1027. //
  1028. rawWorkContext->Parameters.WriteRaw.FinalResponseBuffer = finalResponseBuffer;
  1029. rawWorkContext->Parameters.WriteRaw.ImmediateWriteDone = immediateWriteDone;
  1030. rawWorkContext->Parameters.WriteRaw.ImmediateLength = immediateLength;
  1031. rawWorkContext->Parameters.WriteRaw.Offset = offset;
  1032. rawWorkContext->Parameters.WriteRaw.Pid =
  1033. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  1034. WorkContext->Parameters.WriteRawPhase1.RawWorkContext = rawWorkContext;
  1035. //
  1036. // Copy the start time from the original work context. Indicate
  1037. // that no statistics should be saved from the original, and what
  1038. // kind of statistics should be saved from the raw work context.
  1039. //
  1040. rawWorkContext->StartTime = 0;
  1041. //
  1042. // Copy pointers from the original work context to the raw work
  1043. // context, referencing as necessary.
  1044. //
  1045. rawWorkContext->Endpoint = WorkContext->Endpoint; // not a referenced ptr
  1046. rawWorkContext->Connection = connection;
  1047. SrvReferenceConnection( connection );
  1048. rawWorkContext->Share = NULL;
  1049. rawWorkContext->Session = NULL;
  1050. rawWorkContext->TreeConnect = NULL;
  1051. rawWorkContext->Rfcb = rfcb;
  1052. SrvReferenceRfcb( rfcb );
  1053. //
  1054. // Prepare either a copy write or an MDL write, as appropriate.
  1055. //
  1056. if ( !(lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) ) {
  1057. //
  1058. // The file system doesn't support MDL write. Prepare a copy
  1059. // write.
  1060. //
  1061. rawWorkContext->Parameters.WriteRaw.MdlWrite = FALSE;
  1062. PrepareRawCopyWrite( WorkContext );
  1063. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbWriteRaw complete\n" ));
  1064. return SmbStatusInProgress;
  1065. }
  1066. //
  1067. // The file system supports MDL write. Prepare an MDL write.
  1068. //
  1069. rawWorkContext->Parameters.WriteRaw.MdlWrite = TRUE;
  1070. rawWorkContext->Parameters.WriteRaw.Length = writeLength;
  1071. //
  1072. // Try the fast path first.
  1073. //
  1074. WorkContext->Irp->MdlAddress = NULL;
  1075. WorkContext->Irp->IoStatus.Information = 0;
  1076. IF_SMB_DEBUG(RAW2) {
  1077. KdPrint(( "SrvSmbWriteRaw: trying fast path for offset %ld, "
  1078. "length %ld\n", offset.LowPart, writeLength ));
  1079. }
  1080. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  1081. if ( lfcb->PrepareMdlWrite(
  1082. lfcb->FileObject,
  1083. &offset,
  1084. writeLength,
  1085. key,
  1086. &WorkContext->Irp->MdlAddress,
  1087. &WorkContext->Irp->IoStatus,
  1088. lfcb->DeviceObject
  1089. ) ) {
  1090. //
  1091. // The fast I/O path worked. Send the go-ahead response.
  1092. //
  1093. #if DBG
  1094. IF_SMB_DEBUG(RAW2) {
  1095. KdPrint(( "SrvSmbWriteRaw: fast path worked; MDL %lx, "
  1096. "length %ld\n", WorkContext->Irp->MdlAddress,
  1097. WorkContext->Irp->IoStatus.Information ));
  1098. DumpMdlChain( WorkContext->Irp->MdlAddress );
  1099. }
  1100. #endif
  1101. SrvFsdRestartPrepareRawMdlWrite( WorkContext );
  1102. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbWriteRaw complete\n" ));
  1103. return SmbStatusInProgress;
  1104. }
  1105. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  1106. //
  1107. // The fast I/O path failed. Build the write request, reusing the
  1108. // receive IRP.
  1109. //
  1110. // The fast path may have partially succeeded, returning a partial
  1111. // MDL chain. We need to adjust our write request to account for
  1112. // that.
  1113. //
  1114. IF_SMB_DEBUG(RAW2) {
  1115. KdPrint(( "SrvSmbWriteRaw: fast path failed; MDL %lx, "
  1116. "length %ld\n", WorkContext->Irp->MdlAddress,
  1117. WorkContext->Irp->IoStatus.Information ));
  1118. }
  1119. offset.QuadPart += WorkContext->Irp->IoStatus.Information;
  1120. writeLength -= WorkContext->Irp->IoStatus.Information;
  1121. SrvBuildReadOrWriteRequest(
  1122. WorkContext->Irp, // input IRP address
  1123. lfcb->FileObject, // target file object address
  1124. WorkContext, // context
  1125. IRP_MJ_WRITE, // major function code
  1126. IRP_MN_MDL, // minor function code
  1127. NULL, // buffer address (ignored)
  1128. writeLength, // buffer length
  1129. WorkContext->Irp->MdlAddress, // MDL address
  1130. offset, // byte offset
  1131. key // lock key
  1132. );
  1133. //
  1134. // Pass the request to the file system.
  1135. //
  1136. IF_SMB_DEBUG(RAW2) {
  1137. KdPrint(( "SrvSmbWriteRaw: write to file 0x%lx, offset %ld, "
  1138. "length %ld\n",
  1139. lfcb->FileObject, offset.LowPart, writeLength ));
  1140. }
  1141. WorkContext->FsdRestartRoutine = SrvFsdRestartPrepareRawMdlWrite;
  1142. DEBUG WorkContext->FspRestartRoutine = NULL;
  1143. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1144. //
  1145. // The MDL write has been started. When it completes, processing
  1146. // resumes at SrvFsdRestartPrepareRawMdlWrite.
  1147. //
  1148. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbWriteRaw complete\n" ));
  1149. return SmbStatusInProgress;
  1150. error_exit:
  1151. SrvDecrementRawWriteCount( rfcb );
  1152. error_exit_no_rfcb:
  1153. SrvFsdBuildWriteCompleteResponse(
  1154. WorkContext,
  1155. status,
  1156. immediateWriteDone ? immediateLength : 0
  1157. );
  1158. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawWritesRejected );
  1159. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbWriteRaw complete\n" ));
  1160. return SmbStatusSendResponse;
  1161. } // SrvSmbWriteRaw
  1162. VOID SRVFASTCALL
  1163. AbortRawWrite(
  1164. IN OUT PWORK_CONTEXT WorkContext
  1165. )
  1166. /*++
  1167. Routine Description:
  1168. Handles cleanup when a raw write is aborted after the interim
  1169. "go-ahead" response has been sent. This routine is only used
  1170. when a catastrophic errors occurs -- for example, the connection
  1171. is closing. It does not send a final response to the client.
  1172. This routine is called in the FSP.
  1173. Arguments:
  1174. WorkContext - Supplies a pointer to the work context block
  1175. describing server-specific context for the request.
  1176. This must be a pointer to the raw mode work item -- not the
  1177. original work item that received the Write Raw SMB.
  1178. Return Value:
  1179. None.
  1180. --*/
  1181. {
  1182. PMDL cacheMdl;
  1183. PMDL partialMdl;
  1184. NTSTATUS status;
  1185. PAGED_CODE( );
  1186. //
  1187. // Deallocate the final response buffer, if any.
  1188. //
  1189. if ( WorkContext->Parameters.WriteRaw.FinalResponseBuffer != NULL ) {
  1190. DEALLOCATE_NONPAGED_POOL(
  1191. WorkContext->Parameters.WriteRaw.FinalResponseBuffer
  1192. );
  1193. WorkContext->Parameters.WriteRaw.FinalResponseBuffer = NULL;
  1194. }
  1195. if ( !WorkContext->Parameters.WriteRaw.MdlWrite ) {
  1196. //
  1197. // This was a copy write. Deallocate the raw receive buffer.
  1198. // Note that we do not need to unlock the raw buffer, because it
  1199. // was allocated out of nonpaged pool and locked using
  1200. // MmBuildMdlForNonPagedPool, which doesn't increment reference
  1201. // counts and therefore has no inverse.
  1202. //
  1203. if ( WorkContext->Parameters.WriteRaw.ImmediateWriteDone ) {
  1204. DEALLOCATE_NONPAGED_POOL( WorkContext->RequestBuffer->Buffer );
  1205. } else {
  1206. DEALLOCATE_NONPAGED_POOL(
  1207. (PCHAR)WorkContext->RequestBuffer->Buffer -
  1208. WorkContext->Parameters.WriteRaw.ImmediateLength );
  1209. }
  1210. //
  1211. // Dereference control blocks and requeue the raw mode work
  1212. // item.
  1213. //
  1214. WorkContext->ResponseBuffer->Buffer = NULL;
  1215. SrvRestartWriteCompleteResponse( WorkContext );
  1216. return;
  1217. }
  1218. //
  1219. // This was an MDL write. If a partial MDL was built (because of
  1220. // immediate data), unmap it. Then complete the MDL write,
  1221. // indicating that no data was actually written.
  1222. //
  1223. cacheMdl = WorkContext->Parameters.WriteRaw.FirstMdl;
  1224. partialMdl = WorkContext->Irp->MdlAddress;
  1225. if ( partialMdl != cacheMdl ) {
  1226. ASSERT( (partialMdl->MdlFlags & MDL_PARTIAL) != 0 );
  1227. MmPrepareMdlForReuse( partialMdl );
  1228. }
  1229. #if DBG
  1230. IF_SMB_DEBUG(RAW2) {
  1231. KdPrint(( "AbortRawWrite: Completing MDL write with length 0\n" ));
  1232. DumpMdlChain( cacheMdl );
  1233. }
  1234. #endif
  1235. if( WorkContext->Rfcb->Lfcb->MdlWriteComplete == NULL ||
  1236. WorkContext->Rfcb->Lfcb->MdlWriteComplete(
  1237. WorkContext->Rfcb->Lfcb->FileObject,
  1238. &WorkContext->Parameters.WriteRaw.Offset,
  1239. cacheMdl,
  1240. WorkContext->Rfcb->Lfcb->DeviceObject ) == FALSE ) {
  1241. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  1242. cacheMdl,
  1243. IRP_MJ_WRITE,
  1244. &WorkContext->Parameters.WriteRaw.Offset,
  1245. WorkContext->Parameters.WriteRaw.Length
  1246. );
  1247. if( !NT_SUCCESS( status ) ) {
  1248. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  1249. }
  1250. }
  1251. SrvRestartWriteCompleteResponse( WorkContext );
  1252. return;
  1253. } // AbortRawWrite
  1254. VOID SRVFASTCALL
  1255. PrepareRawCopyWrite (
  1256. IN OUT PWORK_CONTEXT WorkContext
  1257. )
  1258. /*++
  1259. Routine Description:
  1260. Prepares for a raw "copy" write. Allocates a buffer to receive the
  1261. raw data, prepares a work context block and an IRP describing the
  1262. raw receive, queues it to the connection, and sends a "go-ahead"
  1263. response.
  1264. Any immediate data sent in the request SMB has already been written
  1265. when this routine is called, unless this is a named pipe write, in
  1266. which case the immediate data has not been written. In this case,
  1267. we alllocate a buffer big enough for the the immediate data plus the
  1268. raw data, then copy the immediate data to the raw buffer before
  1269. proceeding. The raw data will be received appended to the immediate
  1270. data. Then both peices can be written with a single write. This is
  1271. needed so that data written to a message mode pipe will not be
  1272. written in 2 pieces.
  1273. This routine is called in the FSP.
  1274. Arguments:
  1275. WorkContext - Supplies a pointer to the work context block
  1276. describing server-specific context for the request.
  1277. Return Value:
  1278. None.
  1279. --*/
  1280. {
  1281. PWORK_CONTEXT rawWorkContext;
  1282. PREQ_WRITE_RAW request;
  1283. PRESP_WRITE_RAW_INTERIM response;
  1284. NTSTATUS status;
  1285. PVOID rawBuffer;
  1286. PCHAR writeAddress;
  1287. PMDL mdl;
  1288. SHARE_TYPE shareType;
  1289. PVOID finalResponseBuffer;
  1290. ULONG immediateLength;
  1291. BOOLEAN immediateWriteDone;
  1292. ULONG writeLength;
  1293. ULONG bufferLength;
  1294. BOOLEAN sendWriteComplete = TRUE;
  1295. PIO_STACK_LOCATION irpSp;
  1296. PAGED_CODE( );
  1297. IF_DEBUG(WORKER1) KdPrint(( " - PrepareRawCopyWrite\n" ));
  1298. //
  1299. // Set up local variables.
  1300. //
  1301. rawWorkContext = WorkContext->Parameters.WriteRawPhase1.RawWorkContext;
  1302. request = (PREQ_WRITE_RAW)WorkContext->RequestParameters;
  1303. shareType = rawWorkContext->Rfcb->ShareType;
  1304. immediateLength = rawWorkContext->Parameters.WriteRaw.ImmediateLength;
  1305. immediateWriteDone =
  1306. rawWorkContext->Parameters.WriteRaw.ImmediateWriteDone;
  1307. writeLength = SmbGetUshort( &request->Count ) - immediateLength;
  1308. finalResponseBuffer =
  1309. rawWorkContext->Parameters.WriteRaw.FinalResponseBuffer;
  1310. if ( !immediateWriteDone ) {
  1311. bufferLength = writeLength + immediateLength;
  1312. } else {
  1313. bufferLength = writeLength;
  1314. }
  1315. //
  1316. // Allocate a nonpaged buffer to contain the write data. If this
  1317. // fails, ask the client to use a standard write request.
  1318. //
  1319. rawBuffer = ALLOCATE_NONPAGED_POOL( bufferLength, BlockTypeDataBuffer );
  1320. IF_SMB_DEBUG(RAW2) KdPrint(( "rawBuffer: 0x%lx\n", rawBuffer ));
  1321. if ( rawBuffer == NULL ) {
  1322. // !!! Should we log this error?
  1323. IF_DEBUG(ERRORS) {
  1324. KdPrint(( "PrepareRawCopyWrite: Unable to allocate "
  1325. "raw buffer\n" ));
  1326. }
  1327. status = STATUS_SMB_USE_STANDARD;
  1328. goto abort;
  1329. }
  1330. if ( !immediateWriteDone ) {
  1331. //
  1332. // Copy the immediate data to the raw buffer.
  1333. //
  1334. writeAddress = (PCHAR)WorkContext->RequestHeader +
  1335. SmbGetUshort( &request->DataOffset );
  1336. RtlCopyMemory( rawBuffer, writeAddress, immediateLength );
  1337. //
  1338. // Move the virtual start of the raw buffer to the end of the
  1339. // immediate data.
  1340. //
  1341. rawBuffer = (PCHAR)rawBuffer + immediateLength;
  1342. }
  1343. //
  1344. // If a final response is going to be sent, save information from
  1345. // the request in the final response buffer.
  1346. //
  1347. if ( finalResponseBuffer != NULL ) {
  1348. RtlCopyMemory(
  1349. (PSMB_HEADER)finalResponseBuffer,
  1350. WorkContext->RequestHeader,
  1351. sizeof(SMB_HEADER)
  1352. );
  1353. }
  1354. //
  1355. // Set up the buffer descriptor for the raw buffer.
  1356. //
  1357. rawWorkContext->RequestBuffer->Buffer = rawBuffer;
  1358. rawWorkContext->RequestBuffer->BufferLength = writeLength;
  1359. //
  1360. // Initialize the MDL to describe the raw buffer.
  1361. // (SrvBuildIoControlRequest will lock the buffer for I/O.)
  1362. //
  1363. mdl = rawWorkContext->RequestBuffer->Mdl;
  1364. MmInitializeMdl( mdl, rawBuffer, writeLength );
  1365. //
  1366. // Build the mdl
  1367. //
  1368. MmBuildMdlForNonPagedPool( mdl );
  1369. //
  1370. // Set up the restart routines in the work context block.
  1371. //
  1372. rawWorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1373. rawWorkContext->FspRestartRoutine = SrvRestartRawReceive;
  1374. //
  1375. // Build the I/O request packet.
  1376. //
  1377. (VOID)SrvBuildIoControlRequest(
  1378. rawWorkContext->Irp, // input IRP address
  1379. NULL, // target file object address
  1380. rawWorkContext, // context
  1381. IRP_MJ_INTERNAL_DEVICE_CONTROL, // major function
  1382. TDI_RECEIVE, // minor function
  1383. NULL, // input buffer address
  1384. 0, // input buffer length
  1385. rawBuffer, // output buffer address
  1386. writeLength, // output buffer length
  1387. mdl, // MDL address
  1388. NULL
  1389. );
  1390. irpSp = IoGetNextIrpStackLocation( rawWorkContext->Irp );
  1391. //
  1392. // If this is a writebehind write, tell the transport that we don't
  1393. // plan to reply to the received message.
  1394. //
  1395. if ( finalResponseBuffer == NULL ) {
  1396. ((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveFlags |=
  1397. TDI_RECEIVE_NO_RESPONSE_EXP;
  1398. }
  1399. //
  1400. // Post the receive.
  1401. //
  1402. irpSp->Flags = 0;
  1403. irpSp->DeviceObject = rawWorkContext->Connection->DeviceObject;
  1404. irpSp->FileObject = rawWorkContext->Connection->FileObject;
  1405. ASSERT( rawWorkContext->Irp->StackCount >= irpSp->DeviceObject->StackSize );
  1406. (VOID)IoCallDriver( irpSp->DeviceObject, rawWorkContext->Irp );
  1407. //
  1408. // Build the interim (go-ahead) response.
  1409. //
  1410. response = (PRESP_WRITE_RAW_INTERIM)WorkContext->ResponseParameters;
  1411. response->WordCount = 1;
  1412. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  1413. SmbPutUshort( &response->ByteCount, 0 );
  1414. WorkContext->ResponseParameters = NEXT_LOCATION(
  1415. response,
  1416. RESP_WRITE_RAW_INTERIM,
  1417. 0
  1418. );
  1419. //
  1420. // Send off the interim response by ending processing of the SMB.
  1421. //
  1422. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1423. IF_DEBUG(TRACE2) KdPrint(( "PrepareRawCopyWrite complete\n" ));
  1424. return;
  1425. abort:
  1426. //
  1427. // For one reason or another, we are not going to receive any raw
  1428. // data, so clean up.
  1429. //
  1430. if ( finalResponseBuffer != NULL ) {
  1431. DEALLOCATE_NONPAGED_POOL( finalResponseBuffer );
  1432. }
  1433. SrvRestartWriteCompleteResponse( rawWorkContext );
  1434. //
  1435. // If a response is to be sent, send it now.
  1436. //
  1437. if ( sendWriteComplete ) {
  1438. SrvFsdBuildWriteCompleteResponse(
  1439. WorkContext,
  1440. status,
  1441. immediateWriteDone ? immediateLength : 0
  1442. );
  1443. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1444. } else {
  1445. SrvDereferenceWorkItem( WorkContext );
  1446. }
  1447. IF_DEBUG(TRACE2) KdPrint(( "PrepareRawCopyWrite complete\n" ));
  1448. return;
  1449. } // PrepareRawCopyWrite
  1450. BOOLEAN SRVFASTCALL
  1451. ReadRawPipe (
  1452. IN PWORK_CONTEXT WorkContext
  1453. )
  1454. /*++
  1455. Routine Description:
  1456. Processes the Read Block Raw SMB for pipes.
  1457. Note that Read Block Raw cannot return an error response. When the
  1458. server is unable to process the request, for whatever reason, it
  1459. simply responds with a zero-length message. The client uses a
  1460. normal Read SMB to determine what happened.
  1461. Arguments:
  1462. WorkContext - Pointer to the work context block.
  1463. Return Value:
  1464. TRUE, if operation succeeds.
  1465. FALSE, otherwise
  1466. --*/
  1467. {
  1468. PREQ_READ_RAW request;
  1469. USHORT fid;
  1470. PRFCB rfcb;
  1471. PLFCB lfcb;
  1472. PCONNECTION connection;
  1473. UCHAR minorFunction = 0;
  1474. BOOLEAN byteModePipe;
  1475. PVOID rawBuffer = NULL;
  1476. CLONG readLength;
  1477. PMDL mdl = NULL;
  1478. ULONG key;
  1479. LARGE_INTEGER offset;
  1480. PFILE_PIPE_PEEK_BUFFER pipePeekBuffer;
  1481. PAGED_CODE( );
  1482. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.RawReadsAttempted );
  1483. request = (PREQ_READ_RAW)WorkContext->RequestParameters;
  1484. fid = SmbGetUshort( &request->Fid );
  1485. readLength = SmbGetUshort( &request->MaxCount );
  1486. //
  1487. // If raw mode has been disabled or if the connection is unreliable,
  1488. // reject the raw read. Ask the client to use standard read by
  1489. // sending a zero-length response. The client will react by issuing
  1490. // a normal Read SMB, which we will be able to process.
  1491. //
  1492. connection = WorkContext->Connection;
  1493. rfcb = WorkContext->Rfcb;
  1494. lfcb = rfcb->Lfcb;
  1495. byteModePipe = rfcb->ByteModePipe;
  1496. //
  1497. // Verify that the client has read access to the file via the
  1498. // specified handle.
  1499. //
  1500. if ( !rfcb->ReadAccessGranted ) {
  1501. SrvStatistics.GrantedAccessErrors++;
  1502. IF_DEBUG(ERRORS) {
  1503. KdPrint(( "ReadRawPipe: Read access not granted.\n"));
  1504. }
  1505. return(FALSE);
  1506. }
  1507. //
  1508. // Verify the word counts
  1509. //
  1510. if ( (request->WordCount != 8) && (request->WordCount != 10) ) {
  1511. //
  1512. // Invalid word count. Return 0 bytes.
  1513. //
  1514. return(FALSE);
  1515. }
  1516. //
  1517. // If this operation may block, and we're running short of
  1518. // resources, or if the target is a paused comm device, reject the
  1519. // request.
  1520. //
  1521. if ( rfcb->BlockingModePipe ) {
  1522. if ( SrvReceiveBufferShortage( ) ) {
  1523. //
  1524. // Reject the request.
  1525. //
  1526. // !!! Consider routing the request to the FSP, instead.
  1527. //
  1528. IF_DEBUG(ERRORS) {
  1529. KdPrint(( "ReadRawPipe: No resources for blocking "
  1530. "read\n" ));
  1531. }
  1532. SrvFailedBlockingIoCount++;
  1533. SrvStatistics.BlockingSmbsRejected++;
  1534. return(FALSE);
  1535. }
  1536. //
  1537. // It is okay to start a blocking operation.
  1538. // SrvReceiveBufferShortage() has already incremented
  1539. // SrvBlockingOpsInProgress.
  1540. //
  1541. WorkContext->BlockingOperation = TRUE;
  1542. }
  1543. //
  1544. // Form the lock key using the FID and the PID.
  1545. //
  1546. // *** The FID must be included in the key in order to account for
  1547. // the folding of multiple remote compatibility mode opens into
  1548. // a single local open.
  1549. //
  1550. key = rfcb->ShiftedFid |
  1551. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  1552. //
  1553. // If the SMB buffer is large enough, use it to do the local read.
  1554. //
  1555. if ( readLength <= WorkContext->ResponseBuffer->BufferLength ) {
  1556. WorkContext->Parameters.ReadRaw.SavedResponseBuffer = NULL;
  1557. WorkContext->Parameters.ReadRaw.MdlRead = FALSE;
  1558. //
  1559. // Try the fast I/O path first.
  1560. //
  1561. if ( byteModePipe && (lfcb->FastIoRead != NULL) ) {
  1562. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  1563. if ( lfcb->FastIoRead(
  1564. lfcb->FileObject,
  1565. &offset,
  1566. readLength,
  1567. TRUE,
  1568. key,
  1569. WorkContext->ResponseBuffer->Buffer,
  1570. &WorkContext->Irp->IoStatus,
  1571. lfcb->DeviceObject
  1572. ) ) {
  1573. //
  1574. // The fast I/O path worked. Send the data.
  1575. //
  1576. SrvFsdRestartReadRaw( WorkContext );
  1577. return TRUE;
  1578. }
  1579. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  1580. }
  1581. //
  1582. // The fast I/O path failed, so we need to use a regular copy
  1583. // I/O request. Build an MDL describing the read buffer.
  1584. //
  1585. // *** Note the assumption that the response buffer already has
  1586. // a valid full MDL from which a partial MDL can be built.
  1587. //
  1588. IoBuildPartialMdl(
  1589. WorkContext->ResponseBuffer->Mdl,
  1590. WorkContext->ResponseBuffer->PartialMdl,
  1591. WorkContext->ResponseBuffer->Buffer,
  1592. readLength
  1593. );
  1594. mdl = WorkContext->ResponseBuffer->PartialMdl;
  1595. rawBuffer = WorkContext->ResponseHeader;
  1596. ASSERT( minorFunction == 0 );
  1597. } else {
  1598. //
  1599. // We have to use a normal "copy" read. We need to allocate
  1600. // a separate raw buffer.
  1601. //
  1602. ASSERT( minorFunction == 0 );
  1603. WorkContext->Parameters.ReadRaw.MdlRead = FALSE;
  1604. rawBuffer = ALLOCATE_NONPAGED_POOL(
  1605. readLength,
  1606. BlockTypeDataBuffer
  1607. );
  1608. IF_SMB_DEBUG(RAW2) KdPrint(( "rawBuffer: 0x%lx\n", rawBuffer ));
  1609. if ( rawBuffer == NULL ) {
  1610. IF_DEBUG(ERRORS) {
  1611. KdPrint(( "ReadRawPipe: Unable to allocate raw "
  1612. "buffer\n" ));
  1613. }
  1614. return(FALSE);
  1615. }
  1616. //
  1617. // We also need a buffer descriptor.
  1618. //
  1619. // *** Note: Currently, ResponseBuffer == RequestBuffer in a
  1620. // WorkContext block, so we don't really have to save
  1621. // the ResponseBuffer field. But we do so just to be on
  1622. // the safe side.
  1623. //
  1624. WorkContext->Parameters.ReadRaw.SavedResponseBuffer =
  1625. WorkContext->ResponseBuffer;
  1626. WorkContext->ResponseBuffer = ALLOCATE_NONPAGED_POOL(
  1627. sizeof(BUFFER),
  1628. BlockTypeBuffer
  1629. );
  1630. if ( WorkContext->ResponseBuffer == NULL ) {
  1631. INTERNAL_ERROR(
  1632. ERROR_LEVEL_EXPECTED,
  1633. "ReadRawPipe: Unable to allocate %d bytes from "
  1634. "nonpaged pool.",
  1635. sizeof(BUFFER),
  1636. NULL
  1637. );
  1638. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  1639. WorkContext->ResponseBuffer =
  1640. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  1641. return(FALSE);
  1642. }
  1643. WorkContext->ResponseBuffer->Buffer = rawBuffer;
  1644. WorkContext->ResponseBuffer->BufferLength = readLength;
  1645. //
  1646. // Finally, we need an MDL to describe the raw buffer.
  1647. //
  1648. // *** We used to try to use the PartialMdl for the SMB
  1649. // buffer here, if it was big enough. But since we
  1650. // already decided that the buffer itself isn't big
  1651. // enough, it's extremely likely that the MDL isn't big
  1652. // enough either.
  1653. //
  1654. mdl = IoAllocateMdl( rawBuffer, readLength, FALSE, FALSE, NULL );
  1655. if ( mdl == NULL ) {
  1656. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  1657. WorkContext->ResponseBuffer =
  1658. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  1659. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  1660. return(FALSE);
  1661. }
  1662. WorkContext->ResponseBuffer->Mdl = mdl;
  1663. //
  1664. // Build the mdl
  1665. //
  1666. MmBuildMdlForNonPagedPool( mdl );
  1667. //
  1668. // Try the fast I/O path first.
  1669. //
  1670. if ( byteModePipe && (lfcb->FastIoRead != NULL) ) {
  1671. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  1672. if ( lfcb->FastIoRead(
  1673. lfcb->FileObject,
  1674. &offset,
  1675. readLength,
  1676. TRUE,
  1677. key,
  1678. WorkContext->ResponseBuffer->Buffer,
  1679. &WorkContext->Irp->IoStatus,
  1680. lfcb->DeviceObject
  1681. ) ) {
  1682. //
  1683. // The fast I/O path worked. Send the data.
  1684. //
  1685. SrvFsdRestartReadRaw( WorkContext );
  1686. return TRUE;
  1687. }
  1688. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  1689. }
  1690. //
  1691. // The fast I/O path failed, so we need to use a regular copy
  1692. // I/O request.
  1693. //
  1694. } // read fits in SMB buffer?
  1695. //
  1696. // This is a read block raw on a named pipe. If this is a
  1697. // non-blocking read on a blocking mode pipe, we need to do a
  1698. // peek first. This is to ensure that we don't end up waiting
  1699. // when we're not supposed to.
  1700. //
  1701. // *** We used to have to peek on message mode pipes, in case
  1702. // the message was too large or zero-length. But now we
  1703. // have a special pipe FSCTL for this. See below.
  1704. //
  1705. if ( (SmbGetUshort( &request->MinCount ) == 0) &&
  1706. rfcb->BlockingModePipe ) {
  1707. //
  1708. // Allocate a buffer to peek the pipe. This buffer is freed
  1709. // in RestartPipeReadRawPeek().
  1710. //
  1711. pipePeekBuffer = ALLOCATE_NONPAGED_POOL(
  1712. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  1713. BlockTypeDataBuffer
  1714. );
  1715. if ( pipePeekBuffer == NULL ) {
  1716. //
  1717. // Can't allocate a buffer to do a peek. Nothing to do
  1718. // but return zero bytes to the client.
  1719. //
  1720. INTERNAL_ERROR(
  1721. ERROR_LEVEL_EXPECTED,
  1722. "ReadRawPipe: Unable to allocate %d bytes from"
  1723. "nonpaged pool.",
  1724. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  1725. NULL
  1726. );
  1727. if ( WorkContext->Parameters.ReadRaw.SavedResponseBuffer !=
  1728. NULL ) {
  1729. if ( mdl != WorkContext->Parameters.ReadRaw.
  1730. SavedResponseBuffer->PartialMdl ) {
  1731. IoFreeMdl( mdl );
  1732. }
  1733. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  1734. WorkContext->ResponseBuffer =
  1735. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  1736. DEALLOCATE_NONPAGED_POOL( rawBuffer );
  1737. }
  1738. return(FALSE);
  1739. }
  1740. //
  1741. // Save the address of the pipe peek buffer for the restart
  1742. // routine.
  1743. //
  1744. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.PipePeekBuffer =
  1745. pipePeekBuffer;
  1746. //
  1747. // Build the pipe peek request. We just want the header
  1748. // information. We do not need any data.
  1749. //
  1750. SrvBuildIoControlRequest(
  1751. WorkContext->Irp,
  1752. lfcb->FileObject,
  1753. WorkContext,
  1754. IRP_MJ_FILE_SYSTEM_CONTROL,
  1755. FSCTL_PIPE_PEEK,
  1756. pipePeekBuffer,
  1757. 0,
  1758. NULL,
  1759. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  1760. NULL,
  1761. NULL
  1762. );
  1763. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1764. WorkContext->FspRestartRoutine = RestartPipeReadRawPeek;
  1765. //
  1766. // Pass the request to NPFS.
  1767. //
  1768. (PVOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1769. } else {
  1770. //
  1771. // This is a blocking read, or a non-blocking read on a
  1772. // non-blocking pipe. Build and issue the read request. If
  1773. // this is a message-mode pipe, use the special ReadOverflow
  1774. // FSCTL. This FSCTL returns an error if the pipe is a
  1775. // message mode pipe and the first message in the pipe is
  1776. // either too big or has length 0. We need this because we
  1777. // can't return an error on a raw read -- the best we can do
  1778. // is return a zero-length message. So we need the
  1779. // operation to act like a Peek if the message is the wrong
  1780. // size. That's what the special FSCTL gives us.
  1781. //
  1782. SrvBuildIoControlRequest(
  1783. WorkContext->Irp,
  1784. lfcb->FileObject,
  1785. WorkContext,
  1786. IRP_MJ_FILE_SYSTEM_CONTROL,
  1787. byteModePipe ?
  1788. FSCTL_PIPE_INTERNAL_READ : FSCTL_PIPE_INTERNAL_READ_OVFLOW,
  1789. WorkContext->ResponseBuffer->Buffer,
  1790. 0,
  1791. NULL,
  1792. SmbGetUshort( &request->MaxCount ),
  1793. NULL,
  1794. NULL
  1795. );
  1796. WorkContext->FsdRestartRoutine = SrvFsdRestartReadRaw;
  1797. DEBUG WorkContext->FspRestartRoutine = NULL;
  1798. IF_SMB_DEBUG(RAW2) {
  1799. KdPrint((
  1800. "ReadRawPipe: reading from file 0x%lx, "
  1801. "length %ld, destination 0x%lx\n",
  1802. lfcb->FileObject,
  1803. SmbGetUshort( &request->MaxCount ),
  1804. WorkContext->Parameters.ReadRaw.
  1805. SavedResponseBuffer->Buffer
  1806. ));
  1807. }
  1808. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1809. //
  1810. // The read has been started. When it completes, processing
  1811. // resumes at SrvFsdRestartReadRaw.
  1812. //
  1813. }
  1814. IF_DEBUG(TRACE2) KdPrint(( "ReadRawPipe complete\n" ));
  1815. return TRUE;
  1816. } // ReadRawPipe
  1817. VOID SRVFASTCALL
  1818. RestartMdlReadRawResponse (
  1819. IN OUT PWORK_CONTEXT WorkContext
  1820. )
  1821. /*++
  1822. Routine Description:
  1823. Processes response send completion for an MDL read. Releases the
  1824. MDL back to the file system.
  1825. This routine is called in the FSP.
  1826. Arguments:
  1827. WorkContext - Supplies a pointer to the work context block
  1828. describing server-specific context for the request.
  1829. Return Value:
  1830. None.
  1831. --*/
  1832. {
  1833. NTSTATUS status;
  1834. PAGED_CODE( );
  1835. IF_DEBUG(FSD2) KdPrint(( " - RestartMdlReadRawResponse\n" ));
  1836. //
  1837. // Call the Cache Manager to release the MDL chain. If the MDL read
  1838. // failed to return an MDL (for example, if the read was entirely
  1839. // beyond EOF), then we don't have to do this.
  1840. //
  1841. if ( WorkContext->Irp->MdlAddress ) {
  1842. if( WorkContext->Rfcb->Lfcb->MdlReadComplete == NULL ||
  1843. WorkContext->Rfcb->Lfcb->MdlReadComplete(
  1844. WorkContext->Rfcb->Lfcb->FileObject,
  1845. WorkContext->Irp->MdlAddress,
  1846. WorkContext->Rfcb->Lfcb->DeviceObject ) == FALSE ) {
  1847. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  1848. WorkContext->Irp->MdlAddress,
  1849. IRP_MJ_READ,
  1850. &WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Offset,
  1851. WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.Length
  1852. );
  1853. if( !NT_SUCCESS( status ) ) {
  1854. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  1855. }
  1856. }
  1857. }
  1858. //
  1859. // Start oplock break notifications, if any are outstanding.
  1860. // SrvSendDelayedOplockBreak also sets read raw in progress to FALSE.
  1861. //
  1862. SrvSendDelayedOplockBreak( WorkContext->Connection );
  1863. //
  1864. // Finish postprocessing of the SMB.
  1865. //
  1866. SrvDereferenceWorkItem( WorkContext );
  1867. IF_DEBUG(FSD2) KdPrint(( "RestartMdlReadRawResponse complete.\n" ));
  1868. return;
  1869. } // RestartMdlReadRawResponse
  1870. VOID SRVFASTCALL
  1871. RestartPipeReadRawPeek (
  1872. IN OUT PWORK_CONTEXT WorkContext
  1873. )
  1874. /*++
  1875. Routine Description:
  1876. This function continues a read raw on a named pipe handle.
  1877. This routine is called in the FSP.
  1878. Arguments:
  1879. WorkContext - Supplies a pointer to the work context block
  1880. describing server-specific context for the request.
  1881. Return Value:
  1882. None.
  1883. --*/
  1884. {
  1885. PFILE_PIPE_PEEK_BUFFER pipePeekBuffer;
  1886. PREQ_READ_RAW request;
  1887. ULONG readLength;
  1888. ULONG readDataAvailable;
  1889. ULONG messageLength;
  1890. ULONG numberOfMessages;
  1891. PLFCB lfcb;
  1892. PRFCB rfcb;
  1893. PAGED_CODE( );
  1894. pipePeekBuffer = WorkContext->Parameters.ReadRaw.ReadRawOtherInfo.
  1895. PipePeekBuffer;
  1896. request = (PREQ_READ_RAW)WorkContext->RequestParameters;
  1897. readLength = SmbGetUshort( &request->MaxCount );
  1898. rfcb = WorkContext->Rfcb;
  1899. lfcb = rfcb->Lfcb;
  1900. //
  1901. // The pipe peek has completed. Extract the critical information,
  1902. // then free the buffer.
  1903. //
  1904. readDataAvailable = pipePeekBuffer->ReadDataAvailable;
  1905. messageLength = pipePeekBuffer->MessageLength;
  1906. numberOfMessages = pipePeekBuffer->NumberOfMessages;
  1907. DEALLOCATE_NONPAGED_POOL( pipePeekBuffer );
  1908. //
  1909. // The read request is a non-blocking read on a blocking mode pipe.
  1910. // We react differently based on whether it is a byte mode pipe or
  1911. // a message mode pipe.
  1912. //
  1913. // Byte mode: If there is _any_ data in the pipe, we go get it. The
  1914. // read will complete immediately, copying either as much data
  1915. // as is available, or enough to fill the buffer, whichever is
  1916. // less, and there will be no error. If there is no data in
  1917. // the pipe, we have to return immediately, because we can't
  1918. // wait for data to arrive.
  1919. //
  1920. // Message mode: If there are no messages available, or if the
  1921. // first message is either zero-length or bigger than the
  1922. // client's buffer, we return immediately. We can't indicate
  1923. // underflow or overflow, so we can't allow the message to be
  1924. // pulled out of the queue. Otherwise, we can do the read.
  1925. //
  1926. if ( ( rfcb->ByteModePipe &&
  1927. (readDataAvailable == 0)
  1928. )
  1929. ||
  1930. ( !rfcb->ByteModePipe &&
  1931. ( (numberOfMessages == 0)
  1932. ||
  1933. (messageLength == 0)
  1934. ||
  1935. (messageLength > readLength)
  1936. )
  1937. )
  1938. ) {
  1939. if ( WorkContext->Parameters.ReadRaw.SavedResponseBuffer != NULL ) {
  1940. if ( WorkContext->ResponseBuffer->Mdl != WorkContext->Parameters.
  1941. ReadRaw.SavedResponseBuffer->PartialMdl ) {
  1942. IoFreeMdl( WorkContext->ResponseBuffer->Mdl );
  1943. }
  1944. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer->Buffer );
  1945. DEALLOCATE_NONPAGED_POOL( WorkContext->ResponseBuffer );
  1946. WorkContext->ResponseBuffer =
  1947. WorkContext->Parameters.ReadRaw.SavedResponseBuffer;
  1948. }
  1949. WorkContext->ResponseParameters = WorkContext->ResponseHeader;
  1950. SrvFsdSendResponse( WorkContext );
  1951. IF_DEBUG(TRACE2) KdPrint(( "RestartPipeReadRawPeek complete\n" ));
  1952. return;
  1953. }
  1954. //
  1955. // We have bypassed all of the pitfalls of doing a read block raw
  1956. // on a named pipe.
  1957. //
  1958. // Build and issue the read request.
  1959. //
  1960. // *** Note that we do not use the special ReadOverflow FSCTL here
  1961. // because we know from the above tests that we don't need to.
  1962. //
  1963. SrvBuildIoControlRequest(
  1964. WorkContext->Irp,
  1965. lfcb->FileObject,
  1966. WorkContext,
  1967. IRP_MJ_FILE_SYSTEM_CONTROL,
  1968. FSCTL_PIPE_INTERNAL_READ,
  1969. WorkContext->ResponseBuffer->Buffer,
  1970. 0,
  1971. NULL,
  1972. readLength,
  1973. NULL,
  1974. NULL
  1975. );
  1976. WorkContext->FsdRestartRoutine = SrvFsdRestartReadRaw;
  1977. DEBUG WorkContext->FspRestartRoutine = NULL;
  1978. IF_SMB_DEBUG(RAW2) {
  1979. KdPrint(( "RestartPipeReadRawPeek: reading from file 0x%lx, "
  1980. "length %ld, destination 0x%lx\n",
  1981. lfcb->FileObject, readLength,
  1982. WorkContext->ResponseBuffer->Buffer ));
  1983. }
  1984. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1985. //
  1986. // The read has been started. When it completes, processing resumes
  1987. // at SrvFsdRestartReadRaw.
  1988. //
  1989. IF_DEBUG(TRACE2) KdPrint(( "RestartPipeReadRawPeek complete\n" ));
  1990. return;
  1991. } // RestartPipeReadRawPeek
  1992. VOID SRVFASTCALL
  1993. SrvDecrementRawWriteCount (
  1994. IN PRFCB Rfcb
  1995. )
  1996. /*++
  1997. Routine Description:
  1998. This routine decrements the count of active raw writes for an RFCB.
  1999. If the count goes to zero, and there are work items queued pending
  2000. completion of the raw write, they are restarted. If the count goes
  2001. to zero, and the RFCB is closing, then the RFCB's cleanup is resumed
  2002. here.
  2003. This routine is called in both the FSP and the FSD.
  2004. Arguments:
  2005. Rfcb - Supplies a pointer to the RFCB.
  2006. Return Value:
  2007. None.
  2008. --*/
  2009. {
  2010. PLIST_ENTRY listEntry;
  2011. PWORK_CONTEXT workContext;
  2012. KIRQL oldIrql;
  2013. PCONNECTION connection = Rfcb->Connection;
  2014. //
  2015. // Acquire the spin lock that guards the count.
  2016. //
  2017. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  2018. //
  2019. // Decrement the active raw write count.
  2020. //
  2021. ASSERT( Rfcb->RawWriteCount > 0 );
  2022. Rfcb->RawWriteCount--;
  2023. if ( Rfcb->RawWriteCount == 0 ) {
  2024. //
  2025. // No raw writes are active. Flush the list of work items
  2026. // that were queued pending the completion of the raw write
  2027. // by restarting each of them.
  2028. //
  2029. while ( !IsListEmpty(&Rfcb->RawWriteSerializationList) ) {
  2030. listEntry = RemoveHeadList( &Rfcb->RawWriteSerializationList );
  2031. workContext = CONTAINING_RECORD(
  2032. listEntry,
  2033. WORK_CONTEXT,
  2034. ListEntry
  2035. );
  2036. QUEUE_WORK_TO_FSP( workContext );
  2037. }
  2038. if ( GET_BLOCK_STATE(Rfcb) == BlockStateClosing ) {
  2039. //
  2040. // The count is now zero and the RFCB is closing. The
  2041. // cleanup was deferred pending the completion of all raw
  2042. // writes. Do the cleanup now.
  2043. //
  2044. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2045. SrvCompleteRfcbClose( Rfcb );
  2046. } else {
  2047. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2048. }
  2049. } else {
  2050. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  2051. }
  2052. return;
  2053. } // SrvDecrementRawWriteCount
  2054. VOID SRVFASTCALL
  2055. SrvRestartRawReceive (
  2056. IN OUT PWORK_CONTEXT WorkContext
  2057. )
  2058. /*++
  2059. Routine Description:
  2060. This is the restart routine that is invoked when Write Block Raw
  2061. write data is received. It starts the local write operation.
  2062. This routine is called in the FSP.
  2063. Arguments:
  2064. WorkContext - Supplies a pointer to the work context block
  2065. describing server-specific context for the request.
  2066. Return Value:
  2067. None.
  2068. --*/
  2069. {
  2070. PCONNECTION connection;
  2071. PIRP irp;
  2072. PRFCB rfcb;
  2073. PLFCB lfcb;
  2074. PMDL mdl;
  2075. PMDL partialMdl;
  2076. PCHAR writeAddress;
  2077. CLONG writeLength;
  2078. LARGE_INTEGER offset;
  2079. PVOID finalResponseBuffer;
  2080. CLONG immediateLength;
  2081. ULONG key;
  2082. NTSTATUS status;
  2083. PAGED_CODE( );
  2084. IF_DEBUG(FSD1) KdPrint(( " - SrvRestartRawReceive\n" ));
  2085. //
  2086. // If the I/O request failed or was canceled, or if the connection
  2087. // that received the message is no longer active, or if the server
  2088. // FSP isn't active, abort the request.
  2089. //
  2090. // *** Note that we don't send a final response in any of these
  2091. // cases. We assume that the failure is catastrophic, so
  2092. // there's no use sending a response.
  2093. //
  2094. connection = WorkContext->Connection;
  2095. irp = WorkContext->Irp;
  2096. WorkContext->CurrentWorkQueue->stats.BytesReceived += irp->IoStatus.Information;
  2097. if ( irp->Cancel ||
  2098. !NT_SUCCESS(irp->IoStatus.Status) ||
  2099. (GET_BLOCK_STATE(connection) != BlockStateActive) ||
  2100. SrvFspTransitioning ) {
  2101. IF_DEBUG(TRACE2) {
  2102. if ( irp->Cancel ) {
  2103. KdPrint(( " I/O canceled\n" ));
  2104. } else if ( !NT_SUCCESS(irp->IoStatus.Status) ) {
  2105. KdPrint(( " I/O failed: %X\n", irp->IoStatus.Status ));
  2106. } else if ( SrvFspTransitioning ) {
  2107. KdPrint(( " Server is shutting down.\n" ));
  2108. } else {
  2109. KdPrint(( " Connection no longer active\n" ));
  2110. }
  2111. }
  2112. //
  2113. // Abort the raw write.
  2114. //
  2115. AbortRawWrite( WorkContext );
  2116. IF_DEBUG(TRACE2) KdPrint(( "SrvRestartRawReceive complete\n" ));
  2117. return;
  2118. }
  2119. //
  2120. // Set up local variables.
  2121. //
  2122. rfcb = WorkContext->Rfcb;
  2123. lfcb = rfcb->Lfcb;
  2124. finalResponseBuffer = WorkContext->Parameters.WriteRaw.FinalResponseBuffer;
  2125. immediateLength = WorkContext->Parameters.WriteRaw.ImmediateLength;
  2126. //
  2127. // Determine whether we're doing "copy write" or "MDL write".
  2128. //
  2129. if ( WorkContext->Parameters.WriteRaw.MdlWrite ) {
  2130. #if DBG
  2131. IF_SMB_DEBUG(RAW2) {
  2132. KdPrint(( "SrvRestartRawReceive: Receive MDL chain after receive\n" ));
  2133. DumpMdlChain( irp->MdlAddress );
  2134. }
  2135. #endif
  2136. //
  2137. // This was an MDL write. If a partial MDL was built (because
  2138. // of immediate data), unmap it. Then complete the MDL write.
  2139. //
  2140. mdl = WorkContext->Parameters.WriteRaw.FirstMdl;
  2141. partialMdl = WorkContext->Irp->MdlAddress;
  2142. if ( partialMdl != mdl ) {
  2143. ASSERT( (partialMdl->MdlFlags & MDL_PARTIAL) != 0 );
  2144. MmPrepareMdlForReuse( partialMdl );
  2145. }
  2146. //
  2147. // Build the "complete MDL write" request. Note that
  2148. // irp->IoStatus.Information, which is where we're supposed to
  2149. // put the amount of data actually written, already contains the
  2150. // length of the received data.
  2151. //
  2152. irp->MdlAddress = mdl;
  2153. if ( !WorkContext->Parameters.WriteRaw.ImmediateWriteDone ) {
  2154. irp->IoStatus.Information += immediateLength;
  2155. }
  2156. #if DBG
  2157. IF_SMB_DEBUG(RAW2) {
  2158. KdPrint(( "SrvRestartRawReceive: Completing MDL write with length 0x%lx\n",
  2159. irp->IoStatus.Information ));
  2160. DumpMdlChain( mdl );
  2161. }
  2162. #endif
  2163. if( lfcb->MdlWriteComplete == NULL ||
  2164. lfcb->MdlWriteComplete(
  2165. lfcb->FileObject,
  2166. &WorkContext->Parameters.WriteRaw.Offset,
  2167. mdl,
  2168. lfcb->DeviceObject ) == FALSE ) {
  2169. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  2170. mdl,
  2171. IRP_MJ_WRITE,
  2172. &WorkContext->Parameters.WriteRaw.Offset,
  2173. WorkContext->Parameters.WriteRaw.Length
  2174. );
  2175. if( !NT_SUCCESS( status ) ) {
  2176. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  2177. }
  2178. }
  2179. SrvFsdRestartWriteRaw( WorkContext );
  2180. return;
  2181. }
  2182. //
  2183. // We're doing a copy write. Get parameters for the request.
  2184. //
  2185. offset = WorkContext->Parameters.WriteRaw.Offset;
  2186. mdl = WorkContext->RequestBuffer->Mdl;
  2187. //
  2188. // Determine the amount of data to write. This is the actual amount
  2189. // of data sent by the client. (Note that this cannot be more than
  2190. // the client originally requested.)
  2191. //
  2192. writeAddress = (PCHAR)WorkContext->RequestBuffer->Buffer;
  2193. writeLength = irp->IoStatus.Information;
  2194. //
  2195. // If the immediate data was not written earlier, it immedidately
  2196. // precedes the data we just received. Adjust writeAddress and
  2197. // writeLength so that it too is written.
  2198. //
  2199. if ( !WorkContext->Parameters.WriteRaw.ImmediateWriteDone ) {
  2200. writeAddress -= immediateLength;
  2201. writeLength += immediateLength;
  2202. }
  2203. //
  2204. // Form the lock key using the FID and the PID.
  2205. //
  2206. // *** The FID must be included in the key in order to account for
  2207. // the folding of multiple remote compatibility mode opens into
  2208. // a single local open.
  2209. //
  2210. key = rfcb->ShiftedFid | WorkContext->Parameters.WriteRaw.Pid;
  2211. //
  2212. // Try the fast I/O path first.
  2213. //
  2214. if ( lfcb->FastIoWrite != NULL ) {
  2215. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  2216. if ( lfcb->FastIoWrite(
  2217. lfcb->FileObject,
  2218. &offset,
  2219. writeLength,
  2220. TRUE,
  2221. key,
  2222. writeAddress,
  2223. &WorkContext->Irp->IoStatus,
  2224. lfcb->DeviceObject
  2225. ) ) {
  2226. //
  2227. // The fast I/O path worked. Call the restart routine directly.
  2228. //
  2229. SrvFsdRestartWriteRaw( WorkContext );
  2230. return;
  2231. }
  2232. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  2233. }
  2234. //
  2235. // The fast I/O path failed, so we need to issue a real I/O request.
  2236. //
  2237. // Remap the MDL to describe only the received data, which may be
  2238. // less than was originally mapped.
  2239. //
  2240. // !!! Is this really necessary? Can't we just pass in the entire
  2241. // MDL, and count on the file system to know when to stop?
  2242. //
  2243. if ( writeLength != WorkContext->RequestBuffer->BufferLength ) {
  2244. MmInitializeMdl( mdl, writeAddress, writeLength );
  2245. MmBuildMdlForNonPagedPool( mdl );
  2246. }
  2247. if ( rfcb->ShareType != ShareTypePipe ) {
  2248. //
  2249. // Start the write request, reusing the receive IRP.
  2250. //
  2251. SrvBuildReadOrWriteRequest(
  2252. irp, // input IRP address
  2253. lfcb->FileObject, // target file object address
  2254. WorkContext, // context
  2255. IRP_MJ_WRITE, // major function code
  2256. 0, // minor function code
  2257. writeAddress, // buffer address
  2258. writeLength, // buffer length
  2259. mdl, // MDL address
  2260. offset, // byte offset
  2261. key // lock key
  2262. );
  2263. } else {
  2264. //
  2265. // Build a write request for NPFS.
  2266. //
  2267. SrvBuildIoControlRequest(
  2268. WorkContext->Irp,
  2269. lfcb->FileObject,
  2270. WorkContext,
  2271. IRP_MJ_FILE_SYSTEM_CONTROL,
  2272. FSCTL_PIPE_INTERNAL_WRITE,
  2273. writeAddress,
  2274. writeLength,
  2275. NULL,
  2276. 0,
  2277. NULL,
  2278. NULL
  2279. );
  2280. }
  2281. IF_SMB_DEBUG(RAW2) {
  2282. KdPrint(( "SrvRestartRawReceive: writing to file 0x%lx, "
  2283. "offset %ld, length %ld\n",
  2284. lfcb->FileObject, offset.LowPart, writeLength ));
  2285. }
  2286. //
  2287. // Pass the request to the file system.
  2288. //
  2289. WorkContext->FsdRestartRoutine = SrvFsdRestartWriteRaw;
  2290. DEBUG WorkContext->FspRestartRoutine = NULL;
  2291. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2292. //
  2293. // The write has been started. When it completes, processing
  2294. // continues at SrvFsdRestartWriteRaw.
  2295. //
  2296. return;
  2297. } // SrvRestartRawReceive
  2298. VOID SRVFASTCALL
  2299. SrvRestartReadRawComplete (
  2300. IN OUT PWORK_CONTEXT WorkContext
  2301. )
  2302. /*++
  2303. Routine Description:
  2304. This routine completes a read raw by starting any oplock breaks that
  2305. may have been deferred due to the read raw.
  2306. This routine is called in the FSP.
  2307. Arguments:
  2308. WorkContext - Supplies a pointer to the work context block
  2309. describing server-specific context for the request.
  2310. Return Value:
  2311. None.
  2312. --*/
  2313. {
  2314. PAGED_CODE( );
  2315. //
  2316. // Start oplock break notifications, if any are outstanding.
  2317. // SrvSendDelayedOplockBreak also sets read raw in progress to FALSE.
  2318. //
  2319. SrvSendDelayedOplockBreak( WorkContext->Connection );
  2320. //
  2321. // Finish postprocessing of the SMB.
  2322. //
  2323. SrvDereferenceWorkItem( WorkContext );
  2324. return;
  2325. } // SrvRestartReadRawComplete
  2326. VOID SRVFASTCALL
  2327. SrvRestartWriteCompleteResponse (
  2328. IN OUT PWORK_CONTEXT WorkContext
  2329. )
  2330. /*++
  2331. Routine Description:
  2332. This is the restart routine that is invoked to clean up after a
  2333. Write Block Raw/Mpx completes, and the necessary clean up could not
  2334. be done in the FSD. See RestartWriteCompleteResponse in fsd.c.
  2335. This routine is called in the FSP.
  2336. Arguments:
  2337. WorkContext - Supplies a pointer to the work context block
  2338. describing server-specific context for the request.
  2339. Return Value:
  2340. None.
  2341. --*/
  2342. {
  2343. PAGED_CODE( );
  2344. IF_DEBUG(WORKER1) KdPrint(( " - SrvRestartWriteCompleteResponse\n" ));
  2345. //
  2346. // Decrement the active raw write count for the RFCB, potentially
  2347. // allowing the RFCB to be closed. If WorkContext->Rfcb is NULL,
  2348. // then the count has been decremented in the fsd.
  2349. //
  2350. if ( WorkContext->Rfcb != NULL ) {
  2351. SrvDecrementRawWriteCount ( WorkContext->Rfcb );
  2352. }
  2353. //
  2354. // Dereference control blocks and the connection.
  2355. //
  2356. SrvReleaseContext( WorkContext );
  2357. SrvDereferenceConnection( WorkContext->Connection );
  2358. WorkContext->Connection = NULL;
  2359. WorkContext->Endpoint = NULL; // not a referenced pointer
  2360. //
  2361. // Put the work item back on the raw mode work item list.
  2362. //
  2363. SrvRequeueRawModeWorkItem( WorkContext );
  2364. IF_DEBUG(TRACE2) KdPrint(( "SrvRestartWriteCompleteResponse complete\n" ));
  2365. return;
  2366. } // SrvRestartWriteCompleteResponse
  2367. VOID SRVFASTCALL
  2368. SrvBuildAndSendWriteCompleteResponse (
  2369. IN OUT PWORK_CONTEXT WorkContext
  2370. )
  2371. /*++
  2372. Routine Description:
  2373. Sets up and sends a final response to a Write Block Raw/Mpx request.
  2374. This routine is called in the FSP. It is invoked as a restart routine
  2375. from the FSD when the status to be returned is not STATUS_SUCCESS.
  2376. Arguments:
  2377. WorkContext - Supplies a pointer to the work context block
  2378. describing server-specific context for the request.
  2379. Return Value:
  2380. None.
  2381. --*/
  2382. {
  2383. PAGED_CODE( );
  2384. SrvFsdBuildWriteCompleteResponse(
  2385. WorkContext,
  2386. WorkContext->Irp->IoStatus.Status,
  2387. WorkContext->Irp->IoStatus.Information
  2388. );
  2389. WorkContext->ResponseBuffer->DataLength =
  2390. (CLONG)( (PCHAR)WorkContext->ResponseParameters -
  2391. (PCHAR)WorkContext->ResponseHeader );
  2392. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  2393. SRV_START_SEND_2(
  2394. WorkContext,
  2395. SrvFsdSendCompletionRoutine,
  2396. WorkContext->FsdRestartRoutine,
  2397. NULL
  2398. );
  2399. return;
  2400. } // SrvBuildAndSendWriteCompleteResponse