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.

555 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. FilObSup.c
  5. Abstract:
  6. This module implements the Fat File object support routines.
  7. // @@BEGIN_DDKSPLIT
  8. Author:
  9. Gary Kimura [GaryKi] 30-Aug-1990
  10. Revision History:
  11. // @@END_DDKSPLIT
  12. --*/
  13. #include "FatProcs.h"
  14. //
  15. // The Bug check file id for this module
  16. //
  17. #define BugCheckFileId (FAT_BUG_CHECK_FILOBSUP)
  18. //
  19. // The debug trace level
  20. //
  21. #define Dbg (DEBUG_TRACE_FILOBSUP)
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE, FatForceCacheMiss)
  24. #pragma alloc_text(PAGE, FatPurgeReferencedFileObjects)
  25. #pragma alloc_text(PAGE, FatSetFileObject)
  26. #pragma alloc_text(PAGE, FatDecodeFileObject)
  27. #endif
  28. VOID
  29. FatSetFileObject (
  30. IN PFILE_OBJECT FileObject OPTIONAL,
  31. IN TYPE_OF_OPEN TypeOfOpen,
  32. IN PVOID VcbOrFcbOrDcb,
  33. IN PCCB Ccb OPTIONAL
  34. )
  35. /*++
  36. Routine Description:
  37. This routine sets the file system pointers within the file object
  38. Arguments:
  39. FileObject - Supplies a pointer to the file object being modified, and
  40. can optionally be null.
  41. TypeOfOpen - Supplies the type of open denoted by the file object.
  42. This is only used by this procedure for sanity checking.
  43. VcbOrFcbOrDcb - Supplies a pointer to either a vcb, fcb, or dcb
  44. Ccb - Optionally supplies a pointer to a ccb
  45. Return Value:
  46. None.
  47. --*/
  48. {
  49. DebugTrace(+1, Dbg, "FatSetFileObject, FileObject = %08lx\n", FileObject );
  50. ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB));
  51. ASSERT(((TypeOfOpen == UnopenedFileObject))
  52. ||
  53. ((TypeOfOpen == UserFileOpen) &&
  54. (NodeType(VcbOrFcbOrDcb) == FAT_NTC_FCB) &&
  55. (Ccb != NULL))
  56. ||
  57. ((TypeOfOpen == EaFile) &&
  58. (NodeType(VcbOrFcbOrDcb) == FAT_NTC_FCB) &&
  59. (Ccb == NULL))
  60. ||
  61. ((TypeOfOpen == UserDirectoryOpen) &&
  62. ((NodeType(VcbOrFcbOrDcb) == FAT_NTC_DCB) || (NodeType(VcbOrFcbOrDcb) == FAT_NTC_ROOT_DCB)) &&
  63. (Ccb != NULL))
  64. ||
  65. ((TypeOfOpen == UserVolumeOpen) &&
  66. (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) &&
  67. (Ccb != NULL))
  68. ||
  69. ((TypeOfOpen == VirtualVolumeFile) &&
  70. (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) &&
  71. (Ccb == NULL))
  72. ||
  73. ((TypeOfOpen == DirectoryFile) &&
  74. ((NodeType(VcbOrFcbOrDcb) == FAT_NTC_DCB) || (NodeType(VcbOrFcbOrDcb) == FAT_NTC_ROOT_DCB)) &&
  75. (Ccb == NULL)));
  76. //
  77. // If we were given an Fcb, Dcb, or Vcb, we have some processing to do.
  78. //
  79. ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB));
  80. if ( VcbOrFcbOrDcb != NULL ) {
  81. //
  82. // Set the Vpb field in the file object, and if we were given an
  83. // Fcb or Dcb move the field over to point to the nonpaged Fcb/Dcb
  84. //
  85. if (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) {
  86. FileObject->Vpb = ((PVCB)VcbOrFcbOrDcb)->Vpb;
  87. } else {
  88. FileObject->Vpb = ((PFCB)VcbOrFcbOrDcb)->Vcb->Vpb;
  89. //
  90. // If this is a temporary file, note it in the FcbState
  91. //
  92. if (FlagOn(((PFCB)VcbOrFcbOrDcb)->FcbState, FCB_STATE_TEMPORARY)) {
  93. SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
  94. }
  95. }
  96. }
  97. ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB));
  98. //
  99. // Now set the fscontext fields of the file object
  100. //
  101. if (ARGUMENT_PRESENT( FileObject )) {
  102. FileObject->FsContext = VcbOrFcbOrDcb;
  103. FileObject->FsContext2 = Ccb;
  104. }
  105. ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB));
  106. //
  107. // And return to our caller
  108. //
  109. DebugTrace(-1, Dbg, "FatSetFileObject -> VOID\n", 0);
  110. return;
  111. }
  112. TYPE_OF_OPEN
  113. FatDecodeFileObject (
  114. IN PFILE_OBJECT FileObject,
  115. OUT PVCB *Vcb,
  116. OUT PFCB *FcbOrDcb,
  117. OUT PCCB *Ccb
  118. )
  119. /*++
  120. Routine Description:
  121. This procedure takes a pointer to a file object, that has already been
  122. opened by the Fat file system and figures out what really is opened.
  123. Arguments:
  124. FileObject - Supplies the file object pointer being interrogated
  125. Vcb - Receives a pointer to the Vcb for the file object.
  126. FcbOrDcb - Receives a pointer to the Fcb/Dcb for the file object, if
  127. one exists.
  128. Ccb - Receives a pointer to the Ccb for the file object, if one exists.
  129. Return Value:
  130. TYPE_OF_OPEN - returns the type of file denoted by the input file object.
  131. UserFileOpen - The FO represents a user's opened data file.
  132. Ccb, FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb.
  133. UserDirectoryOpen - The FO represents a user's opened directory.
  134. Ccb, FcbOrDcb, and Vcb are set. FcbOrDcb points to a Dcb/RootDcb
  135. UserVolumeOpen - The FO represents a user's opened volume.
  136. Ccb and Vcb are set. FcbOrDcb is null.
  137. VirtualVolumeFile - The FO represents the special virtual volume file.
  138. Vcb is set, and Ccb and FcbOrDcb are null.
  139. DirectoryFile - The FO represents a special directory file.
  140. Vcb and FcbOrDcb are set. Ccb is null. FcbOrDcb points to a
  141. Dcb/RootDcb.
  142. EaFile - The FO represents an Ea Io stream file.
  143. FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb, and Ccb is
  144. null.
  145. --*/
  146. {
  147. TYPE_OF_OPEN TypeOfOpen;
  148. PVOID FsContext;
  149. PVOID FsContext2;
  150. DebugTrace(+1, Dbg, "FatDecodeFileObject, FileObject = %08lx\n", FileObject);
  151. //
  152. // Reference the fs context fields of the file object, and zero out
  153. // the out pointer parameters.
  154. //
  155. FsContext = FileObject->FsContext;
  156. FsContext2 = FileObject->FsContext2;
  157. //
  158. // Special case the situation where FsContext is null
  159. //
  160. if (FsContext == NULL) {
  161. *Ccb = NULL;
  162. *FcbOrDcb = NULL;
  163. *Vcb = NULL;
  164. TypeOfOpen = UnopenedFileObject;
  165. } else {
  166. //
  167. // Now we can case on the node type code of the fscontext pointer
  168. // and set the appropriate out pointers
  169. //
  170. switch (NodeType(FsContext)) {
  171. case FAT_NTC_VCB:
  172. *Ccb = FsContext2;
  173. *FcbOrDcb = NULL;
  174. *Vcb = FsContext;
  175. TypeOfOpen = ( *Ccb == NULL ? VirtualVolumeFile : UserVolumeOpen );
  176. break;
  177. case FAT_NTC_ROOT_DCB:
  178. case FAT_NTC_DCB:
  179. *Ccb = FsContext2;
  180. *FcbOrDcb = FsContext;
  181. *Vcb = (*FcbOrDcb)->Vcb;
  182. TypeOfOpen = ( *Ccb == NULL ? DirectoryFile : UserDirectoryOpen );
  183. DebugTrace(0, Dbg, "Referencing directory: %Z\n", &(*FcbOrDcb)->FullFileName);
  184. break;
  185. case FAT_NTC_FCB:
  186. *Ccb = FsContext2;
  187. *FcbOrDcb = FsContext;
  188. *Vcb = (*FcbOrDcb)->Vcb;
  189. TypeOfOpen = ( *Ccb == NULL ? EaFile : UserFileOpen );
  190. DebugTrace(0, Dbg, "Referencing file: %Z\n", &(*FcbOrDcb)->FullFileName);
  191. break;
  192. default:
  193. FatBugCheck( NodeType(FsContext), 0, 0 );
  194. }
  195. }
  196. //
  197. // and return to our caller
  198. //
  199. DebugTrace(-1, Dbg, "FatDecodeFileObject -> %08lx\n", TypeOfOpen);
  200. return TypeOfOpen;
  201. }
  202. VOID
  203. FatPurgeReferencedFileObjects (
  204. IN PIRP_CONTEXT IrpContext,
  205. IN PFCB Fcb,
  206. IN FAT_FLUSH_TYPE FlushType
  207. )
  208. /*++
  209. Routine Description:
  210. This routine non-recursively walks from the given FcbOrDcb and trys
  211. to force Cc or Mm to close any sections it may be holding on to.
  212. Arguments:
  213. Fcb - Supplies a pointer to either an fcb or a dcb
  214. FlushType - Specifies the kind of flushing to perform
  215. Return Value:
  216. None.
  217. --*/
  218. {
  219. PFCB OriginalFcb = Fcb;
  220. PFCB NextFcb;
  221. DebugTrace(+1, Dbg, "FatPurgeReferencedFileObjects, Fcb = %08lx\n", Fcb );
  222. ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  223. //
  224. // First, if we have a delayed close, force it closed.
  225. //
  226. FatFspClose(Fcb->Vcb);
  227. //
  228. // Walk the directory tree forcing sections closed.
  229. //
  230. // Note that it very important to get the next node to visit before
  231. // acting on the current node. This is because acting on a node may
  232. // make it, and an arbitrary number of direct ancestors, vanish.
  233. // Since we never visit ancestors in our top-down enumeration scheme, we
  234. // can safely continue the enumeration even when the tree is vanishing
  235. // beneath us. This is way cool.
  236. //
  237. while ( Fcb != NULL ) {
  238. NextFcb = FatGetNextFcbTopDown(IrpContext, Fcb, OriginalFcb);
  239. //
  240. // Check for the EA file fcb
  241. //
  242. if ( !FlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_VOLUME_ID) ) {
  243. FatForceCacheMiss( IrpContext, Fcb, FlushType );
  244. }
  245. Fcb = NextFcb;
  246. }
  247. DebugTrace(-1, Dbg, "FatPurgeReferencedFileObjects (VOID)\n", 0 );
  248. return;
  249. }
  250. VOID
  251. FatForceCacheMiss (
  252. IN PIRP_CONTEXT IrpContext,
  253. IN PFCB Fcb,
  254. IN FAT_FLUSH_TYPE FlushType
  255. )
  256. /*++
  257. Routine Description:
  258. The following routine asks either Cc or Mm to get rid of any cached
  259. pages on a file. Note that this will fail if a user has mapped a file.
  260. If there is a shared cache map, purge the cache section. Otherwise
  261. we have to go and ask Mm to blow away the section.
  262. NOTE: This caller MUST own the Vcb exclusive.
  263. Arguments:
  264. Fcb - Supplies a pointer to an fcb
  265. FlushType - Specifies the kind of flushing to perform
  266. Return Value:
  267. None.
  268. --*/
  269. {
  270. PVCB Vcb;
  271. BOOLEAN ChildrenAcquired = FALSE;
  272. //
  273. // If we can't wait, bail.
  274. //
  275. ASSERT( FatVcbAcquiredExclusive( IrpContext, Fcb->Vcb ) ||
  276. FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) );
  277. if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
  278. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  279. }
  280. //
  281. // If we are purging a directory file object, we must acquire all the
  282. // FCBs exclusive so that the parent directory is not being pinned.
  283. // Careful, we can collide with something acquiring up the tree like
  284. // an unpin repinned flush (FsRtlAcquireFileForCcFlush ...) of a parent
  285. // dir on extending writethrough of a child file (oops). So get things
  286. // going up the tree, not down.
  287. //
  288. if ((NodeType(Fcb) != FAT_NTC_FCB) &&
  289. !IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) {
  290. PLIST_ENTRY Links;
  291. PFCB TempFcb;
  292. ChildrenAcquired = TRUE;
  293. for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink;
  294. Links != &Fcb->Specific.Dcb.ParentDcbQueue;
  295. Links = Links->Flink) {
  296. TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
  297. (VOID)FatAcquireExclusiveFcb( IrpContext, TempFcb );
  298. }
  299. }
  300. (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
  301. //
  302. // We use this flag to indicate to a close beneath us that
  303. // the Fcb resource should be freed before deleting the Fcb.
  304. //
  305. Vcb = Fcb->Vcb;
  306. SetFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS );
  307. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
  308. try {
  309. BOOLEAN DataSectionExists;
  310. BOOLEAN ImageSectionExists;
  311. PSECTION_OBJECT_POINTERS Section;
  312. if ( FlushType ) {
  313. (VOID)FatFlushFile( IrpContext, Fcb, FlushType );
  314. }
  315. //
  316. // The Flush may have made the Fcb go away
  317. //
  318. if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB)) {
  319. Section = &Fcb->NonPaged->SectionObjectPointers;
  320. DataSectionExists = (BOOLEAN)(Section->DataSectionObject != NULL);
  321. ImageSectionExists = (BOOLEAN)(Section->ImageSectionObject != NULL);
  322. //
  323. // Note, it is critical to do the Image section first as the
  324. // purge of the data section may cause the image section to go
  325. // away, but the opposite is not true.
  326. //
  327. if (ImageSectionExists) {
  328. (VOID)MmFlushImageSection( Section, MmFlushForWrite );
  329. }
  330. if (DataSectionExists) {
  331. CcPurgeCacheSection( Section, NULL, 0, FALSE );
  332. }
  333. }
  334. } finally {
  335. //
  336. // If we purging a directory file object, release all the Fcb
  337. // resources that we acquired above. The Dcb cannot have vanished
  338. // if there were Fcbs underneath it, and the Fcbs couldn't have gone
  339. // away since I own the Vcb.
  340. //
  341. if (ChildrenAcquired) {
  342. PLIST_ENTRY Links;
  343. PFCB TempFcb;
  344. for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink;
  345. Links != &Fcb->Specific.Dcb.ParentDcbQueue;
  346. Links = Links->Flink) {
  347. TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
  348. FatReleaseFcb( IrpContext, TempFcb );
  349. }
  350. }
  351. //
  352. // Since we have the Vcb exclusive we know that if any closes
  353. // come in it is because the CcPurgeCacheSection caused the
  354. // Fcb to go away. Also in close, the Fcb was released
  355. // before being freed.
  356. //
  357. if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB) ) {
  358. ClearFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS );
  359. FatReleaseFcb( (IRPCONTEXT), Fcb );
  360. }
  361. }
  362. }