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

2445 lines
74 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. fsdsmb.c
  5. Abstract:
  6. This module implements SMB processing routines and their support
  7. routines for the File System Driver of the LAN Manager server.
  8. *** This module must be nonpageable.
  9. Author:
  10. Chuck Lenzmeier (chuckl) 19-Mar-1990
  11. Revision History:
  12. --*/
  13. //
  14. // This module is laid out as follows:
  15. // Includes
  16. // Local #defines
  17. // Local type definitions
  18. // Forward declarations of local functions
  19. // SMB processing routines
  20. // Restart routines and other support routines
  21. //
  22. #include "precomp.h"
  23. #include "fsdsmb.tmh"
  24. #pragma hdrstop
  25. VOID SRVFASTCALL
  26. SrvFspRestartLargeReadAndXComplete(
  27. IN OUT PWORK_CONTEXT WorkContext
  28. );
  29. VOID SRVFASTCALL
  30. RestartReadAndXCompressedSendComplete (
  31. IN OUT PWORK_CONTEXT WorkContext
  32. );
  33. #if SRVCATCH
  34. VOID
  35. SrvUpdateCatchBuffer (
  36. IN PWORK_CONTEXT WorkContext,
  37. IN OUT PBYTE Buffer,
  38. IN DWORD BufferLength
  39. );
  40. #endif
  41. #ifdef ALLOC_PRAGMA
  42. //#pragma alloc_text( PAGE8FIL, SrvFsdRestartRead )
  43. #pragma alloc_text( PAGE8FIL, SrvFsdRestartReadAndX )
  44. #pragma alloc_text( PAGE8FIL, SrvFsdRestartReadAndXCompressed )
  45. #pragma alloc_text( PAGE8FIL, SrvFsdRestartWrite )
  46. #pragma alloc_text( PAGE8FIL, SrvFsdRestartWriteAndX )
  47. #pragma alloc_text( PAGE, RestartReadAndXCompressedSendComplete )
  48. #pragma alloc_text( PAGE, SrvFspRestartLargeReadAndXComplete )
  49. #if DBG
  50. #pragma alloc_text( PAGE, SrvValidateCompressedData )
  51. #endif
  52. #if SRVCATCH
  53. #pragma alloc_text( PAGE, SrvUpdateCatchBuffer )
  54. #endif
  55. #endif
  56. VOID SRVFASTCALL
  57. SrvFsdRestartRead (
  58. IN OUT PWORK_CONTEXT WorkContext
  59. )
  60. /*++
  61. Routine Description:
  62. Processes file read completion for a Read SMB.
  63. Arguments:
  64. WorkContext - Supplies a pointer to the work context block
  65. describing server-specific context for the request.
  66. Return Value:
  67. None.
  68. --*/
  69. {
  70. PREQ_READ request;
  71. PRESP_READ response;
  72. NTSTATUS status = STATUS_SUCCESS;
  73. PRFCB rfcb;
  74. SHARE_TYPE shareType;
  75. KIRQL oldIrql;
  76. USHORT readLength;
  77. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  78. UNLOCKABLE_CODE( 8FIL );
  79. if (bNeedTrace) {
  80. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  81. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ;
  82. SrvWmiStartContext(WorkContext);
  83. }
  84. else
  85. WorkContext->bAlreadyTrace = FALSE;
  86. IF_DEBUG(FSD2) SrvPrint0( " - SrvFsdRestartRead\n" );
  87. //
  88. // Get the request and response parameter pointers.
  89. //
  90. request = (PREQ_READ)WorkContext->RequestParameters;
  91. response = (PRESP_READ)WorkContext->ResponseParameters;
  92. //
  93. // Get the file pointer.
  94. //
  95. rfcb = WorkContext->Rfcb;
  96. shareType = rfcb->ShareType;
  97. IF_DEBUG(FSD2) {
  98. SrvPrint2( " connection 0x%p, RFCB 0x%p\n",
  99. WorkContext->Connection, rfcb );
  100. }
  101. //
  102. // If the read failed, set an error status in the response header.
  103. // (If we tried to read entirely beyond the end of file, we return a
  104. // normal response indicating that nothing was read.)
  105. //
  106. status = WorkContext->Irp->IoStatus.Status;
  107. readLength = (USHORT)WorkContext->Irp->IoStatus.Information;
  108. if ( status == STATUS_BUFFER_OVERFLOW && shareType == ShareTypePipe ) {
  109. //
  110. // If this is an named pipe and the error is
  111. // STATUS_BUFFER_OVERFLOW, set the error in the smb header, but
  112. // return all the data to the client.
  113. //
  114. SrvSetBufferOverflowError( WorkContext );
  115. } else if ( !NT_SUCCESS(status) ) {
  116. if ( status != STATUS_END_OF_FILE ) {
  117. IF_DEBUG(ERRORS) SrvPrint1( "Read failed: %X\n", status );
  118. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  119. WorkContext->FspRestartRoutine = SrvFsdRestartRead;
  120. QUEUE_WORK_TO_FSP( WorkContext );
  121. } else {
  122. SrvSetSmbError( WorkContext, status );
  123. SrvFsdSendResponse( WorkContext );
  124. }
  125. IF_DEBUG(FSD2) SrvPrint0( "SrvFsdRestartRead complete\n" );
  126. goto Cleanup;
  127. } else {
  128. readLength = 0;
  129. }
  130. }
  131. #ifdef SLMDBG
  132. {
  133. PRFCB_TRACE entry;
  134. PCHAR readAddress;
  135. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  136. rfcb->OperationCount++;
  137. entry = &rfcb->Trace[rfcb->NextTrace];
  138. if ( ++rfcb->NextTrace == SLMDBG_TRACE_COUNT ) {
  139. rfcb->NextTrace = 0;
  140. rfcb->TraceWrapped = TRUE;
  141. }
  142. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  143. entry->Command = WorkContext->NextCommand;
  144. KeQuerySystemTime( &entry->Time );
  145. entry->Data.ReadWrite.Offset = SmbGetUlong( &request->Offset );
  146. entry->Data.ReadWrite.Length = readLength;
  147. readAddress = (PCHAR)response->Buffer;
  148. }
  149. #endif
  150. //
  151. // The read completed successfully. If this is a disk file, update
  152. // the file position.
  153. //
  154. if (shareType == ShareTypeDisk) {
  155. #if SRVCATCH
  156. if( KeGetCurrentIrql() == 0 &&
  157. rfcb->SrvCatch &&
  158. SmbGetUlong( &request->Offset ) == 0 ) {
  159. SrvUpdateCatchBuffer( WorkContext, (PCHAR)response->Buffer, readLength );
  160. }
  161. #endif
  162. rfcb->CurrentPosition = SmbGetUlong( &request->Offset ) + readLength;
  163. }
  164. //
  165. // Save the count of bytes read, to be used to update the server
  166. // statistics database.
  167. //
  168. UPDATE_READ_STATS( WorkContext, readLength );
  169. //
  170. // Build the response message.
  171. //
  172. response->WordCount = 5;
  173. SmbPutUshort( &response->Count, readLength );
  174. RtlZeroMemory( (PVOID)&response->Reserved[0], sizeof(response->Reserved) );
  175. SmbPutUshort(
  176. &response->ByteCount,
  177. (USHORT)(readLength + FIELD_OFFSET(RESP_READ,Buffer[0]) -
  178. FIELD_OFFSET(RESP_READ,BufferFormat))
  179. );
  180. response->BufferFormat = SMB_FORMAT_DATA;
  181. SmbPutUshort( &response->DataLength, readLength );
  182. WorkContext->ResponseParameters = NEXT_LOCATION(
  183. response,
  184. RESP_READ,
  185. readLength
  186. );
  187. //
  188. // Processing of the SMB is complete. Send the response.
  189. //
  190. SrvFsdSendResponse( WorkContext );
  191. Cleanup:
  192. IF_DEBUG(FSD2) SrvPrint0( "SrvFsdRestartRead complete\n" );
  193. if (bNeedTrace) {
  194. SrvWmiEndContext(WorkContext);
  195. }
  196. return;
  197. } // SrvFsdRestartRead
  198. VOID SRVFASTCALL
  199. RestartReadAndXCompressedSendComplete (
  200. IN OUT PWORK_CONTEXT WorkContext
  201. )
  202. /*++
  203. Routine Description:
  204. Processes the TDI transport send complete for a compressed ReadAndX SMB
  205. Arguments:
  206. WorkContext - Supplies a pointer to the work context block
  207. describing server-specific context for the request.
  208. Return Value:
  209. None.
  210. --*/
  211. {
  212. PRFCB rfcb = WorkContext->Rfcb;
  213. PLFCB lfcb = WorkContext->Rfcb->Lfcb;
  214. NTSTATUS status;
  215. PMDL mdl = WorkContext->ResponseBuffer->Mdl->Next;
  216. PAGED_CODE();
  217. //
  218. // If we have a cache mdl, give it back to the cache manager
  219. //
  220. if( mdl != NULL ) {
  221. WorkContext->ResponseBuffer->Mdl->Next = NULL;
  222. }
  223. if( lfcb->MdlReadCompleteCompressed == NULL ||
  224. !lfcb->MdlReadCompleteCompressed( lfcb->FileObject,
  225. mdl,
  226. lfcb->DeviceObject) ) {
  227. status = SrvIssueMdlCompleteRequest( WorkContext, NULL, mdl, IRP_MJ_READ,
  228. &WorkContext->Parameters.ReadAndXCompressed.ReadOffset,
  229. WorkContext->Parameters.ReadAndXCompressed.ReadLength
  230. );
  231. if( !NT_SUCCESS( status ) ) {
  232. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  233. }
  234. }
  235. //
  236. // Free the work item
  237. //
  238. SrvDereferenceWorkItem( WorkContext );
  239. }
  240. #if DBG
  241. VOID
  242. SrvValidateCompressedData(
  243. PWORK_CONTEXT WorkContext,
  244. PMDL CompressedDataMdl,
  245. PCOMPRESSED_DATA_INFO Cdi
  246. )
  247. /*++
  248. Make sure the compressed buffer that we just got from the filesystem is correct
  249. We do this by decompressing it!
  250. --*/
  251. {
  252. ULONG i, compressedDataLength;
  253. PMDL mdl;
  254. NTSTATUS status;
  255. PBYTE compressedBuffer;
  256. PBYTE uncompressedBuffer;
  257. ULONG count;
  258. PBYTE pin;
  259. PAGED_CODE();
  260. //
  261. // We need to copy the compressed data into a flat buffer
  262. //
  263. for ( i = compressedDataLength = 0; i < Cdi->NumberOfChunks; i++ ) {
  264. compressedDataLength += Cdi->CompressedChunkSizes[i];
  265. }
  266. if( compressedDataLength && CompressedDataMdl == NULL ) {
  267. DbgPrint( "SrvValidateCompressedData(wc %X, cdi %X, mdl %X ) -- no MDL!",
  268. WorkContext, Cdi, WorkContext->Irp->MdlAddress );
  269. // DbgBreakPoint();
  270. return;
  271. }
  272. if( compressedDataLength > SrvMaxCompressedDataLength ) {
  273. DbgPrint( "SrvValidateCompressedData(wc %X, cdi %X) compresseddatalength %u\n",
  274. WorkContext, Cdi, compressedDataLength );
  275. DbgBreakPoint();
  276. return;
  277. }
  278. pin = compressedBuffer =
  279. ALLOCATE_NONPAGED_POOL( compressedDataLength, BlockTypeDataBuffer );
  280. if( compressedBuffer == NULL ) {
  281. return;
  282. }
  283. for( mdl = CompressedDataMdl; mdl != NULL; mdl = mdl->Next ) {
  284. i = MmGetMdlByteCount( mdl );
  285. RtlCopyMemory( pin, MmGetSystemAddressForMdl( mdl ), i );
  286. pin += i;
  287. }
  288. //
  289. // The largest output chunk is SrvMaxCompressedDataLength
  290. //
  291. uncompressedBuffer = ALLOCATE_HEAP_COLD( SrvMaxCompressedDataLength, BlockTypeDataBuffer );
  292. if( uncompressedBuffer == NULL ) {
  293. DEALLOCATE_NONPAGED_POOL( compressedBuffer );
  294. return;
  295. }
  296. status = RtlDecompressChunks( uncompressedBuffer, SrvMaxCompressedDataLength,
  297. compressedBuffer, compressedDataLength,
  298. NULL, 0, Cdi );
  299. if( !NT_SUCCESS( status ) ) {
  300. DbgPrint( "\nSrvValidateCompressedData - status %X\n", status );
  301. DbgPrint( " WC %X, CDI %X, Irp %X, Mdl %X, InBuffer %X\n",
  302. WorkContext, Cdi, WorkContext->Irp,
  303. CompressedDataMdl, uncompressedBuffer
  304. );
  305. DbgBreakPoint();
  306. }
  307. DEALLOCATE_NONPAGED_POOL( compressedBuffer );
  308. FREE_HEAP( uncompressedBuffer );
  309. }
  310. #endif
  311. VOID SRVFASTCALL
  312. SrvFsdRestartReadAndXCompressed (
  313. IN OUT PWORK_CONTEXT WorkContext
  314. )
  315. /*++
  316. Routine Description:
  317. Processes file read completion for a compressed ReadAndX SMB
  318. This routine may be called in the FSD or the FSP. There can be
  319. no chained command.
  320. Arguments:
  321. WorkContext - Supplies a pointer to the work context block
  322. describing server-specific context for the request.
  323. Return Value:
  324. None.
  325. --*/
  326. {
  327. PRFCB rfcb = WorkContext->Rfcb;
  328. PIRP irp = WorkContext->Irp;
  329. NTSTATUS status = irp->IoStatus.Status;
  330. ULONG readLength = (ULONG)irp->IoStatus.Information; // size of uncompressed data
  331. ULONG dataLength; // size of compressed data
  332. ULONG cdiLength; // size of compressedDataInfo
  333. USHORT flags2;
  334. PCOMPRESSED_DATA_INFO compressedDataInfo;
  335. PRESP_READ_ANDX response;
  336. ULONG i;
  337. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  338. UNLOCKABLE_CODE( 8FIL );
  339. if (bNeedTrace) {
  340. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  341. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_AND_X;
  342. SrvWmiStartContext(WorkContext);
  343. }
  344. else
  345. WorkContext->bAlreadyTrace = FALSE;
  346. IF_DEBUG( COMPRESSION ) {
  347. KdPrint(( "SRV: SrvFsdRestartReadAndXCompressed status %X, uncompressed len %u, mdl %p\n",
  348. status, readLength, irp->MdlAddress ));
  349. }
  350. if( NT_SUCCESS( status ) && readLength != 0 ) {
  351. //
  352. // Scan the Compression Info structure tallying the sizes of
  353. // each chunk.
  354. //
  355. //
  356. compressedDataInfo = WorkContext->Parameters.ReadAndXCompressed.Aux.Buffer;
  357. #if DBG
  358. SrvValidateCompressedData( WorkContext, WorkContext->Irp->MdlAddress,compressedDataInfo );
  359. #endif
  360. cdiLength = FIELD_OFFSET( COMPRESSED_DATA_INFO, CompressedChunkSizes ) +
  361. (sizeof(ULONG) * compressedDataInfo->NumberOfChunks );
  362. for ( i = dataLength = 0;
  363. i < compressedDataInfo->NumberOfChunks;
  364. i++ ) {
  365. dataLength += compressedDataInfo->CompressedChunkSizes[i];
  366. }
  367. } else if( status == STATUS_END_OF_FILE || readLength == 0 ) {
  368. readLength = dataLength = cdiLength = 0;
  369. } else {
  370. //
  371. // Make sure we are at passive level
  372. //
  373. if( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  374. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndXCompressed;
  375. SrvQueueWorkToFsp( WorkContext );
  376. goto Cleanup;
  377. }
  378. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  379. IF_DEBUG( ERRORS ) {
  380. KdPrint(("SRV: SrvFsdRestartReadAndXCompressed status %X\n", status ));
  381. }
  382. if( status != STATUS_INVALID_READ_MODE &&
  383. status != STATUS_UNSUPPORTED_COMPRESSION &&
  384. status != STATUS_USER_MAPPED_FILE &&
  385. status != STATUS_NOT_SUPPORTED &&
  386. status != STATUS_BAD_COMPRESSION_BUFFER ) {
  387. //
  388. // Set the error and get out!
  389. //
  390. SrvSetSmbError( WorkContext, status );
  391. SrvFsdSendResponse( WorkContext );
  392. goto Cleanup;
  393. }
  394. IF_DEBUG( COMPRESSION ) {
  395. KdPrint(( " %X: rerouting to SrvSmbReadAndX\n", status ));
  396. }
  397. //
  398. // No more compressed reads for this file!
  399. //
  400. rfcb->Mfcb->NonpagedMfcb->OpenFileAttributes &= ~FILE_ATTRIBUTE_COMPRESSED;
  401. //
  402. // We now need to turn around and do a regular non-compressed read. We
  403. // can just reroute this back to the original Read&X processor because we
  404. // know that we have not changed the original request received from the client.
  405. // Also, we have turned off both the FILE_ATTRIBUTE_COMPRESSED flag in the
  406. // Mfcb, as well as the SMB_FLAGS2_COMPRESSED bit in the header. Therefore
  407. // we will not loop!
  408. //
  409. // We also know that SrvSmbReadAndX will return SmbStatusInProgress, because
  410. // all of the error checks have previously passed!
  411. //
  412. // This is not a terribly efficient way to handle this error, but it should be
  413. // extremely rare.
  414. //
  415. SrvStatistics.CompressedReadsFailed++;
  416. (VOID)SrvSmbReadAndX( WorkContext );
  417. goto Cleanup;
  418. }
  419. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  420. //
  421. // Update the file position
  422. //
  423. WorkContext->Rfcb->CurrentPosition =
  424. WorkContext->Parameters.ReadAndXCompressed.ReadOffset.LowPart + readLength;
  425. //
  426. // Build and send the response
  427. //
  428. response = (PRESP_READ_ANDX)WorkContext->ResponseParameters;
  429. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  430. response->WordCount = 12;
  431. response->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
  432. response->AndXReserved = 0;
  433. SmbPutUshort( &response->AndXOffset, 0 );
  434. SmbPutUshort( &response->DataCompactionMode, 0 );
  435. SmbPutUshort( &response->CdiLength, (USHORT)cdiLength );
  436. SmbPutUshort( &response->DataLength, (USHORT)readLength );
  437. SmbPutUshort( &response->DataLengthHigh, (USHORT)(readLength >> 16) );
  438. SmbPutUshort( &response->DataOffset, (USHORT)READX_BUFFER_OFFSET );
  439. RtlZeroMemory( (PVOID)&response->Reserved3[0], sizeof(response->Reserved3) );
  440. SmbPutUshort( &response->ByteCount, (USHORT)(cdiLength + dataLength) );
  441. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  442. //
  443. // If we got some data, indicate to the client that we are returning
  444. // a compressed response
  445. //
  446. if( cdiLength ) {
  447. //
  448. // Copy the COMPRESSED_DATA_INFO structure to the Data[] portion of the
  449. // response.
  450. //
  451. RtlCopyMemory( response->Buffer, compressedDataInfo, cdiLength );
  452. flags2 = SmbGetAlignedUshort( &WorkContext->ResponseHeader->Flags2 );
  453. flags2 |= SMB_FLAGS2_COMPRESSED;
  454. SmbPutAlignedUshort( &WorkContext->ResponseHeader->Flags2, flags2 );
  455. WorkContext->ResponseBuffer->Mdl->Next = irp->MdlAddress;
  456. }
  457. WorkContext->ResponseBuffer->Mdl->ByteCount = READX_BUFFER_OFFSET + cdiLength;
  458. WorkContext->ResponseBuffer->DataLength =
  459. READX_BUFFER_OFFSET + cdiLength + dataLength;
  460. WorkContext->FspRestartRoutine = RestartReadAndXCompressedSendComplete;
  461. irp->Cancel = FALSE;
  462. SrvStartSend2( WorkContext, SrvQueueWorkToFspAtSendCompletion );
  463. Cleanup:
  464. if (bNeedTrace) {
  465. SrvWmiEndContext(WorkContext);
  466. }
  467. return;
  468. }
  469. VOID SRVFASTCALL
  470. SrvFsdRestartReadAndX (
  471. IN OUT PWORK_CONTEXT WorkContext
  472. )
  473. /*++
  474. Routine Description:
  475. Processes file read completion for a ReadAndX SMB.
  476. This routine may be called in the FSD or the FSP. If the chained
  477. command is Close, it will be called in the FSP.
  478. *** This routine cannot look at the original ReadAndX request!
  479. This is because the read data may have overlaid the request.
  480. All necessary information from the request must be stored
  481. in WorkContext->Parameters.ReadAndX.
  482. Arguments:
  483. WorkContext - Supplies a pointer to the work context block
  484. describing server-specific context for the request.
  485. Return Value:
  486. None.
  487. --*/
  488. {
  489. PRESP_READ_ANDX response;
  490. NTSTATUS status = STATUS_SUCCESS;
  491. PRFCB rfcb;
  492. SHARE_TYPE shareType;
  493. KIRQL oldIrql;
  494. PCHAR readAddress;
  495. CLONG bufferOffset;
  496. ULONG readLength;
  497. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  498. UNLOCKABLE_CODE( 8FIL );
  499. if (bNeedTrace) {
  500. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  501. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_AND_X;
  502. SrvWmiStartContext(WorkContext);
  503. }
  504. else
  505. WorkContext->bAlreadyTrace = FALSE;
  506. IF_DEBUG(FSD2) SrvPrint0( " - SrvFsdRestartReadAndX\n" );
  507. //
  508. // Get the response parameter pointer.
  509. //
  510. response = (PRESP_READ_ANDX)WorkContext->ResponseParameters;
  511. //
  512. // Get the file pointer.
  513. //
  514. rfcb = WorkContext->Rfcb;
  515. shareType = rfcb->ShareType;
  516. IF_DEBUG(FSD2) {
  517. SrvPrint2( " connection 0x%p, RFCB 0x%p\n",
  518. WorkContext->Connection, rfcb );
  519. }
  520. //
  521. // If the read failed, set an error status in the response header.
  522. // (If we tried to read entirely beyond the end of file, we return a
  523. // normal response indicating that nothing was read.)
  524. //
  525. status = WorkContext->Irp->IoStatus.Status;
  526. readLength = (ULONG)WorkContext->Irp->IoStatus.Information;
  527. if ( status == STATUS_BUFFER_OVERFLOW && shareType == ShareTypePipe ) {
  528. //
  529. // If this is an named pipe and the error is
  530. // STATUS_BUFFER_OVERFLOW, set the error in the smb header, but
  531. // return all the data to the client.
  532. //
  533. SrvSetBufferOverflowError( WorkContext );
  534. } else if ( !NT_SUCCESS(status) ) {
  535. if ( status != STATUS_END_OF_FILE ) {
  536. IF_DEBUG(ERRORS) SrvPrint1( "Read failed: %X\n", status );
  537. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  538. WorkContext->FspRestartRoutine = SrvFsdRestartReadAndX;
  539. QUEUE_WORK_TO_FSP( WorkContext );
  540. } else {
  541. SrvSetSmbError( WorkContext, status );
  542. SrvFsdSendResponse( WorkContext );
  543. }
  544. IF_DEBUG(FSD2) SrvPrint0("SrvFsdRestartReadAndX complete\n");
  545. goto Cleanup;
  546. } else {
  547. readLength = 0;
  548. }
  549. }
  550. //
  551. // The read completed successfully. Generate information about the
  552. // destination of the read data. Find out how much was actually
  553. // read. If none was read, we don't have to worry about the offset.
  554. //
  555. if ( readLength != 0 ) {
  556. readAddress = WorkContext->Parameters.ReadAndX.ReadAddress;
  557. bufferOffset = (ULONG)(readAddress - (PCHAR)WorkContext->ResponseHeader);
  558. //
  559. // Save the count of bytes read, to be used to update the server
  560. // statistics database.
  561. //
  562. UPDATE_READ_STATS( WorkContext, readLength );
  563. } else {
  564. readAddress = (PCHAR)response->Buffer;
  565. bufferOffset = 0;
  566. }
  567. #ifdef SLMDBG
  568. {
  569. PRFCB_TRACE entry;
  570. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  571. rfcb->OperationCount++;
  572. entry = &rfcb->Trace[rfcb->NextTrace];
  573. if ( ++rfcb->NextTrace == SLMDBG_TRACE_COUNT ) {
  574. rfcb->NextTrace = 0;
  575. rfcb->TraceWrapped = TRUE;
  576. }
  577. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  578. entry->Command = WorkContext->NextCommand;
  579. KeQuerySystemTime( &entry->Time );
  580. entry->Data.ReadWrite.Offset =
  581. WorkContext->Parameters.ReadAndX.ReadOffset.LowPart;
  582. ASSERT (WorkContext->Parameters.ReadAndX.ReadOffset.HighPart == 0);
  583. entry->Data.ReadWrite.Length = readLength;
  584. }
  585. #endif
  586. if (shareType == ShareTypePipe) {
  587. //
  588. // If this is NPFS then, Irp->Overlay.AllocationSize actually
  589. // contains the number bytes left to read on this side of the named
  590. // pipe. Return this information to the client.
  591. //
  592. if (WorkContext->Irp->Overlay.AllocationSize.LowPart != 0) {
  593. SmbPutUshort(
  594. &response->Remaining,
  595. (USHORT)(WorkContext->Irp->Overlay.AllocationSize.LowPart - readLength)
  596. );
  597. } else {
  598. SmbPutUshort(
  599. &response->Remaining,
  600. 0
  601. );
  602. }
  603. } else {
  604. if ( shareType == ShareTypeDisk ) {
  605. #if SRVCATCH
  606. if( KeGetCurrentIrql() == 0 &&
  607. rfcb->SrvCatch &&
  608. WorkContext->Parameters.ReadAndX.ReadOffset.QuadPart == 0 ) {
  609. SrvUpdateCatchBuffer( WorkContext, readAddress, readLength );
  610. }
  611. #endif
  612. //
  613. // If this is a disk file, then update the file position.
  614. //
  615. rfcb->CurrentPosition =
  616. WorkContext->Parameters.ReadAndX.ReadOffset.LowPart +
  617. readLength;
  618. }
  619. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  620. }
  621. //
  622. // Build the response message. (Note that if no data was read, we
  623. // return a byte count of 0 -- we don't add padding.)
  624. //
  625. // *** Note that even though there may have been a chained command,
  626. // we make this the last response in the chain. This is what
  627. // the OS/2 server does. (Sort of -- it doesn't bother to
  628. // update the AndX fields of the response.) Since the only legal
  629. // chained commands are Close and CloseAndTreeDisc, this seems
  630. // like a reasonable thing to do. It does make life easier --
  631. // we don't have to find the end of the read data and write
  632. // another response there. Besides, the read data might have
  633. // completely filled the SMB buffer.
  634. //
  635. response->WordCount = 12;
  636. response->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
  637. response->AndXReserved = 0;
  638. SmbPutUshort( &response->AndXOffset, 0 );
  639. SmbPutUshort( &response->DataCompactionMode, 0 );
  640. SmbPutUshort( &response->Reserved, 0 );
  641. SmbPutUshort( &response->DataLength, (USHORT)readLength );
  642. SmbPutUshort( &response->DataOffset, (USHORT)bufferOffset );
  643. SmbPutUshort( &response->DataLengthHigh, (USHORT)(readLength >> 16) );
  644. RtlZeroMemory( (PVOID)&response->Reserved3[0], sizeof(response->Reserved3) );
  645. SmbPutUshort(
  646. &response->ByteCount,
  647. (USHORT)(readLength + (readAddress - response->Buffer))
  648. );
  649. WorkContext->ResponseParameters = NEXT_LOCATION(
  650. response,
  651. RESP_READ_ANDX,
  652. readLength +
  653. (readAddress - response->Buffer)
  654. );
  655. //
  656. // Processing of the SMB is complete, except that the file may still
  657. // need to be closed. If not, just send the response. If this is a
  658. // ReadAndX and Close, we need to close the file first.
  659. //
  660. // *** Note that other chained commands are illegal, but are ignored
  661. // -- no error is returned.
  662. //
  663. if ( WorkContext->NextCommand != SMB_COM_CLOSE ) {
  664. //
  665. // Not a chained Close. Just send the response.
  666. //
  667. SrvFsdSendResponse( WorkContext );
  668. } else {
  669. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  670. //
  671. // Remember the file last write time, to correctly set this on
  672. // close.
  673. //
  674. WorkContext->Parameters.LastWriteTime =
  675. WorkContext->Parameters.ReadAndX.LastWriteTimeInSeconds;
  676. //
  677. // This is a ReadAndX and Close. Call SrvRestartChainedClose to
  678. // do the close and send the response.
  679. //
  680. SrvRestartChainedClose( WorkContext );
  681. }
  682. IF_DEBUG(FSD2) SrvPrint0( "SrvFsdRestartReadAndX complete\n" );
  683. Cleanup:
  684. if (bNeedTrace) {
  685. SrvWmiEndContext(WorkContext);
  686. }
  687. return;
  688. } // SrvFsdRestartReadAndX
  689. /*
  690. * This routine is called at final send completion
  691. */
  692. VOID SRVFASTCALL
  693. SrvFspRestartLargeReadAndXComplete(
  694. IN OUT PWORK_CONTEXT WorkContext
  695. )
  696. {
  697. NTSTATUS status;
  698. PAGED_CODE();
  699. if( WorkContext->Parameters.ReadAndX.SavedMdl != NULL ) {
  700. WorkContext->ResponseBuffer->Mdl = WorkContext->Parameters.ReadAndX.SavedMdl;
  701. MmPrepareMdlForReuse( WorkContext->ResponseBuffer->PartialMdl );
  702. WorkContext->ResponseBuffer->PartialMdl->Next = NULL;
  703. }
  704. if ( WorkContext->Parameters.ReadAndX.MdlRead == TRUE ) {
  705. //
  706. // Call the Cache Manager to release the MDL chain.
  707. //
  708. if( WorkContext->Parameters.ReadAndX.CacheMdl ) {
  709. //
  710. // Try the fast path first..
  711. //
  712. if( WorkContext->Rfcb->Lfcb->MdlReadComplete == NULL ||
  713. WorkContext->Rfcb->Lfcb->MdlReadComplete(
  714. WorkContext->Rfcb->Lfcb->FileObject,
  715. WorkContext->Parameters.ReadAndX.CacheMdl,
  716. WorkContext->Rfcb->Lfcb->DeviceObject ) == FALSE ) {
  717. //
  718. // Fast path didn't work, try an IRP...
  719. //
  720. status = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  721. WorkContext->Parameters.ReadAndX.CacheMdl,
  722. IRP_MJ_READ,
  723. &WorkContext->Parameters.ReadAndX.ReadOffset,
  724. WorkContext->Parameters.ReadAndX.ReadLength
  725. );
  726. if( !NT_SUCCESS( status ) ) {
  727. //
  728. // At this point, all we can do is complain!
  729. //
  730. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, status );
  731. }
  732. }
  733. }
  734. } else {
  735. PMDL mdl = (PMDL)(((ULONG_PTR)(WorkContext->Parameters.ReadAndX.ReadAddress) + sizeof(PVOID) - 1) & ~(sizeof(PVOID)-1));
  736. //
  737. // We shortened the byte count if the read returned less data than we asked for
  738. //
  739. mdl->ByteCount = WorkContext->Parameters.ReadAndX.ReadLength;
  740. MmUnlockPages( mdl );
  741. MmPrepareMdlForReuse( mdl );
  742. FREE_HEAP( WorkContext->Parameters.ReadAndX.Buffer );
  743. }
  744. SrvDereferenceWorkItem( WorkContext );
  745. return;
  746. }
  747. /*
  748. * This routine is called when the read completes
  749. */
  750. VOID SRVFASTCALL
  751. SrvFsdRestartLargeReadAndX (
  752. IN OUT PWORK_CONTEXT WorkContext
  753. )
  754. /*++
  755. Routine Description:
  756. Processes file read completion for a ReadAndX SMB which
  757. is larger than the negotiated buffer size, and is from
  758. a disk file.
  759. There is no follow on command.
  760. Arguments:
  761. WorkContext - Supplies a pointer to the work context block
  762. describing server-specific context for the request.
  763. Return Value:
  764. None.
  765. --*/
  766. {
  767. PRESP_READ_ANDX response = (PRESP_READ_ANDX)WorkContext->ResponseParameters;
  768. USHORT readLength;
  769. NTSTATUS status = WorkContext->Irp->IoStatus.Status;
  770. PRFCB rfcb = WorkContext->Rfcb;
  771. PIRP irp = WorkContext->Irp;
  772. BOOLEAN mdlRead = WorkContext->Parameters.ReadAndX.MdlRead;
  773. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  774. #ifdef SRVCATCH
  775. // For the Catch case, make sure we're PASSIVE
  776. if( (KeGetCurrentIrql() != PASSIVE_LEVEL) && (WorkContext->Rfcb->SrvCatch != 0) ) {
  777. //
  778. // Requeue this routine to come back around at passive level.
  779. // (inefficient, but should be very rare)
  780. //
  781. WorkContext->FspRestartRoutine = SrvFsdRestartLargeReadAndX;
  782. SrvQueueWorkToFspAtDpcLevel( WorkContext );
  783. goto Cleanup;
  784. }
  785. #endif
  786. UNLOCKABLE_CODE( 8FIL );
  787. if (bNeedTrace) {
  788. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  789. WorkContext->PreviousSMB = EVENT_TYPE_SMB_READ_AND_X;
  790. SrvWmiStartContext(WorkContext);
  791. }
  792. else
  793. WorkContext->bAlreadyTrace = FALSE;
  794. // Copy the MDL pointer back out of the IRP. This is because if the read
  795. // failed, CC will free the MDL and NULL the pointer. Not retrieving it in the
  796. // non-fast-io path will result in us holding (and possibly freeing) a dangling pointer
  797. if( mdlRead )
  798. {
  799. WorkContext->Parameters.ReadAndX.CacheMdl = WorkContext->Irp->MdlAddress;
  800. }
  801. if ( !NT_SUCCESS(status) ) {
  802. if( status != STATUS_END_OF_FILE ) {
  803. IF_DEBUG(ERRORS) SrvPrint1( "Read failed: %X\n", status );
  804. //
  805. // We cannot call SrvSetSmbError() at elevated IRQL.
  806. //
  807. if( KeGetCurrentIrql() != 0 ) {
  808. //
  809. // Requeue this routine to come back around at passive level.
  810. // (inefficient, but should be very rare)
  811. //
  812. WorkContext->FspRestartRoutine = SrvFsdRestartLargeReadAndX;
  813. SrvQueueWorkToFspAtDpcLevel( WorkContext );
  814. goto Cleanup;
  815. }
  816. SrvSetSmbError( WorkContext, status );
  817. }
  818. readLength = 0;
  819. } else if( mdlRead ) {
  820. //
  821. // For an MDL read, we have to walk the MDL chain in order to
  822. // determine how much data was read. This is because the
  823. // operation may have happened in multiple steps, with the MDLs
  824. // being chained together. For example, part of the read may
  825. // have been satisfied by the fast path, while the rest was satisfied
  826. // using an IRP
  827. //
  828. PMDL mdl = WorkContext->Irp->MdlAddress;
  829. readLength = 0;
  830. while( mdl != NULL ) {
  831. readLength += (USHORT)MmGetMdlByteCount( mdl );
  832. mdl = mdl->Next;
  833. }
  834. } else {
  835. //
  836. // This was a copy read. The I/O status block has the length.
  837. //
  838. readLength = (USHORT)WorkContext->Irp->IoStatus.Information;
  839. }
  840. //
  841. // Build the response message. (Note that if no data was read, we
  842. // return a byte count of 0 -- we don't add padding.)
  843. //
  844. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  845. response->WordCount = 12;
  846. response->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
  847. response->AndXReserved = 0;
  848. SmbPutUshort( &response->AndXOffset, 0 );
  849. SmbPutUshort( &response->DataCompactionMode, 0 );
  850. SmbPutUshort( &response->Reserved, 0 );
  851. SmbPutUshort( &response->Reserved2, 0 );
  852. RtlZeroMemory( (PVOID)&response->Reserved3[0], sizeof(response->Reserved3) );
  853. SmbPutUshort( &response->DataLength, readLength );
  854. if( readLength == 0 ) {
  855. SmbPutUshort( &response->DataOffset, 0 );
  856. SmbPutUshort( &response->ByteCount, 0 );
  857. WorkContext->Parameters.ReadAndX.PadCount = 0;
  858. } else {
  859. //
  860. // Update the file position.
  861. //
  862. rfcb->CurrentPosition =
  863. WorkContext->Parameters.ReadAndX.ReadOffset.LowPart +
  864. readLength;
  865. //
  866. // Update statistics
  867. //
  868. UPDATE_READ_STATS( WorkContext, readLength );
  869. SmbPutUshort( &response->DataOffset,
  870. (USHORT)(READX_BUFFER_OFFSET + WorkContext->Parameters.ReadAndX.PadCount) );
  871. SmbPutUshort( &response->ByteCount,
  872. (USHORT)( readLength + WorkContext->Parameters.ReadAndX.PadCount ) );
  873. }
  874. //
  875. // We will use two MDLs to describe the packet we're sending -- one
  876. // for the header and parameters, the other for the data.
  877. //
  878. // Handling of the second MDL varies depending on whether we did a copy
  879. // read or an MDL read.
  880. //
  881. //
  882. // Set the first MDL for just the header + pad
  883. //
  884. IoBuildPartialMdl(
  885. WorkContext->ResponseBuffer->Mdl,
  886. WorkContext->ResponseBuffer->PartialMdl,
  887. WorkContext->ResponseBuffer->Buffer,
  888. READX_BUFFER_OFFSET + WorkContext->Parameters.ReadAndX.PadCount
  889. );
  890. WorkContext->ResponseBuffer->PartialMdl->MdlFlags |=
  891. (WorkContext->ResponseBuffer->Mdl->MdlFlags & MDL_NETWORK_HEADER); // prop flag
  892. //
  893. // Set the overall data length to the header + pad + data
  894. //
  895. WorkContext->ResponseBuffer->DataLength = READX_BUFFER_OFFSET +
  896. WorkContext->Parameters.ReadAndX.PadCount +
  897. readLength;
  898. irp->Cancel = FALSE;
  899. //
  900. // The second MDL depends on the kind of read which we did
  901. //
  902. if( readLength != 0 ) {
  903. if( mdlRead ) {
  904. WorkContext->ResponseBuffer->PartialMdl->Next =
  905. WorkContext->Irp->MdlAddress;
  906. } else {
  907. //
  908. // This was a copy read. The MDL describing the data buffer is in the SMB buffer
  909. //
  910. PMDL mdl = (PMDL)(((ULONG_PTR)(WorkContext->Parameters.ReadAndX.ReadAddress) + sizeof(PVOID) - 1) & ~(sizeof(PVOID)-1));
  911. WorkContext->ResponseBuffer->PartialMdl->Next = mdl;
  912. mdl->ByteCount = readLength;
  913. }
  914. #ifdef SRVCATCH
  915. if( rfcb->SrvCatch && WorkContext->ResponseBuffer->PartialMdl->Next && (WorkContext->Parameters.ReadAndX.ReadOffset.QuadPart == 0) )
  916. {
  917. PVOID Buffer;
  918. Buffer = MmGetSystemAddressForMdlSafe( WorkContext->ResponseBuffer->PartialMdl->Next, LowPagePriority );
  919. if( Buffer )
  920. {
  921. SrvUpdateCatchBuffer( WorkContext, Buffer, WorkContext->ResponseBuffer->PartialMdl->Next->ByteCount );
  922. }
  923. }
  924. #endif
  925. }
  926. //
  927. // SrvStartSend2 wants to use WorkContext->ResponseBuffer->Mdl, but
  928. // we want it to use WorkContext->ResponseBuffer->PartialMdl. So switch
  929. // it!
  930. //
  931. WorkContext->Parameters.ReadAndX.SavedMdl = WorkContext->ResponseBuffer->Mdl;
  932. WorkContext->ResponseBuffer->Mdl = WorkContext->ResponseBuffer->PartialMdl;
  933. //
  934. // Send the response!
  935. //
  936. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  937. WorkContext->FspRestartRoutine = SrvFspRestartLargeReadAndXComplete;
  938. SrvStartSend2( WorkContext, SrvQueueWorkToFspAtSendCompletion );
  939. Cleanup:
  940. if (bNeedTrace) {
  941. SrvWmiEndContext(WorkContext);
  942. }
  943. return;
  944. }
  945. VOID SRVFASTCALL
  946. SrvFsdRestartWrite (
  947. IN OUT PWORK_CONTEXT WorkContext
  948. )
  949. /*++
  950. Routine Description:
  951. Processes file write completion for a Write SMB.
  952. This routine is called in the FSP for a write and close SMB so that
  953. it can free the pageable MFCB and for a write and unlock SMB so that
  954. it can do the unlock; for other SMBs, it is called in the FSD.
  955. Arguments:
  956. WorkContext - Supplies a pointer to the work context block
  957. describing server-specific context for the request.
  958. Return Value:
  959. None.
  960. --*/
  961. {
  962. PREQ_WRITE request;
  963. PRESP_WRITE response;
  964. NTSTATUS status = STATUS_SUCCESS;
  965. PRFCB rfcb;
  966. KIRQL oldIrql;
  967. USHORT writeLength;
  968. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  969. UNLOCKABLE_CODE( 8FIL );
  970. if (bNeedTrace) {
  971. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  972. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE;
  973. SrvWmiStartContext(WorkContext);
  974. }
  975. else
  976. WorkContext->bAlreadyTrace = FALSE;
  977. IF_DEBUG(FSD2) SrvPrint0( " - SrvFsdRestartWrite\n" );
  978. //
  979. // Get the request and response parameter pointers.
  980. //
  981. request = (PREQ_WRITE)WorkContext->RequestParameters;
  982. response = (PRESP_WRITE)WorkContext->ResponseParameters;
  983. //
  984. // Get the file pointer.
  985. //
  986. rfcb = WorkContext->Rfcb;
  987. IF_DEBUG(FSD2) {
  988. SrvPrint2( " connection 0x%p, RFCB 0x%p\n",
  989. WorkContext->Connection, rfcb );
  990. }
  991. //
  992. // If the write failed, set an error status in the response header.
  993. //
  994. status = WorkContext->Irp->IoStatus.Status;
  995. if ( !NT_SUCCESS(status) ) {
  996. IF_DEBUG(ERRORS) SrvPrint1( "Write failed: %X\n", status );
  997. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  998. WorkContext->FspRestartRoutine = SrvFsdRestartWrite;
  999. QUEUE_WORK_TO_FSP( WorkContext );
  1000. goto Cleanup;
  1001. }
  1002. SrvSetSmbError( WorkContext, status );
  1003. } else {
  1004. //
  1005. // The write succeeded.
  1006. //
  1007. writeLength = (USHORT)WorkContext->Irp->IoStatus.Information;
  1008. //
  1009. // Save the count of bytes written, to be used to update the
  1010. // server statistics database.
  1011. //
  1012. UPDATE_WRITE_STATS( WorkContext, writeLength );
  1013. if ( rfcb->ShareType == ShareTypeDisk ) {
  1014. //
  1015. // Update the file position.
  1016. //
  1017. rfcb->CurrentPosition = SmbGetUlong( &request->Offset ) + writeLength;
  1018. if ( WorkContext->NextCommand == SMB_COM_WRITE ) {
  1019. response->WordCount = 1;
  1020. SmbPutUshort( &response->Count, writeLength );
  1021. SmbPutUshort( &response->ByteCount, 0 );
  1022. WorkContext->ResponseParameters =
  1023. NEXT_LOCATION( response, RESP_WRITE, 0 );
  1024. //
  1025. // Processing of the SMB is complete. Send the response.
  1026. //
  1027. SrvFsdSendResponse( WorkContext );
  1028. IF_DEBUG(FSD2) SrvPrint0( "SrvFsdRestartWrite complete\n" );
  1029. goto Cleanup;
  1030. }
  1031. } else if ( rfcb->ShareType == ShareTypePrint ) {
  1032. //
  1033. // Update the file position.
  1034. //
  1035. if ( WorkContext->NextCommand == SMB_COM_WRITE_PRINT_FILE ) {
  1036. rfcb->CurrentPosition += writeLength;
  1037. } else {
  1038. rfcb->CurrentPosition =
  1039. SmbGetUlong( &request->Offset ) + writeLength;
  1040. }
  1041. }
  1042. //
  1043. // If this was a Write and Unlock request, do the unlock. This
  1044. // is safe because we are restarted in the FSP in this case.
  1045. //
  1046. // Note that if the write failed, the range remains locked.
  1047. //
  1048. if ( WorkContext->NextCommand == SMB_COM_WRITE_AND_UNLOCK ) {
  1049. IF_SMB_DEBUG(READ_WRITE1) {
  1050. SrvPrint0( "SrvFsdRestartWrite: unlock requested -- passing request to FSP\n" );
  1051. }
  1052. SrvRestartWriteAndUnlock( WorkContext );
  1053. goto Cleanup;
  1054. } else if ( WorkContext->NextCommand == SMB_COM_WRITE_AND_CLOSE ) {
  1055. WorkContext->Parameters.LastWriteTime = SmbGetUlong(
  1056. &((PREQ_WRITE_AND_CLOSE)request)->LastWriteTimeInSeconds );
  1057. }
  1058. //
  1059. // If everything worked, build a response message. (If something
  1060. // failed, an error indication has already been placed in the SMB.)
  1061. //
  1062. if ( WorkContext->NextCommand == SMB_COM_WRITE_PRINT_FILE ) {
  1063. //
  1064. // ByteCount has a different offset for WRITE_PRINT_FILE
  1065. //
  1066. PRESP_WRITE_PRINT_FILE response2;
  1067. response2 = (PRESP_WRITE_PRINT_FILE)WorkContext->ResponseParameters;
  1068. response2->WordCount = 0;
  1069. SmbPutUshort( &response2->ByteCount, 0 );
  1070. WorkContext->ResponseParameters =
  1071. NEXT_LOCATION( response2, RESP_WRITE_PRINT_FILE, 0 );
  1072. } else {
  1073. response->WordCount = 1;
  1074. SmbPutUshort( &response->Count, writeLength );
  1075. SmbPutUshort( &response->ByteCount, 0 );
  1076. WorkContext->ResponseParameters =
  1077. NEXT_LOCATION( response, RESP_WRITE, 0 );
  1078. }
  1079. }
  1080. //
  1081. // If this was a Write and Close request, close the file. It is
  1082. // safe to close the RFCB here because if this is a Write and Close,
  1083. // we're actually in the FSP, not in the FSD.
  1084. //
  1085. if ( WorkContext->NextCommand == SMB_COM_WRITE_AND_CLOSE ) {
  1086. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  1087. SrvRestartChainedClose( WorkContext );
  1088. goto Cleanup;
  1089. }
  1090. //
  1091. // Processing of the SMB is complete. Send the response.
  1092. //
  1093. SrvFsdSendResponse( WorkContext );
  1094. IF_DEBUG(FSD2) SrvPrint0( "SrvFsdRestartWrite complete\n" );
  1095. Cleanup:
  1096. if (bNeedTrace) {
  1097. SrvWmiEndContext(WorkContext);
  1098. }
  1099. return;
  1100. } // SrvFsdRestartWrite
  1101. VOID SRVFASTCALL
  1102. SrvFsdRestartPrepareMdlWriteAndX (
  1103. IN OUT PWORK_CONTEXT WorkContext
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. Processes the MDL preparation completion for the large WriteAndX SMB.
  1108. This routine initiates the receipt of transport data into the file's MDL,
  1109. and then control resumes at SrvFsdRestartWriteAndX when the transfer of data
  1110. from the transport is complete.
  1111. Arguments:
  1112. WorkContext - Supplies a pointer to the work context block
  1113. describing server-specific context for the request.
  1114. --*/
  1115. {
  1116. PIRP irp = WorkContext->Irp;
  1117. PIO_STACK_LOCATION irpSp;
  1118. PTDI_REQUEST_KERNEL_RECEIVE parameters;
  1119. //
  1120. // Make sure we call SrvFsdRestartWriteAndX at passive level when
  1121. // the TDI receive completes.
  1122. //
  1123. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1124. WorkContext->FspRestartRoutine = SrvFsdRestartWriteAndX;
  1125. //
  1126. // Make sure that we record the MDL address we're using
  1127. //
  1128. ASSERT( WorkContext->Parameters.WriteAndX.MdlAddress == NULL );
  1129. WorkContext->Parameters.WriteAndX.MdlAddress = irp->MdlAddress;
  1130. if( !NT_SUCCESS( irp->IoStatus.Status ) ) {
  1131. //
  1132. // Something went wrong. Early-out to SrvFsdRestartWriteAndX.
  1133. //
  1134. if( KeGetCurrentIrql() < DISPATCH_LEVEL ) {
  1135. SrvFsdRestartWriteAndX( WorkContext );
  1136. } else {
  1137. QUEUE_WORK_TO_FSP( WorkContext );
  1138. }
  1139. return;
  1140. }
  1141. ASSERT( irp->MdlAddress != NULL );
  1142. //
  1143. // Fill in the IRP for the TDI receive. We want to receive the data into
  1144. // the buffer described by the MDL we've just gotten
  1145. //
  1146. irp->Tail.Overlay.OriginalFileObject = NULL;
  1147. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1148. irpSp = IoGetNextIrpStackLocation( irp );
  1149. //
  1150. // Set up the completion routine
  1151. //
  1152. IoSetCompletionRoutine(
  1153. irp,
  1154. SrvFsdIoCompletionRoutine,
  1155. WorkContext,
  1156. TRUE,
  1157. TRUE,
  1158. TRUE
  1159. );
  1160. SET_OPERATION_START_TIME( &WorkContext );
  1161. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1162. irpSp->MinorFunction = (UCHAR)TDI_RECEIVE;
  1163. irpSp->FileObject = WorkContext->Connection->FileObject;
  1164. irpSp->DeviceObject = WorkContext->Connection->DeviceObject;
  1165. irpSp->Flags = 0;
  1166. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  1167. parameters->ReceiveLength = WorkContext->Parameters.WriteAndX.CurrentWriteLength;
  1168. parameters->ReceiveFlags = 0;
  1169. //
  1170. // Account for the amount we are taking in
  1171. //
  1172. WorkContext->Parameters.WriteAndX.RemainingWriteLength -=
  1173. WorkContext->Parameters.WriteAndX.CurrentWriteLength;
  1174. irp->AssociatedIrp.SystemBuffer = NULL;
  1175. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  1176. irp->IoStatus.Status = 0;
  1177. ASSERT( irp->MdlAddress != NULL );
  1178. (VOID)IoCallDriver( irpSp->DeviceObject, irp );
  1179. //
  1180. // Processing resumes at SrvFsdRestartWriteAndX() when we've received
  1181. // the data from the transport. We will be at passive level.
  1182. //
  1183. }
  1184. VOID SRVFASTCALL
  1185. RestartLargeWriteAndX (
  1186. IN OUT PWORK_CONTEXT WorkContext
  1187. )
  1188. /*++
  1189. Routine Description:
  1190. This is the restart routine that's invoked when we have received more data from
  1191. the transport, and we are not using MDLs to transfer the data into the file.
  1192. This routine initiates the write to the file, and then control resumes at
  1193. SrvFsdRestartWriteAndX when the write to the file is complete.
  1194. Arguments:
  1195. WorkContext - Supplies a pointer to the work context block
  1196. describing server-specific context for the request.
  1197. --*/
  1198. {
  1199. PIRP irp = WorkContext->Irp;
  1200. ULONG length;
  1201. PRFCB rfcb = WorkContext->Rfcb;
  1202. PLFCB lfcb = rfcb->Lfcb;
  1203. //
  1204. // Check if we successfully received more data from the transport
  1205. //
  1206. if( irp->Cancel ||
  1207. (!NT_SUCCESS( irp->IoStatus.Status )
  1208. && irp->IoStatus.Status != STATUS_BUFFER_OVERFLOW) ){
  1209. SrvSetSmbError( WorkContext, irp->IoStatus.Status );
  1210. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1211. return;
  1212. }
  1213. //
  1214. // We got more data from the transport. We need to write it out to the file if we
  1215. // haven't encountered any errors yet. The irp at this point holds the results of
  1216. // reading more data from the transport.
  1217. //
  1218. length = (ULONG)irp->IoStatus.Information;
  1219. //
  1220. // Adjust the parameters in the WorkContext
  1221. //
  1222. WorkContext->Parameters.WriteAndX.RemainingWriteLength -= length;
  1223. WorkContext->Parameters.WriteAndX.CurrentWriteLength = length;
  1224. //
  1225. // If we have picked up an error, we just want to keep reading from
  1226. // the transport and not write to the file.
  1227. //
  1228. if( WorkContext->Parameters.WriteAndX.FinalStatus ) {
  1229. //
  1230. // Indicate that we didn't write any more data to the file
  1231. //
  1232. WorkContext->Irp->IoStatus.Information = 0;
  1233. WorkContext->Irp->IoStatus.Status = WorkContext->Parameters.WriteAndX.FinalStatus;
  1234. SrvFsdRestartWriteAndX( WorkContext );
  1235. return;
  1236. }
  1237. //
  1238. // Write the data to the file
  1239. //
  1240. if( lfcb->FastIoWrite != NULL ) {
  1241. try {
  1242. if( lfcb->FastIoWrite(
  1243. lfcb->FileObject,
  1244. &WorkContext->Parameters.WriteAndX.Offset,
  1245. WorkContext->Parameters.WriteAndX.CurrentWriteLength,
  1246. TRUE,
  1247. WorkContext->Parameters.WriteAndX.Key,
  1248. WorkContext->Parameters.WriteAndX.WriteAddress,
  1249. &WorkContext->Irp->IoStatus,
  1250. lfcb->DeviceObject
  1251. ) ) {
  1252. //
  1253. // The fast I/O path worked. Call the restart routine directly
  1254. // to do postprocessing
  1255. //
  1256. SrvFsdRestartWriteAndX( WorkContext );
  1257. return;
  1258. }
  1259. }
  1260. except( EXCEPTION_EXECUTE_HANDLER ) {
  1261. // Fall through to the slow path on an exception
  1262. NTSTATUS status = GetExceptionCode();
  1263. IF_DEBUG(ERRORS) {
  1264. KdPrint(("FastIoRead threw exception %x\n", status ));
  1265. }
  1266. }
  1267. }
  1268. //
  1269. // The fast path failed, use the IRP to write the data to the file
  1270. //
  1271. IoBuildPartialMdl(
  1272. WorkContext->RequestBuffer->Mdl,
  1273. WorkContext->RequestBuffer->PartialMdl,
  1274. WorkContext->Parameters.WriteAndX.WriteAddress,
  1275. WorkContext->Parameters.WriteAndX.CurrentWriteLength
  1276. );
  1277. //
  1278. // Build the IRP.
  1279. //
  1280. SrvBuildReadOrWriteRequest(
  1281. WorkContext->Irp, // input IRP address
  1282. lfcb->FileObject, // target file object address
  1283. WorkContext, // context
  1284. IRP_MJ_WRITE, // major function code
  1285. 0, // minor function code
  1286. WorkContext->Parameters.WriteAndX.WriteAddress,
  1287. WorkContext->Parameters.WriteAndX.CurrentWriteLength,
  1288. WorkContext->RequestBuffer->PartialMdl,
  1289. WorkContext->Parameters.WriteAndX.Offset,
  1290. WorkContext->Parameters.WriteAndX.Key
  1291. );
  1292. //
  1293. // Ensure that processing resumes in SrvFsdRestartWriteAndX when the
  1294. // write has completed. If this is the first part of a large write,
  1295. // we want to ensure that SrvFsdRestartWriteAndX is called at passive
  1296. // level because it might decide to use the cache manager to handle the
  1297. // rest of the write.
  1298. //
  1299. if ( WorkContext->Parameters.WriteAndX.InitialComplete ) {
  1300. WorkContext->FsdRestartRoutine = SrvFsdRestartWriteAndX;
  1301. } else {
  1302. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1303. WorkContext->FspRestartRoutine = SrvFsdRestartWriteAndX;
  1304. }
  1305. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1306. //
  1307. // Processing resumes at SrvFsdRestartWriteAndX() when the file write
  1308. // is complete.
  1309. //
  1310. }
  1311. VOID SRVFASTCALL
  1312. SrvFsdRestartWriteAndX (
  1313. IN OUT PWORK_CONTEXT WorkContext
  1314. )
  1315. /*++
  1316. Routine Description:
  1317. This routine may be called in the FSD or the FSP. If the chained
  1318. command is Close, it will be called in the FSP.
  1319. If WorkContext->LargeIndication is set, this means we are processing
  1320. the flavor of WriteAndX that exceeds our negotiated buffer size. There may
  1321. be more data that we need to fetch from the transport. We may or may not be
  1322. doing MDL writes to the file.
  1323. If there is no more data to be gotten from the transport, we send the response
  1324. to the client.
  1325. Arguments:
  1326. WorkContext - Supplies a pointer to the work context block
  1327. describing server-specific context for the request.
  1328. --*/
  1329. {
  1330. PREQ_WRITE_ANDX request;
  1331. PREQ_NT_WRITE_ANDX ntRequest;
  1332. PRESP_WRITE_ANDX response;
  1333. PRFCB rfcb = WorkContext->Rfcb;
  1334. PIRP irp = WorkContext->Irp;
  1335. NTSTATUS status = irp->IoStatus.Status;
  1336. ULONG writeLength = (ULONG)irp->IoStatus.Information;
  1337. ULONG requestedWriteLength;
  1338. UCHAR nextCommand;
  1339. USHORT nextOffset;
  1340. USHORT reqAndXOffset;
  1341. LARGE_INTEGER position;
  1342. KIRQL oldIrql;
  1343. BOOLEAN bNeedTrace = (WorkContext->bAlreadyTrace == FALSE);
  1344. PREQ_CLOSE closeRequest;
  1345. UNLOCKABLE_CODE( 8FIL );
  1346. if (bNeedTrace) {
  1347. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1348. WorkContext->PreviousSMB = EVENT_TYPE_SMB_WRITE_AND_X;
  1349. SrvWmiStartContext(WorkContext);
  1350. }
  1351. else
  1352. WorkContext->bAlreadyTrace = FALSE;
  1353. IF_DEBUG(FSD2) SrvPrint0( " - SrvFsdRestartWriteAndX\n" );
  1354. //
  1355. // Get the request and response parameter pointers.
  1356. //
  1357. request = (PREQ_WRITE_ANDX)WorkContext->RequestParameters;
  1358. ntRequest = (PREQ_NT_WRITE_ANDX)WorkContext->RequestParameters;
  1359. response = (PRESP_WRITE_ANDX)WorkContext->ResponseParameters;
  1360. IF_DEBUG(FSD2) {
  1361. SrvPrint2( " connection 0x%p, RFCB 0x%p\n",
  1362. WorkContext->Connection, rfcb );
  1363. }
  1364. //
  1365. // If we are using MDL transfers and we have more data to get from the client
  1366. // then STATUS_BUFFER_OVERFLOW is simply an indication from the transport that
  1367. // it has more data to give to us. We consider that a success case for the
  1368. // purposes of this routine.
  1369. //
  1370. if( status == STATUS_BUFFER_OVERFLOW &&
  1371. WorkContext->LargeIndication &&
  1372. WorkContext->Parameters.WriteAndX.MdlAddress &&
  1373. WorkContext->Parameters.WriteAndX.RemainingWriteLength ) {
  1374. status = STATUS_SUCCESS;
  1375. }
  1376. //
  1377. // Remember where the follow-on request begins, and what the next
  1378. // command is, as we are about to overwrite this information.
  1379. //
  1380. reqAndXOffset = SmbGetUshort( &request->AndXOffset );
  1381. nextCommand = request->AndXCommand;
  1382. WorkContext->NextCommand = nextCommand;
  1383. nextOffset = SmbGetUshort( &request->AndXOffset );
  1384. //
  1385. // If the write failed, set an error status in the response header.
  1386. // We still return a valid parameter block, in case some bytes were
  1387. // written before the error occurred. Note that we do _not_ process
  1388. // the next command if the write failed.
  1389. //
  1390. // *** OS/2 server behavior. Note that this is _not_ done for core
  1391. // Write.
  1392. //
  1393. if ( !NT_SUCCESS(status) ) {
  1394. IF_DEBUG(ERRORS) SrvPrint1( "Write failed: %X\n", status );
  1395. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  1396. WorkContext->FspRestartRoutine = SrvFsdRestartWriteAndX;
  1397. QUEUE_WORK_TO_FSP( WorkContext );
  1398. goto Cleanup;
  1399. }
  1400. if( WorkContext->LargeIndication ) {
  1401. //
  1402. // Once this error code is set, we cease writing to the file. But
  1403. // we still need to consume the rest of the data that was sent to us
  1404. // by the client.
  1405. //
  1406. WorkContext->Parameters.WriteAndX.FinalStatus = status;
  1407. }
  1408. SrvSetSmbError( WorkContext, status );
  1409. nextCommand = SMB_COM_NO_ANDX_COMMAND;
  1410. }
  1411. //
  1412. // Update the file position.
  1413. //
  1414. if ( rfcb->ShareType != ShareTypePipe ) {
  1415. //
  1416. // We will ignore the distinction between clients that supply 32-bit
  1417. // and 64-bit file offsets. The reason for doing this is because
  1418. // the only clients that will use CurrentPosition is a 32-bit file
  1419. // offset client. Therefore, the upper 32-bits will never be used
  1420. // anyway. In addition, the RFCB is per client, so there is no
  1421. // possibility of clients mixing 32-bit and 64-bit file offsets.
  1422. // Therefore, for the 64-bit client, we will only read 32-bits of file
  1423. // offset.
  1424. //
  1425. if ( request->ByteCount == 12 ) {
  1426. //
  1427. // The client supplied a 32-bit file offset.
  1428. //
  1429. rfcb->CurrentPosition = SmbGetUlong( &request->Offset ) + writeLength;
  1430. } else {
  1431. //
  1432. // The client supplied a 64-bit file offset. Only use 32-bits of
  1433. // file offset.
  1434. //
  1435. rfcb->CurrentPosition = SmbGetUlong( &ntRequest->Offset ) + writeLength;
  1436. }
  1437. }
  1438. //
  1439. // Save the count of bytes written, to be used to update the server
  1440. // statistics database.
  1441. //
  1442. UPDATE_WRITE_STATS( WorkContext, writeLength );
  1443. IF_SMB_DEBUG(READ_WRITE1) {
  1444. SrvPrint2( "SrvFsdRestartWriteAndX: Fid 0x%lx, wrote %ld bytes\n",
  1445. rfcb->Fid, writeLength );
  1446. }
  1447. //
  1448. // If we are doing large transfers, and there is still more to go, then we
  1449. // need to keep the cycle going.
  1450. //
  1451. if( WorkContext->LargeIndication &&
  1452. WorkContext->Parameters.WriteAndX.RemainingWriteLength ) {
  1453. PIO_STACK_LOCATION irpSp;
  1454. PTDI_REQUEST_KERNEL_RECEIVE parameters;
  1455. LARGE_INTEGER PreviousWriteOffset;
  1456. BOOLEAN fAppending = TRUE;
  1457. PreviousWriteOffset = WorkContext->Parameters.WriteAndX.Offset;
  1458. //
  1459. // If we are only appending, do not change the offset
  1460. //
  1461. if( PreviousWriteOffset.QuadPart != 0xFFFFFFFFFFFFFFFF ) {
  1462. WorkContext->Parameters.WriteAndX.Offset.QuadPart += writeLength;
  1463. fAppending = FALSE;
  1464. }
  1465. //
  1466. // If we haven't tried an MDL write yet, or if we are already using
  1467. // MDLs, then we want to keep using MDLs
  1468. //
  1469. if( NT_SUCCESS( status ) && fAppending == FALSE &&
  1470. ( WorkContext->Parameters.WriteAndX.InitialComplete == FALSE ||
  1471. ( WorkContext->Parameters.WriteAndX.MdlAddress &&
  1472. WorkContext->Parameters.WriteAndX.RemainingWriteLength != 0 )
  1473. ) ) {
  1474. PLFCB lfcb = rfcb->Lfcb;
  1475. NTSTATUS mdlStatus;
  1476. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  1477. WorkContext->Parameters.WriteAndX.InitialComplete = TRUE;
  1478. //
  1479. // If we already have an MDL, complete it now since we've already asked
  1480. // TDI to fill the buffer.
  1481. //
  1482. if( WorkContext->Parameters.WriteAndX.MdlAddress ) {
  1483. irp->MdlAddress = WorkContext->Parameters.WriteAndX.MdlAddress;
  1484. irp->IoStatus.Information = writeLength;
  1485. if( lfcb->MdlWriteComplete == NULL ||
  1486. lfcb->MdlWriteComplete( lfcb->FileObject,
  1487. &PreviousWriteOffset,
  1488. WorkContext->Parameters.WriteAndX.MdlAddress,
  1489. lfcb->DeviceObject
  1490. ) == FALSE ) {
  1491. mdlStatus = SrvIssueMdlCompleteRequest( WorkContext,
  1492. NULL,
  1493. WorkContext->Parameters.WriteAndX.MdlAddress,
  1494. IRP_MJ_WRITE,
  1495. &PreviousWriteOffset,
  1496. writeLength
  1497. );
  1498. if( !NT_SUCCESS( mdlStatus ) ) {
  1499. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, mdlStatus );
  1500. if( NT_SUCCESS( status ) ) {
  1501. WorkContext->Parameters.WriteAndX.FinalStatus = status = mdlStatus;
  1502. }
  1503. }
  1504. }
  1505. //
  1506. // We have disposed of this MDL, get it out of our structures!
  1507. //
  1508. WorkContext->Parameters.WriteAndX.MdlAddress = NULL;
  1509. irp->MdlAddress = NULL;
  1510. }
  1511. //
  1512. // If we have more than 1 buffer's worth remaing, and if the filesystem
  1513. // supports MDL writes, then let's do MDL writes
  1514. //
  1515. if( NT_SUCCESS( status ) &&
  1516. (WorkContext->Parameters.WriteAndX.RemainingWriteLength >
  1517. WorkContext->Parameters.WriteAndX.BufferLength) &&
  1518. (lfcb->FileObject->Flags & FO_CACHE_SUPPORTED) ) {
  1519. LARGE_INTEGER offset;
  1520. ULONG remainingLength;
  1521. irp->IoStatus.Information = 0;
  1522. irp->UserBuffer = NULL;
  1523. irp->MdlAddress = NULL;
  1524. //
  1525. // Figure out how big we want this MDL attempt to be. We could
  1526. // map the whole thing in, but we don't want any single client request
  1527. // to lock down too much of the cache.
  1528. //
  1529. WorkContext->Parameters.WriteAndX.CurrentWriteLength = MIN (
  1530. WorkContext->Parameters.WriteAndX.RemainingWriteLength,
  1531. SrvMaxWriteChunk
  1532. );
  1533. if( lfcb->PrepareMdlWrite(
  1534. lfcb->FileObject,
  1535. &WorkContext->Parameters.WriteAndX.Offset,
  1536. WorkContext->Parameters.WriteAndX.CurrentWriteLength,
  1537. WorkContext->Parameters.WriteAndX.Key,
  1538. &irp->MdlAddress,
  1539. &irp->IoStatus,
  1540. lfcb->DeviceObject
  1541. ) && irp->MdlAddress != NULL ) {
  1542. //
  1543. // The fast path worked!
  1544. //
  1545. SrvFsdRestartPrepareMdlWriteAndX( WorkContext );
  1546. goto Cleanup;
  1547. }
  1548. //
  1549. // The fast path failed, build the write request. The fast path
  1550. // may have partially succeeded, returning a partial MDL chain.
  1551. // We need to adjust our write request to account for that.
  1552. //
  1553. offset.QuadPart = WorkContext->Parameters.WriteAndX.Offset.QuadPart;
  1554. //
  1555. // If we are not just appending, adjust the offset
  1556. //
  1557. if( offset.QuadPart != 0xFFFFFFFFFFFFFFFF ) {
  1558. offset.QuadPart += irp->IoStatus.Information;
  1559. }
  1560. remainingLength = WorkContext->Parameters.WriteAndX.CurrentWriteLength -
  1561. (ULONG)irp->IoStatus.Information;
  1562. SrvBuildReadOrWriteRequest(
  1563. irp, // input IRP address
  1564. lfcb->FileObject, // target file object address
  1565. WorkContext, // context
  1566. IRP_MJ_WRITE, // major function code
  1567. IRP_MN_MDL, // minor function code
  1568. NULL, // buffer address (ignored)
  1569. remainingLength,
  1570. irp->MdlAddress,
  1571. offset,
  1572. WorkContext->Parameters.WriteAndX.Key
  1573. );
  1574. WorkContext->bAlreadyTrace = TRUE;
  1575. WorkContext->FsdRestartRoutine = SrvFsdRestartPrepareMdlWriteAndX;
  1576. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1577. goto Cleanup;
  1578. }
  1579. }
  1580. //
  1581. // We aren't doing MDL operations, so read the data from the transport into
  1582. // the SMB buffer.
  1583. //
  1584. WorkContext->Parameters.WriteAndX.CurrentWriteLength = MIN(
  1585. WorkContext->Parameters.WriteAndX.RemainingWriteLength,
  1586. WorkContext->Parameters.WriteAndX.BufferLength
  1587. );
  1588. //
  1589. // Fill in the IRP for the receive
  1590. //
  1591. irp->Tail.Overlay.OriginalFileObject = NULL;
  1592. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1593. DEBUG irp->RequestorMode = KernelMode;
  1594. //
  1595. // Get a pointer to the next stack location. This one is used to
  1596. // hold the parameters for the device I/O control request.
  1597. //
  1598. irpSp = IoGetNextIrpStackLocation( irp );
  1599. //
  1600. // Set up the completion routine
  1601. //
  1602. IoSetCompletionRoutine(
  1603. irp,
  1604. SrvFsdIoCompletionRoutine,
  1605. WorkContext,
  1606. TRUE,
  1607. TRUE,
  1608. TRUE
  1609. );
  1610. SET_OPERATION_START_TIME( &WorkContext );
  1611. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1612. WorkContext->FspRestartRoutine = RestartLargeWriteAndX;
  1613. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1614. irpSp->MinorFunction = (UCHAR)TDI_RECEIVE;
  1615. irpSp->FileObject = WorkContext->Connection->FileObject;
  1616. irpSp->DeviceObject = WorkContext->Connection->DeviceObject;
  1617. irpSp->Flags = 0;
  1618. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  1619. parameters->ReceiveLength = WorkContext->Parameters.WriteAndX.CurrentWriteLength;
  1620. parameters->ReceiveFlags = 0;
  1621. //
  1622. // Set the buffer's partial mdl to point just after the header for this
  1623. // WriteAndX SMB. We need to preserve the header to make it easier to send
  1624. // back the response.
  1625. //
  1626. IoBuildPartialMdl(
  1627. WorkContext->RequestBuffer->Mdl,
  1628. WorkContext->RequestBuffer->PartialMdl,
  1629. WorkContext->Parameters.WriteAndX.WriteAddress,
  1630. WorkContext->Parameters.WriteAndX.CurrentWriteLength
  1631. );
  1632. irp->MdlAddress = WorkContext->RequestBuffer->PartialMdl;
  1633. irp->AssociatedIrp.SystemBuffer = NULL;
  1634. irp->Flags = (ULONG)IRP_BUFFERED_IO; // ???
  1635. (VOID)IoCallDriver( irpSp->DeviceObject, irp );
  1636. goto Cleanup;
  1637. }
  1638. //
  1639. // We have no more data to write to the file. Clean up
  1640. // and send a response to the client
  1641. //
  1642. //
  1643. // If we are working on a large write using MDLs,
  1644. // then we need to clean up the MDL
  1645. //
  1646. if( WorkContext->LargeIndication &&
  1647. WorkContext->Parameters.WriteAndX.MdlAddress ) {
  1648. PLFCB lfcb = rfcb->Lfcb;
  1649. NTSTATUS mdlStatus;
  1650. ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  1651. irp->MdlAddress = WorkContext->Parameters.WriteAndX.MdlAddress;
  1652. irp->IoStatus.Information = writeLength;
  1653. //
  1654. // Tell the filesystem that we're done with it
  1655. //
  1656. if( lfcb->MdlWriteComplete == NULL ||
  1657. lfcb->MdlWriteComplete( lfcb->FileObject,
  1658. &WorkContext->Parameters.WriteAndX.Offset,
  1659. WorkContext->Parameters.WriteAndX.MdlAddress,
  1660. lfcb->DeviceObject
  1661. ) == FALSE ) {
  1662. mdlStatus = SrvIssueMdlCompleteRequest( WorkContext, NULL,
  1663. WorkContext->Parameters.WriteAndX.MdlAddress,
  1664. IRP_MJ_WRITE,
  1665. &WorkContext->Parameters.WriteAndX.Offset,
  1666. writeLength
  1667. );
  1668. if( !NT_SUCCESS( mdlStatus ) ) {
  1669. SrvLogServiceFailure( SRV_SVC_MDL_COMPLETE, mdlStatus );
  1670. if( NT_SUCCESS( status ) ) {
  1671. status = mdlStatus;
  1672. }
  1673. }
  1674. }
  1675. irp->MdlAddress = NULL;
  1676. }
  1677. //
  1678. // Build the response message.
  1679. //
  1680. requestedWriteLength = SmbGetUshort( &request->DataLength );
  1681. if( WorkContext->LargeIndication ) {
  1682. requestedWriteLength |= (SmbGetUshort( &ntRequest->DataLengthHigh ) << 16);
  1683. writeLength = requestedWriteLength -
  1684. WorkContext->Parameters.WriteAndX.RemainingWriteLength;
  1685. }
  1686. SmbPutUlong( &response->Reserved, 0 );
  1687. SmbPutUshort( &response->CountHigh, (USHORT)(writeLength >> 16) );
  1688. response->AndXCommand = nextCommand;
  1689. response->AndXReserved = 0;
  1690. SmbPutUshort(
  1691. &response->AndXOffset,
  1692. GET_ANDX_OFFSET(
  1693. WorkContext->ResponseHeader,
  1694. WorkContext->ResponseParameters,
  1695. RESP_WRITE_ANDX,
  1696. 0
  1697. )
  1698. );
  1699. response->WordCount = 6;
  1700. if ( rfcb->ShareType == ShareTypeDisk ||
  1701. WorkContext->Parameters.Transaction == NULL ) {
  1702. SmbPutUshort( &response->Count, (USHORT)writeLength );
  1703. } else {
  1704. SmbPutUshort( &response->Count, (USHORT)requestedWriteLength );
  1705. }
  1706. SmbPutUshort( &response->Remaining, (USHORT)-1 );
  1707. SmbPutUshort( &response->ByteCount, 0 );
  1708. WorkContext->ResponseParameters = (PCHAR)WorkContext->ResponseHeader +
  1709. SmbGetUshort( &response->AndXOffset );
  1710. WorkContext->RequestParameters = (PUCHAR)WorkContext->RequestHeader + reqAndXOffset;
  1711. IF_STRESS() {
  1712. // If this was a paging write that failed, log an error
  1713. PNT_SMB_HEADER pHeader = (PNT_SMB_HEADER)WorkContext->RequestHeader;
  1714. if( !NT_SUCCESS(pHeader->Status.NtStatus) && (pHeader->Flags2 & SMB_FLAGS2_PAGING_IO) )
  1715. {
  1716. KdPrint(("Paging Write failure from %z (%x)\n", (PCSTRING)&WorkContext->Connection->OemClientMachineNameString, pHeader->Status.NtStatus ));
  1717. }
  1718. }
  1719. //
  1720. // If this was a raw mode write, queue the work to the FSP for
  1721. // completion. The FSP routine will handling dispatching of the
  1722. // AndX command.
  1723. //
  1724. if ( rfcb->ShareType != ShareTypeDisk &&
  1725. WorkContext->Parameters.Transaction != NULL ) {
  1726. WorkContext->FspRestartRoutine = SrvRestartWriteAndXRaw;
  1727. SrvQueueWorkToFsp( WorkContext );
  1728. goto Cleanup;
  1729. }
  1730. if( nextCommand == SMB_COM_NO_ANDX_COMMAND ) {
  1731. //
  1732. // No more commands. Send the response.
  1733. //
  1734. SrvFsdSendResponse( WorkContext );
  1735. goto Cleanup;
  1736. }
  1737. //
  1738. // Make sure the AndX command is still within the received SMB
  1739. //
  1740. if( (PCHAR)WorkContext->RequestHeader + reqAndXOffset >= END_OF_REQUEST_SMB( WorkContext ) ) {
  1741. IF_DEBUG(SMB_ERRORS) {
  1742. KdPrint(( "SrvFsdRestartWriteAndX: Illegal followon offset: %u\n", reqAndXOffset ));
  1743. }
  1744. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  1745. WorkContext->Irp->IoStatus.Status = STATUS_INVALID_SMB;
  1746. WorkContext->FspRestartRoutine = SrvBuildAndSendErrorResponse;
  1747. WorkContext->FsdRestartRoutine = SrvFsdRestartSmbComplete; // after response
  1748. QUEUE_WORK_TO_FSP( WorkContext );
  1749. } else {
  1750. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1751. SrvFsdSendResponse( WorkContext );
  1752. }
  1753. goto Cleanup;
  1754. }
  1755. //
  1756. // Test for a legal followon command, and dispatch as appropriate.
  1757. // Close is handled specially.
  1758. //
  1759. switch ( nextCommand ) {
  1760. case SMB_COM_READ:
  1761. case SMB_COM_READ_ANDX:
  1762. case SMB_COM_LOCK_AND_READ:
  1763. case SMB_COM_WRITE_ANDX:
  1764. //
  1765. // Queue the work item back to the FSP for further processing.
  1766. //
  1767. WorkContext->FspRestartRoutine = SrvRestartSmbReceived;
  1768. SrvQueueWorkToFsp( WorkContext );
  1769. break;
  1770. case SMB_COM_CLOSE:
  1771. //
  1772. // Save the last write time, to correctly set it. Call
  1773. // SrvRestartChainedClose to close the file and send the response.
  1774. //
  1775. closeRequest = (PREQ_CLOSE)
  1776. ((PUCHAR)WorkContext->RequestHeader + reqAndXOffset);
  1777. //
  1778. // Make sure we stay within the received SMB
  1779. //
  1780. if( (PCHAR)closeRequest + FIELD_OFFSET( REQ_CLOSE, ByteCount)
  1781. <= END_OF_REQUEST_SMB( WorkContext ) ) {
  1782. WorkContext->Parameters.LastWriteTime =
  1783. closeRequest->LastWriteTimeInSeconds;
  1784. SrvRestartChainedClose( WorkContext );
  1785. break;
  1786. }
  1787. /* Falls Through! */
  1788. default: // Illegal followon command
  1789. IF_DEBUG(SMB_ERRORS) {
  1790. SrvPrint1( "SrvFsdRestartWriteAndX: Illegal followon "
  1791. "command: 0x%lx\n", nextCommand );
  1792. }
  1793. if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
  1794. WorkContext->Irp->IoStatus.Status = STATUS_INVALID_SMB;
  1795. WorkContext->FspRestartRoutine = SrvBuildAndSendErrorResponse;
  1796. WorkContext->FsdRestartRoutine = SrvFsdRestartSmbComplete; // after response
  1797. QUEUE_WORK_TO_FSP( WorkContext );
  1798. } else {
  1799. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1800. SrvFsdSendResponse( WorkContext );
  1801. }
  1802. }
  1803. IF_DEBUG(TRACE2) SrvPrint0( "SrvFsdRestartWriteAndX complete\n" );
  1804. Cleanup:
  1805. if (bNeedTrace) {
  1806. SrvWmiEndContext(WorkContext);
  1807. }
  1808. return;
  1809. } // SrvFsdRestartWriteAndX
  1810. #if SRVCATCH
  1811. BYTE CatchPrototype[] = ";UUIDREF=";
  1812. VOID
  1813. SrvUpdateCatchBuffer (
  1814. IN PWORK_CONTEXT WorkContext,
  1815. IN OUT PBYTE Buffer,
  1816. IN DWORD BufferLength
  1817. )
  1818. {
  1819. BYTE idBuffer[ 100 ];
  1820. PBYTE p, ep = idBuffer;
  1821. USHORT bytesRemaining = sizeof( idBuffer );
  1822. UNICODE_STRING userName, domainName;
  1823. OEM_STRING oemString;
  1824. ULONG requiredLength;
  1825. if( BufferLength <= sizeof( CatchPrototype ) ) {
  1826. return;
  1827. }
  1828. if( WorkContext->Session == 0 ) {
  1829. SrvVerifyUid( WorkContext, SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid ) );
  1830. }
  1831. if( WorkContext->Session &&
  1832. NT_SUCCESS( SrvGetUserAndDomainName( WorkContext->Session, &userName, &domainName ) ) ) {
  1833. if( userName.Length && NT_SUCCESS( RtlUnicodeStringToOemString( &oemString, &userName, TRUE ) ) ) {
  1834. if( bytesRemaining >= oemString.Length + 1 ) {
  1835. RtlCopyMemory( ep, oemString.Buffer, oemString.Length );
  1836. ep += oemString.Length;
  1837. *ep++ = '\\';
  1838. bytesRemaining -= (oemString.Length + 1);
  1839. RtlFreeOemString( &oemString );
  1840. }
  1841. }
  1842. if( domainName.Length && NT_SUCCESS( RtlUnicodeStringToOemString( &oemString, &domainName, TRUE ) ) ) {
  1843. if( bytesRemaining >= oemString.Length ) {
  1844. RtlCopyMemory( ep, oemString.Buffer, oemString.Length );
  1845. ep += oemString.Length;
  1846. bytesRemaining -= oemString.Length;
  1847. RtlFreeOemString( &oemString );
  1848. }
  1849. }
  1850. SrvReleaseUserAndDomainName( WorkContext->Session, &userName, &domainName );
  1851. }
  1852. if( WorkContext->Connection && bytesRemaining ) {
  1853. oemString = WorkContext->Connection->OemClientMachineNameString;
  1854. if( oemString.Length && oemString.Length < bytesRemaining + 1 ) {
  1855. *ep++ = ' ';
  1856. RtlCopyMemory( ep, oemString.Buffer, oemString.Length );
  1857. ep += oemString.Length;
  1858. bytesRemaining -= oemString.Length;
  1859. }
  1860. }
  1861. //
  1862. // Insert the CatchPrototype into the output buffer
  1863. //
  1864. if( WorkContext->Rfcb->SrvCatch == 1 )
  1865. {
  1866. RtlCopyMemory( Buffer, CatchPrototype, sizeof( CatchPrototype )-1 );
  1867. Buffer += sizeof( CatchPrototype )-1;
  1868. BufferLength -= (sizeof( CatchPrototype ) - 1);
  1869. //
  1870. // Encode the information
  1871. //
  1872. for( p = idBuffer; BufferLength >= 3 && p < ep; p++, BufferLength =- 2 ) {
  1873. *Buffer++ = SrvHexChars[ ((*p) >> 4) & 0xf ];
  1874. *Buffer++ = SrvHexChars[ (*p) & 0xf ];
  1875. }
  1876. if( BufferLength >= 3 ) {
  1877. *Buffer++ = '\r';
  1878. *Buffer++ = '\n';
  1879. *Buffer++ = ';';
  1880. }
  1881. }
  1882. else if( WorkContext->Rfcb->SrvCatch == 2 )
  1883. {
  1884. PBYTE InnerBuffer;
  1885. ULONG Offset;
  1886. Offset = SrvFindCatchOffset( Buffer, BufferLength );
  1887. if( Offset )
  1888. {
  1889. InnerBuffer = Buffer + Offset;
  1890. BufferLength = 1020;
  1891. RtlCopyMemory( InnerBuffer, CatchPrototype, sizeof( CatchPrototype )-1 );
  1892. InnerBuffer += sizeof( CatchPrototype )-1;
  1893. BufferLength -= (sizeof( CatchPrototype ) - 1);
  1894. //
  1895. // Encode the information
  1896. //
  1897. for( p = idBuffer; BufferLength >= 3 && p < ep; p++, BufferLength =- 2 ) {
  1898. *InnerBuffer++ = SrvHexChars[ ((*p) >> 4) & 0xf ];
  1899. *InnerBuffer++ = SrvHexChars[ (*p) & 0xf ];
  1900. }
  1901. if( BufferLength >= 3 ) {
  1902. *InnerBuffer++ = '\r';
  1903. *InnerBuffer++ = '\n';
  1904. *InnerBuffer++ = ';';
  1905. }
  1906. SrvCorrectCatchBuffer( Buffer, Offset );
  1907. }
  1908. }
  1909. }
  1910. #endif