[BTRFS] Fix booting with runtime checks
[reactos.git] / drivers / filesystems / fastfat_new / filobsup.c
1 /*++
2
3 Copyright (c) 1989-2000 Microsoft Corporation
4
5 Module Name:
6
7 FilObSup.c
8
9 Abstract:
10
11 This module implements the Fat File object support routines.
12
13
14 --*/
15
16 #include "fatprocs.h"
17
18 //
19 // The Bug check file id for this module
20 //
21
22 #define BugCheckFileId (FAT_BUG_CHECK_FILOBSUP)
23
24 //
25 // The debug trace level
26 //
27
28 #define Dbg (DEBUG_TRACE_FILOBSUP)
29
30 #ifdef ALLOC_PRAGMA
31 #pragma alloc_text(PAGE, FatForceCacheMiss)
32 #pragma alloc_text(PAGE, FatPurgeReferencedFileObjects)
33 #pragma alloc_text(PAGE, FatSetFileObject)
34 #pragma alloc_text(PAGE, FatDecodeFileObject)
35 #endif
36
37 \f
38 VOID
39 FatSetFileObject (
40 IN PFILE_OBJECT FileObject OPTIONAL,
41 IN TYPE_OF_OPEN TypeOfOpen,
42 IN PVOID VcbOrFcbOrDcb,
43 IN PCCB Ccb OPTIONAL
44 )
45
46 /*++
47
48 Routine Description:
49
50 This routine sets the file system pointers within the file object
51
52 Arguments:
53
54 FileObject - Supplies a pointer to the file object being modified, and
55 can optionally be null.
56
57 TypeOfOpen - Supplies the type of open denoted by the file object.
58 This is only used by this procedure for sanity checking.
59
60 VcbOrFcbOrDcb - Supplies a pointer to either a vcb, fcb, or dcb
61
62 Ccb - Optionally supplies a pointer to a ccb
63
64 Return Value:
65
66 None.
67
68 --*/
69
70 {
71 PAGED_CODE();
72
73 DebugTrace(+1, Dbg, "FatSetFileObject, FileObject = %p\n", FileObject );
74
75 NT_ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB));
76
77
78 NT_ASSERT(((TypeOfOpen == UnopenedFileObject))
79
80 ||
81
82 ((TypeOfOpen == UserFileOpen) &&
83 (NodeType(VcbOrFcbOrDcb) == FAT_NTC_FCB) &&
84 (Ccb != NULL))
85
86 ||
87
88 ((TypeOfOpen == EaFile) &&
89 (NodeType(VcbOrFcbOrDcb) == FAT_NTC_FCB) &&
90 (Ccb == NULL))
91
92 ||
93
94 ((TypeOfOpen == UserDirectoryOpen) &&
95 ((NodeType(VcbOrFcbOrDcb) == FAT_NTC_DCB) || (NodeType(VcbOrFcbOrDcb) == FAT_NTC_ROOT_DCB)) &&
96 (Ccb != NULL))
97
98 ||
99
100 ((TypeOfOpen == UserVolumeOpen) &&
101 (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) &&
102 (Ccb != NULL))
103
104 ||
105
106 ((TypeOfOpen == VirtualVolumeFile) &&
107 (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) &&
108 (Ccb == NULL))
109
110 ||
111
112 ((TypeOfOpen == DirectoryFile) &&
113 ((NodeType(VcbOrFcbOrDcb) == FAT_NTC_DCB) || (NodeType(VcbOrFcbOrDcb) == FAT_NTC_ROOT_DCB)) &&
114 (Ccb == NULL))
115 );
116
117
118 UNREFERENCED_PARAMETER( TypeOfOpen );
119
120 //
121 // If we were given an Fcb, Dcb, or Vcb, we have some processing to do.
122 //
123
124 NT_ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB));
125
126 if ( VcbOrFcbOrDcb != NULL ) {
127
128 //
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
131 //
132
133 if (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) {
134
135 FileObject->Vpb = ((PVCB)VcbOrFcbOrDcb)->Vpb;
136
137 } else {
138
139 FileObject->Vpb = ((PFCB)VcbOrFcbOrDcb)->Vcb->Vpb;
140
141 //
142 // If this is a temporary file, note it in the FcbState
143 //
144
145 if (FlagOn(((PFCB)VcbOrFcbOrDcb)->FcbState, FCB_STATE_TEMPORARY)) {
146
147 SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
148 }
149 }
150 }
151
152 NT_ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB));
153
154 //
155 // Now set the fscontext fields of the file object
156 //
157
158 if (ARGUMENT_PRESENT( FileObject )) {
159
160 FileObject->FsContext = VcbOrFcbOrDcb;
161 FileObject->FsContext2 = Ccb;
162 }
163
164 NT_ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB));
165
166 //
167 // And return to our caller
168 //
169
170 DebugTrace(-1, Dbg, "FatSetFileObject -> VOID\n", 0);
171
172 return;
173 }
174
175 TYPE_OF_OPEN
176 FatDecodeFileObject (
177 _In_ PFILE_OBJECT FileObject,
178 _Outptr_ PVCB *Vcb,
179 _Outptr_ PFCB *FcbOrDcb,
180 _Outptr_ PCCB *Ccb
181 )
182
183 /*++
184
185 Routine Description:
186
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.
189
190 Arguments:
191
192 FileObject - Supplies the file object pointer being interrogated
193
194 Vcb - Receives a pointer to the Vcb for the file object.
195
196 FcbOrDcb - Receives a pointer to the Fcb/Dcb for the file object, if
197 one exists.
198
199 Ccb - Receives a pointer to the Ccb for the file object, if one exists.
200
201 Return Value:
202
203 TYPE_OF_OPEN - returns the type of file denoted by the input file object.
204
205 UserFileOpen - The FO represents a user's opened data file.
206 Ccb, FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb.
207
208 UserDirectoryOpen - The FO represents a user's opened directory.
209 Ccb, FcbOrDcb, and Vcb are set. FcbOrDcb points to a Dcb/RootDcb
210
211 UserVolumeOpen - The FO represents a user's opened volume.
212 Ccb and Vcb are set. FcbOrDcb is null.
213
214 VirtualVolumeFile - The FO represents the special virtual volume file.
215 Vcb is set, and Ccb and FcbOrDcb are null.
216
217 DirectoryFile - The FO represents a special directory file.
218 Vcb and FcbOrDcb are set. Ccb is null. FcbOrDcb points to a
219 Dcb/RootDcb.
220
221 EaFile - The FO represents an Ea Io stream file.
222 FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb, and Ccb is
223 null.
224
225 --*/
226
227 {
228 TYPE_OF_OPEN TypeOfOpen;
229 PVOID FsContext;
230 PVOID FsContext2;
231
232 PAGED_CODE();
233
234 DebugTrace(+1, Dbg, "FatDecodeFileObject, FileObject = %p\n", FileObject);
235
236 //
237 // Reference the fs context fields of the file object, and zero out
238 // the out pointer parameters.
239 //
240
241 FsContext = FileObject->FsContext;
242 FsContext2 = FileObject->FsContext2;
243
244 //
245 // Special case the situation where FsContext is null
246 //
247
248 if (FsContext == NULL) {
249
250 *Ccb = NULL;
251 *FcbOrDcb = NULL;
252 *Vcb = NULL;
253
254 TypeOfOpen = UnopenedFileObject;
255
256 } else {
257
258 //
259 // Now we can case on the node type code of the fscontext pointer
260 // and set the appropriate out pointers
261 //
262
263 switch (NodeType(FsContext)) {
264
265 case FAT_NTC_VCB:
266
267 *Ccb = FsContext2;
268 *FcbOrDcb = NULL;
269 *Vcb = FsContext;
270
271 TypeOfOpen = ( *Ccb == NULL ? VirtualVolumeFile : UserVolumeOpen );
272
273 break;
274
275 case FAT_NTC_ROOT_DCB:
276 case FAT_NTC_DCB:
277
278 *Ccb = FsContext2;
279 *FcbOrDcb = FsContext;
280 *Vcb = (*FcbOrDcb)->Vcb;
281
282 TypeOfOpen = ( *Ccb == NULL ? DirectoryFile : UserDirectoryOpen );
283
284 DebugTrace(0, Dbg, "Referencing directory: %wZ\n", &(*FcbOrDcb)->FullFileName);
285
286 break;
287
288 case FAT_NTC_FCB:
289
290 *Ccb = FsContext2;
291 *FcbOrDcb = FsContext;
292 *Vcb = (*FcbOrDcb)->Vcb;
293
294 if (*Ccb != NULL ) {
295
296 TypeOfOpen = UserFileOpen;
297 DebugTrace(0, Dbg, "Referencing file: %wZ\n", &(*FcbOrDcb)->FullFileName);
298
299 } else {
300
301 //
302 // No Ccb means this is a special open.
303 //
304
305
306 if ( *FcbOrDcb == (*Vcb)->EaFcb ) {
307
308 TypeOfOpen = EaFile;
309 DebugTrace(0, Dbg, "Referencing EA file: %wZ\n", &(*FcbOrDcb)->FullFileName);
310
311 } else {
312
313 #ifdef _MSC_VER
314 #pragma prefast(suppress:28159, "things are seriously wrong if we get here")
315 #endif
316 FatBugCheck( NodeType(FsContext), 0, 0 );
317
318 }
319
320 }
321
322 break;
323
324 default:
325
326 #ifdef _MSC_VER
327 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
328 #endif
329 FatBugCheck( NodeType(FsContext), 0, 0 );
330 }
331 }
332
333 //
334 // and return to our caller
335 //
336
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);
341
342 return TypeOfOpen;
343 }
344
345 _Requires_lock_held_(_Global_critical_region_)
346 VOID
347 FatPurgeReferencedFileObjects (
348 IN PIRP_CONTEXT IrpContext,
349 IN PFCB Fcb,
350 IN FAT_FLUSH_TYPE FlushType
351 )
352
353 /*++
354
355 Routine Description:
356
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.
359
360 Arguments:
361
362 Fcb - Supplies a pointer to either an fcb or a dcb
363
364 FlushType - Specifies the kind of flushing to perform
365
366 Return Value:
367
368 None.
369
370 --*/
371
372 {
373 PFCB OriginalFcb = Fcb;
374 PFCB NextFcb;
375
376 PAGED_CODE();
377
378 DebugTrace(+1, Dbg, "FatPurgeReferencedFileObjects, Fcb = %p\n", Fcb );
379
380 NT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
381
382 //
383 // First, if we have a delayed close, force it closed.
384 //
385
386 FatFspClose(Fcb->Vcb);
387
388 //
389 // Walk the directory tree forcing sections closed.
390 //
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.
397 //
398
399 while ( Fcb != NULL ) {
400
401 NextFcb = FatGetNextFcbTopDown(IrpContext, Fcb, OriginalFcb);
402
403 //
404 // Check for the EA file fcb
405 //
406
407 if ( !FlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_VOLUME_ID) ) {
408
409 FatForceCacheMiss( IrpContext, Fcb, FlushType );
410 }
411
412 Fcb = NextFcb;
413 }
414
415 DebugTrace(-1, Dbg, "FatPurgeReferencedFileObjects (VOID)\n", 0 );
416
417 return;
418 }
419
420 \f
421 _Requires_lock_held_(_Global_critical_region_)
422 VOID
423 FatForceCacheMiss (
424 IN PIRP_CONTEXT IrpContext,
425 IN PFCB Fcb,
426 IN FAT_FLUSH_TYPE FlushType
427 )
428
429 /*++
430
431 Routine Description:
432
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.
435
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.
438
439 NOTE: This caller MUST own the Vcb exclusive.
440
441 Arguments:
442
443 Fcb - Supplies a pointer to an fcb
444
445 FlushType - Specifies the kind of flushing to perform
446
447 Return Value:
448
449 None.
450
451 --*/
452
453 {
454 PVCB Vcb;
455 BOOLEAN ChildrenAcquired = FALSE;
456
457 PAGED_CODE();
458
459 //
460 // If we can't wait, bail.
461 //
462
463 NT_ASSERT( FatVcbAcquiredExclusive( IrpContext, Fcb->Vcb ) ||
464 FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) );
465
466 if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
467
468 FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
469 }
470
471 //
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.
478 //
479
480 if ((NodeType(Fcb) != FAT_NTC_FCB) &&
481 !IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) {
482
483 PLIST_ENTRY Links;
484 PFCB TempFcb;
485
486 ChildrenAcquired = TRUE;
487
488 for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink;
489 Links != &Fcb->Specific.Dcb.ParentDcbQueue;
490 Links = Links->Flink) {
491
492 TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
493
494 (VOID)FatAcquireExclusiveFcb( IrpContext, TempFcb );
495 }
496 }
497
498 (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
499
500 //
501 // We use this flag to indicate to a close beneath us that
502 // the Fcb resource should be freed before deleting the Fcb.
503 //
504
505 Vcb = Fcb->Vcb;
506
507 SetFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS );
508
509 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
510
511 _SEH2_TRY {
512
513 BOOLEAN DataSectionExists;
514 BOOLEAN ImageSectionExists;
515
516 PSECTION_OBJECT_POINTERS Section;
517
518 if ( FlushType ) {
519
520 (VOID)FatFlushFile( IrpContext, Fcb, FlushType );
521 }
522
523 //
524 // The Flush may have made the Fcb go away
525 //
526
527 if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB)) {
528
529 Section = &Fcb->NonPaged->SectionObjectPointers;
530
531 DataSectionExists = (BOOLEAN)(Section->DataSectionObject != NULL);
532 ImageSectionExists = (BOOLEAN)(Section->ImageSectionObject != NULL);
533
534 //
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.
538 //
539
540 if (ImageSectionExists) {
541
542 (VOID)MmFlushImageSection( Section, MmFlushForWrite );
543 }
544
545 if (DataSectionExists) {
546
547 CcPurgeCacheSection( Section, NULL, 0, FALSE );
548 }
549 }
550
551 } _SEH2_FINALLY {
552
553 //
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.
558 //
559
560 if (ChildrenAcquired) {
561
562 PLIST_ENTRY Links;
563 PFCB TempFcb;
564
565 for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink;
566 Links != &Fcb->Specific.Dcb.ParentDcbQueue;
567 Links = Links->Flink) {
568
569 TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
570
571 FatReleaseFcb( IrpContext, TempFcb );
572 }
573 }
574
575 //
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.
580 //
581
582 if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB) ) {
583
584 ClearFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS );
585
586 FatReleaseFcb( (IRPCONTEXT), Fcb );
587 }
588 } _SEH2_END;
589 }
590
591