Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4114 lines
123 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. #ifdef ALLOC_PRAGMA
  60. #pragma alloc_text( PAGE, SrvSmbLockAndRead )
  61. #pragma alloc_text( PAGE, SrvSmbReadAndX )
  62. #pragma alloc_text( PAGE, SrvSmbSeek )
  63. #pragma alloc_text( PAGE, SrvSmbWrite )
  64. #pragma alloc_text( PAGE, SrvSmbWriteAndX )
  65. #pragma alloc_text( PAGE, SrvRestartChainedClose )
  66. #pragma alloc_text( PAGE, RestartLockAndRead )
  67. #pragma alloc_text( PAGE, RestartPipeReadAndXPeek )
  68. #pragma alloc_text( PAGE, SrvRestartWriteAndUnlock )
  69. #pragma alloc_text( PAGE, SrvRestartWriteAndXRaw )
  70. #pragma alloc_text( PAGE, SetNewSize )
  71. #pragma alloc_text( PAGE, SrvBuildAndSendErrorResponse )
  72. #pragma alloc_text( PAGE8FIL, SetNewPosition )
  73. #endif
  74. SMB_PROCESSOR_RETURN_TYPE
  75. SrvSmbLockAndRead (
  76. SMB_PROCESSOR_PARAMETERS
  77. )
  78. /*++
  79. Routine Description:
  80. Processes Lock And Read SMB. The Lock part of this SMB is started
  81. here as an asynchronous request. When the request completes, the
  82. routine RestartLockAndRead is called. If the lock was obtained,
  83. that routine calls SrvSmbRead, the SMB processor for the core Read
  84. SMB, to process the Read part of the Lock And Read SMB.
  85. Arguments:
  86. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  87. of the parameters to SMB processor routines.
  88. Return Value:
  89. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  90. --*/
  91. {
  92. PREQ_READ request;
  93. USHORT fid;
  94. LARGE_INTEGER length;
  95. LARGE_INTEGER offset;
  96. ULONG key;
  97. BOOLEAN failImmediately;
  98. PRFCB rfcb;
  99. PLFCB lfcb;
  100. PSRV_TIMER timer;
  101. NTSTATUS status = STATUS_SUCCESS;
  102. SMB_STATUS SmbStatus = SmbStatusInProgress;
  103. PAGED_CODE( );
  104. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  105. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOCK_AND_READ;
  106. SrvWmiStartContext(WorkContext);
  107. request = (PREQ_READ)WorkContext->RequestParameters;
  108. //
  109. // Verify the FID. If verified, the RFCB is referenced and its
  110. // addresses is stored in the WorkContext block, and the RFCB
  111. // address is returned.
  112. //
  113. fid = SmbGetUshort( &request->Fid );
  114. rfcb = SrvVerifyFid(
  115. WorkContext,
  116. fid,
  117. TRUE,
  118. SrvRestartSmbReceived, // serialize with raw write
  119. &status
  120. );
  121. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  122. if ( !NT_SUCCESS( status )) {
  123. //
  124. // Invalid file ID or write behind error. Reject the request.
  125. //
  126. IF_DEBUG(ERRORS) {
  127. KdPrint((
  128. "SrvSmbLockAndRead: Status %X on FID: 0x%lx\n",
  129. status,
  130. fid
  131. ));
  132. }
  133. SrvSetSmbError( WorkContext, status );
  134. SmbStatus = SmbStatusSendResponse;
  135. goto Cleanup;
  136. }
  137. //
  138. // The work item has been queued because a raw write is in
  139. // progress.
  140. //
  141. SmbStatus = SmbStatusInProgress;
  142. goto Cleanup;
  143. }
  144. if( rfcb->Lfcb->Session->IsSessionExpired )
  145. {
  146. status = SESSION_EXPIRED_STATUS_CODE;
  147. SrvSetSmbError( WorkContext, status );
  148. SmbStatus = SmbStatusSendResponse;
  149. goto Cleanup;
  150. }
  151. //
  152. // Verify that the client has lock access to the file via the
  153. // specified handle.
  154. //
  155. if ( rfcb->LockAccessGranted && rfcb->ExclusiveLockGranted ) {
  156. //
  157. // Get the offset and length of the range being locked. Combine the
  158. // FID with the caller's PID to form the local lock key.
  159. //
  160. // *** The FID must be included in the key in order to account for
  161. // the folding of multiple remote compatibility mode opens into
  162. // a single local open.
  163. //
  164. offset.QuadPart = SmbGetUlong( &request->Offset );
  165. length.QuadPart = SmbGetUshort( &request->Count );
  166. key = rfcb->ShiftedFid |
  167. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  168. IF_SMB_DEBUG(READ_WRITE1) {
  169. KdPrint(( "Lock and Read request; FID 0x%lx, count %ld, offset %ld\n",
  170. fid, length.LowPart, offset.LowPart ));
  171. }
  172. lfcb = rfcb->Lfcb;
  173. IF_SMB_DEBUG(READ_WRITE2) {
  174. KdPrint(( "SrvSmbLockAndRead: Locking in file 0x%p: (%ld,%ld), key 0x%lx\n",
  175. lfcb->FileObject, offset.LowPart, length.LowPart, key ));
  176. }
  177. //
  178. // If the session has expired, return that info
  179. //
  180. if( lfcb->Session->IsSessionExpired )
  181. {
  182. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  183. status = SESSION_EXPIRED_STATUS_CODE;
  184. SmbStatus = SmbStatusSendResponse;
  185. goto Cleanup;
  186. }
  187. //
  188. // Try the turbo lock path first. If the client is retrying the
  189. // lock that just failed, we want FailImmediately to be FALSE, so
  190. // that the fast path fails if there's a conflict.
  191. //
  192. failImmediately = (BOOLEAN)(
  193. (offset.QuadPart != rfcb->PagedRfcb->LastFailingLockOffset.QuadPart)
  194. &&
  195. (offset.QuadPart < SrvLockViolationOffset) );
  196. if ( lfcb->FastIoLock != NULL ) {
  197. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksAttempted );
  198. if ( lfcb->FastIoLock(
  199. lfcb->FileObject,
  200. &offset,
  201. &length,
  202. IoGetCurrentProcess(),
  203. key,
  204. failImmediately,
  205. TRUE,
  206. &WorkContext->Irp->IoStatus,
  207. lfcb->DeviceObject
  208. ) ) {
  209. //
  210. // If the turbo path got the lock, start the read.
  211. // Otherwise, return an error.
  212. //
  213. if ( NT_SUCCESS( WorkContext->Irp->IoStatus.Status ) ) {
  214. InterlockedIncrement( &rfcb->NumberOfLocks );
  215. SmbStatus = SrvSmbRead( WorkContext );
  216. goto Cleanup;
  217. }
  218. WorkContext->Parameters.Lock.Timer = NULL;
  219. RestartLockAndRead( WorkContext );
  220. return SmbStatusInProgress;
  221. }
  222. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksFailed );
  223. }
  224. //
  225. // The turbo path failed (or didn't exist). Start the lock request,
  226. // reusing the receive IRP. If the client is retrying the lock that
  227. // just failed, start a timer for the request.
  228. //
  229. timer = NULL;
  230. if ( !failImmediately ) {
  231. timer = SrvAllocateTimer( );
  232. if ( timer == NULL ) {
  233. failImmediately = TRUE;
  234. }
  235. }
  236. SrvBuildLockRequest(
  237. WorkContext->Irp, // input IRP address
  238. lfcb->FileObject, // target file object address
  239. WorkContext, // context
  240. offset, // byte offset
  241. length, // range length
  242. key, // lock key
  243. failImmediately,
  244. TRUE // exclusive lock?
  245. );
  246. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  247. WorkContext->bAlreadyTrace = FALSE;
  248. WorkContext->FspRestartRoutine = RestartLockAndRead;
  249. //
  250. // Start the timer, if necessary.
  251. //
  252. WorkContext->Parameters.Lock.Timer = timer;
  253. if ( timer != NULL ) {
  254. SrvSetTimer(
  255. timer,
  256. &SrvLockViolationDelayRelative,
  257. TimeoutLockRequest,
  258. WorkContext
  259. );
  260. }
  261. //
  262. // Pass the request to the file system.
  263. //
  264. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  265. //
  266. // The lock request has been started. Return the InProgress status
  267. // to the caller, indicating that the caller should do nothing
  268. // further with the SMB/WorkContext at the present time.
  269. //
  270. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbLockAndRead complete\n" ));
  271. SmbStatus = SmbStatusInProgress;
  272. } else {
  273. SrvStatistics.GrantedAccessErrors++;
  274. IF_DEBUG(ERRORS) {
  275. KdPrint(( "SrvSmbLockAndRead: Lock access not granted.\n"));
  276. }
  277. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  278. status = STATUS_ACCESS_DENIED;
  279. SmbStatus = SmbStatusSendResponse;
  280. }
  281. Cleanup:
  282. SrvWmiEndContext(WorkContext);
  283. return SmbStatus;
  284. } // SrvSmbLockAndRead
  285. SMB_PROCESSOR_RETURN_TYPE
  286. SrvSmbRead (
  287. SMB_PROCESSOR_PARAMETERS
  288. )
  289. /*++
  290. Routine Description:
  291. Processes the Read SMB. This is the "core" read. Also processes
  292. the Read part of the Lock and Read SMB.
  293. Arguments:
  294. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  295. of the parameters to SMB processor routines.
  296. Return Value:
  297. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  298. --*/
  299. {
  300. PREQ_READ request;
  301. PRESP_READ response;
  302. NTSTATUS status = STATUS_SUCCESS;
  303. SMB_STATUS SmbStatus = SmbStatusInProgress;
  304. USHORT fid;
  305. PRFCB rfcb;
  306. PLFCB lfcb;
  307. PCHAR readAddress;
  308. CLONG readLength;
  309. LARGE_INTEGER offset;
  310. ULONG key;
  311. SHARE_TYPE shareType;
  312. PAGED_CODE( );
  313. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  314. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ;
  315. SrvWmiStartContext(WorkContext);
  316. request = (PREQ_READ)WorkContext->RequestParameters;
  317. response = (PRESP_READ)WorkContext->ResponseParameters;
  318. fid = SmbGetUshort( &request->Fid );
  319. IF_SMB_DEBUG(READ_WRITE1) {
  320. KdPrint(( "Read request; FID 0x%lx, count %ld, offset %ld\n",
  321. fid, SmbGetUshort( &request->Count ),
  322. SmbGetUlong( &request->Offset ) ));
  323. }
  324. //
  325. // First, verify the FID. If verified, the RFCB is referenced and
  326. // its address is stored in the WorkContext block, and the RFCB
  327. // address is returned.
  328. //
  329. rfcb = SrvVerifyFid(
  330. WorkContext,
  331. fid,
  332. TRUE,
  333. SrvRestartSmbReceived, // serialize with raw write
  334. &status
  335. );
  336. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  337. if ( !NT_SUCCESS(status) ) {
  338. //
  339. // Invalid file ID or write behind error. Reject the
  340. // request.
  341. //
  342. IF_DEBUG(ERRORS) {
  343. KdPrint((
  344. "SrvSmbRead: Status %X on FID: 0x%lx\n",
  345. status,
  346. fid
  347. ));
  348. }
  349. SrvSetSmbError( WorkContext, status );
  350. SmbStatus = SmbStatusSendResponse;
  351. goto Cleanup;
  352. }
  353. //
  354. // The work item has been queued because a raw write is in
  355. // progress.
  356. //
  357. SmbStatus = SmbStatusInProgress;
  358. goto Cleanup;
  359. }
  360. lfcb = rfcb->Lfcb;
  361. shareType = rfcb->ShareType;
  362. //
  363. // If the session has expired, return that info
  364. //
  365. if( lfcb->Session->IsSessionExpired )
  366. {
  367. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  368. status = SESSION_EXPIRED_STATUS_CODE;
  369. SmbStatus = SmbStatusSendResponse;
  370. goto Cleanup;
  371. }
  372. //
  373. // Verify that the client has read access to the file via the
  374. // specified handle.
  375. //
  376. if ( !rfcb->ReadAccessGranted ) {
  377. CHECK_PAGING_IO_ACCESS(
  378. WorkContext,
  379. rfcb->GrantedAccess,
  380. &status );
  381. if ( !NT_SUCCESS( status ) ) {
  382. SrvStatistics.GrantedAccessErrors++;
  383. IF_DEBUG(ERRORS) {
  384. KdPrint(( "SrvSmbRead: Read access not granted.\n"));
  385. }
  386. SrvSetSmbError( WorkContext, status );
  387. SmbStatus = SmbStatusSendResponse;
  388. goto Cleanup;
  389. }
  390. }
  391. //
  392. // If this operation may block, and we are running short of free
  393. // work items, fail this SMB with an out of resources error.
  394. //
  395. if ( rfcb->BlockingModePipe ) {
  396. if ( SrvReceiveBufferShortage( ) ) {
  397. //
  398. // Fail the operation.
  399. //
  400. SrvStatistics.BlockingSmbsRejected++;
  401. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  402. status = STATUS_INSUFF_SERVER_RESOURCES;
  403. SmbStatus = SmbStatusSendResponse;
  404. goto Cleanup;
  405. } else {
  406. //
  407. // It is okay to start a blocking operation.
  408. // SrvReceiveBufferShortage() has already incremented
  409. // SrvBlockingOpsInProgress.
  410. //
  411. WorkContext->BlockingOperation = TRUE;
  412. }
  413. }
  414. //
  415. // Form the lock key using the FID and the PID. (This is also
  416. // irrelevant for pipes.)
  417. //
  418. // *** The FID must be included in the key in order to account for
  419. // the folding of multiple remote compatibility mode opens into
  420. // a single local open.
  421. //
  422. key = rfcb->ShiftedFid |
  423. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  424. //
  425. // See if the direct host IPX smart card can handle this read. If so,
  426. // return immediately, and the card will call our restart routine at
  427. // SrvIpxSmartCardReadComplete
  428. //
  429. if( rfcb->PagedRfcb->IpxSmartCardContext ) {
  430. IF_DEBUG( SIPX ) {
  431. KdPrint(( "SrvSmbRead: calling SmartCard Read for context %p\n",
  432. WorkContext ));
  433. }
  434. //
  435. // Set the fields needed by SrvIpxSmartCardReadComplete in case the smart
  436. // card is going to handle this request
  437. //
  438. WorkContext->Parameters.SmartCardRead.MdlReadComplete = lfcb->MdlReadComplete;
  439. WorkContext->Parameters.SmartCardRead.DeviceObject = lfcb->DeviceObject;
  440. if( SrvIpxSmartCard.Read( WorkContext->RequestBuffer->Buffer,
  441. rfcb->PagedRfcb->IpxSmartCardContext,
  442. key,
  443. WorkContext ) == TRUE ) {
  444. IF_DEBUG( SIPX ) {
  445. KdPrint(( " SrvSmbRead: SmartCard Read returns TRUE\n" ));
  446. }
  447. SmbStatus = SmbStatusInProgress;
  448. goto Cleanup;
  449. }
  450. IF_DEBUG( SIPX ) {
  451. KdPrint(( " SrvSmbRead: SmartCard Read returns FALSE\n" ));
  452. }
  453. }
  454. //
  455. // Determine the maximum amount of data we can read. This is the
  456. // minimum of the amount requested by the client and the amount of
  457. // room left in the response buffer. (Note that even though we may
  458. // use an MDL read, the read length is still limited to the size of
  459. // an SMB buffer.)
  460. //
  461. readAddress = (PCHAR)response->Buffer;
  462. readLength = MIN(
  463. (CLONG)SmbGetUshort( &request->Count ),
  464. WorkContext->ResponseBuffer->BufferLength -
  465. PTR_DIFF(readAddress, WorkContext->ResponseHeader)
  466. );
  467. //
  468. // Get the file offset. (This is irrelevant for pipes.)
  469. //
  470. offset.QuadPart = SmbGetUlong( &request->Offset );
  471. //
  472. // Try the fast I/O path first. If that fails, fall through to the
  473. // normal build-an-IRP path.
  474. //
  475. if ( lfcb->FastIoRead != NULL ) {
  476. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  477. try {
  478. if ( lfcb->FastIoRead(
  479. lfcb->FileObject,
  480. &offset,
  481. readLength,
  482. TRUE,
  483. key,
  484. readAddress,
  485. &WorkContext->Irp->IoStatus,
  486. lfcb->DeviceObject
  487. ) ) {
  488. //
  489. // The fast I/O path worked. Call the restart routine directly
  490. // to do postprocessing (including sending the response).
  491. //
  492. WorkContext->bAlreadyTrace = TRUE;
  493. SrvFsdRestartRead( WorkContext );
  494. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbRead complete.\n" ));
  495. SmbStatus = SmbStatusInProgress;
  496. goto Cleanup;
  497. }
  498. }
  499. except( EXCEPTION_EXECUTE_HANDLER ) {
  500. // Fall through to the slow path on an exception
  501. status = GetExceptionCode();
  502. IF_DEBUG(ERRORS) {
  503. KdPrint(("FastIoRead threw exception %x\n", status ));
  504. }
  505. }
  506. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  507. }
  508. //
  509. // The turbo path failed. Build the read request, reusing the
  510. // receive IRP.
  511. //
  512. if ( rfcb->ShareType != ShareTypePipe ) {
  513. //
  514. // Note that we never do MDL reads here. The reasoning behind
  515. // this is that because the read is going into an SMB buffer, it
  516. // can't be all that large (by default, no more than 4K bytes),
  517. // so the difference in cost between copy and MDL is minimal; in
  518. // fact, copy read is probably faster than MDL read.
  519. //
  520. // Build an MDL describing the read buffer. Note that if the
  521. // file system can complete the read immediately, the MDL isn't
  522. // really needed, but if the file system must send the request
  523. // to its FSP, the MDL _is_ needed.
  524. //
  525. // *** Note the assumption that the response buffer already has
  526. // a valid full MDL from which a partial MDL can be built.
  527. //
  528. IoBuildPartialMdl(
  529. WorkContext->ResponseBuffer->Mdl,
  530. WorkContext->ResponseBuffer->PartialMdl,
  531. readAddress,
  532. readLength
  533. );
  534. //
  535. // Build the IRP.
  536. //
  537. SrvBuildReadOrWriteRequest(
  538. WorkContext->Irp, // input IRP address
  539. lfcb->FileObject, // target file object address
  540. WorkContext, // context
  541. IRP_MJ_READ, // major function code
  542. 0, // minor function code
  543. readAddress, // buffer address
  544. readLength, // buffer length
  545. WorkContext->ResponseBuffer->PartialMdl, // MDL address
  546. offset, // byte offset
  547. key // lock key
  548. );
  549. IF_SMB_DEBUG(READ_WRITE2) {
  550. KdPrint(( "SrvSmbRead: copy read from file 0x%p, offset %ld, length %ld, destination 0x%p\n",
  551. lfcb->FileObject, offset.LowPart, readLength,
  552. readAddress ));
  553. }
  554. } else { // if ( rfcb->ShareType != ShareTypePipe )
  555. //
  556. // Build the PIPE_INTERNAL_READ IRP.
  557. //
  558. SrvBuildIoControlRequest(
  559. WorkContext->Irp,
  560. lfcb->FileObject,
  561. WorkContext,
  562. IRP_MJ_FILE_SYSTEM_CONTROL,
  563. FSCTL_PIPE_INTERNAL_READ,
  564. readAddress,
  565. 0,
  566. NULL,
  567. readLength,
  568. NULL,
  569. NULL
  570. );
  571. IF_SMB_DEBUG(READ_WRITE2) {
  572. KdPrint(( "SrvSmbRead: reading from file 0x%p, length %ld, destination 0x%p\n",
  573. lfcb->FileObject, readLength, readAddress ));
  574. }
  575. }
  576. //
  577. // Load the restart routine address and pass the request to the file
  578. // system.
  579. //
  580. WorkContext->bAlreadyTrace = TRUE;
  581. WorkContext->FsdRestartRoutine = SrvFsdRestartRead;
  582. DEBUG WorkContext->FspRestartRoutine = NULL;
  583. #if SRVCATCH
  584. if( rfcb->SrvCatch > 0 ) {
  585. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  586. WorkContext->bAlreadyTrace = FALSE;
  587. WorkContext->FspRestartRoutine = SrvFsdRestartRead;
  588. }
  589. #endif
  590. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  591. //
  592. // The read has been started. Control will return to the restart
  593. // routine when the read completes.
  594. //
  595. SmbStatus = SmbStatusInProgress;
  596. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbRead complete.\n" ));
  597. Cleanup:
  598. SrvWmiEndContext(WorkContext);
  599. return SmbStatus;
  600. } // SrvSmbRead
  601. SMB_PROCESSOR_RETURN_TYPE
  602. SrvSmbReadAndX (
  603. SMB_PROCESSOR_PARAMETERS
  604. )
  605. /*++
  606. Routine Description:
  607. Processes the Read And X SMB.
  608. Arguments:
  609. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  610. of the parameters to SMB processor routines.
  611. Return Value:
  612. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  613. --*/
  614. {
  615. PREQ_READ_ANDX request;
  616. PREQ_NT_READ_ANDX ntRequest;
  617. PRESP_READ_ANDX response;
  618. NTSTATUS status = STATUS_SUCCESS;
  619. SMB_STATUS SmbStatus = SmbStatusInProgress;
  620. USHORT fid;
  621. PRFCB rfcb;
  622. PLFCB lfcb;
  623. CLONG bufferOffset;
  624. PCHAR readAddress;
  625. CLONG readLength;
  626. LARGE_INTEGER offset;
  627. ULONG key;
  628. SHARE_TYPE shareType;
  629. BOOLEAN largeRead;
  630. PMDL mdl = NULL;
  631. UCHAR minorFunction;
  632. PBYTE readBuffer;
  633. USHORT flags2;
  634. PAGED_CODE( );
  635. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  636. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_AND_X;
  637. SrvWmiStartContext(WorkContext);
  638. request = (PREQ_READ_ANDX)WorkContext->RequestParameters;
  639. ntRequest = (PREQ_NT_READ_ANDX)WorkContext->RequestParameters;
  640. response = (PRESP_READ_ANDX)WorkContext->ResponseParameters;
  641. fid = SmbGetUshort( &request->Fid );
  642. IF_SMB_DEBUG(READ_WRITE1) {
  643. KdPrint(( "ReadAndX request; FID 0x%lx, count %ld, offset %ld\n",
  644. fid, SmbGetUshort( &request->MaxCount ),
  645. SmbGetUlong( &request->Offset ) ));
  646. }
  647. //
  648. // First, verify the FID. If verified, the RFCB is referenced and
  649. // its address is stored in the WorkContext block, and the RFCB
  650. // address is returned.
  651. //
  652. rfcb = SrvVerifyFid(
  653. WorkContext,
  654. fid,
  655. TRUE,
  656. SrvRestartSmbReceived, // serialize with raw write
  657. &status
  658. );
  659. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  660. if ( !NT_SUCCESS(status) ) {
  661. //
  662. // Invalid file ID or write behind error. Reject the
  663. // request.
  664. //
  665. IF_DEBUG(ERRORS) {
  666. KdPrint((
  667. "SrvSmbReadAndX Status %X on FID: 0x%lx\n",
  668. status,
  669. fid
  670. ));
  671. }
  672. SrvSetSmbError( WorkContext, status );
  673. SmbStatus = SmbStatusSendResponse;
  674. goto Cleanup;
  675. }
  676. //
  677. // The work item has been queued because a raw write is in
  678. // progress.
  679. //
  680. SmbStatus = SmbStatusInProgress;
  681. goto Cleanup;
  682. }
  683. lfcb = rfcb->Lfcb;
  684. shareType = rfcb->ShareType;
  685. //
  686. // If the session has expired, return that info
  687. //
  688. if( lfcb->Session->IsSessionExpired )
  689. {
  690. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  691. status = SESSION_EXPIRED_STATUS_CODE;
  692. SmbStatus = SmbStatusSendResponse;
  693. goto Cleanup;
  694. }
  695. //
  696. // Verify that the client has read access to the file via the
  697. // specified handle.
  698. //
  699. if ( !rfcb->ReadAccessGranted ) {
  700. CHECK_PAGING_IO_ACCESS(
  701. WorkContext,
  702. rfcb->GrantedAccess,
  703. &status );
  704. if ( !NT_SUCCESS( status ) ) {
  705. SrvStatistics.GrantedAccessErrors++;
  706. IF_DEBUG(ERRORS) {
  707. KdPrint(( "SrvSmbReadAndX: Read access not granted.\n"));
  708. }
  709. SrvSetSmbError( WorkContext, status );
  710. SmbStatus = SmbStatusSendResponse;
  711. goto Cleanup;
  712. }
  713. }
  714. readLength = (CLONG)SmbGetUshort( &request->MaxCount );
  715. //
  716. // NT requests allow the specification of up to 32 bits worth of read length.
  717. // This field is overlaid with the Timeout field for pipe reads. Some redirs
  718. // set this field to 0xFFFFFFFF, even if a pipe isn't involved. So, we need to
  719. // filter out those fellows.
  720. //
  721. if( request->WordCount == 12 &&
  722. shareType != ShareTypePipe
  723. && SmbGetUshort( &ntRequest->MaxCountHigh ) != 0xFFFF ) {
  724. readLength |= ((CLONG)SmbGetUshort( &ntRequest->MaxCountHigh )) << 16;
  725. }
  726. //
  727. // The returned data must be longword aligned. (Note the assumption
  728. // that the SMB itself is longword aligned.)
  729. //
  730. // NOTE: Don't change this for 64-bit, as it will Break Win2K interop
  731. bufferOffset = PTR_DIFF(response->Buffer, WorkContext->ResponseHeader);
  732. WorkContext->Parameters.ReadAndX.PadCount = (USHORT)(3 - (bufferOffset & 3));
  733. // This was changed to be Pointer-size aligned so this works in 64-bit
  734. bufferOffset = (bufferOffset + 3) & ~3;
  735. //
  736. // If we are not reading from a disk file, or we're connectionless,
  737. // or there's an ANDX command,
  738. // don't let the client exceed the negotiated buffer size.
  739. //
  740. if( shareType != ShareTypeDisk ||
  741. request->AndXCommand != SMB_COM_NO_ANDX_COMMAND ||
  742. WorkContext->Endpoint->IsConnectionless ) {
  743. readLength = MIN( readLength,
  744. WorkContext->ResponseBuffer->BufferLength - bufferOffset
  745. );
  746. } else {
  747. //
  748. // We're letting large reads through! Make sure it isn't
  749. // too large
  750. //
  751. readLength = MIN( readLength, SrvMaxReadSize );
  752. }
  753. largeRead = ( readLength > WorkContext->ResponseBuffer->BufferLength - bufferOffset );
  754. readAddress = (PCHAR)WorkContext->ResponseHeader + bufferOffset;
  755. WorkContext->Parameters.ReadAndX.ReadAddress = readAddress;
  756. WorkContext->Parameters.ReadAndX.ReadLength = readLength;
  757. //
  758. // Get the file offset. (This is irrelevant for pipes.)
  759. //
  760. if ( shareType != ShareTypePipe ) {
  761. if ( request->WordCount == 10 ) {
  762. //
  763. // The client supplied a 32-bit offset.
  764. //
  765. offset.QuadPart = SmbGetUlong( &request->Offset );
  766. } else if ( request->WordCount == 12 ) {
  767. //
  768. // The client supplied a 64-bit offset.
  769. //
  770. offset.LowPart = SmbGetUlong( &ntRequest->Offset );
  771. offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh );
  772. //
  773. // Reject negative offsets
  774. //
  775. if ( offset.QuadPart < 0 ) {
  776. SrvLogInvalidSmb( WorkContext );
  777. IF_DEBUG(ERRORS) {
  778. KdPrint(( "SrvSmbReadAndX: Negative offset rejected.\n"));
  779. }
  780. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  781. status = STATUS_INVALID_SMB;
  782. SmbStatus = SmbStatusSendResponse;
  783. goto Cleanup;
  784. }
  785. } else {
  786. //
  787. // This is an invalid word count for Read and X.
  788. //
  789. SrvLogInvalidSmb( WorkContext );
  790. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  791. status = STATUS_INVALID_SMB;
  792. SmbStatus = SmbStatusSendResponse;
  793. goto Cleanup;
  794. }
  795. WorkContext->Parameters.ReadAndX.ReadOffset = offset;
  796. } else {
  797. if ( (request->WordCount != 10) && (request->WordCount != 12) ) {
  798. //
  799. // This is an invalid word count for Read and X.
  800. //
  801. SrvLogInvalidSmb( WorkContext );
  802. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  803. status = STATUS_INVALID_SMB;
  804. SmbStatus = SmbStatusSendResponse;
  805. goto Cleanup;
  806. }
  807. }
  808. //
  809. // Form the lock key using the FID and the PID. (This is also
  810. // irrelevant for pipes.)
  811. //
  812. // *** The FID must be included in the key in order to account for
  813. // the folding of multiple remote compatibility mode opens into
  814. // a single local open.
  815. //
  816. key = rfcb->ShiftedFid |
  817. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  818. //
  819. // Save the AndX command code. This is necessary because the read
  820. // data may overwrite the AndX command. This command must be Close.
  821. // We don't need to save the offset because we're not going to look
  822. // at the AndX command request after starting the read.
  823. //
  824. WorkContext->NextCommand = request->AndXCommand;
  825. if ( request->AndXCommand == SMB_COM_CLOSE ) {
  826. //
  827. // Make sure the accompanying CLOSE fits within the received SMB buffer
  828. //
  829. if( (PCHAR)WorkContext->RequestHeader + request->AndXOffset + FIELD_OFFSET(REQ_CLOSE,Buffer) >
  830. END_OF_REQUEST_SMB( WorkContext ) ) {
  831. SrvLogInvalidSmb( WorkContext );
  832. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  833. status = STATUS_INVALID_SMB;
  834. SmbStatus = SmbStatusSendResponse;
  835. goto Cleanup;
  836. }
  837. WorkContext->Parameters.ReadAndX.LastWriteTimeInSeconds =
  838. ((PREQ_CLOSE)((PUCHAR)WorkContext->RequestHeader +
  839. request->AndXOffset))->LastWriteTimeInSeconds;
  840. }
  841. //
  842. // Try the fast I/O path first. If that fails, fall through to the
  843. // normal build-an-IRP path.
  844. //
  845. if( !largeRead ) {
  846. small_read:
  847. if ( lfcb->FastIoRead != NULL ) {
  848. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  849. try {
  850. if ( lfcb->FastIoRead(
  851. lfcb->FileObject,
  852. &offset,
  853. readLength,
  854. TRUE,
  855. key,
  856. readAddress,
  857. &WorkContext->Irp->IoStatus,
  858. lfcb->DeviceObject
  859. ) ) {
  860. //
  861. // The fast I/O path worked. Call the restart routine directly
  862. // to do postprocessing (including sending the response).
  863. //
  864. WorkContext->bAlreadyTrace = TRUE;
  865. SrvFsdRestartReadAndX( WorkContext );
  866. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbReadAndX complete.\n" ));
  867. SmbStatus = SmbStatusInProgress;
  868. goto Cleanup;
  869. }
  870. }
  871. except( EXCEPTION_EXECUTE_HANDLER ) {
  872. // Fall through to the slow path on an exception
  873. status = GetExceptionCode();
  874. IF_DEBUG(ERRORS) {
  875. KdPrint(("FastIoRead threw exception %x\n", status ));
  876. }
  877. }
  878. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  879. }
  880. //
  881. // The turbo path failed. Build the read request, reusing the
  882. // receive IRP.
  883. //
  884. if ( shareType == ShareTypePipe ) {
  885. //
  886. // Pipe read. If this is a non-blocking read, ensure we won't
  887. // block; otherwise, proceed with the request.
  888. //
  889. if ( rfcb->BlockingModePipe &&
  890. (SmbGetUshort( &request->MinCount ) == 0) ) {
  891. PFILE_PIPE_PEEK_BUFFER pipePeekBuffer;
  892. //
  893. // This is a non-blocking read. Allocate a buffer to peek
  894. // the pipe, so that we can tell if a read operation will
  895. // block. This buffer is freed in
  896. // RestartPipeReadAndXPeek().
  897. //
  898. pipePeekBuffer = ALLOCATE_NONPAGED_POOL(
  899. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  900. BlockTypeDataBuffer
  901. );
  902. if ( pipePeekBuffer == NULL ) {
  903. //
  904. // Return to client with out of memory status.
  905. //
  906. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  907. status = STATUS_INSUFF_SERVER_RESOURCES;
  908. SmbStatus = SmbStatusSendResponse;
  909. goto Cleanup;
  910. }
  911. //
  912. // Save the address of the peek buffer so that the restart
  913. // routine can find it.
  914. //
  915. WorkContext->Parameters.ReadAndX.PipePeekBuffer = pipePeekBuffer;
  916. //
  917. // Build the pipe peek request. We just want the header
  918. // information. We do not need any data.
  919. //
  920. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  921. WorkContext->FspRestartRoutine = RestartPipeReadAndXPeek;
  922. SrvBuildIoControlRequest(
  923. WorkContext->Irp,
  924. lfcb->FileObject,
  925. WorkContext,
  926. IRP_MJ_FILE_SYSTEM_CONTROL,
  927. FSCTL_PIPE_PEEK,
  928. pipePeekBuffer,
  929. 0,
  930. NULL,
  931. FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[0] ),
  932. NULL,
  933. NULL
  934. );
  935. //
  936. // Pass the request to NPFS.
  937. //
  938. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  939. } else {
  940. //
  941. // This operation may block. If we are short of receive
  942. // work items, reject the request.
  943. //
  944. if ( SrvReceiveBufferShortage( ) ) {
  945. //
  946. // Fail the operation.
  947. //
  948. SrvStatistics.BlockingSmbsRejected++;
  949. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  950. status = STATUS_INSUFF_SERVER_RESOURCES;
  951. SmbStatus = SmbStatusSendResponse;
  952. goto Cleanup;
  953. } else {
  954. //
  955. // It is okay to start a blocking operation.
  956. // SrvReceiveBufferShortage() has already incremented
  957. // SrvBlockingOpsInProgress.
  958. //
  959. WorkContext->BlockingOperation = TRUE;
  960. //
  961. // Proceed with a potentially blocking read.
  962. //
  963. WorkContext->Parameters.ReadAndX.PipePeekBuffer = NULL;
  964. RestartPipeReadAndXPeek( WorkContext );
  965. }
  966. }
  967. } else {
  968. //
  969. // This is not a pipe read.
  970. //
  971. // Note that we never do MDL reads here. The reasoning behind
  972. // this is that because the read is going into an SMB buffer, it
  973. // can't be all that large (by default, no more than 4K bytes),
  974. // so the difference in cost between copy and MDL is minimal; in
  975. // fact, copy read is probably faster than MDL read.
  976. //
  977. // Build an MDL describing the read buffer. Note that if the
  978. // file system can complete the read immediately, the MDL isn't
  979. // really needed, but if the file system must send the request
  980. // to its FSP, the MDL _is_ needed.
  981. //
  982. // *** Note the assumption that the response buffer already has
  983. // a valid full MDL from which a partial MDL can be built.
  984. //
  985. IoBuildPartialMdl(
  986. WorkContext->ResponseBuffer->Mdl,
  987. WorkContext->ResponseBuffer->PartialMdl,
  988. readAddress,
  989. readLength
  990. );
  991. //
  992. // Build the IRP.
  993. //
  994. SrvBuildReadOrWriteRequest(
  995. WorkContext->Irp, // input IRP address
  996. lfcb->FileObject, // target file object address
  997. WorkContext, // context
  998. IRP_MJ_READ, // major function code
  999. 0, // minor function code
  1000. readAddress, // buffer address
  1001. readLength, // buffer length
  1002. WorkContext->ResponseBuffer->PartialMdl, // MDL address
  1003. offset, // byte offset
  1004. key // lock key
  1005. );
  1006. IF_SMB_DEBUG(READ_WRITE2) {
  1007. KdPrint(( "SrvSmbReadAndX: copy read from file 0x%p, offset %ld, length %ld, destination 0x%p\n",
  1008. lfcb->FileObject, offset.LowPart, readLength,
  1009. readAddress ));
  1010. }
  1011. //
  1012. // Pass the request to the file system. If the chained command
  1013. // is Close, we need to arrange to restart in the FSP after the
  1014. // read completes.
  1015. //
  1016. if ( WorkContext->NextCommand != SMB_COM_CLOSE ) {
  1017. WorkContext->bAlreadyTrace = TRUE;
  1018. WorkContext->FsdRestartRoutine = SrvFsdRestartReadAndX;
  1019. DEBUG WorkContext->FspRestartRoutine = NULL;
  1020. } else {
  1021. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1022. WorkContext->bAlreadyTrace = FALSE;
  1023. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndX;
  1024. }
  1025. #if SRVCATCH
  1026. if( rfcb->SrvCatch > 0 ) {
  1027. //
  1028. // Ensure passive level on restart
  1029. //
  1030. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1031. WorkContext->bAlreadyTrace = FALSE;
  1032. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndX;
  1033. }
  1034. #endif
  1035. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1036. //
  1037. // The read has been started. Control will return to the restart
  1038. // routine when the read completes.
  1039. //
  1040. }
  1041. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbReadAndX complete.\n" ));
  1042. SmbStatus = SmbStatusInProgress;
  1043. goto Cleanup;
  1044. }
  1045. //
  1046. // The client is doing a read from a disk file which exceeds our SMB buffer.
  1047. // We do our best to satisfy it.
  1048. //
  1049. // If we are unable to get buffers, we resort to doing a short read which fits
  1050. // in our smb buffer.
  1051. //
  1052. WorkContext->Parameters.ReadAndX.MdlRead = FALSE;
  1053. //
  1054. // Does the target file system support the cache manager routines?
  1055. //
  1056. if( lfcb->FileObject->Flags & FO_CACHE_SUPPORTED ) {
  1057. //
  1058. // We can use an MDL read. Try the fast I/O path first.
  1059. //
  1060. WorkContext->Irp->MdlAddress = NULL;
  1061. WorkContext->Irp->IoStatus.Information = 0;
  1062. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  1063. if( lfcb->MdlRead &&
  1064. lfcb->MdlRead(
  1065. lfcb->FileObject,
  1066. &offset,
  1067. readLength,
  1068. key,
  1069. &WorkContext->Irp->MdlAddress,
  1070. &WorkContext->Irp->IoStatus,
  1071. lfcb->DeviceObject
  1072. ) && WorkContext->Irp->MdlAddress != NULL ) {
  1073. //
  1074. // The fast I/O path worked. Send the data.
  1075. //
  1076. WorkContext->Parameters.ReadAndX.MdlRead = TRUE;
  1077. WorkContext->Parameters.ReadAndX.CacheMdl = WorkContext->Irp->MdlAddress;
  1078. WorkContext->bAlreadyTrace = TRUE;
  1079. SrvFsdRestartLargeReadAndX( WorkContext );
  1080. SmbStatus = SmbStatusInProgress;
  1081. goto Cleanup;
  1082. }
  1083. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  1084. if( WorkContext->Irp->MdlAddress ) {
  1085. //
  1086. // The fast I/O path failed. We need to issue a regular MDL read
  1087. // request.
  1088. //
  1089. // The fast path may have partially succeeded, returning a partial MDL
  1090. // chain. We need to adjust our read request to account for that.
  1091. //
  1092. offset.QuadPart += WorkContext->Irp->IoStatus.Information;
  1093. readLength -= (ULONG)WorkContext->Irp->IoStatus.Information;
  1094. mdl = WorkContext->Irp->MdlAddress;
  1095. WorkContext->Parameters.ReadAndX.CacheMdl = mdl;
  1096. readBuffer = NULL;
  1097. minorFunction = IRP_MN_MDL;
  1098. WorkContext->Parameters.ReadAndX.MdlRead = TRUE;
  1099. }
  1100. }
  1101. if( WorkContext->Parameters.ReadAndX.MdlRead == FALSE ) {
  1102. minorFunction = 0;
  1103. //
  1104. // We have to use a normal "copy" read. We need to allocate a
  1105. // separate buffer to hold the data, and we'll use the SMB buffer
  1106. // itself to hold the MDL
  1107. //
  1108. readBuffer = ALLOCATE_HEAP( readLength, BlockTypeLargeReadX );
  1109. if( readBuffer == NULL ) {
  1110. IF_DEBUG( ERRORS ) {
  1111. KdPrint(( "SrvSmbReadX: Unable to allocate large buffer\n" ));
  1112. }
  1113. //
  1114. // Trim back the read length so it will fit in the smb buffer and
  1115. // return as much data as we can.
  1116. //
  1117. readLength = MIN( readLength,
  1118. WorkContext->ResponseBuffer->BufferLength - bufferOffset
  1119. );
  1120. largeRead = FALSE;
  1121. goto small_read;
  1122. }
  1123. WorkContext->Parameters.ReadAndX.Buffer = readBuffer;
  1124. //
  1125. // Use the SMB buffer as the MDL to describe the just allocated read buffer.
  1126. // Lock the buffer into memory
  1127. //
  1128. mdl = (PMDL)(((ULONG_PTR)readAddress + sizeof(PVOID) - 1) & ~(sizeof(PVOID)-1));
  1129. MmInitializeMdl( mdl, readBuffer, readLength );
  1130. try {
  1131. MmProbeAndLockPages( mdl, KernelMode, IoWriteAccess );
  1132. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1133. IF_DEBUG( ERRORS ) {
  1134. KdPrint(( "SrvSmbReadX: MmProbeAndLockPages status %X\n", GetExceptionCode() ));
  1135. }
  1136. FREE_HEAP( readBuffer );
  1137. WorkContext->Parameters.ReadAndX.Buffer = NULL;
  1138. //
  1139. // Trim back the read length so it will fit in the smb buffer and
  1140. // return as much data as we can.
  1141. //
  1142. readLength = MIN( readLength,
  1143. WorkContext->ResponseBuffer->BufferLength - bufferOffset
  1144. );
  1145. largeRead = FALSE;
  1146. goto small_read;
  1147. }
  1148. if (MmGetSystemAddressForMdlSafe( mdl,NormalPoolPriority ) == NULL) {
  1149. // The mapping call has failed. fail the read operation with the
  1150. // appropriate error.
  1151. FREE_HEAP( readBuffer );
  1152. WorkContext->Parameters.ReadAndX.Buffer = NULL;
  1153. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  1154. status = STATUS_INSUFF_SERVER_RESOURCES;
  1155. SmbStatus = SmbStatusSendResponse;
  1156. goto Cleanup;
  1157. }
  1158. if( lfcb->FastIoRead != NULL ) {
  1159. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
  1160. try {
  1161. if ( lfcb->FastIoRead(
  1162. lfcb->FileObject,
  1163. &offset,
  1164. readLength,
  1165. TRUE,
  1166. key,
  1167. readBuffer,
  1168. &WorkContext->Irp->IoStatus,
  1169. lfcb->DeviceObject
  1170. ) ) {
  1171. //
  1172. // The fast I/O path worked. Send the data.
  1173. //
  1174. WorkContext->bAlreadyTrace = TRUE;
  1175. SrvFsdRestartLargeReadAndX( WorkContext );
  1176. SmbStatus = SmbStatusInProgress;
  1177. goto Cleanup;
  1178. }
  1179. }
  1180. except( EXCEPTION_EXECUTE_HANDLER ) {
  1181. // Fall through to the slow path on an exception
  1182. status = GetExceptionCode();
  1183. IF_DEBUG(ERRORS) {
  1184. KdPrint(("FastIoRead threw exception %x\n", status ));
  1185. }
  1186. }
  1187. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
  1188. }
  1189. }
  1190. //
  1191. // We didn't satisfy the request with the fast I/O path
  1192. //
  1193. SrvBuildReadOrWriteRequest(
  1194. WorkContext->Irp, // input IRP address
  1195. lfcb->FileObject, // target file object address
  1196. WorkContext, // context
  1197. IRP_MJ_READ, // major function code
  1198. minorFunction, // minor function code
  1199. readBuffer, // buffer address
  1200. readLength, // buffer length
  1201. mdl, // MDL address
  1202. offset, // byte offset
  1203. key // lock key
  1204. );
  1205. //
  1206. // Pass the request to the file system. We want to queue the
  1207. // response to the head because we've tied up a fair amount
  1208. // resources with this SMB.
  1209. //
  1210. WorkContext->QueueToHead = 1;
  1211. WorkContext->bAlreadyTrace = TRUE;
  1212. WorkContext->FsdRestartRoutine = SrvFsdRestartLargeReadAndX;
  1213. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1214. //
  1215. // The read has been started. When it completes, processing
  1216. // continues at SrvFsdRestartLargeReadAndX
  1217. //
  1218. SmbStatus = SmbStatusInProgress;
  1219. Cleanup:
  1220. SrvWmiEndContext(WorkContext);
  1221. return SmbStatus;
  1222. } // SrvSmbReadAndX
  1223. SMB_PROCESSOR_RETURN_TYPE
  1224. SrvSmbSeek (
  1225. SMB_PROCESSOR_PARAMETERS
  1226. )
  1227. /*++
  1228. Routine Description:
  1229. Processes the Seek SMB.
  1230. Arguments:
  1231. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  1232. of the parameters to SMB processor routines.
  1233. Return Value:
  1234. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  1235. --*/
  1236. {
  1237. PREQ_SEEK request;
  1238. PRESP_SEEK response;
  1239. NTSTATUS status = STATUS_SUCCESS;
  1240. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1241. PRFCB rfcb;
  1242. PLFCB lfcb;
  1243. LONG offset;
  1244. ULONG newPosition;
  1245. IO_STATUS_BLOCK iosb;
  1246. FILE_STANDARD_INFORMATION fileInformation;
  1247. BOOLEAN lockHeld = FALSE;
  1248. SMB_DIALECT smbDialect;
  1249. PFAST_IO_DISPATCH fastIoDispatch;
  1250. PAGED_CODE( );
  1251. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1252. WorkContext->PreviousSMB = EVENT_TYPE_SMB_SEEK;
  1253. SrvWmiStartContext(WorkContext);
  1254. request = (PREQ_SEEK)WorkContext->RequestParameters;
  1255. response = (PRESP_SEEK)WorkContext->ResponseParameters;
  1256. offset = (LONG)SmbGetUlong( &request->Offset );
  1257. IF_SMB_DEBUG(READ_WRITE1) {
  1258. KdPrint(( "Seek request; FID 0x%lx, mode %ld, offset %ld\n",
  1259. SmbGetUshort( &request->Fid ),
  1260. SmbGetUshort( &request->Mode ),
  1261. offset ));
  1262. }
  1263. //
  1264. // Verify the FID. If verified, the RFCB block is referenced
  1265. // and its addresses is stored in the WorkContext block, and the
  1266. // RFCB address is returned.
  1267. //
  1268. rfcb = SrvVerifyFid(
  1269. WorkContext,
  1270. SmbGetUshort( &request->Fid ),
  1271. TRUE,
  1272. SrvRestartSmbReceived, // serialize with raw write
  1273. &status
  1274. );
  1275. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1276. if ( !NT_SUCCESS(status) ) {
  1277. //
  1278. // Invalid file ID or write behind error. Reject the request.
  1279. //
  1280. IF_DEBUG(ERRORS) {
  1281. KdPrint((
  1282. "SrvSmbSeek: Status %X on FID: 0x%lx\n",
  1283. status,
  1284. SmbGetUshort( &request->Fid )
  1285. ));
  1286. }
  1287. SrvSetSmbError( WorkContext, status );
  1288. SmbStatus = SmbStatusSendResponse;
  1289. goto Cleanup;
  1290. }
  1291. //
  1292. // The work item has been queued because a raw write is in
  1293. // progress.
  1294. //
  1295. SmbStatus = SmbStatusInProgress;
  1296. goto Cleanup;
  1297. }
  1298. if( rfcb->Lfcb->Session->IsSessionExpired )
  1299. {
  1300. status = SESSION_EXPIRED_STATUS_CODE;
  1301. SrvSetSmbError( WorkContext, status );
  1302. SmbStatus = SmbStatusSendResponse;
  1303. goto Cleanup;
  1304. }
  1305. //
  1306. // We maintain our own file pointer, because the I/O and file system
  1307. // don't do it for us (at least not the way we need them to). This
  1308. // isn't all that bad, since the target file position is passed in
  1309. // all read/write SMBs. So we don't actually issue a system call to
  1310. // set the file position here, although we do have to return the
  1311. // position we would have set it to.
  1312. //
  1313. // The seek request is in one of three modes:
  1314. //
  1315. // 0 = seek relative to beginning of file
  1316. // 1 = seek relative to current file position
  1317. // 2 = seek relative to end of file
  1318. //
  1319. // For modes 0 and 1, we can easily calculate the final position.
  1320. // For mode 2, however, we have to issue a system call to obtain the
  1321. // current end of file and calculate the final position relative to
  1322. // that. Note that we can't just maintain our own end of file marker,
  1323. // because another local process could change it out from under us.
  1324. //
  1325. // !!! Need to check for wraparound (either positive or negative).
  1326. //
  1327. switch ( SmbGetUshort( &request->Mode ) ) {
  1328. case 0:
  1329. //
  1330. // Seek relative to beginning of file. The new file position
  1331. // is simply that specified in the request. Note that this
  1332. // may be beyond the actual end of the file. This is OK.
  1333. // Negative seeks must be handled specially.
  1334. //
  1335. newPosition = offset;
  1336. if ( !SetNewPosition( rfcb, &newPosition, FALSE ) ) {
  1337. goto negative_seek;
  1338. }
  1339. break;
  1340. case 1:
  1341. //
  1342. // Seek relative to current position. The new file position is
  1343. // the current position plus the specified offset (which may be
  1344. // negative). Note that this may be beyond the actual end of
  1345. // the file. This is OK. Negative seeks must be handled
  1346. // specially.
  1347. //
  1348. newPosition = offset;
  1349. if ( !SetNewPosition( rfcb, &newPosition, TRUE ) ) {
  1350. goto negative_seek;
  1351. }
  1352. break;
  1353. case 2:
  1354. //
  1355. // Seek relative to end of file. The new file position
  1356. // is the current end of file plus the specified offset.
  1357. //
  1358. IF_SMB_DEBUG(READ_WRITE2) {
  1359. KdPrint(( "SrvSmbSeek: Querying end-of-file\n" ));
  1360. }
  1361. lfcb = rfcb->Lfcb;
  1362. fastIoDispatch = lfcb->DeviceObject->DriverObject->FastIoDispatch;
  1363. if ( fastIoDispatch &&
  1364. fastIoDispatch->FastIoQueryStandardInfo &&
  1365. fastIoDispatch->FastIoQueryStandardInfo(
  1366. lfcb->FileObject,
  1367. TRUE,
  1368. &fileInformation,
  1369. &iosb,
  1370. lfcb->DeviceObject
  1371. ) ) {
  1372. status = iosb.Status;
  1373. } else {
  1374. status = NtQueryInformationFile(
  1375. lfcb->FileHandle,
  1376. &iosb,
  1377. &fileInformation,
  1378. sizeof(fileInformation),
  1379. FileStandardInformation
  1380. );
  1381. }
  1382. if ( !NT_SUCCESS(status) ) {
  1383. INTERNAL_ERROR(
  1384. ERROR_LEVEL_UNEXPECTED,
  1385. "SrvSmbSeek: QueryInformationFile (file information) "
  1386. "returned %X",
  1387. status,
  1388. NULL
  1389. );
  1390. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  1391. SrvSetSmbError( WorkContext, status );
  1392. SmbStatus = SmbStatusSendResponse;
  1393. goto Cleanup;
  1394. }
  1395. if ( fileInformation.EndOfFile.HighPart != 0 ) {
  1396. INTERNAL_ERROR(
  1397. ERROR_LEVEL_UNEXPECTED,
  1398. "SrvSmbSeek: EndOfFile is beyond where client can read",
  1399. NULL,
  1400. NULL
  1401. );
  1402. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, STATUS_END_OF_FILE);
  1403. SrvSetSmbError( WorkContext, STATUS_END_OF_FILE);
  1404. status = STATUS_END_OF_FILE;
  1405. SmbStatus = SmbStatusSendResponse;
  1406. goto Cleanup;
  1407. }
  1408. newPosition = fileInformation.EndOfFile.LowPart + offset;
  1409. if ( !SetNewPosition( rfcb, &newPosition, FALSE ) ) {
  1410. goto negative_seek;
  1411. }
  1412. break;
  1413. default:
  1414. //
  1415. // Invalid seek mode. Reject the request.
  1416. //
  1417. IF_DEBUG(SMB_ERRORS) {
  1418. KdPrint(( "SrvSmbSeek: Invalid mode: 0x%lx\n",
  1419. SmbGetUshort( &request->Mode ) ));
  1420. }
  1421. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  1422. status = STATUS_INVALID_PARAMETER;
  1423. SmbStatus = SmbStatusSendResponse;
  1424. goto Cleanup;
  1425. } // switch ( request->Mode )
  1426. //
  1427. // Return the new file position in the response SMB.
  1428. //
  1429. // *** Note the assumption that the high part of the 64-bit EOF
  1430. // marker is zero. If it's not (i.e., the file is bigger than
  1431. // 4GB), then we're out of luck, because the SMB protocol can't
  1432. // express that.
  1433. //
  1434. IF_SMB_DEBUG(READ_WRITE2) {
  1435. KdPrint(( "SrvSmbSeek: New file position %ld\n", newPosition ));
  1436. }
  1437. response->WordCount = 2;
  1438. SmbPutUlong( &response->Offset, newPosition );
  1439. SmbPutUshort( &response->ByteCount, 0 );
  1440. WorkContext->ResponseParameters = NEXT_LOCATION( response, RESP_SEEK, 0 );
  1441. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbSeek complete\n" ));
  1442. SmbStatus = SmbStatusSendResponse;
  1443. goto Cleanup;
  1444. negative_seek:
  1445. //
  1446. // The client specified an absolute or relative seek that pointed
  1447. // before the beginning of the file. For some clients, this is not
  1448. // an error, and results in positioning at the BOF. Non-NT LAN Man
  1449. // clients can request a negative seek on a named-pipe and expect
  1450. // the operation to succeed.
  1451. //
  1452. smbDialect = rfcb->Connection->SmbDialect;
  1453. if( smbDialect >= SmbDialectLanMan20 ||
  1454. ( !IS_NT_DIALECT( smbDialect ) && rfcb->ShareType == ShareTypePipe )) {
  1455. //
  1456. // Negative seeks allowed for these fellows!
  1457. // Seek to the beginning of the file
  1458. //
  1459. newPosition = 0;
  1460. SetNewPosition( rfcb, &newPosition, FALSE );
  1461. IF_SMB_DEBUG(READ_WRITE2) {
  1462. KdPrint(( "SrvSmbSeek: New file position: 0\n" ));
  1463. }
  1464. response->WordCount = 2;
  1465. SmbPutUlong( &response->Offset, 0 );
  1466. SmbPutUshort( &response->ByteCount, 0 );
  1467. WorkContext->ResponseParameters = NEXT_LOCATION( response, RESP_SEEK, 0 );
  1468. } else {
  1469. //
  1470. // Negative seeks are not allowed!
  1471. //
  1472. IF_DEBUG(SMB_ERRORS) {
  1473. KdPrint(( "SrvSmbSeek: Negative seek\n" ));
  1474. }
  1475. SrvSetSmbError( WorkContext, STATUS_OS2_NEGATIVE_SEEK );
  1476. status = STATUS_OS2_NEGATIVE_SEEK;
  1477. }
  1478. SmbStatus = SmbStatusSendResponse;
  1479. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbSeek complete\n" ));
  1480. Cleanup:
  1481. SrvWmiEndContext(WorkContext);
  1482. return SmbStatus;
  1483. } // SrvSmbSeek
  1484. SMB_PROCESSOR_RETURN_TYPE
  1485. SrvSmbWrite (
  1486. SMB_PROCESSOR_PARAMETERS
  1487. )
  1488. /*++
  1489. Routine Description:
  1490. Processes the Write, Write and Close, and Write and Unlock, and
  1491. Write Print File SMBs.
  1492. Arguments:
  1493. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  1494. of the parameters to SMB processor routines.
  1495. Return Value:
  1496. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  1497. --*/
  1498. {
  1499. PREQ_WRITE request;
  1500. PRESP_WRITE response;
  1501. NTSTATUS status = STATUS_SUCCESS;
  1502. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1503. USHORT fid;
  1504. PRFCB rfcb;
  1505. PLFCB lfcb;
  1506. PCHAR writeAddress;
  1507. CLONG writeLength;
  1508. LARGE_INTEGER offset;
  1509. ULONG key;
  1510. SHARE_TYPE shareType;
  1511. PAGED_CODE( );
  1512. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1513. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE;
  1514. SrvWmiStartContext(WorkContext);
  1515. request = (PREQ_WRITE)WorkContext->RequestParameters;
  1516. response = (PRESP_WRITE)WorkContext->ResponseParameters;
  1517. fid = SmbGetUshort( &request->Fid );
  1518. IF_SMB_DEBUG(READ_WRITE1) {
  1519. KdPrint(( "Write%s request; FID 0x%lx, count %ld, offset %ld\n",
  1520. WorkContext->NextCommand == SMB_COM_WRITE_AND_UNLOCK ?
  1521. " and Unlock" :
  1522. WorkContext->NextCommand == SMB_COM_WRITE_AND_CLOSE ?
  1523. " and Close" : "",
  1524. fid, SmbGetUshort( &request->Count ),
  1525. SmbGetUlong( &request->Offset ) ));
  1526. }
  1527. //
  1528. // First, verify the FID. If verified, the RFCB is referenced and
  1529. // its address is stored in the WorkContext block, and the RFCB
  1530. // address is returned.
  1531. //
  1532. // Call SrvVerifyFid, but do not fail (return NULL) if there is
  1533. // a saved write behind error for this rfcb. We need the rfcb
  1534. // in case this is a write and close SMB, in order to process
  1535. // the close.
  1536. //
  1537. rfcb = SrvVerifyFid(
  1538. WorkContext,
  1539. fid,
  1540. FALSE,
  1541. SrvRestartSmbReceived, // serialize with raw write
  1542. &status
  1543. );
  1544. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1545. if ( !NT_SUCCESS( status ) ) {
  1546. //
  1547. // Invalid file ID. Reject the request.
  1548. //
  1549. IF_DEBUG(SMB_ERRORS) {
  1550. KdPrint(("SrvSmbWrite: Invalid FID: 0x%lx\n", fid ));
  1551. }
  1552. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  1553. status = STATUS_INVALID_HANDLE;
  1554. SmbStatus = SmbStatusSendResponse;
  1555. goto Cleanup;
  1556. }
  1557. //
  1558. // The work item has been queued because a raw write is in
  1559. // progress.
  1560. //
  1561. SmbStatus = SmbStatusInProgress;
  1562. goto Cleanup;
  1563. } else if ( !NT_SUCCESS( rfcb->SavedError ) ) {
  1564. NTSTATUS savedErrorStatus;
  1565. //
  1566. // Check the saved error.
  1567. //
  1568. savedErrorStatus = SrvCheckForSavedError( WorkContext, rfcb );
  1569. //
  1570. // See if the saved error was still there.
  1571. //
  1572. if ( !NT_SUCCESS( savedErrorStatus ) ) {
  1573. //
  1574. // There was a write behind error.
  1575. //
  1576. //
  1577. // Do not update the file timestamp.
  1578. //
  1579. WorkContext->Parameters.LastWriteTime = 0;
  1580. //
  1581. // If this is not a Write and Close, we can send the
  1582. // response now. If it is a Write and Close, we need to
  1583. // close the file first.
  1584. //
  1585. if ( WorkContext->NextCommand != SMB_COM_WRITE_AND_CLOSE ) {
  1586. //
  1587. // Not Write and Close. Just send the response.
  1588. //
  1589. status = savedErrorStatus;
  1590. SmbStatus = SmbStatusSendResponse;
  1591. goto Cleanup;
  1592. }
  1593. //
  1594. // This is a Write and Close.
  1595. //
  1596. SrvRestartChainedClose( WorkContext );
  1597. SmbStatus = SmbStatusInProgress;
  1598. goto Cleanup;
  1599. }
  1600. }
  1601. lfcb = rfcb->Lfcb;
  1602. //
  1603. // If the session has expired, return that info
  1604. //
  1605. if( lfcb->Session->IsSessionExpired )
  1606. {
  1607. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  1608. status = SESSION_EXPIRED_STATUS_CODE;
  1609. SmbStatus = SmbStatusSendResponse;
  1610. goto Cleanup;
  1611. }
  1612. //
  1613. // Verify that the client has write access to the file via the
  1614. // specified handle.
  1615. //
  1616. if ( !rfcb->WriteAccessGranted && !rfcb->AppendAccessGranted ) {
  1617. SrvStatistics.GrantedAccessErrors++;
  1618. IF_DEBUG(ERRORS) {
  1619. KdPrint(( "SrvSmbWrite: Write access not granted.\n"));
  1620. }
  1621. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  1622. status = STATUS_ACCESS_DENIED;
  1623. SmbStatus = SmbStatusSendResponse;
  1624. goto Cleanup;
  1625. }
  1626. //
  1627. // If the write length is zero, truncate the file at the specified
  1628. // offset.
  1629. //
  1630. if ( (SmbGetUshort( &request->Count ) == 0) && (rfcb->GrantedAccess & FILE_WRITE_DATA) ) {
  1631. SetNewSize( WorkContext );
  1632. SmbStatus = SmbStatusInProgress;
  1633. goto Cleanup;
  1634. }
  1635. rfcb->WrittenTo = TRUE;
  1636. //
  1637. // Get the file share type.
  1638. //
  1639. shareType = rfcb->ShareType;
  1640. //
  1641. // If this operation may block, and we are running short of free
  1642. // work items, fail this SMB with an out of resources error.
  1643. //
  1644. if ( rfcb->BlockingModePipe ) {
  1645. if ( SrvReceiveBufferShortage( ) ) {
  1646. //
  1647. // Fail the operation.
  1648. //
  1649. SrvStatistics.BlockingSmbsRejected++;
  1650. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  1651. status = STATUS_INSUFF_SERVER_RESOURCES;
  1652. SmbStatus = SmbStatusSendResponse;
  1653. goto Cleanup;
  1654. } else {
  1655. //
  1656. // It is okay to start a blocking operation.
  1657. // SrvReceiveBufferShortage() has already incremented
  1658. // SrvBlockingOpsInProgress.
  1659. //
  1660. WorkContext->BlockingOperation = TRUE;
  1661. }
  1662. }
  1663. //
  1664. // *** If the Remaining field of the request is ever used, make sure
  1665. // that this is not a write and close SMB, which does not
  1666. // include a valid Remaining field.
  1667. //
  1668. //
  1669. // Determine the amount of data to write. This is the minimum of
  1670. // the amount requested by the client and the amount of data
  1671. // actually sent in the request buffer.
  1672. //
  1673. // !!! Should it be an error for the client to send less data than
  1674. // it actually wants us to write? The OS/2 server seems not to
  1675. // reject such requests.
  1676. //
  1677. if ( WorkContext->NextCommand != SMB_COM_WRITE_PRINT_FILE ) {
  1678. if ( WorkContext->NextCommand != SMB_COM_WRITE_AND_CLOSE ) {
  1679. writeAddress = (PCHAR)request->Buffer;
  1680. } else {
  1681. //
  1682. // Look at the WordCount field -- it should be 6 or 12.
  1683. // From this we can calculate the writeAddress.
  1684. //
  1685. if ( request->WordCount == 6 ) {
  1686. writeAddress =
  1687. (PCHAR)((PREQ_WRITE_AND_CLOSE)request)->Buffer;
  1688. } else if ( request->WordCount == 12 ) {
  1689. writeAddress =
  1690. (PCHAR)((PREQ_WRITE_AND_CLOSE_LONG)request)->Buffer;
  1691. } else {
  1692. //
  1693. // An illegal WordCount value was passed. Return an error
  1694. // to the client.
  1695. //
  1696. IF_DEBUG(SMB_ERRORS) {
  1697. KdPrint(( "SrvSmbWrite: Bad WordCount for "
  1698. "WriteAndClose: %ld, should be 6 or 12\n",
  1699. request->WordCount ));
  1700. }
  1701. SrvLogInvalidSmb( WorkContext );
  1702. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1703. status = STATUS_INVALID_SMB;
  1704. SmbStatus = SmbStatusSendResponse;
  1705. goto Cleanup;
  1706. }
  1707. }
  1708. writeLength = MIN(
  1709. (CLONG)SmbGetUshort( &request->Count ),
  1710. WorkContext->ResponseBuffer->DataLength -
  1711. PTR_DIFF(writeAddress, WorkContext->RequestHeader)
  1712. );
  1713. offset.QuadPart = SmbGetUlong( &request->Offset );
  1714. } else {
  1715. writeAddress = (PCHAR)( ((PREQ_WRITE_PRINT_FILE)request)->Buffer ) + 3;
  1716. writeLength =
  1717. MIN(
  1718. (CLONG)SmbGetUshort(
  1719. &((PREQ_WRITE_PRINT_FILE)request)->ByteCount ) - 3,
  1720. WorkContext->ResponseBuffer->DataLength -
  1721. PTR_DIFF(writeAddress, WorkContext->RequestHeader)
  1722. );
  1723. offset.QuadPart = rfcb->CurrentPosition;
  1724. }
  1725. //
  1726. // Ensure that the client is writing beyond the original file size
  1727. //
  1728. if( !rfcb->WriteAccessGranted &&
  1729. offset.QuadPart < rfcb->Mfcb->NonpagedMfcb->OpenFileSize.QuadPart ) {
  1730. //
  1731. // The client is only allowed to append to this file!
  1732. //
  1733. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  1734. status = STATUS_ACCESS_DENIED;
  1735. SmbStatus = SmbStatusSendResponse;
  1736. goto Cleanup;
  1737. }
  1738. //
  1739. // Form the lock key using the FID and the PID.
  1740. //
  1741. // *** The FID must be included in the key in order to account for
  1742. // the folding of multiple remote compatibility mode opens into
  1743. // a single local open.
  1744. //
  1745. key = rfcb->ShiftedFid |
  1746. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  1747. //
  1748. // Try the fast I/O path first. If that fails, fall through to the
  1749. // normal build-an-IRP path.
  1750. //
  1751. if ( lfcb->FastIoWrite != NULL ) {
  1752. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  1753. try {
  1754. if ( lfcb->FastIoWrite(
  1755. lfcb->FileObject,
  1756. &offset,
  1757. writeLength,
  1758. TRUE,
  1759. key,
  1760. writeAddress,
  1761. &WorkContext->Irp->IoStatus,
  1762. lfcb->DeviceObject
  1763. ) ) {
  1764. //
  1765. // The fast I/O path worked. Call the restart routine directly
  1766. // to do postprocessing (including sending the response).
  1767. //
  1768. WorkContext->bAlreadyTrace = TRUE;
  1769. SrvFsdRestartWrite( WorkContext );
  1770. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbWrite complete.\n" ));
  1771. SmbStatus = SmbStatusInProgress;
  1772. goto Cleanup;
  1773. }
  1774. }
  1775. except( EXCEPTION_EXECUTE_HANDLER ) {
  1776. // Fall through to the slow path on an exception
  1777. status = GetExceptionCode();
  1778. IF_DEBUG(ERRORS) {
  1779. KdPrint(("FastIoRead threw exception %x\n", status ));
  1780. }
  1781. }
  1782. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  1783. }
  1784. //
  1785. // The turbo path failed. Build the write request, reusing the
  1786. // receive IRP.
  1787. //
  1788. if (shareType != ShareTypePipe) {
  1789. //
  1790. // Build an MDL describing the write buffer. Note that if the
  1791. // file system can complete the write immediately, the MDL isn't
  1792. // really needed, but if the file system must send the request
  1793. // to its FSP, the MDL _is_ needed.
  1794. //
  1795. // *** Note the assumption that the request buffer already has a
  1796. // valid full MDL from which a partial MDL can be built.
  1797. //
  1798. IoBuildPartialMdl(
  1799. WorkContext->RequestBuffer->Mdl,
  1800. WorkContext->RequestBuffer->PartialMdl,
  1801. writeAddress,
  1802. writeLength
  1803. );
  1804. //
  1805. // Build the IRP.
  1806. //
  1807. SrvBuildReadOrWriteRequest(
  1808. WorkContext->Irp, // input IRP address
  1809. lfcb->FileObject, // target file object address
  1810. WorkContext, // context
  1811. IRP_MJ_WRITE, // major function code
  1812. 0, // minor function code
  1813. writeAddress, // buffer address
  1814. writeLength, // buffer length
  1815. WorkContext->RequestBuffer->PartialMdl, // MDL address
  1816. offset, // byte offset
  1817. key // lock key
  1818. );
  1819. IF_SMB_DEBUG(READ_WRITE2) {
  1820. KdPrint(( "SrvSmbWrite: writing to file 0x%p, offset %ld, length %ld, source 0x%p\n",
  1821. lfcb->FileObject, offset.LowPart, writeLength,
  1822. writeAddress ));
  1823. }
  1824. } else {
  1825. //
  1826. // Build the PIPE_INTERNAL_WRITE IRP.
  1827. //
  1828. SrvBuildIoControlRequest(
  1829. WorkContext->Irp,
  1830. lfcb->FileObject,
  1831. WorkContext,
  1832. IRP_MJ_FILE_SYSTEM_CONTROL,
  1833. FSCTL_PIPE_INTERNAL_WRITE,
  1834. writeAddress,
  1835. writeLength,
  1836. NULL,
  1837. 0,
  1838. NULL,
  1839. NULL
  1840. );
  1841. IF_SMB_DEBUG(READ_WRITE2) {
  1842. KdPrint(( "SrvSmbWrite: writing to file 0x%p length %ld, destination 0x%p\n",
  1843. lfcb->FileObject, writeLength,
  1844. writeAddress ));
  1845. }
  1846. }
  1847. //
  1848. // Pass the request to the file system. If this is a write and
  1849. // close, we have to restart in the FSP because the restart routine
  1850. // will free the MFCB stored in paged pool. Similarly, if this is a
  1851. // write and unlock, we have to restart in the FSP to do the unlock.
  1852. //
  1853. if ( (WorkContext->RequestHeader->Command == SMB_COM_WRITE_AND_CLOSE) ||
  1854. (WorkContext->RequestHeader->Command == SMB_COM_WRITE_AND_UNLOCK) ) {
  1855. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1856. WorkContext->bAlreadyTrace = FALSE;
  1857. WorkContext->FspRestartRoutine = SrvFsdRestartWrite;
  1858. } else {
  1859. WorkContext->bAlreadyTrace = TRUE;
  1860. WorkContext->FsdRestartRoutine = SrvFsdRestartWrite;
  1861. DEBUG WorkContext->FspRestartRoutine = NULL;
  1862. }
  1863. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1864. //
  1865. // The write has been started. Control will return to
  1866. // SrvFsdRestartWrite when the write completes.
  1867. //
  1868. SmbStatus = SmbStatusInProgress;
  1869. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbWrite complete.\n" ));
  1870. Cleanup:
  1871. SrvWmiEndContext(WorkContext);
  1872. return SmbStatus;
  1873. } // SrvSmbWrite
  1874. SMB_PROCESSOR_RETURN_TYPE
  1875. SrvSmbWriteAndX (
  1876. SMB_PROCESSOR_PARAMETERS
  1877. )
  1878. /*++
  1879. Routine Description:
  1880. Processes the Write And X SMB.
  1881. Arguments:
  1882. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  1883. of the parameters to SMB processor routines.
  1884. Return Value:
  1885. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  1886. --*/
  1887. {
  1888. PSMB_HEADER header;
  1889. PREQ_WRITE_ANDX request;
  1890. PREQ_NT_WRITE_ANDX ntRequest;
  1891. PRESP_WRITE_ANDX response;
  1892. PCONNECTION connection;
  1893. NTSTATUS status = STATUS_SUCCESS;
  1894. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1895. USHORT fid;
  1896. PRFCB rfcb;
  1897. PLFCB lfcb;
  1898. CLONG bufferOffset;
  1899. PCHAR writeAddress;
  1900. CLONG writeLength;
  1901. LARGE_INTEGER offset;
  1902. ULONG key;
  1903. SHARE_TYPE shareType;
  1904. BOOLEAN writeThrough;
  1905. ULONG remainingBytes;
  1906. ULONG totalLength;
  1907. SMB_DIALECT smbDialect;
  1908. PTRANSACTION transaction;
  1909. PCHAR trailingBytes;
  1910. USHORT flags2;
  1911. PAGED_CODE( );
  1912. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1913. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_AND_X;
  1914. //SrvReferenceWorkItem(WorkContext);
  1915. SrvWmiStartContext(WorkContext);
  1916. header = (PSMB_HEADER)WorkContext->RequestHeader;
  1917. request = (PREQ_WRITE_ANDX)WorkContext->RequestParameters;
  1918. ntRequest = (PREQ_NT_WRITE_ANDX)WorkContext->RequestParameters;
  1919. response = (PRESP_WRITE_ANDX)WorkContext->ResponseParameters;
  1920. //
  1921. // Initialize the transaction pointer.
  1922. //
  1923. WorkContext->Parameters.Transaction = NULL;
  1924. //
  1925. // If this WriteAndX is actually a psuedo WriteBlockMultiplex, all
  1926. // of the WriteAndX pieces must be assembled before submitting the
  1927. // request to NPFS. (This exists to support large message mode
  1928. // writes to clients that can't do WriteBlockMultiplex.)
  1929. //
  1930. // This must be handled in the FSP.
  1931. //
  1932. fid = SmbGetUshort( &request->Fid );
  1933. IF_SMB_DEBUG(READ_WRITE1) {
  1934. KdPrint(( "WriteAndX request; FID 0x%lx, count %ld, offset %ld\n",
  1935. fid, SmbGetUshort( &request->DataLength ),
  1936. SmbGetUlong( &request->Offset ) ));
  1937. }
  1938. rfcb = SrvVerifyFid(
  1939. WorkContext,
  1940. fid,
  1941. TRUE,
  1942. SrvRestartSmbReceived, // serialize with raw write
  1943. &status
  1944. );
  1945. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  1946. if ( !NT_SUCCESS( status ) ) {
  1947. //
  1948. // Invalid file ID or write behind error. Reject the request.
  1949. //
  1950. IF_DEBUG(ERRORS) {
  1951. KdPrint((
  1952. "SrvSmbWriteAndX: status %X on FID: 0x%lx\n",
  1953. status,
  1954. fid
  1955. ));
  1956. }
  1957. SrvSetSmbError( WorkContext, status );
  1958. SmbStatus = SrvConsumeSmbData( WorkContext );
  1959. goto Cleanup;
  1960. }
  1961. //
  1962. // The work item has been queued because a raw write is in
  1963. // progress.
  1964. //
  1965. SmbStatus = SmbStatusInProgress;
  1966. goto Cleanup;
  1967. }
  1968. //
  1969. // Get the LFCB and the file share type.
  1970. //
  1971. lfcb = rfcb->Lfcb;
  1972. shareType = rfcb->ShareType;
  1973. //
  1974. // If the session has expired, return that info
  1975. //
  1976. if( lfcb->Session->IsSessionExpired )
  1977. {
  1978. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  1979. status = SESSION_EXPIRED_STATUS_CODE;
  1980. SmbStatus = SrvConsumeSmbData( WorkContext );
  1981. goto Cleanup;
  1982. }
  1983. if( WorkContext->LargeIndication && shareType != ShareTypeDisk ) {
  1984. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1985. status = STATUS_INVALID_SMB;
  1986. //
  1987. // We need to consume the rest of this SMB!
  1988. //
  1989. SmbStatus = SrvConsumeSmbData( WorkContext );
  1990. goto Cleanup;
  1991. }
  1992. //
  1993. // Verify that the client has write access to the file via the
  1994. // specified handle.
  1995. //
  1996. if ( !rfcb->WriteAccessGranted && !rfcb->AppendAccessGranted ) {
  1997. SrvStatistics.GrantedAccessErrors++;
  1998. IF_DEBUG(ERRORS) {
  1999. KdPrint(( "SrvSmbWriteAndX: Write access not granted.\n"));
  2000. }
  2001. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  2002. status = STATUS_ACCESS_DENIED;
  2003. SmbStatus = SrvConsumeSmbData( WorkContext );
  2004. goto Cleanup;
  2005. }
  2006. rfcb->WrittenTo = TRUE;
  2007. flags2 = SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 );
  2008. //
  2009. // Ensure the correct write through mode
  2010. //
  2011. if ( shareType == ShareTypeDisk ) {
  2012. writeThrough = (BOOLEAN)((SmbGetUshort( &request->WriteMode ) &
  2013. SMB_WMODE_WRITE_THROUGH) != 0);
  2014. if ( writeThrough && (lfcb->FileMode & FILE_WRITE_THROUGH) == 0
  2015. || !writeThrough && (lfcb->FileMode & FILE_WRITE_THROUGH) != 0 ) {
  2016. SrvSetFileWritethroughMode( lfcb, writeThrough );
  2017. }
  2018. RtlZeroMemory( &WorkContext->Parameters.WriteAndX,
  2019. sizeof( WorkContext->Parameters.WriteAndX) );
  2020. } else if ( rfcb->BlockingModePipe ) {
  2021. //
  2022. // If this operation may block, and we are running short of free
  2023. // work items, fail this SMB with an out of resources error.
  2024. //
  2025. if ( SrvReceiveBufferShortage( ) ) {
  2026. //
  2027. // Fail the operation.
  2028. //
  2029. SrvStatistics.BlockingSmbsRejected++;
  2030. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  2031. status = STATUS_INSUFF_SERVER_RESOURCES;
  2032. SmbStatus = SrvConsumeSmbData( WorkContext );
  2033. goto Cleanup;
  2034. } else {
  2035. //
  2036. // SrvBlockingOpsInProgress has already been incremented.
  2037. // Flag this work item as a blocking operation.
  2038. //
  2039. WorkContext->BlockingOperation = TRUE;
  2040. }
  2041. }
  2042. //
  2043. // Determine the amount of data to write. This is the minimum of
  2044. // the amount requested by the client and the amount of data
  2045. // actually sent in the request buffer.
  2046. //
  2047. // !!! Should it be an error for the client to send less data than
  2048. // it actually wants us to write? The OS/2 server seems not to
  2049. // reject such requests.
  2050. //
  2051. bufferOffset = SmbGetUshort( &request->DataOffset );
  2052. writeAddress = (PCHAR)WorkContext->ResponseHeader + bufferOffset;
  2053. writeLength = MIN(
  2054. (CLONG)SmbGetUshort( &request->DataLength ),
  2055. WorkContext->ResponseBuffer->DataLength - bufferOffset
  2056. );
  2057. remainingBytes = SmbGetUshort( &request->Remaining );
  2058. //
  2059. // Form the lock key using the FID and the PID.
  2060. //
  2061. // *** The FID must be included in the key in order to account for
  2062. // the folding of multiple remote compatibility mode opens into
  2063. // a single local open.
  2064. //
  2065. key = rfcb->ShiftedFid |
  2066. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  2067. flags2 = SmbGetAlignedUshort( &WorkContext->RequestHeader->Flags2 );
  2068. //
  2069. // Get the file offset.
  2070. //
  2071. if ( shareType != ShareTypePipe ) {
  2072. if ( request->WordCount == 12 ) {
  2073. //
  2074. // The client has supplied a 32 bit file offset.
  2075. //
  2076. offset.QuadPart = SmbGetUlong( &request->Offset );
  2077. } else if ( request->WordCount == 14 ) {
  2078. //
  2079. // The client has supplied a 64 bit file offset. This must be an
  2080. // uplevel NT-like client
  2081. //
  2082. offset.LowPart = SmbGetUlong( &ntRequest->Offset );
  2083. offset.HighPart = SmbGetUlong( &ntRequest->OffsetHigh );
  2084. //
  2085. // Reject negative offsets
  2086. //
  2087. if ( offset.QuadPart < 0 && offset.QuadPart != 0xFFFFFFFFFFFFFFFF ) {
  2088. IF_DEBUG(ERRORS) {
  2089. KdPrint(( "SrvSmbWriteAndX: Negative offset rejected.\n"));
  2090. }
  2091. SrvLogInvalidSmb( WorkContext );
  2092. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2093. status = STATUS_INVALID_SMB;
  2094. SmbStatus = SrvConsumeSmbData( WorkContext );
  2095. goto Cleanup;
  2096. }
  2097. } else {
  2098. //
  2099. // Invalid word count.
  2100. //
  2101. SrvLogInvalidSmb( WorkContext );
  2102. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2103. status = STATUS_INVALID_SMB;
  2104. SmbStatus = SrvConsumeSmbData( WorkContext );
  2105. goto Cleanup;
  2106. }
  2107. //
  2108. // If the client can only append, ensure that the client is writing
  2109. // beyond the original EOF
  2110. //
  2111. if( !rfcb->WriteAccessGranted &&
  2112. offset.QuadPart < rfcb->Mfcb->NonpagedMfcb->OpenFileSize.QuadPart ) {
  2113. //
  2114. // The client is only allowed to append to this file!
  2115. //
  2116. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  2117. status = STATUS_ACCESS_DENIED;
  2118. SmbStatus = SrvConsumeSmbData( WorkContext );
  2119. goto Cleanup;
  2120. }
  2121. //
  2122. // Gather up parameters for large writes
  2123. //
  2124. if( WorkContext->LargeIndication ) {
  2125. //
  2126. // There can be no follow-on command, and we can not be using security signatures
  2127. //
  2128. if( request->WordCount != 14 ||
  2129. WorkContext->Connection->SmbSecuritySignatureActive == TRUE ||
  2130. request->AndXCommand != SMB_COM_NO_ANDX_COMMAND ) {
  2131. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2132. status = STATUS_INVALID_SMB;
  2133. SmbStatus = SrvConsumeSmbData( WorkContext );
  2134. goto Cleanup;
  2135. }
  2136. WorkContext->Parameters.WriteAndX.RemainingWriteLength =
  2137. (ULONG)SmbGetUshort( &ntRequest->DataLengthHigh ) << 16;
  2138. WorkContext->Parameters.WriteAndX.RemainingWriteLength +=
  2139. (ULONG)SmbGetUshort( &ntRequest->DataLength );
  2140. WorkContext->Parameters.WriteAndX.CurrentWriteLength = MIN(
  2141. WorkContext->Parameters.WriteAndX.RemainingWriteLength,
  2142. WorkContext->ResponseBuffer->DataLength - bufferOffset );
  2143. writeLength = WorkContext->Parameters.WriteAndX.CurrentWriteLength;
  2144. WorkContext->Parameters.WriteAndX.RemainingWriteLength -= writeLength;
  2145. WorkContext->Parameters.WriteAndX.WriteAddress = writeAddress;
  2146. WorkContext->Parameters.WriteAndX.BufferLength = writeLength;
  2147. WorkContext->Parameters.WriteAndX.Key = key;
  2148. WorkContext->Parameters.WriteAndX.Offset = offset;
  2149. //
  2150. // If the data should have fit within the original SMB buffer, then
  2151. // this is an error
  2152. //
  2153. if( WorkContext->Parameters.WriteAndX.RemainingWriteLength == 0 ) {
  2154. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2155. status = STATUS_INVALID_SMB;
  2156. SmbStatus = SrvConsumeSmbData( WorkContext );
  2157. goto Cleanup;
  2158. }
  2159. }
  2160. } else {
  2161. if ( (request->WordCount != 12) && (request->WordCount != 14) ) {
  2162. //
  2163. // Invalid word count.
  2164. //
  2165. SrvLogInvalidSmb( WorkContext );
  2166. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2167. status = STATUS_INVALID_SMB;
  2168. SmbStatus = SmbStatusSendResponse;
  2169. goto Cleanup;
  2170. }
  2171. //
  2172. // Is this a multipiece named pipe write?
  2173. //
  2174. connection = WorkContext->Connection;
  2175. if ( (SmbGetUshort( &request->WriteMode ) &
  2176. SMB_WMODE_WRITE_RAW_NAMED_PIPE) != 0 ) {
  2177. //
  2178. // This is a multipiece named pipe write, is this the first
  2179. // piece?
  2180. //
  2181. if ( (SmbGetUshort( &request->WriteMode ) &
  2182. SMB_WMODE_START_OF_MESSAGE) != 0 ) {
  2183. //
  2184. // This is the first piece of a multipart WriteAndX SMB.
  2185. // Allocate a buffer large enough to hold all of the data.
  2186. //
  2187. // The first two bytes of the data part of the SMB are the
  2188. // named pipe message header, which we ignore. Adjust for
  2189. // that.
  2190. //
  2191. //
  2192. // Ensure that enough bytes are available
  2193. //
  2194. if( writeLength < 2 ) {
  2195. SrvLogInvalidSmb( WorkContext );
  2196. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2197. status = STATUS_INVALID_SMB;
  2198. SmbStatus = SmbStatusSendResponse;
  2199. goto Cleanup;
  2200. }
  2201. writeAddress += 2;
  2202. writeLength -= 2;
  2203. // If this is an OS/2 client, add the current write to the
  2204. // remainingBytes count. This is a bug in the OS/2 rdr.
  2205. //
  2206. smbDialect = connection->SmbDialect;
  2207. if ( smbDialect == SmbDialectLanMan21 ||
  2208. smbDialect == SmbDialectLanMan20 ||
  2209. smbDialect == SmbDialectLanMan10 ) {
  2210. //
  2211. // Ignore the 1st 2 bytes of the message as they are the
  2212. // OS/2 message header.
  2213. //
  2214. totalLength = writeLength + remainingBytes;
  2215. } else {
  2216. if( writeLength > remainingBytes ) {
  2217. // This is an invalid SMB, they are trying to overrun the buffer
  2218. SrvLogInvalidSmb( WorkContext );
  2219. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2220. return SmbStatusSendResponse;
  2221. }
  2222. totalLength = remainingBytes;
  2223. }
  2224. SrvAllocateTransaction(
  2225. &transaction,
  2226. (PVOID *)&trailingBytes,
  2227. connection,
  2228. totalLength,
  2229. #if DBG
  2230. StrWriteAndX, // Transaction name
  2231. #else
  2232. StrNull,
  2233. #endif
  2234. NULL,
  2235. TRUE, // Source name is Unicode
  2236. FALSE // Not a remote API
  2237. );
  2238. if ( transaction == NULL ) {
  2239. //
  2240. // Could not allocate a large enough buffer.
  2241. //
  2242. IF_DEBUG(ERRORS) {
  2243. KdPrint(( "Unable to allocate transaction\n" ));
  2244. }
  2245. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  2246. status = STATUS_INSUFF_SERVER_RESOURCES;
  2247. SmbStatus = SmbStatusSendResponse;
  2248. goto Cleanup;
  2249. } else {
  2250. //
  2251. // Successfully allocated a transaction block.
  2252. //
  2253. // Save the TID, PID, UID, and MID from this request in
  2254. // the transaction block. These values are used to
  2255. // relate secondary requests to the appropriate primary
  2256. // request.
  2257. //
  2258. transaction->Tid = SmbGetAlignedUshort( &header->Tid );
  2259. transaction->Pid = SmbGetAlignedUshort( &header->Pid );
  2260. transaction->Uid = SmbGetAlignedUshort( &header->Uid );
  2261. transaction->OtherInfo = fid;
  2262. //
  2263. // Remember the total size of the buffer and the number
  2264. // of bytes received so far.
  2265. //
  2266. transaction->DataCount = writeLength;
  2267. transaction->TotalDataCount = totalLength;
  2268. transaction->InData = trailingBytes + writeLength;
  2269. transaction->OutData = trailingBytes;
  2270. transaction->Connection = connection;
  2271. SrvReferenceConnection( connection );
  2272. transaction->Session = lfcb->Session;
  2273. SrvReferenceSession( transaction->Session );
  2274. transaction->TreeConnect = lfcb->TreeConnect;
  2275. SrvReferenceTreeConnect( transaction->TreeConnect );
  2276. //
  2277. // Copy the data out of the SMB buffer.
  2278. //
  2279. RtlCopyMemory(
  2280. trailingBytes,
  2281. writeAddress,
  2282. writeLength
  2283. );
  2284. //
  2285. // Increase the write length again, so as not to confuse
  2286. // the redirector.
  2287. //
  2288. writeLength += 2;
  2289. //
  2290. // Link the transaction block into the connection's
  2291. // pending transaction list. This will fail if there is
  2292. // already a tranaction with the same xID values in the
  2293. // list.
  2294. //
  2295. if ( !SrvInsertTransaction( transaction ) ) {
  2296. //
  2297. // A transaction with the same xIDs is already in
  2298. // progress. Return an error to the client.
  2299. //
  2300. // *** Note that SrvDereferenceTransaction can't be
  2301. // used here because that routine assumes that
  2302. // the transaction is queued to the transaction
  2303. // list.
  2304. //
  2305. SrvDereferenceTreeConnect( transaction->TreeConnect );
  2306. SrvDereferenceSession( transaction->Session );
  2307. SrvFreeTransaction( transaction );
  2308. SrvDereferenceConnection( connection );
  2309. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2310. status = STATUS_INVALID_SMB;
  2311. SmbStatus = SmbStatusSendResponse;
  2312. goto Cleanup;
  2313. }
  2314. } // else ( transaction sucessfully allocated )
  2315. } else { // This is a secondary piece to a multi-part message
  2316. transaction = SrvFindTransaction(
  2317. connection,
  2318. header,
  2319. fid
  2320. );
  2321. if ( transaction == NULL ) {
  2322. //
  2323. // Unable to find a matching transaction.
  2324. //
  2325. IF_DEBUG(ERRORS) {
  2326. KdPrint(( "Cannot find initial write request for "
  2327. "WriteAndX SMB\n"));
  2328. }
  2329. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2330. status = STATUS_INVALID_SMB;
  2331. SmbStatus = SmbStatusSendResponse;
  2332. goto Cleanup;
  2333. }
  2334. //
  2335. // Make sure there is enough space left in the transaction
  2336. // buffer for the data that we have received.
  2337. //
  2338. if ( transaction->TotalDataCount - transaction->DataCount
  2339. < writeLength ) {
  2340. //
  2341. // Too much data. Throw out the entire buffer and
  2342. // reject this write request.
  2343. //
  2344. SrvCloseTransaction( transaction );
  2345. SrvDereferenceTransaction( transaction );
  2346. SrvSetSmbError( WorkContext, STATUS_BUFFER_OVERFLOW );
  2347. status = STATUS_BUFFER_OVERFLOW;
  2348. SmbStatus = SmbStatusSendResponse;
  2349. goto Cleanup;
  2350. }
  2351. RtlCopyMemory(transaction->InData, writeAddress, writeLength );
  2352. //
  2353. // Update the transaction data pointer to where the next
  2354. // WriteAndX data buffer will go.
  2355. //
  2356. transaction->InData += writeLength;
  2357. transaction->DataCount += writeLength;
  2358. } // secondary piece of multipart write
  2359. if ( transaction->DataCount < transaction->TotalDataCount ) {
  2360. //
  2361. // We don't have all of the data yet.
  2362. //
  2363. PRESP_WRITE_ANDX writeResponse;
  2364. UCHAR nextCommand;
  2365. //
  2366. // SrvAllocateTransaction or SrvFindTransaction referenced
  2367. // the transaction, so dereference it.
  2368. //
  2369. SrvDereferenceTransaction( transaction );
  2370. //
  2371. // Send an interim response.
  2372. //
  2373. ASSERT( request->AndXCommand == SMB_COM_NO_ANDX_COMMAND );
  2374. writeResponse = (PRESP_WRITE_ANDX)WorkContext->ResponseParameters;
  2375. nextCommand = request->AndXCommand;
  2376. //
  2377. // Build the response message.
  2378. //
  2379. writeResponse->AndXCommand = nextCommand;
  2380. writeResponse->AndXReserved = 0;
  2381. SmbPutUshort(
  2382. &writeResponse->AndXOffset,
  2383. GET_ANDX_OFFSET(
  2384. WorkContext->ResponseHeader,
  2385. WorkContext->ResponseParameters,
  2386. RESP_WRITE_ANDX,
  2387. 0
  2388. )
  2389. );
  2390. writeResponse->WordCount = 6;
  2391. SmbPutUshort( &writeResponse->Count, (USHORT)writeLength );
  2392. SmbPutUshort( &writeResponse->Remaining, (USHORT)-1 );
  2393. SmbPutUlong( &writeResponse->Reserved, 0 );
  2394. SmbPutUshort( &writeResponse->ByteCount, 0 );
  2395. WorkContext->ResponseParameters =
  2396. (PCHAR)WorkContext->ResponseHeader +
  2397. SmbGetUshort( &writeResponse->AndXOffset );
  2398. SmbStatus = SmbStatusSendResponse;
  2399. goto Cleanup;
  2400. }
  2401. //
  2402. // We have all of the data. Set up to write it.
  2403. //
  2404. writeAddress = transaction->OutData;
  2405. writeLength = PTR_DIFF(transaction->InData, transaction->OutData);
  2406. //
  2407. // Save a pointer to the transaction block so that it can be
  2408. // freed when the write completes.
  2409. //
  2410. // *** Note that we retain the reference to the transaction that
  2411. // was set by SrvAllocateTransaction or added by
  2412. // SrvFindTransaction.
  2413. //
  2414. WorkContext->Parameters.Transaction = transaction;
  2415. //
  2416. // Fall through to issue the I/O request.
  2417. //
  2418. } // "raw mode" write?
  2419. }
  2420. //
  2421. // Try the fast I/O path first. If that fails, fall through to the
  2422. // normal build-an-IRP path.
  2423. //
  2424. if ( lfcb->FastIoWrite != NULL ) {
  2425. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
  2426. try {
  2427. if ( lfcb->FastIoWrite(
  2428. lfcb->FileObject,
  2429. &offset,
  2430. writeLength,
  2431. TRUE,
  2432. key,
  2433. writeAddress,
  2434. &WorkContext->Irp->IoStatus,
  2435. lfcb->DeviceObject
  2436. ) ) {
  2437. IF_SYSCACHE_RFCB( rfcb ) {
  2438. KdPrint(( "FastIoWrite Rfcb %p Length %x Offset %x succeeded\n", rfcb, writeLength, offset.u.LowPart ));
  2439. }
  2440. //
  2441. // The fast I/O path worked. Call the restart routine directly
  2442. // to do postprocessing (including sending the response).
  2443. //
  2444. WorkContext->bAlreadyTrace = TRUE;
  2445. SrvFsdRestartWriteAndX( WorkContext );
  2446. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbWriteAndX complete.\n" ));
  2447. SmbStatus = SmbStatusInProgress;
  2448. goto Cleanup;
  2449. }
  2450. else
  2451. {
  2452. IF_SYSCACHE_RFCB( rfcb ) {
  2453. KdPrint(( "FastIoWrite Rfcb %p Length %x Offset %x failed status %x\n", rfcb, writeLength, offset.u.LowPart, WorkContext->Irp->IoStatus.Status ));
  2454. }
  2455. }
  2456. }
  2457. except( EXCEPTION_EXECUTE_HANDLER ) {
  2458. // Fall through to the slow path on an exception
  2459. status = GetExceptionCode();
  2460. IF_DEBUG(ERRORS) {
  2461. KdPrint(("FastIoRead threw exception %x\n", status ));
  2462. }
  2463. IF_SYSCACHE_RFCB( rfcb ) {
  2464. KdPrint(( "FastIoWrite Rfcb %p Length %x Offset %x threw exception\n", rfcb, writeLength, offset.u.LowPart ));
  2465. }
  2466. }
  2467. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
  2468. }
  2469. //
  2470. // The turbo path failed. Build the write request, reusing the
  2471. // receive IRP.
  2472. //
  2473. if ( shareType != ShareTypePipe ) {
  2474. //
  2475. // Build an MDL describing the write buffer. Note that if the
  2476. // file system can complete the write immediately, the MDL isn't
  2477. // really needed, but if the file system must send the request
  2478. // to its FSP, the MDL _is_ needed.
  2479. //
  2480. // *** Note the assumption that the request buffer already has a
  2481. // valid full MDL from which a partial MDL can be built.
  2482. //
  2483. IoBuildPartialMdl(
  2484. WorkContext->RequestBuffer->Mdl,
  2485. WorkContext->RequestBuffer->PartialMdl,
  2486. writeAddress,
  2487. writeLength
  2488. );
  2489. //
  2490. // Build the IRP.
  2491. //
  2492. SrvBuildReadOrWriteRequest(
  2493. WorkContext->Irp, // input IRP address
  2494. lfcb->FileObject, // target file object address
  2495. WorkContext, // context
  2496. IRP_MJ_WRITE, // major function code
  2497. 0, // minor function code
  2498. writeAddress, // buffer address
  2499. writeLength, // buffer length
  2500. WorkContext->RequestBuffer->PartialMdl, // MDL address
  2501. offset, // byte offset
  2502. key // lock key
  2503. );
  2504. IF_SMB_DEBUG(READ_WRITE2) {
  2505. KdPrint(( "SrvSmbWriteAndX: writing to file 0x%p, offset %ld, length %ld, source 0x%p\n",
  2506. lfcb->FileObject, offset.LowPart, writeLength,
  2507. writeAddress ));
  2508. }
  2509. } else {
  2510. //
  2511. // Build the PIPE_INTERNAL_WRITE IRP.
  2512. //
  2513. SrvBuildIoControlRequest(
  2514. WorkContext->Irp,
  2515. lfcb->FileObject,
  2516. WorkContext,
  2517. IRP_MJ_FILE_SYSTEM_CONTROL,
  2518. FSCTL_PIPE_INTERNAL_WRITE,
  2519. writeAddress,
  2520. writeLength,
  2521. NULL,
  2522. 0,
  2523. NULL,
  2524. NULL
  2525. );
  2526. IF_SMB_DEBUG(READ_WRITE2) {
  2527. KdPrint(( "SrvSmbWriteAndX: writing to file 0x%p length %ld, destination 0x%p\n",
  2528. lfcb->FileObject, writeLength,
  2529. writeAddress ));
  2530. }
  2531. }
  2532. //
  2533. // Pass the request to the file system. If the chained command is
  2534. // Close, we need to arrange to restart in the FSP after the write
  2535. // completes.
  2536. //
  2537. // If we have a LargeIndication, we may want to do some cache
  2538. // operations in the restart routine. For this, we must be at passive
  2539. // level.
  2540. //
  2541. if ( WorkContext->LargeIndication == FALSE
  2542. && request->AndXCommand != SMB_COM_CLOSE ) {
  2543. IF_SYSCACHE_RFCB( rfcb )
  2544. {
  2545. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2546. WorkContext->bAlreadyTrace = FALSE;
  2547. WorkContext->FspRestartRoutine = SrvFsdRestartWriteAndX;
  2548. }
  2549. else
  2550. {
  2551. WorkContext->bAlreadyTrace = TRUE;
  2552. WorkContext->FsdRestartRoutine = SrvFsdRestartWriteAndX;
  2553. DEBUG WorkContext->FspRestartRoutine = NULL;
  2554. }
  2555. } else {
  2556. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2557. WorkContext->bAlreadyTrace = FALSE;
  2558. WorkContext->FspRestartRoutine = SrvFsdRestartWriteAndX;
  2559. }
  2560. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  2561. //
  2562. // The write has been started. Control will return to
  2563. // SrvFsdRestartWriteAndX when the write completes.
  2564. //
  2565. SmbStatus = SmbStatusInProgress;
  2566. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "SrvSmbWriteAndX complete.\n" ));
  2567. Cleanup:
  2568. SrvWmiEndContext(WorkContext);
  2569. //SrvDereferenceWorkItem(WorkContext);
  2570. return SmbStatus;
  2571. } // SrvSmbWriteAndX
  2572. VOID SRVFASTCALL
  2573. SrvRestartChainedClose (
  2574. IN OUT PWORK_CONTEXT WorkContext
  2575. )
  2576. /*++
  2577. Routine Description:
  2578. This is the restart routine invoked after before the response to a
  2579. WriteAndClose, or a ReadAndX or a WriteAndX when the chained command
  2580. is Close. This routine closes the file, then sends the response.
  2581. This operation cannot be done in the FSD. Closing a file
  2582. dereferences a number of blocks that are in the FSP address space.
  2583. Arguments:
  2584. WorkContext - Supplies a pointer to the work context block
  2585. representing the work item. The response parameters must be
  2586. fully set up.
  2587. Return Value:
  2588. None.
  2589. --*/
  2590. {
  2591. PRFCB rfcb = WorkContext->Rfcb;
  2592. PRESP_CLOSE closeResponse = WorkContext->ResponseParameters;
  2593. PAGED_CODE( );
  2594. //
  2595. // Set the file last write time.
  2596. //
  2597. if ( rfcb->WriteAccessGranted || rfcb->AppendAccessGranted ) {
  2598. (VOID)SrvSetLastWriteTime(
  2599. rfcb,
  2600. WorkContext->Parameters.LastWriteTime,
  2601. rfcb->Lfcb->GrantedAccess
  2602. );
  2603. }
  2604. //
  2605. // Close the file.
  2606. //
  2607. IF_SMB_DEBUG(READ_WRITE2) {
  2608. KdPrint(( "SrvRestartChainedClose: closing RFCB 0x%p\n", WorkContext->Rfcb ));
  2609. }
  2610. SrvCloseRfcb( WorkContext->Rfcb );
  2611. //
  2612. // Dereference the RFCB immediately, rather than waiting for normal
  2613. // work context cleanup after the response send completes. This
  2614. // gets the xFCB structures cleaned up in a more timely manner.
  2615. //
  2616. // *** The specific motivation for this change was to fix a problem
  2617. // where a compatibility mode open was closed, the response was
  2618. // sent, and a Delete SMB was received before the send
  2619. // completion was processed. This resulted in the MFCB and LFCB
  2620. // still being present, which caused the delete processing to
  2621. // try to use the file handle in the LFCB, which we just closed
  2622. // here.
  2623. //
  2624. SrvDereferenceRfcb( WorkContext->Rfcb );
  2625. WorkContext->Rfcb = NULL;
  2626. //
  2627. // Build the response parameters.
  2628. //
  2629. closeResponse->WordCount = 0;
  2630. SmbPutUshort( &closeResponse->ByteCount, 0 );
  2631. WorkContext->ResponseParameters = NEXT_LOCATION( closeResponse, RESP_CLOSE, 0 );
  2632. //
  2633. // Send the response.
  2634. //
  2635. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  2636. return;
  2637. } // SrvRestartChainedClose
  2638. VOID SRVFASTCALL
  2639. RestartLockAndRead (
  2640. IN OUT PWORK_CONTEXT WorkContext
  2641. )
  2642. /*++
  2643. Routine Description:
  2644. Processes file lock completion for a Lock and Read SMB.
  2645. Arguments:
  2646. WorkContext - Supplies a pointer to the work context block
  2647. describing server-specific context for the request.
  2648. Return Value:
  2649. None.
  2650. --*/
  2651. {
  2652. PREQ_READ request;
  2653. LARGE_INTEGER offset;
  2654. NTSTATUS status = STATUS_SUCCESS;
  2655. SMB_STATUS smbStatus = SmbStatusInProgress;
  2656. PSRV_TIMER timer;
  2657. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  2658. PAGED_CODE( );
  2659. if (bNeedTrace) {
  2660. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  2661. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOCK_AND_READ;
  2662. SrvWmiStartContext(WorkContext);
  2663. }
  2664. else
  2665. WorkContext->bAlreadyTrace = FALSE;
  2666. IF_DEBUG(WORKER1) KdPrint(( " - RestartLockAndRead\n" ));
  2667. //
  2668. // If this request was being timed, cancel the timer.
  2669. //
  2670. timer = WorkContext->Parameters.Lock.Timer;
  2671. if ( timer != NULL ) {
  2672. SrvCancelTimer( timer );
  2673. SrvFreeTimer( timer );
  2674. }
  2675. //
  2676. // If the lock request failed, set an error status in the response
  2677. // header.
  2678. //
  2679. status = WorkContext->Irp->IoStatus.Status;
  2680. if ( !NT_SUCCESS(status) ) {
  2681. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.LockViolations );
  2682. IF_DEBUG(ERRORS) KdPrint(( "Lock failed: %X\n", status ));
  2683. //
  2684. // Store the failing lock offset.
  2685. //
  2686. request = (PREQ_READ)WorkContext->RequestParameters;
  2687. offset.QuadPart = SmbGetUlong( &request->Offset );
  2688. WorkContext->Rfcb->PagedRfcb->LastFailingLockOffset = offset;
  2689. //
  2690. // Send back the bad news.
  2691. //
  2692. if ( status == STATUS_CANCELLED ) {
  2693. status = STATUS_FILE_LOCK_CONFLICT;
  2694. }
  2695. SrvSetSmbError( WorkContext, status );
  2696. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  2697. IF_DEBUG(TRACE2) KdPrint(( "RestartLockAndRead complete\n" ));
  2698. goto Cleanup;
  2699. }
  2700. //
  2701. // The lock request completed successfully.
  2702. //
  2703. InterlockedIncrement(
  2704. &WorkContext->Rfcb->NumberOfLocks
  2705. );
  2706. //
  2707. // Start the read to complete the LockAndRead.
  2708. //
  2709. smbStatus = SrvSmbRead( WorkContext );
  2710. if ( smbStatus != SmbStatusInProgress ) {
  2711. SrvEndSmbProcessing( WorkContext, smbStatus );
  2712. }
  2713. Cleanup:
  2714. if (bNeedTrace) {
  2715. SrvWmiEndContext(WorkContext);
  2716. }
  2717. return;
  2718. } // RestartLockAndRead
  2719. VOID SRVFASTCALL
  2720. RestartPipeReadAndXPeek(
  2721. IN OUT PWORK_CONTEXT WorkContext
  2722. )
  2723. /*++
  2724. Routine Description:
  2725. This function continues a read and X on a named pipe handle. It can
  2726. be called as a restart routine if a peek is preformed, but can also
  2727. be called directly from SrvSmbReadAndX if it is not necessary to
  2728. peek the pipe before reading from it.
  2729. Arguments:
  2730. WorkContext - Supplies a pointer to the work context block
  2731. representing the work item.
  2732. Return Value:
  2733. None.
  2734. --*/
  2735. {
  2736. NTSTATUS status;
  2737. PLFCB lfcb;
  2738. PIRP irp = WorkContext->Irp;
  2739. PIO_STACK_LOCATION irpSp;
  2740. PDEVICE_OBJECT deviceObject;
  2741. PAGED_CODE( );
  2742. lfcb = WorkContext->Rfcb->Lfcb;
  2743. if ( WorkContext->Parameters.ReadAndX.PipePeekBuffer != NULL ) {
  2744. //
  2745. // Non-blocking read. We have issued a pipe peek; free the peek
  2746. // buffer.
  2747. //
  2748. DEALLOCATE_NONPAGED_POOL(
  2749. WorkContext->Parameters.ReadAndX.PipePeekBuffer
  2750. );
  2751. //
  2752. // Now see if there is data to read.
  2753. //
  2754. status = irp->IoStatus.Status;
  2755. if ( NT_SUCCESS(status) ) {
  2756. //
  2757. // There is no data in the pipe. Fail the read.
  2758. //
  2759. SrvSetSmbError( WorkContext, STATUS_PIPE_EMPTY );
  2760. SrvFsdSendResponse( WorkContext );
  2761. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "RestartPipeReadAndXPeek complete.\n" ));
  2762. return;
  2763. } else if ( status != STATUS_BUFFER_OVERFLOW ) {
  2764. //
  2765. // An error occurred. Return the status to the caller.
  2766. //
  2767. SrvSetSmbError( WorkContext, status );
  2768. SrvFsdSendResponse( WorkContext );
  2769. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "RestartPipeReadAndXPeek complete.\n" ));
  2770. return;
  2771. }
  2772. //
  2773. // There is data in pipe; proceed with read.
  2774. //
  2775. }
  2776. //
  2777. // in line internal read
  2778. //
  2779. deviceObject = lfcb->DeviceObject;
  2780. irp->Tail.Overlay.OriginalFileObject = lfcb->FileObject;
  2781. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  2782. DEBUG irp->RequestorMode = KernelMode;
  2783. //
  2784. // Get a pointer to the next stack location. This one is used to
  2785. // hold the parameters for the device I/O control request.
  2786. //
  2787. irpSp = IoGetNextIrpStackLocation( irp );
  2788. //
  2789. // Set up the completion routine.
  2790. //
  2791. IoSetCompletionRoutine(
  2792. irp,
  2793. SrvFsdIoCompletionRoutine,
  2794. WorkContext,
  2795. TRUE,
  2796. TRUE,
  2797. TRUE
  2798. );
  2799. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL,
  2800. irpSp->MinorFunction = 0;
  2801. irpSp->FileObject = lfcb->FileObject;
  2802. irpSp->DeviceObject = deviceObject;
  2803. //
  2804. // Copy the caller's parameters to the service-specific portion of the
  2805. // IRP for those parameters that are the same for all three methods.
  2806. //
  2807. irpSp->Parameters.FileSystemControl.OutputBufferLength =
  2808. WorkContext->Parameters.ReadAndX.ReadLength;
  2809. irpSp->Parameters.FileSystemControl.InputBufferLength = 0;
  2810. irpSp->Parameters.FileSystemControl.FsControlCode = FSCTL_PIPE_INTERNAL_READ;
  2811. irp->MdlAddress = NULL;
  2812. irp->AssociatedIrp.SystemBuffer =
  2813. WorkContext->Parameters.ReadAndX.ReadAddress,
  2814. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2815. //
  2816. // end in-line
  2817. //
  2818. //
  2819. // Pass the request to the file system. If the chained command is
  2820. // Close, we need to arrange to restart in the FSP after the read
  2821. // completes.
  2822. //
  2823. if ( WorkContext->NextCommand != SMB_COM_CLOSE ) {
  2824. WorkContext->bAlreadyTrace = TRUE;
  2825. WorkContext->FsdRestartRoutine = SrvFsdRestartReadAndX;
  2826. DEBUG WorkContext->FspRestartRoutine = NULL;
  2827. } else {
  2828. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2829. WorkContext->bAlreadyTrace = FALSE;
  2830. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndX;
  2831. }
  2832. IF_SMB_DEBUG(READ_WRITE2) {
  2833. KdPrint(( "RestartPipeReadAndXPeek: reading from file 0x%p, length %ld, destination 0x%p\n",
  2834. lfcb->FileObject,
  2835. WorkContext->Parameters.ReadAndX.ReadLength,
  2836. WorkContext->Parameters.ReadAndX.ReadAddress
  2837. ));
  2838. }
  2839. (VOID)IoCallDriver( deviceObject, WorkContext->Irp );
  2840. //
  2841. // The read has been started. Control will return to the restart
  2842. // routine when the read completes.
  2843. //
  2844. IF_SMB_DEBUG(READ_WRITE2) KdPrint(( "RestartPipeReadAndXPeek complete.\n" ));
  2845. return;
  2846. } // RestartPipeReadAndXPeek
  2847. VOID SRVFASTCALL
  2848. SrvRestartWriteAndUnlock (
  2849. IN OUT PWORK_CONTEXT WorkContext
  2850. )
  2851. /*++
  2852. Routine Description:
  2853. This restart routine is used when the Write part of a Write and
  2854. Unlock SMB completes successfully. (Note that the range remains
  2855. locked if the write fails.) This routine handles the Unlock part of
  2856. the request.
  2857. Arguments:
  2858. WorkContext - Supplies a pointer to the work context block
  2859. describing server-specific context for the request.
  2860. Return Value:
  2861. None.
  2862. --*/
  2863. {
  2864. PREQ_WRITE request;
  2865. PRESP_WRITE response;
  2866. NTSTATUS status;
  2867. PRFCB rfcb;
  2868. PLFCB lfcb;
  2869. LARGE_INTEGER length;
  2870. LARGE_INTEGER offset;
  2871. ULONG key;
  2872. PAGED_CODE( );
  2873. IF_DEBUG(WORKER1) KdPrint(( " - SrvRestartWriteAndUnlock\n" ));
  2874. //
  2875. // Get the request and response parameter pointers.
  2876. //
  2877. request = (PREQ_WRITE)WorkContext->RequestParameters;
  2878. response = (PRESP_WRITE)WorkContext->ResponseParameters;
  2879. //
  2880. // Get the file pointer.
  2881. //
  2882. rfcb = WorkContext->Rfcb;
  2883. IF_DEBUG(TRACE2) {
  2884. KdPrint(( " connection 0x%p, RFCB 0x%p\n",
  2885. WorkContext->Connection, rfcb ));
  2886. }
  2887. lfcb = rfcb->Lfcb;
  2888. //
  2889. // Get the offset and length of the range being unlocked.
  2890. // Combine the FID with the caller's PID to form the local
  2891. // lock key.
  2892. //
  2893. // *** The FID must be included in the key in order to
  2894. // account for the folding of multiple remote
  2895. // compatibility mode opens into a single local open.
  2896. //
  2897. offset.QuadPart = SmbGetUlong( &request->Offset );
  2898. length.QuadPart = SmbGetUshort( &request->Count );
  2899. key = rfcb->ShiftedFid |
  2900. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  2901. //
  2902. // Verify that the client has unlock access to the file via
  2903. // the specified handle.
  2904. //
  2905. if ( rfcb->UnlockAccessGranted ) {
  2906. //
  2907. // Issue the Unlock request.
  2908. //
  2909. // *** Note that we do the Unlock synchronously. Unlock is a
  2910. // quick operation, so there's no point in doing it
  2911. // asynchronously. In order to do this, we have to let
  2912. // normal I/O completion happen (so the event is set), which
  2913. // means that we have to allocate a new IRP (I/O completion
  2914. // likes to deallocate an IRP). This is a little wasteful,
  2915. // since we've got a perfectly good IRP hanging around.
  2916. //
  2917. IF_SMB_DEBUG(READ_WRITE2) {
  2918. KdPrint(( "SrvRestartWriteAndUnlock: Unlocking in file 0x%p: (%ld,%ld), key 0x%lx\n", lfcb->FileObject,
  2919. offset.LowPart, length.LowPart, key ));
  2920. }
  2921. status = SrvIssueUnlockRequest(
  2922. lfcb->FileObject, // target file object
  2923. &lfcb->DeviceObject, // target device object
  2924. IRP_MN_UNLOCK_SINGLE, // unlock operation
  2925. offset, // byte offset
  2926. length, // range length
  2927. key // lock key
  2928. );
  2929. //
  2930. // If the unlock request failed, set an error status in
  2931. // the response header. Otherwise, build a success response.
  2932. //
  2933. if ( !NT_SUCCESS(status) ) {
  2934. IF_DEBUG(ERRORS) {
  2935. KdPrint(( "SrvRestartWriteAndUnlock: Unlock failed: %X\n",
  2936. status ));
  2937. }
  2938. SrvSetSmbError( WorkContext, status );
  2939. } else {
  2940. response->WordCount = 1;
  2941. SmbPutUshort( &response->Count, (USHORT)length.LowPart );
  2942. SmbPutUshort( &response->ByteCount, 0 );
  2943. WorkContext->ResponseParameters =
  2944. NEXT_LOCATION( response, RESP_WRITE, 0 );
  2945. }
  2946. } else {
  2947. SrvStatistics.GrantedAccessErrors++;
  2948. IF_DEBUG(ERRORS) {
  2949. KdPrint(( "SrvRestartWriteAndUnlock: Unlock access not granted.\n"));
  2950. }
  2951. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  2952. }
  2953. //
  2954. // Processing of the SMB is complete. Call SrvEndSmbProcessing
  2955. // to send the response.
  2956. //
  2957. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  2958. IF_DEBUG(TRACE2) KdPrint(( "RestartWrite complete\n" ));
  2959. return;
  2960. } // SrvRestartWriteAndUnlock
  2961. VOID SRVFASTCALL
  2962. SrvRestartWriteAndXRaw (
  2963. IN PWORK_CONTEXT WorkContext
  2964. )
  2965. /*++
  2966. Routine Description:
  2967. This function completes processing of a WriteAndX raw protocol.
  2968. The work context block already points to the correct response. All
  2969. that is left to do is free the transaction block, and dispatch the
  2970. And-X command, or send the response.
  2971. Arguments:
  2972. WorkContext - A pointer to a set of
  2973. Return Value:
  2974. None.
  2975. --*/
  2976. {
  2977. PTRANSACTION transaction;
  2978. PAGED_CODE( );
  2979. transaction = WorkContext->Parameters.Transaction;
  2980. ASSERT( transaction != NULL );
  2981. ASSERT( GET_BLOCK_TYPE( transaction ) == BlockTypeTransaction );
  2982. SrvCloseTransaction( transaction );
  2983. SrvDereferenceTransaction( transaction );
  2984. //
  2985. // Test for a legal followon command, and dispatch as appropriate.
  2986. // Close and CloseAndTreeDisconnect are handled specially.
  2987. //
  2988. switch ( WorkContext->NextCommand ) {
  2989. case SMB_COM_NO_ANDX_COMMAND:
  2990. //
  2991. // No more commands. Send the response.
  2992. //
  2993. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  2994. break;
  2995. case SMB_COM_READ:
  2996. case SMB_COM_READ_ANDX:
  2997. case SMB_COM_LOCK_AND_READ:
  2998. //
  2999. // Redispatch the SMB for more processing.
  3000. //
  3001. SrvProcessSmb( WorkContext );
  3002. break;
  3003. case SMB_COM_CLOSE:
  3004. //case SMB_COM_CLOSE_AND_TREE_DISC: // Bogus SMB
  3005. //
  3006. // Call SrvRestartChainedClose to get the file time set and the
  3007. // file closed.
  3008. //
  3009. WorkContext->Parameters.LastWriteTime =
  3010. ((PREQ_CLOSE)WorkContext->RequestParameters)->LastWriteTimeInSeconds;
  3011. SrvRestartChainedClose( WorkContext );
  3012. break;
  3013. default: // Illegal followon command
  3014. IF_DEBUG(SMB_ERRORS) {
  3015. KdPrint(( "SrvRestartWriteAndXRaw: Illegal followon "
  3016. "command: 0x%lx\n", WorkContext->NextCommand ));
  3017. }
  3018. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  3019. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  3020. }
  3021. IF_DEBUG(TRACE2) KdPrint(( "SrvRestartWriteAndXRaw complete\n" ));
  3022. return;
  3023. } // SrvRestartWriteAndXRaw
  3024. VOID SRVFASTCALL
  3025. SetNewSize (
  3026. IN OUT PWORK_CONTEXT WorkContext
  3027. )
  3028. /*++
  3029. Routine Description:
  3030. Processes the Write SMB when Count == 0. Sets the size of the
  3031. target file to the specified Offset.
  3032. Arguments:
  3033. WorkContext - Supplies a pointer to the work context block
  3034. describing server-specific context for the request.
  3035. Return Value:
  3036. None.
  3037. --*/
  3038. {
  3039. PREQ_WRITE request;
  3040. PRESP_WRITE response;
  3041. NTSTATUS status;
  3042. IO_STATUS_BLOCK ioStatusBlock;
  3043. ACCESS_MASK grantedAccess;
  3044. PLFCB lfcb;
  3045. FILE_END_OF_FILE_INFORMATION newEndOfFile;
  3046. FILE_ALLOCATION_INFORMATION newAllocation;
  3047. PAGED_CODE( );
  3048. IF_DEBUG(TRACE2) KdPrint(( "SetNewSize entered\n" ));
  3049. request = (PREQ_WRITE)WorkContext->RequestParameters;
  3050. response = (PRESP_WRITE)WorkContext->ResponseParameters;
  3051. grantedAccess = WorkContext->Rfcb->GrantedAccess;
  3052. lfcb = WorkContext->Rfcb->Lfcb;
  3053. //
  3054. // Verify that the client has the appropriate access to the file via
  3055. // the specified handle.
  3056. //
  3057. CHECK_FILE_INFORMATION_ACCESS(
  3058. grantedAccess,
  3059. IRP_MJ_SET_INFORMATION,
  3060. FileEndOfFileInformation,
  3061. &status
  3062. );
  3063. if ( NT_SUCCESS(status) ) {
  3064. CHECK_FILE_INFORMATION_ACCESS(
  3065. grantedAccess,
  3066. IRP_MJ_SET_INFORMATION,
  3067. FileAllocationInformation,
  3068. &status
  3069. );
  3070. }
  3071. if ( !NT_SUCCESS(status) ) {
  3072. SrvStatistics.GrantedAccessErrors++;
  3073. IF_DEBUG(SMB_ERRORS) {
  3074. KdPrint(( "SetNewSize: IoCheckFunctionAccess failed: "
  3075. "0x%X, GrantedAccess: %lx\n",
  3076. status, grantedAccess ));
  3077. }
  3078. SrvSetSmbError( WorkContext, status );
  3079. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  3080. return;
  3081. }
  3082. //
  3083. // NtSetInformationFile allows a 64-bit file size, but the SMB
  3084. // protocol only allows 32-bit file sizes. Only set the lower 32
  3085. // bits, leaving the upper bits zero.
  3086. //
  3087. newEndOfFile.EndOfFile.QuadPart = SmbGetUlong( &request->Offset );
  3088. //
  3089. // Set the new EOF.
  3090. //
  3091. status = NtSetInformationFile(
  3092. lfcb->FileHandle,
  3093. &ioStatusBlock,
  3094. &newEndOfFile,
  3095. sizeof(newEndOfFile),
  3096. FileEndOfFileInformation
  3097. );
  3098. if ( NT_SUCCESS(status) ) {
  3099. //
  3100. // Set the new allocation size for the file.
  3101. //
  3102. // !!! This should ONLY be done if this is a down-level client!
  3103. //
  3104. newAllocation.AllocationSize = newEndOfFile.EndOfFile;
  3105. status = NtSetInformationFile(
  3106. lfcb->FileHandle,
  3107. &ioStatusBlock,
  3108. &newAllocation,
  3109. sizeof(newAllocation),
  3110. FileAllocationInformation
  3111. );
  3112. }
  3113. if ( !NT_SUCCESS(status) ) {
  3114. IF_DEBUG(ERRORS) {
  3115. KdPrint(( "SetNewSize: NtSetInformationFile failed, "
  3116. "status = %X\n", status ));
  3117. }
  3118. SrvSetSmbError( WorkContext, status );
  3119. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  3120. return;
  3121. }
  3122. //
  3123. // Build and send the response SMB.
  3124. //
  3125. response->WordCount = 1;
  3126. SmbPutUshort( &response->Count, 0 );
  3127. SmbPutUshort( &response->ByteCount, 0 );
  3128. WorkContext->ResponseParameters = NEXT_LOCATION( response, RESP_WRITE, 0 );
  3129. IF_DEBUG(TRACE2) KdPrint(( "SetNewSize complete\n" ));
  3130. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  3131. return;
  3132. } // SetNewSize
  3133. BOOLEAN
  3134. SetNewPosition (
  3135. IN PRFCB Rfcb,
  3136. IN OUT PULONG Offset,
  3137. IN BOOLEAN RelativeSeek
  3138. )
  3139. /*++
  3140. Routine Description:
  3141. Sets the new file pointer.
  3142. Arguments:
  3143. Rfcb - A pointer to the rfcb block which contains the position.
  3144. Offset - A pointer to the offset sent by client. If RelativeSeek is
  3145. TRUE, then this pointer will be updated.
  3146. RelativeSeek - Whether the seek is relative to the current position.
  3147. Return Value:
  3148. TRUE, Not nagative seek. Position has been updated.
  3149. FALSE, Negative seek. Position not updated.
  3150. --*/
  3151. {
  3152. LARGE_INTEGER newPosition;
  3153. UNLOCKABLE_CODE( 8FIL );
  3154. if ( RelativeSeek ) {
  3155. newPosition.QuadPart = Rfcb->CurrentPosition + *Offset;
  3156. } else {
  3157. newPosition.QuadPart = *Offset;
  3158. }
  3159. if ( newPosition.QuadPart < 0 ) {
  3160. return FALSE;
  3161. }
  3162. Rfcb->CurrentPosition = newPosition.LowPart;
  3163. *Offset = newPosition.LowPart;
  3164. return TRUE;
  3165. } // SetNewPosition
  3166. VOID SRVFASTCALL
  3167. SrvBuildAndSendErrorResponse (
  3168. IN OUT PWORK_CONTEXT WorkContext
  3169. )
  3170. {
  3171. PAGED_CODE( );
  3172. SrvSetSmbError( WorkContext, WorkContext->Irp->IoStatus.Status );
  3173. SrvFsdSendResponse( WorkContext );
  3174. return;
  3175. } // SrvBuildAndSendErrorResponse