53bc3dec0fdc0a67c207e6b8164d2a4260168b49
[reactos.git] / reactos / drivers / filesystems / fastfat_new / fat.c
1 /*
2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/filesystems/fastfat/fat.c
5 * PURPOSE: FAT support routines
6 * PROGRAMMERS: Alexey Vlasov
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* PROTOTYPES ***************************************************************/
15 typedef struct _FAT_SCAN_CONTEXT
16 {
17 PFILE_OBJECT FileObject;
18 LARGE_INTEGER PageOffset;
19 LONGLONG BeyoundLastEntryOffset;
20 PVOID PageBuffer;
21 PBCB PageBcb;
22 } FAT_SCAN_CONTEXT;
23
24 #define FatEntryToDataOffset(xEntry, xVcb) \
25 ((xVcb)->DataArea + (((LONGLONG) ((xEntry) - 0x02)) << (xVcb)->BytesPerClusterLog))
26
27 #define FatDataOffsetToEntry(xOffset, xVcb) \
28 ((ULONG) ((xOffset - (xVcb)->DataArea) >> (xVcb)->BytesPerClusterLog) + 0x02)
29
30 ULONG
31 FatScanFat12ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
32 IN OUT PULONG Index,
33 IN BOOLEAN CanWait);
34
35 ULONG
36 FatSetFat12ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
37 IN ULONG Index,
38 IN ULONG Length,
39 IN BOOLEAN CanWait);
40
41 ULONG
42 FatScanFat12ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
43 IN OUT PULONG Index,
44 IN ULONG IndexValue,
45 IN BOOLEAN CanWait);
46
47 ULONG
48 FatSetFat12ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
49 IN ULONG Index,
50 IN ULONG Length,
51 IN ULONG IndexValue,
52 IN BOOLEAN CanWait);
53
54 ULONG
55 FatScanFat16ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
56 IN OUT PULONG Index,
57 IN BOOLEAN CanWait);
58
59 ULONG
60 FatSetFat16ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
61 IN ULONG Index,
62 IN ULONG Length,
63 IN BOOLEAN CanWait);
64
65 ULONG
66 FatScanFat16ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
67 IN OUT PULONG Index,
68 IN ULONG IndexValue,
69 IN BOOLEAN CanWait);
70
71 ULONG
72 FatSetFat16ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
73 IN ULONG Index,
74 IN ULONG Length,
75 IN ULONG IndexValue,
76 IN BOOLEAN CanWait);
77
78 ULONG
79 FatScanFat32ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
80 IN OUT PULONG Index,
81 IN BOOLEAN CanWait);
82
83 ULONG
84 FatSetFat32ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
85 IN ULONG Index,
86 IN ULONG Length,
87 IN BOOLEAN CanWait);
88
89 ULONG
90 FatScanFat32ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
91 IN OUT PULONG Index,
92 IN ULONG IndexValue,
93 IN BOOLEAN CanWait);
94
95 ULONG
96 FatSetFat32ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
97 IN ULONG Index,
98 IN ULONG Length,
99 IN ULONG IndexValue,
100 IN BOOLEAN CanWait);
101
102 BOOLEAN
103 NTAPI
104 FatValidBpb(IN PBIOS_PARAMETER_BLOCK Bpb);
105
106 /* VARIABLES ****************************************************************/
107 FAT_METHODS Fat12Methods = {
108 FatScanFat12ForContinousRun,
109 FatSetFat12ContinousRun,
110 FatScanFat16ForValueRun,
111 FatSetFat12ValueRun
112 };
113
114 FAT_METHODS Fat16Methods = {
115 FatScanFat16ForContinousRun,
116 FatSetFat16ContinousRun,
117 FatScanFat16ForValueRun,
118 FatSetFat16ValueRun
119 };
120
121 FAT_METHODS Fat32Methods = {
122 FatScanFat32ForContinousRun,
123 FatSetFat32ContinousRun,
124 FatScanFat32ForValueRun,
125 FatSetFat32ValueRun
126 };
127
128 /* FUNCTIONS ****************************************************************/
129
130 /*
131 * FUNCTION:
132 * Determines the index of the set bit.
133 * ARGUMENTS:
134 * Number = Number having a single bit set.
135 * RETURNS: Index of the set bit.
136 */
137 FORCEINLINE
138 ULONG
139 FatPowerOfTwo(
140 ULONG Number)
141 {
142 ULONG Temp;
143 Temp = Number
144 - ((Number >> 1) & 033333333333)
145 - ((Number >> 2) & 011111111111);
146 return (((Temp + (Temp >> 3)) & 030707070707) % 63);
147 }
148
149 ULONG
150 FatScanFat12ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
151 IN OUT PULONG Index,
152 IN BOOLEAN CanWait)
153 {
154 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
155 }
156
157 ULONG
158 FatSetFat12ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
159 IN ULONG Index,
160 IN ULONG Length,
161 IN BOOLEAN CanWait)
162 {
163 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
164 }
165
166 ULONG
167 FatScanFat12ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
168 IN OUT PULONG Index,
169 IN ULONG IndexValue,
170 IN BOOLEAN CanWait)
171 {
172 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
173 }
174
175 ULONG
176 FatSetFat12ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
177 IN ULONG Index,
178 IN ULONG Length,
179 IN ULONG IndexValue,
180 IN BOOLEAN CanWait)
181 {
182 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
183 }
184
185 ULONG
186 FatScanFat16ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
187 IN OUT PULONG Index,
188 IN BOOLEAN CanWait)
189 {
190 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
191 }
192
193 ULONG
194 FatSetFat16ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
195 IN ULONG Index,
196 IN ULONG Length,
197 IN BOOLEAN CanWait)
198 {
199 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
200 }
201
202 ULONG
203 FatScanFat16ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
204 IN OUT PULONG Index,
205 IN ULONG IndexValue,
206 IN BOOLEAN CanWait)
207 {
208 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
209 }
210
211 ULONG
212 FatSetFat16ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
213 IN ULONG Index,
214 IN ULONG Length,
215 IN ULONG IndexValue,
216 IN BOOLEAN CanWait)
217 {
218 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
219 }
220
221 /*
222 * FUNCTION:
223 * Scans FAT32 for continous chain of clusters
224 * ARGUMENTS:
225 * Context = Pointer to FAT_SCAN_CONTEXT.
226 * Index = Supplies the Index of the first cluster
227 * and receves the last index after the last
228 * cluster in the chain.
229 * CanWait = Indicates if the context allows blocking.
230 * RETURNS: Value of the last claster terminated the scan.
231 * NOTES: Raises STATUS_CANT_WAIT race condition.
232 */
233 ULONG
234 FatScanFat32ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
235 IN OUT PULONG Index,
236 IN BOOLEAN CanWait)
237 {
238 LONGLONG PageOffset;
239 SIZE_T OffsetWithinPage, PageValidLength;
240 PULONG Entry, BeyoudLastEntry;
241 /* Determine page offset and the offset within page
242 * for the first cluster.
243 */
244 PageValidLength = PAGE_SIZE;
245 PageOffset = ((LONGLONG) *Index) << 0x2;
246 OffsetWithinPage = (SIZE_T) (PageOffset & (PAGE_SIZE - 1));
247 PageOffset -= OffsetWithinPage;
248 /* Check if the context already has the required page mapped.
249 * Map the first page is necessary.
250 */
251 if (PageOffset != Context->PageOffset.QuadPart)
252 {
253 Context->PageOffset.QuadPart = PageOffset;
254 if (Context->PageBcb != NULL)
255 {
256 CcUnpinData(Context->PageBcb);
257 Context->PageBcb = NULL;
258 }
259 if (!CcMapData(Context->FileObject,
260 &Context->PageOffset,
261 PAGE_SIZE,
262 CanWait,
263 &Context->PageBcb,
264 &Context->PageBuffer))
265 {
266 Context->PageOffset.QuadPart = 0LL;
267 ExRaiseStatus(STATUS_CANT_WAIT);
268 }
269 }
270 Entry = Add2Ptr(Context->PageBuffer, OffsetWithinPage, PULONG);
271 /* Next Page Offset */
272 PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE;
273 if (PageOffset > Context->BeyoundLastEntryOffset)
274 PageValidLength = (SIZE_T) (Context->BeyoundLastEntryOffset
275 - Context->PageOffset.QuadPart);
276 BeyoudLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PULONG);
277 while (TRUE)
278 {
279 do
280 {
281 if ((*Entry & FAT_CLUSTER_LAST) != ++(*Index))
282 return (*Entry & FAT_CLUSTER_LAST);
283 } while (++Entry < BeyoudLastEntry);
284 /* Check if this is the last available entry */
285 if (PageValidLength < PAGE_SIZE)
286 break;
287 /* We are getting beyound current page and
288 * are still in the continous run, map the next page.
289 */
290 Context->PageOffset.QuadPart = PageOffset;
291 CcUnpinData(Context->PageBcb);
292 if (!CcMapData(Context->FileObject,
293 &Context->PageOffset, PAGE_SIZE, CanWait,
294 &Context->PageBcb, &Context->PageBuffer))
295 {
296 Context->PageBcb = NULL;
297 Context->PageOffset.QuadPart = 0LL;
298 ExRaiseStatus(STATUS_CANT_WAIT);
299 }
300 Entry = (PULONG) Context->PageBuffer;
301 /* Next Page Offset */
302 PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE;
303 if (PageOffset > Context->BeyoundLastEntryOffset)
304 PageValidLength = (SIZE_T) (Context->BeyoundLastEntryOffset
305 - Context->PageOffset.QuadPart);
306 BeyoudLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PULONG);
307 }
308 return (*Index - 1);
309 }
310
311 ULONG
312 FatSetFat32ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context,
313 IN ULONG Index,
314 IN ULONG Length,
315 IN BOOLEAN CanWait)
316 {
317 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
318 }
319
320 ULONG
321 FatScanFat32ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
322 IN OUT PULONG Index,
323 IN ULONG IndexValue,
324 IN BOOLEAN CanWait)
325 {
326 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
327 }
328
329 ULONG
330 FatSetFat32ValueRun(IN OUT PFAT_SCAN_CONTEXT Context,
331 IN ULONG Index,
332 IN ULONG Length,
333 IN ULONG IndexValue,
334 IN BOOLEAN CanWait)
335 {
336 ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
337 }
338
339 /*
340 * FUNCTION:
341 * Queries file MCB for the specified region [Vbo, Vbo + Length],
342 * returns the number of runs in the region as well as the first
343 * run of the range itself.
344 * If the specified region is not fully cached in MCB the routine
345 * scans FAT for the file and fills the MCB until the file offset
346 * (defined as Vbo + Length) is reached.
347 * ARGUMENTS:
348 * Fcb = Pointer to FCB structure for the file.
349 * Vbo = Virtual Byte Offset in the file.
350 * Lbo = Receives the Value of Logical Byte offset corresponding
351 * to supplied Vbo Value.
352 * Length = Supplies file range length to be examined and recieves
353 * the length of first run.
354 * OutIndex = Recieves the index (in MCB cache) of first run.
355 * RETURNS: Incremented index of the last run (+1).
356 * NOTES: Should be called by I/O routines to split the I/O operation
357 * into sequential or parallel I/O operations.
358 */
359 ULONG
360 FatScanFat(IN PFCB Fcb,
361 IN LONGLONG Vbo,
362 OUT PLONGLONG Lbo,
363 IN OUT PLONGLONG Length,
364 OUT PULONG Index,
365 IN BOOLEAN CanWait)
366 {
367 LONGLONG CurrentLbo, CurrentVbo, BeyoundLastVbo, CurrentLength;
368 ULONG Entry, NextEntry, NumberOfEntries, CurrentIndex;
369 FAT_SCAN_CONTEXT Context;
370 PVCB Vcb;
371
372 /* Some often used values */
373 Vcb = Fcb->Vcb;
374 CurrentIndex = 0;
375 BeyoundLastVbo = Vbo + *Length;
376 CurrentLength = ((LONGLONG) Vcb->Clusters) << Vcb->BytesPerClusterLog;
377 if (BeyoundLastVbo > CurrentLength)
378 BeyoundLastVbo = CurrentLength;
379 /* Try to locate first run */
380 if (FsRtlLookupLargeMcbEntry(&Fcb->Mcb, Vbo, Lbo, Length, NULL, NULL, Index))
381 {
382 /* Check if we have a single mapped run */
383 if (Vbo >= BeyoundLastVbo)
384 goto FatScanFcbFatExit;
385 } else {
386 *Length = 0L;
387 }
388 /* Get the first scan startup values */
389 if (FsRtlLookupLastLargeMcbEntryAndIndex(
390 &Fcb->Mcb, &CurrentVbo, &CurrentLbo, &CurrentIndex))
391 {
392 Entry = FatDataOffsetToEntry(CurrentLbo, Vcb);
393 }
394 else
395 {
396 /* Map is empty, set up initial values */
397 Entry = Fcb->FirstCluster;
398 if (Entry <= 0x2)
399 ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR);
400 if (Entry >= Vcb->Clusters)
401 {
402 if (Entry < FAT_CLUSTER_LAST)
403 ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR);
404 BeyoundLastVbo = 0LL;
405 }
406 CurrentIndex = 0L;
407 CurrentVbo = 0LL;
408 }
409 RtlZeroMemory(&Context, sizeof(Context));
410 Context.FileObject = Vcb->VolumeFileObject;
411 while (CurrentVbo < BeyoundLastVbo)
412 {
413 /* Locate Continous run starting with the current entry */
414 NumberOfEntries = Entry;
415 NextEntry = Vcb->Methods.ScanContinousRun(
416 &Context, &NumberOfEntries, CanWait);
417 NumberOfEntries -= Entry;
418 /* Check value that terminated the for being valid for FAT */
419 if (NextEntry <= 0x2)
420 ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR);
421 if (NextEntry >= Vcb->Clusters)
422 {
423 if (NextEntry < FAT_CLUSTER_LAST)
424 ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR);
425 break;
426 }
427 /* Add new run */
428 CurrentLength = ((LONGLONG) NumberOfEntries)
429 << Vcb->BytesPerClusterLog;
430 FsRtlAddLargeMcbEntry(&Fcb->Mcb,
431 CurrentVbo,
432 FatEntryToDataOffset(Entry, Vcb),
433 CurrentLength);
434 /* Setup next iteration */
435 Entry = NextEntry;
436 CurrentVbo += CurrentLength;
437 CurrentIndex ++;
438 }
439 if (*Length == 0LL && CurrentIndex > 0)
440 {
441 if (!FsRtlLookupLargeMcbEntry(&Fcb->Mcb,
442 Vbo, Lbo, Length, NULL, NULL, Index))
443 {
444 *Index = 0L;
445 *Lbo = 0LL;
446 }
447 }
448 FatScanFcbFatExit:
449 return CurrentIndex;
450 }
451
452 BOOLEAN
453 NTAPI
454 FatValidBpb(IN PBIOS_PARAMETER_BLOCK Bpb)
455 {
456 return (FatValidBytesPerSector(Bpb->BytesPerSector)
457 && FatValidSectorsPerCluster(Bpb->SectorsPerCluster)
458 && Bpb->ReservedSectors > 0
459 && Bpb->Fats > 0
460 && (Bpb->Sectors > 0 || Bpb->LargeSectors > 0)
461 && (Bpb->SectorsPerFat > 0
462 || (Bpb->LargeSectorsPerFat > 0 && Bpb->FsVersion == 0))
463 && (Bpb->Media == 0xf0
464 || Bpb->Media == 0xf8
465 || Bpb->Media == 0xf9
466 || Bpb->Media == 0xfb
467 || Bpb->Media == 0xfc
468 || Bpb->Media == 0xfd
469 || Bpb->Media == 0xfe
470 || Bpb->Media == 0xff)
471 && (Bpb->SectorsPerFat == 0 || Bpb->RootEntries > 0)
472 && (Bpb->SectorsPerFat > 0 || !Bpb->MirrorDisabled));
473 }
474
475 VOID
476 FatiInitializeVcb(PVCB Vcb)
477 {
478 ULONG ClustersCapacity;
479
480 /* Various characteristics needed for navigation in FAT */
481 if ((Vcb->Sectors = Vcb->Bpb.Sectors) == 0)
482 Vcb->Sectors = Vcb->Bpb.LargeSectors;
483 if ((Vcb->SectorsPerFat = Vcb->Bpb.SectorsPerFat) == 0)
484 Vcb->SectorsPerFat = Vcb->Bpb.LargeSectorsPerFat;
485 Vcb->RootDirent = Vcb->Bpb.ReservedSectors + Vcb->Bpb.Fats * Vcb->SectorsPerFat;
486 Vcb->RootDirentSectors = BytesToSectors(Vcb,
487 Vcb->Bpb.RootEntries * sizeof(DIR_ENTRY));
488 Vcb->DataArea = Vcb->RootDirent + Vcb->RootDirentSectors;
489 Vcb->Clusters = (Vcb->Sectors - Vcb->Bpb.ReservedSectors
490 - Vcb->Bpb.Fats * Vcb->SectorsPerFat
491 - Vcb->RootDirentSectors) / Vcb->Bpb.SectorsPerCluster;
492 if (Vcb->BytesPerClusterLog < 4087)
493 {
494 Vcb->IndexDepth = 0x0c;
495 Vcb->Methods = Fat12Methods;
496 }
497 else
498 {
499 Vcb->IndexDepth = 0x10;
500 Vcb->Methods = Fat16Methods;
501 }
502 /* Large Sectors are used for FAT32 */
503 if (Vcb->Bpb.Sectors == 0) {
504 Vcb->IndexDepth = 0x20;
505 Vcb->Methods = Fat32Methods;
506 }
507 ClustersCapacity = (SectorsToBytes(Vcb, Vcb->Sectors) * 0x8 / Vcb->IndexDepth) - 1;
508 if (Vcb->Clusters > ClustersCapacity)
509 Vcb->Clusters = ClustersCapacity;
510 Vcb->BytesPerCluster = SectorsToBytes(Vcb, Vcb->Bpb.SectorsPerCluster);
511 Vcb->BytesPerClusterLog = FatPowerOfTwo(Vcb->BytesPerCluster);
512 Vcb->BeyoundLastClusterInFat = ((LONGLONG) Vcb->Clusters) * Vcb->IndexDepth / 0x8;
513 }
514
515 NTSTATUS
516 FatInitializeVcb(IN PVCB Vcb,
517 IN PDEVICE_OBJECT TargetDeviceObject,
518 IN PVPB Vpb)
519 {
520 NTSTATUS Status;
521 PBCB Bcb;
522 PVOID Buffer;
523 LARGE_INTEGER Offset;
524
525 RtlZeroMemory(Vcb, sizeof(*Vcb));
526
527 /* Initialize list head, so that it will
528 * not fail in cleanup.
529 */
530 InitializeListHead(&Vcb->VcbLinks);
531
532 /* Setup FCB Header */
533 Vcb->Header.NodeTypeCode = FAT_NTC_VCB;
534 Vcb->Header.NodeByteSize = sizeof(*Vcb);
535
536 /* Setup Vcb fields */
537 Vcb->TargetDeviceObject = TargetDeviceObject;
538 ObReferenceObject(TargetDeviceObject);
539
540 /* Setup FCB Header */
541 ExInitializeFastMutex(&Vcb->HeaderMutex);
542 FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->HeaderMutex);
543
544 /* Create Volume File Object */
545 Vcb->VolumeFileObject = IoCreateStreamFileObject(NULL,
546 Vcb->TargetDeviceObject);
547
548 /* We have to setup all FCB fields needed for CC */
549 Vcb->VolumeFileObject->FsContext = Vcb;
550 Vcb->VolumeFileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
551
552 /* At least full boot sector should be available */
553 Vcb->Header.FileSize.QuadPart = sizeof(PACKED_BOOT_SECTOR);
554 Vcb->Header.AllocationSize.QuadPart = sizeof(PACKED_BOOT_SECTOR);
555 Vcb->Header.ValidDataLength.HighPart = MAXLONG;
556 Vcb->Header.ValidDataLength.LowPart = MAXULONG;
557
558 /* Initialize CC */
559 CcInitializeCacheMap(Vcb->VolumeFileObject,
560 (PCC_FILE_SIZES)&Vcb->Header.AllocationSize,
561 FALSE,
562 &FatGlobalData.CacheMgrNoopCallbacks,
563 Vcb);
564
565 /* Read boot sector */
566 Offset.QuadPart = 0;
567 Bcb = NULL;
568
569 /* Note: Volume Read path does not require
570 * any of the parameters set further
571 * in this routine.
572 */
573 if (CcMapData(Vcb->VolumeFileObject,
574 &Offset,
575 sizeof(PACKED_BOOT_SECTOR),
576 TRUE,
577 &Bcb,
578 &Buffer))
579 {
580 PPACKED_BOOT_SECTOR BootSector = (PPACKED_BOOT_SECTOR) Buffer;
581 FatUnpackBios(&Vcb->Bpb, &BootSector->PackedBpb);
582 if (!(FatBootSectorJumpValid(BootSector->Jump) &&
583 FatValidBpb(&Vcb->Bpb)))
584 {
585 Status = STATUS_UNRECOGNIZED_VOLUME;
586 }
587 CopyUchar4(&Vpb->SerialNumber, BootSector->Id);
588 CcUnpinData(Bcb);
589 }
590 else
591 {
592 Status = STATUS_UNRECOGNIZED_VOLUME;
593 goto FatInitializeVcbCleanup;
594 }
595
596 /* Set up notifications */
597 FsRtlNotifyInitializeSync(&Vcb->NotifySync);
598 InitializeListHead(&Vcb->NotifyList);
599
600 /* Call helper function */
601 FatiInitializeVcb(Vcb);
602
603 /* Add this Vcb to grobal Vcb list. */
604 InsertTailList(&FatGlobalData.VcbListHead, &Vcb->VcbLinks);
605 return STATUS_SUCCESS;
606
607 FatInitializeVcbCleanup:
608
609 /* Unwind the routine actions */
610 FatUninitializeVcb(Vcb);
611 return Status;
612 }
613
614 VOID
615 FatUninitializeVcb(IN PVCB Vcb)
616 {
617 LARGE_INTEGER ZeroSize;
618
619 ZeroSize.QuadPart = 0LL;
620
621 /* Close volume file */
622 if (Vcb->VolumeFileObject != NULL)
623 {
624 /* Uninitialize CC. */
625 CcUninitializeCacheMap(Vcb->VolumeFileObject, &ZeroSize, NULL);
626 ObDereferenceObject(Vcb->VolumeFileObject);
627 Vcb->VolumeFileObject = NULL;
628 }
629
630 /* Free notifications stuff */
631 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
632
633 /* Unlink from global Vcb list. */
634 RemoveEntryList(&Vcb->VcbLinks);
635
636 /* Release Target Device */
637 ObDereferenceObject(Vcb->TargetDeviceObject);
638 Vcb->TargetDeviceObject = NULL;
639 }
640
641 /* EOF */
642
643