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

468 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbclose.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs:
  7. Close
  8. Author:
  9. David Treadwell (davidtr) 16-Nov-1989
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "smbclose.tmh"
  14. #pragma hdrstop
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvSmbClose )
  17. #endif
  18. SMB_PROCESSOR_RETURN_TYPE
  19. SrvSmbClose (
  20. SMB_PROCESSOR_PARAMETERS
  21. )
  22. /*++
  23. Routine Description:
  24. Processes a Close SMB.
  25. Arguments:
  26. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  27. of the parameters to SMB processor routines.
  28. Return Value:
  29. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  30. --*/
  31. {
  32. PREQ_CLOSE request;
  33. PRESP_CLOSE response;
  34. NTSTATUS status = STATUS_SUCCESS;
  35. #ifdef INCLUDE_SMB_IFMODIFIED
  36. BOOLEAN extendedInfo = FALSE;
  37. SRV_NETWORK_OPEN_INFORMATION fileNetInfo;
  38. ULONG flags;
  39. USN usnValue;
  40. ULONGLONG fileRefNumber;
  41. #endif
  42. PSESSION session;
  43. PRFCB rfcb;
  44. SMB_STATUS SmbStatus = SmbStatusInProgress;
  45. PAGED_CODE( );
  46. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  47. WorkContext->PreviousSMB = EVENT_TYPE_SMB_CLOSE;
  48. SrvWmiStartContext(WorkContext);
  49. IF_SMB_DEBUG(OPEN_CLOSE1) {
  50. KdPrint(( "Close file request header at 0x%p, response header at 0x%p\n",
  51. WorkContext->RequestHeader,
  52. WorkContext->ResponseHeader ));
  53. KdPrint(( "Close file request parameters at 0x%p, response parameters at 0x%p\n",
  54. WorkContext->RequestParameters,
  55. WorkContext->ResponseParameters ));
  56. }
  57. //
  58. // Set up parameters.
  59. //
  60. request = (PREQ_CLOSE)(WorkContext->RequestParameters);
  61. response = (PRESP_CLOSE)(WorkContext->ResponseParameters);
  62. //
  63. // If a session block has not already been assigned to the current
  64. // work context, verify the UID. If verified, the address of the
  65. // session block corresponding to this user is stored in the
  66. // WorkContext block and the session block is referenced.
  67. //
  68. session = SrvVerifyUid(
  69. WorkContext,
  70. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )
  71. );
  72. if ( session == NULL ) {
  73. IF_DEBUG(SMB_ERRORS) {
  74. KdPrint(( "SrvSmbClose: Invalid UID: 0x%lx\n",
  75. SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid ) ));
  76. }
  77. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
  78. SmbStatus = SmbStatusSendResponse;
  79. goto Cleanup;
  80. }
  81. //
  82. // First, verify the FID. If verified, the RFCB and the TreeConnect
  83. // block are referenced and their addresses are stored in the
  84. // WorkContext block, and the RFCB address is returned.
  85. //
  86. // Call SrvVerifyFid, but do not fail (return NULL) if there
  87. // is a saved write behind error for this rfcb. The rfcb is
  88. // needed in order to process the close.
  89. //
  90. rfcb = SrvVerifyFid(
  91. WorkContext,
  92. SmbGetUshort( &request->Fid ),
  93. FALSE,
  94. SrvRestartSmbReceived, // serialize with raw write
  95. &status
  96. );
  97. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  98. if ( !NT_SUCCESS( status ) ) {
  99. //
  100. // Invalid file ID. Reject the request.
  101. //
  102. IF_DEBUG(SMB_ERRORS) {
  103. KdPrint(( "SrvSmbClose: Invalid FID: 0x%lx\n",
  104. SmbGetUshort( &request->Fid ) ));
  105. }
  106. SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
  107. SmbStatus = SmbStatusSendResponse;
  108. goto Cleanup;
  109. }
  110. //
  111. // The work item has been queued because a raw write is in
  112. // progress.
  113. //
  114. SmbStatus = SmbStatusInProgress;
  115. goto Cleanup;
  116. } else if( rfcb->ShareType == ShareTypePrint &&
  117. WorkContext->UsingBlockingThread == 0 ) {
  118. //
  119. // Closing this file will result in the scheduling of a print
  120. // job. This means we will have to talk with srvsvc, a lengthy
  121. // operation. Shift this close over to a blocking thread.
  122. //
  123. SrvQueueWorkToBlockingThread( WorkContext );
  124. SmbStatus = SmbStatusInProgress;
  125. goto Cleanup;
  126. } else if ( !NT_SUCCESS( rfcb->SavedError ) ) {
  127. //
  128. // Check the saved error.
  129. //
  130. (VOID) SrvCheckForSavedError( WorkContext, rfcb );
  131. }
  132. //
  133. // Set the last write time on the file from the time specified in
  134. // the SMB. Even though the SMB spec says that this is optional,
  135. // we must support it for the following reasons:
  136. //
  137. // 1) The only way to set a file time in DOS is through a
  138. // handle-based API which the DOS redir never sees; the API
  139. // just sets the time in DOS's FCB, and the redir is expected
  140. // set the time when it closes the file. Therefore, if we
  141. // didn't do this, there would be no way t set a file time
  142. // from DOS.
  143. //
  144. // 2) It is better for a file to have a redirector's version
  145. // of a time than the server's. This keeps the time
  146. // consistent for apps running on the client. Setting
  147. // the file time on close keeps the file time consistent
  148. // with the time on the client.
  149. //
  150. // !!! should we do anything with the return code from this routine?
  151. if( rfcb->WriteAccessGranted ||
  152. #ifdef INCLUDE_SMB_IFMODIFIED
  153. rfcb->WrittenTo ||
  154. #endif
  155. rfcb->AppendAccessGranted ) {
  156. #ifdef INCLUDE_SMB_IFMODIFIED
  157. (VOID)SrvSetLastWriteTime(
  158. rfcb,
  159. SmbGetUlong( &request->LastWriteTimeInSeconds ),
  160. rfcb->GrantedAccess,
  161. TRUE
  162. );
  163. #else
  164. (VOID)SrvSetLastWriteTime(
  165. rfcb,
  166. SmbGetUlong( &request->LastWriteTimeInSeconds ),
  167. rfcb->GrantedAccess
  168. );
  169. #endif
  170. }
  171. //
  172. // Now proceed to do the actual close file, even if there was
  173. // a write behind error.
  174. //
  175. #ifdef SLMDBG
  176. if ( SrvIsSlmStatus( &rfcb->Mfcb->FileName ) &&
  177. (rfcb->GrantedAccess & FILE_WRITE_DATA) ) {
  178. ULONG offset;
  179. status = SrvValidateSlmStatus(
  180. rfcb->Lfcb->FileHandle,
  181. WorkContext,
  182. &offset
  183. );
  184. if ( !NT_SUCCESS(status) ) {
  185. SrvReportCorruptSlmStatus(
  186. &rfcb->Mfcb->FileName,
  187. status,
  188. offset,
  189. SLMDBG_CLOSE,
  190. rfcb->Lfcb->Session
  191. );
  192. SrvReportSlmStatusOperations( rfcb, FALSE );
  193. SrvDisallowSlmAccess(
  194. &rfcb->Lfcb->FileObject->FileName,
  195. rfcb->Lfcb->TreeConnect->Share->RootDirectoryHandle
  196. );
  197. SrvSetSmbError( WorkContext, STATUS_DISK_CORRUPT_ERROR );
  198. }
  199. }
  200. #endif
  201. #ifdef INCLUDE_SMB_IFMODIFIED
  202. if (request->WordCount == 5 && rfcb->ShareType == ShareTypeDisk) {
  203. //
  204. // This is an extended close request, fill in all the new fields
  205. //
  206. status = SrvQueryNetworkOpenInformation(
  207. rfcb->Lfcb->FileHandle,
  208. rfcb->Lfcb->FileObject,
  209. &fileNetInfo,
  210. FALSE
  211. );
  212. if ( NT_SUCCESS(status) ) {
  213. PREQ_EXTENDED_CLOSE extendedRequest = (PREQ_EXTENDED_CLOSE) request;
  214. LARGE_INTEGER ourUsnValue;
  215. LARGE_INTEGER ourFileRefNumber;
  216. BOOLEAN writeClose;
  217. flags = SmbGetUlong( &extendedRequest->Flags );
  218. extendedInfo = TRUE;
  219. usnValue = 0;
  220. fileRefNumber = 0;
  221. if (rfcb->Lfcb->FileUpdated) {
  222. //
  223. // the file has been updated, let's close out the current
  224. // usn journal entry so that we can get an accurate USN
  225. // number (rather than have the entry generated at close).
  226. //
  227. rfcb->Lfcb->FileUpdated = FALSE;
  228. writeClose = TRUE;
  229. } else {
  230. writeClose = FALSE;
  231. }
  232. //
  233. // get the current USN number for this file.
  234. //
  235. status = SrvIssueQueryUsnInfoRequest( rfcb,
  236. writeClose,
  237. &ourUsnValue,
  238. &ourFileRefNumber );
  239. if (NT_SUCCESS(status)) {
  240. usnValue = ourUsnValue.QuadPart;
  241. fileRefNumber = ourFileRefNumber.QuadPart;
  242. } else {
  243. IF_DEBUG(ERRORS) {
  244. KdPrint(( "SrvSmbClose: Query USN info failed: 0x%X for handle %u\n",
  245. status, rfcb->Lfcb->FileObject ));
  246. }
  247. }
  248. } else {
  249. IF_DEBUG(SMB_ERRORS) {
  250. KdPrint(( "SrvSmbClose: NtGetFileInfo returned 0x%lx\n", status ));
  251. }
  252. }
  253. }
  254. #endif
  255. SrvCloseRfcb( rfcb );
  256. //
  257. // Dereference the RFCB immediately, rather than waiting for normal
  258. // work context cleanup after the response send completes. This
  259. // gets the xFCB structures cleaned up in a more timely manner.
  260. //
  261. // *** The specific motivation for this change was to fix a problem
  262. // where a compatibility mode open was closed, the response was
  263. // sent, and a Delete SMB was received before the send
  264. // completion was processed. This resulted in the MFCB and LFCB
  265. // still being present, which caused the delete processing to
  266. // try to use the file handle in the LFCB, which we just closed
  267. // here.
  268. //
  269. SrvDereferenceRfcb( rfcb );
  270. WorkContext->Rfcb = NULL;
  271. WorkContext->OplockOpen = FALSE;
  272. #if 0
  273. //
  274. // If this is a CloseAndTreeDisc SMB, do the tree disconnect.
  275. //
  276. if ( WorkContext->RequestHeader->Command == SMB_COM_CLOSE_AND_TREE_DISC ) {
  277. IF_SMB_DEBUG(OPEN_CLOSE1) {
  278. KdPrint(( "Disconnecting tree 0x%lx\n", WorkContext->TreeConnect ));
  279. }
  280. SrvCloseTreeConnect( WorkContext->TreeConnect );
  281. }
  282. #endif
  283. //
  284. // Build the response SMB.
  285. //
  286. #ifdef INCLUDE_SMB_IFMODIFIED
  287. if ( ! extendedInfo ) {
  288. #endif
  289. response->WordCount = 0;
  290. SmbPutUshort( &response->ByteCount, 0 );
  291. WorkContext->ResponseParameters = NEXT_LOCATION(
  292. response,
  293. RESP_CLOSE,
  294. 0
  295. );
  296. #ifdef INCLUDE_SMB_IFMODIFIED
  297. } else {
  298. PRESP_EXTENDED_CLOSE extendedResponse = (PRESP_EXTENDED_CLOSE) response;
  299. LARGE_INTEGER usnToLarge;
  300. extendedResponse->WordCount = SMB_RESP_EXTENDED_CLOSE_WORK_COUNT;
  301. SmbPutUshort( &extendedResponse->ByteCount, 0 );
  302. SmbPutUlong( &extendedResponse->Flags, flags );
  303. SmbPutUlong(
  304. &extendedResponse->CreationTime.HighPart,
  305. fileNetInfo.CreationTime.HighPart
  306. );
  307. SmbPutUlong(
  308. &extendedResponse->CreationTime.LowPart,
  309. fileNetInfo.CreationTime.LowPart
  310. );
  311. SmbPutUlong(
  312. &extendedResponse->LastWriteTime.HighPart,
  313. fileNetInfo.LastWriteTime.HighPart
  314. );
  315. SmbPutUlong(
  316. &extendedResponse->LastWriteTime.LowPart,
  317. fileNetInfo.LastWriteTime.LowPart
  318. );
  319. SmbPutUlong(
  320. &extendedResponse->ChangeTime.HighPart,
  321. fileNetInfo.ChangeTime.HighPart
  322. );
  323. SmbPutUlong(
  324. &extendedResponse->ChangeTime.LowPart,
  325. fileNetInfo.ChangeTime.LowPart
  326. );
  327. SmbPutUlong(
  328. &extendedResponse->AllocationSize.HighPart,
  329. fileNetInfo.AllocationSize.HighPart
  330. );
  331. SmbPutUlong(
  332. &extendedResponse->AllocationSize.LowPart,
  333. fileNetInfo.AllocationSize.LowPart
  334. );
  335. SmbPutUlong(
  336. &extendedResponse->EndOfFile.HighPart,
  337. fileNetInfo.EndOfFile.HighPart
  338. );
  339. SmbPutUlong(
  340. &extendedResponse->EndOfFile.LowPart,
  341. fileNetInfo.EndOfFile.LowPart
  342. );
  343. usnToLarge.QuadPart = usnValue;
  344. SmbPutUlong(
  345. &extendedResponse->UsnValue.HighPart,
  346. usnToLarge.HighPart
  347. );
  348. SmbPutUlong(
  349. &extendedResponse->UsnValue.LowPart,
  350. usnToLarge.LowPart
  351. );
  352. usnToLarge.QuadPart = fileRefNumber;
  353. SmbPutUlong(
  354. &extendedResponse->FileReferenceNumber.HighPart,
  355. usnToLarge.HighPart
  356. );
  357. SmbPutUlong(
  358. &extendedResponse->FileReferenceNumber.LowPart,
  359. usnToLarge.LowPart
  360. );
  361. SmbPutUlong( &extendedResponse->FileAttributes, fileNetInfo.FileAttributes );
  362. WorkContext->ResponseParameters = NEXT_LOCATION(
  363. extendedResponse,
  364. RESP_EXTENDED_CLOSE,
  365. 0
  366. );
  367. }
  368. #endif
  369. SmbStatus = SmbStatusSendResponse;
  370. Cleanup:
  371. SrvWmiEndContext(WorkContext);
  372. return SmbStatus;
  373. } // SrvSmbClose