[CDFS_NEW] Force calling convention to allow build
[reactos.git] / drivers / filesystems / cdfs_new / cachesup.c
1 /*++
2
3 Copyright (c) 1990-2000 Microsoft Corporation
4
5 Module Name:
6
7 Cache.c
8
9 Abstract:
10
11 This module implements the cache management routines for the Cdfs
12 FSD and FSP, by calling the Common Cache Manager.
13
14
15 --*/
16
17 #include "cdprocs.h"
18
19 //
20 // The Bug check file id for this module
21 //
22
23 #define BugCheckFileId (CDFS_BUG_CHECK_CACHESUP)
24
25 //
26 // Local debug trace level
27 //
28
29 #ifdef ALLOC_PRAGMA
30 #pragma alloc_text(PAGE, CdCompleteMdl)
31 #pragma alloc_text(PAGE, CdCreateInternalStream)
32 #pragma alloc_text(PAGE, CdDeleteInternalStream)
33 #pragma alloc_text(PAGE, CdPurgeVolume)
34 #endif
35
36 \f
37 VOID
38 CdCreateInternalStream (
39 IN PIRP_CONTEXT IrpContext,
40 IN PVCB Vcb,
41 IN PFCB Fcb
42 )
43
44 /*++
45
46 Routine Description:
47
48 This function creates an internal stream file for interaction
49 with the cache manager. The Fcb here can be for either a
50 directory stream or for a path table stream.
51
52 Arguments:
53
54 Vcb - Vcb for this volume.
55
56 Fcb - Points to the Fcb for this file. It is either an Index or
57 Path Table Fcb.
58
59 Return Value:
60
61 None.
62
63 --*/
64
65 {
66 PFILE_OBJECT StreamFile = NULL;
67 BOOLEAN DecrementReference = FALSE;
68
69 BOOLEAN CleanupDirContext = FALSE;
70 BOOLEAN UpdateFcbSizes = FALSE;
71
72 DIRENT Dirent;
73 DIRENT_ENUM_CONTEXT DirContext;
74
75 PAGED_CODE();
76
77 ASSERT_IRP_CONTEXT( IrpContext );
78 ASSERT_FCB( Fcb );
79
80 //
81 // We may only have the Fcb shared. Lock the Fcb and do a
82 // safe test to see if we need to really create the file object.
83 //
84
85 CdLockFcb( IrpContext, Fcb );
86
87 if (Fcb->FileObject != NULL) {
88
89 CdUnlockFcb( IrpContext, Fcb );
90 return;
91 }
92
93 //
94 // Use a try-finally to facilitate cleanup.
95 //
96
97 try {
98
99 //
100 // Create the internal stream. The Vpb should be pointing at our volume
101 // device object at this point.
102 //
103
104 StreamFile = IoCreateStreamFileObject( NULL, Vcb->Vpb->RealDevice );
105
106 if (StreamFile == NULL) {
107
108 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
109 }
110
111 //
112 // Initialize the fields of the file object.
113 //
114
115 StreamFile->ReadAccess = TRUE;
116 StreamFile->WriteAccess = FALSE;
117 StreamFile->DeleteAccess = FALSE;
118
119 StreamFile->SectionObjectPointer = &Fcb->FcbNonpaged->SegmentObject;
120
121 //
122 // Set the file object type and increment the Vcb counts.
123 //
124
125 CdSetFileObject( IrpContext,
126 StreamFile,
127 StreamFileOpen,
128 Fcb,
129 NULL );
130
131 //
132 // We will reference the current Fcb twice to keep it from going
133 // away in the error path. Otherwise if we dereference it
134 // below in the finally clause a close could cause the Fcb to
135 // be deallocated.
136 //
137
138 CdLockVcb( IrpContext, Vcb );
139 CdIncrementReferenceCounts( IrpContext, Fcb, 2, 0 );
140 CdUnlockVcb( IrpContext, Vcb );
141 DecrementReference = TRUE;
142
143 //
144 // Initialize the cache map for the file.
145 //
146
147 CcInitializeCacheMap( StreamFile,
148 (PCC_FILE_SIZES)&Fcb->AllocationSize,
149 TRUE,
150 &CdData.CacheManagerCallbacks,
151 Fcb );
152
153 //
154 // Go ahead and store the stream file into the Fcb.
155 //
156
157 Fcb->FileObject = StreamFile;
158 StreamFile = NULL;
159
160 //
161 // If this is the first file object for a directory then we need to
162 // read the self entry for this directory and update the sizes
163 // in the Fcb. We know that the Fcb has been initialized so
164 // that we have a least one sector available to read.
165 //
166
167 if (!FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED )) {
168
169 ULONG NewDataLength;
170
171 //
172 // Initialize the search structures.
173 //
174
175 CdInitializeDirContext( IrpContext, &DirContext );
176 CdInitializeDirent( IrpContext, &Dirent );
177 CleanupDirContext = TRUE;
178
179 //
180 // Read the dirent from disk and transfer the data to the
181 // in-memory dirent.
182 //
183
184 CdLookupDirent( IrpContext,
185 Fcb,
186 Fcb->StreamOffset,
187 &DirContext );
188
189 CdUpdateDirentFromRawDirent( IrpContext, Fcb, &DirContext, &Dirent );
190
191 //
192 // Verify that this really for the self entry. We do this by
193 // updating the name in the dirent and then checking that it matches
194 // one of the hard coded names.
195 //
196
197 CdUpdateDirentName( IrpContext, &Dirent, FALSE );
198
199 if (Dirent.CdFileName.FileName.Buffer != CdUnicodeSelfArray) {
200
201 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
202 }
203
204 //
205 // If the data sizes are different then update the header
206 // and Mcb for this Fcb.
207 //
208
209 NewDataLength = BlockAlign( Vcb, Dirent.DataLength + Fcb->StreamOffset );
210
211 if (NewDataLength == 0) {
212
213 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
214 }
215
216 if (NewDataLength != Fcb->FileSize.QuadPart) {
217
218 Fcb->AllocationSize.QuadPart =
219 Fcb->FileSize.QuadPart =
220 Fcb->ValidDataLength.QuadPart = NewDataLength;
221
222 CcSetFileSizes( Fcb->FileObject, (PCC_FILE_SIZES) &Fcb->AllocationSize );
223
224 CdTruncateAllocation( IrpContext, Fcb, 0 );
225 CdAddInitialAllocation( IrpContext,
226 Fcb,
227 Dirent.StartingOffset,
228 NewDataLength );
229
230 UpdateFcbSizes = TRUE;
231 }
232
233 //
234 // Check for the existence flag and transform to hidden.
235 //
236
237 if (FlagOn( Dirent.DirentFlags, CD_ATTRIBUTE_HIDDEN )) {
238
239 SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
240 }
241
242 //
243 // Convert the time to NT time.
244 //
245
246 CdConvertCdTimeToNtTime( IrpContext,
247 Dirent.CdTime,
248 (PLARGE_INTEGER) &Fcb->CreationTime );
249
250 //
251 // Update the Fcb flags to indicate we have read the
252 // self entry.
253 //
254
255 SetFlag( Fcb->FcbState, FCB_STATE_INITIALIZED );
256
257 //
258 // If we updated the sizes then we want to purge the file. Go
259 // ahead and unpin and then purge the first page.
260 //
261
262 CdCleanupDirContext( IrpContext, &DirContext );
263 CdCleanupDirent( IrpContext, &Dirent );
264 CleanupDirContext = FALSE;
265
266 if (UpdateFcbSizes) {
267
268 CcPurgeCacheSection( &Fcb->FcbNonpaged->SegmentObject,
269 NULL,
270 0,
271 FALSE );
272 }
273 }
274
275 } finally {
276
277 //
278 // Cleanup any dirent structures we may have used.
279 //
280
281 if (CleanupDirContext) {
282
283 CdCleanupDirContext( IrpContext, &DirContext );
284 CdCleanupDirent( IrpContext, &Dirent );
285 }
286
287 //
288 // If we raised then we need to dereference the file object.
289 //
290
291 if (StreamFile != NULL) {
292
293 ObDereferenceObject( StreamFile );
294 Fcb->FileObject = NULL;
295 }
296
297 //
298 // Dereference and unlock the Fcb.
299 //
300
301 if (DecrementReference) {
302
303 CdLockVcb( IrpContext, Vcb );
304 CdDecrementReferenceCounts( IrpContext, Fcb, 1, 0 );
305 CdUnlockVcb( IrpContext, Vcb );
306 }
307
308 CdUnlockFcb( IrpContext, Fcb );
309 }
310
311 return;
312 }
313
314 \f
315 VOID
316 CdDeleteInternalStream (
317 IN PIRP_CONTEXT IrpContext,
318 IN PFCB Fcb
319 )
320
321 /*++
322
323 Routine Description:
324
325 This function creates an internal stream file for interaction
326 with the cache manager. The Fcb here can be for either a
327 directory stream or for a path table stream.
328
329 Arguments:
330
331 Fcb - Points to the Fcb for this file. It is either an Index or
332 Path Table Fcb.
333
334 Return Value:
335
336 None.
337
338 --*/
339
340 {
341 PFILE_OBJECT FileObject;
342
343 PAGED_CODE();
344
345 ASSERT_IRP_CONTEXT( IrpContext );
346 ASSERT_FCB( Fcb );
347
348 //
349 // Lock the Fcb.
350 //
351
352 CdLockFcb( IrpContext, Fcb );
353
354 //
355 // Capture the file object.
356 //
357
358 FileObject = Fcb->FileObject;
359 Fcb->FileObject = NULL;
360
361 //
362 // It is now safe to unlock the Fcb.
363 //
364
365 CdUnlockFcb( IrpContext, Fcb );
366
367 //
368 // Dereference the file object if present.
369 //
370
371 if (FileObject != NULL) {
372
373 if (FileObject->PrivateCacheMap != NULL) {
374
375 CcUninitializeCacheMap( FileObject, NULL, NULL );
376 }
377
378 ObDereferenceObject( FileObject );
379 }
380
381 return;
382 }
383
384 \f
385 NTSTATUS
386 CdCompleteMdl (
387 IN PIRP_CONTEXT IrpContext,
388 IN PIRP Irp
389 )
390
391 /*++
392
393 Routine Description:
394
395 This routine performs the function of completing Mdl reads.
396 It should be called only from CdFsdRead.
397
398 Arguments:
399
400 Irp - Supplies the originating Irp.
401
402 Return Value:
403
404 NTSTATUS - Will always be STATUS_SUCCESS.
405
406 --*/
407
408 {
409 PFILE_OBJECT FileObject;
410
411 PAGED_CODE();
412
413 //
414 // Do completion processing.
415 //
416
417 FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;
418
419 CcMdlReadComplete( FileObject, Irp->MdlAddress );
420
421 //
422 // Mdl is now deallocated.
423 //
424
425 Irp->MdlAddress = NULL;
426
427 //
428 // Complete the request and exit right away.
429 //
430
431 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
432
433 return STATUS_SUCCESS;
434 }
435
436 \f
437 NTSTATUS
438 CdPurgeVolume (
439 IN PIRP_CONTEXT IrpContext,
440 IN PVCB Vcb,
441 IN BOOLEAN DismountUnderway
442 )
443
444 /*++
445
446 Routine Description:
447
448 This routine is called to purge the volume. The purpose is to make all the stale file
449 objects in the system go away in order to lock the volume.
450
451 The Vcb is already acquired exclusively. We will lock out all file operations by
452 acquiring the global file resource. Then we will walk through all of the Fcb's and
453 perform the purge.
454
455 Arguments:
456
457 Vcb - Vcb for the volume to purge.
458
459 DismountUnderway - Indicates that we are trying to delete all of the objects.
460 We will purge the Path Table and VolumeDasd and dereference all
461 internal streams.
462
463 Return Value:
464
465 NTSTATUS - The first failure of the purge operation.
466
467 --*/
468
469 {
470 NTSTATUS Status = STATUS_SUCCESS;
471
472 PVOID RestartKey = NULL;
473 PFCB ThisFcb = NULL;
474 PFCB NextFcb;
475
476 BOOLEAN RemovedFcb;
477
478 PAGED_CODE();
479
480 ASSERT_EXCLUSIVE_VCB( Vcb);
481
482 //
483 // Force any remaining Fcb's in the delayed close queue to be closed.
484 //
485
486 CdFspClose( Vcb );
487
488 //
489 // Acquire the global file resource.
490 //
491
492 CdAcquireAllFiles( IrpContext, Vcb );
493
494 //
495 // Loop through each Fcb in the Fcb Table and perform the flush.
496 //
497
498 while (TRUE) {
499
500 //
501 // Lock the Vcb to lookup the next Fcb.
502 //
503
504 CdLockVcb( IrpContext, Vcb );
505 NextFcb = CdGetNextFcb( IrpContext, Vcb, &RestartKey );
506
507 //
508 // Reference the NextFcb if present.
509 //
510
511 if (NextFcb != NULL) {
512
513 NextFcb->FcbReference += 1;
514 }
515
516 //
517 // If the last Fcb is present then decrement reference count and call teardown
518 // to see if it should be removed.
519 //
520
521 if (ThisFcb != NULL) {
522
523 ThisFcb->FcbReference -= 1;
524
525 CdUnlockVcb( IrpContext, Vcb );
526
527 CdTeardownStructures( IrpContext, ThisFcb, &RemovedFcb );
528
529 } else {
530
531 CdUnlockVcb( IrpContext, Vcb );
532 }
533
534 //
535 // Break out of the loop if no more Fcb's.
536 //
537
538 if (NextFcb == NULL) {
539
540 break;
541 }
542
543 //
544 // Move to the next Fcb.
545 //
546
547 ThisFcb = NextFcb;
548
549 //
550 // If there is a image section then see if that can be closed.
551 //
552
553 if (ThisFcb->FcbNonpaged->SegmentObject.ImageSectionObject != NULL) {
554
555 MmFlushImageSection( &ThisFcb->FcbNonpaged->SegmentObject, MmFlushForWrite );
556 }
557
558 //
559 // If there is a data section then purge this. If there is an image
560 // section then we won't be able to. Remember this if it is our first
561 // error.
562 //
563
564 if ((ThisFcb->FcbNonpaged->SegmentObject.DataSectionObject != NULL) &&
565 !CcPurgeCacheSection( &ThisFcb->FcbNonpaged->SegmentObject,
566 NULL,
567 0,
568 FALSE ) &&
569 (Status == STATUS_SUCCESS)) {
570
571 Status = STATUS_UNABLE_TO_DELETE_SECTION;
572 }
573
574 //
575 // Dereference the internal stream if dismounting.
576 //
577
578 if (DismountUnderway &&
579 (SafeNodeType( ThisFcb ) != CDFS_NTC_FCB_DATA) &&
580 (ThisFcb->FileObject != NULL)) {
581
582 CdDeleteInternalStream( IrpContext, ThisFcb );
583 }
584 }
585
586 //
587 // Now look at the path table and volume Dasd Fcb's.
588 //
589
590 if (DismountUnderway) {
591
592 if (Vcb->PathTableFcb != NULL) {
593
594 ThisFcb = Vcb->PathTableFcb;
595 InterlockedIncrement( &Vcb->PathTableFcb->FcbReference );
596
597 if ((ThisFcb->FcbNonpaged->SegmentObject.DataSectionObject != NULL) &&
598 !CcPurgeCacheSection( &ThisFcb->FcbNonpaged->SegmentObject,
599 NULL,
600 0,
601 FALSE ) &&
602 (Status == STATUS_SUCCESS)) {
603
604 Status = STATUS_UNABLE_TO_DELETE_SECTION;
605 }
606
607 CdDeleteInternalStream( IrpContext, ThisFcb );
608
609 InterlockedDecrement( &ThisFcb->FcbReference );
610
611 CdTeardownStructures( IrpContext, ThisFcb, &RemovedFcb );
612 }
613
614 if (Vcb->VolumeDasdFcb != NULL) {
615
616 ThisFcb = Vcb->VolumeDasdFcb;
617 InterlockedIncrement( &ThisFcb->FcbReference );
618
619 if ((ThisFcb->FcbNonpaged->SegmentObject.DataSectionObject != NULL) &&
620 !CcPurgeCacheSection( &ThisFcb->FcbNonpaged->SegmentObject,
621 NULL,
622 0,
623 FALSE ) &&
624 (Status == STATUS_SUCCESS)) {
625
626 Status = STATUS_UNABLE_TO_DELETE_SECTION;
627 }
628
629 InterlockedDecrement( &ThisFcb->FcbReference );
630
631 CdTeardownStructures( IrpContext, ThisFcb, &RemovedFcb );
632 }
633 }
634
635 //
636 // Release all of the files.
637 //
638
639 CdReleaseAllFiles( IrpContext, Vcb );
640
641 return Status;
642 }
643
644