Author: fireball Date: Fri Jan 23 04:19:57 2009 New Revision: 39033
URL: http://svn.reactos.org/svn/reactos?rev=39033&view=rev Log: Alex Vlasov - Implement FAT operations (scanning, finding continuous runs). - Implement and plug in VCB initialization.
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fat.c trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fat.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fat.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fat.c [iso-8859-1] Fri Jan 23 04:19:57 2009 @@ -3,7 +3,7 @@ * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/filesystems/fastfat/fat.c * PURPOSE: FAT support routines - * PROGRAMMERS: + * PROGRAMMERS: Alexey Vlasov */
/* INCLUDES *****************************************************************/ @@ -11,7 +11,678 @@ #define NDEBUG #include "fastfat.h"
+/* PROTOTYPES ***************************************************************/ +typedef struct _FAT_SCAN_CONTEXT +{ + PFILE_OBJECT FileObject; + LARGE_INTEGER PageOffset; + LONGLONG BeyoundLastEntryOffset; + PVOID PageBuffer; + PBCB PageBcb; +} FAT_SCAN_CONTEXT; + +#define FatEntryToDataOffset(xEntry, xVcb) \ + ((xVcb)->DataArea + (((LONGLONG) ((xEntry) - 0x02)) << (xVcb)->BytesPerClusterLog)) + +#define FatDataOffsetToEntry(xOffset, xVcb) \ + ((ULONG) ((xOffset - (xVcb)->DataArea) >> (xVcb)->BytesPerClusterLog) + 0x02) + +ULONG +FatScanFat12ForContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN BOOLEAN CanWait); + +ULONG +FatSetFat12ContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN BOOLEAN CanWait); + +ULONG +FatScanFat12ForValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN ULONG IndexValue, + IN BOOLEAN CanWait); + +ULONG +FatSetFat12ValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN ULONG IndexValue, + IN BOOLEAN CanWait); + +ULONG +FatScanFat16ForContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN BOOLEAN CanWait); + +ULONG +FatSetFat16ContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN BOOLEAN CanWait); + +ULONG +FatScanFat16ForValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN ULONG IndexValue, + IN BOOLEAN CanWait); + +ULONG +FatSetFat16ValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN ULONG IndexValue, + IN BOOLEAN CanWait); + +ULONG +FatScanFat32ForContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN BOOLEAN CanWait); + +ULONG +FatSetFat32ContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN BOOLEAN CanWait); + +ULONG +FatScanFat32ForValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN ULONG IndexValue, + IN BOOLEAN CanWait); + +ULONG +FatSetFat32ValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN ULONG IndexValue, + IN BOOLEAN CanWait); + +BOOLEAN +NTAPI +FatValidBpb( + IN PBIOS_PARAMETER_BLOCK Bpb); + +/* VARIABLES ****************************************************************/ +FAT_METHODS Fat12Methods = { + FatScanFat12ForContinousRun, + FatSetFat12ContinousRun, + FatScanFat16ForValueRun, + FatSetFat12ValueRun +}; + +FAT_METHODS Fat16Methods = { + FatScanFat16ForContinousRun, + FatSetFat16ContinousRun, + FatScanFat16ForValueRun, + FatSetFat16ValueRun +}; + +FAT_METHODS Fat32Methods = { + FatScanFat32ForContinousRun, + FatSetFat32ContinousRun, + FatScanFat32ForValueRun, + FatSetFat32ValueRun +}; + /* FUNCTIONS ****************************************************************/ - +FORCEINLINE +ULONG +FatPowerOfTwo( + ULONG Number) +/* + * FUNCTION: + * Determines the index of the set bit. + * ARGUMENTS: + * Number = Number having a single bit set. + * RETURNS: Index of the set bit. + */ +{ + ULONG Temp; + Temp = Number + - ((Number >> 1) & 033333333333) + - ((Number >> 2) & 011111111111); + return (((Temp + (Temp >> 3)) & 030707070707) % 63); +} + +ULONG +FatScanFat12ForContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatSetFat12ContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatScanFat12ForValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN ULONG IndexValue, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatSetFat12ValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN ULONG IndexValue, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatScanFat16ForContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatSetFat16ContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatScanFat16ForValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN ULONG IndexValue, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatSetFat16ValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN ULONG IndexValue, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatScanFat32ForContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN BOOLEAN CanWait) +/* + * FUNCTION: + * Scans FAT32 for continous chain of clusters + * ARGUMENTS: + * Context = Pointer to FAT_SCAN_CONTEXT. + * Index = Supplies the Index of the first cluster + * and receves the last index after the last + * cluster in the chain. + * CanWait = Indicates if the context allows blocking. + * RETURNS: Value of the last claster terminated the scan. + * NOTES: Raises STATUS_CANT_WAIT race condition. + */ +{ + LONGLONG PageOffset; + SIZE_T OffsetWithinPage, PageValidLength; + PULONG Entry, BeyoudLastEntry; + /* + * Determine page offset and the offset within page + * for the first cluster. + */ + PageValidLength = PAGE_SIZE; + PageOffset = ((LONGLONG) *Index) << 0x2; + OffsetWithinPage = (SIZE_T) (PageOffset & (PAGE_SIZE - 1)); + PageOffset -= OffsetWithinPage; + /* + * Check if the context already has the required page mapped. + * Map the first page is necessary. + */ + if (PageOffset != Context->PageOffset.QuadPart) + { + Context->PageOffset.QuadPart = PageOffset; + if (Context->PageBcb != NULL) + { + CcUnpinData(Context->PageBcb); + Context->PageBcb = NULL; + } + if (!CcMapData(Context->FileObject, &Context->PageOffset, + PAGE_SIZE, CanWait, &Context->PageBcb, &Context->PageBuffer)) + { + Context->PageOffset.QuadPart = 0LL; + ExRaiseStatus(STATUS_CANT_WAIT); + } + } + Entry = Add2Ptr(Context->PageBuffer, OffsetWithinPage, PULONG); + /* + * Next Page Offset. + */ + PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE; + if (PageOffset > Context->BeyoundLastEntryOffset) + PageValidLength = (SIZE_T) (Context->BeyoundLastEntryOffset + - Context->PageOffset.QuadPart); + BeyoudLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PULONG); + while (TRUE) + { + do + { + if ((*Entry & FAT_CLUSTER_LAST) != ++(*Index) ) + return (*Entry & FAT_CLUSTER_LAST); + } + while (++Entry < BeyoudLastEntry); + /* + * Check if this is the last available entry. + */ + if (PageValidLength < PAGE_SIZE) + break; + /* + * We are getting beyound current page and + * are still in the continous run, map the next page. + */ + Context->PageOffset.QuadPart = PageOffset; + CcUnpinData(Context->PageBcb); + if (!CcMapData(Context->FileObject, + &Context->PageOffset, PAGE_SIZE, CanWait, + &Context->PageBcb, &Context->PageBuffer)) + { + Context->PageBcb = NULL; + Context->PageOffset.QuadPart = 0LL; + ExRaiseStatus(STATUS_CANT_WAIT); + } + Entry = (PULONG) Context->PageBuffer; + /* + * Next Page Offset. + */ + PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE; + if (PageOffset > Context->BeyoundLastEntryOffset) + PageValidLength = (SIZE_T) (Context->BeyoundLastEntryOffset + - Context->PageOffset.QuadPart); + BeyoudLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PULONG); + } + return (*Index - 1); +} + +ULONG +FatSetFat32ContinousRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatScanFat32ForValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN OUT PULONG Index, + IN ULONG IndexValue, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatSetFat32ValueRun( + IN OUT PFAT_SCAN_CONTEXT Context, + IN ULONG Index, + IN ULONG Length, + IN ULONG IndexValue, + IN BOOLEAN CanWait) +{ + ExRaiseStatus(STATUS_NOT_IMPLEMENTED); +} + +ULONG +FatScanFat( + IN PFCB Fcb, + IN LONGLONG Vbo, + OUT PLONGLONG Lbo, + IN OUT PLONGLONG Length, + OUT PULONG Index, + IN BOOLEAN CanWait +) +/* + * FUNCTION: + * Queries file MCB for the specified region [Vbo, Vbo + Length], + * returns the number of runs in the region as well as the first + * run of the range itself. + * If the specified region is not fully cached in MCB the routine + * scans FAT for the file and fills the MCB until the file offset + * (defined as Vbo + Length) is reached. + * ARGUMENTS: + * Fcb = Pointer to FCB structure for the file. + * Vbo = Virtual Byte Offset in the file. + * Lbo = Receives the Value of Logical Byte offset corresponding + * to supplied Vbo Value. + * Length = Supplies file range length to be examined and recieves + * the length of first run. + * OutIndex = Recieves the index (in MCB cache) of first run. + * RETURNS: Incremented index of the last run (+1). + * NOTES: Should be called by I/O routines to split the I/O operation + * into sequential or parallel I/O operations. + */ +{ + LONGLONG CurrentLbo, CurrentVbo, BeyoundLastVbo, CurrentLength; + ULONG Entry, NextEntry, NumberOfEntries, CurrentIndex; + FAT_SCAN_CONTEXT Context; + PVCB Vcb; + + /* + * Some often used values + */ + Vcb = Fcb->Vcb; + CurrentIndex = 0; + BeyoundLastVbo = Vbo + *Length; + CurrentLength = ((LONGLONG) Vcb->Clusters) << Vcb->BytesPerClusterLog; + if (BeyoundLastVbo > CurrentLength) + BeyoundLastVbo = CurrentLength; + /* + * Try to locate first run. + */ + if (FsRtlLookupLargeMcbEntry(&Fcb->Mcb, Vbo, Lbo, Length, NULL, NULL, Index)) + { + /* + * Check if we have a single mapped run. + */ + if (Vbo >= BeyoundLastVbo) + goto FatScanFcbFatExit; + } else { + *Length = 0L; + } + /* + * Get the first scan startup values. + */ + if (FsRtlLookupLastLargeMcbEntryAndIndex( + &Fcb->Mcb, &CurrentVbo, &CurrentLbo, &CurrentIndex)) + { + Entry = FatDataOffsetToEntry(CurrentLbo, Vcb); + } + else + { + /* + * Map is empty, set up initial values. + */ + Entry = Fcb->FirstCluster; + if (Entry <= 0x2) + ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR); + if (Entry >= Vcb->Clusters) + { + if (Entry < FAT_CLUSTER_LAST) + ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR); + BeyoundLastVbo = 0LL; + } + CurrentIndex = 0L; + CurrentVbo = 0LL; + } + RtlZeroMemory(&Context, sizeof(Context)); + Context.FileObject = Vcb->VolumeFileObject; + while (CurrentVbo < BeyoundLastVbo) + { + /* + * Locate Continous run starting with the current entry. + */ + NumberOfEntries = Entry; + NextEntry = Vcb->Methods.ScanContinousRun( + &Context, &NumberOfEntries, CanWait); + NumberOfEntries -= Entry; + /* + * Check value that terminated the for being valid for FAT. + */ + if (NextEntry <= 0x2) + ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR); + if (NextEntry >= Vcb->Clusters) + { + if (NextEntry < FAT_CLUSTER_LAST) + ExRaiseStatus(STATUS_FILE_CORRUPT_ERROR); + break; + } + /* + * Add new run. + */ + CurrentLength = ((LONGLONG) NumberOfEntries) + << Vcb->BytesPerClusterLog; + FsRtlAddLargeMcbEntry(&Fcb->Mcb, + CurrentVbo, + FatEntryToDataOffset(Entry, Vcb), + CurrentLength); + /* + * Setup next iteration. + */ + Entry = NextEntry; + CurrentVbo += CurrentLength; + CurrentIndex ++; + } + if (*Length == 0LL && CurrentIndex > 0) + { + if (!FsRtlLookupLargeMcbEntry(&Fcb->Mcb, + Vbo, Lbo, Length, NULL, NULL, Index)) + { + *Index = 0L; + *Lbo = 0LL; + } + } +FatScanFcbFatExit: + return CurrentIndex; +} + +BOOLEAN +NTAPI +FatValidBpb( + IN PBIOS_PARAMETER_BLOCK Bpb) +{ + return (FatValidBytesPerSector(Bpb->BytesPerSector) + && FatValidSectorsPerCluster(Bpb->SectorsPerCluster) + && Bpb->ReservedSectors > 0 + && Bpb->Fats > 0 + && (Bpb->Sectors > 0 || Bpb->LargeSectors > 0) + && (Bpb->SectorsPerFat > 0 + || (Bpb->LargeSectorsPerFat > 0 && Bpb->FsVersion == 0)) + && (Bpb->Media == 0xf0 + || Bpb->Media == 0xf8 + || Bpb->Media == 0xf9 + || Bpb->Media == 0xfb + || Bpb->Media == 0xfc + || Bpb->Media == 0xfd + || Bpb->Media == 0xfe + || Bpb->Media == 0xff) + && (Bpb->SectorsPerFat == 0 || Bpb->RootEntries > 0) + && (Bpb->SectorsPerFat > 0 || !Bpb->MirrorDisabled)); +} + +VOID +FatiInitializeVcb( + PVCB Vcb) +{ + ULONG ClustersCapacity; + + /* Various characteristics needed for navigation in FAT */ + if ((Vcb->Sectors = Vcb->Bpb.Sectors) == 0) + Vcb->Sectors = Vcb->Bpb.LargeSectors; + if ((Vcb->SectorsPerFat = Vcb->Bpb.SectorsPerFat) == 0) + Vcb->SectorsPerFat = Vcb->Bpb.LargeSectorsPerFat; + Vcb->RootDirent = Vcb->Bpb.ReservedSectors + Vcb->Bpb.Fats * Vcb->SectorsPerFat; + Vcb->RootDirentSectors = BytesToSectors(Vcb, + Vcb->Bpb.RootEntries * sizeof(DIR_ENTRY)); + Vcb->DataArea = Vcb->RootDirent + Vcb->RootDirentSectors; + Vcb->Clusters = (Vcb->Sectors - Vcb->Bpb.ReservedSectors + - Vcb->Bpb.Fats * Vcb->SectorsPerFat + - Vcb->RootDirentSectors) / Vcb->Bpb.SectorsPerCluster; + if (Vcb->BytesPerClusterLog < 4087) + { + Vcb->IndexDepth = 0x0c; + Vcb->Methods = Fat12Methods; + } + else + { + Vcb->IndexDepth = 0x10; + Vcb->Methods = Fat16Methods; + } + /* Large Sectors are used for FAT32 */ + if (Vcb->Bpb.Sectors == 0) { + Vcb->IndexDepth = 0x20; + Vcb->Methods = Fat32Methods; + } + ClustersCapacity = (SectorsToBytes(Vcb, Vcb->Sectors) * 0x8 / Vcb->IndexDepth) - 1; + if (Vcb->Clusters > ClustersCapacity) + Vcb->Clusters = ClustersCapacity; + Vcb->BytesPerCluster = SectorsToBytes(Vcb, Vcb->Bpb.SectorsPerCluster); + Vcb->BytesPerClusterLog = FatPowerOfTwo(Vcb->BytesPerCluster); + Vcb->BeyoundLastClusterInFat = ((LONGLONG) Vcb->Clusters) * Vcb->IndexDepth / 0x8; +} + +NTSTATUS +FatInitializeVcb( + IN PVCB Vcb, + IN PDEVICE_OBJECT TargetDeviceObject, + IN PVPB Vpb) +{ + NTSTATUS Status; + PBCB Bcb; + PVOID Buffer; + LARGE_INTEGER Offset; + + RtlZeroMemory(Vcb, sizeof(*Vcb)); + + /* + * Initialize list head, so that it will + * not fail in cleanup. + */ + InitializeListHead(&Vcb->VcbLinks); + + /* Setup FCB Header. */ + Vcb->Header.NodeTypeCode = FAT_NTC_VCB; + Vcb->Header.NodeByteSize = sizeof(*Vcb); + + /* Setup Vcb fields */ + Vcb->TargetDeviceObject = TargetDeviceObject; + ObReferenceObject(TargetDeviceObject); + + /* Setup FCB Header. */ + ExInitializeFastMutex(&Vcb->HeaderMutex); + FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->HeaderMutex); + + /* Create Volume File Object. */ + Vcb->VolumeFileObject = IoCreateStreamFileObject(NULL, + Vcb->TargetDeviceObject); + + /* We have to setup all FCB fields needed for CC. */ + Vcb->VolumeFileObject->FsContext = Vcb; + Vcb->VolumeFileObject->SectionObjectPointer = &Vcb->SectionObjectPointers; + + + /* At least full boot sector should be available. */ + Vcb->Header.FileSize.QuadPart = sizeof(PACKED_BOOT_SECTOR); + Vcb->Header.AllocationSize.QuadPart = sizeof(PACKED_BOOT_SECTOR); + Vcb->Header.ValidDataLength.HighPart = MAXLONG; + Vcb->Header.ValidDataLength.LowPart = MAXULONG; + + /* Initialize CC. */ + CcInitializeCacheMap(Vcb->VolumeFileObject, + (PCC_FILE_SIZES) &Vcb->Header.AllocationSize, + FALSE, + &FatGlobalData.CacheMgrNoopCallbacks, + Vcb); + + /* Read boot sector */ + Offset.QuadPart = 0; + Bcb = NULL; + /* + * Note: Volume Read path does not require + * any of the parameters set further + * in this routine. + */ + if (CcMapData(Vcb->VolumeFileObject, + &Offset, + sizeof(PACKED_BOOT_SECTOR), + TRUE, + &Bcb, + &Buffer)) + { + PPACKED_BOOT_SECTOR BootSector = (PPACKED_BOOT_SECTOR) Buffer; + FatUnpackBios(&Vcb->Bpb, &BootSector->PackedBpb); + if (!(FatBootSectorJumpValid(BootSector->Jump) + && FatValidBpb(&Vcb->Bpb))) + { + Status = STATUS_UNRECOGNIZED_VOLUME; + } + CopyUchar4( &Vpb->SerialNumber, BootSector->Id ); + CcUnpinData(Bcb); + } + else + { + Status = STATUS_UNRECOGNIZED_VOLUME; + goto FatInitializeVcbCleanup; + } + FatiInitializeVcb(Vcb); + /* Add this Vcb to grobal Vcb list. */ + InsertTailList(&FatGlobalData.VcbListHead, &Vcb->VcbLinks); + return STATUS_SUCCESS; + +FatInitializeVcbCleanup: + + /* Unwind the routine actions */ + FatUninitializeVcb(Vcb); + return Status; +} + +VOID +FatUninitializeVcb( + IN PVCB Vcb) +{ + LARGE_INTEGER ZeroSize; + + ZeroSize.QuadPart = 0LL; + + /* Close volume file */ + if (Vcb->VolumeFileObject != NULL) + { + /* Uninitialize CC. */ + CcUninitializeCacheMap(Vcb->VolumeFileObject, &ZeroSize, NULL); + ObDereferenceObject(Vcb->VolumeFileObject); + Vcb->VolumeFileObject = NULL; + } + /* Unlink from global Vcb list. */ + RemoveEntryList(&Vcb->VcbLinks); + + /* Release Target Device */ + ObReferenceObject(Vcb->TargetDeviceObject); + Vcb->TargetDeviceObject = NULL; +}
/* EOF */ + +
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c [iso-8859-1] Fri Jan 23 04:19:57 2009 @@ -109,10 +109,20 @@ /* Save device object in a VPB */ Vpb->DeviceObject = (PDEVICE_OBJECT)VolumeDevice;
- /* TODO: Initialize VCB for this volume */ + /* Initialize VCB for this volume */ + Status = FatInitializeVcb(&VolumeDevice->Vcb, TargetDeviceObject, Vpb); + if (!NT_SUCCESS(Status)) + goto FatMountVolumeCleanup;
/* Return success */ return STATUS_SUCCESS; + + +FatMountVolumeCleanup: + + /* Unwind the routine actions */ + IoDeleteDevice((PDEVICE_OBJECT)VolumeDevice); + return Status; }