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