Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5361 lines
163 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbrdwrt.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs:
  7. Lock and Read
  8. Read
  9. Read and X
  10. Seek
  11. Write
  12. Write and Close
  13. Write and Unlock
  14. Write and X
  15. Note that raw mode and multiplexed mode SMB processors are not
  16. contained in this module. Check smbraw.c and smbmpx.c instead.
  17. SMB commands that pertain exclusively to locking (LockByteRange,
  18. UnlockByteRange, and LockingAndX) are processed in smblock.c.
  19. --*/
  20. #include "precomp.h"
  21. #include "smbrdwrt.tmh"
  22. #pragma hdrstop
  23. #define BugCheckFileId SRV_FILE_SMBRDWRT
  24. //
  25. // External routine from smblock.c
  26. //
  27. VOID
  28. TimeoutLockRequest (
  29. IN PKDPC Dpc,
  30. IN PVOID DeferredContext,
  31. IN PVOID SystemArgument1,
  32. IN PVOID SystemArgument2
  33. );
  34. //
  35. // Forward declarations
  36. //
  37. STATIC
  38. VOID SRVFASTCALL
  39. RestartLockAndRead (
  40. IN OUT PWORK_CONTEXT WorkContext
  41. );
  42. STATIC
  43. VOID SRVFASTCALL
  44. RestartPipeReadAndXPeek (
  45. IN OUT PWORK_CONTEXT WorkContext
  46. );
  47. STATIC
  48. BOOLEAN
  49. SetNewPosition (
  50. IN PRFCB Rfcb,
  51. IN OUT PULONG Offset,
  52. IN BOOLEAN RelativeSeek
  53. );
  54. STATIC
  55. VOID SRVFASTCALL
  56. SetNewSize (
  57. IN OUT PWORK_CONTEXT WorkContext
  58. );
  59. SMB_PROCESSOR_RETURN_TYPE
  60. SrvSmbWriteAndXCompressed (
  61. SMB_PROCESSOR_PARAMETERS
  62. );
  63. VOID SRVFASTCALL
  64. RestartPrepareWriteCompressed (
  65. IN OUT PWORK_CONTEXT WorkContext
  66. );
  67. VOID SRVFASTCALL
  68. RestartWriteCompressed (
  69. IN OUT PWORK_CONTEXT WorkContext
  70. );
  71. VOID SRVFASTCALL
  72. RestartWriteCompressedCopy (
  73. IN OUT PWORK_CONTEXT WorkContext
  74. );
  75. #ifdef ALLOC_PRAGMA
  76. #pragma alloc_text( PAGE, SrvSmbLockAndRead )
  77. #pragma alloc_text( PAGE, SrvSmbReadAndX )
  78. #pragma alloc_text( PAGE, SrvSmbSeek )
  79. #pragma alloc_text( PAGE, SrvSmbWrite )
  80. #pragma alloc_text( PAGE, SrvSmbWriteAndX )
  81. #pragma alloc_text( PAGE, SrvSmbWriteAndXCompressed )
  82. #pragma alloc_text( PAGE, RestartPrepareWriteCompressed )
  83. #pragma alloc_text( PAGE, RestartWriteCompressedCopy )
  84. #pragma alloc_text( PAGE, SrvRestartChainedClose )
  85. #pragma alloc_text( PAGE, RestartLockAndRead )
  86. #pragma alloc_text( PAGE, RestartPipeReadAndXPeek )
  87. #pragma alloc_text( PAGE, SrvRestartWriteAndUnlock )
  88. #pragma alloc_text( PAGE, SrvRestartWriteAndXRaw )
  89. #pragma alloc_text( PAGE, SetNewSize )
  90. #pragma alloc_text( PAGE, SrvBuildAndSendErrorResponse )
  91. #pragma alloc_text( PAGE8FIL, SetNewPosition )
  92. #endif
  93. SMB_PROCESSOR_RETURN_TYPE
  94. SrvSmbLockAndRead (
  95. SMB_PROCESSOR_PARAMETERS
  96. )
  97. /*++
  98. Routine Description:
  99. Processes Lock And Read SMB. The Lock part of this SMB is started
  100. here as an asynchronous request. When the request completes, the
  101. routine RestartLockAndRead is called. If the lock was obtained,
  102. that routine calls SrvSmbRead, the SMB processor for the core Read
  103. SMB, to process the Read part of the Lock And Read SMB.
  104. Arguments:
  105. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  106. of the parameters to SMB processor routines.
  107. Return Value:
  108. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  109. --*/
  110. {
  111. PREQ_READ request;
  112. USHORT fid;
  113. LARGE_INTEGER length;
  114. LARGE_INTEGER offset;
  115. ULONG key;
  116. BOOLEAN failImmediately;
  117. PRFCB rfcb;
  118. PLFCB lfcb;
  119. PSRV_TIMER timer;
  120. NTSTATUS status = STATUS_SUCCESS;
  121. SMB_STATUS SmbStatus = SmbStatusInProgress;
  122. PAGED_CODE( );
  123. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  124. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOCK_AND_READ;
  125. SrvWmiStartContext(WorkContext);
  126. request = (PREQ_READ)WorkContext->RequestParameters;
  127. //
  128. // Verify the FID. If verified, the RFCB is referenced and its
  129. // addresses is stored in the WorkContext block, and the RFCB
  130. // address is returned.
  131. //
  132. fid = SmbGetUshort( &request->Fid );
  133. rfcb = SrvVerifyFid(
  134. WorkContext,
  135. fid,
  136. TRUE,
  137. SrvRestartSmbReceived, // serialize with raw write
  138. &status
  139. );
  140. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  141. if ( !NT_SUCCESS( status )) {
  142. //
  143. // Invalid file ID or write behind error. Reject the request.
  144. //
  145. IF_DEBUG(ERRORS) {
  146. KdPrint((
  147. "SrvSmbLockAndRead: Status %X on FID: 0x%lx\n",
  148. status,
  149. fid
  150. ));
  151. }
  152. SrvSetSmbError( WorkContext, status );
  153. SmbStatus = SmbStatusSendResponse;
  154. goto Cleanup;
  155. }
  156. //
  157. // The work item has been queued because a raw write is in
  158. // progress.
  159. //
  160. SmbStatus = SmbStatusInProgress;
  161. goto Cleanup;
  162. }
  163. if( rfcb->Lfcb->Session->IsSessionExpired )
  164. {
  165. status = SESSION_EXPIRED_STATUS_CODE;
  166. SrvSetSmbError( WorkContext, status );
  167. SmbStatus = SmbStatusSendResponse;
  168. goto Cleanup;
  169. }
  170. //
  171. // Verify that the client has lock access to the file via the
  172. // specified handle.
  173. //
  174. if ( rfcb->LockAccessGranted ) {
  175. //
  176. // Get the offset and length of the range being locked. Combine the
  177. // FID with the caller's PID to form the local lock key.
  178. //
  179. // *** The FID must be included in the key in order to account for
  180. // the folding of multiple remote compatibility mode opens into
  181. // a single local open.
  182. //
  183. offset.QuadPart = SmbGetUlong( &request->Offset );
  184. length.QuadPart = SmbGetUshort( &request->Count );
  185. key = rfcb->ShiftedFid |
  186. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  187. IF_SMB_DEBUG(READ_WRITE1) {
  188. KdPrint(( "Lock and Read request; FID 0x%lx, count %ld, offset %ld\n",
  189. fid, length.LowPart, offset.LowPart ));
  190. }
  191. #ifdef INCLUDE_SMB_PERSISTENT
  192. WorkContext->Parameters.Lock.Offset.QuadPart = offset.QuadPart;
  193. WorkContext->Parameters.Lock.Length.QuadPart = length.QuadPart;
  194. WorkContext->Parameters.Lock.Exclusive = TRUE;
  195. #endif
  196. lfcb = rfcb->Lfcb;
  197. IF_SMB_DEBUG(READ_WRITE2) {
  198. KdPrint(( "SrvSmbLockAndRead: Locking in file 0x%p: (%ld,%ld), key 0x%lx\n",
  199. lfcb->FileObject, offset.LowPart, length.LowPart, key ));
  200. }
  201. //
  202. // If the session has expired, return that info
  203. //
  204. if( lfcb->Session->IsSessionExpired )
  205. {
  206. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  207. status = SESSION_EXPIRED_STATUS_CODE;
  208. SmbStatus = SmbStatusSendResponse;
  209. goto Cleanup;
  210. }
  211. //
  212. // Try the turbo lock path first. If the client is retrying the
  213. // lock that just failed, we want FailImmediately to be FALSE, so
  214. // that the fast path fails if there's a conflict.
  215. //
  216. failImmediately = (BOOLEAN)(
  217. (offset.QuadPart != rfcb->PagedRfcb->LastFailingLockOffset.QuadPart)
  218. &&
  219. (offset.QuadPart < SrvLockViolationOffset) );
  220. if ( lfcb->FastIoLock != NULL ) {
  221. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksAttempted );
  222. if ( lfcb->FastIoLock(
  223. lfcb->FileObject,
  224. &offset,
  225. &length,
  226. IoGetCurrentProcess(),
  227. key,
  228. failImmediately,
  229. TRUE,
  230. &WorkContext->Irp->IoStatus,
  231. lfcb->DeviceObject
  232. ) ) {
  233. //
  234. // If the turbo path got the lock, start the read.
  235. // Otherwise, return an error.
  236. //
  237. #ifdef INCLUDE_SMB_PERSISTENT
  238. if ( NT_SUCCESS( WorkContext->Irp->IoStatus.Status ) &&
  239. ! rfcb->PersistentHandle ) {
  240. #else
  241. if ( NT_SUCCESS( WorkContext->Irp->IoStatus.Status ) ) {
  242. #endif
  243. InterlockedIncrement( &rfcb->NumberOfLocks );
  244. SmbStatus = SrvSmbRead( WorkContext );
  245. goto Cleanup;
  246. }
  247. WorkContext->Parameters.Lock.Timer = NULL;
  248. RestartLockAndRead( WorkContext );
  249. return SmbStatusInProgress;
  250. }
  251. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksFailed );
  252. }
  253. //
  254. // The turbo path failed (or didn't exist). Start the lock request,
  255. // reusing the receive IRP. If the client is retrying the lock that
  256. // just failed, start a timer for the request.
  257. //
  258. timer = NULL;
  259. if ( !failImmediately ) {
  260. timer = SrvAllocateTimer( );
  261. if ( timer == NULL ) {
  262. failImmediately = TRUE;
  263. }
  264. }
  265. SrvBuildLockRequest(
  266. WorkContext->Irp, // input IRP address
  267. lfcb->FileObject, // target file object address
  268. WorkContext, // context
  269. offset, // byte offset
  270. length, // range length
  271. key, // lock key
  272. failImmediately,
  273. TRUE // exclusive lock?
  274. );
  275. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  276. WorkContext->bAlreadyTrace = FALSE;
  277. WorkContext->FspRestartRoutine = RestartLockAndRead;
  278. //
  279. // Start the timer, if necessary.
  280. //
  281. WorkContext->Parameters.Lock.Timer = timer;
  282. if ( timer != NULL ) {
  283. SrvSetTimer(
  284. timer,
  285. &SrvLockViolationDelayRelative,
  286. TimeoutLockRequest,
  287. WorkContext
  288. );
  289. }
  290. //
  291. // Pass the request to the file system.
  292. //
  293. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  294. //
  295. // The lock request has been started. Return the InProgress status
  296. // to the caller, indicating that the caller should do nothing
  297. // further with the SMB/WorkContext at the present time.
  298. //
  299. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbLockAndRead complete\n" ));
  300. SmbStatus = SmbStatusInProgress;
  301. } else {
  302. SrvStatistics.GrantedAccessErrors++;
  303. IF_DEBUG(ERRORS) {
  304. KdPrint(( "SrvSmbLockAndRead: Lock access not granted.\n"));
  305. }
  306. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  307. status = STATUS_ACCESS_DENIED;
  308. SmbStatus = SmbStatusSendResponse;
  309. }
  310. Cleanup:
  311. SrvWmiEndContext(WorkContext);
  312. return SmbStatus;
  313. } // SrvSmbLockAndRead
  314. SMB_PROCESSOR_RETURN_TYPE
  315. SrvSmbRead (
  316. SMB_PROCESSOR_PARAMETERS
  317. )
  318. /*++
  319. Routine Description:
  320. Processes the Read SMB. This is the "core" read. Also processes
  321. the Read part of the Lock and Read SMB.
  322. Arguments:
  323. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  324. of the parameters to SMB processor routines.
  325. Return Value:
  326. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  327. --*/
  328. {
  329. PREQ_READ request;
  330. PRESP_READ response;
  331. NTSTATUS status = STATUS_SUCCESS;
  332. SMB_STATUS SmbStatus = SmbStatusInProgress;
  333. USHORT fid;
  334. PRFCB rfcb;
  335. PLFCB lfcb;
  336. PCHAR readAddress;
  337. CLONG readLength;
  338. LARGE_INTEGER offset;
  339. ULONG key;
  340. SHARE_TYPE shareType;
  341. PAGED_CODE( );
  342. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  343. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ;
  344. SrvWmiStartContext(WorkContext);
  345. request = (PREQ_READ)WorkContext->RequestParameters;
  346. response = (PRESP_READ)WorkContext->ResponseParameters;
  347. fid = SmbGetUshort( &request->Fid );
  348. IF_SMB_DEBUG(READ_WRITE1) {
  349. KdPrint(( "Read request; FID 0x%lx, count %ld, offset %ld\n",
  350. fid, SmbGetUshort( &request->Count ),
  351. SmbGetUlong( &request->Offset ) ));
  352. }
  353. //
  354. // First, verify the FID. If verified, the RFCB is referenced and
  355. // its address is stored in the WorkContext block, and the RFCB
  356. // address is returned.
  357. //
  358. rfcb = SrvVerifyFid(
  359. WorkContext,
  360. fid,
  361. TRUE,
  362. SrvRestartSmbReceived, // serialize with raw write
  363. &status
  364. );
  365. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  366. if ( !NT_SUCCESS(status) ) {
  367. //
  368. // Invalid file ID or write behind error. Reject the
  369. // request.
  370. //
  371. IF_DEBUG(ERRORS) {
  372. KdPrint((
  373. "SrvSmbRead: Status %X on FID: 0x%lx\n",
  374. status,
  375. fid
  376. ));
  377. }
  378. SrvSetSmbError( WorkContext, status );
  379. SmbStatus = SmbStatusSendResponse;
  380. goto Cleanup;
  381. }
  382. //
  383. // The work item has been queued because a raw write is in
  384. // progress.
  385. //
  386. SmbStatus = SmbStatusInProgress;
  387. goto Cleanup;
  388. }
  389. lfcb = rfcb->Lfcb;
  390. shareType = rfcb->ShareType;
  391. //
  392. // If the session has expired, return that info
  393. //
  394. if( lfcb->Session->IsSessionExpired )
  395. {
  396. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  397. status = SESSION_EXPIRED_STATUS_CODE;
  398. SmbStatus = SmbStatusSendResponse;
  399. goto Cleanup;
  400. }
  401. //
  402. // Verify that the client has read access to the file via the
  403. // specified handle.
  404. //
  405. if ( !rfcb->ReadAccessGranted ) {
  406. CHECK_PAGING_IO_ACCESS(
  407. WorkContext,
  408. rfcb->GrantedAccess,
  409. &status );
  410. if ( !NT_SUCCESS( status ) ) {
  411. SrvStatistics.GrantedAccessErrors++;
  412. IF_DEBUG(ERRORS) {
  413. KdPrint(( "SrvSmbRead: Read access not granted.\n"));
  414. }
  415. SrvSetSmbError( WorkContext, status );
  416. SmbStatus = SmbStatusSendResponse;
  417. goto Cleanup;
  418. }
  419. }
  420. //
  421. // If this operation may block, and we are running short of free
  422. // work items, fail this SMB with an out of resources error.
  423. //
  424. if ( rfcb->BlockingModePipe ) {
  425. if ( SrvReceiveBufferShortage( ) ) {
  426. //
  427. // Fail the operation.
  428. //
  429. SrvStatistics.BlockingSmbsRejected++;
  430. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  431. status = STATUS_INSUFF_SERVER_RESOURCES;
  432. SmbStatus = SmbStatusSendResponse;
  433. goto Cleanup;
  434. } else {
  435. //
  436. // It is okay to start a blocking operation.
  437. // SrvReceiveBufferShortage() has already incremented
  438. // SrvBlockingOpsInProgress.
  439. //
  440. WorkContext->BlockingOperation = TRUE;
  441. }
  442. }
  443. //
  444. // Form the lock key using the FID and the PID. (This is also
  445. // irrelevant for pipes.)
  446. //
  447. // *** The FID must be included in the key in order to account for
  448. // the folding of multiple remote compatibility mode opens into
  449. // a single local open.
  450. //
  451. key = rfcb->ShiftedFid |
  452. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  453. //
  454. // See if the direct host IPX smart card can handle this read. If so,
  455. // return immediately, and the card will call our restart routine at
  456. // SrvIpxSmartCardReadComplete
  457. //
  458. if( rfcb->PagedRfcb->IpxSmartCardContext ) {
  459. IF_DEBUG( SIPX ) {
  460. KdPrint(( "SrvSmbRead: calling SmartCard Read for context %p\n",
  461. WorkContext ));
  462. }
  463. //
  464. // Set the fields needed by SrvIpxSmartCardReadComplete in case the smart
  465. // card is going to handle this request
  466. //
  467. WorkContext->Parameters.SmartCardRead.MdlReadComplete = lfcb->MdlReadComplete;
  468. WorkContext->Parameters.SmartCardRead.DeviceObject = lfcb->DeviceObject;
  469. if( SrvIpxSmartCard.Read( WorkContext->RequestBuffer->Buffer,
  470. rfcb->PagedRfcb->IpxSmartCardContext,
  471. key,
  472. WorkContext ) == TRUE ) {
  473. IF_DEBUG( SIPX ) {
  474. KdPrint(( " SrvSmbRead: SmartCard Read returns TRUE\n" ));
  475. }
  476. SmbStatus = SmbStatusInProgress;
  477. goto Cleanup;
  478. }
  479. IF_DEBUG( SIPX ) {
  480. KdPrint(( " SrvSmbRead: SmartCard Read returns FALSE\n" ));
  481. }
  482. }
  483. //
  484. // Determine the maximum amount of data we can read. This is the
  485. // minimum of the amount requested by the client and the amount of
  486. // room left in the response buffer. (Note that even though we may
  487. // use an MDL read, the read length is still limited to the size of
  488. // an SMB buffer.)
  489. //
  490. readAddress = (PCHAR)response->Buffer;
  491. readLength = MIN(
  492. (CLONG)SmbGetUshort( &request->Count ),
  493. WorkContext->ResponseBuffer->BufferLength -
  494. PTR_DIFF(readAddress, WorkContext->ResponseHeader)
  495. );
  496. //
  497. // Get the file offset. (This is irrelevant for pipes.)
  498. //
  499. offset.QuadPart = SmbGetUlong( &request->Offset );
  500. //
  501. // Try the fast I/O path first. If that fails, fall through to the
  502. // normal build-an-IRP path.
  503. //
  504. if ( lfcb->FastIoRead != NULL ) {
  505. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  506. try {
  507. if ( lfcb->FastIoRead(
  508. lfcb->FileObject,
  509. &offset,
  510. readLength,
  511. TRUE,
  512. key,
  513. readAddress,
  514. &WorkContext->Irp->IoStatus,
  515. lfcb->DeviceObject
  516. ) ) {
  517. //
  518. // The fast I/O path worked. Call the restart routine directly
  519. // to do postprocessing (including sending the response).
  520. //
  521. WorkContext->bAlreadyTrace = TRUE;
  522. SrvFsdRestartRead( WorkContext );
  523. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbRead complete.\n" ));
  524. SmbStatus = SmbStatusInProgress;
  525. goto Cleanup;
  526. }
  527. }
  528. except( EXCEPTION_EXECUTE_HANDLER ) {
  529. // Fall through to the slow path on an exception
  530. NTSTATUS status = GetExceptionCode();
  531. IF_DEBUG(ERRORS) {
  532. KdPrint(("FastIoRead threw exception %x\n", status ));
  533. }
  534. }
  535. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  536. }
  537. //
  538. // The turbo path failed. Build the read request, reusing the
  539. // receive IRP.
  540. //
  541. if ( rfcb->ShareType != ShareTypePipe ) {
  542. //
  543. // Note that we never do MDL reads here. The reasoning behind
  544. // this is that because the read is going into an SMB buffer, it
  545. // can't be all that large (by default, no more than 4K bytes),
  546. // so the difference in cost between copy and MDL is minimal; in
  547. // fact, copy read is probably faster than MDL read.
  548. //
  549. // Build an MDL describing the read buffer. Note that if the
  550. // file system can complete the read immediately, the MDL isn't
  551. // really needed, but if the file system must send the request
  552. // to its FSP, the MDL _is_ needed.
  553. //
  554. // *** Note the assumption that the response buffer already has
  555. // a valid full MDL from which a partial MDL can be built.
  556. //
  557. IoBuildPartialMdl(
  558. WorkContext->ResponseBuffer->Mdl,
  559. WorkContext->ResponseBuffer->PartialMdl,
  560. readAddress,
  561. readLength
  562. );
  563. //
  564. // Build the IRP.
  565. //
  566. SrvBuildReadOrWriteRequest(
  567. WorkContext->Irp, // input IRP address
  568. lfcb->FileObject, // target file object address
  569. WorkContext, // context
  570. IRP_MJ_READ, // major function code
  571. 0, // minor function code
  572. readAddress, // buffer address
  573. readLength, // buffer length
  574. WorkContext->ResponseBuffer->PartialMdl, // MDL address
  575. offset, // byte offset
  576. key // lock key
  577. );
  578. IF_SMB_DEBUG(READ_WRITE2) {
  579. KdPrint(( "SrvSmbRead: copy read from file 0x%p, offset %ld, length %ld, destination 0x%p\n",
  580. lfcb->FileObject, offset.LowPart, readLength,
  581. readAddress ));
  582. }
  583. } else { // if ( rfcb->ShareType != ShareTypePipe )
  584. //
  585. // Build the PIPE_INTERNAL_READ IRP.
  586. //
  587. SrvBuildIoControlRequest(
  588. WorkContext->Irp,
  589. lfcb->FileObject,
  590. WorkContext,
  591. IRP_MJ_FILE_SYSTEM_CONTROL,
  592. FSCTL_PIPE_INTERNAL_READ,
  593. readAddress,
  594. 0,
  595. NULL,
  596. readLength,
  597. NULL,
  598. NULL
  599. );
  600. IF_SMB_DEBUG(READ_WRITE2) {
  601. KdPrint(( "SrvSmbRead: reading from file 0x%p, length %ld, destination 0x%p\n",
  602. lfcb->FileObject, readLength, readAddress ));
  603. }
  604. }
  605. //
  606. // Load the restart routine address and pass the request to the file
  607. // system.
  608. //
  609. WorkContext->bAlreadyTrace = TRUE;
  610. WorkContext->FsdRestartRoutine = SrvFsdRestartRead;
  611. DEBUG WorkContext->FspRestartRoutine = NULL;
  612. #if SRVCATCH
  613. if( rfcb->SrvCatch ) {
  614. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  615. WorkContext->bAlreadyTrace = FALSE;
  616. WorkContext->FspRestartRoutine = SrvFsdRestartRead;
  617. }
  618. #endif
  619. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  620. //
  621. // The read has been started. Control will return to the restart
  622. // routine when the read completes.
  623. //
  624. SmbStatus = SmbStatusInProgress;
  625. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbRead complete.\n" ));
  626. Cleanup:
  627. SrvWmiEndContext(WorkContext);
  628. return SmbStatus;
  629. } // SrvSmbRead
  630. SMB_PROCESSOR_RETURN_TYPE
  631. SrvSmbReadAndX (
  632. SMB_PROCESSOR_PARAMETERS
  633. )
  634. /*++
  635. Routine Description:
  636. Processes the Read And X SMB.
  637. Arguments:
  638. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  639. of the parameters to SMB processor routines.
  640. Return Value:
  641. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  642. --*/
  643. {
  644. PREQ_READ_ANDX request;
  645. PREQ_NT_READ_ANDX ntRequest;
  646. PRESP_READ_ANDX response;
  647. NTSTATUS status = STATUS_SUCCESS;
  648. SMB_STATUS SmbStatus = SmbStatusInProgress;
  649. USHORT fid;
  650. PRFCB rfcb;
  651. PLFCB lfcb;
  652. CLONG bufferOffset;
  653. PCHAR readAddress;
  654. CLONG readLength;
  655. LARGE_INTEGER offset;
  656. ULONG key;
  657. SHARE_TYPE shareType;
  658. BOOLEAN largeRead;
  659. PMDL mdl = NULL;
  660. UCHAR minorFunction;
  661. PBYTE readBuffer;
  662. USHORT flags2;
  663. BOOLEAN compressedData = FALSE;
  664. PAGED_CODE( );
  665. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  666. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_AND_X;
  667. SrvWmiStartContext(WorkContext);
  668. request = (PREQ_READ_ANDX)WorkContext->RequestParameters;
  669. ntRequest = (PREQ_NT_READ_ANDX)WorkContext->RequestParameters;
  670. response = (PRESP_READ_ANDX)WorkContext->ResponseParameters;
  671. fid = SmbGetUshort( &request->Fid );
  672. IF_SMB_DEBUG(READ_WRITE1) {
  673. KdPrint(( "ReadAndX request; FID 0x%lx, count %ld, offset %ld\n",
  674. fid, SmbGetUshort( &request->MaxCount ),
  675. SmbGetUlong( &request->Offset ) ));
  676. }
  677. //
  678. // First, verify the FID. If verified, the RFCB is referenced and
  679. // its address is stored in the WorkContext block, and the RFCB
  680. // address is returned.
  681. //
  682. rfcb = SrvVerifyFid(
  683. WorkContext,
  684. fid,
  685. TRUE,
  686. SrvRestartSmbReceived, // serialize with raw write
  687. &status
  688. );
  689. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  690. if ( !NT_SUCCESS(status) ) {
  691. //
  692. // Invalid file ID or write behind error. Reject the
  693. // request.
  694. //
  695. IF_DEBUG(ERRORS) {
  696. KdPrint((
  697. "SrvSmbReadAndX Status %X on FID: 0x%lx\n",
  698. status,
  699. fid
  700. ));
  701. }
  702. SrvSetSmbError( WorkContext, status );
  703. SmbStatus = SmbStatusSendResponse;
  704. goto Cleanup;
  705. }
  706. //
  707. // The work item has been queued because a raw write is in
  708. // progress.
  709. //
  710. SmbStatus = SmbStatusInProgress;
  711. goto Cleanup;
  712. }
  713. lfcb = rfcb->Lfcb;
  714. shareType = rfcb->ShareType;
  715. //
  716. // If the session has expired, return that info
  717. //
  718. if( lfcb->Session->IsSessionExpired )
  719. {
  720. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  721. status = SESSION_EXPIRED_STATUS_CODE;
  722. SmbStatus = SmbStatusSendResponse;
  723. goto Cleanup;
  724. }
  725. //
  726. // Verify that the client has read access to the file via the
  727. // specified handle.
  728. //
  729. if ( !rfcb->ReadAccessGranted ) {
  730. CHECK_PAGING_IO_ACCESS(
  731. WorkContext,
  732. rfcb->GrantedAccess,
  733. &status );
  734. if ( !NT_SUCCESS( status ) ) {
  735. SrvStatistics.GrantedAccessErrors++;
  736. IF_DEBUG(ERRORS) {
  737. KdPrint(( "SrvSmbReadAndX: Read access not granted.\n"));
  738. }
  739. SrvSetSmbError( WorkContext, status );
  740. SmbStatus = SmbStatusSendResponse;
  741. goto Cleanup;
  742. }
  743. }
  744. readLength = (CLONG)SmbGetUshort( &request->MaxCount );
  745. //
  746. // NT requests allow the specification of up to 32 bits worth of read length.
  747. // This field is overlaid with the Timeout field for pipe reads. Some redirs
  748. // set this field to 0xFFFFFFFF, even if a pipe isn't involved. So, we need to
  749. // filter out those fellows.
  750. //
  751. if( request->WordCount == 12 &&
  752. shareType != ShareTypePipe
  753. && SmbGetUshort( &ntRequest->MaxCountHigh ) != 0xFFFF ) {
  754. readLength |= ((CLONG)SmbGetUshort( &ntRequest->MaxCountHigh )) << 16;
  755. }
  756. //
  757. // The returned data must be longword aligned. (Note the assumption
  758. // that the SMB itself is longword aligned.)
  759. //
  760. // NOTE: Don't change this for 64-bit, as it will Break Win2K interop
  761. bufferOffset = PTR_DIFF(response->Buffer, WorkContext->ResponseHeader);
  762. WorkContext->Parameters.ReadAndX.PadCount = (USHORT)(3 - (bufferOffset & 3));
  763. // This was changed to be Pointer-size aligned so this works in 64-bit
  764. bufferOffset = (bufferOffset + 3) & ~3;
  765. //
  766. // If we are not reading from a disk file, or we're connectionless,
  767. // or there's an ANDX command,
  768. // don't let the client exceed the negotiated buffer size.
  769. //
  770. if( shareType != ShareTypeDisk ||
  771. request->AndXCommand != SMB_COM_NO_ANDX_COMMAND ||
  772. WorkContext->Endpoint->IsConnectionless ) {
  773. readLength = MIN( readLength,
  774. WorkContext->ResponseBuffer->BufferLength - bufferOffset
  775. );
  776. } else {
  777. //
  778. // We're letting large reads through! Make sure it isn't
  779. // too large
  780. //
  781. readLength = MIN( readLength, SrvMaxReadSize );
  782. }
  783. largeRead = ( readLength > WorkContext->ResponseBuffer->BufferLength - bufferOffset );
  784. readAddress = (PCHAR)WorkContext->ResponseHeader + bufferOffset;
  785. WorkContext->Parameters.ReadAndX.ReadAddress = readAddress;
  786. WorkContext->Parameters.ReadAndX.ReadLength = readLength;
  787. //
  788. // Get the file offset. (This is irrelevant for pipes.)
  789. //
  790. if ( shareType != ShareTypePipe ) {
  791. if ( request->WordCount == 10 ) {
  792. //
  793. // The client supplied a 32-bit offset.
  794. //
  795. offset.QuadPart = SmbGetUlong( &request->Offset );
  796. } else if ( request->WordCount == 12 ) {
  797. //
  798. // The client supplied a 64-bit offset.
  799. //
  800. offset.LowPart = SmbGetUlong( &ntRequest->Offset );
  801. offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh );
  802. //
  803. // Reject negative offsets
  804. //
  805. if ( offset.QuadPart < 0 ) {
  806. SrvLogInvalidSmb( WorkContext );
  807. IF_DEBUG(ERRORS) {
  808. KdPrint(( "SrvSmbReadAndX: Negative offset rejected.\n"));
  809. }
  810. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  811. status = STATUS_INVALID_SMB;
  812. SmbStatus = SmbStatusSendResponse;
  813. goto Cleanup;
  814. }
  815. //
  816. // Is the client requesting compressed data?
  817. //
  818. flags2 = SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 );
  819. if( flags2 & SMB_FLAGS2_COMPRESSED ) {
  820. if( SrvSupportsCompression == TRUE &&
  821. request->AndXCommand == SMB_COM_NO_ANDX_COMMAND &&
  822. (lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) ) {
  823. SrvStatistics.CompressedReads++;
  824. compressedData = TRUE;
  825. }
  826. //
  827. // Turn off the bit in the response until we absolutely know that
  828. // we've gotten compressed data to return to the client
  829. //
  830. flags2 &= ~SMB_FLAGS2_COMPRESSED;
  831. SmbPutAlignedUshort( &WorkContext->ResponseHeader->Flags2, flags2 );
  832. }
  833. } else {
  834. //
  835. // This is an invalid word count for Read and X.
  836. //
  837. SrvLogInvalidSmb( WorkContext );
  838. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  839. status = STATUS_INVALID_SMB;
  840. SmbStatus = SmbStatusSendResponse;
  841. goto Cleanup;
  842. }
  843. WorkContext->Parameters.ReadAndX.ReadOffset = offset;
  844. } else {
  845. if ( (request->WordCount != 10) && (request->WordCount != 12) ) {
  846. //
  847. // This is an invalid word count for Read and X.
  848. //
  849. SrvLogInvalidSmb( WorkContext );
  850. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  851. status = STATUS_INVALID_SMB;
  852. SmbStatus = SmbStatusSendResponse;
  853. goto Cleanup;
  854. }
  855. }
  856. //
  857. // Form the lock key using the FID and the PID. (This is also
  858. // irrelevant for pipes.)
  859. //
  860. // *** The FID must be included in the key in order to account for
  861. // the folding of multiple remote compatibility mode opens into
  862. // a single local open.
  863. //
  864. key = rfcb->ShiftedFid |
  865. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  866. //
  867. // Save the AndX command code. This is necessary because the read
  868. // data may overwrite the AndX command. This command must be Close.
  869. // We don't need to save the offset because we're not going to look
  870. // at the AndX command request after starting the read.
  871. //
  872. WorkContext->NextCommand = request->AndXCommand;
  873. if ( request->AndXCommand == SMB_COM_CLOSE ) {
  874. //
  875. // Make sure the accompanying CLOSE fits within the received SMB buffer
  876. //
  877. if( (PCHAR)WorkContext->RequestHeader + request->AndXOffset + FIELD_OFFSET(REQ_CLOSE,Buffer) >
  878. END_OF_REQUEST_SMB( WorkContext ) ) {
  879. SrvLogInvalidSmb( WorkContext );
  880. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  881. status = STATUS_INVALID_SMB;
  882. SmbStatus = SmbStatusSendResponse;
  883. goto Cleanup;
  884. }
  885. WorkContext->Parameters.ReadAndX.LastWriteTimeInSeconds =
  886. ((PREQ_CLOSE)((PUCHAR)WorkContext->RequestHeader +
  887. request->AndXOffset))->LastWriteTimeInSeconds;
  888. }
  889. //
  890. // Try the fast I/O path first. If that fails, fall through to the
  891. // normal build-an-IRP path.
  892. //
  893. if( !largeRead && !compressedData ) {
  894. small_read:
  895. if ( lfcb->FastIoRead != NULL ) {
  896. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  897. try {
  898. if ( lfcb->FastIoRead(
  899. lfcb->FileObject,
  900. &offset,
  901. readLength,
  902. TRUE,
  903. key,
  904. readAddress,
  905. &WorkContext->Irp->IoStatus,
  906. lfcb->DeviceObject
  907. ) ) {
  908. //
  909. // The fast I/O path worked. Call the restart routine directly
  910. // to do postprocessing (including sending the response).
  911. //
  912. WorkContext->bAlreadyTrace = TRUE;
  913. SrvFsdRestartReadAndX( WorkContext );
  914. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbReadAndX complete.\n" ));
  915. SmbStatus = SmbStatusInProgress;
  916. goto Cleanup;
  917. }
  918. }
  919. except( EXCEPTION_EXECUTE_HANDLER ) {
  920. // Fall through to the slow path on an exception
  921. NTSTATUS status = GetExceptionCode();
  922. IF_DEBUG(ERRORS) {
  923. KdPrint(("FastIoRead threw exception %x\n", status ));
  924. }
  925. }
  926. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  927. }
  928. //
  929. // The turbo path failed. Build the read request, reusing the
  930. // receive IRP.
  931. //
  932. if ( shareType == ShareTypePipe ) {
  933. //
  934. // Pipe read. If this is a non-blocking read, ensure we won't
  935. // block; otherwise, proceed with the request.
  936. //
  937. if ( rfcb->BlockingModePipe &&
  938. (SmbGetUshort( &request->MinCount ) == 0) ) {
  939. PFILE_PIPE_PEEK_BUFFER pipePeekBuffer;
  940. //
  941. // This is a non-blocking read. Allocate a buffer to peek
  942. // the pipe, so that we can tell if a read operation will
  943. // block. This buffer is freed in
  944. // RestartPipeReadAndXPeek().
  945. //
  946. pipePeekBuffer = ALLOCATE_NONPAGED_POOL(
  947. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  948. BlockTypeDataBuffer
  949. );
  950. if ( pipePeekBuffer == NULL ) {
  951. //
  952. // Return to client with out of memory status.
  953. //
  954. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  955. status = STATUS_INSUFF_SERVER_RESOURCES;
  956. SmbStatus = SmbStatusSendResponse;
  957. goto Cleanup;
  958. }
  959. //
  960. // Save the address of the peek buffer so that the restart
  961. // routine can find it.
  962. //
  963. WorkContext->Parameters.ReadAndX.PipePeekBuffer = pipePeekBuffer;
  964. //
  965. // Build the pipe peek request. We just want the header
  966. // information. We do not need any data.
  967. //
  968. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  969. WorkContext->FspRestartRoutine = RestartPipeReadAndXPeek;
  970. SrvBuildIoControlRequest(
  971. WorkContext->Irp,
  972. lfcb->FileObject,
  973. WorkContext,
  974. IRP_MJ_FILE_SYSTEM_CONTROL,
  975. FSCTL_PIPE_PEEK,
  976. pipePeekBuffer,
  977. 0,
  978. NULL,
  979. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  980. NULL,
  981. NULL
  982. );
  983. //
  984. // Pass the request to NPFS.
  985. //
  986. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  987. } else {
  988. //
  989. // This operation may block. If we are short of receive
  990. // work items, reject the request.
  991. //
  992. if ( SrvReceiveBufferShortage( ) ) {
  993. //
  994. // Fail the operation.
  995. //
  996. SrvStatistics.BlockingSmbsRejected++;
  997. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  998. status = STATUS_INSUFF_SERVER_RESOURCES;
  999. SmbStatus = SmbStatusSendResponse;
  1000. goto Cleanup;
  1001. } else {
  1002. //
  1003. // It is okay to start a blocking operation.
  1004. // SrvReceiveBufferShortage() has already incremented
  1005. // SrvBlockingOpsInProgress.
  1006. //
  1007. WorkContext->BlockingOperation = TRUE;
  1008. //
  1009. // Proceed with a potentially blocking read.
  1010. //
  1011. WorkContext->Parameters.ReadAndX.PipePeekBuffer = NULL;
  1012. RestartPipeReadAndXPeek( WorkContext );
  1013. }
  1014. }
  1015. } else {
  1016. //
  1017. // This is not a pipe read.
  1018. //
  1019. // Note that we never do MDL reads here. The reasoning behind
  1020. // this is that because the read is going into an SMB buffer, it
  1021. // can't be all that large (by default, no more than 4K bytes),
  1022. // so the difference in cost between copy and MDL is minimal; in
  1023. // fact, copy read is probably faster than MDL read.
  1024. //
  1025. // Build an MDL describing the read buffer. Note that if the
  1026. // file system can complete the read immediately, the MDL isn't
  1027. // really needed, but if the file system must send the request
  1028. // to its FSP, the MDL _is_ needed.
  1029. //
  1030. // *** Note the assumption that the response buffer already has
  1031. // a valid full MDL from which a partial MDL can be built.
  1032. //
  1033. IoBuildPartialMdl(
  1034. WorkContext->ResponseBuffer->Mdl,
  1035. WorkContext->ResponseBuffer->PartialMdl,
  1036. readAddress,
  1037. readLength
  1038. );
  1039. //
  1040. // Build the IRP.
  1041. //
  1042. SrvBuildReadOrWriteRequest(
  1043. WorkContext->Irp, // input IRP address
  1044. lfcb->FileObject, // target file object address
  1045. WorkContext, // context
  1046. IRP_MJ_READ, // major function code
  1047. 0, // minor function code
  1048. readAddress, // buffer address
  1049. readLength, // buffer length
  1050. WorkContext->ResponseBuffer->PartialMdl, // MDL address
  1051. offset, // byte offset
  1052. key // lock key
  1053. );
  1054. IF_SMB_DEBUG(READ_WRITE2) {
  1055. KdPrint(( "SrvSmbReadAndX: copy read from file 0x%p, offset %ld, length %ld, destination 0x%p\n",
  1056. lfcb->FileObject, offset.LowPart, readLength,
  1057. readAddress ));
  1058. }
  1059. //
  1060. // Pass the request to the file system. If the chained command
  1061. // is Close, we need to arrange to restart in the FSP after the
  1062. // read completes.
  1063. //
  1064. if ( WorkContext->NextCommand != SMB_COM_CLOSE ) {
  1065. WorkContext->bAlreadyTrace = TRUE;
  1066. WorkContext->FsdRestartRoutine = SrvFsdRestartReadAndX;
  1067. DEBUG WorkContext->FspRestartRoutine = NULL;
  1068. } else {
  1069. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1070. WorkContext->bAlreadyTrace = FALSE;
  1071. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndX;
  1072. }
  1073. #if SRVCATCH
  1074. if( rfcb->SrvCatch ) {
  1075. //
  1076. // Ensure passive level on restart
  1077. //
  1078. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1079. WorkContext->bAlreadyTrace = FALSE;
  1080. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndX;
  1081. }
  1082. #endif
  1083. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1084. //
  1085. // The read has been started. Control will return to the restart
  1086. // routine when the read completes.
  1087. //
  1088. }
  1089. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbReadAndX complete.\n" ));
  1090. SmbStatus = SmbStatusInProgress;
  1091. goto Cleanup;
  1092. }
  1093. IF_DEBUG( COMPRESSION ) {
  1094. if( compressedData ) {
  1095. KdPrint(("SRV: Compressed ReadAndX: %u requested at %u:%u\n",
  1096. readLength, offset.HighPart, offset.LowPart ));
  1097. }
  1098. }
  1099. //
  1100. // The client is doing a read from a disk file which exceeds our SMB buffer, or
  1101. // the client is asking for compressed data. We do our best to satisfy it.
  1102. //
  1103. // If we are unable to get buffers, we resort to doing a short read which fits
  1104. // in our smb buffer.
  1105. //
  1106. WorkContext->Parameters.ReadAndX.MdlRead = FALSE;
  1107. //
  1108. // Does the target file system support the cache manager routines?
  1109. //
  1110. if( lfcb->FileObject->Flags & FO_CACHE_SUPPORTED ) {
  1111. //
  1112. // We can use an MDL read. Try the fast I/O path first.
  1113. //
  1114. WorkContext->Irp->MdlAddress = NULL;
  1115. WorkContext->Irp->IoStatus.Information = 0;
  1116. //
  1117. // Check if this is a compressed read request. If so, we'll try
  1118. // an Mdl Read Compressed request to the cache manager.
  1119. //
  1120. //
  1121. // If the requested offset is aligned on a 4KB boundary,
  1122. // the readLength is a multiple of 4KB, the file is
  1123. // compressed, and the file size is at least 4KB -> try for compressed!
  1124. //
  1125. if( compressedData &&
  1126. lfcb->FastIoReadCompressed &&
  1127. (offset.LowPart & 0xfff) == 0 &&
  1128. (readLength & 0xfff) == 0 &&
  1129. (rfcb->Mfcb->NonpagedMfcb->OpenFileAttributes & FILE_ATTRIBUTE_COMPRESSED) &&
  1130. rfcb->Mfcb->NonpagedMfcb->OpenFileSize.QuadPart >= 4096 ) {
  1131. ULONG compressedInfoLength;
  1132. WorkContext->Parameters.ReadAndXCompressed.ReadOffset = offset;
  1133. WorkContext->Parameters.ReadAndXCompressed.ReadLength = readLength;
  1134. RtlZeroMemory( &WorkContext->Parameters.ReadAndXCompressed.Aux,
  1135. sizeof( WorkContext->Parameters.ReadAndXCompressed.Aux ) );
  1136. //
  1137. // Calculate the maximal length for the COMPRESSED_DATA_INFO structure
  1138. //
  1139. compressedInfoLength = (FIELD_OFFSET(COMPRESSED_DATA_INFO, CompressedChunkSizes ) +
  1140. (((readLength + 4096 - 1) / 4096) * sizeof(ULONG) ));
  1141. //
  1142. // Just to be sure!
  1143. //
  1144. compressedInfoLength += sizeof( ULONG );
  1145. //
  1146. // The COMPRESSED_DATA_INFO is pointed to by ReadAndX.Aux.Buffer,
  1147. // which is carved out of the 4KB response buffer. Place it into
  1148. // the WORK_CONTEXT block at a quad aligned spot. We'll move it into
  1149. // place later for the response.
  1150. //
  1151. WorkContext->Parameters.ReadAndXCompressed.Aux.Buffer =
  1152. (PVOID)((ULONG_PTR)(WorkContext->ResponseBuffer->Buffer) +
  1153. WorkContext->ResponseBuffer->BufferLength -
  1154. compressedInfoLength);
  1155. //
  1156. // Quad align the pointer
  1157. //
  1158. WorkContext->Parameters.ReadAndXCompressed.Aux.Buffer =
  1159. (PVOID)((ULONG_PTR)(WorkContext->Parameters.ReadAndXCompressed.Aux.Buffer) & ~7);
  1160. //
  1161. // Set the length of the buffer
  1162. //
  1163. WorkContext->Parameters.ReadAndXCompressed.Aux.Length = compressedInfoLength;
  1164. //
  1165. // Be a good citizen!
  1166. //
  1167. RtlZeroMemory( WorkContext->Parameters.ReadAndXCompressed.Aux.Buffer,
  1168. WorkContext->Parameters.ReadAndXCompressed.Aux.Length );
  1169. //
  1170. // Try the fast compressed path first...
  1171. //
  1172. try {
  1173. if ( lfcb->FastIoReadCompressed(
  1174. lfcb->FileObject, // File Object
  1175. &offset, // File offset
  1176. readLength, // Length of desired data
  1177. key, // Lock Key
  1178. NULL, // Output buffer
  1179. &WorkContext->Irp->MdlAddress, // Output MDL chain
  1180. &WorkContext->Irp->IoStatus, // I/O status block
  1181. WorkContext->Parameters.ReadAndXCompressed.Aux.Buffer,// CompressedDataInfo
  1182. WorkContext->Parameters.ReadAndXCompressed.Aux.Length,// Size of above buffer
  1183. lfcb->DeviceObject // Device object
  1184. ) ) {
  1185. //
  1186. // The fast I/O path worked. Send the data.
  1187. //
  1188. WorkContext->bAlreadyTrace = TRUE;
  1189. SrvFsdRestartReadAndXCompressed( WorkContext );
  1190. SmbStatus = SmbStatusInProgress;
  1191. goto Cleanup;
  1192. }
  1193. }
  1194. except( EXCEPTION_EXECUTE_HANDLER ) {
  1195. // Fall through to the slow path on an exception
  1196. NTSTATUS status = GetExceptionCode();
  1197. IF_DEBUG(ERRORS) {
  1198. KdPrint(("FastIoRead threw exception %x\n", status ));
  1199. }
  1200. }
  1201. //
  1202. // The fast path failed, and a compressed read entirely
  1203. // succeeds or entirely fails. There is no need to adjust
  1204. // offset or readLength (as we do with noncompressed reads)
  1205. //
  1206. IF_DEBUG( COMPRESSION ) {
  1207. KdPrint(( " Fast Path failed, submitting IRP\n" ));
  1208. }
  1209. ASSERT( WorkContext->Irp->MdlAddress == NULL );
  1210. WorkContext->Irp->IoStatus.Information = 0;
  1211. SrvBuildReadOrWriteRequest(
  1212. WorkContext->Irp, // input IRP address
  1213. lfcb->FileObject, // target file object address
  1214. WorkContext, // context
  1215. IRP_MJ_READ, // major function code
  1216. IRP_MN_MDL | IRP_MN_COMPRESSED, // minor function code
  1217. NULL, // buffer address
  1218. readLength, // buffer length
  1219. NULL, // MDL address
  1220. offset, // byte offset
  1221. key // lock key
  1222. );
  1223. WorkContext->Irp->Tail.Overlay.AuxiliaryBuffer =
  1224. (PVOID)&WorkContext->Parameters.ReadAndXCompressed.Aux;
  1225. WorkContext->bAlreadyTrace = TRUE;
  1226. WorkContext->FsdRestartRoutine = SrvFsdRestartReadAndXCompressed;
  1227. #if DBG
  1228. WorkContext->bAlreadyTrace = FALSE;
  1229. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndXCompressed;
  1230. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1231. #endif
  1232. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1233. SmbStatus = SmbStatusInProgress;
  1234. goto Cleanup;
  1235. } else if( compressedData ) {
  1236. SrvStatistics.CompressedReadsRejected++;
  1237. IF_DEBUG( COMPRESSION ) {
  1238. KdPrint(("SRV: Compressed ReadAndX: UNCOMPRESSED RESPONSE\n" ));
  1239. }
  1240. }
  1241. //
  1242. // Not a compressed read.
  1243. //
  1244. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  1245. if( lfcb->MdlRead(
  1246. lfcb->FileObject,
  1247. &offset,
  1248. readLength,
  1249. key,
  1250. &WorkContext->Irp->MdlAddress,
  1251. &WorkContext->Irp->IoStatus,
  1252. lfcb->DeviceObject
  1253. ) && WorkContext->Irp->MdlAddress != NULL ) {
  1254. //
  1255. // The fast I/O path worked. Send the data.
  1256. //
  1257. WorkContext->Parameters.ReadAndX.MdlRead = TRUE;
  1258. WorkContext->Parameters.ReadAndX.CacheMdl = WorkContext->Irp->MdlAddress;
  1259. WorkContext->bAlreadyTrace = TRUE;
  1260. SrvFsdRestartLargeReadAndX( WorkContext );
  1261. SmbStatus = SmbStatusInProgress;
  1262. goto Cleanup;
  1263. }
  1264. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  1265. if( WorkContext->Irp->MdlAddress ) {
  1266. //
  1267. // The fast I/O path failed. We need to issue a regular MDL read
  1268. // request.
  1269. //
  1270. // The fast path may have partially succeeded, returning a partial MDL
  1271. // chain. We need to adjust our read request to account for that.
  1272. //
  1273. offset.QuadPart += WorkContext->Irp->IoStatus.Information;
  1274. readLength -= (ULONG)WorkContext->Irp->IoStatus.Information;
  1275. mdl = WorkContext->Irp->MdlAddress;
  1276. WorkContext->Parameters.ReadAndX.CacheMdl = mdl;
  1277. readBuffer = NULL;
  1278. minorFunction = IRP_MN_MDL;
  1279. WorkContext->Parameters.ReadAndX.MdlRead = TRUE;
  1280. }
  1281. }
  1282. if( WorkContext->Parameters.ReadAndX.MdlRead == FALSE ) {
  1283. minorFunction = 0;
  1284. //
  1285. // We have to use a normal "copy" read. We need to allocate a
  1286. // separate buffer to hold the data, and we'll use the SMB buffer
  1287. // itself to hold the MDL
  1288. //
  1289. readBuffer = ALLOCATE_HEAP( readLength, BlockTypeLargeReadX );
  1290. if( readBuffer == NULL ) {
  1291. IF_DEBUG( ERRORS ) {
  1292. KdPrint(( "SrvSmbReadX: Unable to allocate large buffer\n" ));
  1293. }
  1294. //
  1295. // Trim back the read length so it will fit in the smb buffer and
  1296. // return as much data as we can.
  1297. //
  1298. readLength = MIN( readLength,
  1299. WorkContext->ResponseBuffer->BufferLength - bufferOffset
  1300. );
  1301. largeRead = FALSE;
  1302. goto small_read;
  1303. }
  1304. WorkContext->Parameters.ReadAndX.Buffer = readBuffer;
  1305. //
  1306. // Use the SMB buffer as the MDL to describe the just allocated read buffer.
  1307. // Lock the buffer into memory
  1308. //
  1309. mdl = (PMDL)(((ULONG_PTR)readAddress + sizeof(PVOID) - 1) & ~(sizeof(PVOID)-1));
  1310. MmInitializeMdl( mdl, readBuffer, readLength );
  1311. try {
  1312. MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
  1313. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1314. IF_DEBUG( ERRORS ) {
  1315. KdPrint(( "SrvSmbReadX: MmProbeAndLockPages status %X\n", GetExceptionCode() ));
  1316. }
  1317. FREE_HEAP( readBuffer );
  1318. WorkContext->Parameters.ReadAndX.Buffer = NULL;
  1319. //
  1320. // Trim back the read length so it will fit in the smb buffer and
  1321. // return as much data as we can.
  1322. //
  1323. readLength = MIN( readLength,
  1324. WorkContext->ResponseBuffer->BufferLength - bufferOffset
  1325. );
  1326. largeRead = FALSE;
  1327. goto small_read;
  1328. }
  1329. if (MmGetSystemAddressForMdlSafe( mdl,NormalPoolPriority ) == NULL) {
  1330. // The mapping call has failed. fail the read operation with the
  1331. // appropriate error.
  1332. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  1333. status = STATUS_INSUFF_SERVER_RESOURCES;
  1334. SmbStatus = SmbStatusSendResponse;
  1335. goto Cleanup;
  1336. }
  1337. if( lfcb->FastIoRead != NULL ) {
  1338. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  1339. try {
  1340. if ( lfcb->FastIoRead(
  1341. lfcb->FileObject,
  1342. &offset,
  1343. readLength,
  1344. TRUE,
  1345. key,
  1346. readBuffer,
  1347. &WorkContext->Irp->IoStatus,
  1348. lfcb->DeviceObject
  1349. ) ) {
  1350. //
  1351. // The fast I/O path worked. Send the data.
  1352. //
  1353. WorkContext->bAlreadyTrace = TRUE;
  1354. SrvFsdRestartLargeReadAndX( WorkContext );
  1355. SmbStatus = SmbStatusInProgress;
  1356. goto Cleanup;
  1357. }
  1358. }
  1359. except( EXCEPTION_EXECUTE_HANDLER ) {
  1360. // Fall through to the slow path on an exception
  1361. NTSTATUS status = GetExceptionCode();
  1362. IF_DEBUG(ERRORS) {
  1363. KdPrint(("FastIoRead threw exception %x\n", status ));
  1364. }
  1365. }
  1366. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  1367. }
  1368. }
  1369. //
  1370. // We didn't satisfy the request with the fast I/O path
  1371. //
  1372. SrvBuildReadOrWriteRequest(
  1373. WorkContext->Irp, // input IRP address
  1374. lfcb->FileObject, // target file object address
  1375. WorkContext, // context
  1376. IRP_MJ_READ, // major function code
  1377. minorFunction, // minor function code
  1378. readBuffer, // buffer address
  1379. readLength, // buffer length
  1380. mdl, // MDL address
  1381. offset, // byte offset
  1382. key // lock key
  1383. );
  1384. //
  1385. // Pass the request to the file system. We want to queue the
  1386. // response to the head because we've tied up a fair amount
  1387. // resources with this SMB.
  1388. //
  1389. WorkContext->QueueToHead = 1;
  1390. WorkContext->bAlreadyTrace = TRUE;
  1391. WorkContext->FsdRestartRoutine = SrvFsdRestartLargeReadAndX;
  1392. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1393. //
  1394. // The read has been started. When it completes, processing
  1395. // continues at SrvFsdRestartLargeReadAndX
  1396. //
  1397. SmbStatus = SmbStatusInProgress;
  1398. Cleanup:
  1399. SrvWmiEndContext(WorkContext);
  1400. return SmbStatus;
  1401. } // SrvSmbReadAndX
  1402. SMB_PROCESSOR_RETURN_TYPE
  1403. SrvSmbSeek (
  1404. SMB_PROCESSOR_PARAMETERS
  1405. )
  1406. /*++
  1407. Routine Description:
  1408. Processes the Seek SMB.
  1409. Arguments:
  1410. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  1411. of the parameters to SMB processor routines.
  1412. Return Value:
  1413. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  1414. --*/
  1415. {
  1416. PREQ_SEEK request;
  1417. PRESP_SEEK response;
  1418. NTSTATUS status = STATUS_SUCCESS;
  1419. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1420. PRFCB rfcb;
  1421. PLFCB lfcb;
  1422. LONG offset;
  1423. ULONG newPosition;
  1424. IO_STATUS_BLOCK iosb;
  1425. FILE_STANDARD_INFORMATION fileInformation;
  1426. BOOLEAN lockHeld = FALSE;
  1427. SMB_DIALECT smbDialect;
  1428. PFAST_IO_DISPATCH fastIoDispatch;
  1429. PAGED_CODE( );
  1430. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1431. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SEEK;
  1432. SrvWmiStartContext(WorkContext);
  1433. request = (PREQ_SEEK)WorkContext->RequestParameters;
  1434. response = (PRESP_SEEK)WorkContext->ResponseParameters;
  1435. offset = (LONG)SmbGetUlong( &request->Offset );
  1436. IF_SMB_DEBUG(READ_WRITE1) {
  1437. KdPrint(( "Seek request; FID 0x%lx, mode %ld, offset %ld\n",
  1438. SmbGetUshort( &request->Fid ),
  1439. SmbGetUshort( &request->Mode ),
  1440. offset ));
  1441. }
  1442. //
  1443. // Verify the FID. If verified, the RFCB block is referenced
  1444. // and its addresses is stored in the WorkContext block, and the
  1445. // RFCB address is returned.
  1446. //
  1447. rfcb = SrvVerifyFid(
  1448. WorkContext,
  1449. SmbGetUshort( &request->Fid ),
  1450. TRUE,
  1451. SrvRestartSmbReceived, // serialize with raw write
  1452. &status
  1453. );
  1454. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1455. if ( !NT_SUCCESS(status) ) {
  1456. //
  1457. // Invalid file ID or write behind error. Reject the request.
  1458. //
  1459. IF_DEBUG(ERRORS) {
  1460. KdPrint((
  1461. "SrvSmbSeek: Status %X on FID: 0x%lx\n",
  1462. status,
  1463. SmbGetUshort( &request->Fid )
  1464. ));
  1465. }
  1466. SrvSetSmbError( WorkContext, status );
  1467. SmbStatus = SmbStatusSendResponse;
  1468. goto Cleanup;
  1469. }
  1470. //
  1471. // The work item has been queued because a raw write is in
  1472. // progress.
  1473. //
  1474. SmbStatus = SmbStatusInProgress;
  1475. goto Cleanup;
  1476. }
  1477. if( rfcb->Lfcb->Session->IsSessionExpired )
  1478. {
  1479. status = SESSION_EXPIRED_STATUS_CODE;
  1480. SrvSetSmbError( WorkContext, status );
  1481. SmbStatus = SmbStatusSendResponse;
  1482. goto Cleanup;
  1483. }
  1484. //
  1485. // We maintain our own file pointer, because the I/O and file system
  1486. // don't do it for us (at least not the way we need them to). This
  1487. // isn't all that bad, since the target file position is passed in
  1488. // all read/write SMBs. So we don't actually issue a system call to
  1489. // set the file position here, although we do have to return the
  1490. // position we would have set it to.
  1491. //
  1492. // The seek request is in one of three modes:
  1493. //
  1494. // 0 = seek relative to beginning of file
  1495. // 1 = seek relative to current file position
  1496. // 2 = seek relative to end of file
  1497. //
  1498. // For modes 0 and 1, we can easily calculate the final position.
  1499. // For mode 2, however, we have to issue a system call to obtain the
  1500. // current end of file and calculate the final position relative to
  1501. // that. Note that we can't just maintain our own end of file marker,
  1502. // because another local process could change it out from under us.
  1503. //
  1504. // !!! Need to check for wraparound (either positive or negative).
  1505. //
  1506. switch ( SmbGetUshort( &request->Mode ) ) {
  1507. case 0:
  1508. //
  1509. // Seek relative to beginning of file. The new file position
  1510. // is simply that specified in the request. Note that this
  1511. // may be beyond the actual end of the file. This is OK.
  1512. // Negative seeks must be handled specially.
  1513. //
  1514. newPosition = offset;
  1515. if ( !SetNewPosition( rfcb, &newPosition, FALSE ) ) {
  1516. goto negative_seek;
  1517. }
  1518. break;
  1519. case 1:
  1520. //
  1521. // Seek relative to current position. The new file position is
  1522. // the current position plus the specified offset (which may be
  1523. // negative). Note that this may be beyond the actual end of
  1524. // the file. This is OK. Negative seeks must be handled
  1525. // specially.
  1526. //
  1527. newPosition = offset;
  1528. if ( !SetNewPosition( rfcb, &newPosition, TRUE ) ) {
  1529. goto negative_seek;
  1530. }
  1531. break;
  1532. case 2:
  1533. //
  1534. // Seek relative to end of file. The new file position
  1535. // is the current end of file plus the specified offset.
  1536. //
  1537. IF_SMB_DEBUG(READ_WRITE2) {
  1538. KdPrint(( "SrvSmbSeek: Querying end-of-file\n" ));
  1539. }
  1540. lfcb = rfcb->Lfcb;
  1541. fastIoDispatch = lfcb->DeviceObject->DriverObject->FastIoDispatch;
  1542. if ( fastIoDispatch &&
  1543. fastIoDispatch->FastIoQueryStandardInfo &&
  1544. fastIoDispatch->FastIoQueryStandardInfo(
  1545. lfcb->FileObject,
  1546. TRUE,
  1547. &fileInformation,
  1548. &iosb,
  1549. lfcb->DeviceObject
  1550. ) ) {
  1551. status = iosb.Status;
  1552. } else {
  1553. status = NtQueryInformationFile(
  1554. lfcb->FileHandle,
  1555. &iosb,
  1556. &fileInformation,
  1557. sizeof(fileInformation),
  1558. FileStandardInformation
  1559. );
  1560. }
  1561. if ( !NT_SUCCESS(status) ) {
  1562. INTERNAL_ERROR(
  1563. ERROR_LEVEL_UNEXPECTED,
  1564. "SrvSmbSeek: QueryInformationFile (file information) "
  1565. "returned %X",
  1566. status,
  1567. NULL
  1568. );
  1569. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  1570. SrvSetSmbError( WorkContext, status );
  1571. SmbStatus = SmbStatusSendResponse;
  1572. goto Cleanup;
  1573. }
  1574. if ( fileInformation.EndOfFile.HighPart != 0 ) {
  1575. INTERNAL_ERROR(
  1576. ERROR_LEVEL_UNEXPECTED,
  1577. "SrvSmbSeek: EndOfFile is beyond where client can read",
  1578. NULL,
  1579. NULL
  1580. );
  1581. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, STATUS_END_OF_FILE);
  1582. SrvSetSmbError( WorkContext, STATUS_END_OF_FILE);
  1583. status = STATUS_END_OF_FILE;
  1584. SmbStatus = SmbStatusSendResponse;
  1585. goto Cleanup;
  1586. }
  1587. newPosition = fileInformation.EndOfFile.LowPart + offset;
  1588. if ( !SetNewPosition( rfcb, &newPosition, FALSE ) ) {
  1589. goto negative_seek;
  1590. }
  1591. break;
  1592. default:
  1593. //
  1594. // Invalid seek mode. Reject the request.
  1595. //
  1596. IF_DEBUG(SMB_ERRORS) {
  1597. KdPrint(( "SrvSmbSeek: Invalid mode: 0x%lx\n",
  1598. SmbGetUshort( &request->Mode ) ));
  1599. }
  1600. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  1601. status = STATUS_INVALID_PARAMETER;
  1602. SmbStatus = SmbStatusSendResponse;
  1603. goto Cleanup;
  1604. } // switch ( request->Mode )
  1605. //
  1606. // Return the new file position in the response SMB.
  1607. //
  1608. // *** Note the assumption that the high part of the 64-bit EOF
  1609. // marker is zero. If it's not (i.e., the file is bigger than
  1610. // 4GB), then we're out of luck, because the SMB protocol can't
  1611. // express that.
  1612. //
  1613. IF_SMB_DEBUG(READ_WRITE2) {
  1614. KdPrint(( "SrvSmbSeek: New file position %ld\n", newPosition ));
  1615. }
  1616. response->WordCount = 2;
  1617. SmbPutUlong( &response->Offset, newPosition );
  1618. SmbPutUshort( &response->ByteCount, 0 );
  1619. WorkContext->ResponseParameters = NEXT_LOCATION( response, RESP_SEEK, 0 );
  1620. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbSeek complete\n" ));
  1621. SmbStatus = SmbStatusSendResponse;
  1622. goto Cleanup;
  1623. negative_seek:
  1624. //
  1625. // The client specified an absolute or relative seek that pointed
  1626. // before the beginning of the file. For some clients, this is not
  1627. // an error, and results in positioning at the BOF. Non-NT LAN Man
  1628. // clients can request a negative seek on a named-pipe and expect
  1629. // the operation to succeed.
  1630. //
  1631. smbDialect = rfcb->Connection->SmbDialect;
  1632. if( smbDialect >= SmbDialectLanMan20 ||
  1633. ( !IS_NT_DIALECT( smbDialect ) && rfcb->ShareType == ShareTypePipe )) {
  1634. //
  1635. // Negative seeks allowed for these fellows!
  1636. // Seek to the beginning of the file
  1637. //
  1638. newPosition = 0;
  1639. SetNewPosition( rfcb, &newPosition, FALSE );
  1640. IF_SMB_DEBUG(READ_WRITE2) {
  1641. KdPrint(( "SrvSmbSeek: New file position: 0\n" ));
  1642. }
  1643. response->WordCount = 2;
  1644. SmbPutUlong( &response->Offset, 0 );
  1645. SmbPutUshort( &response->ByteCount, 0 );
  1646. WorkContext->ResponseParameters = NEXT_LOCATION( response, RESP_SEEK, 0 );
  1647. } else {
  1648. //
  1649. // Negative seeks are not allowed!
  1650. //
  1651. IF_DEBUG(SMB_ERRORS) {
  1652. KdPrint(( "SrvSmbSeek: Negative seek\n" ));
  1653. }
  1654. SrvSetSmbError( WorkContext, STATUS_OS2_NEGATIVE_SEEK );
  1655. status = STATUS_OS2_NEGATIVE_SEEK;
  1656. }
  1657. SmbStatus = SmbStatusSendResponse;
  1658. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbSeek complete\n" ));
  1659. Cleanup:
  1660. SrvWmiEndContext(WorkContext);
  1661. return SmbStatus;
  1662. } // SrvSmbSeek
  1663. SMB_PROCESSOR_RETURN_TYPE
  1664. SrvSmbWrite (
  1665. SMB_PROCESSOR_PARAMETERS
  1666. )
  1667. /*++
  1668. Routine Description:
  1669. Processes the Write, Write and Close, and Write and Unlock, and
  1670. Write Print File SMBs.
  1671. Arguments:
  1672. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  1673. of the parameters to SMB processor routines.
  1674. Return Value:
  1675. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  1676. --*/
  1677. {
  1678. PREQ_WRITE request;
  1679. PRESP_WRITE response;
  1680. NTSTATUS status = STATUS_SUCCESS;
  1681. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1682. USHORT fid;
  1683. PRFCB rfcb;
  1684. PLFCB lfcb;
  1685. PCHAR writeAddress;
  1686. CLONG writeLength;
  1687. LARGE_INTEGER offset;
  1688. ULONG key;
  1689. SHARE_TYPE shareType;
  1690. PAGED_CODE( );
  1691. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1692. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE;
  1693. SrvWmiStartContext(WorkContext);
  1694. request = (PREQ_WRITE)WorkContext->RequestParameters;
  1695. response = (PRESP_WRITE)WorkContext->ResponseParameters;
  1696. fid = SmbGetUshort( &request->Fid );
  1697. IF_SMB_DEBUG(READ_WRITE1) {
  1698. KdPrint(( "Write%s request; FID 0x%lx, count %ld, offset %ld\n",
  1699. WorkContext->NextCommand == SMB_COM_WRITE_AND_UNLOCK ?
  1700. " and Unlock" :
  1701. WorkContext->NextCommand == SMB_COM_WRITE_AND_CLOSE ?
  1702. " and Close" : "",
  1703. fid, SmbGetUshort( &request->Count ),
  1704. SmbGetUlong( &request->Offset ) ));
  1705. }
  1706. //
  1707. // First, verify the FID. If verified, the RFCB is referenced and
  1708. // its address is stored in the WorkContext block, and the RFCB
  1709. // address is returned.
  1710. //
  1711. // Call SrvVerifyFid, but do not fail (return NULL) if there is
  1712. // a saved write behind error for this rfcb. We need the rfcb
  1713. // in case this is a write and close SMB, in order to process
  1714. // the close.
  1715. //
  1716. rfcb = SrvVerifyFid(
  1717. WorkContext,
  1718. fid,
  1719. FALSE,
  1720. SrvRestartSmbReceived, // serialize with raw write
  1721. &status
  1722. );
  1723. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1724. if ( !NT_SUCCESS( status ) ) {
  1725. //
  1726. // Invalid file ID. Reject the request.
  1727. //
  1728. IF_DEBUG(SMB_ERRORS) {
  1729. KdPrint(("SrvSmbWrite: Invalid FID: 0x%lx\n", fid ));
  1730. }
  1731. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  1732. status = STATUS_INVALID_HANDLE;
  1733. SmbStatus = SmbStatusSendResponse;
  1734. goto Cleanup;
  1735. }
  1736. //
  1737. // The work item has been queued because a raw write is in
  1738. // progress.
  1739. //
  1740. SmbStatus = SmbStatusInProgress;
  1741. goto Cleanup;
  1742. } else if ( !NT_SUCCESS( rfcb->SavedError ) ) {
  1743. NTSTATUS savedErrorStatus;
  1744. //
  1745. // Check the saved error.
  1746. //
  1747. savedErrorStatus = SrvCheckForSavedError( WorkContext, rfcb );
  1748. //
  1749. // See if the saved error was still there.
  1750. //
  1751. if ( !NT_SUCCESS( savedErrorStatus ) ) {
  1752. //
  1753. // There was a write behind error.
  1754. //
  1755. //
  1756. // Do not update the file timestamp.
  1757. //
  1758. WorkContext->Parameters.LastWriteTime = 0;
  1759. //
  1760. // If this is not a Write and Close, we can send the
  1761. // response now. If it is a Write and Close, we need to
  1762. // close the file first.
  1763. //
  1764. if ( WorkContext->NextCommand != SMB_COM_WRITE_AND_CLOSE ) {
  1765. //
  1766. // Not Write and Close. Just send the response.
  1767. //
  1768. status = savedErrorStatus;
  1769. SmbStatus = SmbStatusSendResponse;
  1770. goto Cleanup;
  1771. }
  1772. //
  1773. // This is a Write and Close.
  1774. //
  1775. SrvRestartChainedClose( WorkContext );
  1776. SmbStatus = SmbStatusInProgress;
  1777. goto Cleanup;
  1778. }
  1779. }
  1780. lfcb = rfcb->Lfcb;
  1781. //
  1782. // If the session has expired, return that info
  1783. //
  1784. if( lfcb->Session->IsSessionExpired )
  1785. {
  1786. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  1787. status = SESSION_EXPIRED_STATUS_CODE;
  1788. SmbStatus = SmbStatusSendResponse;
  1789. goto Cleanup;
  1790. }
  1791. //
  1792. // Verify that the client has write access to the file via the
  1793. // specified handle.
  1794. //
  1795. if ( !rfcb->WriteAccessGranted && !rfcb->AppendAccessGranted ) {
  1796. SrvStatistics.GrantedAccessErrors++;
  1797. IF_DEBUG(ERRORS) {
  1798. KdPrint(( "SrvSmbWrite: Write access not granted.\n"));
  1799. }
  1800. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  1801. status = STATUS_ACCESS_DENIED;
  1802. SmbStatus = SmbStatusSendResponse;
  1803. goto Cleanup;
  1804. }
  1805. //
  1806. // If the write length is zero, truncate the file at the specified
  1807. // offset.
  1808. //
  1809. if ( (SmbGetUshort( &request->Count ) == 0) && (rfcb->GrantedAccess & FILE_WRITE_DATA) ) {
  1810. SetNewSize( WorkContext );
  1811. SmbStatus = SmbStatusInProgress;
  1812. goto Cleanup;
  1813. }
  1814. rfcb->WrittenTo = TRUE;
  1815. #ifdef INCLUDE_SMB_IFMODIFIED
  1816. rfcb->Lfcb->FileUpdated = TRUE;
  1817. #endif
  1818. //
  1819. // Get the file share type.
  1820. //
  1821. shareType = rfcb->ShareType;
  1822. //
  1823. // If this operation may block, and we are running short of free
  1824. // work items, fail this SMB with an out of resources error.
  1825. //
  1826. if ( rfcb->BlockingModePipe ) {
  1827. if ( SrvReceiveBufferShortage( ) ) {
  1828. //
  1829. // Fail the operation.
  1830. //
  1831. SrvStatistics.BlockingSmbsRejected++;
  1832. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  1833. status = STATUS_INSUFF_SERVER_RESOURCES;
  1834. SmbStatus = SmbStatusSendResponse;
  1835. goto Cleanup;
  1836. } else {
  1837. //
  1838. // It is okay to start a blocking operation.
  1839. // SrvReceiveBufferShortage() has already incremented
  1840. // SrvBlockingOpsInProgress.
  1841. //
  1842. WorkContext->BlockingOperation = TRUE;
  1843. }
  1844. }
  1845. //
  1846. // *** If the Remaining field of the request is ever used, make sure
  1847. // that this is not a write and close SMB, which does not
  1848. // include a valid Remaining field.
  1849. //
  1850. //
  1851. // Determine the amount of data to write. This is the minimum of
  1852. // the amount requested by the client and the amount of data
  1853. // actually sent in the request buffer.
  1854. //
  1855. // !!! Should it be an error for the client to send less data than
  1856. // it actually wants us to write? The OS/2 server seems not to
  1857. // reject such requests.
  1858. //
  1859. if ( WorkContext->NextCommand != SMB_COM_WRITE_PRINT_FILE ) {
  1860. if ( WorkContext->NextCommand != SMB_COM_WRITE_AND_CLOSE ) {
  1861. writeAddress = (PCHAR)request->Buffer;
  1862. } else {
  1863. //
  1864. // Look at the WordCount field -- it should be 6 or 12.
  1865. // From this we can calculate the writeAddress.
  1866. //
  1867. if ( request->WordCount == 6 ) {
  1868. writeAddress =
  1869. (PCHAR)((PREQ_WRITE_AND_CLOSE)request)->Buffer;
  1870. } else if ( request->WordCount == 12 ) {
  1871. writeAddress =
  1872. (PCHAR)((PREQ_WRITE_AND_CLOSE_LONG)request)->Buffer;
  1873. } else {
  1874. //
  1875. // An illegal WordCount value was passed. Return an error
  1876. // to the client.
  1877. //
  1878. IF_DEBUG(SMB_ERRORS) {
  1879. KdPrint(( "SrvSmbWrite: Bad WordCount for "
  1880. "WriteAndClose: %ld, should be 6 or 12\n",
  1881. request->WordCount ));
  1882. }
  1883. SrvLogInvalidSmb( WorkContext );
  1884. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1885. status = STATUS_INVALID_SMB;
  1886. SmbStatus = SmbStatusSendResponse;
  1887. goto Cleanup;
  1888. }
  1889. }
  1890. writeLength = MIN(
  1891. (CLONG)SmbGetUshort( &request->Count ),
  1892. WorkContext->ResponseBuffer->DataLength -
  1893. PTR_DIFF(writeAddress, WorkContext->RequestHeader)
  1894. );
  1895. offset.QuadPart = SmbGetUlong( &request->Offset );
  1896. } else {
  1897. writeAddress = (PCHAR)( ((PREQ_WRITE_PRINT_FILE)request)->Buffer ) + 3;
  1898. writeLength =
  1899. MIN(
  1900. (CLONG)SmbGetUshort(
  1901. &((PREQ_WRITE_PRINT_FILE)request)->ByteCount ) - 3,
  1902. WorkContext->ResponseBuffer->DataLength -
  1903. PTR_DIFF(writeAddress, WorkContext->RequestHeader)
  1904. );
  1905. offset.QuadPart = rfcb->CurrentPosition;
  1906. }
  1907. //
  1908. // Ensure that the client is writing beyond the original file size
  1909. //
  1910. if( !rfcb->WriteAccessGranted &&
  1911. offset.QuadPart < rfcb->Mfcb->NonpagedMfcb->OpenFileSize.QuadPart ) {
  1912. //
  1913. // The client is only allowed to append to this file!
  1914. //
  1915. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  1916. status = STATUS_ACCESS_DENIED;
  1917. SmbStatus = SmbStatusSendResponse;
  1918. goto Cleanup;
  1919. }
  1920. #ifdef SLMDBG
  1921. {
  1922. PRFCB_TRACE entry;
  1923. KIRQL oldIrql;
  1924. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  1925. rfcb->WriteCount++;
  1926. rfcb->OperationCount++;
  1927. entry = &rfcb->Trace[rfcb->NextTrace];
  1928. if ( ++rfcb->NextTrace == SLMDBG_TRACE_COUNT ) {
  1929. rfcb->NextTrace = 0;
  1930. rfcb->TraceWrapped = TRUE;
  1931. }
  1932. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  1933. entry->Command = WorkContext->NextCommand;
  1934. KeQuerySystemTime( &entry->Time );
  1935. entry->Data.ReadWrite.Offset = offset.LowPart;
  1936. entry->Data.ReadWrite.Length = writeLength;
  1937. }
  1938. #endif
  1939. //
  1940. // Form the lock key using the FID and the PID.
  1941. //
  1942. // *** The FID must be included in the key in order to account for
  1943. // the folding of multiple remote compatibility mode opens into
  1944. // a single local open.
  1945. //
  1946. key = rfcb->ShiftedFid |
  1947. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  1948. //
  1949. // Try the fast I/O path first. If that fails, fall through to the
  1950. // normal build-an-IRP path.
  1951. //
  1952. if ( lfcb->FastIoWrite != NULL ) {
  1953. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  1954. try {
  1955. if ( lfcb->FastIoWrite(
  1956. lfcb->FileObject,
  1957. &offset,
  1958. writeLength,
  1959. TRUE,
  1960. key,
  1961. writeAddress,
  1962. &WorkContext->Irp->IoStatus,
  1963. lfcb->DeviceObject
  1964. ) ) {
  1965. //
  1966. // The fast I/O path worked. Call the restart routine directly
  1967. // to do postprocessing (including sending the response).
  1968. //
  1969. WorkContext->bAlreadyTrace = TRUE;
  1970. SrvFsdRestartWrite( WorkContext );
  1971. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbWrite complete.\n" ));
  1972. SmbStatus = SmbStatusInProgress;
  1973. goto Cleanup;
  1974. }
  1975. }
  1976. except( EXCEPTION_EXECUTE_HANDLER ) {
  1977. // Fall through to the slow path on an exception
  1978. NTSTATUS status = GetExceptionCode();
  1979. IF_DEBUG(ERRORS) {
  1980. KdPrint(("FastIoRead threw exception %x\n", status ));
  1981. }
  1982. }
  1983. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  1984. }
  1985. //
  1986. // The turbo path failed. Build the write request, reusing the
  1987. // receive IRP.
  1988. //
  1989. if (shareType != ShareTypePipe) {
  1990. //
  1991. // Build an MDL describing the write buffer. Note that if the
  1992. // file system can complete the write immediately, the MDL isn't
  1993. // really needed, but if the file system must send the request
  1994. // to its FSP, the MDL _is_ needed.
  1995. //
  1996. // *** Note the assumption that the request buffer already has a
  1997. // valid full MDL from which a partial MDL can be built.
  1998. //
  1999. IoBuildPartialMdl(
  2000. WorkContext->RequestBuffer->Mdl,
  2001. WorkContext->RequestBuffer->PartialMdl,
  2002. writeAddress,
  2003. writeLength
  2004. );
  2005. //
  2006. // Build the IRP.
  2007. //
  2008. SrvBuildReadOrWriteRequest(
  2009. WorkContext->Irp, // input IRP address
  2010. lfcb->FileObject, // target file object address
  2011. WorkContext, // context
  2012. IRP_MJ_WRITE, // major function code
  2013. 0, // minor function code
  2014. writeAddress, // buffer address
  2015. writeLength, // buffer length
  2016. WorkContext->RequestBuffer->PartialMdl, // MDL address
  2017. offset, // byte offset
  2018. key // lock key
  2019. );
  2020. IF_SMB_DEBUG(READ_WRITE2) {
  2021. KdPrint(( "SrvSmbWrite: writing to file 0x%p, offset %ld, length %ld, source 0x%p\n",
  2022. lfcb->FileObject, offset.LowPart, writeLength,
  2023. writeAddress ));
  2024. }
  2025. } else {
  2026. //
  2027. // Build the PIPE_INTERNAL_WRITE IRP.
  2028. //
  2029. SrvBuildIoControlRequest(
  2030. WorkContext->Irp,
  2031. lfcb->FileObject,
  2032. WorkContext,
  2033. IRP_MJ_FILE_SYSTEM_CONTROL,
  2034. FSCTL_PIPE_INTERNAL_WRITE,
  2035. writeAddress,
  2036. writeLength,
  2037. NULL,
  2038. 0,
  2039. NULL,
  2040. NULL
  2041. );
  2042. IF_SMB_DEBUG(READ_WRITE2) {
  2043. KdPrint(( "SrvSmbWrite: writing to file 0x%p length %ld, destination 0x%p\n",
  2044. lfcb->FileObject, writeLength,
  2045. writeAddress ));
  2046. }
  2047. }
  2048. //
  2049. // Pass the request to the file system. If this is a write and
  2050. // close, we have to restart in the FSP because the restart routine
  2051. // will free the MFCB stored in paged pool. Similarly, if this is a
  2052. // write and unlock, we have to restart in the FSP to do the unlock.
  2053. //
  2054. if ( (WorkContext->RequestHeader->Command == SMB_COM_WRITE_AND_CLOSE) ||
  2055. (WorkContext->RequestHeader->Command == SMB_COM_WRITE_AND_UNLOCK) ) {
  2056. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2057. WorkContext->bAlreadyTrace = FALSE;
  2058. WorkContext->FspRestartRoutine = SrvFsdRestartWrite;
  2059. } else {
  2060. WorkContext->bAlreadyTrace = TRUE;
  2061. WorkContext->FsdRestartRoutine = SrvFsdRestartWrite;
  2062. DEBUG WorkContext->FspRestartRoutine = NULL;
  2063. }
  2064. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2065. //
  2066. // The write has been started. Control will return to
  2067. // SrvFsdRestartWrite when the write completes.
  2068. //
  2069. SmbStatus = SmbStatusInProgress;
  2070. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbWrite complete.\n" ));
  2071. Cleanup:
  2072. SrvWmiEndContext(WorkContext);
  2073. return SmbStatus;
  2074. } // SrvSmbWrite
  2075. SMB_PROCESSOR_RETURN_TYPE
  2076. SrvSmbWriteAndX (
  2077. SMB_PROCESSOR_PARAMETERS
  2078. )
  2079. /*++
  2080. Routine Description:
  2081. Processes the Write And X SMB.
  2082. Arguments:
  2083. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  2084. of the parameters to SMB processor routines.
  2085. Return Value:
  2086. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  2087. --*/
  2088. {
  2089. PSMB_HEADER header;
  2090. PREQ_WRITE_ANDX request;
  2091. PREQ_NT_WRITE_ANDX ntRequest;
  2092. PRESP_WRITE_ANDX response;
  2093. PCONNECTION connection;
  2094. NTSTATUS status = STATUS_SUCCESS;
  2095. SMB_STATUS SmbStatus = SmbStatusInProgress;
  2096. USHORT fid;
  2097. PRFCB rfcb;
  2098. PLFCB lfcb;
  2099. CLONG bufferOffset;
  2100. PCHAR writeAddress;
  2101. CLONG writeLength;
  2102. LARGE_INTEGER offset;
  2103. ULONG key;
  2104. SHARE_TYPE shareType;
  2105. BOOLEAN writeThrough;
  2106. ULONG remainingBytes;
  2107. ULONG totalLength;
  2108. SMB_DIALECT smbDialect;
  2109. PTRANSACTION transaction;
  2110. PCHAR trailingBytes;
  2111. USHORT flags2;
  2112. PAGED_CODE( );
  2113. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  2114. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_AND_X;
  2115. SrvWmiStartContext(WorkContext);
  2116. header = (PSMB_HEADER)WorkContext->RequestHeader;
  2117. request = (PREQ_WRITE_ANDX)WorkContext->RequestParameters;
  2118. ntRequest = (PREQ_NT_WRITE_ANDX)WorkContext->RequestParameters;
  2119. response = (PRESP_WRITE_ANDX)WorkContext->ResponseParameters;
  2120. //
  2121. // Initialize the transaction pointer.
  2122. //
  2123. WorkContext->Parameters.Transaction = NULL;
  2124. //
  2125. // If this WriteAndX is actually a psuedo WriteBlockMultiplex, all
  2126. // of the WriteAndX pieces must be assembled before submitting the
  2127. // request to NPFS. (This exists to support large message mode
  2128. // writes to clients that can't do WriteBlockMultiplex.)
  2129. //
  2130. // This must be handled in the FSP.
  2131. //
  2132. fid = SmbGetUshort( &request->Fid );
  2133. IF_SMB_DEBUG(READ_WRITE1) {
  2134. KdPrint(( "WriteAndX request; FID 0x%lx, count %ld, offset %ld\n",
  2135. fid, SmbGetUshort( &request->DataLength ),
  2136. SmbGetUlong( &request->Offset ) ));
  2137. }
  2138. rfcb = SrvVerifyFid(
  2139. WorkContext,
  2140. fid,
  2141. TRUE,
  2142. SrvRestartSmbReceived, // serialize with raw write
  2143. &status
  2144. );
  2145. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  2146. if ( !NT_SUCCESS( status ) ) {
  2147. //
  2148. // Invalid file ID or write behind error. Reject the request.
  2149. //
  2150. IF_DEBUG(ERRORS) {
  2151. KdPrint((
  2152. "SrvSmbWriteAndX: status %X on FID: 0x%lx\n",
  2153. status,
  2154. fid
  2155. ));
  2156. }
  2157. SrvSetSmbError( WorkContext, status );
  2158. SmbStatus = SrvConsumeSmbData( WorkContext );
  2159. goto Cleanup;
  2160. }
  2161. //
  2162. // The work item has been queued because a raw write is in
  2163. // progress.
  2164. //
  2165. SmbStatus = SmbStatusInProgress;
  2166. goto Cleanup;
  2167. }
  2168. //
  2169. // Get the LFCB and the file share type.
  2170. //
  2171. lfcb = rfcb->Lfcb;
  2172. shareType = rfcb->ShareType;
  2173. //
  2174. // If the session has expired, return that info
  2175. //
  2176. if( lfcb->Session->IsSessionExpired )
  2177. {
  2178. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  2179. status = SESSION_EXPIRED_STATUS_CODE;
  2180. SmbStatus = SrvConsumeSmbData( WorkContext );
  2181. goto Cleanup;
  2182. }
  2183. if( WorkContext->LargeIndication && shareType != ShareTypeDisk ) {
  2184. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2185. status = STATUS_INVALID_SMB;
  2186. //
  2187. // We need to consume the rest of this SMB!
  2188. //
  2189. SmbStatus = SrvConsumeSmbData( WorkContext );
  2190. goto Cleanup;
  2191. }
  2192. //
  2193. // Verify that the client has write access to the file via the
  2194. // specified handle.
  2195. //
  2196. if ( !rfcb->WriteAccessGranted && !rfcb->AppendAccessGranted ) {
  2197. SrvStatistics.GrantedAccessErrors++;
  2198. IF_DEBUG(ERRORS) {
  2199. KdPrint(( "SrvSmbWriteAndX: Write access not granted.\n"));
  2200. }
  2201. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  2202. status = STATUS_ACCESS_DENIED;
  2203. SmbStatus = SrvConsumeSmbData( WorkContext );
  2204. goto Cleanup;
  2205. }
  2206. rfcb->WrittenTo = TRUE;
  2207. #ifdef INCLUDE_SMB_IFMODIFIED
  2208. rfcb->Lfcb->FileUpdated = TRUE;
  2209. #endif
  2210. flags2 = SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 );
  2211. //
  2212. // Ensure the correct write through mode, and handle compressed writes
  2213. //
  2214. if ( shareType == ShareTypeDisk ) {
  2215. writeThrough = (BOOLEAN)((SmbGetUshort( &request->WriteMode ) &
  2216. SMB_WMODE_WRITE_THROUGH) != 0);
  2217. if ( writeThrough && (lfcb->FileMode & FILE_WRITE_THROUGH) == 0
  2218. || !writeThrough && (lfcb->FileMode & FILE_WRITE_THROUGH) != 0 ) {
  2219. SrvSetFileWritethroughMode( lfcb, writeThrough );
  2220. }
  2221. RtlZeroMemory( &WorkContext->Parameters.WriteAndX,
  2222. sizeof( WorkContext->Parameters.WriteAndX) );
  2223. //
  2224. // If this is a compressed write, handle it separately.
  2225. //
  2226. if( flags2 & SMB_FLAGS2_COMPRESSED ) {
  2227. SmbStatus = SrvSmbWriteAndXCompressed( WorkContext );
  2228. goto Cleanup;
  2229. }
  2230. } else if ( rfcb->BlockingModePipe ) {
  2231. //
  2232. // If this operation may block, and we are running short of free
  2233. // work items, fail this SMB with an out of resources error.
  2234. //
  2235. if ( SrvReceiveBufferShortage( ) ) {
  2236. //
  2237. // Fail the operation.
  2238. //
  2239. SrvStatistics.BlockingSmbsRejected++;
  2240. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  2241. status = STATUS_INSUFF_SERVER_RESOURCES;
  2242. SmbStatus = SrvConsumeSmbData( WorkContext );
  2243. goto Cleanup;
  2244. } else {
  2245. //
  2246. // SrvBlockingOpsInProgress has already been incremented.
  2247. // Flag this work item as a blocking operation.
  2248. //
  2249. WorkContext->BlockingOperation = TRUE;
  2250. }
  2251. }
  2252. //
  2253. // Determine the amount of data to write. This is the minimum of
  2254. // the amount requested by the client and the amount of data
  2255. // actually sent in the request buffer.
  2256. //
  2257. // !!! Should it be an error for the client to send less data than
  2258. // it actually wants us to write? The OS/2 server seems not to
  2259. // reject such requests.
  2260. //
  2261. bufferOffset = SmbGetUshort( &request->DataOffset );
  2262. writeAddress = (PCHAR)WorkContext->ResponseHeader + bufferOffset;
  2263. writeLength = MIN(
  2264. (CLONG)SmbGetUshort( &request->DataLength ),
  2265. WorkContext->ResponseBuffer->DataLength - bufferOffset
  2266. );
  2267. remainingBytes = SmbGetUshort( &request->Remaining );
  2268. //
  2269. // Form the lock key using the FID and the PID.
  2270. //
  2271. // *** The FID must be included in the key in order to account for
  2272. // the folding of multiple remote compatibility mode opens into
  2273. // a single local open.
  2274. //
  2275. key = rfcb->ShiftedFid |
  2276. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  2277. flags2 = SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 );
  2278. //
  2279. // Get the file offset.
  2280. //
  2281. if ( shareType != ShareTypePipe ) {
  2282. if ( request->WordCount == 12 ) {
  2283. //
  2284. // The client has supplied a 32 bit file offset.
  2285. //
  2286. offset.QuadPart = SmbGetUlong( &request->Offset );
  2287. } else if ( request->WordCount == 14 ) {
  2288. //
  2289. // The client has supplied a 64 bit file offset. This must be an
  2290. // uplevel NT-like client
  2291. //
  2292. offset.LowPart = SmbGetUlong( &ntRequest->Offset );
  2293. offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh );
  2294. //
  2295. // Reject negative offsets
  2296. //
  2297. if ( offset.QuadPart < 0 && offset.QuadPart != 0xFFFFFFFFFFFFFFFF ) {
  2298. IF_DEBUG(ERRORS) {
  2299. KdPrint(( "SrvSmbWriteAndX: Negative offset rejected.\n"));
  2300. }
  2301. SrvLogInvalidSmb( WorkContext );
  2302. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2303. status = STATUS_INVALID_SMB;
  2304. SmbStatus = SrvConsumeSmbData( WorkContext );
  2305. goto Cleanup;
  2306. }
  2307. } else {
  2308. //
  2309. // Invalid word count.
  2310. //
  2311. SrvLogInvalidSmb( WorkContext );
  2312. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2313. status = STATUS_INVALID_SMB;
  2314. SmbStatus = SrvConsumeSmbData( WorkContext );
  2315. goto Cleanup;
  2316. }
  2317. //
  2318. // If the client can only append, ensure that the client is writing
  2319. // beyond the original EOF
  2320. //
  2321. if( !rfcb->WriteAccessGranted &&
  2322. offset.QuadPart < rfcb->Mfcb->NonpagedMfcb->OpenFileSize.QuadPart ) {
  2323. //
  2324. // The client is only allowed to append to this file!
  2325. //
  2326. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  2327. status = STATUS_ACCESS_DENIED;
  2328. SmbStatus = SrvConsumeSmbData( WorkContext );
  2329. goto Cleanup;
  2330. }
  2331. //
  2332. // Gather up parameters for large writes
  2333. //
  2334. if( WorkContext->LargeIndication ) {
  2335. //
  2336. // There can be no follow-on command, and we can not be using security signatures
  2337. //
  2338. if( request->WordCount != 14 ||
  2339. WorkContext->Connection->SmbSecuritySignatureActive == TRUE ||
  2340. request->AndXCommand != SMB_COM_NO_ANDX_COMMAND ) {
  2341. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2342. status = STATUS_INVALID_SMB;
  2343. SmbStatus = SrvConsumeSmbData( WorkContext );
  2344. goto Cleanup;
  2345. }
  2346. WorkContext->Parameters.WriteAndX.RemainingWriteLength =
  2347. (ULONG)SmbGetUshort( &ntRequest->DataLengthHigh ) << 16;
  2348. WorkContext->Parameters.WriteAndX.RemainingWriteLength +=
  2349. (ULONG)SmbGetUshort( &ntRequest->DataLength );
  2350. WorkContext->Parameters.WriteAndX.CurrentWriteLength = MIN(
  2351. WorkContext->Parameters.WriteAndX.RemainingWriteLength,
  2352. WorkContext->ResponseBuffer->DataLength - bufferOffset );
  2353. writeLength = WorkContext->Parameters.WriteAndX.CurrentWriteLength;
  2354. WorkContext->Parameters.WriteAndX.RemainingWriteLength -= writeLength;
  2355. WorkContext->Parameters.WriteAndX.WriteAddress = writeAddress;
  2356. WorkContext->Parameters.WriteAndX.BufferLength = writeLength;
  2357. WorkContext->Parameters.WriteAndX.Key = key;
  2358. WorkContext->Parameters.WriteAndX.Offset = offset;
  2359. //
  2360. // If the data should have fit within the original SMB buffer, then
  2361. // this is an error
  2362. //
  2363. if( WorkContext->Parameters.WriteAndX.RemainingWriteLength == 0 ) {
  2364. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2365. status = STATUS_INVALID_SMB;
  2366. SmbStatus = SrvConsumeSmbData( WorkContext );
  2367. goto Cleanup;
  2368. }
  2369. }
  2370. } else {
  2371. if ( (request->WordCount != 12) && (request->WordCount != 14) ) {
  2372. //
  2373. // Invalid word count.
  2374. //
  2375. SrvLogInvalidSmb( WorkContext );
  2376. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2377. status = STATUS_INVALID_SMB;
  2378. SmbStatus = SmbStatusSendResponse;
  2379. goto Cleanup;
  2380. }
  2381. //
  2382. // Is this a multipiece named pipe write?
  2383. //
  2384. connection = WorkContext->Connection;
  2385. if ( (SmbGetUshort( &request->WriteMode ) &
  2386. SMB_WMODE_WRITE_RAW_NAMED_PIPE) != 0 ) {
  2387. //
  2388. // This is a multipiece named pipe write, is this the first
  2389. // piece?
  2390. //
  2391. if ( (SmbGetUshort( &request->WriteMode ) &
  2392. SMB_WMODE_START_OF_MESSAGE) != 0 ) {
  2393. //
  2394. // This is the first piece of a multipart WriteAndX SMB.
  2395. // Allocate a buffer large enough to hold all of the data.
  2396. //
  2397. // The first two bytes of the data part of the SMB are the
  2398. // named pipe message header, which we ignore. Adjust for
  2399. // that.
  2400. //
  2401. //
  2402. // Ensure that enough bytes are available
  2403. //
  2404. if( writeLength < 2 ) {
  2405. SrvLogInvalidSmb( WorkContext );
  2406. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2407. status = STATUS_INVALID_SMB;
  2408. SmbStatus = SmbStatusSendResponse;
  2409. goto Cleanup;
  2410. }
  2411. writeAddress += 2;
  2412. writeLength -= 2;
  2413. // If this is an OS/2 client, add the current write to the
  2414. // remainingBytes count. This is a bug in the OS/2 rdr.
  2415. //
  2416. smbDialect = connection->SmbDialect;
  2417. if ( smbDialect == SmbDialectLanMan21 ||
  2418. smbDialect == SmbDialectLanMan20 ||
  2419. smbDialect == SmbDialectLanMan10 ) {
  2420. //
  2421. // Ignore the 1st 2 bytes of the message as they are the
  2422. // OS/2 message header.
  2423. //
  2424. totalLength = writeLength + remainingBytes;
  2425. } else {
  2426. if( writeLength > remainingBytes ) {
  2427. // This is an invalid SMB, they are trying to overrun the buffer
  2428. SrvLogInvalidSmb( WorkContext );
  2429. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2430. return SmbStatusSendResponse;
  2431. }
  2432. totalLength = remainingBytes;
  2433. }
  2434. SrvAllocateTransaction(
  2435. &transaction,
  2436. (PVOID *)&trailingBytes,
  2437. connection,
  2438. totalLength,
  2439. #if DBG
  2440. StrWriteAndX, // Transaction name
  2441. #else
  2442. StrNull,
  2443. #endif
  2444. NULL,
  2445. TRUE, // Source name is Unicode
  2446. FALSE // Not a remote API
  2447. );
  2448. if ( transaction == NULL ) {
  2449. //
  2450. // Could not allocate a large enough buffer.
  2451. //
  2452. IF_DEBUG(ERRORS) {
  2453. KdPrint(( "Unable to allocate transaction\n" ));
  2454. }
  2455. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  2456. status = STATUS_INSUFF_SERVER_RESOURCES;
  2457. SmbStatus = SmbStatusSendResponse;
  2458. goto Cleanup;
  2459. } else {
  2460. //
  2461. // Successfully allocated a transaction block.
  2462. //
  2463. // Save the TID, PID, UID, and MID from this request in
  2464. // the transaction block. These values are used to
  2465. // relate secondary requests to the appropriate primary
  2466. // request.
  2467. //
  2468. transaction->Tid = SmbGetAlignedUshort( &header->Tid );
  2469. transaction->Pid = SmbGetAlignedUshort( &header->Pid );
  2470. transaction->Uid = SmbGetAlignedUshort( &header->Uid );
  2471. transaction->OtherInfo = fid;
  2472. //
  2473. // Remember the total size of the buffer and the number
  2474. // of bytes received so far.
  2475. //
  2476. transaction->DataCount = writeLength;
  2477. transaction->TotalDataCount = totalLength;
  2478. transaction->InData = trailingBytes + writeLength;
  2479. transaction->OutData = trailingBytes;
  2480. transaction->Connection = connection;
  2481. SrvReferenceConnection( connection );
  2482. transaction->Session = lfcb->Session;
  2483. SrvReferenceSession( transaction->Session );
  2484. transaction->TreeConnect = lfcb->TreeConnect;
  2485. SrvReferenceTreeConnect( transaction->TreeConnect );
  2486. //
  2487. // Copy the data out of the SMB buffer.
  2488. //
  2489. RtlCopyMemory(
  2490. trailingBytes,
  2491. writeAddress,
  2492. writeLength
  2493. );
  2494. //
  2495. // Increase the write length again, so as not to confuse
  2496. // the redirector.
  2497. //
  2498. writeLength += 2;
  2499. //
  2500. // Link the transaction block into the connection's
  2501. // pending transaction list. This will fail if there is
  2502. // already a tranaction with the same xID values in the
  2503. // list.
  2504. //
  2505. if ( !SrvInsertTransaction( transaction ) ) {
  2506. //
  2507. // A transaction with the same xIDs is already in
  2508. // progress. Return an error to the client.
  2509. //
  2510. // *** Note that SrvDereferenceTransaction can't be
  2511. // used here because that routine assumes that
  2512. // the transaction is queued to the transaction
  2513. // list.
  2514. //
  2515. SrvDereferenceTreeConnect( transaction->TreeConnect );
  2516. SrvDereferenceSession( transaction->Session );
  2517. SrvFreeTransaction( transaction );
  2518. SrvDereferenceConnection( connection );
  2519. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2520. status = STATUS_INVALID_SMB;
  2521. SmbStatus = SmbStatusSendResponse;
  2522. goto Cleanup;
  2523. }
  2524. } // else ( transaction sucessfully allocated )
  2525. } else { // This is a secondary piece to a multi-part message
  2526. transaction = SrvFindTransaction(
  2527. connection,
  2528. header,
  2529. fid
  2530. );
  2531. if ( transaction == NULL ) {
  2532. //
  2533. // Unable to find a matching transaction.
  2534. //
  2535. IF_DEBUG(ERRORS) {
  2536. KdPrint(( "Cannot find initial write request for "
  2537. "WriteAndX SMB\n"));
  2538. }
  2539. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2540. status = STATUS_INVALID_SMB;
  2541. SmbStatus = SmbStatusSendResponse;
  2542. goto Cleanup;
  2543. }
  2544. //
  2545. // Make sure there is enough space left in the transaction
  2546. // buffer for the data that we have received.
  2547. //
  2548. if ( transaction->TotalDataCount - transaction->DataCount
  2549. < writeLength ) {
  2550. //
  2551. // Too much data. Throw out the entire buffer and
  2552. // reject this write request.
  2553. //
  2554. SrvCloseTransaction( transaction );
  2555. SrvDereferenceTransaction( transaction );
  2556. SrvSetSmbError( WorkContext, STATUS_BUFFER_OVERFLOW );
  2557. status = STATUS_BUFFER_OVERFLOW;
  2558. SmbStatus = SmbStatusSendResponse;
  2559. goto Cleanup;
  2560. }
  2561. RtlCopyMemory(transaction->InData, writeAddress, writeLength );
  2562. //
  2563. // Update the transaction data pointer to where the next
  2564. // WriteAndX data buffer will go.
  2565. //
  2566. transaction->InData += writeLength;
  2567. transaction->DataCount += writeLength;
  2568. } // secondary piece of multipart write
  2569. if ( transaction->DataCount < transaction->TotalDataCount ) {
  2570. //
  2571. // We don't have all of the data yet.
  2572. //
  2573. PRESP_WRITE_ANDX response;
  2574. UCHAR nextCommand;
  2575. //
  2576. // SrvAllocateTransaction or SrvFindTransaction referenced
  2577. // the transaction, so dereference it.
  2578. //
  2579. SrvDereferenceTransaction( transaction );
  2580. //
  2581. // Send an interim response.
  2582. //
  2583. ASSERT( request->AndXCommand == SMB_COM_NO_ANDX_COMMAND );
  2584. response = (PRESP_WRITE_ANDX)WorkContext->ResponseParameters;
  2585. nextCommand = request->AndXCommand;
  2586. //
  2587. // Build the response message.
  2588. //
  2589. response->AndXCommand = nextCommand;
  2590. response->AndXReserved = 0;
  2591. SmbPutUshort(
  2592. &response->AndXOffset,
  2593. GET_ANDX_OFFSET(
  2594. WorkContext->ResponseHeader,
  2595. WorkContext->ResponseParameters,
  2596. RESP_WRITE_ANDX,
  2597. 0
  2598. )
  2599. );
  2600. response->WordCount = 6;
  2601. SmbPutUshort( &response->Count, (USHORT)writeLength );
  2602. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  2603. SmbPutUlong( &response->Reserved, 0 );
  2604. SmbPutUshort( &response->ByteCount, 0 );
  2605. WorkContext->ResponseParameters =
  2606. (PCHAR)WorkContext->ResponseHeader +
  2607. SmbGetUshort( &response->AndXOffset );
  2608. SmbStatus = SmbStatusSendResponse;
  2609. goto Cleanup;
  2610. }
  2611. //
  2612. // We have all of the data. Set up to write it.
  2613. //
  2614. writeAddress = transaction->OutData;
  2615. writeLength = PTR_DIFF(transaction->InData, transaction->OutData);
  2616. //
  2617. // Save a pointer to the transaction block so that it can be
  2618. // freed when the write completes.
  2619. //
  2620. // *** Note that we retain the reference to the transaction that
  2621. // was set by SrvAllocateTransaction or added by
  2622. // SrvFindTransaction.
  2623. //
  2624. WorkContext->Parameters.Transaction = transaction;
  2625. //
  2626. // Fall through to issue the I/O request.
  2627. //
  2628. } // "raw mode" write?
  2629. }
  2630. #ifdef SLMDBG
  2631. {
  2632. PRFCB_TRACE entry;
  2633. KIRQL oldIrql;
  2634. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  2635. rfcb->WriteCount++;
  2636. rfcb->OperationCount++;
  2637. entry = &rfcb->Trace[rfcb->NextTrace];
  2638. if ( ++rfcb->NextTrace == SLMDBG_TRACE_COUNT ) {
  2639. rfcb->NextTrace = 0;
  2640. rfcb->TraceWrapped = TRUE;
  2641. }
  2642. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  2643. entry->Command = WorkContext->NextCommand;
  2644. KeQuerySystemTime( &entry->Time );
  2645. entry->Data.ReadWrite.Offset = offset.LowPart;
  2646. entry->Data.ReadWrite.Length = writeLength;
  2647. }
  2648. #endif
  2649. //
  2650. // Try the fast I/O path first. If that fails, fall through to the
  2651. // normal build-an-IRP path.
  2652. //
  2653. if ( lfcb->FastIoWrite != NULL ) {
  2654. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  2655. try {
  2656. if ( lfcb->FastIoWrite(
  2657. lfcb->FileObject,
  2658. &offset,
  2659. writeLength,
  2660. TRUE,
  2661. key,
  2662. writeAddress,
  2663. &WorkContext->Irp->IoStatus,
  2664. lfcb->DeviceObject
  2665. ) ) {
  2666. //
  2667. // The fast I/O path worked. Call the restart routine directly
  2668. // to do postprocessing (including sending the response).
  2669. //
  2670. WorkContext->bAlreadyTrace = TRUE;
  2671. SrvFsdRestartWriteAndX( WorkContext );
  2672. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbWriteAndX complete.\n" ));
  2673. SmbStatus = SmbStatusInProgress;
  2674. goto Cleanup;
  2675. }
  2676. }
  2677. except( EXCEPTION_EXECUTE_HANDLER ) {
  2678. // Fall through to the slow path on an exception
  2679. NTSTATUS status = GetExceptionCode();
  2680. IF_DEBUG(ERRORS) {
  2681. KdPrint(("FastIoRead threw exception %x\n", status ));
  2682. }
  2683. }
  2684. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  2685. }
  2686. //
  2687. // The turbo path failed. Build the write request, reusing the
  2688. // receive IRP.
  2689. //
  2690. if ( shareType != ShareTypePipe ) {
  2691. //
  2692. // Build an MDL describing the write buffer. Note that if the
  2693. // file system can complete the write immediately, the MDL isn't
  2694. // really needed, but if the file system must send the request
  2695. // to its FSP, the MDL _is_ needed.
  2696. //
  2697. // *** Note the assumption that the request buffer already has a
  2698. // valid full MDL from which a partial MDL can be built.
  2699. //
  2700. IoBuildPartialMdl(
  2701. WorkContext->RequestBuffer->Mdl,
  2702. WorkContext->RequestBuffer->PartialMdl,
  2703. writeAddress,
  2704. writeLength
  2705. );
  2706. //
  2707. // Build the IRP.
  2708. //
  2709. SrvBuildReadOrWriteRequest(
  2710. WorkContext->Irp, // input IRP address
  2711. lfcb->FileObject, // target file object address
  2712. WorkContext, // context
  2713. IRP_MJ_WRITE, // major function code
  2714. 0, // minor function code
  2715. writeAddress, // buffer address
  2716. writeLength, // buffer length
  2717. WorkContext->RequestBuffer->PartialMdl, // MDL address
  2718. offset, // byte offset
  2719. key // lock key
  2720. );
  2721. IF_SMB_DEBUG(READ_WRITE2) {
  2722. KdPrint(( "SrvSmbWriteAndX: writing to file 0x%p, offset %ld, length %ld, source 0x%p\n",
  2723. lfcb->FileObject, offset.LowPart, writeLength,
  2724. writeAddress ));
  2725. }
  2726. } else {
  2727. //
  2728. // Build the PIPE_INTERNAL_WRITE IRP.
  2729. //
  2730. SrvBuildIoControlRequest(
  2731. WorkContext->Irp,
  2732. lfcb->FileObject,
  2733. WorkContext,
  2734. IRP_MJ_FILE_SYSTEM_CONTROL,
  2735. FSCTL_PIPE_INTERNAL_WRITE,
  2736. writeAddress,
  2737. writeLength,
  2738. NULL,
  2739. 0,
  2740. NULL,
  2741. NULL
  2742. );
  2743. IF_SMB_DEBUG(READ_WRITE2) {
  2744. KdPrint(( "SrvSmbWriteAndX: writing to file 0x%p length %ld, destination 0x%p\n",
  2745. lfcb->FileObject, writeLength,
  2746. writeAddress ));
  2747. }
  2748. }
  2749. //
  2750. // Pass the request to the file system. If the chained command is
  2751. // Close, we need to arrange to restart in the FSP after the write
  2752. // completes.
  2753. //
  2754. // If we have a LargeIndication, we may want to do some cache
  2755. // operations in the restart routine. For this, we must be at passive
  2756. // level.
  2757. //
  2758. if ( WorkContext->LargeIndication == FALSE
  2759. && request->AndXCommand != SMB_COM_CLOSE ) {
  2760. WorkContext->bAlreadyTrace = TRUE;
  2761. WorkContext->FsdRestartRoutine = SrvFsdRestartWriteAndX;
  2762. DEBUG WorkContext->FspRestartRoutine = NULL;
  2763. } else {
  2764. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2765. WorkContext->bAlreadyTrace = FALSE;
  2766. WorkContext->FspRestartRoutine = SrvFsdRestartWriteAndX;
  2767. }
  2768. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2769. //
  2770. // The write has been started. Control will return to
  2771. // SrvFsdRestartWriteAndX when the write completes.
  2772. //
  2773. SmbStatus = SmbStatusInProgress;
  2774. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbWriteAndX complete.\n" ));
  2775. Cleanup:
  2776. SrvWmiEndContext(WorkContext);
  2777. return SmbStatus;
  2778. } // SrvSmbWriteAndX
  2779. SMB_PROCESSOR_RETURN_TYPE
  2780. SrvSmbWriteAndXCompressed (
  2781. SMB_PROCESSOR_PARAMETERS
  2782. )
  2783. /*++
  2784. Routine Description:
  2785. Processes the Write And X SMB to a disk file, when the request is compressed.
  2786. Arguments:
  2787. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  2788. of the parameters to SMB processor routines.
  2789. Return Value:
  2790. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  2791. --*/
  2792. {
  2793. PREQ_NT_WRITE_ANDX ntRequest = (PREQ_NT_WRITE_ANDX)WorkContext->RequestParameters;
  2794. PRFCB rfcb = WorkContext->Rfcb;
  2795. PLFCB lfcb = rfcb->Lfcb;
  2796. CLONG bufferOffset;
  2797. ULONG numChunks, i;
  2798. ULONG uncompressedLength;
  2799. PAGED_CODE();
  2800. //
  2801. // We only support this over virtual circuits
  2802. //
  2803. if( WorkContext->Connection->DirectHostIpx ) {
  2804. IF_DEBUG( ERRORS ) {
  2805. KdPrint(("SRV: Compressed write rejected on direct host IPX!\n" ));
  2806. }
  2807. goto errout;
  2808. }
  2809. RtlZeroMemory( &WorkContext->Parameters.WriteC, sizeof( WorkContext->Parameters.WriteC ) );
  2810. WorkContext->Parameters.WriteC.Offset.LowPart = SmbGetUlong( &ntRequest->Offset );
  2811. WorkContext->Parameters.WriteC.Offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh );
  2812. //
  2813. // If all the client can do is to append, ensure that is all the client is doing
  2814. //
  2815. if( !rfcb->WriteAccessGranted &&
  2816. WorkContext->Parameters.WriteC.Offset.QuadPart <
  2817. rfcb->Mfcb->NonpagedMfcb->OpenFileSize.QuadPart ) {
  2818. IF_DEBUG( ERRORS ) {
  2819. KdPrint(("Srv: Compressed write rejected, only APPEND access granted!\n" ));
  2820. }
  2821. goto errout;
  2822. }
  2823. //
  2824. // If the server supports compression, this is an NT-style Write&X,
  2825. // there's no followon command, the client is writing to a 4K boundry,
  2826. // the target file is compressed, and the target filesystem supports the
  2827. // cache routines -- then we will give compressed writes a shot.
  2828. //
  2829. if( SrvSupportsCompression == FALSE ||
  2830. lfcb->FastIoWriteCompressed == NULL ||
  2831. ntRequest->WordCount != 14 ||
  2832. ntRequest->AndXCommand != SMB_COM_NO_ANDX_COMMAND ||
  2833. WorkContext->Parameters.WriteC.Offset.QuadPart < 0 ||
  2834. (WorkContext->Parameters.WriteC.Offset.LowPart & 0xfff) ||
  2835. !(rfcb->Mfcb->NonpagedMfcb->OpenFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ||
  2836. !(lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) ) {
  2837. //
  2838. // We cannot do a compressed write to this file. Tell the client
  2839. // to retry the operation uncompressed. A polite client probably
  2840. // won't try compressed writes to this file again.
  2841. //
  2842. IF_DEBUG( ERRORS ) {
  2843. KdPrint(("SRV: Compressed write rejected at %u\n", __LINE__));
  2844. }
  2845. goto errout;
  2846. }
  2847. WorkContext->Parameters.WriteC.CdiLength = SmbGetUshort( &ntRequest->CdiLength );
  2848. //
  2849. // If the client said it wanted to do a compressed write, but it
  2850. // didn't give us a COMPRESSED_DATA_INFO structure, then it goofed.
  2851. //
  2852. if( WorkContext->Parameters.WriteC.CdiLength == 0 ) {
  2853. IF_DEBUG( ERRORS ) {
  2854. KdPrint(("SRV: Compressed write rejected: CdiLength == 0!\n" ));
  2855. }
  2856. goto errout;
  2857. }
  2858. bufferOffset = SmbGetUshort( &ntRequest->DataOffset );
  2859. //
  2860. // COMPRESSED_DATA_INFO struct must fit within the buffer we've received
  2861. //
  2862. if( WorkContext->Parameters.WriteC.CdiLength >
  2863. WorkContext->RequestBuffer->DataLength - bufferOffset ) {
  2864. IF_DEBUG( ERRORS ) {
  2865. KdPrint(("SRV: Compressed write rejected: Cdi too large\n" ));
  2866. }
  2867. goto errout;
  2868. }
  2869. //
  2870. // The number of elements in the COMPRESSED_DATA_INFO structure
  2871. // must be sensible. Make sure the COMPRESSED_DATA_INFO is properly
  2872. // aligned.
  2873. //
  2874. if( ((ULONG_PTR)WorkContext->RequestHeader + bufferOffset) & 0x7 ) {
  2875. IF_DEBUG( ERRORS ) {
  2876. KdPrint(("SRV: Compressed write rejected: Cdi not properly aligned\n" ));
  2877. }
  2878. goto errout;
  2879. }
  2880. WorkContext->Parameters.WriteC.Cdi =
  2881. (PCOMPRESSED_DATA_INFO)((ULONG_PTR)WorkContext->RequestHeader + bufferOffset);
  2882. //
  2883. // Make sure we know how to decompress this kind of format
  2884. //
  2885. if( RtlGetCompressionWorkSpaceSize(
  2886. WorkContext->Parameters.WriteC.Cdi->CompressionFormatAndEngine,
  2887. &numChunks,
  2888. &numChunks ) != STATUS_SUCCESS ) {
  2889. IF_DEBUG( ERRORS ) {
  2890. KdPrint(("SRV: Compressed write rejected: RtlGetCompressionWorkSpaceSize!\n" ));
  2891. }
  2892. goto errout;
  2893. }
  2894. //
  2895. // Calculate the number of chunks that we believe we should get, based
  2896. // on the size of the COMPRESSED_DATA_INFO structure that the client indicated
  2897. //
  2898. numChunks =
  2899. ( WorkContext->Parameters.WriteC.CdiLength -
  2900. FIELD_OFFSET( COMPRESSED_DATA_INFO, CompressedChunkSizes ) )/ sizeof( ULONG );
  2901. //
  2902. // Make sure the number chunks in the COMPRESSED_DATA_INFO structure
  2903. // agrees with what we calculate. Maybe if the client tries going uncompressed
  2904. // it will get it right!
  2905. //
  2906. if( numChunks != WorkContext->Parameters.WriteC.Cdi->NumberOfChunks ) {
  2907. IF_DEBUG( ERRORS ) {
  2908. KdPrint(("SRV: Compressed write rejected: numChunks wrong\n" ));
  2909. }
  2910. goto errout;
  2911. }
  2912. //
  2913. // Calculate the amount of compressed data that accompanies this request.
  2914. //
  2915. WorkContext->Parameters.WriteC.CompressedDataLength =
  2916. WorkContext->BytesAvailable -
  2917. bufferOffset -
  2918. WorkContext->Parameters.WriteC.CdiLength;
  2919. if( WorkContext->Parameters.WriteC.CompressedDataLength == 0 ||
  2920. WorkContext->Parameters.WriteC.CompressedDataLength > SrvMaxCompressedDataLength ) {
  2921. IF_DEBUG( ERRORS ) {
  2922. KdPrint(("SRV: Compressed write rejected: CompressedDataLength %u\n",
  2923. WorkContext->Parameters.WriteC.CompressedDataLength ));
  2924. }
  2925. goto errout;
  2926. }
  2927. //
  2928. // Compute the amount of Compressed data that we got in our initial receive.
  2929. //
  2930. WorkContext->Parameters.WriteC.InitialFragmentSize =
  2931. WorkContext->RequestBuffer->DataLength -
  2932. bufferOffset -
  2933. WorkContext->Parameters.WriteC.CdiLength;
  2934. //
  2935. // If we got all of it in this request, but we have LargeIndication turned on, this
  2936. // is some sort of error by the client.
  2937. //
  2938. if( WorkContext->Parameters.WriteC.InitialFragmentSize >=
  2939. WorkContext->Parameters.WriteC.CompressedDataLength &&
  2940. WorkContext->LargeIndication ) {
  2941. IF_DEBUG( ERRORS ) {
  2942. KdPrint(("SRV: Compressed write rejected: LargeIndication, but we got"
  2943. "all of it!\n" ));
  2944. }
  2945. goto errout;
  2946. }
  2947. uncompressedLength = ((ULONG)SmbGetUshort( &ntRequest->DataLengthHigh ) << 16) |
  2948. ((ULONG)SmbGetUshort( &ntRequest->DataLength ));
  2949. WorkContext->Parameters.WriteC.UncompressedDataLength = uncompressedLength;
  2950. WorkContext->Parameters.WriteC.Key = rfcb->ShiftedFid |
  2951. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  2952. WorkContext->Parameters.WriteC.DeviceObject = lfcb->DeviceObject;
  2953. WorkContext->Parameters.WriteC.FileObject = lfcb->FileObject;
  2954. WorkContext->Parameters.WriteC.MdlWriteCompleteCompressed = lfcb->MdlWriteCompleteCompressed;
  2955. //
  2956. // We've gathered up all the state we need into the WriteC block. Now let's
  2957. // see if we can do the write!
  2958. //
  2959. WorkContext->Irp->MdlAddress = NULL;
  2960. WorkContext->Irp->IoStatus.Information = 0;
  2961. WorkContext->Irp->IoStatus.Status = STATUS_SUCCESS;
  2962. IF_DEBUG( COMPRESSION ) {
  2963. KdPrint(("SRV: Compressed Write: %u compressed, %u uncompressed\n",
  2964. WorkContext->Parameters.WriteC.CompressedDataLength,
  2965. WorkContext->Parameters.WriteC.UncompressedDataLength
  2966. ));
  2967. }
  2968. SrvStatistics.CompressedWrites++;
  2969. try {
  2970. if( lfcb->FastIoWriteCompressed(
  2971. lfcb->FileObject,
  2972. &WorkContext->Parameters.WriteC.Offset,
  2973. WorkContext->Parameters.WriteC.UncompressedDataLength,
  2974. WorkContext->Parameters.WriteC.Key,
  2975. NULL,
  2976. &WorkContext->Irp->MdlAddress,
  2977. &WorkContext->Irp->IoStatus,
  2978. (PVOID)WorkContext->Parameters.WriteC.Cdi,
  2979. WorkContext->Parameters.WriteC.CdiLength,
  2980. lfcb->DeviceObject ) && WorkContext->Irp->MdlAddress ) {
  2981. WorkContext->bAlreadyTrace = TRUE;
  2982. RestartPrepareWriteCompressed( WorkContext );
  2983. return SmbStatusInProgress;
  2984. }
  2985. }
  2986. except( EXCEPTION_EXECUTE_HANDLER ) {
  2987. // Fall through to the slow path on an exception
  2988. NTSTATUS status = GetExceptionCode();
  2989. IF_DEBUG(ERRORS) {
  2990. KdPrint(("FastIoRead threw exception %x\n", status ));
  2991. }
  2992. }
  2993. //
  2994. // The fast path failed -- try using an IRP.
  2995. //
  2996. SrvBuildReadOrWriteRequest(
  2997. WorkContext->Irp,
  2998. lfcb->FileObject,
  2999. WorkContext,
  3000. IRP_MJ_WRITE,
  3001. IRP_MN_COMPRESSED | IRP_MN_MDL,
  3002. NULL,
  3003. WorkContext->Parameters.WriteC.UncompressedDataLength,
  3004. NULL,
  3005. WorkContext->Parameters.WriteC.Offset,
  3006. WorkContext->Parameters.WriteC.Key
  3007. );
  3008. WorkContext->Parameters.WriteC.Aux.Buffer = WorkContext->Parameters.WriteC.Cdi;
  3009. WorkContext->Parameters.WriteC.Aux.Length = WorkContext->Parameters.WriteC.CdiLength;
  3010. WorkContext->Irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)&WorkContext->Parameters.WriteC.Aux;
  3011. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  3012. WorkContext->bAlreadyTrace = FALSE;
  3013. WorkContext->FspRestartRoutine = RestartPrepareWriteCompressed;
  3014. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  3015. //
  3016. // The MDL write has been started. When it completes, processing
  3017. // resumes at RestartPrepareWriteCompressed at passive level
  3018. //
  3019. return SmbStatusInProgress;
  3020. errout:
  3021. SrvStatistics.CompressedWritesRejected++;
  3022. SrvSetSmbError( WorkContext, STATUS_SMB_USE_STANDARD );
  3023. return SrvConsumeSmbData( WorkContext );
  3024. }
  3025. VOID SRVFASTCALL
  3026. RestartPrepareWriteCompressed(
  3027. IN OUT PWORK_CONTEXT WorkContext
  3028. )
  3029. /*++
  3030. Routine Description:
  3031. This is the restart routine invoked after we have tried to prepare
  3032. an MDL for a compressed write. It is called at passive level.
  3033. --*/
  3034. {
  3035. PIRP irp = WorkContext->Irp;
  3036. NTSTATUS status = irp->IoStatus.Status;
  3037. PREQ_NT_WRITE_ANDX ntRequest = (PREQ_NT_WRITE_ANDX)WorkContext->RequestParameters;
  3038. ULONG initialAmount;
  3039. PCHAR bufferAddress;
  3040. ULONG count;
  3041. PMDL mdl = irp->MdlAddress;
  3042. PTDI_REQUEST_KERNEL_RECEIVE parameters;
  3043. PIO_STACK_LOCATION irpSp;
  3044. PAGED_CODE();
  3045. WorkContext->Parameters.WriteC.Mdl = mdl;
  3046. if( mdl == NULL && status != STATUS_SUCCESS ) {
  3047. IF_DEBUG( ERRORS ) {
  3048. KdPrint(( "SRV: RestartPrepareWriteCompressed status %X, MDL %p\n", status, mdl ));
  3049. }
  3050. if( status == STATUS_BUFFER_OVERFLOW ||
  3051. status == STATUS_NOT_SUPPORTED ||
  3052. status == STATUS_USER_MAPPED_FILE ) {
  3053. IF_DEBUG( COMPRESSION ) {
  3054. KdPrint(( "SRV: RestartPrepareWriteCompressed, try uncompressed\n" ));
  3055. }
  3056. //
  3057. // Ntfs will force us down the uncompressed path if no substantial gains
  3058. // can be made in writing out the compressed data. Currently the savings
  3059. // must be at least one chunk size. Ntfs will also force us down the
  3060. // uncompressed path if this file is mapped. To avoid having the client
  3061. // send us the data again, we'll decompress it in a side buffer and do
  3062. // a normal write to the file. Then we'll clear the flags2
  3063. // SMB_FLAGS2_COMPRESSED flag to let the client know that we had to write
  3064. // it uncompressed. The client should cease sending us compressed data.
  3065. //
  3066. //
  3067. // Let the client know that we were having to try it uncompressed
  3068. //
  3069. SmbPutAlignedUshort(
  3070. &WorkContext->RequestHeader->Flags2,
  3071. SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 )
  3072. & ~SMB_FLAGS2_COMPRESSED
  3073. );
  3074. //
  3075. // Maybe we have already received the compressed data!
  3076. //
  3077. if( WorkContext->Parameters.WriteC.InitialFragmentSize ==
  3078. WorkContext->Parameters.WriteC.CompressedDataLength ) {
  3079. ASSERT( WorkContext->LargeIndication == FALSE );
  3080. IF_DEBUG( COMPRESSION ) {
  3081. KdPrint(( "SRV: RestartPrepareWriteCompressed, already have the data!\n" ));
  3082. }
  3083. //
  3084. // Make it look like the TDI receive was successful
  3085. //
  3086. WorkContext->Irp->IoStatus.Status = STATUS_SUCCESS;
  3087. WorkContext->Parameters.WriteC.CompressedBuffer =
  3088. (PCHAR)WorkContext->RequestHeader +
  3089. SmbGetUshort( &ntRequest->DataOffset ) +
  3090. WorkContext->Parameters.WriteC.CdiLength;
  3091. RestartWriteCompressed( WorkContext );
  3092. return;
  3093. }
  3094. //
  3095. // We need a buffer to receive the compressed data
  3096. //
  3097. WorkContext->Parameters.WriteC.CompressedBuffer =
  3098. ALLOCATE_HEAP_COLD( WorkContext->Parameters.WriteC.CompressedDataLength,
  3099. BlockTypeDataBuffer );
  3100. if( WorkContext->Parameters.WriteC.CompressedBuffer == NULL ) {
  3101. status = STATUS_SMB_USE_STANDARD;
  3102. } else {
  3103. //
  3104. // We need an MDL to describe the compressed data buffer
  3105. //
  3106. count = (ULONG)MmSizeOfMdl( WorkContext->Parameters.WriteC.CompressedBuffer,
  3107. WorkContext->Parameters.WriteC.CompressedDataLength );
  3108. mdl = ALLOCATE_NONPAGED_POOL( count, BlockTypeDataBuffer );
  3109. if( mdl == NULL ) {
  3110. DEALLOCATE_NONPAGED_POOL( WorkContext->Parameters.WriteC.CompressedBuffer );
  3111. status = STATUS_SMB_USE_STANDARD;
  3112. } else {
  3113. MmInitializeMdl( mdl,
  3114. WorkContext->Parameters.WriteC.CompressedBuffer,
  3115. WorkContext->Parameters.WriteC.CompressedDataLength
  3116. );
  3117. try {
  3118. MmProbeAndLockPages( mdl, KernelMode, IoReadAccess | IoWriteAccess );
  3119. MmGetSystemAddressForMdl( mdl );
  3120. WorkContext->Parameters.WriteC.Mdl = mdl;
  3121. SrvStatistics.CompressedWritesExpanded++;
  3122. } except( EXCEPTION_EXECUTE_HANDLER ) {
  3123. IF_DEBUG( ERRORS ) {
  3124. KdPrint(( "MmProbeAndLockPages status %X at line %d\n", GetExceptionCode(), __LINE__ ));
  3125. }
  3126. DEALLOCATE_NONPAGED_POOL( WorkContext->Parameters.WriteC.CompressedBuffer );
  3127. DEALLOCATE_NONPAGED_POOL( mdl );
  3128. WorkContext->Parameters.WriteC.CompressedBuffer = NULL;
  3129. mdl = NULL;
  3130. status = STATUS_SMB_USE_STANDARD;
  3131. }
  3132. }
  3133. }
  3134. } else {
  3135. SrvStatistics.CompressedWritesFailed++;
  3136. }
  3137. if( mdl == NULL ) {
  3138. if( status == STATUS_SMB_USE_STANDARD ) {
  3139. SrvStatistics.CompressedWritesRejected++;
  3140. }
  3141. SrvSetSmbError( WorkContext, status );
  3142. if( SrvConsumeSmbData( WorkContext ) == SmbStatusSendResponse ) {
  3143. WorkContext->ResponseBuffer->DataLength = sizeof( SMB_HEADER );
  3144. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  3145. //
  3146. // Send the response!
  3147. //
  3148. SRV_START_SEND_2(
  3149. WorkContext,
  3150. SrvFsdRestartSmbAtSendCompletion,
  3151. NULL,
  3152. NULL
  3153. );
  3154. }
  3155. return;
  3156. }
  3157. }
  3158. if( mdl ) {
  3159. //
  3160. // We now have a place to receive the compressed data. It's described by 'mdl'
  3161. //
  3162. bufferAddress = (PCHAR)WorkContext->RequestHeader +
  3163. SmbGetUshort( &ntRequest->DataOffset ) +
  3164. WorkContext->Parameters.WriteC.CdiLength;
  3165. initialAmount = WorkContext->Parameters.WriteC.InitialFragmentSize;
  3166. //
  3167. // Copy the data that we initially received into the buffer described by 'mdl'
  3168. //
  3169. while( initialAmount > 0 ) {
  3170. PVOID SystemAddress;
  3171. count = MIN( initialAmount, MmGetMdlByteCount( mdl ) );
  3172. SystemAddress = MmGetSystemAddressForMdl( mdl );
  3173. if( !SystemAddress )
  3174. {
  3175. // In low resource situations, we can fail to map the buffer
  3176. SrvSetSmbError( WorkContext, STATUS_INSUFFICIENT_RESOURCES );
  3177. SrvConsumeSmbData( WorkContext );
  3178. return;
  3179. }
  3180. RtlCopyMemory( SystemAddress, bufferAddress, count );
  3181. bufferAddress += count;
  3182. initialAmount -= count;
  3183. if( initialAmount ) {
  3184. ASSERT( mdl->Next != NULL );
  3185. mdl = mdl->Next;
  3186. }
  3187. }
  3188. if( mdl && count == MmGetMdlByteCount( mdl ) ) {
  3189. mdl = mdl->Next;
  3190. count = 0;
  3191. }
  3192. } else if( WorkContext->LargeIndication ) {
  3193. //
  3194. // We are here because the filesystem thought the CDI indicated that no
  3195. // more data was required. Yet the client sent us a lot of data.
  3196. //
  3197. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  3198. SrvConsumeSmbData( WorkContext );
  3199. return;
  3200. }
  3201. //
  3202. // If there is no more data to be received from the transport, we are done!
  3203. //
  3204. if( !WorkContext->LargeIndication ) {
  3205. irp->MdlAddress = NULL;
  3206. RestartWriteCompressed( WorkContext );
  3207. return;
  3208. }
  3209. //
  3210. // Time to build the IRP for the TDI receive. We want to receive the remaining
  3211. // data into the buffer described by the MDL we've just gotten, but we
  3212. // need to skip over the InitialFragmentSize. We therefore need to come up with
  3213. // another MDL.
  3214. //
  3215. //
  3216. // Since we've already copied the initial data portion to the target buffer, we
  3217. // can reuse the space in the receive buffer for our MDL, ensuring it is properly
  3218. // aligned.
  3219. //
  3220. irp->MdlAddress = (PMDL)((PCHAR)WorkContext->RequestHeader +
  3221. SmbGetUshort( &ntRequest->DataOffset ) +
  3222. WorkContext->Parameters.WriteC.CdiLength);
  3223. irp->MdlAddress = (PMDL)((((ULONG_PTR)(irp->MdlAddress)) + 7) & ~7);
  3224. ASSERT( WorkContext->Parameters.WriteC.InitialFragmentSize );
  3225. //
  3226. // Build an MDL describing the region into which we want to receive the data.
  3227. // We want an MDL that describes the compressed buffer, but accounts for the
  3228. // fact that we've already consumed the InitialFragmentSize bytes.
  3229. //
  3230. //
  3231. // I am sure this is not the prescribed way to do this!!
  3232. //
  3233. MmGetSystemAddressForMdl( mdl );
  3234. RtlCopyMemory( irp->MdlAddress, mdl, mdl->Size );
  3235. (PBYTE)(irp->MdlAddress->MappedSystemVa) += count;
  3236. irp->MdlAddress->ByteCount -= count;
  3237. irp->MdlAddress->ByteOffset += count;
  3238. irp->MdlAddress->Next = mdl->Next;
  3239. //
  3240. // Prepare the TDI receive for the rest of the compressed data
  3241. //
  3242. irp->Tail.Overlay.OriginalFileObject = NULL;
  3243. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  3244. irpSp = IoGetNextIrpStackLocation( irp );
  3245. IoSetCompletionRoutine(
  3246. irp,
  3247. SrvFsdIoCompletionRoutine,
  3248. WorkContext,
  3249. TRUE,
  3250. TRUE,
  3251. TRUE
  3252. );
  3253. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  3254. irpSp->MinorFunction = (UCHAR)TDI_RECEIVE;
  3255. irpSp->FileObject = WorkContext->Connection->FileObject;
  3256. irpSp->DeviceObject = WorkContext->Connection->DeviceObject;
  3257. irpSp->Flags = 0;
  3258. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  3259. parameters->ReceiveLength = WorkContext->Parameters.WriteC.CompressedDataLength -
  3260. WorkContext->Parameters.WriteC.InitialFragmentSize;
  3261. parameters->ReceiveFlags = 0;
  3262. irp->AssociatedIrp.SystemBuffer = NULL;
  3263. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  3264. irp->Cancel = FALSE;
  3265. if( WorkContext->Parameters.WriteC.CompressedBuffer ) {
  3266. //
  3267. // If we are using the side buffer, we need to restart at passive level.
  3268. //
  3269. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  3270. WorkContext->bAlreadyTrace = FALSE;
  3271. WorkContext->FspRestartRoutine = RestartWriteCompressed;
  3272. } else {
  3273. //
  3274. // We can resume at dispatch level if we are writing directly to the cache
  3275. // buffers
  3276. //
  3277. WorkContext->bAlreadyTrace = TRUE;
  3278. WorkContext->FsdRestartRoutine = RestartWriteCompressed;
  3279. }
  3280. (VOID)IoCallDriver( irpSp->DeviceObject, irp );
  3281. }
  3282. VOID SRVFASTCALL
  3283. RestartWriteCompressed (
  3284. IN OUT PWORK_CONTEXT WorkContext
  3285. )
  3286. /*++
  3287. Routine Description:
  3288. This is the restart routine invoked after the transport has completed the
  3289. receipt of data into buffer we've supplied.
  3290. --*/
  3291. {
  3292. NTSTATUS status = WorkContext->Irp->IoStatus.Status;
  3293. IF_DEBUG( ERRORS ) {
  3294. if( status != STATUS_SUCCESS ) {
  3295. KdPrint(("RestartWriteCompressed: TDI rcv status %X\n", status ));
  3296. }
  3297. }
  3298. //
  3299. // Are we receiving the data directly into the file, or are we having
  3300. // to receive it into a side buffer so we can decompress it ourselves?
  3301. //
  3302. if( WorkContext->Parameters.WriteC.CompressedBuffer != NULL ) {
  3303. PLFCB lfcb = WorkContext->Rfcb->Lfcb;
  3304. BOOLEAN compressedBufferAllocated = FALSE;
  3305. //
  3306. // We are having to decompressed the data ourselves. There are two cases:
  3307. // 1) We received the compressed data in the initial SMB request and did
  3308. // not have to post a follow-on receive to TDI. In this case, WriteC.Mdl
  3309. // is NULL, and WriteC.CompressedBuffer points into our initial SMB. We
  3310. // need to ensure that we do not free it!
  3311. //
  3312. // 2) We had to submit a follow-on receive to TDI for all of the compressed
  3313. // data. In this case WriteC.CompressedBuffer points to the buffer we
  3314. // allocated for the receive, and WriteC.Mdl describes this buffer.
  3315. //
  3316. if( WorkContext->Parameters.WriteC.Mdl ) {
  3317. MmUnlockPages( WorkContext->Parameters.WriteC.Mdl );
  3318. DEALLOCATE_NONPAGED_POOL( WorkContext->Parameters.WriteC.Mdl );
  3319. WorkContext->Parameters.WriteC.Mdl = NULL;
  3320. compressedBufferAllocated = TRUE;
  3321. }
  3322. //
  3323. // Did we get all the data from the transport? Note that if we received all
  3324. // of the data in the initial SMB buffer, then status has been set to
  3325. // STATUS_SUCCESS in RestartPrepareWriteCompressed() above.
  3326. //
  3327. if( status != STATUS_SUCCESS ) {
  3328. FREE_HEAP( WorkContext->Parameters.WriteC.CompressedBuffer );
  3329. SrvSetSmbError( WorkContext, status );
  3330. if( status == STATUS_BUFFER_OVERFLOW ) {
  3331. SrvConsumeSmbData( WorkContext );
  3332. return;
  3333. }
  3334. //
  3335. // Use the standard processor to return the WriteAndX response
  3336. //
  3337. WorkContext->LargeIndication = FALSE;
  3338. WorkContext->Irp->IoStatus.Information = 0;
  3339. SrvFsdRestartWriteAndX( WorkContext );
  3340. return;
  3341. }
  3342. //
  3343. // Now, we need to allocate a buffer for the decompression, and then
  3344. // actually do the decompression
  3345. //
  3346. WorkContext->LargeIndication = FALSE;
  3347. WorkContext->Irp->IoStatus.Information = 0;
  3348. WorkContext->Parameters.WriteC.UncompressedBuffer =
  3349. ALLOCATE_HEAP_COLD( WorkContext->Parameters.WriteC.UncompressedDataLength,
  3350. BlockTypeDataBuffer );
  3351. if( WorkContext->Parameters.WriteC.UncompressedBuffer == NULL ) {
  3352. if( compressedBufferAllocated ) {
  3353. FREE_HEAP( WorkContext->Parameters.WriteC.CompressedBuffer );
  3354. }
  3355. WorkContext->Irp->IoStatus.Status = STATUS_SMB_USE_STANDARD;
  3356. SrvFsdRestartWriteAndX( WorkContext );
  3357. return;
  3358. }
  3359. status = RtlDecompressChunks(
  3360. WorkContext->Parameters.WriteC.UncompressedBuffer,
  3361. WorkContext->Parameters.WriteC.UncompressedDataLength,
  3362. WorkContext->Parameters.WriteC.CompressedBuffer,
  3363. WorkContext->Parameters.WriteC.CompressedDataLength,
  3364. NULL,
  3365. 0,
  3366. WorkContext->Parameters.WriteC.Cdi
  3367. );
  3368. IF_DEBUG( ERRORS ) {
  3369. if( !NT_SUCCESS( status ) ) {
  3370. KdPrint(("RtlDecompressChunks( WC %p, Cdi %p, Buffer %p, Length %u ) status %X\n",
  3371. WorkContext,
  3372. WorkContext->Parameters.WriteC.Cdi,
  3373. WorkContext->Parameters.WriteC.CompressedBuffer,
  3374. WorkContext->Parameters.WriteC.CompressedDataLength,
  3375. status
  3376. ));
  3377. }
  3378. }
  3379. //
  3380. // We don't need the compressed buffer anymore
  3381. //
  3382. if( compressedBufferAllocated ) {
  3383. FREE_HEAP( WorkContext->Parameters.WriteC.CompressedBuffer );
  3384. }
  3385. WorkContext->Parameters.WriteC.CompressedBuffer = NULL;
  3386. if( status != STATUS_SUCCESS ) {
  3387. IF_DEBUG( COMPRESSION ) {
  3388. KdPrint(( "RtlDecompressChunks returns status %X\n", status ));
  3389. }
  3390. FREE_HEAP( WorkContext->Parameters.WriteC.UncompressedBuffer );
  3391. WorkContext->Irp->IoStatus.Status = status;
  3392. SrvFsdRestartWriteAndX( WorkContext );
  3393. return;
  3394. }
  3395. //
  3396. // Since we are going to submit the data to the filesystem, we need an
  3397. // MDL to describe it. We can use the original CDI pointer now, since
  3398. // we know that it is aligned, and it's sitting in the SMB buffer, which
  3399. // is nonpaged pool.
  3400. //
  3401. WorkContext->Parameters.WriteC.Mdl = (PMDL)WorkContext->Parameters.WriteC.Cdi;
  3402. WorkContext->Parameters.WriteC.Cdi = NULL;
  3403. MmInitializeMdl( WorkContext->Parameters.WriteC.Mdl,
  3404. WorkContext->Parameters.WriteC.UncompressedBuffer,
  3405. WorkContext->Parameters.WriteC.UncompressedDataLength
  3406. );
  3407. //
  3408. // Filesystem wants the incoming data to be locked down
  3409. //
  3410. try {
  3411. MmProbeAndLockPages(
  3412. WorkContext->Parameters.WriteC.Mdl,
  3413. KernelMode,
  3414. IoReadAccess
  3415. );
  3416. } except( EXCEPTION_EXECUTE_HANDLER ) {
  3417. status = GetExceptionCode();
  3418. IF_DEBUG( COMPRESSION ) {
  3419. KdPrint(( "MmProbeAndLockPages returns status %X\n", status ));
  3420. }
  3421. FREE_HEAP( WorkContext->Parameters.WriteC.UncompressedBuffer );
  3422. WorkContext->Parameters.WriteC.UncompressedBuffer = NULL;
  3423. WorkContext->Irp->IoStatus.Status = status;
  3424. SrvFsdRestartWriteAndX( WorkContext );
  3425. return;
  3426. }
  3427. MmGetSystemAddressForMdl( WorkContext->Parameters.WriteC.Mdl );
  3428. //
  3429. // Finally! We have the uncompressed data in WriteC.UncompressedBuffer,
  3430. // its length is WriteC.UncompressedDataLength, and it
  3431. // is described by WriteC.Mdl
  3432. //
  3433. if ( lfcb->FastIoWrite != NULL ) {
  3434. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  3435. try {
  3436. if ( lfcb->FastIoWrite(
  3437. lfcb->FileObject,
  3438. &WorkContext->Parameters.WriteC.Offset,
  3439. WorkContext->Parameters.WriteC.UncompressedDataLength,
  3440. TRUE,
  3441. WorkContext->Parameters.WriteC.Key,
  3442. WorkContext->Parameters.WriteC.UncompressedBuffer,
  3443. &WorkContext->Irp->IoStatus,
  3444. lfcb->DeviceObject
  3445. ) ) {
  3446. RestartWriteCompressedCopy( WorkContext );
  3447. return;
  3448. }
  3449. }
  3450. except( EXCEPTION_EXECUTE_HANDLER ) {
  3451. // Fall through to the slow path on an exception
  3452. NTSTATUS status = GetExceptionCode();
  3453. IF_DEBUG(ERRORS) {
  3454. KdPrint(("FastIoRead threw exception %x\n", status ));
  3455. }
  3456. }
  3457. }
  3458. SrvBuildReadOrWriteRequest(
  3459. WorkContext->Irp, // input IRP address
  3460. lfcb->FileObject, // target file object address
  3461. WorkContext, // context
  3462. IRP_MJ_WRITE, // major function code
  3463. 0, // minor function code
  3464. WorkContext->Parameters.WriteC.UncompressedBuffer,
  3465. WorkContext->Parameters.WriteC.UncompressedDataLength,
  3466. WorkContext->Parameters.WriteC.Mdl,
  3467. WorkContext->Parameters.WriteC.Offset,
  3468. WorkContext->Parameters.WriteC.Key
  3469. );
  3470. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  3471. WorkContext->bAlreadyTrace = FALSE;
  3472. WorkContext->FspRestartRoutine = RestartWriteCompressedCopy;
  3473. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  3474. return;
  3475. }
  3476. //
  3477. // We are not having to do the decompression ourselves -- we have written
  3478. // it directly to the filesystem!
  3479. //
  3480. //
  3481. // We may be at raised IRQL at this point. If we are, we should complete
  3482. // the compressed MDL write and come back around again at lowered IRQL
  3483. //
  3484. //
  3485. // Complete the compressed write. Then, if we are at raised IRQL, get out!
  3486. //
  3487. if( WorkContext->Parameters.WriteC.MdlCompleted == FALSE ) {
  3488. if( WorkContext->Parameters.WriteC.MdlWriteCompleteCompressed == NULL ||
  3489. WorkContext->Parameters.WriteC.MdlWriteCompleteCompressed(
  3490. WorkContext->Parameters.WriteC.FileObject,
  3491. &WorkContext->Parameters.WriteC.Offset,
  3492. WorkContext->Parameters.WriteC.Mdl,
  3493. WorkContext->Parameters.WriteC.DeviceObject ) == FALSE ) {
  3494. NTSTATUS mdlStatus;
  3495. mdlStatus = SrvIssueMdlCompleteRequest( NULL, NULL,
  3496. WorkContext->Parameters.WriteC.Mdl,
  3497. IRP_MJ_WRITE,
  3498. &WorkContext->Parameters.WriteC.Offset,
  3499. WorkContext->Parameters.WriteC.CompressedDataLength
  3500. );
  3501. if( !NT_SUCCESS( mdlStatus ) && KeGetCurrentIrql() == PASSIVE_LEVEL ) {
  3502. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, mdlStatus );
  3503. }
  3504. }
  3505. WorkContext->Parameters.WriteC.MdlCompleted = TRUE;
  3506. //
  3507. // If we are at raised IRQL, this is as far as we can go.
  3508. //
  3509. if( KeGetCurrentIrql() != PASSIVE_LEVEL ) {
  3510. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  3511. WorkContext->bAlreadyTrace = FALSE;
  3512. WorkContext->FspRestartRoutine = RestartWriteCompressed;
  3513. SrvQueueWorkToFspAtDpcLevel( WorkContext );
  3514. return;
  3515. }
  3516. }
  3517. //
  3518. // If we didn't get all of the data from the transport, something really went
  3519. // wrong.
  3520. //
  3521. if( status == STATUS_BUFFER_OVERFLOW ) {
  3522. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  3523. SrvConsumeSmbData( WorkContext );
  3524. return;
  3525. }
  3526. //
  3527. // Use the standard processor to return the WriteAndX response
  3528. //
  3529. WorkContext->LargeIndication = FALSE;
  3530. WorkContext->Irp->IoStatus.Information = WorkContext->Parameters.WriteC.UncompressedDataLength;
  3531. SrvFsdRestartWriteAndX( WorkContext );
  3532. }
  3533. VOID SRVFASTCALL
  3534. RestartWriteCompressedCopy (
  3535. IN OUT PWORK_CONTEXT WorkContext
  3536. )
  3537. /*++
  3538. Routine Description:
  3539. If we needed to do an uncompressed write on the client's behalf, we
  3540. decompress the buffer ourselves and write it to the file. This is the
  3541. restart routine for that uncompressed write attempt.
  3542. --*/
  3543. {
  3544. PAGED_CODE();
  3545. //
  3546. // Clean up after ourselves
  3547. //
  3548. MmUnlockPages( WorkContext->Parameters.WriteC.Mdl );
  3549. FREE_HEAP( WorkContext->Parameters.WriteC.UncompressedBuffer );
  3550. WorkContext->Parameters.WriteC.UncompressedBuffer = NULL;
  3551. //
  3552. // And send the response to the client
  3553. //
  3554. SrvFsdRestartWriteAndX( WorkContext );
  3555. }
  3556. VOID SRVFASTCALL
  3557. SrvRestartChainedClose (
  3558. IN OUT PWORK_CONTEXT WorkContext
  3559. )
  3560. /*++
  3561. Routine Description:
  3562. This is the restart routine invoked after before the response to a
  3563. WriteAndClose, or a ReadAndX or a WriteAndX when the chained command
  3564. is Close. This routine closes the file, then sends the response.
  3565. This operation cannot be done in the FSD. Closing a file
  3566. dereferences a number of blocks that are in the FSP address space.
  3567. Arguments:
  3568. WorkContext - Supplies a pointer to the work context block
  3569. representing the work item. The response parameters must be
  3570. fully set up.
  3571. Return Value:
  3572. None.
  3573. --*/
  3574. {
  3575. PRFCB rfcb = WorkContext->Rfcb;
  3576. PRESP_CLOSE closeResponse = WorkContext->ResponseParameters;
  3577. PAGED_CODE( );
  3578. //
  3579. // Set the file last write time.
  3580. //
  3581. if ( rfcb->WriteAccessGranted || rfcb->AppendAccessGranted ) {
  3582. #ifdef INCLUDE_SMB_IFMODIFIED
  3583. (VOID)SrvSetLastWriteTime(
  3584. rfcb,
  3585. WorkContext->Parameters.LastWriteTime,
  3586. rfcb->Lfcb->GrantedAccess,
  3587. FALSE
  3588. );
  3589. #else
  3590. (VOID)SrvSetLastWriteTime(
  3591. rfcb,
  3592. WorkContext->Parameters.LastWriteTime,
  3593. rfcb->Lfcb->GrantedAccess
  3594. );
  3595. #endif
  3596. }
  3597. //
  3598. // Close the file.
  3599. //
  3600. IF_SMB_DEBUG(READ_WRITE2) {
  3601. KdPrint(( "SrvRestartChainedClose: closing RFCB 0x%p\n", WorkContext->Rfcb ));
  3602. }
  3603. #ifdef SLMDBG
  3604. if ( SrvIsSlmStatus( &rfcb->Mfcb->FileName ) &&
  3605. (rfcb->GrantedAccess & FILE_WRITE_DATA) ) {
  3606. NTSTATUS status;
  3607. ULONG offset;
  3608. status = SrvValidateSlmStatus( rfcb->Lfcb->FileHandle, WorkContext, &offset );
  3609. if ( !NT_SUCCESS(status) ) {
  3610. SrvReportCorruptSlmStatus(
  3611. &rfcb->Mfcb->FileName,
  3612. status,
  3613. offset,
  3614. SLMDBG_CLOSE,
  3615. rfcb->Lfcb->Session
  3616. );
  3617. SrvReportSlmStatusOperations( rfcb, FALSE );
  3618. SrvDisallowSlmAccess(
  3619. &rfcb->Lfcb->FileObject->FileName,
  3620. rfcb->Lfcb->TreeConnect->Share->RootDirectoryHandle
  3621. );
  3622. }
  3623. }
  3624. #endif
  3625. SrvCloseRfcb( WorkContext->Rfcb );
  3626. //
  3627. // Dereference the RFCB immediately, rather than waiting for normal
  3628. // work context cleanup after the response send completes. This
  3629. // gets the xFCB structures cleaned up in a more timely manner.
  3630. //
  3631. // *** The specific motivation for this change was to fix a problem
  3632. // where a compatibility mode open was closed, the response was
  3633. // sent, and a Delete SMB was received before the send
  3634. // completion was processed. This resulted in the MFCB and LFCB
  3635. // still being present, which caused the delete processing to
  3636. // try to use the file handle in the LFCB, which we just closed
  3637. // here.
  3638. //
  3639. SrvDereferenceRfcb( WorkContext->Rfcb );
  3640. WorkContext->Rfcb = NULL;
  3641. //
  3642. // Build the response parameters.
  3643. //
  3644. closeResponse->WordCount = 0;
  3645. SmbPutUshort( &closeResponse->ByteCount, 0 );
  3646. WorkContext->ResponseParameters = NEXT_LOCATION( closeResponse, RESP_CLOSE, 0 );
  3647. //
  3648. // Send the response.
  3649. //
  3650. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  3651. return;
  3652. } // SrvRestartChainedClose
  3653. VOID SRVFASTCALL
  3654. RestartLockAndRead (
  3655. IN OUT PWORK_CONTEXT WorkContext
  3656. )
  3657. /*++
  3658. Routine Description:
  3659. Processes file lock completion for a Lock and Read SMB.
  3660. Arguments:
  3661. WorkContext - Supplies a pointer to the work context block
  3662. describing server-specific context for the request.
  3663. Return Value:
  3664. None.
  3665. --*/
  3666. {
  3667. PREQ_READ request;
  3668. LARGE_INTEGER offset;
  3669. NTSTATUS status = STATUS_SUCCESS;
  3670. SMB_STATUS smbStatus = SmbStatusInProgress;
  3671. PSRV_TIMER timer;
  3672. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  3673. PAGED_CODE( );
  3674. if (bNeedTrace) {
  3675. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  3676. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOCK_AND_READ;
  3677. SrvWmiStartContext(WorkContext);
  3678. }
  3679. else
  3680. WorkContext->bAlreadyTrace = FALSE;
  3681. IF_DEBUG(WORKER1) KdPrint(( " - RestartLockAndRead\n" ));
  3682. //
  3683. // If this request was being timed, cancel the timer.
  3684. //
  3685. timer = WorkContext->Parameters.Lock.Timer;
  3686. if ( timer != NULL ) {
  3687. SrvCancelTimer( timer );
  3688. SrvFreeTimer( timer );
  3689. }
  3690. //
  3691. // If the lock request failed, set an error status in the response
  3692. // header.
  3693. //
  3694. status = WorkContext->Irp->IoStatus.Status;
  3695. if ( !NT_SUCCESS(status) ) {
  3696. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.LockViolations );
  3697. IF_DEBUG(ERRORS) KdPrint(( "Lock failed: %X\n", status ));
  3698. //
  3699. // Store the failing lock offset.
  3700. //
  3701. request = (PREQ_READ)WorkContext->RequestParameters;
  3702. offset.QuadPart = SmbGetUlong( &request->Offset );
  3703. WorkContext->Rfcb->PagedRfcb->LastFailingLockOffset = offset;
  3704. //
  3705. // Send back the bad news.
  3706. //
  3707. if ( status == STATUS_CANCELLED ) {
  3708. status = STATUS_FILE_LOCK_CONFLICT;
  3709. }
  3710. SrvSetSmbError( WorkContext, status );
  3711. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  3712. IF_DEBUG(TRACE2) KdPrint(( "RestartLockAndRead complete\n" ));
  3713. goto Cleanup;
  3714. }
  3715. //
  3716. // The lock request completed successfully.
  3717. //
  3718. InterlockedIncrement(
  3719. &WorkContext->Rfcb->NumberOfLocks
  3720. );
  3721. #ifdef INCLUDE_SMB_PERSISTENT
  3722. if (WorkContext->Rfcb->PersistentHandle) {
  3723. //
  3724. // record the lock in the state file before we send back the response.
  3725. //
  3726. }
  3727. #endif
  3728. //
  3729. // Start the read to complete the LockAndRead.
  3730. //
  3731. smbStatus = SrvSmbRead( WorkContext );
  3732. if ( smbStatus != SmbStatusInProgress ) {
  3733. SrvEndSmbProcessing( WorkContext, smbStatus );
  3734. }
  3735. Cleanup:
  3736. if (bNeedTrace) {
  3737. SrvWmiEndContext(WorkContext);
  3738. }
  3739. return;
  3740. } // RestartLockAndRead
  3741. VOID SRVFASTCALL
  3742. RestartPipeReadAndXPeek(
  3743. IN OUT PWORK_CONTEXT WorkContext
  3744. )
  3745. /*++
  3746. Routine Description:
  3747. This function continues a read and X on a named pipe handle. It can
  3748. be called as a restart routine if a peek is preformed, but can also
  3749. be called directly from SrvSmbReadAndX if it is not necessary to
  3750. peek the pipe before reading from it.
  3751. Arguments:
  3752. WorkContext - Supplies a pointer to the work context block
  3753. representing the work item.
  3754. Return Value:
  3755. None.
  3756. --*/
  3757. {
  3758. NTSTATUS status;
  3759. PLFCB lfcb;
  3760. PIRP irp = WorkContext->Irp;
  3761. PIO_STACK_LOCATION irpSp;
  3762. PDEVICE_OBJECT deviceObject;
  3763. PAGED_CODE( );
  3764. lfcb = WorkContext->Rfcb->Lfcb;
  3765. if ( WorkContext->Parameters.ReadAndX.PipePeekBuffer != NULL ) {
  3766. //
  3767. // Non-blocking read. We have issued a pipe peek; free the peek
  3768. // buffer.
  3769. //
  3770. DEALLOCATE_NONPAGED_POOL(
  3771. WorkContext->Parameters.ReadAndX.PipePeekBuffer
  3772. );
  3773. //
  3774. // Now see if there is data to read.
  3775. //
  3776. status = irp->IoStatus.Status;
  3777. if ( NT_SUCCESS(status) ) {
  3778. //
  3779. // There is no data in the pipe. Fail the read.
  3780. //
  3781. SrvSetSmbError( WorkContext, STATUS_PIPE_EMPTY );
  3782. SrvFsdSendResponse( WorkContext );
  3783. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "RestartPipeReadAndXPeek complete.\n" ));
  3784. return;
  3785. } else if ( status != STATUS_BUFFER_OVERFLOW ) {
  3786. //
  3787. // An error occurred. Return the status to the caller.
  3788. //
  3789. SrvSetSmbError( WorkContext, status );
  3790. SrvFsdSendResponse( WorkContext );
  3791. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "RestartPipeReadAndXPeek complete.\n" ));
  3792. return;
  3793. }
  3794. //
  3795. // There is data in pipe; proceed with read.
  3796. //
  3797. }
  3798. //
  3799. // in line internal read
  3800. //
  3801. deviceObject = lfcb->DeviceObject;
  3802. irp->Tail.Overlay.OriginalFileObject = lfcb->FileObject;
  3803. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  3804. DEBUG irp->RequestorMode = KernelMode;
  3805. //
  3806. // Get a pointer to the next stack location. This one is used to
  3807. // hold the parameters for the device I/O control request.
  3808. //
  3809. irpSp = IoGetNextIrpStackLocation( irp );
  3810. //
  3811. // Set up the completion routine.
  3812. //
  3813. IoSetCompletionRoutine(
  3814. irp,
  3815. SrvFsdIoCompletionRoutine,
  3816. WorkContext,
  3817. TRUE,
  3818. TRUE,
  3819. TRUE
  3820. );
  3821. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL,
  3822. irpSp->MinorFunction = 0;
  3823. irpSp->FileObject = lfcb->FileObject;
  3824. irpSp->DeviceObject = deviceObject;
  3825. //
  3826. // Copy the caller's parameters to the service-specific portion of the
  3827. // IRP for those parameters that are the same for all three methods.
  3828. //
  3829. irpSp->Parameters.FileSystemControl.OutputBufferLength =
  3830. WorkContext->Parameters.ReadAndX.ReadLength;
  3831. irpSp->Parameters.FileSystemControl.InputBufferLength = 0;
  3832. irpSp->Parameters.FileSystemControl.FsControlCode = FSCTL_PIPE_INTERNAL_READ;
  3833. irp->MdlAddress = NULL;
  3834. irp->AssociatedIrp.SystemBuffer =
  3835. WorkContext->Parameters.ReadAndX.ReadAddress,
  3836. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  3837. //
  3838. // end in-line
  3839. //
  3840. //
  3841. // Pass the request to the file system. If the chained command is
  3842. // Close, we need to arrange to restart in the FSP after the read
  3843. // completes.
  3844. //
  3845. if ( WorkContext->NextCommand != SMB_COM_CLOSE ) {
  3846. WorkContext->bAlreadyTrace = TRUE;
  3847. WorkContext->FsdRestartRoutine = SrvFsdRestartReadAndX;
  3848. DEBUG WorkContext->FspRestartRoutine = NULL;
  3849. } else {
  3850. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  3851. WorkContext->bAlreadyTrace = FALSE;
  3852. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndX;
  3853. }
  3854. IF_SMB_DEBUG(READ_WRITE2) {
  3855. KdPrint(( "RestartPipeReadAndXPeek: reading from file 0x%p, length %ld, destination 0x%p\n",
  3856. lfcb->FileObject,
  3857. WorkContext->Parameters.ReadAndX.ReadLength,
  3858. WorkContext->Parameters.ReadAndX.ReadAddress
  3859. ));
  3860. }
  3861. (VOID)IoCallDriver( deviceObject, WorkContext->Irp );
  3862. //
  3863. // The read has been started. Control will return to the restart
  3864. // routine when the read completes.
  3865. //
  3866. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "RestartPipeReadAndXPeek complete.\n" ));
  3867. return;
  3868. } // RestartPipeReadAndXPeek
  3869. VOID SRVFASTCALL
  3870. SrvRestartWriteAndUnlock (
  3871. IN OUT PWORK_CONTEXT WorkContext
  3872. )
  3873. /*++
  3874. Routine Description:
  3875. This restart routine is used when the Write part of a Write and
  3876. Unlock SMB completes successfully. (Note that the range remains
  3877. locked if the write fails.) This routine handles the Unlock part of
  3878. the request.
  3879. Arguments:
  3880. WorkContext - Supplies a pointer to the work context block
  3881. describing server-specific context for the request.
  3882. Return Value:
  3883. None.
  3884. --*/
  3885. {
  3886. PREQ_WRITE request;
  3887. PRESP_WRITE response;
  3888. NTSTATUS status;
  3889. PRFCB rfcb;
  3890. PLFCB lfcb;
  3891. LARGE_INTEGER length;
  3892. LARGE_INTEGER offset;
  3893. ULONG key;
  3894. PAGED_CODE( );
  3895. IF_DEBUG(WORKER1) KdPrint(( " - SrvRestartWriteAndUnlock\n" ));
  3896. //
  3897. // Get the request and response parameter pointers.
  3898. //
  3899. request = (PREQ_WRITE)WorkContext->RequestParameters;
  3900. response = (PRESP_WRITE)WorkContext->ResponseParameters;
  3901. //
  3902. // Get the file pointer.
  3903. //
  3904. rfcb = WorkContext->Rfcb;
  3905. IF_DEBUG(TRACE2) {
  3906. KdPrint(( " connection 0x%p, RFCB 0x%p\n",
  3907. WorkContext->Connection, rfcb ));
  3908. }
  3909. lfcb = rfcb->Lfcb;
  3910. //
  3911. // Get the offset and length of the range being unlocked.
  3912. // Combine the FID with the caller's PID to form the local
  3913. // lock key.
  3914. //
  3915. // *** The FID must be included in the key in order to
  3916. // account for the folding of multiple remote
  3917. // compatibility mode opens into a single local open.
  3918. //
  3919. offset.QuadPart = SmbGetUlong( &request->Offset );
  3920. length.QuadPart = SmbGetUshort( &request->Count );
  3921. key = rfcb->ShiftedFid |
  3922. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  3923. //
  3924. // Verify that the client has unlock access to the file via
  3925. // the specified handle.
  3926. //
  3927. if ( rfcb->UnlockAccessGranted ) {
  3928. //
  3929. // Issue the Unlock request.
  3930. //
  3931. // *** Note that we do the Unlock synchronously. Unlock is a
  3932. // quick operation, so there's no point in doing it
  3933. // asynchronously. In order to do this, we have to let
  3934. // normal I/O completion happen (so the event is set), which
  3935. // means that we have to allocate a new IRP (I/O completion
  3936. // likes to deallocate an IRP). This is a little wasteful,
  3937. // since we've got a perfectly good IRP hanging around.
  3938. //
  3939. IF_SMB_DEBUG(READ_WRITE2) {
  3940. KdPrint(( "SrvRestartWriteAndUnlock: Unlocking in file 0x%p: (%ld,%ld), key 0x%lx\n", lfcb->FileObject,
  3941. offset.LowPart, length.LowPart, key ));
  3942. }
  3943. status = SrvIssueUnlockRequest(
  3944. lfcb->FileObject, // target file object
  3945. &lfcb->DeviceObject, // target device object
  3946. IRP_MN_UNLOCK_SINGLE, // unlock operation
  3947. offset, // byte offset
  3948. length, // range length
  3949. key // lock key
  3950. );
  3951. //
  3952. // If the unlock request failed, set an error status in
  3953. // the response header. Otherwise, build a success response.
  3954. //
  3955. if ( !NT_SUCCESS(status) ) {
  3956. IF_DEBUG(ERRORS) {
  3957. KdPrint(( "SrvRestartWriteAndUnlock: Unlock failed: %X\n",
  3958. status ));
  3959. }
  3960. SrvSetSmbError( WorkContext, status );
  3961. } else {
  3962. response->WordCount = 1;
  3963. SmbPutUshort( &response->Count, (USHORT)length.LowPart );
  3964. SmbPutUshort( &response->ByteCount, 0 );
  3965. WorkContext->ResponseParameters =
  3966. NEXT_LOCATION( response, RESP_WRITE, 0 );
  3967. }
  3968. } else {
  3969. SrvStatistics.GrantedAccessErrors++;
  3970. IF_DEBUG(ERRORS) {
  3971. KdPrint(( "SrvRestartWriteAndUnlock: Unlock access not granted.\n"));
  3972. }
  3973. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  3974. }
  3975. //
  3976. // Processing of the SMB is complete. Call SrvEndSmbProcessing
  3977. // to send the response.
  3978. //
  3979. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  3980. IF_DEBUG(TRACE2) KdPrint(( "RestartWrite complete\n" ));
  3981. return;
  3982. } // SrvRestartWriteAndUnlock
  3983. VOID SRVFASTCALL
  3984. SrvRestartWriteAndXRaw (
  3985. IN PWORK_CONTEXT WorkContext
  3986. )
  3987. /*++
  3988. Routine Description:
  3989. This function completes processing of a WriteAndX raw protocol.
  3990. The work context block already points to the correct response. All
  3991. that is left to do is free the transaction block, and dispatch the
  3992. And-X command, or send the response.
  3993. Arguments:
  3994. WorkContext - A pointer to a set of
  3995. Return Value:
  3996. None.
  3997. --*/
  3998. {
  3999. PTRANSACTION transaction;
  4000. PAGED_CODE( );
  4001. transaction = WorkContext->Parameters.Transaction;
  4002. ASSERT( transaction != NULL );
  4003. ASSERT( GET_BLOCK_TYPE( transaction ) == BlockTypeTransaction );
  4004. SrvCloseTransaction( transaction );
  4005. SrvDereferenceTransaction( transaction );
  4006. //
  4007. // Test for a legal followon command, and dispatch as appropriate.
  4008. // Close and CloseAndTreeDisconnect are handled specially.
  4009. //
  4010. switch ( WorkContext->NextCommand ) {
  4011. case SMB_COM_NO_ANDX_COMMAND:
  4012. //
  4013. // No more commands. Send the response.
  4014. //
  4015. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  4016. break;
  4017. case SMB_COM_READ:
  4018. case SMB_COM_READ_ANDX:
  4019. case SMB_COM_LOCK_AND_READ:
  4020. //
  4021. // Redispatch the SMB for more processing.
  4022. //
  4023. SrvProcessSmb( WorkContext );
  4024. break;
  4025. case SMB_COM_CLOSE:
  4026. //case SMB_COM_CLOSE_AND_TREE_DISC: // Bogus SMB
  4027. //
  4028. // Call SrvRestartChainedClose to get the file time set and the
  4029. // file closed.
  4030. //
  4031. WorkContext->Parameters.LastWriteTime =
  4032. ((PREQ_CLOSE)WorkContext->RequestParameters)->LastWriteTimeInSeconds;
  4033. SrvRestartChainedClose( WorkContext );
  4034. break;
  4035. default: // Illegal followon command
  4036. IF_DEBUG(SMB_ERRORS) {
  4037. KdPrint(( "SrvRestartWriteAndXRaw: Illegal followon "
  4038. "command: 0x%lx\n", WorkContext->NextCommand ));
  4039. }
  4040. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  4041. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  4042. }
  4043. IF_DEBUG(TRACE2) KdPrint(( "SrvRestartWriteAndXRaw complete\n" ));
  4044. return;
  4045. } // SrvRestartWriteAndXRaw
  4046. VOID SRVFASTCALL
  4047. SetNewSize (
  4048. IN OUT PWORK_CONTEXT WorkContext
  4049. )
  4050. /*++
  4051. Routine Description:
  4052. Processes the Write SMB when Count == 0. Sets the size of the
  4053. target file to the specified Offset.
  4054. Arguments:
  4055. WorkContext - Supplies a pointer to the work context block
  4056. describing server-specific context for the request.
  4057. Return Value:
  4058. None.
  4059. --*/
  4060. {
  4061. PREQ_WRITE request;
  4062. PRESP_WRITE response;
  4063. NTSTATUS status;
  4064. IO_STATUS_BLOCK ioStatusBlock;
  4065. ACCESS_MASK grantedAccess;
  4066. PLFCB lfcb;
  4067. FILE_END_OF_FILE_INFORMATION newEndOfFile;
  4068. FILE_ALLOCATION_INFORMATION newAllocation;
  4069. PAGED_CODE( );
  4070. IF_DEBUG(TRACE2) KdPrint(( "SetNewSize entered\n" ));
  4071. request = (PREQ_WRITE)WorkContext->RequestParameters;
  4072. response = (PRESP_WRITE)WorkContext->ResponseParameters;
  4073. grantedAccess = WorkContext->Rfcb->GrantedAccess;
  4074. lfcb = WorkContext->Rfcb->Lfcb;
  4075. //
  4076. // Verify that the client has the appropriate access to the file via
  4077. // the specified handle.
  4078. //
  4079. CHECK_FILE_INFORMATION_ACCESS(
  4080. grantedAccess,
  4081. IRP_MJ_SET_INFORMATION,
  4082. FileEndOfFileInformation,
  4083. &status
  4084. );
  4085. if ( NT_SUCCESS(status) ) {
  4086. CHECK_FILE_INFORMATION_ACCESS(
  4087. grantedAccess,
  4088. IRP_MJ_SET_INFORMATION,
  4089. FileAllocationInformation,
  4090. &status
  4091. );
  4092. }
  4093. if ( !NT_SUCCESS(status) ) {
  4094. SrvStatistics.GrantedAccessErrors++;
  4095. IF_DEBUG(SMB_ERRORS) {
  4096. KdPrint(( "SetNewSize: IoCheckFunctionAccess failed: "
  4097. "0x%X, GrantedAccess: %lx\n",
  4098. status, grantedAccess ));
  4099. }
  4100. SrvSetSmbError( WorkContext, status );
  4101. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  4102. return;
  4103. }
  4104. //
  4105. // NtSetInformationFile allows a 64-bit file size, but the SMB
  4106. // protocol only allows 32-bit file sizes. Only set the lower 32
  4107. // bits, leaving the upper bits zero.
  4108. //
  4109. newEndOfFile.EndOfFile.QuadPart = SmbGetUlong( &request->Offset );
  4110. //
  4111. // Set the new EOF.
  4112. //
  4113. status = NtSetInformationFile(
  4114. lfcb->FileHandle,
  4115. &ioStatusBlock,
  4116. &newEndOfFile,
  4117. sizeof(newEndOfFile),
  4118. FileEndOfFileInformation
  4119. );
  4120. if ( NT_SUCCESS(status) ) {
  4121. //
  4122. // Set the new allocation size for the file.
  4123. //
  4124. // !!! This should ONLY be done if this is a down-level client!
  4125. //
  4126. newAllocation.AllocationSize = newEndOfFile.EndOfFile;
  4127. status = NtSetInformationFile(
  4128. lfcb->FileHandle,
  4129. &ioStatusBlock,
  4130. &newAllocation,
  4131. sizeof(newAllocation),
  4132. FileAllocationInformation
  4133. );
  4134. }
  4135. if ( !NT_SUCCESS(status) ) {
  4136. IF_DEBUG(ERRORS) {
  4137. KdPrint(( "SetNewSize: NtSetInformationFile failed, "
  4138. "status = %X\n", status ));
  4139. }
  4140. SrvSetSmbError( WorkContext, status );
  4141. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  4142. return;
  4143. }
  4144. //
  4145. // Build and send the response SMB.
  4146. //
  4147. response->WordCount = 1;
  4148. SmbPutUshort( &response->Count, 0 );
  4149. SmbPutUshort( &response->ByteCount, 0 );
  4150. WorkContext->ResponseParameters = NEXT_LOCATION( response, RESP_WRITE, 0 );
  4151. #ifdef INCLUDE_SMB_IFMODIFIED
  4152. WorkContext->Rfcb->Lfcb->FileUpdated = TRUE;
  4153. #endif
  4154. IF_DEBUG(TRACE2) KdPrint(( "SetNewSize complete\n" ));
  4155. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  4156. return;
  4157. } // SetNewSize
  4158. BOOLEAN
  4159. SetNewPosition (
  4160. IN PRFCB Rfcb,
  4161. IN OUT PULONG Offset,
  4162. IN BOOLEAN RelativeSeek
  4163. )
  4164. /*++
  4165. Routine Description:
  4166. Sets the new file pointer.
  4167. Arguments:
  4168. Rfcb - A pointer to the rfcb block which contains the position.
  4169. Offset - A pointer to the offset sent by client. If RelativeSeek is
  4170. TRUE, then this pointer will be updated.
  4171. RelativeSeek - Whether the seek is relative to the current position.
  4172. Return Value:
  4173. TRUE, Not nagative seek. Position has been updated.
  4174. FALSE, Negative seek. Position not updated.
  4175. --*/
  4176. {
  4177. LARGE_INTEGER newPosition;
  4178. UNLOCKABLE_CODE( 8FIL );
  4179. if ( RelativeSeek ) {
  4180. newPosition.QuadPart = Rfcb->CurrentPosition + *Offset;
  4181. } else {
  4182. newPosition.QuadPart = *Offset;
  4183. }
  4184. if ( newPosition.QuadPart < 0 ) {
  4185. return FALSE;
  4186. }
  4187. Rfcb->CurrentPosition = newPosition.LowPart;
  4188. *Offset = newPosition.LowPart;
  4189. return TRUE;
  4190. } // SetNewPosition
  4191. VOID SRVFASTCALL
  4192. SrvBuildAndSendErrorResponse (
  4193. IN OUT PWORK_CONTEXT WorkContext
  4194. )
  4195. {
  4196. PAGED_CODE( );
  4197. SrvSetSmbError( WorkContext, WorkContext->Irp->IoStatus.Status );
  4198. SrvFsdSendResponse( WorkContext );
  4199. return;
  4200. } // SrvBuildAndSendErrorResponse