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.

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