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.

580 lines
13 KiB

  1. /*++
  2. Copyright (c) 1992-4 Microsoft Corporation
  3. Module Name:
  4. Close.c
  5. Abstract:
  6. This module implements the File Close routine for the NetWare
  7. redirector called by the dispatch driver.
  8. Author:
  9. Colin Watson [ColinW] 19-Dec-1992
  10. Revision History:
  11. --*/
  12. #include "Procs.h"
  13. //
  14. // The local debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_CLOSE)
  17. //
  18. // Local procedure prototypes
  19. //
  20. NTSTATUS
  21. NwCommonClose (
  22. IN PIRP_CONTEXT IrpContext
  23. );
  24. NTSTATUS
  25. NwCloseRcb (
  26. IN PIRP_CONTEXT IrpContext,
  27. IN PRCB Rcb
  28. );
  29. NTSTATUS
  30. NwCloseIcb (
  31. IN PIRP_CONTEXT IrpContext,
  32. IN PICB Icb
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text( PAGE, NwFsdClose )
  36. #pragma alloc_text( PAGE, NwCommonClose )
  37. #pragma alloc_text( PAGE, NwCloseRcb )
  38. #pragma alloc_text( PAGE, NwCloseIcb )
  39. #endif
  40. NTSTATUS
  41. NwFsdClose (
  42. IN PDEVICE_OBJECT DeviceObject,
  43. IN PIRP Irp
  44. )
  45. /*++
  46. Routine Description:
  47. This routine implements the FSD part of Close.
  48. Arguments:
  49. DeviceObject - Supplies the redirector device object.
  50. Irp - Supplies the Irp being processed
  51. Return Value:
  52. NTSTATUS - The FSD status for the IRP
  53. --*/
  54. {
  55. NTSTATUS Status;
  56. PIRP_CONTEXT IrpContext = NULL;
  57. BOOLEAN TopLevel;
  58. PAGED_CODE();
  59. DebugTrace(+1, Dbg, "NwFsdClose\n", 0);
  60. FsRtlEnterFileSystem();
  61. NwReferenceUnlockableCodeSection ();
  62. //
  63. // Call the common Close routine
  64. //
  65. TopLevel = NwIsIrpTopLevel( Irp );
  66. try {
  67. IrpContext = AllocateIrpContext( Irp );
  68. Status = NwCommonClose( IrpContext );
  69. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  70. if ( IrpContext == NULL ) {
  71. //
  72. // If we couldn't allocate an irp context, just complete
  73. // irp without any fanfare.
  74. //
  75. Status = STATUS_INSUFFICIENT_RESOURCES;
  76. Irp->IoStatus.Status = Status;
  77. Irp->IoStatus.Information = 0;
  78. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  79. } else {
  80. //
  81. // We had some trouble trying to perform the requested
  82. // operation, so we'll abort the I/O request with
  83. // the error status that we get back from the
  84. // execption code.
  85. //
  86. Status = NwProcessException( IrpContext, GetExceptionCode() );
  87. }
  88. }
  89. if ( IrpContext ) {
  90. NwDequeueIrpContext( IrpContext, FALSE );
  91. NwCompleteRequest( IrpContext, Status );
  92. }
  93. if ( TopLevel ) {
  94. NwSetTopLevelIrp( NULL );
  95. }
  96. //
  97. // And return to our caller
  98. //
  99. DebugTrace(-1, Dbg, "NwFsdClose -> %08lx\n", Status);
  100. NwDereferenceUnlockableCodeSection ();
  101. UNREFERENCED_PARAMETER( DeviceObject );
  102. FsRtlExitFileSystem();
  103. return Status;
  104. }
  105. NTSTATUS
  106. NwCommonClose (
  107. IN PIRP_CONTEXT IrpContext
  108. )
  109. /*++
  110. Routine Description:
  111. This is the common routine for closing a file.
  112. Arguments:
  113. IrpContext - Supplies the Irp to process
  114. Return Value:
  115. NTSTATUS - the return status for the operation
  116. --*/
  117. {
  118. PIRP Irp;
  119. PIO_STACK_LOCATION irpSp;
  120. NTSTATUS status;
  121. NODE_TYPE_CODE nodeTypeCode;
  122. PVOID fsContext, fsContext2;
  123. PAGED_CODE();
  124. Irp = IrpContext->pOriginalIrp;
  125. irpSp = IoGetCurrentIrpStackLocation( Irp );
  126. DebugTrace(+1, Dbg, "NwCommonClose\n", 0);
  127. DebugTrace( 0, Dbg, "IrpContext = %08lx\n", (ULONG_PTR)IrpContext);
  128. DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG_PTR)Irp);
  129. DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG_PTR)irpSp->FileObject);
  130. try {
  131. //
  132. // Get the a referenced pointer to the node and make sure it is
  133. // not being closed.
  134. //
  135. if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  136. &fsContext,
  137. &fsContext2 )) == NTC_UNDEFINED) {
  138. DebugTrace(0, Dbg, "The file is disconnected\n", 0);
  139. status = STATUS_INVALID_HANDLE;
  140. DebugTrace(-1, Dbg, "NwCommonClose -> %08lx\n", status );
  141. try_return( NOTHING );
  142. }
  143. //
  144. // Decide how to handle this IRP.
  145. //
  146. switch (nodeTypeCode) {
  147. case NW_NTC_RCB: // Close the file system
  148. status = NwCloseRcb( IrpContext, (PRCB)fsContext2 );
  149. status = STATUS_SUCCESS;
  150. break;
  151. case NW_NTC_ICB: // Close the remote file
  152. case NW_NTC_ICB_SCB: // Close the SCB
  153. status = NwCloseIcb( IrpContext, (PICB)fsContext2 );
  154. NwDereferenceUnlockableCodeSection ();
  155. break;
  156. #ifdef NWDBG
  157. default:
  158. //
  159. // This is not one of ours.
  160. //
  161. KeBugCheck( RDR_FILE_SYSTEM );
  162. break;
  163. #endif
  164. }
  165. try_exit: NOTHING;
  166. } finally {
  167. //
  168. // Just in-case this handle was the last one before we unload.
  169. //
  170. NwUnlockCodeSections(TRUE);
  171. DebugTrace(-1, Dbg, "NwCommonClose -> %08lx\n", status);
  172. }
  173. return status;
  174. }
  175. NTSTATUS
  176. NwCloseRcb (
  177. IN PIRP_CONTEXT IrpContext,
  178. IN PRCB Rcb
  179. )
  180. /*++
  181. Routine Description:
  182. The routine cleans up a RCB.
  183. Arguments:
  184. IrpContext - Supplies the IRP context pointers for this close.
  185. Rcb - Supplies the RCB for MSFS.
  186. Return Value:
  187. NTSTATUS - An appropriate completion status
  188. --*/
  189. {
  190. NTSTATUS status;
  191. PAGED_CODE();
  192. DebugTrace(+1, Dbg, "NwCloseRcb...\n", 0);
  193. //
  194. // Now acquire exclusive access to the Rcb
  195. //
  196. NwAcquireExclusiveRcb( Rcb, TRUE );
  197. status = STATUS_SUCCESS;
  198. --Rcb->OpenCount;
  199. NwReleaseRcb( Rcb );
  200. DebugTrace(-1, Dbg, "MsCloseRcb -> %08lx\n", status);
  201. //
  202. // And return to our caller
  203. //
  204. return status;
  205. }
  206. NTSTATUS
  207. NwCloseIcb (
  208. IN PIRP_CONTEXT IrpContext,
  209. IN PICB Icb
  210. )
  211. /*++
  212. Routine Description:
  213. The routine cleans up an ICB.
  214. Arguments:
  215. IrpContext - Supplies the IRP context pointers for this close.
  216. Rcb - Supplies the RCB for MSFS.
  217. Return Value:
  218. NTSTATUS - An appropriate completion status
  219. --*/
  220. {
  221. NTSTATUS Status;
  222. PNONPAGED_SCB pNpScb;
  223. PVCB Vcb;
  224. PFCB Fcb;
  225. PAGED_CODE();
  226. DebugTrace(+1, Dbg, "NwCloseIcb...\n", 0);
  227. ASSERT( Icb->State == ICB_STATE_CLEANED_UP ||
  228. Icb->State == ICB_STATE_CLOSE_PENDING );
  229. //
  230. // If this is a remote file close the remote handle.
  231. //
  232. Status = STATUS_SUCCESS;
  233. IrpContext->Icb = Icb;
  234. Fcb = Icb->SuperType.Fcb;
  235. if (( Icb->NodeTypeCode == NW_NTC_ICB ) ||
  236. ( Icb->NodeTypeCode == NW_NTC_DCB )) {
  237. pNpScb = Fcb->Scb->pNpScb;
  238. IrpContext->pNpScb = pNpScb;
  239. if ( Icb->HasRemoteHandle ) {
  240. Vcb = Fcb->Vcb;
  241. //
  242. // Dump the write behind cache.
  243. //
  244. Status = AcquireFcbAndFlushCache( IrpContext, Fcb->NonPagedFcb );
  245. if ( !NT_SUCCESS( Status ) ) {
  246. IoRaiseInformationalHardError(
  247. STATUS_LOST_WRITEBEHIND_DATA,
  248. &Fcb->FullFileName,
  249. (PKTHREAD)IrpContext->pOriginalIrp->Tail.Overlay.Thread );
  250. }
  251. //
  252. // Is this a print job?
  253. // Icb->IsPrintJob will be false if a 16 bit app is
  254. // responsible for sending the job.
  255. //
  256. if ( FlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) &&
  257. Icb->IsPrintJob ) {
  258. //
  259. // Yes, did we print?
  260. //
  261. if ( Icb->ActuallyPrinted ) {
  262. //
  263. // Yes. Send a close file and start queue job NCP
  264. //
  265. Status = ExchangeWithWait(
  266. IrpContext,
  267. SynchronousResponseCallback,
  268. "Sdw",
  269. NCP_ADMIN_FUNCTION, NCP_CLOSE_FILE_AND_START_JOB,
  270. Vcb->Specific.Print.QueueId,
  271. Icb->JobId );
  272. } else {
  273. //
  274. // No. Cancel the job.
  275. //
  276. Status = ExchangeWithWait(
  277. IrpContext,
  278. SynchronousResponseCallback,
  279. "Sdw",
  280. NCP_ADMIN_FUNCTION, NCP_CLOSE_FILE_AND_CANCEL_JOB,
  281. Vcb->Specific.Print.QueueId,
  282. Icb->JobId );
  283. }
  284. } else {
  285. if ( Icb->SuperType.Fcb->NodeTypeCode != NW_NTC_DCB ) {
  286. //
  287. // No, send a close file NCP.
  288. //
  289. ASSERT( IrpContext->pTdiStruct == NULL );
  290. Status = ExchangeWithWait(
  291. IrpContext,
  292. SynchronousResponseCallback,
  293. "F-r",
  294. NCP_CLOSE,
  295. Icb->Handle, sizeof( Icb->Handle ) );
  296. // If this is in the long file name space and
  297. // the last access flag has been set, we have to
  298. // reset the last access time _after_ closing the file.
  299. if ( Icb->UserSetLastAccessTime &&
  300. BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
  301. Status = ExchangeWithWait(
  302. IrpContext,
  303. SynchronousResponseCallback,
  304. "LbbWD_W_bDbC",
  305. NCP_LFN_SET_INFO,
  306. Fcb->Vcb->Specific.Disk.LongNameSpace,
  307. Fcb->Vcb->Specific.Disk.LongNameSpace,
  308. SEARCH_ALL_FILES,
  309. LFN_FLAG_SET_INFO_LASTACCESS_DATE,
  310. 28,
  311. Fcb->LastAccessDate,
  312. 8,
  313. Fcb->Vcb->Specific.Disk.VolumeNumber,
  314. Fcb->Vcb->Specific.Disk.Handle,
  315. 0,
  316. &Fcb->RelativeFileName );
  317. }
  318. //
  319. // If someone set the shareable bit, then
  320. // see if we can send the NCP over the wire (all
  321. // instances of the file need to be closed).
  322. //
  323. if ( BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LAZY_SET_SHAREABLE ) ) {
  324. LazySetShareable( IrpContext, Icb, Fcb );
  325. }
  326. } else {
  327. Status = ExchangeWithWait (
  328. IrpContext,
  329. SynchronousResponseCallback,
  330. "Sb",
  331. NCP_DIR_FUNCTION, NCP_DEALLOCATE_DIR_HANDLE,
  332. Icb->Handle[0]);
  333. }
  334. }
  335. Icb->HasRemoteHandle = FALSE;
  336. }
  337. } else {
  338. pNpScb = Icb->SuperType.Scb->pNpScb;
  339. IrpContext->pNpScb = pNpScb;
  340. IrpContext->pScb = pNpScb->pScb;
  341. if ( Icb->HasRemoteHandle ) {
  342. //
  343. // If we have a remote handle this is a file stream ICB. We
  344. // need to close the remote handle. The exchange will get us
  345. // to the head of the queue to protect the SCB state.
  346. //
  347. Status = ExchangeWithWait(
  348. IrpContext,
  349. SynchronousResponseCallback,
  350. "F-r",
  351. NCP_CLOSE,
  352. Icb->Handle, sizeof( Icb->Handle ) );
  353. Icb->HasRemoteHandle = FALSE;
  354. pNpScb->pScb->OpenNdsStreams--;
  355. ASSERT( pNpScb->pScb->MajorVersion > 3 );
  356. //
  357. // Do we need to unlicense this connection?
  358. //
  359. if ( ( pNpScb->pScb->UserName.Length == 0 ) &&
  360. ( pNpScb->pScb->VcbCount == 0 ) &&
  361. ( pNpScb->pScb->OpenNdsStreams == 0 ) ) {
  362. NdsUnlicenseConnection( IrpContext );
  363. }
  364. NwDequeueIrpContext( IrpContext, FALSE );
  365. }
  366. if ( Icb->IsExCredentialHandle ) {
  367. ExCreateDereferenceCredentials( IrpContext, Icb->pContext );
  368. }
  369. }
  370. if ( Icb->Pid != INVALID_PID ) {
  371. //
  372. // This ICB was involved in a search, send the end job,
  373. // then free the PID.
  374. //
  375. NwUnmapPid(pNpScb, Icb->Pid, IrpContext );
  376. }
  377. //
  378. // Update the time the SCB was last used.
  379. //
  380. KeQuerySystemTime( &pNpScb->LastUsedTime );
  381. //
  382. // Wait the SCB queue. We do this now since NwDeleteIcb may cause
  383. // a packet to be sent by this thread (from NwCleanupVcb()) while
  384. // holding the RCB. To eliminate this potential source of deadlock,
  385. // queue this IrpContext to the SCB queue before acquiring the RCB.
  386. //
  387. // Also, we mark this IRP context not reconnectable, since the
  388. // reconnect logic, will try to acquire the RCB.
  389. //
  390. NwAppendToQueueAndWait( IrpContext );
  391. ClearFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
  392. //
  393. // Delete the ICB.
  394. //
  395. NwDeleteIcb( IrpContext, Icb );
  396. //
  397. // And return to our caller
  398. //
  399. DebugTrace(-1, Dbg, "NwCloseIcb -> %08lx\n", Status);
  400. return Status;
  401. }