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.

844 lines
29 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 Microsoft Corporation
  3. Module Name:
  4. write.c
  5. Abstract:
  6. This module implements the mini redirector call down routines pertaining
  7. to write of file system objects.
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. #pragma warning(error:4101) // Unreferenced local variable
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, MRxSmbWrite)
  14. #pragma alloc_text(PAGE, MRxSmbBuildWriteRequest)
  15. #pragma alloc_text(PAGE, SmbPseExchangeStart_Write)
  16. #pragma alloc_text(PAGE, MRxSmbFinishWrite)
  17. #endif
  18. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_WRITE)
  23. #ifndef FORCE_NO_NTWRITEANDX
  24. #define MRxSmbForceNoNtWriteAndX FALSE
  25. #else
  26. BOOLEAN MRxSmbForceNoNtWriteAndX = TRUE;
  27. #endif
  28. #define WRITE_COPY_THRESHOLD 64
  29. #define FORCECOPYMODE FALSE
  30. #ifdef SETFORCECOPYMODE
  31. #undef FORCECOPYMODE
  32. #define FORCECOPYMODE MRxSmbForceCopyMode
  33. ULONG MRxSmbForceCopyMode = TRUE;
  34. #endif
  35. NTSTATUS
  36. SmbPseExchangeStart_Write(
  37. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  38. );
  39. ULONG MRxSmbWriteSendOptions = 0;
  40. NTSTATUS
  41. MRxSmbWrite (
  42. IN PRX_CONTEXT RxContext)
  43. /*++
  44. Routine Description:
  45. This routine opens a file across the network.
  46. Arguments:
  47. RxContext - the RDBSS context
  48. Return Value:
  49. NTSTATUS - The return status for the operation
  50. --*/
  51. {
  52. NTSTATUS Status = STATUS_SUCCESS;
  53. RxCaptureFcb;
  54. RxCaptureFobx;
  55. PMRX_SRV_OPEN SrvOpen;
  56. PMRX_SMB_SRV_OPEN smbSrvOpen;
  57. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  58. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  59. PAGED_CODE();
  60. RxDbgTrace(+1, Dbg, ("MRxSmbWrite\n", 0 ));
  61. if (RxContext->pFcb->pNetRoot->Type == NET_ROOT_PIPE) {
  62. Status = STATUS_NOT_SUPPORTED;
  63. RxDbgTrace(-1, Dbg, ("MRxSmbWrite: Pipe write returned %lx\n",Status));
  64. return Status;
  65. }
  66. if ( NodeType(capFcb) == RDBSS_NTC_MAILSLOT ) {
  67. Status = STATUS_NOT_SUPPORTED;
  68. RxDbgTrace(-1, Dbg, ("MRxSmbWrite: Mailslot write returned %lx\n",Status));
  69. return Status;
  70. }
  71. if(NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE) {
  72. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  73. smbFcb->MFlags |= SMB_FCB_FLAG_WRITES_PERFORMED;
  74. }
  75. ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
  76. SrvOpen = capFobx->pSrvOpen;
  77. smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  78. if (smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_II &&
  79. !BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
  80. LOWIO_READWRITEFLAG_PAGING_IO)) {
  81. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  82. PMRX_SRV_CALL pSrvCall;
  83. pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)SrvOpen->pVNetRoot->Context;
  84. pSrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  85. RxIndicateChangeOfBufferingStateForSrvOpen(
  86. pSrvCall,
  87. SrvOpen,
  88. MRxSmbMakeSrvOpenKey(pVNetRootContext->TreeId,smbSrvOpen->Fid),
  89. ULongToPtr(SMB_OPLOCK_LEVEL_NONE));
  90. SmbCeLog(("Breaking oplock to None in Write SO %lx\n",SrvOpen));
  91. }
  92. do {
  93. Status = __SmbPseCreateOrdinaryExchange(
  94. RxContext,
  95. capFobx->pSrvOpen->pVNetRoot,
  96. SMBPSE_OE_FROM_WRITE,
  97. SmbPseExchangeStart_Write,
  98. &OrdinaryExchange);
  99. if (Status != STATUS_SUCCESS) {
  100. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  101. return Status;
  102. }
  103. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  104. if ( Status != STATUS_PENDING ) {
  105. BOOLEAN FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  106. ASSERT( FinalizationComplete );
  107. } else {
  108. ASSERT(BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  109. }
  110. if ((Status == STATUS_RETRY) &&
  111. BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  112. MRxSmbResumeAsyncReadWriteRequests(RxContext);
  113. Status = STATUS_PENDING;
  114. }
  115. } while (Status == STATUS_RETRY);
  116. RxDbgTrace(-1, Dbg, ("MRxSmbWrite exit with status=%08lx\n", Status ));
  117. return(Status);
  118. } // MRxSmbWrite
  119. NTSTATUS
  120. MRxSmbBuildWriteRequest(
  121. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  122. BOOLEAN IsPagingIo,
  123. UCHAR WriteCommand,
  124. ULONG ByteCount,
  125. PLARGE_INTEGER ByteOffsetAsLI,
  126. PBYTE Buffer,
  127. PMDL BufferAsMdl)
  128. /*++
  129. Routine Description:
  130. This is the start routine for write.
  131. Arguments:
  132. pExchange - the exchange instance
  133. Return Value:
  134. NTSTATUS - The return status for the operation
  135. --*/
  136. {
  137. NTSTATUS Status;
  138. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  139. PRX_CONTEXT RxContext = StufferState->RxContext;
  140. RxCaptureFcb;
  141. RxCaptureFobx;
  142. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  143. PNT_SMB_HEADER NtSmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
  144. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  145. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  146. ULONG OffsetLow,OffsetHigh;
  147. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  148. USHORT WriteMode = 0;
  149. ULONG DataLengthLow,DataLengthHigh;
  150. ULONG BytesRemaining = 0;
  151. BOOLEAN AddLengthBytes = FALSE;
  152. ULONG WriteCommandSize;
  153. PSMBCE_SERVER pServer = SmbCeGetExchangeServer((PSMB_EXCHANGE)OrdinaryExchange);
  154. BOOLEAN UseNtVersion;
  155. UseNtVersion = BooleanFlagOn(pServer->DialectFlags,DF_NT_SMBS) &&
  156. !MRxSmbForceNoNtWriteAndX;
  157. // The data length field in SMB is a USHORT, and hence the data length given
  158. // needs to be split up into two parts -- DataLengthHigh and DataLengthLow
  159. DataLengthLow = (ByteCount & 0xffff);
  160. DataLengthHigh = ((ByteCount & 0xffff0000) >> 16);
  161. OffsetLow = ByteOffsetAsLI->LowPart;
  162. OffsetHigh = ByteOffsetAsLI->HighPart;
  163. switch (WriteCommand) {
  164. case SMB_COM_WRITE_ANDX:
  165. WriteCommandSize = SMB_REQUEST_SIZE(NT_WRITE_ANDX);
  166. break;
  167. case SMB_COM_WRITE:
  168. WriteCommandSize = SMB_REQUEST_SIZE(WRITE);
  169. break;
  170. case SMB_COM_WRITE_PRINT_FILE:
  171. WriteCommandSize = SMB_REQUEST_SIZE(WRITE_PRINT_FILE);
  172. break;
  173. }
  174. Status = MRxSmbStartSMBCommand(
  175. StufferState,
  176. SetInitialSMB_Never,
  177. WriteCommand,
  178. WriteCommandSize,
  179. NO_EXTRA_DATA,
  180. NO_SPECIAL_ALIGNMENT,
  181. RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  182. 0,0,0,0 STUFFERTRACE(Dbg,'FC'));
  183. MRxSmbDumpStufferState(
  184. 1000,
  185. "SMB Write Request before stuffing",
  186. StufferState);
  187. switch (WriteCommand) {
  188. case SMB_COM_WRITE_ANDX :
  189. {
  190. if ( UseNtVersion && IsPagingIo ) {
  191. SmbPutAlignedUshort(
  192. &NtSmbHeader->Flags2,
  193. SmbGetAlignedUshort(&NtSmbHeader->Flags2)|SMB_FLAGS2_PAGING_IO );
  194. }
  195. //
  196. // If the file object was opened in write through mode, set write
  197. // through on the write operation.
  198. if (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WRITE_THROUGH)) {
  199. WriteMode |= SMB_WMODE_WRITE_THROUGH;
  200. }
  201. MRxSmbStuffSMB (
  202. StufferState,
  203. "XwddwwwwQ",
  204. // X UCHAR WordCount;
  205. // UCHAR AndXCommand;
  206. // UCHAR AndXReserved;
  207. // _USHORT( AndXOffset );
  208. smbSrvOpen->Fid, // w _USHORT( Fid );
  209. OffsetLow, // d _ULONG( Offset );
  210. -1, // d _ULONG( Timeout );
  211. WriteMode, // w _USHORT( WriteMode );
  212. BytesRemaining, // w _USHORT( Remaining );
  213. DataLengthHigh, // w _USHORT( DataLengthHigh );
  214. DataLengthLow, // w _USHORT( DataLength );
  215. // Q _USHORT( DataOffset );
  216. SMB_OFFSET_CHECK(WRITE_ANDX,DataOffset)
  217. StufferCondition(UseNtVersion), "D",
  218. SMB_OFFSET_CHECK(NT_WRITE_ANDX,OffsetHigh)
  219. OffsetHigh, // D NTonly _ULONG( OffsetHigh );
  220. //
  221. STUFFER_CTL_NORMAL, "BS5",
  222. // B _USHORT( ByteCount );
  223. SMB_WCT_CHECK(((UseNtVersion)?14:12))
  224. // UCHAR Buffer[1];
  225. // S //UCHAR Pad[];
  226. // 5 //UCHAR Data[];
  227. StufferCondition(AddLengthBytes), "w", LowIoContext->ParamsFor.ReadWrite.ByteCount,
  228. StufferCondition(Buffer!=NULL), "c!",
  229. ByteCount,
  230. Buffer, // c the actual data
  231. 0
  232. );
  233. }
  234. break;
  235. case SMB_COM_WRITE :
  236. {
  237. MRxSmbStuffSMB (
  238. StufferState,
  239. "0wwdwByw",
  240. // 0 UCHAR WordCount; // Count of parameter words = 5
  241. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  242. DataLengthLow, // w _USHORT( Count ); // Number of bytes to be written
  243. OffsetLow, // d _ULONG( Offset ); // Offset in file to begin write
  244. BytesRemaining, // w _USHORT( Remaining ); // Bytes remaining to satisfy request
  245. SMB_WCT_CHECK(5) // B _USHORT( ByteCount ); // Count of data bytes
  246. // //UCHAR Buffer[1]; // Buffer containing:
  247. 0x01, // y UCHAR BufferFormat; // 0x01 -- Data block
  248. DataLengthLow, // w _USHORT( DataLength ); // Length of data
  249. // ULONG Buffer[1]; // Data
  250. StufferCondition(Buffer!=NULL), "c!",
  251. ByteCount,
  252. Buffer, // c the actual data
  253. 0
  254. );
  255. }
  256. break;
  257. case SMB_COM_WRITE_PRINT_FILE:
  258. {
  259. MRxSmbStuffSMB (
  260. StufferState,
  261. "0wByw",
  262. // 0 UCHAR WordCount; // Count of parameter words = 1
  263. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  264. SMB_WCT_CHECK(1) // B _USHORT( ByteCount ); // Count of data bytes; min = 4
  265. // UCHAR Buffer[1]; // Buffer containing:
  266. 0x01, // y //UCHAR BufferFormat; // 0x01 -- Data block
  267. DataLengthLow, // w //USHORT DataLength; // Length of data
  268. // //UCHAR Data[]; // Data
  269. StufferCondition(Buffer!=NULL), "c!",
  270. ByteCount,
  271. Buffer, // c the actual data
  272. 0
  273. );
  274. }
  275. break;
  276. default:
  277. Status = STATUS_UNSUCCESSFUL ;
  278. break;
  279. }
  280. if ( BufferAsMdl ) {
  281. MRxSmbStuffAppendRawData( StufferState, BufferAsMdl );
  282. MRxSmbStuffSetByteCount( StufferState );
  283. }
  284. MRxSmbDumpStufferState(
  285. 700,
  286. "SMB Write Request after stuffing",
  287. StufferState);
  288. if (Status==STATUS_SUCCESS) {
  289. InterlockedIncrement(&MRxSmbStatistics.SmallWriteSmbs);
  290. }
  291. return Status;
  292. }
  293. BOOLEAN DisableLargeWrites = 0;
  294. NTSTATUS
  295. SmbPseExchangeStart_Write (
  296. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  297. )
  298. /*++
  299. Routine Description:
  300. This is the start routine for write.
  301. Arguments:
  302. pExchange - the exchange instance
  303. Return Value:
  304. NTSTATUS - The return status for the operation
  305. --*/
  306. {
  307. NTSTATUS Status;
  308. ULONG StartEntryCount;
  309. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  310. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  311. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  312. PMDL OriginalDataMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
  313. RxCaptureFcb;
  314. RxCaptureFobx;
  315. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  316. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  317. PMRX_SMB_FCB SmbFcb = MRxSmbGetFcbExtension(capFcb);
  318. BOOLEAN SynchronousIo, IsPagingIo;
  319. BOOLEAN WriteToTheEnd = FALSE;
  320. UCHAR WriteCommand;
  321. PAGED_CODE();
  322. RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Write\n"));
  323. ASSERT( OrdinaryExchange->Type == ORDINARY_EXCHANGE );
  324. ASSERT(
  325. (
  326. (OriginalDataMdl!=NULL) &&
  327. (
  328. RxMdlIsLocked(OriginalDataMdl) ||
  329. RxMdlSourceIsNonPaged(OriginalDataMdl)
  330. )
  331. ) ||
  332. (
  333. (OriginalDataMdl==NULL) &&
  334. (LowIoContext->ParamsFor.ReadWrite.ByteCount==0)
  335. )
  336. );
  337. ASSERT((OrdinaryExchange->SmbCeFlags&SMBCE_EXCHANGE_ATTEMPT_RECONNECTS) == 0 );
  338. OrdinaryExchange->StartEntryCount++;
  339. StartEntryCount = OrdinaryExchange->StartEntryCount;
  340. SynchronousIo = !BooleanFlagOn(
  341. RxContext->Flags,
  342. RX_CONTEXT_FLAG_ASYNC_OPERATION);
  343. IsPagingIo = BooleanFlagOn(
  344. LowIoContext->ParamsFor.ReadWrite.Flags,
  345. LOWIO_READWRITEFLAG_PAGING_IO);
  346. // Ensure that the Fid is validated
  347. SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID);
  348. for (;;) {
  349. PSMBCE_SERVER pServer;
  350. PSMBCE_NET_ROOT pNetRoot;
  351. pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  352. pNetRoot = SmbCeGetExchangeNetRoot(OrdinaryExchange);
  353. switch (OrdinaryExchange->OpSpecificState) {
  354. case SmbPseOEInnerIoStates_Initial:
  355. {
  356. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
  357. if ( !SynchronousIo ) {
  358. OrdinaryExchange->AsyncResumptionRoutine = SmbPseExchangeStart_Write;
  359. }
  360. MRxSmbSetInitialSMB( StufferState STUFFERTRACE(Dbg,'FC') );
  361. rw->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
  362. rw->ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  363. rw->RemainingByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  364. if (rw->ByteOffsetAsLI.QuadPart == -1 ) {
  365. WriteToTheEnd = TRUE;
  366. rw->ByteOffsetAsLI.QuadPart = smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart;
  367. }
  368. if (OriginalDataMdl != NULL) {
  369. rw->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
  370. } else {
  371. rw->UserBufferBase = (PBYTE)1; //any nonzero value will do
  372. }
  373. rw->ThisBufferOffset = 0;
  374. rw->PartialExchangeMdlInUse = FALSE;
  375. rw->PartialDataMdlInUse = FALSE;
  376. }
  377. //lack of break is intentional
  378. case SmbPseOEInnerIoStates_ReadyToSend:
  379. {
  380. ULONG MaximumBufferSizeThisIteration;
  381. PCHAR Buffer = NULL;
  382. PMDL BufferAsMdl = NULL;
  383. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_OperationOutstanding;
  384. OrdinaryExchange->SendOptions = MRxSmbWriteSendOptions;
  385. if (FlagOn(pServer->DialectFlags,DF_LANMAN10) &&
  386. FlagOn(pServer->DialectFlags,DF_LARGE_FILES) &&
  387. (StufferState->RxContext->pFcb->pNetRoot->Type != NET_ROOT_PRINT)) {
  388. WriteCommand = SMB_COM_WRITE_ANDX;
  389. } else if (StufferState->RxContext->pFcb->pNetRoot->Type == NET_ROOT_PRINT){
  390. WriteCommand = SMB_COM_WRITE_PRINT_FILE;
  391. } else {
  392. WriteCommand = SMB_COM_WRITE;
  393. }
  394. MaximumBufferSizeThisIteration = pNetRoot->MaximumWriteBufferSize;
  395. // There are four parameters pertaining to a write request
  396. //
  397. // 1. Write Length -- rw->ThisByteCount
  398. // 2. Write Offset -- rw->ByteOffsetAsLI
  399. // 3. Write Buffer -- Buffer
  400. // 4. Write Buffer as a MDL -- BufferAsMdl
  401. //
  402. // All writes can be classified into one of the following
  403. // categories ...
  404. //
  405. // 1. Extremely Small writes
  406. // These are writes lesser than the COPY_THRESHOLD or
  407. // we are in a debug mode that forces us to do only small
  408. // writes.
  409. //
  410. // 2. Write requests against downlevel servers or non disk
  411. // file write requests against up level servers.
  412. // In all these cases we are constrained by the Server
  413. // which limits the number of bytes to roughly 4k. This
  414. // is based upon the Smb Buffer size returned during
  415. // negotiation.
  416. //
  417. // 3. Write requests against uplevel (NT5+)
  418. // servers
  419. // These write requests can be arbitrarily large
  420. //
  421. if ((rw->RemainingByteCount < WRITE_COPY_THRESHOLD) ||
  422. FORCECOPYMODE) {
  423. if (FORCECOPYMODE &&
  424. (rw->ThisByteCount > MaximumBufferSizeThisIteration) ) {
  425. rw->ThisByteCount = MaximumBufferSizeThisIteration;
  426. } else {
  427. rw->ThisByteCount = rw->RemainingByteCount;
  428. }
  429. Buffer = rw->UserBufferBase + rw->ThisBufferOffset;
  430. ASSERT( WRITE_COPY_THRESHOLD <= pNetRoot->MaximumWriteBufferSize );
  431. } else {
  432. rw->ThisByteCount = min(
  433. rw->RemainingByteCount,
  434. MaximumBufferSizeThisIteration);
  435. if ((rw->ThisBufferOffset != 0) ||
  436. (rw->ThisByteCount != OriginalDataMdl->ByteCount)) {
  437. MmInitializeMdl(
  438. &rw->PartialDataMdl,
  439. 0,
  440. MAX_PARTIAL_DATA_MDL_BUFFER_SIZE);
  441. IoBuildPartialMdl(
  442. OriginalDataMdl,
  443. &rw->PartialDataMdl,
  444. (PCHAR)MmGetMdlVirtualAddress(OriginalDataMdl) +
  445. rw->ThisBufferOffset,
  446. rw->ThisByteCount );
  447. BufferAsMdl = &rw->PartialDataMdl;
  448. } else {
  449. BufferAsMdl = OriginalDataMdl;
  450. }
  451. }
  452. Status = MRxSmbBuildWriteRequest(
  453. OrdinaryExchange,
  454. IsPagingIo,
  455. WriteCommand,
  456. rw->ThisByteCount,
  457. &rw->ByteOffsetAsLI,
  458. Buffer,
  459. BufferAsMdl);
  460. if (Status != STATUS_SUCCESS) {
  461. RxDbgTrace(0, Dbg, ("bad write stuffer status........\n"));
  462. goto FINALLY;
  463. }
  464. InterlockedIncrement(&MRxSmbStatistics.WriteSmbs);
  465. Status = SmbPseOrdinaryExchange(
  466. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  467. SMBPSE_OETYPE_WRITE );
  468. if ( Status == STATUS_PENDING) {
  469. ASSERT( !SynchronousIo );
  470. goto FINALLY;
  471. }
  472. }
  473. //lack of break is intentional
  474. case SmbPseOEInnerIoStates_OperationOutstanding:
  475. case SmbPseOEInnerIoStates_OperationCompleted:
  476. {
  477. SetFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_SUBSEQUENT_OPERATION);
  478. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
  479. if (rw->PartialExchangeMdlInUse) {
  480. MmPrepareMdlForReuse(
  481. &rw->PartialExchangeMdl);
  482. rw->PartialDataMdlInUse = FALSE;
  483. }
  484. if (rw->PartialDataMdlInUse) {
  485. MmPrepareMdlForReuse(
  486. &rw->PartialDataMdl);
  487. rw->PartialDataMdlInUse = FALSE;
  488. }
  489. Status = OrdinaryExchange->Status;
  490. if (Status == STATUS_SMB_USE_STANDARD) {
  491. // Send the remaining data using Restart all over again and
  492. rw->UserBufferBase = RxLowIoGetBufferAddress( RxContext );
  493. rw->ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
  494. rw->RemainingByteCount = LowIoContext->ParamsFor.ReadWrite.ByteCount;
  495. if (rw->ByteOffsetAsLI.QuadPart == -1 ) {
  496. WriteToTheEnd = TRUE;
  497. rw->ByteOffsetAsLI.QuadPart = smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart;
  498. }
  499. rw->BytesReturned = 0;
  500. rw->ThisByteCount = 0;
  501. rw->ThisBufferOffset = 0;
  502. RxContext->InformationToReturn = 0;
  503. OrdinaryExchange->Status = STATUS_SUCCESS;
  504. Status = STATUS_SUCCESS;
  505. }
  506. rw->RemainingByteCount -= rw->BytesReturned;
  507. RxContext->InformationToReturn += rw->BytesReturned;
  508. if (Status == STATUS_SUCCESS) {
  509. rw->ByteOffsetAsLI.QuadPart += rw->BytesReturned;
  510. rw->ThisBufferOffset += rw->BytesReturned;
  511. if (WriteToTheEnd) {
  512. smbSrvOpen->FileInfo.Standard.EndOfFile.QuadPart += rw->BytesReturned;
  513. }
  514. }
  515. if ((Status != STATUS_SUCCESS) ||
  516. (rw->RemainingByteCount == 0)) {
  517. PSMBCE_SESSION pSession = SmbCeGetExchangeSession(OrdinaryExchange);
  518. RxDbgTrace(
  519. 0,
  520. Dbg,
  521. (
  522. "OE %lx TBC %lx RBC %lx BR %lx TBO %lx\n",
  523. OrdinaryExchange,rw->ThisByteCount,
  524. rw->RemainingByteCount,
  525. rw->BytesReturned,
  526. rw->ThisBufferOffset )
  527. );
  528. RxDbgTrace(
  529. 0,
  530. Dbg,
  531. ("Bytes written %lx\n",
  532. RxContext->InformationToReturn)
  533. );
  534. goto FINALLY;
  535. }
  536. RxDbgTrace(
  537. 0,
  538. Dbg,
  539. ( "Next Iteration OE %lx RBC %lx TBO %lx\n",
  540. OrdinaryExchange,
  541. rw->RemainingByteCount,
  542. rw->ThisBufferOffset)
  543. );
  544. RxDbgTrace(
  545. 0,
  546. Dbg,
  547. ("OE %lx TBC %lx, BR %lx\n",
  548. OrdinaryExchange,
  549. rw->ThisByteCount,
  550. rw->BytesReturned));
  551. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
  552. }
  553. break;
  554. }
  555. }
  556. FINALLY:
  557. if ( Status != STATUS_PENDING) {
  558. if (Status != STATUS_RETRY) {
  559. SmbPseAsyncCompletionIfNecessary(OrdinaryExchange,RxContext);
  560. }
  561. }
  562. RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Write exit w %08lx\n", Status ));
  563. return Status;
  564. } // SmbPseExchangeStart_Write
  565. NTSTATUS
  566. MRxSmbFinishWrite (
  567. IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  568. IN PBYTE ResponseBuffer
  569. )
  570. /*++
  571. Routine Description:
  572. This routine actually gets the stuff out of the write response and finishes
  573. the write. Everything you need is locked down... so we can finish in the
  574. indication routine
  575. Arguments:
  576. OrdinaryExchange - the exchange instance
  577. ResponseBuffer - the response
  578. Return Value:
  579. RXSTATUS - The return status for the operation
  580. --*/
  581. {
  582. NTSTATUS Status = STATUS_SUCCESS;
  583. ULONG BytesReturned;
  584. PAGED_CODE();
  585. RxDbgTrace(+1, Dbg, ("MRxSmbFinishWrite\n"));
  586. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishWrite:");
  587. switch (OrdinaryExchange->LastSmbCommand) {
  588. case SMB_COM_WRITE_ANDX:
  589. {
  590. PSMBCE_SERVER pServer;
  591. PSMBCE_NET_ROOT pNetRoot;
  592. PRESP_WRITE_ANDX Response = (PRESP_WRITE_ANDX)ResponseBuffer;
  593. if (Response->WordCount != 6 ||
  594. SmbGetUshort(&Response->ByteCount) != 0) {
  595. Status = STATUS_INVALID_NETWORK_RESPONSE;
  596. }
  597. pServer = SmbCeGetExchangeServer((PSMB_EXCHANGE)OrdinaryExchange);
  598. pNetRoot = SmbCeGetExchangeNetRoot((PSMB_EXCHANGE)OrdinaryExchange);
  599. BytesReturned = SmbGetUshort( &Response->Count );
  600. if (FlagOn(pServer->DialectFlags,DF_LARGE_WRITEX)) {
  601. ULONG BytesReturnedHigh;
  602. BytesReturnedHigh = SmbGetUshort(&Response->CountHigh);
  603. BytesReturned = (BytesReturnedHigh << 16) | BytesReturned;
  604. }
  605. if ((OrdinaryExchange->Status == STATUS_SUCCESS) &&
  606. (OrdinaryExchange->ReadWrite.ThisByteCount > 2) &&
  607. (BytesReturned == 0)) {
  608. Status = STATUS_INVALID_NETWORK_RESPONSE;
  609. }
  610. //if we added 2 headerbytes then let's get rid of them......
  611. if ( FlagOn(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_REDUCE_RETURNCOUNT) ) {
  612. // BytesReturned -= sizeof(USHORT);
  613. ClearFlag(OrdinaryExchange->OpSpecificFlags,OE_RW_FLAG_REDUCE_RETURNCOUNT);
  614. }
  615. }
  616. break;
  617. case SMB_COM_WRITE :
  618. {
  619. PRESP_WRITE Response = (PRESP_WRITE)ResponseBuffer;
  620. if (Response->WordCount != 1 ||
  621. SmbGetUshort(&Response->ByteCount) != 0) {
  622. Status = STATUS_INVALID_NETWORK_RESPONSE;
  623. }
  624. BytesReturned = SmbGetUshort( &Response->Count );
  625. }
  626. break;
  627. case SMB_COM_WRITE_PRINT_FILE:
  628. {
  629. PRESP_WRITE_PRINT_FILE Response = (PRESP_WRITE_PRINT_FILE)ResponseBuffer;
  630. if (Response->WordCount != 0) {
  631. Status = STATUS_INVALID_NETWORK_RESPONSE;
  632. }
  633. //the response does not tell how many bytes were taken! get the byte count from the exchange
  634. BytesReturned = OrdinaryExchange->ReadWrite.ThisByteCount;
  635. }
  636. break;
  637. default :
  638. Status = STATUS_INVALID_NETWORK_RESPONSE;
  639. break;
  640. }
  641. RxDbgTrace(0, Dbg, ("-->BytesReturned=%08lx\n", BytesReturned));
  642. OrdinaryExchange->ReadWrite.BytesReturned = BytesReturned;
  643. if (Status == STATUS_SUCCESS &&
  644. OrdinaryExchange->ReadWrite.ThisByteCount > 2 &&
  645. BytesReturned > OrdinaryExchange->ReadWrite.ThisByteCount) {
  646. Status = STATUS_INVALID_NETWORK_RESPONSE;
  647. }
  648. RxDbgTrace(-1, Dbg, ("MRxSmbFinishWrite returning %08lx\n", Status ));
  649. return Status;
  650. } // MRxSmbFinishWrite
  651.