3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the Fat File object support routines.
19 // The Bug check file id for this module
22 #define BugCheckFileId (FAT_BUG_CHECK_FILOBSUP)
25 // The debug trace level
28 #define Dbg (DEBUG_TRACE_FILOBSUP)
31 #pragma alloc_text(PAGE, FatForceCacheMiss)
32 #pragma alloc_text(PAGE, FatPurgeReferencedFileObjects)
33 #pragma alloc_text(PAGE, FatSetFileObject)
34 #pragma alloc_text(PAGE, FatDecodeFileObject)
40 IN PFILE_OBJECT FileObject OPTIONAL
,
41 IN TYPE_OF_OPEN TypeOfOpen
,
42 IN PVOID VcbOrFcbOrDcb
,
50 This routine sets the file system pointers within the file object
54 FileObject - Supplies a pointer to the file object being modified, and
55 can optionally be null.
57 TypeOfOpen - Supplies the type of open denoted by the file object.
58 This is only used by this procedure for sanity checking.
60 VcbOrFcbOrDcb - Supplies a pointer to either a vcb, fcb, or dcb
62 Ccb - Optionally supplies a pointer to a ccb
73 DebugTrace(+1, Dbg
, "FatSetFileObject, FileObject = %p\n", FileObject
);
75 NT_ASSERT((Ccb
== NULL
) || (NodeType(Ccb
) == FAT_NTC_CCB
));
78 NT_ASSERT(((TypeOfOpen
== UnopenedFileObject
))
82 ((TypeOfOpen
== UserFileOpen
) &&
83 (NodeType(VcbOrFcbOrDcb
) == FAT_NTC_FCB
) &&
88 ((TypeOfOpen
== EaFile
) &&
89 (NodeType(VcbOrFcbOrDcb
) == FAT_NTC_FCB
) &&
94 ((TypeOfOpen
== UserDirectoryOpen
) &&
95 ((NodeType(VcbOrFcbOrDcb
) == FAT_NTC_DCB
) || (NodeType(VcbOrFcbOrDcb
) == FAT_NTC_ROOT_DCB
)) &&
100 ((TypeOfOpen
== UserVolumeOpen
) &&
101 (NodeType(VcbOrFcbOrDcb
) == FAT_NTC_VCB
) &&
106 ((TypeOfOpen
== VirtualVolumeFile
) &&
107 (NodeType(VcbOrFcbOrDcb
) == FAT_NTC_VCB
) &&
112 ((TypeOfOpen
== DirectoryFile
) &&
113 ((NodeType(VcbOrFcbOrDcb
) == FAT_NTC_DCB
) || (NodeType(VcbOrFcbOrDcb
) == FAT_NTC_ROOT_DCB
)) &&
118 UNREFERENCED_PARAMETER( TypeOfOpen
);
121 // If we were given an Fcb, Dcb, or Vcb, we have some processing to do.
124 NT_ASSERT((Ccb
== NULL
) || (NodeType(Ccb
) == FAT_NTC_CCB
));
126 if ( VcbOrFcbOrDcb
!= NULL
) {
129 // Set the Vpb field in the file object, and if we were given an
130 // Fcb or Dcb move the field over to point to the nonpaged Fcb/Dcb
133 if (NodeType(VcbOrFcbOrDcb
) == FAT_NTC_VCB
) {
135 FileObject
->Vpb
= ((PVCB
)VcbOrFcbOrDcb
)->Vpb
;
139 FileObject
->Vpb
= ((PFCB
)VcbOrFcbOrDcb
)->Vcb
->Vpb
;
142 // If this is a temporary file, note it in the FcbState
145 if (FlagOn(((PFCB
)VcbOrFcbOrDcb
)->FcbState
, FCB_STATE_TEMPORARY
)) {
147 SetFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
152 NT_ASSERT((Ccb
== NULL
) || (NodeType(Ccb
) == FAT_NTC_CCB
));
155 // Now set the fscontext fields of the file object
158 if (ARGUMENT_PRESENT( FileObject
)) {
160 FileObject
->FsContext
= VcbOrFcbOrDcb
;
161 FileObject
->FsContext2
= Ccb
;
164 NT_ASSERT((Ccb
== NULL
) || (NodeType(Ccb
) == FAT_NTC_CCB
));
167 // And return to our caller
170 DebugTrace(-1, Dbg
, "FatSetFileObject -> VOID\n", 0);
176 FatDecodeFileObject (
177 _In_ PFILE_OBJECT FileObject
,
179 _Outptr_ PFCB
*FcbOrDcb
,
187 This procedure takes a pointer to a file object, that has already been
188 opened by the Fat file system and figures out what really is opened.
192 FileObject - Supplies the file object pointer being interrogated
194 Vcb - Receives a pointer to the Vcb for the file object.
196 FcbOrDcb - Receives a pointer to the Fcb/Dcb for the file object, if
199 Ccb - Receives a pointer to the Ccb for the file object, if one exists.
203 TYPE_OF_OPEN - returns the type of file denoted by the input file object.
205 UserFileOpen - The FO represents a user's opened data file.
206 Ccb, FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb.
208 UserDirectoryOpen - The FO represents a user's opened directory.
209 Ccb, FcbOrDcb, and Vcb are set. FcbOrDcb points to a Dcb/RootDcb
211 UserVolumeOpen - The FO represents a user's opened volume.
212 Ccb and Vcb are set. FcbOrDcb is null.
214 VirtualVolumeFile - The FO represents the special virtual volume file.
215 Vcb is set, and Ccb and FcbOrDcb are null.
217 DirectoryFile - The FO represents a special directory file.
218 Vcb and FcbOrDcb are set. Ccb is null. FcbOrDcb points to a
221 EaFile - The FO represents an Ea Io stream file.
222 FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb, and Ccb is
228 TYPE_OF_OPEN TypeOfOpen
;
234 DebugTrace(+1, Dbg
, "FatDecodeFileObject, FileObject = %p\n", FileObject
);
237 // Reference the fs context fields of the file object, and zero out
238 // the out pointer parameters.
241 FsContext
= FileObject
->FsContext
;
242 FsContext2
= FileObject
->FsContext2
;
245 // Special case the situation where FsContext is null
248 if (FsContext
== NULL
) {
254 TypeOfOpen
= UnopenedFileObject
;
259 // Now we can case on the node type code of the fscontext pointer
260 // and set the appropriate out pointers
263 switch (NodeType(FsContext
)) {
271 TypeOfOpen
= ( *Ccb
== NULL
? VirtualVolumeFile
: UserVolumeOpen
);
275 case FAT_NTC_ROOT_DCB
:
279 *FcbOrDcb
= FsContext
;
280 *Vcb
= (*FcbOrDcb
)->Vcb
;
282 TypeOfOpen
= ( *Ccb
== NULL
? DirectoryFile
: UserDirectoryOpen
);
284 DebugTrace(0, Dbg
, "Referencing directory: %wZ\n", &(*FcbOrDcb
)->FullFileName
);
291 *FcbOrDcb
= FsContext
;
292 *Vcb
= (*FcbOrDcb
)->Vcb
;
296 TypeOfOpen
= UserFileOpen
;
297 DebugTrace(0, Dbg
, "Referencing file: %wZ\n", &(*FcbOrDcb
)->FullFileName
);
302 // No Ccb means this is a special open.
306 if ( *FcbOrDcb
== (*Vcb
)->EaFcb
) {
309 DebugTrace(0, Dbg
, "Referencing EA file: %wZ\n", &(*FcbOrDcb
)->FullFileName
);
314 #pragma prefast(suppress:28159, "things are seriously wrong if we get here")
316 FatBugCheck( NodeType(FsContext
), 0, 0 );
327 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
329 FatBugCheck( NodeType(FsContext
), 0, 0 );
334 // and return to our caller
337 DebugTrace(0, Dbg
, "FatDecodeFileObject -> VCB(%p)\n", *Vcb
);
338 DebugTrace(0, Dbg
, "FatDecodeFileObject -> FCB(%p)\n", *FcbOrDcb
);
339 DebugTrace(0, Dbg
, "FatDecodeFileObject -> CCB(%p)\n", *Ccb
);
340 DebugTrace(-1, Dbg
, "FatDecodeFileObject -> TypeOfOpen = %08lx\n", TypeOfOpen
);
345 _Requires_lock_held_(_Global_critical_region_
)
347 FatPurgeReferencedFileObjects (
348 IN PIRP_CONTEXT IrpContext
,
350 IN FAT_FLUSH_TYPE FlushType
357 This routine non-recursively walks from the given FcbOrDcb and trys
358 to force Cc or Mm to close any sections it may be holding on to.
362 Fcb - Supplies a pointer to either an fcb or a dcb
364 FlushType - Specifies the kind of flushing to perform
373 PFCB OriginalFcb
= Fcb
;
378 DebugTrace(+1, Dbg
, "FatPurgeReferencedFileObjects, Fcb = %p\n", Fcb
);
380 NT_ASSERT( FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) );
383 // First, if we have a delayed close, force it closed.
386 FatFspClose(Fcb
->Vcb
);
389 // Walk the directory tree forcing sections closed.
391 // Note that it very important to get the next node to visit before
392 // acting on the current node. This is because acting on a node may
393 // make it, and an arbitrary number of direct ancestors, vanish.
394 // Since we never visit ancestors in our top-down enumeration scheme, we
395 // can safely continue the enumeration even when the tree is vanishing
396 // beneath us. This is way cool.
399 while ( Fcb
!= NULL
) {
401 NextFcb
= FatGetNextFcbTopDown(IrpContext
, Fcb
, OriginalFcb
);
404 // Check for the EA file fcb
407 if ( !FlagOn(Fcb
->DirentFatFlags
, FAT_DIRENT_ATTR_VOLUME_ID
) ) {
409 FatForceCacheMiss( IrpContext
, Fcb
, FlushType
);
415 DebugTrace(-1, Dbg
, "FatPurgeReferencedFileObjects (VOID)\n", 0 );
421 _Requires_lock_held_(_Global_critical_region_
)
424 IN PIRP_CONTEXT IrpContext
,
426 IN FAT_FLUSH_TYPE FlushType
433 The following routine asks either Cc or Mm to get rid of any cached
434 pages on a file. Note that this will fail if a user has mapped a file.
436 If there is a shared cache map, purge the cache section. Otherwise
437 we have to go and ask Mm to blow away the section.
439 NOTE: This caller MUST own the Vcb exclusive.
443 Fcb - Supplies a pointer to an fcb
445 FlushType - Specifies the kind of flushing to perform
455 BOOLEAN ChildrenAcquired
= FALSE
;
460 // If we can't wait, bail.
463 NT_ASSERT( FatVcbAcquiredExclusive( IrpContext
, Fcb
->Vcb
) ||
464 FlagOn( Fcb
->Vcb
->VcbState
, VCB_STATE_FLAG_LOCKED
) );
466 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
468 FatRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
472 // If we are purging a directory file object, we must acquire all the
473 // FCBs exclusive so that the parent directory is not being pinned.
474 // Careful, we can collide with something acquiring up the tree like
475 // an unpin repinned flush (FsRtlAcquireFileForCcFlush ...) of a parent
476 // dir on extending writethrough of a child file (oops). So get things
477 // going up the tree, not down.
480 if ((NodeType(Fcb
) != FAT_NTC_FCB
) &&
481 !IsListEmpty(&Fcb
->Specific
.Dcb
.ParentDcbQueue
)) {
486 ChildrenAcquired
= TRUE
;
488 for (Links
= Fcb
->Specific
.Dcb
.ParentDcbQueue
.Flink
;
489 Links
!= &Fcb
->Specific
.Dcb
.ParentDcbQueue
;
490 Links
= Links
->Flink
) {
492 TempFcb
= CONTAINING_RECORD( Links
, FCB
, ParentDcbLinks
);
494 (VOID
)FatAcquireExclusiveFcb( IrpContext
, TempFcb
);
498 (VOID
)FatAcquireExclusiveFcb( IrpContext
, Fcb
);
501 // We use this flag to indicate to a close beneath us that
502 // the Fcb resource should be freed before deleting the Fcb.
507 SetFlag( Fcb
->FcbState
, FCB_STATE_FORCE_MISS_IN_PROGRESS
);
509 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
);
513 BOOLEAN DataSectionExists
;
514 BOOLEAN ImageSectionExists
;
516 PSECTION_OBJECT_POINTERS Section
;
520 (VOID
)FatFlushFile( IrpContext
, Fcb
, FlushType
);
524 // The Flush may have made the Fcb go away
527 if (!FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
)) {
529 Section
= &Fcb
->NonPaged
->SectionObjectPointers
;
531 DataSectionExists
= (BOOLEAN
)(Section
->DataSectionObject
!= NULL
);
532 ImageSectionExists
= (BOOLEAN
)(Section
->ImageSectionObject
!= NULL
);
535 // Note, it is critical to do the Image section first as the
536 // purge of the data section may cause the image section to go
537 // away, but the opposite is not true.
540 if (ImageSectionExists
) {
542 (VOID
)MmFlushImageSection( Section
, MmFlushForWrite
);
545 if (DataSectionExists
) {
547 CcPurgeCacheSection( Section
, NULL
, 0, FALSE
);
554 // If we purging a directory file object, release all the Fcb
555 // resources that we acquired above. The Dcb cannot have vanished
556 // if there were Fcbs underneath it, and the Fcbs couldn't have gone
557 // away since I own the Vcb.
560 if (ChildrenAcquired
) {
565 for (Links
= Fcb
->Specific
.Dcb
.ParentDcbQueue
.Flink
;
566 Links
!= &Fcb
->Specific
.Dcb
.ParentDcbQueue
;
567 Links
= Links
->Flink
) {
569 TempFcb
= CONTAINING_RECORD( Links
, FCB
, ParentDcbLinks
);
571 FatReleaseFcb( IrpContext
, TempFcb
);
576 // Since we have the Vcb exclusive we know that if any closes
577 // come in it is because the CcPurgeCacheSection caused the
578 // Fcb to go away. Also in close, the Fcb was released
579 // before being freed.
582 if ( !FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
) ) {
584 ClearFlag( Fcb
->FcbState
, FCB_STATE_FORCE_MISS_IN_PROGRESS
);
586 FatReleaseFcb( (IRPCONTEXT
), Fcb
);