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.

1147 lines
44 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. locks.c
  5. Abstract:
  6. This module implements the mini redirector call down routines pertaining to locks
  7. of file system objects.
  8. Author:
  9. Joe Linn [JoeLi] 7-March-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #pragma warning(error:4101) // Unreferenced local variable
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, MRxSmbLocks)
  17. #pragma alloc_text(PAGE, MRxSmbBuildLocksAndX)
  18. #pragma alloc_text(PAGE, MRxSmbBuildLockAssert)
  19. #pragma alloc_text(PAGE, SmbPseExchangeStart_Locks)
  20. #pragma alloc_text(PAGE, MRxSmbFinishLocks)
  21. #pragma alloc_text(PAGE, MRxSmbUnlockRoutine)
  22. #pragma alloc_text(PAGE, MRxSmbCompleteBufferingStateChangeRequest)
  23. #pragma alloc_text(PAGE, MRxSmbBuildFlush)
  24. #pragma alloc_text(PAGE, MRxSmbFlush)
  25. #pragma alloc_text(PAGE, MRxSmbIsLockRealizable)
  26. #pragma alloc_text(PAGE, MRxSmbFinishFlush)
  27. #endif
  28. //
  29. // The local debug trace level
  30. //
  31. #define Dbg (DEBUG_TRACE_LOCKCTRL)
  32. NTSTATUS
  33. SmbPseExchangeStart_Locks(
  34. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  35. );
  36. ULONG MRxSmbSrvLockBufSize = 0xffff;
  37. ULONG MRxSmbLockSendOptions = 0; //use the default options
  38. NTSTATUS
  39. MRxSmbBuildFlush (
  40. PSMBSTUFFER_BUFFER_STATE StufferState
  41. );
  42. NTSTATUS
  43. MRxSmbLocks(
  44. IN PRX_CONTEXT RxContext)
  45. /*++
  46. Routine Description:
  47. This routine handles network requests for filelocks
  48. Arguments:
  49. RxContext - the RDBSS context
  50. Return Value:
  51. RXSTATUS - The return status for the operation
  52. --*/
  53. {
  54. NTSTATUS Status = STATUS_SUCCESS;
  55. RxCaptureFcb;
  56. RxCaptureFobx;
  57. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  58. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  59. PAGED_CODE();
  60. RxDbgTrace(+1, Dbg, ("MRxSmbLocks\n", 0 ));
  61. ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
  62. Status = SmbPseCreateOrdinaryExchange(RxContext,
  63. SrvOpen->pVNetRoot,
  64. SMBPSE_OE_FROM_LOCKS,
  65. SmbPseExchangeStart_Locks,
  66. &OrdinaryExchange
  67. );
  68. if (Status != STATUS_SUCCESS) {
  69. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  70. return(Status);
  71. }
  72. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  73. if (Status!=RX_MAP_STATUS(PENDING)) {
  74. BOOLEAN FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  75. ASSERT(FinalizationComplete);
  76. }
  77. RxDbgTrace(-1, Dbg, ("MRxSmbLocks exit with status=%08lx\n", Status ));
  78. return(Status);
  79. }
  80. NTSTATUS
  81. MRxSmbBuildLocksAndX (
  82. PSMBSTUFFER_BUFFER_STATE StufferState
  83. )
  84. /*++
  85. Routine Description:
  86. This builds a LockingAndX SMB for a single unlock or a single lock.
  87. Arguments:
  88. StufferState - the state of the smbbuffer from the stuffer's point of view
  89. Return Value:
  90. RXSTATUS
  91. SUCCESS
  92. NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
  93. Notes:
  94. --*/
  95. {
  96. NTSTATUS Status;
  97. PRX_CONTEXT RxContext = StufferState->RxContext;
  98. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  99. RxCaptureFcb;RxCaptureFobx;
  100. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
  101. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(StufferState->Exchange);
  102. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  103. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  104. PLARGE_INTEGER ByteOffsetAsLI,LengthAsLI;
  105. USHORT NumberOfLocks,NumberOfUnlocks;
  106. BOOLEAN UseLockList = FALSE;
  107. //ULONG OffsetLow,OffsetHigh;
  108. PAGED_CODE();
  109. RxDbgTrace(+1, Dbg, ("MRxSmbBuildLocksAndX\n"));
  110. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  111. switch (LowIoContext->Operation) {
  112. case LOWIO_OP_SHAREDLOCK:
  113. case LOWIO_OP_EXCLUSIVELOCK:
  114. NumberOfLocks = 1; NumberOfUnlocks = 0;
  115. break;
  116. case LOWIO_OP_UNLOCK:
  117. NumberOfLocks = 0; NumberOfUnlocks = 1;
  118. break;
  119. case LOWIO_OP_UNLOCK_MULTIPLE:
  120. //CODE.IMPROVEMENT these should be sent in groups....not one at a time!
  121. NumberOfLocks = 0; NumberOfUnlocks = 1;
  122. UseLockList = TRUE;
  123. break;
  124. }
  125. if (!UseLockList) {
  126. ByteOffsetAsLI = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.ByteOffset;
  127. LengthAsLI = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.Length;
  128. } else {
  129. //it's okay that this code is big.....see the C.I. above
  130. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  131. PLOWIO_LOCK_LIST LockList = rw->LockList;
  132. ByteOffsetAsLI = (PLARGE_INTEGER)&LockList->ByteOffset;
  133. LengthAsLI = (PLARGE_INTEGER)&LockList->Length;
  134. RxDbgTrace(0, Dbg, ("MRxSmbBuildLocksAndX using locklist, byteoffptr,lengthptr=%08lx,%08lx\n",
  135. ByteOffsetAsLI, LengthAsLI ));
  136. //DbgBreakPoint();
  137. }
  138. if (FlagOn(pServer->DialectFlags,DF_LANMAN20)) {
  139. ULONG SharedLock = (LowIoContext->Operation==LOWIO_OP_SHAREDLOCK);
  140. ULONG Timeout = (LowIoContext->ParamsFor.Locks.Flags&LOWIO_LOCKSFLAG_FAIL_IMMEDIATELY)?0:0xffffffff;
  141. ULONG UseLargeOffsets = LOCKING_ANDX_LARGE_FILES;
  142. if (!FlagOn(pServer->DialectFlags,DF_NT_SMBS)) {
  143. UseLargeOffsets = 0;
  144. }
  145. COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_Never, SMB_COM_LOCKING_ANDX,
  146. SMB_REQUEST_SIZE(LOCKING_ANDX),
  147. NO_EXTRA_DATA,NO_SPECIAL_ALIGNMENT,RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  148. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  149. );
  150. MRxSmbDumpStufferState (1000,"SMB w/ NTLOCKS&X before stuffing",StufferState);
  151. MRxSmbStuffSMB (StufferState,
  152. "XwwDwwB?",
  153. // X UCHAR WordCount; // Count of parameter words = 8
  154. // UCHAR AndXCommand; // Secondary (X) command; 0xFF = none
  155. // UCHAR AndXReserved; // Reserved (must be 0)
  156. // _USHORT( AndXOffset ); // Offset to next command WordCount
  157. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  158. //
  159. // //
  160. // // When NT protocol is not negotiated the OplockLevel field is
  161. // // omitted, and LockType field is a full word. Since the upper
  162. // // bits of LockType are never used, this definition works for
  163. // // all protocols.
  164. // //
  165. //
  166. SharedLock // w UCHAR( LockType ); // Locking mode:
  167. +UseLargeOffsets,
  168. // // bit 0: 0 = lock out all access
  169. // // 1 = read OK while locked
  170. // // bit 1: 1 = 1 user total file unlock
  171. // UCHAR( OplockLevel ); // The new oplock level
  172. SMB_OFFSET_CHECK(LOCKING_ANDX,Timeout)
  173. Timeout, // D _ULONG( Timeout );
  174. NumberOfUnlocks, // w _USHORT( NumberOfUnlocks ); // Num. unlock range structs following
  175. NumberOfLocks, // w _USHORT( NumberOfLocks ); // Num. lock range structs following
  176. SMB_WCT_CHECK(8) 0
  177. // B? _USHORT( ByteCount ); // Count of data bytes
  178. // UCHAR Buffer[1]; // Buffer containing:
  179. // //LOCKING_ANDX_RANGE Unlocks[]; // Unlock ranges
  180. // //LOCKING_ANDX_RANGE Locks[]; // Lock ranges
  181. );
  182. if (UseLargeOffsets) {
  183. //NTversion
  184. //CODE.IMPROVEMENT put in some kind of facility to do an offset check here
  185. MRxSmbStuffSMB (StufferState,
  186. "wwdddd!",
  187. // typedef struct _NT_LOCKING_ANDX_RANGE {
  188. MRXSMB_PROCESS_ID , // w _USHORT( Pid ); // PID of process "owning" lock
  189. 0, // w _USHORT( Pad ); // Pad to DWORD align (mbz)
  190. ByteOffsetAsLI->HighPart,// d _ULONG( OffsetHigh ); // Ofset to bytes to [un]lock (high)
  191. ByteOffsetAsLI->LowPart, // d _ULONG( OffsetLow ); // Ofset to bytes to [un]lock (low)
  192. LengthAsLI->HighPart, // d _ULONG( LengthHigh ); // Number of bytes to [un]lock (high)
  193. LengthAsLI->LowPart // d _ULONG( LengthLow ); // Number of bytes to [un]lock (low)
  194. // } NTLOCKING_ANDX_RANGE;
  195. );
  196. } else {
  197. MRxSmbStuffSMB (StufferState,
  198. "wdd!",
  199. MRXSMB_PROCESS_ID , // typedef struct _LOCKING_ANDX_RANGE {
  200. // w _USHORT( Pid ); // PID of process "owning" lock
  201. // d _ULONG( Offset ); // Ofset to bytes to [un]lock
  202. ByteOffsetAsLI->LowPart,
  203. // d _ULONG( Length ); // Number of bytes to [un]lock
  204. LengthAsLI->LowPart
  205. // } LOCKING_ANDX_RANGE;
  206. );
  207. }
  208. MRxSmbDumpStufferState (700,"SMB w/ NTLOCKS&X after stuffing",StufferState);
  209. } else {
  210. //lockbyterange and unlockbyterange have the same format......
  211. COVERED_CALL(MRxSmbStartSMBCommand ( StufferState, SetInitialSMB_Never,
  212. (UCHAR)((NumberOfLocks==0)?SMB_COM_UNLOCK_BYTE_RANGE
  213. :SMB_COM_LOCK_BYTE_RANGE),
  214. SMB_REQUEST_SIZE(LOCK_BYTE_RANGE),
  215. NO_EXTRA_DATA,NO_SPECIAL_ALIGNMENT,RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  216. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  217. );
  218. MRxSmbDumpStufferState (1000,"SMB w/ corelocking before stuffing",StufferState);
  219. ASSERT(ByteOffsetAsLI->HighPart==0);
  220. ASSERT(LengthAsLI->HighPart==0);
  221. MRxSmbStuffSMB (StufferState,
  222. "0wddB!",
  223. // 0 UCHAR WordCount; // Count of parameter words = 5
  224. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  225. LengthAsLI->LowPart, // d _ULONG( Count ); // Count of bytes to lock
  226. ByteOffsetAsLI->LowPart, // d _ULONG( Offset ); // Offset from start of file
  227. // B! _USHORT( ByteCount ); // Count of data bytes = 0
  228. SMB_WCT_CHECK(5) 0
  229. // UCHAR Buffer[1]; // empty
  230. );
  231. MRxSmbDumpStufferState (700,"SMB w/ corelocking after stuffing",StufferState);
  232. }
  233. FINALLY:
  234. RxDbgTraceUnIndent(-1, Dbg);
  235. return(Status);
  236. }
  237. NTSTATUS
  238. MRxSmbBuildLockAssert (
  239. PSMBSTUFFER_BUFFER_STATE StufferState
  240. )
  241. /*++
  242. Routine Description:
  243. This builds a LockingAndX SMB for multiple locks by calling the lock enumerator.
  244. Arguments:
  245. StufferState - the state of the smbbuffer from the stuffer's point of view
  246. Return Value:
  247. RXSTATUS
  248. SUCCESS
  249. NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
  250. Notes:
  251. CODE.IMRPOVEMENT.ASHAMED this is just like the code in MRxSmbBuildLocksAndX; btw MRxSmbBuildLocksAndX
  252. doesn't build a locksandX
  253. CODE.IMPROVEMENT all of the checks to find out if a lock is of a valid type need to be moved
  254. before the call to the fsrtl lockpackage. if you can't handle it then you need to get out before it tries
  255. lock buffering. check this in on mark's bug
  256. --*/
  257. {
  258. NTSTATUS Status;
  259. PRX_CONTEXT RxContext = StufferState->RxContext;
  260. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  261. RxCaptureFcb;RxCaptureFobx;
  262. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
  263. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(StufferState->Exchange);
  264. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  265. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  266. PRX_LOCK_ENUMERATOR LockEnumerator = OrdinaryExchange->AssertLocks.LockEnumerator;
  267. ULONG UseLargeOffsets;
  268. BOOLEAN LocksExclusiveForThisPacket = TRUE;
  269. PBYTE PtrToLockCount;
  270. PAGED_CODE();
  271. RxDbgTrace(+1, Dbg, ("MRxSmbBuildLockAssert enum=%08lx\n",LockEnumerator));
  272. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  273. if (smbSrvOpen->Fid == 0xffff) {
  274. return STATUS_FILE_CLOSED;
  275. }
  276. RxDbgTrace(0,Dbg,("Oplock response for FID(%lx)\n",smbSrvOpen->Fid));
  277. UseLargeOffsets = FlagOn(pServer->DialectFlags,DF_NT_SMBS)?LOCKING_ANDX_LARGE_FILES:0;
  278. //UseLargeOffsets = FALSE;
  279. OrdinaryExchange->AssertLocks.NumberOfLocksPlaced = 0;
  280. for (;;) {
  281. ASSERT_ORDINARY_EXCHANGE ( OrdinaryExchange );
  282. RxDbgTrace(0, Dbg, ("top of loop %08lx %08lx %08lx\n",
  283. OrdinaryExchange->AssertLocks.NumberOfLocksPlaced,
  284. OrdinaryExchange->AssertLocks.LockAreaNonEmpty,
  285. OrdinaryExchange->AssertLocks.EndOfListReached
  286. ));
  287. if (!OrdinaryExchange->AssertLocks.EndOfListReached
  288. && !OrdinaryExchange->AssertLocks.LockAreaNonEmpty) {
  289. //get a new lock
  290. //DbgBreakPoint();
  291. if (LockEnumerator(
  292. OrdinaryExchange->AssertLocks.SrvOpen,
  293. &OrdinaryExchange->AssertLocks.ContinuationHandle,
  294. &OrdinaryExchange->AssertLocks.NextLockOffset,
  295. &OrdinaryExchange->AssertLocks.NextLockRange,
  296. &OrdinaryExchange->AssertLocks.NextLockIsExclusive
  297. )){
  298. OrdinaryExchange->AssertLocks.LockAreaNonEmpty = TRUE;
  299. } else {
  300. OrdinaryExchange->AssertLocks.LockAreaNonEmpty = FALSE;
  301. OrdinaryExchange->AssertLocks.EndOfListReached = TRUE;
  302. OrdinaryExchange->AssertLocks.NextLockIsExclusive = TRUE;
  303. }
  304. }
  305. RxDbgTrace(0, Dbg, ("got a lockorempty %08lx %08lx %08lx\n",
  306. OrdinaryExchange->AssertLocks.NumberOfLocksPlaced,
  307. OrdinaryExchange->AssertLocks.LockAreaNonEmpty,
  308. OrdinaryExchange->AssertLocks.EndOfListReached
  309. ));
  310. //DbgBreakPoint();
  311. if (OrdinaryExchange->AssertLocks.NumberOfLocksPlaced == 0){
  312. ULONG Timeout = 0xffffffff;
  313. ULONG SharedLock = !OrdinaryExchange->AssertLocks.NextLockIsExclusive;
  314. LocksExclusiveForThisPacket = OrdinaryExchange->AssertLocks.NextLockIsExclusive;
  315. COVERED_CALL(MRxSmbStartSMBCommand (StufferState, SetInitialSMB_Never, SMB_COM_LOCKING_ANDX,
  316. SMB_REQUEST_SIZE(LOCKING_ANDX),
  317. NO_EXTRA_DATA,NO_SPECIAL_ALIGNMENT,RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  318. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  319. );
  320. MRxSmbDumpStufferState (1000,"SMB w/ NTLOCKS&X(assertbuf) before stuffing",StufferState);
  321. MRxSmbStuffSMB (StufferState,
  322. "XwrwDwrwB?",
  323. // X UCHAR WordCount; // Count of parameter words = 8
  324. // UCHAR AndXCommand; // Secondary (X) command; 0xFF = none
  325. // UCHAR AndXReserved; // Reserved (must be 0)
  326. // _USHORT( AndXOffset ); // Offset to next command WordCount
  327. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  328. //
  329. // //
  330. // // When NT protocol is not negotiated the OplockLevel field is
  331. // // omitted, and LockType field is a full word. Since the upper
  332. // // bits of LockType are never used, this definition works for
  333. // // all protocols.
  334. // //
  335. //
  336. // rw UCHAR( LockType ); // Locking mode:
  337. &OrdinaryExchange->AssertLocks.PtrToLockType,0,
  338. SharedLock+UseLargeOffsets,
  339. // // bit 0: 0 = lock out all access
  340. // // 1 = read OK while locked
  341. // // bit 1: 1 = 1 user total file unlock
  342. // UCHAR( OplockLevel ); // The new oplock level
  343. SMB_OFFSET_CHECK(LOCKING_ANDX,Timeout)
  344. Timeout, // D _ULONG( Timeout );
  345. 0, // w _USHORT( NumberOfUnlocks ); // Num. unlock range structs following
  346. // rw _USHORT( NumberOfLocks ); // Num. lock range structs following
  347. &PtrToLockCount,0,
  348. 0,
  349. SMB_WCT_CHECK(8) 0
  350. // B? _USHORT( ByteCount ); // Count of data bytes
  351. // UCHAR Buffer[1]; // Buffer containing:
  352. // //LOCKING_ANDX_RANGE Unlocks[]; // Unlock ranges
  353. // //LOCKING_ANDX_RANGE Locks[]; // Lock ranges
  354. );
  355. ASSERT_ORDINARY_EXCHANGE ( OrdinaryExchange );
  356. RxDbgTrace(0, Dbg, ("PTRS %08lx %08lx\n",
  357. OrdinaryExchange->AssertLocks.PtrToLockType,
  358. PtrToLockCount
  359. ));
  360. }
  361. if (OrdinaryExchange->AssertLocks.EndOfListReached
  362. || (LocksExclusiveForThisPacket != OrdinaryExchange->AssertLocks.NextLockIsExclusive)
  363. || (OrdinaryExchange->AssertLocks.NumberOfLocksPlaced >= 20) //CODE.IMPROVEMENT.ASHAMED
  364. // the lock limit will have to take cognizance of the remaining space in the buffer. this will be
  365. // different depending on whether a full buffer is used or a vestigial buffer. SO, this cannot just
  366. // be turned into another constant
  367. ){
  368. break;
  369. }
  370. ASSERT_ORDINARY_EXCHANGE ( OrdinaryExchange );
  371. if (UseLargeOffsets) {
  372. MRxSmbStuffSMB (StufferState,
  373. "wwdddd?",
  374. // typedef struct _NT_LOCKING_ANDX_RANGE {
  375. MRXSMB_PROCESS_ID , // w _USHORT( Pid ); // PID of process "owning" lock
  376. 0, // w _USHORT( Pad ); // Pad to DWORD align (mbz)
  377. // d _ULONG( OffsetHigh ); // Ofset to bytes to [un]lock (high)
  378. OrdinaryExchange->AssertLocks.NextLockOffset.HighPart,
  379. // d _ULONG( OffsetLow ); // Ofset to bytes to [un]lock (low)
  380. OrdinaryExchange->AssertLocks.NextLockOffset.LowPart,
  381. // d _ULONG( LengthHigh ); // Number of bytes to [un]lock (high)
  382. OrdinaryExchange->AssertLocks.NextLockRange.HighPart,
  383. // d _ULONG( LengthLow ); // Number of bytes to [un]lock (low)
  384. OrdinaryExchange->AssertLocks.NextLockRange.LowPart,
  385. // } NTLOCKING_ANDX_RANGE;
  386. 0
  387. );
  388. } else {
  389. MRxSmbStuffSMB (StufferState,
  390. "wdd?",
  391. MRXSMB_PROCESS_ID , // typedef struct _LOCKING_ANDX_RANGE {
  392. // w _USHORT( Pid ); // PID of process "owning" lock
  393. // d _ULONG( Offset ); // Ofset to bytes to [un]lock
  394. OrdinaryExchange->AssertLocks.NextLockOffset.LowPart,
  395. // d _ULONG( Length ); // Number of bytes to [un]lock
  396. OrdinaryExchange->AssertLocks.NextLockRange.LowPart,
  397. // } LOCKING_ANDX_RANGE;
  398. 0
  399. );
  400. }
  401. ASSERT_ORDINARY_EXCHANGE ( OrdinaryExchange );
  402. OrdinaryExchange->AssertLocks.NumberOfLocksPlaced += 1;
  403. SmbPutUshort(PtrToLockCount, (USHORT)(OrdinaryExchange->AssertLocks.NumberOfLocksPlaced));
  404. OrdinaryExchange->AssertLocks.LockAreaNonEmpty = FALSE;
  405. ASSERT_ORDINARY_EXCHANGE ( OrdinaryExchange );
  406. }
  407. MRxSmbStuffSMB (StufferState, "!", 0); //fill in the bytecount
  408. MRxSmbDumpStufferState (700,"SMB w/ NTLOCKS&X(assertingbuffered) after stuffing",StufferState);
  409. FINALLY:
  410. RxDbgTraceUnIndent(-1, Dbg);
  411. return(Status);
  412. }
  413. NTSTATUS
  414. SmbPseExchangeStart_Locks(
  415. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  416. )
  417. /*++
  418. Routine Description:
  419. This is the start routine for locks AND for flush.
  420. Arguments:
  421. pExchange - the exchange instance
  422. Return Value:
  423. RXSTATUS - The return status for the operation
  424. --*/
  425. {
  426. NTSTATUS Status;
  427. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  428. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  429. ULONG StartEntryCount;
  430. SMB_PSE_ORDINARY_EXCHANGE_TYPE OEType;
  431. PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
  432. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  433. RxCaptureFcb; RxCaptureFobx;
  434. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  435. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  436. // Flushes must always be synchronous so we can interact with CC
  437. BOOLEAN SynchronousIo = (OrdinaryExchange->EntryPoint == SMBPSE_OE_FROM_FLUSH) || !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
  438. BOOLEAN ThisIsARetry = FALSE;
  439. PAGED_CODE();
  440. RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Locks\n", 0 ));
  441. ASSERT(OrdinaryExchange->Type == ORDINARY_EXCHANGE);
  442. ASSERT( (OrdinaryExchange->SmbCeFlags&SMBCE_EXCHANGE_ATTEMPT_RECONNECTS) == 0 );
  443. OrdinaryExchange->StartEntryCount++;
  444. StartEntryCount = OrdinaryExchange->StartEntryCount;
  445. // Ensure that the Fid is validated
  446. SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID);
  447. for (;;) {
  448. switch (OrdinaryExchange->OpSpecificState) {
  449. case SmbPseOEInnerIoStates_Initial:
  450. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
  451. if (!SynchronousIo) {
  452. OrdinaryExchange->AsyncResumptionRoutine = SmbPseExchangeStart_Locks;
  453. }
  454. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  455. //CODE.IMPROVEMENT union another field over this to lose the casts....we have to do this
  456. //early because copying the head of the list is only done once. this variable is reset for
  457. //those cases where we don't use the locklist
  458. rw->LockList = LowIoContext->ParamsFor.Locks.LockList;
  459. //lack of break is intentional
  460. case SmbPseOEInnerIoStates_ReadyToSend:
  461. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_OperationOutstanding;
  462. OrdinaryExchange->SendOptions = MRxSmbLockSendOptions;
  463. switch (OrdinaryExchange->EntryPoint) {
  464. case SMBPSE_OE_FROM_FLUSH:
  465. OEType = SMBPSE_OETYPE_FLUSH;
  466. if (!ThisIsARetry) {
  467. COVERED_CALL(MRxSmbBuildFlush(StufferState));
  468. }
  469. break;
  470. case SMBPSE_OE_FROM_ASSERTBUFFEREDLOCKS:
  471. OEType = SMBPSE_OETYPE_ASSERTBUFFEREDLOCKS;
  472. if (!ThisIsARetry) {
  473. COVERED_CALL(MRxSmbBuildLockAssert(StufferState));
  474. }
  475. if ((OrdinaryExchange->AssertLocks.EndOfListReached)
  476. && (OrdinaryExchange->AssertLocks.NumberOfLocksPlaced == 0) ) {
  477. OrdinaryExchange->SendOptions = RXCE_SEND_SYNCHRONOUS;
  478. OrdinaryExchange->SmbCeFlags |= SMBCE_EXCHANGE_MID_VALID;
  479. OrdinaryExchange->Mid = SMBCE_OPLOCK_RESPONSE_MID;
  480. OrdinaryExchange->Flags |= SMBPSE_OE_FLAG_NO_RESPONSE_EXPECTED;
  481. if (smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_II) {
  482. *((WORD UNALIGNED *)OrdinaryExchange->AssertLocks.PtrToLockType) |=
  483. ((OPLOCK_BROKEN_TO_II << 8) | 2);
  484. } else {
  485. *((WORD UNALIGNED *)OrdinaryExchange->AssertLocks.PtrToLockType) |=
  486. ((OPLOCK_BROKEN_TO_NONE << 8) | 2);
  487. }
  488. }
  489. break;
  490. case SMBPSE_OE_FROM_LOCKS:
  491. OEType = SMBPSE_OETYPE_LOCKS;
  492. switch (LowIoContext->Operation) {
  493. case LOWIO_OP_SHAREDLOCK:
  494. case LOWIO_OP_EXCLUSIVELOCK:
  495. ASSERT (MRxSmbIsLockRealizable(
  496. capFcb,
  497. (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.ByteOffset,
  498. (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.Length,
  499. LowIoContext->ParamsFor.Locks.Flags
  500. )
  501. == STATUS_SUCCESS);
  502. //lack of break is intentional...........
  503. case LOWIO_OP_UNLOCK:
  504. rw->LockList = NULL;
  505. if (!ThisIsARetry) {
  506. COVERED_CALL(MRxSmbBuildLocksAndX(StufferState));
  507. }
  508. break;
  509. case LOWIO_OP_UNLOCK_MULTIPLE: {
  510. RxDbgTrace(0, Dbg, ("--->in locks_start, remaining locklist=%08lx\n", rw->LockList));
  511. ASSERT( rw->LockList != NULL );
  512. if (!ThisIsARetry) {
  513. COVERED_CALL(MRxSmbBuildLocksAndX(StufferState));
  514. }
  515. break;
  516. }
  517. default:
  518. ASSERT(!"Bad lowio op for locks\n");
  519. Status = RX_MAP_STATUS(NOT_IMPLEMENTED);
  520. goto FINALLY;
  521. }
  522. break;
  523. default:
  524. ASSERT(!"Bad entrypoint for locks_start\n");
  525. Status = RX_MAP_STATUS(NOT_IMPLEMENTED);
  526. goto FINALLY;
  527. }
  528. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  529. OEType
  530. );
  531. if (Status==RX_MAP_STATUS(PENDING)) {
  532. ASSERT(!SynchronousIo);
  533. goto FINALLY;
  534. }
  535. ThisIsARetry = FALSE;
  536. //lack of break is intentional
  537. case SmbPseOEInnerIoStates_OperationOutstanding:
  538. OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_ReadyToSend;
  539. Status = OrdinaryExchange->SmbStatus;
  540. if (Status == STATUS_RETRY) {
  541. SmbCeUninitializeExchangeTransport((PSMB_EXCHANGE)OrdinaryExchange);
  542. Status = SmbCeReconnect(SmbCeGetExchangeVNetRoot(OrdinaryExchange));
  543. if (Status == STATUS_SUCCESS) {
  544. RxLog(("session recover %lx\n",OrdinaryExchange));
  545. OrdinaryExchange->SmbStatus = STATUS_SUCCESS;
  546. Status = SmbCeInitializeExchangeTransport((PSMB_EXCHANGE)OrdinaryExchange);
  547. if (Status != STATUS_SUCCESS) {
  548. goto FINALLY;
  549. }
  550. ThisIsARetry = TRUE;
  551. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
  552. continue;
  553. } else {
  554. goto FINALLY;
  555. }
  556. }
  557. switch (OrdinaryExchange->EntryPoint) {
  558. case SMBPSE_OE_FROM_FLUSH:
  559. goto FINALLY;
  560. //break;
  561. case SMBPSE_OE_FROM_ASSERTBUFFEREDLOCKS:
  562. if ((OrdinaryExchange->AssertLocks.EndOfListReached)
  563. && (OrdinaryExchange->AssertLocks.NumberOfLocksPlaced == 0) ) {
  564. goto FINALLY;
  565. }
  566. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
  567. break;
  568. case SMBPSE_OE_FROM_LOCKS:
  569. // if the locklist is empty. we can get out. this can happen either because we're not using
  570. // the locklist OR because we advance to the end of the list. that's why there are two checks
  571. if (rw->LockList == NULL) goto FINALLY;
  572. rw->LockList = rw->LockList->Next;
  573. if (rw->LockList == 0) goto FINALLY;
  574. if (Status != RX_MAP_STATUS(SUCCESS)) { goto FINALLY; }
  575. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
  576. break;
  577. //default:
  578. // ASSERT(!"Bad entrypoint for locks_start\n");
  579. // Status = RxStatus(NOT_IMPLEMENTED);
  580. // goto FINALLY;
  581. }
  582. break;
  583. }
  584. }
  585. FINALLY:
  586. //CODE.IMPROVEMENT read_start and write_start and locks_start should be combined.....we use this
  587. //macro until then to keep the async stuff identical
  588. if ( Status != RX_MAP_STATUS(PENDING) ) {
  589. SmbPseAsyncCompletionIfNecessary(OrdinaryExchange,RxContext);
  590. }
  591. RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Locks exit w %08lx\n", Status ));
  592. return Status;
  593. }
  594. //CODE.IMPROVEMENT this routine should not even be called...........
  595. NTSTATUS
  596. MRxSmbFinishLocks (
  597. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  598. PRESP_LOCKING_ANDX Response
  599. )
  600. /*++
  601. Routine Description:
  602. This routine actually gets the stuff out of the Close response and finishes the locks.
  603. Arguments:
  604. OrdinaryExchange - the exchange instance
  605. Response - the response
  606. Return Value:
  607. RXSTATUS - The return status for the operation
  608. --*/
  609. {
  610. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  611. PAGED_CODE();
  612. RxDbgTrace(+1, Dbg, ("MRxSmbFinishLocks\n"));
  613. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishLocks:");
  614. if (Response->WordCount != 2) {
  615. Status = STATUS_INVALID_NETWORK_RESPONSE;
  616. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  617. }
  618. RxDbgTrace(-1, Dbg, ("MRxSmbFinishLocks returning %08lx\n", Status ));
  619. return Status;
  620. }
  621. #if 0
  622. NTSTATUS
  623. MRxSmbUnlockRoutine (
  624. IN PRX_CONTEXT RxContext,
  625. IN PFILE_LOCK_INFO LockInfo
  626. )
  627. /*++
  628. Routine Description:
  629. This routine is called from the RDBSS whenever the fsrtl lock package calls the rdbss unlock routine.
  630. CODE.IMPROVEMENT what should really happen is that this should only be called for unlockall and unlockbykey;
  631. the other cases should be handled in the rdbss.
  632. Arguments:
  633. Context - the RxContext associated with this request
  634. LockInfo - gives information about the particular range being unlocked
  635. Return Value:
  636. RXSTATUS - The return status for the operation
  637. --*/
  638. {
  639. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  640. PAGED_CODE();
  641. switch (LowIoContext->Operation) {
  642. case LOWIO_OP_SHAREDLOCK:
  643. case LOWIO_OP_EXCLUSIVELOCK:
  644. case LOWIO_OP_UNLOCK:
  645. return STATUS_SUCCESS;
  646. case LOWIO_OP_UNLOCKALL:
  647. case LOWIO_OP_UNLOCKALLBYKEY:
  648. default:
  649. return STATUS_NOT_IMPLEMENTED;
  650. }
  651. }
  652. #endif
  653. NTSTATUS
  654. MRxSmbCompleteBufferingStateChangeRequest(
  655. IN OUT PRX_CONTEXT RxContext,
  656. IN OUT PMRX_SRV_OPEN SrvOpen,
  657. IN PVOID pContext
  658. )
  659. /*++
  660. Routine Description:
  661. This routine is called to assert the locks that the wrapper has buffered. currently, it is synchronous!
  662. Arguments:
  663. RxContext - the open instance
  664. SrvOpen - tells which fcb is to be used. CODE.IMPROVEMENT this param is redundant if the rxcontext is filled out completely
  665. LockEnumerator - the routine to call to get the locks
  666. Return Value:
  667. RXSTATUS - The return status for the operation
  668. --*/
  669. {
  670. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  671. PSMBSTUFFER_BUFFER_STATE StufferState = NULL;
  672. PMRX_FCB Fcb = SrvOpen->pFcb;
  673. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(Fcb);
  674. USHORT NewOplockLevel = (USHORT)(pContext);
  675. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  676. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  677. PAGED_CODE();
  678. RxDbgTrace(+1, Dbg, ("MRxSmbCompleteBufferingStateChangeRequest\n", 0 ));
  679. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  680. RxDbgTrace(0,Dbg,("@@@@@@ Old Level (%lx) to New Level %lx @@@@\n",smbSrvOpen->OplockLevel,NewOplockLevel));
  681. if (NewOplockLevel == SMB_OPLOCK_LEVEL_NONE)
  682. {
  683. SrvOpen->Flags |= SRVOPEN_FLAG_DONTUSE_READ_CACHING;
  684. }
  685. smbFcb->LastOplockLevel = NewOplockLevel;
  686. if ((smbSrvOpen->OplockLevel == SMB_OPLOCK_LEVEL_II) &&
  687. (NewOplockLevel == SMB_OPLOCK_LEVEL_NONE)) {
  688. return RX_MAP_STATUS(SUCCESS);
  689. }
  690. smbSrvOpen->OplockLevel = (UCHAR)NewOplockLevel;
  691. Status = SmbPseCreateOrdinaryExchange(RxContext,
  692. SrvOpen->pVNetRoot,
  693. SMBPSE_OE_FROM_ASSERTBUFFEREDLOCKS,
  694. SmbPseExchangeStart_Locks,
  695. &OrdinaryExchange
  696. );
  697. if (Status != STATUS_SUCCESS) {
  698. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  699. return(Status);
  700. }
  701. // The SERVER has a time window of 45 seconds associated with OPLOCK responses.
  702. // During this period oplock responses ( the last packet ) do not elicit any
  703. // response. If the response at the server is received after this window has
  704. // elapsed the OPLOCK response will elicit a normal LOCKING_ANDX response from
  705. // the server.
  706. OrdinaryExchange->AssertLocks.LockEnumerator = RxLockEnumerator;
  707. OrdinaryExchange->AssertLocks.SrvOpen = SrvOpen;
  708. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  709. ASSERT (Status!=RX_MAP_STATUS(PENDING));
  710. if (Status!=RX_MAP_STATUS(PENDING)) {
  711. BOOLEAN FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  712. ASSERT(FinalizationComplete);
  713. }
  714. RxDbgTrace(-1, Dbg, ("MRxSmbAssertBufferedFileLocks exit with status=%08lx\n", Status ));
  715. return(Status);
  716. }
  717. #undef Dbg
  718. #define Dbg (DEBUG_TRACE_FLUSH)
  719. NTSTATUS
  720. MRxSmbBuildFlush (
  721. PSMBSTUFFER_BUFFER_STATE StufferState
  722. )
  723. /*++
  724. Routine Description:
  725. This builds a Flush SMB. we don't have to worry about login id and such
  726. since that is done by the connection engine....pretty neat huh? all we have to do
  727. is to format up the bits.
  728. Arguments:
  729. StufferState - the state of the smbbuffer from the stuffer's point of view
  730. Return Value:
  731. RXSTATUS
  732. SUCCESS
  733. NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
  734. Notes:
  735. --*/
  736. {
  737. NTSTATUS Status;
  738. PRX_CONTEXT RxContext = StufferState->RxContext;
  739. RxCaptureFcb;RxCaptureFobx;
  740. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  741. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  742. PAGED_CODE();
  743. RxDbgTrace(+1, Dbg, ("MRxSmbBuildFlush\n", 0 ));
  744. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  745. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_Never, SMB_COM_FLUSH,
  746. SMB_REQUEST_SIZE(FLUSH),
  747. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  748. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  749. );
  750. MRxSmbDumpStufferState (1100,"SMB w/ FLUSH before stuffing",StufferState);
  751. MRxSmbStuffSMB (StufferState,
  752. "0wB!",
  753. // 0 UCHAR WordCount; // Count of parameter words = 1
  754. smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
  755. SMB_WCT_CHECK(1) 0 // B _USHORT( ByteCount ); // Count of data bytes = 0
  756. // UCHAR Buffer[1]; // empty
  757. );
  758. MRxSmbDumpStufferState (700,"SMB w/ FLUSH after stuffing",StufferState);
  759. FINALLY:
  760. RxDbgTraceUnIndent(-1,Dbg);
  761. return(Status);
  762. }
  763. NTSTATUS
  764. MRxSmbFlush(
  765. IN PRX_CONTEXT RxContext)
  766. /*++
  767. Routine Description:
  768. This routine handles network requests for file flush
  769. Arguments:
  770. RxContext - the RDBSS context
  771. Return Value:
  772. RXSTATUS - The return status for the operation
  773. --*/
  774. {
  775. NTSTATUS Status = STATUS_SUCCESS;
  776. RxCaptureFcb;
  777. RxCaptureFobx;
  778. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  779. NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
  780. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  781. PAGED_CODE();
  782. RxDbgTrace(+1, Dbg, ("MRxSmbFlush\n"));
  783. if (TypeOfOpen == RDBSS_NTC_SPOOLFILE) {
  784. //we don't buffer spoolfiles....just get out....
  785. RxDbgTrace(-1, Dbg, ("MRxSmbFlush exit on spoolfile\n"));
  786. return(STATUS_SUCCESS);
  787. }
  788. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  789. NOTHING;
  790. } else {
  791. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  792. if (smbSrvOpen->hfShadow != 0){
  793. NTSTATUS FlushNtStatus;
  794. FlushNtStatus = MRxSmbDCscFlush(RxContext);
  795. if (FlushNtStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  796. RxDbgTrace(-1, Dbg, ("MRxSmbFlush exit on DCON\n"));
  797. return(FlushNtStatus);
  798. } else {
  799. NOTHING;
  800. }
  801. }
  802. }
  803. ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
  804. Status = SmbPseCreateOrdinaryExchange(RxContext,
  805. SrvOpen->pVNetRoot,
  806. SMBPSE_OE_FROM_FLUSH,
  807. SmbPseExchangeStart_Locks,
  808. &OrdinaryExchange
  809. );
  810. if (Status != STATUS_SUCCESS) {
  811. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  812. return(Status);
  813. }
  814. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  815. ASSERT (Status!=RX_MAP_STATUS(PENDING));
  816. if (Status!=RX_MAP_STATUS(PENDING)) {
  817. BOOLEAN FinalizationComplete = SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  818. ASSERT(FinalizationComplete);
  819. }
  820. RxDbgTrace(-1, Dbg, ("MRxSmbFlush exit with status=%08lx\n", Status ));
  821. return(Status);
  822. }
  823. NTSTATUS
  824. MRxSmbIsLockRealizable (
  825. IN OUT PMRX_FCB pFcb,
  826. IN PLARGE_INTEGER ByteOffset,
  827. IN PLARGE_INTEGER Length,
  828. IN ULONG LowIoLockFlags
  829. )
  830. {
  831. PSMBCEDB_SERVER_ENTRY pServerEntry;
  832. ULONG DialectFlags;
  833. PAGED_CODE();
  834. pServerEntry = SmbCeGetAssociatedServerEntry(pFcb->pNetRoot->pSrvCall);
  835. DialectFlags = pServerEntry->Server.DialectFlags;
  836. //nt servers implement all types of locks
  837. if (FlagOn(DialectFlags,DF_NT_SMBS)
  838. || SmbCeIsServerInDisconnectedMode(pServerEntry)) {
  839. return(STATUS_SUCCESS);
  840. }
  841. //nonnt servers do not handle 64bit locks or 0-length locks
  842. if ( (ByteOffset->HighPart!=0)
  843. || (Length->HighPart!=0)
  844. || (Length->QuadPart==0) ) {
  845. return(STATUS_NOT_SUPPORTED);
  846. }
  847. // Lanman 2.0 pinball servers don't support shared locks (even
  848. // though Lanman 2.0 FAT servers support them). As a result,
  849. // we cannot support shared locks to Lanman servers.
  850. //
  851. if (!FlagOn(DialectFlags,DF_LANMAN21)
  852. && !FlagOn(LowIoLockFlags,LOWIO_LOCKSFLAG_EXCLUSIVELOCK)) {
  853. return(STATUS_NOT_SUPPORTED);
  854. }
  855. // if a server cannot do lockingAndX, then we can't do
  856. // !FailImmediately because there's no timeout
  857. if (!FlagOn(DialectFlags,DF_LANMAN20)
  858. && !FlagOn(LowIoLockFlags,LOWIO_LOCKSFLAG_FAIL_IMMEDIATELY)) {
  859. return(STATUS_NOT_SUPPORTED);
  860. }
  861. return(STATUS_SUCCESS);
  862. }
  863. #if 0
  864. CODE.IMPROVEMENT this is never called but it had been called it would have checked WC and BC.
  865. this should be added to the model...especially for checked.
  866. NTSTATUS
  867. MRxSmbFinishFlush (
  868. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  869. PRESP_FLUSH Response
  870. )
  871. /*++
  872. Routine Description:
  873. This routine actually gets the stuff out of the Close response and finishes the locks.
  874. Arguments:
  875. OrdinaryExchange - the exchange instance
  876. Response - the response
  877. Return Value:
  878. RXSTATUS - The return status for the operation
  879. --*/
  880. {
  881. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  882. PAGED_CODE();
  883. RxDbgTrace(+1, Dbg, ("MRxSmbFinishFlush\n"));
  884. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishFlush:");
  885. if (Response->WordCount != 0) {
  886. Status = STATUS_INVALID_NETWORK_RESPONSE;
  887. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  888. }
  889. RxDbgTrace(-1, Dbg, ("MRxSmbFinishFlush returning %08lx\n", Status ));
  890. return Status;
  891. }
  892. #endif //if 0