Windows NT 4.0 source code leak
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.

1166 lines
34 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. close.c
  5. Abstract:
  6. This module implements the NtClose API in the NT redirector.
  7. Author:
  8. Larry Osterman (LarryO) 16-Jul-1990
  9. Revision History:
  10. 16-Jul-1990 LarryO
  11. Created
  12. --*/
  13. #define INCLUDE_SMB_OPEN_CLOSE
  14. #define INCLUDE_SMB_READ_WRITE
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "stdarg.h"
  18. NTSTATUS
  19. RdrProcessDeleteOnClose(
  20. IN PIRP Irp,
  21. IN PICB Icb
  22. );
  23. VOID
  24. RdrFlushFileObjectForClose(
  25. IN PIRP Irp,
  26. IN PFILE_OBJECT FileObject,
  27. IN PICB Icb
  28. );
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(PAGE, RdrFsdCleanup)
  31. #pragma alloc_text(PAGE, RdrProcessDeleteOnClose)
  32. #pragma alloc_text(PAGE, RdrFsdClose)
  33. #pragma alloc_text(PAGE, RdrFlushFileObjectForClose)
  34. #endif
  35. NTSTATUS
  36. RdrFsdCleanup (
  37. IN PFS_DEVICE_OBJECT DeviceObject,
  38. IN PIRP Irp
  39. )
  40. /*++
  41. Routine Description:
  42. This routine processes the CLEANUP IRP request in the redirector FSD.
  43. This routine is called when all references to an existing handle
  44. have gone away. On a disk file, it will send the close SMB, on a
  45. file being used for a directory search the search will be closed
  46. on all other types of files, it is ignored.
  47. Arguments:
  48. DriverObject - Supplies a pointer to the redirector driver object.
  49. Irp - Supplies a pointer to the IRP to be processed.
  50. Return Value:
  51. NTSTATUS - The FSD status for this Irp.
  52. --*/
  53. {
  54. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  55. PFILE_OBJECT FileObject = IrpSp->FileObject;
  56. PICB Icb = ICB_OF(IrpSp);
  57. PFCB Fcb = FCB_OF(IrpSp);
  58. PSHARE_ACCESS ShareAccess;
  59. PAGED_CODE();
  60. if (DeviceObject == (PFS_DEVICE_OBJECT)BowserDeviceObject) {
  61. return BowserFsdCleanup(BowserDeviceObject, Irp);
  62. }
  63. FsRtlEnterFileSystem();
  64. //RdrLog(( "cleanup", &Fcb->FileName, 0 ));
  65. dprintf(DPRT_CLEANUP|DPRT_DISPATCH, ("RdrFsdCleanup: FileObject: %lx File: %lx (%wZ)\n", FileObject, Fcb, &Fcb->FileName));
  66. //
  67. // Lets assume that close is synchronous....
  68. //
  69. ASSERT(CanFsdWait(Irp)==TRUE);
  70. ASSERT(Icb->Signature==STRUCTURE_SIGNATURE_ICB);
  71. ASSERT(Fcb->Header.NodeTypeCode==STRUCTURE_SIGNATURE_FCB);
  72. RdrReferenceDiscardableCode(RdrFileDiscardableSection);
  73. //
  74. // We must have the file locked for some form of access before we close the file
  75. //
  76. RdrAcquireFcbLock(Fcb, ExclusiveLock, TRUE);
  77. if (Icb->Flags & ICB_TCONCREATED) {
  78. ULONG NumberOfTreeConnections;
  79. ULONG NumberOfOpenDirectories;
  80. ULONG NumberOfOpenFiles;
  81. //
  82. // If this file object caused the default security entry to be set
  83. // on a file, remove the default security entry.
  84. //
  85. if (Icb->Flags & ICB_SET_DEFAULT_SE) {
  86. RdrUnsetDefaultSecurityEntry(Icb->Se);
  87. }
  88. //
  89. // Now count the number of tree connections outstanding on this
  90. // connection (ie count the number of NET USEs to this connection.
  91. //
  92. RdrGetConnectionReferences(Fcb->Connection, NULL, Icb->Se,
  93. &NumberOfTreeConnections,
  94. &NumberOfOpenDirectories,
  95. &NumberOfOpenFiles);
  96. //
  97. // If this is the last tree connection, mark the connection as no
  98. // longer being tree connected (and thus eligable for enumeration via
  99. // the Enumerate_Connections FsCtl).
  100. //
  101. if ((NumberOfTreeConnections <= 1)) {
  102. dprintf(DPRT_CONNECT, ("Close Tree Connection. No connections left, turning off TREECONNECTED bit for \\%wZ\\%wZ\n", &Fcb->Connection->Server->Text, &Fcb->Connection->Text));
  103. RdrResetConnectlistFlag(Fcb->Connection, CLE_TREECONNECTED);
  104. }
  105. }
  106. if ((Icb->Type == Directory) &&
  107. FlagOn(Fcb->Connection->Server->Capabilities, DF_NT_SMBS)) {
  108. //
  109. // Mark the file as being forced closed in case a posted notify
  110. // comes in before we get the FCB lock and is processed after we
  111. // release the FCB lock.
  112. //
  113. Icb->Flags |= ICB_FORCECLOSED;
  114. //
  115. // Cancel any outstanding change notify requests for this directory.
  116. //
  117. RdrAbandonOutstandingRequests( FileObject );
  118. //
  119. // Release the FCB lock and wait for the outstanding directory
  120. // control change directories to complete.
  121. //
  122. // It is safe to release the FCB lock, because no other requests will
  123. // be coming in on this handle - there are no user references to this
  124. // handle, thus there can be no activity on this handle.
  125. //
  126. RdrReleaseFcbLock(Fcb);
  127. RdrWaitForAndXBehindOperation(&Icb->u.d.DirCtrlOutstanding);
  128. //
  129. // Re-acquire the FCB lock now.
  130. //
  131. RdrAcquireFcbLock(Fcb, ExclusiveLock, TRUE);
  132. }
  133. //
  134. // Mark that there is one less open outstanding on this file.
  135. //
  136. Fcb->NumberOfOpens -= 1 ;
  137. ASSERT (Fcb->NumberOfOpens >= 0);
  138. //
  139. // Update the last write time on the file to indicate when
  140. // we last modified the contents of the file.
  141. //
  142. if ((Icb->Flags & ICB_USER_SET_TIMES) == 0) {
  143. if (FileObject->Flags &FO_FILE_MODIFIED ) {
  144. LARGE_INTEGER CurrentTime;
  145. KeQuerySystemTime(&CurrentTime);
  146. Fcb->LastWriteTime = CurrentTime;
  147. Fcb->ChangeTime = CurrentTime;
  148. }
  149. }
  150. switch (Icb->Type) {
  151. case Unknown:
  152. InternalError(("Unknown file type passed into Cleanup\n"));
  153. break;
  154. case Redirector:
  155. //
  156. // Stop SmbTrace if it's running and the one closing is the
  157. // client who started it.
  158. //
  159. SmbTraceStop(FileObject, SMBTRACE_REDIRECTOR);
  160. // fall through
  161. case NetRoot:
  162. case Mailslot:
  163. break;
  164. case TreeConnect:
  165. break;
  166. case ServerRoot:
  167. case PrinterFile:
  168. case FileOrDirectory:
  169. break;
  170. case Directory:
  171. //
  172. // Complete any notify Irps on this file handle.
  173. //
  174. #ifdef NOTIFY
  175. FsRtlNotifyCleanup( Fcb->Connection->NotifySync,
  176. &Fcb->Connection->DirNotifyList,
  177. Icb );
  178. #endif
  179. break;
  180. case NamedPipe:
  181. case Com:
  182. ASSERT(NT_SUCCESS(RdrIsOperationValid(Icb, IRP_MJ_CLEANUP, FileObject)));
  183. // If we have write behind then flush the buffer.
  184. if ((Icb->Type == NamedPipe) &&
  185. ( Icb->NonPagedFcb->FileType == FileTypeByteModePipe ) &&
  186. ( Icb->u.p.PipeState & SMB_PIPE_NOWAIT )){
  187. // Prevent 2 threads corrupting Icb->u.p.WriteData
  188. if ( !RdrNpAcquireExclusive ( TRUE, &Icb->u.p.WriteData.Semaphore ) ) {
  189. // Another thread is accessing the pipe handle and !Wait
  190. InternalError(("Failed Exclusive access with Wait==TRUE"));
  191. }
  192. if ( RdrNpWriteFlush ( Irp, Icb, TRUE ) == STATUS_DRIVER_INTERNAL_ERROR ) {
  193. InternalError(("CancelTimer failed during close"));
  194. }
  195. RdrNpRelease ( &Icb->u.p.WriteData.Semaphore );
  196. ASSERT( Icb->u.p.TimeoutRunning == FALSE ); // All should be idle now
  197. }
  198. //
  199. // We want to send the close on this file from the cleanup IRP.
  200. //
  201. // If the file has a blocking read outstanding on this file,
  202. // the close IRP won't get generated until after the read completes,
  203. // thus we have to send the close SMB to allow outstanding reads
  204. // to unwind.
  205. //
  206. if ( !(Icb->Flags & ICB_DEFERREDOPEN) ) {
  207. NTSTATUS Status;
  208. // Only send close if we actually opened the remote file
  209. Status = RdrCloseFile(NULL, Icb, FileObject, TRUE);
  210. }
  211. break;
  212. case DiskFile:
  213. //
  214. // If the file has any locks outstanding on the file,
  215. // make sure they are unlocked.
  216. //
  217. (VOID) FsRtlFastUnlockAll( &Fcb->FileLock,
  218. FileObject,
  219. IoGetRequestorProcess( Irp ),
  220. Icb );
  221. //
  222. // Wait for any unlock behind operations on the file to complete.
  223. //
  224. RdrWaitForAndXBehindOperation(&Icb->u.f.AndXBehind);
  225. //
  226. // Set the CLEANUP_COMPLETE flag so that we don't try to
  227. // reinitialize the cache map. If a read or write initializes
  228. // the cache map after we uninitialize it below, the
  229. // reinitialized cache map will hang around forever, and maybe
  230. // cause a crash in the cache manager after the file object
  231. // disappears.
  232. //
  233. FileObject->Flags |= FO_CLEANUP_COMPLETE;
  234. //
  235. // If the file is cached, remove it from the cache.
  236. //
  237. if (Icb->Flags & ICB_HASHANDLE) {
  238. if (!FlagOn(FileObject->Flags, FO_TEMPORARY_FILE)) {
  239. NTSTATUS Status;
  240. //
  241. // Don't use this IRP for the write flush, since we can't use
  242. // write behind if we use this IRP.
  243. //
  244. Status = RdrFlushWriteBufferForFile(NULL, Icb, (BOOLEAN)!RdrUseAsyncWriteBehind);
  245. if (!NT_SUCCESS(Status)) {
  246. #if MAGIC_BULLET
  247. if ( RdrEnableMagic ) {
  248. RdrSendMagicBullet(NULL);
  249. DbgPrint( "RDR: About to raise close behind hard error for IRP %x\n", Irp );
  250. DbgBreakPoint();
  251. }
  252. #endif
  253. IoRaiseInformationalHardError(Status, NULL, Irp->Tail.Overlay.Thread);
  254. RdrWriteErrorLogEntry(Fcb->Connection->Server,
  255. IO_ERR_LAYERED_FAILURE,
  256. EVENT_RDR_CLOSE_BEHIND,
  257. Status,
  258. NULL,
  259. 0
  260. );
  261. }
  262. //
  263. // Wait for any write behind operations on the file to complete.
  264. //
  265. RdrWaitForWriteBehindOperation(Icb);
  266. //RdrLog(( "clean2", &Fcb->FileName, 0 ));
  267. }
  268. //
  269. // If the file is not oplocked with a batch file oplock, we
  270. // want to purge the file from the cache, otherwise we want
  271. // to simply tell the cache manager it can remove the file
  272. // when it wants to.
  273. //
  274. //
  275. // We also don't want to allow alternate data streams to live
  276. // in the cache after the file is closed, since we can't easily
  277. // detect when they are re-opened.
  278. //
  279. if ((Icb->u.f.Flags & ICBF_OPLOCKED) &&
  280. (Icb->u.f.OplockLevel == SMB_OPLOCK_LEVEL_BATCH) &&
  281. (Icb->NonPagedFcb->SharingCheckFcb == NULL)) {
  282. dprintf(DPRT_CACHE, ("Removing file %lx (Fcb %lx) from the cache (soft)\n", FileObject, Fcb));
  283. //
  284. // Remove the file from the cache. We call
  285. // CcUninitializeCacheMap because we want to enable the "Lazy
  286. // Delete" logic.
  287. //
  288. //RdrLog(( "ccunini2", &Fcb->FileName, 1, 0xffffffff ));
  289. CcUninitializeCacheMap(FileObject, NULL, NULL);
  290. } else {
  291. //
  292. // Flush the file from the cache.
  293. //
  294. //RdrLog(( "rdflshc2", &Fcb->FileName, 0 ));
  295. RdrFlushFileObjectForClose(Irp, FileObject, Icb);
  296. //
  297. // Otherwise, we need to pull the file from the cache
  298. // right now.
  299. //
  300. if (CcIsFileCached(FileObject)) {
  301. dprintf(DPRT_CACHE, ("Removing file %lx (Fcb %lx) from the cache (hard)\n", FileObject, Fcb));
  302. //
  303. // WARNING: This will release and re-acquire the FCB lock
  304. //
  305. //RdrLog(( "rdunini2", &Fcb->FileName, 0 ));
  306. RdrUninitializeCacheMap(FileObject, &RdrZero);
  307. } else {
  308. //
  309. // Make sure that the cache manager cleans up from this file. Even
  310. // though it is currently not cached, maybe it was at one time and
  311. // somehow got PrivateCacheMap set to non NULL.
  312. //
  313. dprintf(DPRT_CACHE, ("Removing file %lx (Fcb %lx) from the cache (soft)\n", FileObject, Fcb));
  314. //
  315. // WARNING: This will release and re-acquire the FCB lock
  316. //
  317. //RdrLog(( "rdunini3", &Fcb->FileName, 1, 0xffffffff ));
  318. RdrUninitializeCacheMap(FileObject, NULL);
  319. }
  320. //
  321. // If this is an executable opened over the net, then
  322. // its possible that the executables image section
  323. // might still be kept open.
  324. //
  325. // Ask MM to flush the section closed. This will fail
  326. // if the executable in question is still running.
  327. //
  328. //RdrLog(( "mmflush2", &Fcb->FileName, 1, MmFlushForWrite ));
  329. MmFlushImageSection(&Fcb->NonPagedFcb->SectionObjectPointer,
  330. MmFlushForWrite);
  331. //
  332. // There is also a possiblity that there is a user section
  333. // open on this file, in which case we need to force the
  334. // section closed to make sure that they are cleaned up.
  335. //
  336. //RdrLog(( "mmforce2", &Fcb->FileName, 1, TRUE ));
  337. MmForceSectionClosed(&Fcb->NonPagedFcb->SectionObjectPointer, TRUE);
  338. }
  339. } else {
  340. //
  341. // This file has been invalidated.
  342. //
  343. // Check to see if it is still in the cache, and if it is,
  344. // blow it away.
  345. //
  346. // This can happen if a read request comes in while the redir
  347. // is tearing down a connection (in RdrInvalidateConnectionFiles),
  348. // and re-initializes the cache map.
  349. //
  350. //
  351. // WARNING: This will release and re-acquire the FCB lock
  352. //
  353. //RdrLog(( "rdunini3", &Fcb->FileName, 0 ));
  354. RdrUninitializeCacheMap(FileObject, &RdrZero);
  355. }
  356. break;
  357. default:
  358. dprintf(DPRT_CLEANUP, ("Unsupported file type passed into RdrFsdCleanup\n"));
  359. break;
  360. }
  361. //
  362. // Remove the sharing semantics for this file, it's now closed
  363. //
  364. if ((Icb->Type != NamedPipe) &&
  365. (Icb->Type != Mailslot) &&
  366. (Icb->Type != PrinterFile) &&
  367. (Icb->Type != Com)) {
  368. if (Icb->NonPagedFcb->SharingCheckFcb != NULL) {
  369. ShareAccess = &Icb->NonPagedFcb->SharingCheckFcb->ShareAccess;
  370. } else {
  371. ShareAccess = &Icb->Fcb->ShareAccess;
  372. }
  373. dprintf(DPRT_CLEANUP, ("Removing share access for file object %08lx, Fcb = %08lx, ShareAccess=%08lx\n", FileObject, Fcb, ShareAccess));
  374. RdrRemoveShareAccess(FileObject, ShareAccess);
  375. }
  376. //
  377. // If there are no other user handles to this file, and the file is still
  378. // oplocked, then mark a timeout for the file to expire.
  379. //
  380. if ((Fcb->NumberOfOpens == 0)
  381. &&
  382. (Icb->u.f.Flags & ICBF_OPLOCKED)) {
  383. RdrReleaseFcbLock(Fcb);
  384. RdrSetDormantCachedFile(Fcb);
  385. } else {
  386. RdrReleaseFcbLock(Fcb);
  387. }
  388. dprintf(DPRT_CLEANUP, ("Completing IRP with status= %X\n", STATUS_SUCCESS));
  389. RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
  390. RdrCompleteRequest(Irp, STATUS_SUCCESS);
  391. FsRtlExitFileSystem();
  392. return STATUS_SUCCESS;
  393. UNREFERENCED_PARAMETER(DeviceObject);
  394. }
  395. VOID
  396. RdrFlushFileObjectForClose(
  397. IN PIRP Irp,
  398. IN PFILE_OBJECT FileObject,
  399. IN PICB Icb
  400. )
  401. {
  402. IO_STATUS_BLOCK IoSb;
  403. PFCB Fcb = Icb->Fcb;
  404. PAGED_CODE();
  405. //
  406. // If this is not a temporary file, we need to flush the data
  407. // on the file on close.
  408. //
  409. // If it IS a temporary file, we can skip doing the flush, and
  410. // toss any write behind data.
  411. //
  412. if (!FlagOn(FileObject->Flags, FO_TEMPORARY_FILE)) {
  413. //
  414. // First flush the file's dirty data from the cache.
  415. //
  416. //RdrLog(( "ccflush3", &Fcb->FileName, 1, 0xffffffff ));
  417. CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &IoSb);
  418. if (!NT_SUCCESS(IoSb.Status)) {
  419. #if MAGIC_BULLET
  420. if ( RdrEnableMagic ) {
  421. RdrSendMagicBullet(NULL);
  422. DbgPrint( "RDR: About to raise close behind lost data hard error for IRP %x\n", Irp );
  423. DbgBreakPoint();
  424. }
  425. #endif
  426. IoRaiseInformationalHardError(IoSb.Status, NULL,
  427. Irp->Tail.Overlay.Thread);
  428. KdPrint(("RDR: Data lost on close behind: %X\n", IoSb.Status));
  429. RdrWriteErrorLogEntry(
  430. Fcb->Connection->Server,
  431. IO_ERR_LAYERED_FAILURE,
  432. EVENT_RDR_CLOSE_BEHIND,
  433. IoSb.Status,
  434. NULL,
  435. 0
  436. );
  437. } else {
  438. //
  439. // Serialize behind paging I/O to ensure flush is done.
  440. //
  441. ExAcquireResourceExclusive(Icb->Fcb->Header.PagingIoResource, TRUE);
  442. ExReleaseResource(Icb->Fcb->Header.PagingIoResource);
  443. }
  444. }
  445. }
  446. NTSTATUS
  447. RdrFsdClose (
  448. IN PFS_DEVICE_OBJECT DeviceObject,
  449. IN PIRP Irp
  450. )
  451. /*++
  452. Routine Description:
  453. This routine processes the NtClose request in the redirector FSD.
  454. Arguments:
  455. DriverObject - Supplies a pointer to the redirector driver object.
  456. Irp - Supplies a pointer to the IRP to be processed.
  457. Return Value:
  458. NTSTATUS - The FSD status for this Irp.
  459. Note:
  460. There is a race condition with close behind here.
  461. The problem is as follows:
  462. When we close behind a file, it is possible that the close will
  463. complete before the CLOSE IRP comes into the redirector. In order to
  464. close the race condition, we have to reference the file object to prevent
  465. the close from coming into the redirector until the file has been completely
  466. closed.
  467. We also have to have the file locked before the close comes in because it
  468. is possible that another open will come in for this file before the close is
  469. processed. If this is the case, then the sharing modes of the two openers
  470. may be incompatable, so we want to block the open from proceeding until the
  471. close has finally completed.
  472. --*/
  473. {
  474. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  475. PFILE_OBJECT FileObject = IrpSp->FileObject;
  476. PICB Icb = ICB_OF(IrpSp);
  477. PFCB Fcb = FCB_OF(IrpSp);
  478. PSECURITY_ENTRY Se;
  479. NTSTATUS Status = STATUS_SUCCESS;
  480. BOOLEAN DereferenceDiscardableCode = TRUE;
  481. PAGED_CODE();
  482. if (DeviceObject == (PFS_DEVICE_OBJECT)BowserDeviceObject) {
  483. return BowserFsdClose(BowserDeviceObject, Irp);
  484. }
  485. FsRtlEnterFileSystem();
  486. //RdrLog(( "close", &Fcb->FileName, 0 ));
  487. Se = Icb->Se;
  488. dprintf(DPRT_DISPATCH|DPRT_CLOSE, ("RdrFsdClose, FileObject: %08lx Fcb:%08lx (%wZ)\n", FileObject, Fcb, &Fcb->FileName));
  489. ASSERT(CanFsdWait(Irp)==TRUE);
  490. ASSERT(Icb->Fcb == Fcb);
  491. ASSERT(Icb->Signature==STRUCTURE_SIGNATURE_ICB);
  492. ASSERT(Fcb->Header.NodeTypeCode==STRUCTURE_SIGNATURE_FCB);
  493. //
  494. // We must have the file locked for some form of access
  495. // before we initiate the close of the file, because
  496. // of the problem described in RdrFsdCleanup.
  497. //
  498. // This will have the side effect of waiting for any
  499. // write&unlock operations to complete
  500. //
  501. RdrAcquireFcbLock(Fcb, ExclusiveLock, TRUE);
  502. try {
  503. RdrReferenceDiscardableCode(RdrFileDiscardableSection);
  504. switch (Icb->Type) {
  505. case Redirector:
  506. case NetRoot:
  507. //
  508. // All that is necessary to do when closing a redirector file
  509. // is to free up the ICB pointer.
  510. //
  511. RdrFreeIcb(Icb);
  512. if (Se != NULL) {
  513. RdrDereferenceSecurityEntryForFile(Se);
  514. }
  515. RdrDereferenceFcb(Irp, Fcb->NonPagedFcb, TRUE, 0, Se);
  516. if (Se != NULL) {
  517. RdrDereferenceSecurityEntry(Se->NonPagedSecurityEntry);
  518. }
  519. DereferenceDiscardableCode = FALSE;
  520. try_return(Status = STATUS_SUCCESS);
  521. break;
  522. case Directory:
  523. case DiskFile:
  524. if (Icb->Flags & ICB_HASHANDLE ) {
  525. LONG NumberOfOpenFiles = 0;
  526. LONG TotalNumberOfFiles = 0;
  527. PLIST_ENTRY IcbEntry;
  528. #ifdef _CAIRO_ // OFS STORAGE
  529. //
  530. // Release any pending searches. We do this on all file
  531. // and dir handles since OFS supports enumeration of embeddings
  532. // through file handles
  533. //
  534. Status = RdrFindClose (Irp, Icb, Icb->u.d.Scb);
  535. #else
  536. //
  537. // If this is a directory, close any outstanding searches on
  538. // the file.
  539. //
  540. if (Icb->Type == Directory) {
  541. Status = RdrFindClose(Irp, Icb, Icb->u.d.Scb);
  542. }
  543. #endif
  544. //
  545. // Count the number of ICB's associated with this FCB that have
  546. // the same file id as the one we are trying to close. If it is the
  547. // only file with that file id, then it is safe to close this file.
  548. //
  549. // If there are other ICB's that share this file's ICB, then it is unsafe
  550. // to close the remote file, so we should simply close the file.
  551. //
  552. for (IcbEntry = Fcb->InstanceChain.Flink ;
  553. IcbEntry != &Fcb->InstanceChain ;
  554. IcbEntry = IcbEntry->Flink) {
  555. PICB IcbToFlush = CONTAINING_RECORD(IcbEntry, ICB, InstanceNext);
  556. if ((IcbToFlush->Flags & ICB_HASHANDLE)
  557. &&
  558. (IcbToFlush->FileId == Icb->FileId)) {
  559. NumberOfOpenFiles += 1;
  560. }
  561. if (IcbToFlush->Flags & ICB_HASHANDLE) {
  562. TotalNumberOfFiles += 1;
  563. }
  564. }
  565. ASSERT (NumberOfOpenFiles >= 1);
  566. if (NumberOfOpenFiles == 1) {
  567. //
  568. // If this is not a level II oplock, then flag that there
  569. // are going to be no more oplock breaks on this file.
  570. //
  571. if (Fcb->NonPagedFcb->OplockLevel != SMB_OPLOCK_LEVEL_II) {
  572. Fcb->NonPagedFcb->Flags &= ~FCB_OPLOCKED;
  573. }
  574. //
  575. // We want to turn of the HasOplockHandle if
  576. // we're closing the oplocked file id.
  577. //
  578. if (Icb->FileId == Fcb->NonPagedFcb->OplockedFileId) {
  579. Fcb->NonPagedFcb->Flags &= ~FCB_HASOPLOCKHANDLE;
  580. //
  581. // Blast the oplocked file id on the file - it's
  582. // no longer good.
  583. //
  584. Fcb->NonPagedFcb->OplockedFileId = 0;
  585. //
  586. // If there's an oplocked security entry for this
  587. // file, dereference it and reset the pointer - it
  588. // can no longer be good.
  589. //
  590. if (Fcb->NonPagedFcb->OplockedSecurityEntry != NULL) {
  591. RdrDereferenceSecurityEntry(Fcb->NonPagedFcb->OplockedSecurityEntry);
  592. Fcb->NonPagedFcb->OplockedSecurityEntry = NULL;
  593. }
  594. }
  595. Status = RdrCloseFile(Irp, Icb, FileObject, TRUE);
  596. if ((TotalNumberOfFiles == 1) &&
  597. (FlagOn(Fcb->NonPagedFcb->Flags,FCB_DELETEONCLOSE))) {
  598. RdrProcessDeleteOnClose( Irp, Icb );
  599. }
  600. #ifdef NOTIFY
  601. //
  602. // We call the notify package to report that the
  603. // attribute and last modification times have both
  604. // changed.
  605. //
  606. FsRtlNotifyReportChange( Fcb->Connection->NotifySync,
  607. &Fcb->Connection->DirNotifyList,
  608. (PANSI_STRING)&Fcb->FileName,
  609. (PANSI_STRING)&Fcb->LastFileName,
  610. FILE_NOTIFY_CHANGE_LAST_WRITE );
  611. #endif
  612. if (Icb->Flags & ICB_SETATTRONCLOSE) {
  613. FILE_BASIC_INFORMATION BasicInfo;
  614. RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
  615. BasicInfo.FileAttributes = Icb->Fcb->Attribute;
  616. Status = RdrSetFileAttributes(Irp, Icb, &BasicInfo);
  617. if (!NT_SUCCESS(Status)) {
  618. RdrWriteErrorLogEntry(
  619. Fcb->Connection->Server,
  620. IO_ERR_LAYERED_FAILURE,
  621. EVENT_RDR_DELAYED_SET_ATTRIBUTES_FAILED,
  622. Status,
  623. Icb->Fcb->FileName.Buffer,
  624. Icb->Fcb->FileName.Length
  625. );
  626. }
  627. }
  628. //
  629. // RdrUnlinkAndFreeIcb will release the FCB lock.
  630. //
  631. RdrUnlinkAndFreeIcb (Irp, Icb, FileObject);
  632. try_return(Status);
  633. } else {
  634. //
  635. // Some other file handle is active on this file,
  636. // so we just want to unlink this from the FCB.
  637. //
  638. RdrUnlinkAndFreeIcb(Irp, Icb, FileObject);
  639. try_return(Status = STATUS_SUCCESS);
  640. break;
  641. }
  642. ASSERT (FALSE);
  643. }
  644. if (Icb->Flags & ICB_DELETEONCLOSE) {
  645. Status = RdrProcessDeleteOnClose(Irp, Icb);
  646. }
  647. //
  648. // NOTE: FALL THROUGH
  649. //
  650. // On disk files, if there is no associated remote file id, this means that
  651. // we want to simply free up the storage associated with the file.
  652. //
  653. case TreeConnect:
  654. //
  655. // We are closing a tree connection with a special IPC connection
  656. // on it. Release the synchronization event protecting
  657. // access to the special IPC connection.
  658. //
  659. // if (Se->Transport != NULL) {
  660. // ASSERT (Se->Flags & SE_USE_SPECIAL_IPC);
  661. //
  662. // KeSetEvent(&Fcb->Connection->Server->SpecialIpcSynchronizationLock, 0, FALSE);
  663. // }
  664. case Mailslot:
  665. case ServerRoot:
  666. //
  667. // If this is a directory, close any outstanding searches on
  668. // the file.
  669. //
  670. if (Icb->Type == Directory || Icb->Type == TreeConnect) {
  671. Status = RdrFindClose(Irp, Icb, Icb->u.d.Scb);
  672. }
  673. //
  674. // All that the redirector has to do to close a tree connection
  675. // is to remove the reference to the connection structure.
  676. //
  677. if (FlagOn(Icb->Flags, ICB_TCONCREATED)) {
  678. DereferenceDiscardableCode = FALSE;
  679. }
  680. RdrUnlinkAndFreeIcb (Irp, Icb, FileObject);
  681. try_return(Status = STATUS_SUCCESS);
  682. break;
  683. case PrinterFile:
  684. ASSERT (!FlagOn(Icb->Flags, ICB_DELETEONCLOSE));
  685. ASSERT(NT_SUCCESS(RdrIsOperationValid(Icb, IRP_MJ_CLOSE, FileObject)));
  686. //
  687. // We want to send the close on this file from the cleanup IRP.
  688. //
  689. // If the file has a blocking read outstanding on this file,
  690. // the close IRP won't get generated until after the read completes,
  691. // thus we have to send the close SMB to allow outstanding reads
  692. // to unwind.
  693. //
  694. if ( !(Icb->Flags & ICB_DEFERREDOPEN) ) {
  695. NTSTATUS Status;
  696. // Only send close if we actually opened the remote file
  697. Status = RdrCloseFile(NULL, Icb, FileObject, TRUE);
  698. }
  699. RdrUnlinkAndFreeIcb (Irp, Icb, FileObject);
  700. try_return(Status);
  701. break;
  702. case NamedPipe:
  703. case Com:
  704. case FileOrDirectory:
  705. ASSERT (!FlagOn(Icb->Flags, ICB_DELETEONCLOSE));
  706. //
  707. // All that the redirector has to do to close one of these files
  708. // is to remove the reference to the connection structure.
  709. //
  710. RdrUnlinkAndFreeIcb (Irp, Icb, FileObject);
  711. try_return(Status);
  712. break;
  713. case Unknown:
  714. InternalError(("Unknown file type passed into NtCloseFile\n"));
  715. try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
  716. break;
  717. default:
  718. InternalError(("Unsupported file type passed into RdrFsdClose\n"));
  719. try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
  720. break;
  721. }
  722. try_exit:NOTHING;
  723. } finally {
  724. dprintf(DPRT_CLOSE, ("Completing IRP with status= %X\n", Status));
  725. if (Status != STATUS_PENDING) {
  726. //
  727. // If the close failed, we want to unwind from the close operation
  728. // and release the resources associated with the file, since
  729. // we can't recover properly anyway.
  730. //
  731. RdrCompleteRequest(Irp, Status);
  732. }
  733. RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
  734. if (DereferenceDiscardableCode) {
  735. RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
  736. }
  737. }
  738. FsRtlExitFileSystem();
  739. return Status;
  740. if (DeviceObject);
  741. }
  742. NTSTATUS
  743. RdrProcessDeleteOnClose(
  744. IN PIRP Irp,
  745. IN PICB Icb
  746. )
  747. {
  748. NTSTATUS status;
  749. PFCB fcb=Icb->Fcb;
  750. PAGED_CODE();
  751. //
  752. // If this is a deleteonclose file handle, and the FCB in question
  753. // exists, then we want to delete the file now.
  754. //
  755. if (!FlagOn(fcb->NonPagedFcb->Flags, FCB_DOESNTEXIST)) {
  756. if (Icb->Type == DiskFile) {
  757. status = RdrDeleteFile(
  758. Irp, &fcb->FileName,
  759. BooleanFlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE),
  760. fcb->Connection, Icb->Se);
  761. } else if (Icb->Type == Directory) {
  762. status = RdrGenericPathSmb(Irp,
  763. SMB_COM_DELETE_DIRECTORY,
  764. BooleanFlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE),
  765. &fcb->FileName,
  766. fcb->Connection,
  767. Icb->Se);
  768. } else {
  769. InternalError(("Unknown file type passed into RdrProcessDeleteOnClose: %d\n", Icb->Type));
  770. }
  771. if (!NT_SUCCESS(status)) {
  772. RdrWriteErrorLogEntry(fcb->Connection->Server,
  773. IO_ERR_LAYERED_FAILURE,
  774. EVENT_RDR_DELETEONCLOSE_FAILED,
  775. status,
  776. Icb->Fcb->FileName.Buffer,
  777. Icb->Fcb->FileName.Length
  778. );
  779. } else {
  780. //
  781. // The file specified doesn't exist anymore.
  782. //
  783. fcb->NonPagedFcb->Flags |= FCB_DOESNTEXIST;
  784. }
  785. }
  786. return status;
  787. }
  788. #if DBG || RDRDBG_LOG
  789. #define RDR_LOG_MAX 2048
  790. #define RDR_LOG_EVENT_LENGTH 8
  791. #define RDR_LOG_DWORDS_LENGTH 12
  792. #define RDR_LOG_TEXT_LENGTH 4
  793. ULONG RdrLogIndex = 0;
  794. typedef struct {
  795. UCHAR Event[RDR_LOG_EVENT_LENGTH];
  796. ULONG Dwords[RDR_LOG_DWORDS_LENGTH];
  797. WCHAR Text[RDR_LOG_TEXT_LENGTH];
  798. } RDR_LOG, *PRDR_LOG;
  799. RDR_LOG RdrLogBuffer[RDR_LOG_MAX] = {0};
  800. BOOLEAN RdrLogDisabled = FALSE;
  801. VOID
  802. RdrLog2 (
  803. IN PSZ Event,
  804. IN PUNICODE_STRING Text,
  805. IN ULONG DwordCount,
  806. ...
  807. )
  808. {
  809. PRDR_LOG log;
  810. KIRQL oldIrql;
  811. PWCH buff;
  812. ULONG len;
  813. ULONG index;
  814. PULONG dword;
  815. va_list arglist;
  816. if (RdrLogDisabled) return;
  817. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  818. log = &RdrLogBuffer[RdrLogIndex];
  819. if ( ++RdrLogIndex >= RDR_LOG_MAX ) {
  820. RdrLogIndex = 0;
  821. }
  822. KeLowerIrql( oldIrql );
  823. RtlZeroMemory( log, sizeof(RDR_LOG) );
  824. strncpy( log->Event, Event, RDR_LOG_EVENT_LENGTH );
  825. if ( Text != NULL ) {
  826. buff = Text->Buffer;
  827. len = Text->Length/sizeof(WCHAR);
  828. if ( len > RDR_LOG_TEXT_LENGTH ) {
  829. buff += len - RDR_LOG_TEXT_LENGTH;
  830. len = RDR_LOG_TEXT_LENGTH;
  831. }
  832. wcsncpy( log->Text, buff, len );
  833. }
  834. va_start( arglist, DwordCount );
  835. dword = log->Dwords;
  836. for ( index = 0; index < MIN(DwordCount,RDR_LOG_DWORDS_LENGTH); index++ ) {
  837. *dword++ = va_arg( arglist, ULONG );
  838. }
  839. return;
  840. }
  841. #endif