XP did not have a WDK. Did you mean XP IFS?

Best regards,
Alex Ionescu

On Thu, Nov 23, 2017 at 4:04 AM, Pierre Schweitzer <pierre@reactos.org> wrote:
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a913501626e599fba9d702149896f36046832deb

commit a913501626e599fba9d702149896f36046832deb
Author: Pierre Schweitzer <pierre@reactos.org>
AuthorDate: Thu Nov 23 15:04:05 2017 +0100

    [FASTFAT_NEW] This is not permitted by WDK license.
    We should rather import from MS GitHub and backport to NT5.2.
---
 drivers/filesystems/fastfat_new/CMakeLists.txt |   44 -
 drivers/filesystems/fastfat_new/acchksup.c     |  374 --
 drivers/filesystems/fastfat_new/allocsup.c     | 5001 ------------------
 drivers/filesystems/fastfat_new/cachesup.c     | 1814 -------
 drivers/filesystems/fastfat_new/cleanup.c      | 1027 ----
 drivers/filesystems/fastfat_new/close.c        | 1224 -----
 drivers/filesystems/fastfat_new/create.c       | 5684 --------------------
 drivers/filesystems/fastfat_new/devctrl.c      |  308 --
 drivers/filesystems/fastfat_new/deviosup.c     | 3284 ------------
 drivers/filesystems/fastfat_new/dirctrl.c      | 1526 ------
 drivers/filesystems/fastfat_new/dirsup.c       | 3647 -------------
 drivers/filesystems/fastfat_new/dumpsup.c      |  381 --
 drivers/filesystems/fastfat_new/ea.c           | 2013 -------
 drivers/filesystems/fastfat_new/easup.c        | 3811 --------------
 drivers/filesystems/fastfat_new/fastfat.rc     |    5 -
 drivers/filesystems/fastfat_new/fat.h          |  729 ---
 drivers/filesystems/fastfat_new/fatdata.c      | 1424 -----
 drivers/filesystems/fastfat_new/fatdata.h      |  328 --
 drivers/filesystems/fastfat_new/fatinit.c      |  675 ---
 drivers/filesystems/fastfat_new/fatprocs.h     | 2817 ----------
 drivers/filesystems/fastfat_new/fatprocssrc.c  |    1 -
 drivers/filesystems/fastfat_new/fatstruc.h     | 1614 ------
 drivers/filesystems/fastfat_new/fileinfo.c     | 4635 ----------------
 drivers/filesystems/fastfat_new/filobsup.c     |  547 --
 drivers/filesystems/fastfat_new/flush.c        | 1261 -----
 drivers/filesystems/fastfat_new/fsctrl.c       | 6726 ------------------------
 drivers/filesystems/fastfat_new/fspdisp.c      |  472 --
 drivers/filesystems/fastfat_new/lfn.h          |   56 -
 drivers/filesystems/fastfat_new/lockctrl.c     |  726 ---
 drivers/filesystems/fastfat_new/namesup.c      | 1021 ----
 drivers/filesystems/fastfat_new/nodetype.h     |  193 -
 drivers/filesystems/fastfat_new/pnp.c          |  815 ---
 drivers/filesystems/fastfat_new/read.c         | 1649 ------
 drivers/filesystems/fastfat_new/resrcsup.c     |  807 ---
 drivers/filesystems/fastfat_new/shutdown.c     |  304 --
 drivers/filesystems/fastfat_new/sources        |   45 -
 drivers/filesystems/fastfat_new/splaysup.c     |  504 --
 drivers/filesystems/fastfat_new/strucsup.c     | 3626 -------------
 drivers/filesystems/fastfat_new/timesup.c      |  364 --
 drivers/filesystems/fastfat_new/verfysup.c     | 1853 -------
 drivers/filesystems/fastfat_new/volinfo.c      | 1272 -----
 drivers/filesystems/fastfat_new/workque.c      |  362 --
 drivers/filesystems/fastfat_new/write.c        | 2830 ----------
 43 files changed, 67799 deletions(-)

diff --git a/drivers/filesystems/fastfat_new/CMakeLists.txt b/drivers/filesystems/fastfat_new/CMakeLists.txt
deleted file mode 100644
index f21d829e63..0000000000
--- a/drivers/filesystems/fastfat_new/CMakeLists.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-
-list(APPEND SOURCE
-    acchksup.c
-    allocsup.c
-    cachesup.c
-    cleanup.c
-    close.c
-    create.c
-    devctrl.c
-    deviosup.c
-    dirctrl.c
-    dirsup.c
-    dumpsup.c
-    ea.c
-    easup.c
-    fatdata.c
-    fatinit.c
-    fatprocssrc.c
-    fileinfo.c
-    filobsup.c
-    flush.c
-    fsctrl.c
-    fspdisp.c
-    lockctrl.c
-    namesup.c
-    pnp.c
-    read.c
-    resrcsup.c
-    shutdown.c
-    splaysup.c
-    strucsup.c
-    timesup.c
-    verfysup.c
-    volinfo.c
-    workque.c
-    write.c
-    fatprocs.h)
-
-add_library(fastfat SHARED ${SOURCE} fastfat.rc)
-set_module_type(fastfat kernelmodedriver)
-target_link_libraries(fastfat ${PSEH_LIB} memcmp)
-add_importlibs(fastfat ntoskrnl hal)
-add_pch(fastfat fatprocs.h SOURCE)
-add_cd_file(TARGET fastfat DESTINATION reactos/system32/drivers NO_CAB FOR all)
diff --git a/drivers/filesystems/fastfat_new/acchksup.c b/drivers/filesystems/fastfat_new/acchksup.c
deleted file mode 100644
index b0c78a81a4..0000000000
--- a/drivers/filesystems/fastfat_new/acchksup.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*++
-
-Copyright (c) 1989-2000 Microsoft Corporation
-
-Module Name:
-
-    AcChkSup.c
-
-Abstract:
-
-    This module implements the FAT access checking routine
-
-
---*/
-
-#include "fatprocs.h"
-
-//
-//  Our debug trace level
-//
-
-#define Dbg                              (DEBUG_TRACE_ACCHKSUP)
-
-NTSTATUS
-FatCreateRestrictEveryoneToken(
-    IN PACCESS_TOKEN Token,
-    OUT PACCESS_TOKEN *RestrictedToken
-    );
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, FatCheckFileAccess)
-#pragma alloc_text(PAGE, FatCreateRestrictEveryoneToken)
-#pragma alloc_text(PAGE, FatExplicitDeviceAccessGranted)
-#endif
-
-
-BOOLEAN
-FatCheckFileAccess (
-    PIRP_CONTEXT IrpContext,
-    IN UCHAR DirentAttributes,
-    IN PACCESS_MASK DesiredAccess
-    )
-
-/*++
-
-Routine Description:
-
-    This routine checks if a desired access is allowed to a file represented
-    by the specified DirentAttriubutes.
-
-Arguments:
-
-    DirentAttributes - Supplies the Dirent attributes to check access for
-
-    DesiredAccess - Supplies the desired access mask that we are checking for
-
-Return Value:
-
-    BOOLEAN - TRUE if access is allowed and FALSE otherwise
-
---*/
-
-{
-    BOOLEAN Result;
-
-    DebugTrace(+1, Dbg, "FatCheckFileAccess\n", 0);
-    DebugTrace( 0, Dbg, "DirentAttributes = %8lx\n", DirentAttributes);
-    DebugTrace( 0, Dbg, "DesiredAccess    = %8lx\n", *DesiredAccess);
-
-    //
-    //  This procedures is programmed like a string of filters each
-    //  filter checks to see if some access is allowed,  if it is not allowed
-    //  the filter return FALSE to the user without further checks otherwise
-    //  it moves on to the next filter.  The filter check is to check for
-    //  desired access flags that are not allowed for a particular dirent
-    //
-
-    Result = TRUE;
-
-    _SEH2_TRY {
-
-        //
-        //  Check for Volume ID or Device Dirents, these are not allowed user
-        //  access at all
-        //
-
-        if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_VOLUME_ID) ||
-            FlagOn(DirentAttributes, FAT_DIRENT_ATTR_DEVICE)) {
-
-            DebugTrace(0, Dbg, "Cannot access volume id or device\n", 0);
-
-            try_return( Result = FALSE );
-        }
-
-        //
-        //  Check the desired access for the object - we only blackball that
-        //  we do not understand.  The model of filesystems using ACLs is that
-        //  they do not type the ACL to the object the ACL is on.  Permissions
-        //  are not checked for consistency vs. the object type - dir/file.
-        //
-
-        if (FlagOn(*DesiredAccess, ~(DELETE |
-                                     READ_CONTROL |
-                                     WRITE_OWNER |
-                                     WRITE_DAC |
-                                     SYNCHRONIZE |
-                                     ACCESS_SYSTEM_SECURITY |
-                                     FILE_WRITE_DATA |
-                                     FILE_READ_EA |
-                                     FILE_WRITE_EA |
-                                     FILE_READ_ATTRIBUTES |
-                                     FILE_WRITE_ATTRIBUTES |
-                                     FILE_LIST_DIRECTORY |
-                                     FILE_TRAVERSE |
-                                     FILE_DELETE_CHILD |
-                                     FILE_APPEND_DATA))) {
-
-            DebugTrace(0, Dbg, "Cannot open object\n", 0);
-
-            try_return( Result = FALSE );
-        }
-
-        //
-        //  Check for a read-only Dirent
-        //
-
-        if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
-
-            //
-            //  Check the desired access for a read-only dirent, we blackball
-            //  WRITE, FILE_APPEND_DATA, FILE_ADD_FILE,
-            //  FILE_ADD_SUBDIRECTORY, and FILE_DELETE_CHILD
-            //
-
-            if (FlagOn(*DesiredAccess, ~(DELETE |
-                                         READ_CONTROL |
-                                         WRITE_OWNER |
-                                         WRITE_DAC |
-                                         SYNCHRONIZE |
-                                         ACCESS_SYSTEM_SECURITY |
-                                         FILE_READ_DATA |
-                                         FILE_READ_EA |
-                                         FILE_WRITE_EA |
-                                         FILE_READ_ATTRIBUTES |
-                                         FILE_WRITE_ATTRIBUTES |
-                                         FILE_EXECUTE |
-                                         FILE_LIST_DIRECTORY |
-                                         FILE_TRAVERSE))) {
-
-                DebugTrace(0, Dbg, "Cannot open readonly\n", 0);
-
-                try_return( Result = FALSE );
-            }
-        }
-
-    try_exit: NOTHING;
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatCheckFileAccess );
-
-        DebugTrace(-1, Dbg, "FatCheckFileAccess -> %08lx\n", Result);
-    } _SEH2_END;
-
-    UNREFERENCED_PARAMETER( IrpContext );
-
-    return Result;
-}
-
-
-NTSTATUS
-FatExplicitDeviceAccessGranted (
-    IN PIRP_CONTEXT IrpContext,
-    IN PDEVICE_OBJECT DeviceObject,
-    IN PACCESS_STATE AccessState,
-    IN KPROCESSOR_MODE ProcessorMode
-    )
-
-/*++
-
-Routine Description:
-
-    This function asks whether the SID described in the input access state has
-    been granted any explicit access to the given device object.  It does this
-    by acquiring a token stripped of its ability to acquire access via the
-    Everyone SID and re-doing the access check.
-
-Arguments:
-
-    DeviceObject - the device whose ACL will be checked
-
-    AccessState - the access state describing the security context to be checked
-
-    ProcessorMode - the mode this check should occur against
-
-Return Value:
-
-    NTSTATUS - Indicating whether explicit access was granted.
-
---*/
-
-{
-    NTSTATUS Status;
-#ifndef __REACTOS__
-    BOOLEAN Result;
-#endif
-
-    PACCESS_TOKEN OriginalAccessToken;
-    PACCESS_TOKEN RestrictedAccessToken;
-
-    PACCESS_TOKEN *EffectiveToken;
-
-    PRIVILEGE_SET PrivilegeSet;
-
-    ACCESS_MASK GrantedAccess;
-
-    //
-    //  If the access state indicates that specific access other
-    //  than traverse was acquired, either Everyone does have such
-    //  access or explicit access was granted.  In both cases, we're
-    //  happy to let this proceed.
-    //
-
-    if (AccessState->PreviouslyGrantedAccess & (SPECIFIC_RIGHTS_ALL ^
-                                                FILE_TRAVERSE)) {
-
-        return STATUS_SUCCESS;
-    }
-
-    //
-    //  If the manage volume privilege is held, this also permits access.
-    //
-
-    PrivilegeSet.PrivilegeCount = 1;
-    PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
-    PrivilegeSet.Privilege[0].Luid = RtlConvertLongToLuid( SE_MANAGE_VOLUME_PRIVILEGE );
-    PrivilegeSet.Privilege[0].Attributes = 0;
-
-    if (SePrivilegeCheck( &PrivilegeSet,
-                          &AccessState->SubjectSecurityContext,
-                          ProcessorMode )) {
-
-        return STATUS_SUCCESS;
-    }
-
-    //
-    //  Capture the subject context as a prelude to everything below.
-    //
-
-    SeLockSubjectContext( &AccessState->SubjectSecurityContext );
-
-    //
-    //  Convert the token in the subject context into one which does not
-    //  acquire access through the Everyone SID.
-    //
-    //  The logic for deciding which token is effective comes from
-    //  SeQuerySubjectContextToken; since there is no natural way
-    //  of getting a pointer to it, do it by hand.
-    //
-
-    if (ARGUMENT_PRESENT( AccessState->SubjectSecurityContext.ClientToken )) {
-        EffectiveToken = &AccessState->SubjectSecurityContext.ClientToken;
-    } else {
-        EffectiveToken = &AccessState->SubjectSecurityContext.PrimaryToken;
-    }
-
-    OriginalAccessToken = *EffectiveToken;
-    Status = FatCreateRestrictEveryoneToken( OriginalAccessToken, &RestrictedAccessToken );
-
-    if (!NT_SUCCESS(Status)) {
-
-        SeReleaseSubjectContext( &AccessState->SubjectSecurityContext );
-        return Status;
-    }
-
-    //
-    //  Now see if the resulting context has access to the device through
-    //  its explicitly granted access.  We swap in our restricted token
-    //  for this check as the effective client token.
-    //
-
-    *EffectiveToken = RestrictedAccessToken;
-
-#ifndef __REACTOS__
-    Result = SeAccessCheck( DeviceObject->SecurityDescriptor,
-#else
-    SeAccessCheck( DeviceObject->SecurityDescriptor,
-#endif
-                            &AccessState->SubjectSecurityContext,
-                            FALSE,
-                            AccessState->OriginalDesiredAccess,
-                            0,
-                            NULL,
-                            IoGetFileObjectGenericMapping(),
-                            ProcessorMode,
-                            &GrantedAccess,
-                            &Status );
-
-    *EffectiveToken = OriginalAccessToken;
-
-    //
-    //  Cleanup and return.
-    //
-
-    SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
-    ObDereferenceObject( RestrictedAccessToken );
-
-    return Status;
-}
-
-
-NTSTATUS
-FatCreateRestrictEveryoneToken (
-    IN PACCESS_TOKEN Token,
-    OUT PACCESS_TOKEN *RestrictedToken
-    )
-
-/*++
-
-Routine Description:
-
-    This function takes a token as the input and returns a new restricted token
-    from which Everyone sid has been disabled.  The resulting token may be used
-    to find out if access is available to a user-sid by explicit means.
-
-Arguments:
-
-    Token - Input token from which Everyone sid needs to be deactivated.
-
-    RestrictedToken - Receives the the new restricted token.
-        This must be released using ObDereferenceObject(*RestrictedToken);
-
-Return Value:
-
-    NTSTATUS - Returned by SeFilterToken.
-
---*/
-
-{
-    //
-    // Array of sids to disable.
-    //
-
-    TOKEN_GROUPS SidsToDisable;
-
-    NTSTATUS Status = STATUS_SUCCESS;
-
-    //
-    //  Restricted token will contain the original sids with one change:
-    //  If Everyone sid is present in the token, it will be marked for DenyOnly.
-    //
-
-    *RestrictedToken = NULL;
-
-    //
-    //  Put Everyone sid in the array of sids to disable. This will mark it
-    //  for SE_GROUP_USE_FOR_DENY_ONLY and it'll only be applicable for Deny aces.
-    //
-
-    SidsToDisable.GroupCount = 1;
-    SidsToDisable.Groups[0].Attributes = 0;
-    SidsToDisable.Groups[0].Sid = SeExports->SeWorldSid;
-
-    Status = SeFilterToken(
-                 Token,            // Token that needs to be restricted.
-                 0,                // No flags
-                 &SidsToDisable,   // Disable everyone sid
-                 NULL,             // Do not create any restricted sids
-                 NULL,             // Do not delete any privileges
-                 RestrictedToken   // Restricted token
-                 );
-
-    return Status;
-}
-
diff --git a/drivers/filesystems/fastfat_new/allocsup.c b/drivers/filesystems/fastfat_new/allocsup.c
deleted file mode 100644
index 79a9e7865a..0000000000
--- a/drivers/filesystems/fastfat_new/allocsup.c
+++ /dev/null
@@ -1,5001 +0,0 @@
-/*++
-
-Copyright (c) 1990-2000 Microsoft Corporation
-
-Module Name:
-
-    AllocSup.c
-
-Abstract:
-
-    This module implements the Allocation support routines for Fat.
-
-
---*/
-
-#include "fatprocs.h"
-
-//
-//  The Bug check file id for this module
-//
-
-#define BugCheckFileId                   (FAT_BUG_CHECK_ALLOCSUP)
-
-//
-//  Local debug trace level
-//
-
-#define Dbg                              (DEBUG_TRACE_ALLOCSUP)
-
-#define FatMin(a, b)    ((a) < (b) ? (a) : (b))
-
-//
-//  This strucure is used by FatLookupFatEntry to remember a pinned page
-//  of fat.
-//
-
-typedef struct _FAT_ENUMERATION_CONTEXT {
-
-    VBO VboOfPinnedPage;
-    PBCB Bcb;
-    PVOID PinnedPage;
-
-} FAT_ENUMERATION_CONTEXT, *PFAT_ENUMERATION_CONTEXT;
-
-//
-//  Local support routine prototypes
-//
-
-VOID
-FatLookupFatEntry(
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN ULONG FatIndex,
-    IN OUT PULONG FatEntry,
-    IN OUT PFAT_ENUMERATION_CONTEXT Context
-    );
-
-VOID
-FatSetFatRun(
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN ULONG StartingFatIndex,
-    IN ULONG ClusterCount,
-    IN BOOLEAN ChainTogether
-    );
-
-UCHAR
-FatLogOf(
-    IN ULONG Value
-    );
-
-//
-//  Note that the KdPrint below will ONLY fire when the assert does. Leave it
-//  alone.
-//
-
-#if DBG
-#define ASSERT_CURRENT_WINDOW_GOOD(VCB) {                                               \
-    ULONG FreeClusterBitMapClear;                                                       \
-    ASSERT( (VCB)->FreeClusterBitMap.Buffer != NULL );                                  \
-    FreeClusterBitMapClear = RtlNumberOfClearBits(&(VCB)->FreeClusterBitMap);           \
-    if ((VCB)->CurrentWindow->ClustersFree != FreeClusterBitMapClear) {                 \
-        KdPrint(("FAT: ClustersFree %x h != FreeClusterBitMapClear %x h\n",             \
-                 (VCB)->CurrentWindow->ClustersFree,                                    \
-                 FreeClusterBitMapClear));                                              \
-    }                                                                                   \
-    ASSERT( (VCB)->CurrentWindow->ClustersFree == FreeClusterBitMapClear );             \
-}
-#else
-#define ASSERT_CURRENT_WINDOW_GOOD(VCB)
-#endif
-
-//
-//  The following macros provide a convenient way of hiding the details
-//  of bitmap allocation schemes.
-//
-
-
-//
-//  VOID
-//  FatLockFreeClusterBitMap (
-//      IN PVCB Vcb
-//      );
-//
-
-#define FatLockFreeClusterBitMap(VCB) {                         \
-    ASSERT(KeAreApcsDisabled());                                \
-    ExAcquireFastMutexUnsafe( &(VCB)->FreeClusterBitMapMutex ); \
-    ASSERT_CURRENT_WINDOW_GOOD(VCB)                             \
-}
-
-//
-//  VOID
-//  FatUnlockFreeClusterBitMap (
-//      IN PVCB Vcb
-//      );
-//
-
-#define FatUnlockFreeClusterBitMap(VCB) {                       \
-    ASSERT_CURRENT_WINDOW_GOOD(VCB)                             \
-    ASSERT(KeAreApcsDisabled());                                \
-    ExReleaseFastMutexUnsafe( &(VCB)->FreeClusterBitMapMutex ); \
-}
-
-//
-//  BOOLEAN
-//  FatIsClusterFree (
-//      IN PIRP_CONTEXT IrpContext,
-//      IN PVCB Vcb,
-//      IN ULONG FatIndex
-//      );
-//
-
-#define FatIsClusterFree(IRPCONTEXT,VCB,FAT_INDEX)                            \
-    (RtlCheckBit(&(VCB)->FreeClusterBitMap,(FAT_INDEX)-2) == 0)
-
-//
-//  VOID
-//  FatFreeClusters  (
-//      IN PIRP_CONTEXT IrpContext,
-//      IN PVCB Vcb,
-//      IN ULONG FatIndex,
-//      IN ULONG ClusterCount
-//      );
-//
-
-#define FatFreeClusters(IRPCONTEXT,VCB,FAT_INDEX,CLUSTER_COUNT) {             \
-    if ((CLUSTER_COUNT) == 1) {                                               \
-        FatSetFatEntry((IRPCONTEXT),(VCB),(FAT_INDEX),FAT_CLUSTER_AVAILABLE); \
-    } else {                                                                  \
-        FatSetFatRun((IRPCONTEXT),(VCB),(FAT_INDEX),(CLUSTER_COUNT),FALSE);   \
-    }                                                                         \
-}
-
-//
-//  VOID
-//  FatAllocateClusters  (
-//      IN PIRP_CONTEXT IrpContext,
-//      IN PVCB Vcb,
-//      IN ULONG FatIndex,
-//      IN ULONG ClusterCount
-//      );
-//
-
-#define FatAllocateClusters(IRPCONTEXT,VCB,FAT_INDEX,CLUSTER_COUNT) {      \
-    if ((CLUSTER_COUNT) == 1) {                                            \
-        FatSetFatEntry((IRPCONTEXT),(VCB),(FAT_INDEX),FAT_CLUSTER_LAST);   \
-    } else {                                                               \
-        FatSetFatRun((IRPCONTEXT),(VCB),(FAT_INDEX),(CLUSTER_COUNT),TRUE); \
-    }                                                                      \
-}
-
-//
-//  VOID
-//  FatUnreserveClusters  (
-//      IN PIRP_CONTEXT IrpContext,
-//      IN PVCB Vcb,
-//      IN ULONG FatIndex,
-//      IN ULONG ClusterCount
-//      );
-//
-
-#define FatUnreserveClusters(IRPCONTEXT,VCB,FAT_INDEX,CLUSTER_COUNT) {                      \
-    ASSERT( (FAT_INDEX) + (CLUSTER_COUNT) - 2 <= (VCB)->FreeClusterBitMap.SizeOfBitMap );   \
-    ASSERT( (FAT_INDEX) >= 2);                                                              \
-    RtlClearBits(&(VCB)->FreeClusterBitMap,(FAT_INDEX)-2,(CLUSTER_COUNT));                  \
-    if ((FAT_INDEX) < (VCB)->ClusterHint) {                                                 \
-        (VCB)->ClusterHint = (FAT_INDEX);                                                   \
-    }                                                                                       \
-}
-
-//
-//  VOID
-//  FatReserveClusters  (
-//      IN PIRP_CONTEXT IrpContext,
-//      IN PVCB Vcb,
-//      IN ULONG FatIndex,
-//      IN ULONG ClusterCount
-//      );
-//
-//  Handle wrapping the hint back to the front.
-//
-
-#define FatReserveClusters(IRPCONTEXT,VCB,FAT_INDEX,CLUSTER_COUNT) {                        \
-    ULONG _AfterRun = (FAT_INDEX) + (CLUSTER_COUNT);                                        \
-    ASSERT( (FAT_INDEX) + (CLUSTER_COUNT) - 2 <= (VCB)->FreeClusterBitMap.SizeOfBitMap );   \
-    ASSERT( (FAT_INDEX) >= 2);                                                              \
-    RtlSetBits(&(VCB)->FreeClusterBitMap,(FAT_INDEX)-2,(CLUSTER_COUNT));                    \
-                                                                                            \
-    if (_AfterRun - 2 >= (VCB)->FreeClusterBitMap.SizeOfBitMap) {                           \
-        _AfterRun = 2;                                                                      \
-    }                                                                                       \
-    if (RtlCheckBit(&(VCB)->FreeClusterBitMap, _AfterRun - 2))  {                                   \
-        (VCB)->ClusterHint = RtlFindClearBits( &(VCB)->FreeClusterBitMap, 1, _AfterRun - 2) + 2;    \
-        if (1 == (VCB)->ClusterHint)  {                                                             \
-            (VCB)->ClusterHint = 2;                                                         \
-        }                                                                                   \
-    }                                                                                       \
-    else {                                                                                  \
-        (VCB)->ClusterHint = _AfterRun;                                                     \
-    }                                                                                       \
-}
-
-//
-//  ULONG
-//  FatFindFreeClusterRun (
-//      IN PIRP_CONTEXT IrpContext,
-//      IN PVCB Vcb,
-//      IN ULONG ClusterCount,
-//      IN ULONG AlternateClusterHint
-//      );
-//
-//  Do a special check if only one cluster is desired.
-//
-
-#define FatFindFreeClusterRun(IRPCONTEXT,VCB,CLUSTER_COUNT,CLUSTER_HINT) ( \
-    (CLUSTER_COUNT == 1) &&                                                \
-    FatIsClusterFree((IRPCONTEXT), (VCB), (CLUSTER_HINT)) ?                \
-        (CLUSTER_HINT) :                                                   \
-        RtlFindClearBits( &(VCB)->FreeClusterBitMap,                       \
-                          (CLUSTER_COUNT),                                 \
-                          (CLUSTER_HINT) - 2) + 2                          \
-)
-
-//
-//  FAT32: Define the maximum size of the FreeClusterBitMap to be the
-//  maximum size of a FAT16 FAT.  If there are more clusters on the
-//  volume than can be represented by this many bytes of bitmap, the
-//  FAT will be split into "buckets", each of which does fit.
-//
-//  Note this count is in clusters/bits of bitmap.
-//
-
-#define MAX_CLUSTER_BITMAP_SIZE         (1 << 16)
-
-//
-//  Calculate the window a given cluster number is in.
-//
-
-#define FatWindowOfCluster(C)           (((C) - 2) / MAX_CLUSTER_BITMAP_SIZE)
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, FatAddFileAllocation)
-#pragma alloc_text(PAGE, FatAllocateDiskSpace)
-#pragma alloc_text(PAGE, FatDeallocateDiskSpace)
-#pragma alloc_text(PAGE, FatExamineFatEntries)
-#pragma alloc_text(PAGE, FatInterpretClusterType)
-#pragma alloc_text(PAGE, FatLogOf)
-#pragma alloc_text(PAGE, FatLookupFatEntry)
-#pragma alloc_text(PAGE, FatLookupFileAllocation)
-#pragma alloc_text(PAGE, FatLookupFileAllocationSize)
-#pragma alloc_text(PAGE, FatMergeAllocation)
-#pragma alloc_text(PAGE, FatSetFatEntry)
-#pragma alloc_text(PAGE, FatSetFatRun)
-#pragma alloc_text(PAGE, FatSetupAllocationSupport)
-#pragma alloc_text(PAGE, FatSplitAllocation)
-#pragma alloc_text(PAGE, FatTearDownAllocationSupport)
-#pragma alloc_text(PAGE, FatTruncateFileAllocation)
-#endif
-
-
-INLINE
-ULONG
-FatSelectBestWindow(
-    IN PVCB Vcb
-    )
-/*++
-
-Routine Description:
-
-    Choose a window to allocate clusters from.   Order of preference is:
-
-    1.  First window with >50% free clusters
-    2.  First empty window
-    3.  Window with greatest number of free clusters.
-
-Arguments:
-
-    Vcb - Supplies the Vcb for the volume
-
-Return Value:
-
-    'Best window' number (index into Vcb->Windows[])
-
---*/
-{
-    ULONG i, Fave = 0;
-    ULONG MaxFree = 0;
-    ULONG FirstEmpty = -1;
-    ULONG ClustersPerWindow = MAX_CLUSTER_BITMAP_SIZE;
-
-    ASSERT( 1 != Vcb->NumberOfWindows);
-
-    for (i = 0; i < Vcb->NumberOfWindows; i++) {
-
-        if (Vcb->Windows[i].ClustersFree == ClustersPerWindow)  {
-
-            if (-1 == FirstEmpty)  {
-
-                //
-                //  Keep note of the first empty window on the disc
-                //
-
-                FirstEmpty = i;
-            }
-        }
-        else if (Vcb->Windows[i].ClustersFree > MaxFree)  {
-
-            //
-            //  This window has the most free clusters,  so far
-            //
-
-            MaxFree = Vcb->Windows[i].ClustersFree;
-            Fave = i;
-
-            //
-            //  If this window has >50% free clusters,  then we will take it,
-            //  so don't bother considering more windows.
-            //
-
-            if (MaxFree >= (ClustersPerWindow >> 1))  {
-
-                break;
-            }
-        }
-    }
-
-    //
-    //  If there were no windows with 50% or more freespace,  then select the
-    //  first empty window on the disc,  if any - otherwise we'll just go with
-    //  the one with the most free clusters.
-    //
-
-    if ((MaxFree < (ClustersPerWindow >> 1)) && (-1 != FirstEmpty))  {
-
-        Fave = FirstEmpty;
-    }
-
-    return Fave;
-}
-
-
-VOID
-FatSetupAllocationSupport (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb
-    )
-
-/*++
-
-Routine Description:
-
-    This routine fills in the Allocation Support structure in the Vcb.
-    Most entries are computed using fat.h macros supplied with data from
-    the Bios Parameter Block.  The free cluster count, however, requires
-    going to the Fat and actually counting free sectors.  At the same time
-    the free cluster bit map is initalized.
-
-Arguments:
-
-    Vcb - Supplies the Vcb to fill in.
-
---*/
-
-{
-#ifndef __REACTOS__
-    ULONG BitMapSize;
-    PVOID BitMapBuffer;
-#endif
-    ULONG BitIndex;
-
-#ifndef __REACTOS__
-    PBCB Bcb;
-
-    ULONG Page;
-    ULONG Offset;
-    ULONG FatIndexBitSize;
-#endif
-    ULONG ClustersDescribableByFat;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatSetupAllocationSupport\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb = %8lx\n", Vcb);
-
-    //
-    //  Compute a number of fields for Vcb.AllocationSupport
-    //
-
-    Vcb->AllocationSupport.RootDirectoryLbo = FatRootDirectoryLbo( &Vcb->Bpb );
-    Vcb->AllocationSupport.RootDirectorySize = FatRootDirectorySize( &Vcb->Bpb );
-
-    Vcb->AllocationSupport.FileAreaLbo = FatFileAreaLbo( &Vcb->Bpb );
-
-    Vcb->AllocationSupport.NumberOfClusters = FatNumberOfClusters( &Vcb->Bpb );
-
-    Vcb->AllocationSupport.FatIndexBitSize = FatIndexBitSize( &Vcb->Bpb );
-
-    Vcb->AllocationSupport.LogOfBytesPerSector = FatLogOf(Vcb->Bpb.BytesPerSector);
-    Vcb->AllocationSupport.LogOfBytesPerCluster = FatLogOf(FatBytesPerCluster( &Vcb->Bpb ));
-    Vcb->AllocationSupport.NumberOfFreeClusters = 0;
-
-    //
-    //  Deal with a bug in DOS 5 format, if the Fat is not big enough to
-    //  describe all the clusters on the disk, reduce this number.  We expect
-    //  that fat32 volumes will not have this problem.
-    //
-    //  Turns out this was not a good assumption.  We have to do this always now.
-    //
-
-    ClustersDescribableByFat = ( ((FatIsFat32(Vcb)? Vcb->Bpb.LargeSectorsPerFat :
-                                                    Vcb->Bpb.SectorsPerFat) *
-                                  Vcb->Bpb.BytesPerSector * 8)
-                                 / FatIndexBitSize(&Vcb->Bpb) ) - 2;
-
-    if (Vcb->AllocationSupport.NumberOfClusters > ClustersDescribableByFat) {
-
-        Vcb->AllocationSupport.NumberOfClusters = ClustersDescribableByFat;
-    }
-
-    //
-    //  Extend the virtual volume file to include the Fat
-    //
-
-    {
-        CC_FILE_SIZES FileSizes;
-
-        FileSizes.AllocationSize.QuadPart =
-        FileSizes.FileSize.QuadPart = (FatReservedBytes( &Vcb->Bpb ) +
-                                       FatBytesPerFat( &Vcb->Bpb ));
-        FileSizes.ValidDataLength = FatMaxLarge;
-
-        if ( Vcb->VirtualVolumeFile->PrivateCacheMap == NULL ) {
-
-            CcInitializeCacheMap( Vcb->VirtualVolumeFile,
-                                  &FileSizes,
-                                  TRUE,
-                                  &FatData.CacheManagerNoOpCallbacks,
-                                  Vcb );
-
-        } else {
-
-            CcSetFileSizes( Vcb->VirtualVolumeFile, &FileSizes );
-        }
-    }
-
-    _SEH2_TRY {
-
-        if (FatIsFat32(Vcb) &&
-            Vcb->AllocationSupport.NumberOfClusters > MAX_CLUSTER_BITMAP_SIZE) {
-
-            Vcb->NumberOfWindows = (Vcb->AllocationSupport.NumberOfClusters +
-                                    MAX_CLUSTER_BITMAP_SIZE - 1) /
-                                   MAX_CLUSTER_BITMAP_SIZE;
-
-#ifndef __REACTOS__
-            BitMapSize = MAX_CLUSTER_BITMAP_SIZE;
-#endif
-
-        } else {
-
-            Vcb->NumberOfWindows = 1;
-#ifndef __REACTOS__
-            BitMapSize = Vcb->AllocationSupport.NumberOfClusters;
-#endif
-        }
-
-        Vcb->Windows = FsRtlAllocatePoolWithTag( PagedPool,
-                                                 Vcb->NumberOfWindows * sizeof(FAT_WINDOW),
-                                                 TAG_FAT_WINDOW );
-
-        RtlInitializeBitMap( &Vcb->FreeClusterBitMap,
-                             NULL,
-                             0 );
-
-        //
-        //  Chose a FAT window to begin operation in.
-        //
-
-        if (Vcb->NumberOfWindows > 1) {
-
-            //
-            //  Read the fat and count up free clusters.  We bias by the two reserved
-            //  entries in the FAT.
-            //
-
-            FatExamineFatEntries( IrpContext, Vcb,
-                                  2,
-                                  Vcb->AllocationSupport.NumberOfClusters + 2 - 1,
-                                  TRUE,
-                                  NULL,
-                                  NULL);
-
-
-            //
-            //  Pick a window to begin allocating from
-            //
-
-            Vcb->CurrentWindow = &Vcb->Windows[ FatSelectBestWindow( Vcb)];
-
-        } else {
-
-            Vcb->CurrentWindow = &Vcb->Windows[0];
-
-            //
-            //  Carefully bias ourselves by the two reserved entries in the FAT.
-            //
-
-            Vcb->CurrentWindow->FirstCluster = 2;
-            Vcb->CurrentWindow->LastCluster = Vcb->AllocationSupport.NumberOfClusters + 2 - 1;
-        }
-
-        //
-        //  Now transition to the FAT window we have chosen.
-        //
-
-        FatExamineFatEntries( IrpContext, Vcb,
-                              0,
-                              0,
-                              FALSE,
-                              Vcb->CurrentWindow,
-                              NULL);
-
-        //
-        //  Now set the ClusterHint to the first free bit in our favorite
-        //  window (except the ClusterHint is off by two).
-        //
-
-        Vcb->ClusterHint =
-            (BitIndex = RtlFindClearBits( &Vcb->FreeClusterBitMap, 1, 0 )) != -1 ?
-                BitIndex + 2 : 2;
-
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatSetupAllocationSupport );
-
-        //
-        //  If we hit an exception, back out.
-        //
-
-        if (_SEH2_AbnormalTermination()) {
-
-            FatTearDownAllocationSupport( IrpContext, Vcb );
-        }
-    } _SEH2_END;
-
-    return;
-}
-
-
-VOID
-FatTearDownAllocationSupport (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb
-    )
-
-/*++
-
-Routine Description:
-
-    This routine prepares the volume for closing.  Specifically, we must
-    release the free fat bit map buffer, and uninitialize the dirty fat
-    Mcb.
-
-Arguments:
-
-    Vcb - Supplies the Vcb to fill in.
-
-Return Value:
-
-    VOID
-
---*/
-
-{
-    DebugTrace(+1, Dbg, "FatTearDownAllocationSupport\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb = %8lx\n", Vcb);
-
-    PAGED_CODE();
-
-    //
-    //  If there are FAT buckets, free them.
-    //
-
-    if ( Vcb->Windows != NULL ) {
-
-        ExFreePool( Vcb->Windows );
-        Vcb->Windows = NULL;
-    }
-
-    //
-    //  Free the memory associated with the free cluster bitmap.
-    //
-
-    if ( Vcb->FreeClusterBitMap.Buffer != NULL ) {
-
-        ExFreePool( Vcb->FreeClusterBitMap.Buffer );
-
-        //
-        //  NULL this field as an flag.
-        //
-
-        Vcb->FreeClusterBitMap.Buffer = NULL;
-    }
-
-    //
-    //  And remove all the runs in the dirty fat Mcb
-    //
-
-    FatRemoveMcbEntry( Vcb, &Vcb->DirtyFatMcb, 0, 0xFFFFFFFF );
-
-    DebugTrace(-1, Dbg, "FatTearDownAllocationSupport -> (VOID)\n", 0);
-
-    UNREFERENCED_PARAMETER( IrpContext );
-
-    return;
-}
-
-
-VOID
-FatLookupFileAllocation (
-    IN PIRP_CONTEXT IrpContext,
-    IN PFCB FcbOrDcb,
-    IN VBO Vbo,
-    OUT PLBO Lbo,
-    OUT PULONG ByteCount,
-    OUT PBOOLEAN Allocated,
-    OUT PBOOLEAN EndOnMax,
-    OUT PULONG Index
-    )
-
-/*++
-
-Routine Description:
-
-    This routine looks up the existing mapping of VBO to LBO for a
-    file/directory.  The information it queries is either stored in the
-    mcb field of the fcb/dcb or it is stored on in the fat table and
-    needs to be retrieved and decoded, and updated in the mcb.
-
-Arguments:
-
-    FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being queried
-
-    Vbo - Supplies the VBO whose LBO we want returned
-
-    Lbo - Receives the LBO corresponding to the input Vbo if one exists
-
-    ByteCount - Receives the number of bytes within the run the run
-                that correpond between the input vbo and output lbo.
-
-    Allocated - Receives TRUE if the Vbo does have a corresponding Lbo
-                and FALSE otherwise.
-
-    EndOnMax - Receives TRUE if the run ends in the maximal FAT cluster,
-                which results in a fractional bytecount.
-
-    Index - Receives the Index of the run
-
---*/
-
-{
-    VBO CurrentVbo;
-    LBO CurrentLbo;
-    LBO PriorLbo;
-
-    VBO FirstVboOfCurrentRun;
-    LBO FirstLboOfCurrentRun;
-
-    BOOLEAN LastCluster;
-    ULONG Runs;
-
-    PVCB Vcb;
-    FAT_ENTRY FatEntry;
-    ULONG BytesPerCluster;
-    ULARGE_INTEGER BytesOnVolume;
-
-    FAT_ENUMERATION_CONTEXT Context;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatLookupFileAllocation\n", 0);
-    DebugTrace( 0, Dbg, "  FcbOrDcb  = %8lx\n", FcbOrDcb);
-    DebugTrace( 0, Dbg, "  Vbo       = %8lx\n", Vbo);
-    DebugTrace( 0, Dbg, "  Lbo       = %8lx\n", Lbo);
-    DebugTrace( 0, Dbg, "  ByteCount = %8lx\n", ByteCount);
-    DebugTrace( 0, Dbg, "  Allocated = %8lx\n", Allocated);
-
-    Context.Bcb = NULL;
-
-    Vcb = FcbOrDcb->Vcb;
-
-    *EndOnMax = FALSE;
-
-    //
-    //  Check the trivial case that the mapping is already in our
-    //  Mcb.
-    //
-
-    if ( FatLookupMcbEntry(Vcb, &FcbOrDcb->Mcb, Vbo, Lbo, ByteCount, Index) ) {
-
-        *Allocated = TRUE;
-
-        ASSERT( ByteCount != 0);
-
-        //
-        //  Detect the overflow case, trim and claim the condition.
-        //
-
-        if (Vbo + *ByteCount == 0) {
-
-            *EndOnMax = TRUE;
-        }
-
-        DebugTrace( 0, Dbg, "Found run in Mcb.\n", 0);
-        DebugTrace(-1, Dbg, "FatLookupFileAllocation -> (VOID)\n", 0);
-        return;
-    }
-
-    //
-    //  Initialize the Vcb, the cluster size, LastCluster, and
-    //  FirstLboOfCurrentRun (to be used as an indication of the first
-    //  iteration through the following while loop).
-    //
-
-    BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
-
-    BytesOnVolume.QuadPart = UInt32x32To64( Vcb->AllocationSupport.NumberOfClusters, BytesPerCluster );
-
-    LastCluster = FALSE;
-    FirstLboOfCurrentRun = 0;
-
-    //
-    //  Discard the case that the request extends beyond the end of
-    //  allocation.  Note that if the allocation size if not known
-    //  AllocationSize is set to 0xffffffff.
-    //
-
-    if ( Vbo >= FcbOrDcb->Header.AllocationSize.LowPart ) {
-
-        *Allocated = FALSE;
-
-        DebugTrace( 0, Dbg, "Vbo beyond end of file.\n", 0);
-        DebugTrace(-1, Dbg, "FatLookupFileAllocation -> (VOID)\n", 0);
-        return;
-    }
-
-    //
-    //  The Vbo is beyond the last Mcb entry.  So we adjust Current Vbo/Lbo
-    //  and FatEntry to describe the beginning of the last entry in the Mcb.
-    //  This is used as initialization for the following loop.
-    //
-    //  If the Mcb was empty, we start at the beginning of the file with
-    //  CurrentVbo set to 0 to indicate a new run.
-    //
-
-    if (FatLookupLastMcbEntry( Vcb, &FcbOrDcb->Mcb, &CurrentVbo, &CurrentLbo, &Runs )) {
-
-        DebugTrace( 0, Dbg, "Current Mcb size = %8lx.\n", CurrentVbo + 1);
-
-        CurrentVbo -= (BytesPerCluster - 1);
-        CurrentLbo -= (BytesPerCluster - 1);
-
-        //
-        //  Convert an index to a count.
-        //
-
-        Runs += 1;
-
-    } else {
-
-        DebugTrace( 0, Dbg, "Mcb empty.\n", 0);
-
-        //
-        //  Check for an FcbOrDcb that has no allocation
-        //
-
-        if (FcbOrDcb->FirstClusterOfFile == 0) {
-
-            *Allocated = FALSE;
-
-            DebugTrace( 0, Dbg, "File has no allocation.\n", 0);
-            DebugTrace(-1, Dbg, "FatLookupFileAllocation -> (VOID)\n", 0);
-            return;
-
-        } else {
-
-            CurrentVbo = 0;
-            CurrentLbo = FatGetLboFromIndex( Vcb, FcbOrDcb->FirstClusterOfFile );
-            FirstVboOfCurrentRun = CurrentVbo;
-            FirstLboOfCurrentRun = CurrentLbo;
-
-            Runs = 0;
-
-            DebugTrace( 0, Dbg, "First Lbo of file = %8lx\n", CurrentLbo);
-        }
-    }
-
-    //
-    //  Now we know that we are looking up a valid Vbo, but it is
-    //  not in the Mcb, which is a monotonically increasing list of
-    //  Vbo's.  Thus we have to go to the Fat, and update
-    //  the Mcb as we go.  We use a try-finally to unpin the page
-    //  of fat hanging around.  Also we mark *Allocated = FALSE, so that
-    //  the caller wont try to use the data if we hit an exception.
-    //
-
-    *Allocated = FALSE;
-
-    _SEH2_TRY {
-
-        FatEntry = (FAT_ENTRY)FatGetIndexFromLbo( Vcb, CurrentLbo );
-
-        //
-        //  ASSERT that CurrentVbo and CurrentLbo are now cluster alligned.
-        //  The assumption here, is that only whole clusters of Vbos and Lbos
-        //  are mapped in the Mcb.
-        //
-
-        ASSERT( ((CurrentLbo - Vcb->AllocationSupport.FileAreaLbo)
-                                                    % BytesPerCluster == 0) &&
-                (CurrentVbo % BytesPerCluster == 0) );
-
-        //
-        //  Starting from the first Vbo after the last Mcb entry, scan through
-        //  the Fat looking for our Vbo. We continue through the Fat until we
-        //  hit a noncontiguity beyond the desired Vbo, or the last cluster.
-        //
-
-        while ( !LastCluster ) {
-
-            //
-            //  Get the next fat entry, and update our Current variables.
-            //
-
-#ifndef __REACTOS__
-            FatLookupFatEntry( IrpContext, Vcb, FatEntry, &FatEntry, &Context );
-#else
-            FatLookupFatEntry( IrpContext, Vcb, FatEntry, (PULONG)&FatEntry, &Context );
-#endif
-
-            PriorLbo = CurrentLbo;
-            CurrentLbo = FatGetLboFromIndex( Vcb, FatEntry );
-            CurrentVbo += BytesPerCluster;
-
-            switch ( FatInterpretClusterType( Vcb, FatEntry )) {
-
-            //
-            //  Check for a break in the Fat allocation chain.
-            //
-
-            case FatClusterAvailable:
-            case FatClusterReserved:
-            case FatClusterBad:
-
-                DebugTrace( 0, Dbg, "Break in allocation chain, entry = %d\n", FatEntry);
-                DebugTrace(-1, Dbg, "FatLookupFileAllocation -> Fat Corrupt.  Raise Status.\n", 0);
-
-                FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
-                FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
-                break;
-
-            //
-            //  If this is the last cluster, we must update the Mcb and
-            //  exit the loop.
-            //
-
-            case FatClusterLast:
-
-                //
-                //  Assert we know where the current run started.  If the
-                //  Mcb was empty when we were called, thenFirstLboOfCurrentRun
-                //  was set to the start of the file.  If the Mcb contained an
-                //  entry, then FirstLboOfCurrentRun was set on the first
-                //  iteration through the loop.  Thus if FirstLboOfCurrentRun
-                //  is 0, then there was an Mcb entry and we are on our first
-                //  iteration, meaing that the last cluster in the Mcb was
-                //  really the last allocated cluster, but we checked Vbo
-                //  against AllocationSize, and found it OK, thus AllocationSize
-                //  must be too large.
-                //
-                //  Note that, when we finally arrive here, CurrentVbo is actually
-                //  the first Vbo beyond the file allocation and CurrentLbo is
-                //  meaningless.
-                //
-
-                DebugTrace( 0, Dbg, "Read last cluster of file.\n", 0);
-
-                //
-                //  Detect the case of the maximal file.  Note that this really isn't
-                //  a proper Vbo - those are zero-based, and this is a one-based number.
-                //  The maximal file, of 2^32 - 1 bytes, has a maximum byte offset of
-                //  2^32 - 2.
-                //
-                //  Just so we don't get confused here.
-                //
-
-                if (CurrentVbo == 0) {
-
-                    *EndOnMax = TRUE;
-                    CurrentVbo -= 1;
-                }
-
-                LastCluster = TRUE;
-
-                if (FirstLboOfCurrentRun != 0 ) {
-
-                    DebugTrace( 0, Dbg, "Adding a run to the Mcb.\n", 0);
-                    DebugTrace( 0, Dbg, "  Vbo    = %08lx.\n", FirstVboOfCurrentRun);
-                    DebugTrace( 0, Dbg, "  Lbo    = %08lx.\n", FirstLboOfCurrentRun);
-                    DebugTrace( 0, Dbg, "  Length = %08lx.\n", CurrentVbo - FirstVboOfCurrentRun);
-
-                    (VOID)FatAddMcbEntry( Vcb,
-                                          &FcbOrDcb->Mcb,
-                                          FirstVboOfCurrentRun,
-                                          FirstLboOfCurrentRun,
-                                          CurrentVbo - FirstVboOfCurrentRun );
-
-                    Runs += 1;
-                }
-
-                //
-                //  Being at the end of allocation, make sure we have found
-                //  the Vbo.  If we haven't, seeing as we checked VBO
-                //  against AllocationSize, the real disk allocation is less
-                //  than that of AllocationSize.  This comes about when the
-                //  real allocation is not yet known, and AllocaitonSize
-                //  contains MAXULONG.
-                //
-                //  KLUDGE! - If we were called by FatLookupFileAllocationSize
-                //  Vbo is set to MAXULONG - 1, and AllocationSize to the lookup
-                //  hint. Thus we merrily go along looking for a match that isn't
-                //  there, but in the meantime building an Mcb.  If this is
-                //  the case, fill in AllocationSize and return.
-                //
-
-                if ( Vbo == MAXULONG - 1 ) {
-
-                    *Allocated = FALSE;
-                    FcbOrDcb->Header.AllocationSize.QuadPart = CurrentVbo;
-
-                    DebugTrace( 0, Dbg, "New file allocation size = %08lx.\n", CurrentVbo);
-                    try_return ( NOTHING );
-                }
-
-                //
-                //  We will lie ever so slightly if we really terminated on the
-                //  maximal byte of a file.  It is really allocated.
-                //
-
-                if (Vbo >= CurrentVbo && !*EndOnMax) {
-
-                    *Allocated = FALSE;
-                    try_return ( NOTHING );
-                }
-
-                break;
-
-            //
-            //  This is a continuation in the chain.  If the run has a
-            //  discontiguity at this point, update the Mcb, and if we are beyond
-            //  the desired Vbo, this is the end of the run, so set LastCluster
-            //  and exit the loop.
-            //
-
-            case FatClusterNext:
-
-                //
-                //  This is the loop check.  The Vbo must not be bigger than the size of
-                //  the volume, and the Vbo must not have a) wrapped and b) not been at the
-                //  very last cluster in the chain, for the case of the maximal file.
-                //
-
-                if ( CurrentVbo == 0 ||
-                     (BytesOnVolume.HighPart == 0 && CurrentVbo > BytesOnVolume.LowPart)) {
-
-                    FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
-                    FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
-                }
-
-                if ( PriorLbo + BytesPerCluster != CurrentLbo ) {
-
-                    //
-                    //  Note that on the first time through the loop
-                    //  (FirstLboOfCurrentRun == 0), we don't add the
-                    //  run to the Mcb since it curresponds to the last
-                    //  run already stored in the Mcb.
-                    //
-
-                    if ( FirstLboOfCurrentRun != 0 ) {
-
-                        DebugTrace( 0, Dbg, "Adding a run to the Mcb.\n", 0);
-                        DebugTrace( 0, Dbg, "  Vbo    = %08lx.\n", FirstVboOfCurrentRun);
-                        DebugTrace( 0, Dbg, "  Lbo    = %08lx.\n", FirstLboOfCurrentRun);
-                        DebugTrace( 0, Dbg, "  Length = %08lx.\n", CurrentVbo - FirstVboOfCurrentRun);
-
-                        FatAddMcbEntry( Vcb,
-                                        &FcbOrDcb->Mcb,
-                                        FirstVboOfCurrentRun,
-                                        FirstLboOfCurrentRun,
-                                        CurrentVbo - FirstVboOfCurrentRun );
-
-                        Runs += 1;
-                    }
-
-                    //
-                    //  Since we are at a run boundry, with CurrentLbo and
-                    //  CurrentVbo being the first cluster of the next run,
-                    //  we see if the run we just added encompases the desired
-                    //  Vbo, and if so exit.  Otherwise we set up two new
-                    //  First*boOfCurrentRun, and continue.
-                    //
-
-                    if (CurrentVbo > Vbo) {
-
-                        LastCluster = TRUE;
-
-                    } else {
-
-                        FirstVboOfCurrentRun = CurrentVbo;
-                        FirstLboOfCurrentRun = CurrentLbo;
-                    }
-                }
-                break;
-
-            default:
-
-                DebugTrace(0, Dbg, "Illegal Cluster Type.\n", FatEntry);
-
-                FatBugCheck( 0, 0, 0 );
-
-                break;
-
-            } // switch()
-        } // while()
-
-        //
-        //  Load up the return parameters.
-        //
-        //  On exit from the loop, Vbo still contains the desired Vbo, and
-        //  CurrentVbo is the first byte after the run that contained the
-        //  desired Vbo.
-        //
-
-        *Allocated = TRUE;
-
-        *Lbo = FirstLboOfCurrentRun + (Vbo - FirstVboOfCurrentRun);
-
-        *ByteCount = CurrentVbo - Vbo;
-
-        if (ARGUMENT_PRESENT(Index)) {
-
-            //
-            //  Note that Runs only needs to be accurate with respect to where we
-            //  ended.  Since partial-lookup cases will occur without exclusive
-            //  synchronization, the Mcb itself may be much bigger by now.
-            //
-
-            *Index = Runs - 1;
-        }
-
-    try_exit: NOTHING;
-
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatLookupFileAllocation );
-
-        //
-        //  We are done reading the Fat, so unpin the last page of fat
-        //  that is hanging around
-        //
-
-        FatUnpinBcb( IrpContext, Context.Bcb );
-
-        DebugTrace(-1, Dbg, "FatLookupFileAllocation -> (VOID)\n", 0);
-    } _SEH2_END;
-
-    return;
-}
-
-
-VOID
-FatAddFileAllocation (
-    IN PIRP_CONTEXT IrpContext,
-    IN PFCB FcbOrDcb,
-    IN PFILE_OBJECT FileObject OPTIONAL,
-    IN ULONG DesiredAllocationSize
-    )
-
-/*++
-
-Routine Description:
-
-    This routine adds additional allocation to the specified file/directory.
-    Additional allocation is added by appending clusters to the file/directory.
-
-    If the file already has a sufficient allocation then this procedure
-    is effectively a noop.
-
-Arguments:
-
-    FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being modified.
-               This parameter must not specify the root dcb.
-
-    FileObject - If supplied inform the cache manager of the change.
-
-    DesiredAllocationSize - Supplies the minimum size, in bytes, that we want
-                            allocated to the file/directory.
-
---*/
-
-{
-    PVCB Vcb;
-    LARGE_MCB NewMcb;
-    PLARGE_MCB McbToCleanup = NULL;
-    PDIRENT Dirent = NULL;
-    ULONG NewAllocation;
-    PBCB Bcb = NULL;
-    BOOLEAN UnwindWeAllocatedDiskSpace = FALSE;
-    BOOLEAN UnwindAllocationSizeSet = FALSE;
-    BOOLEAN UnwindCacheManagerInformed = FALSE;
-    BOOLEAN UnwindWeInitializedMcb = FALSE;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatAddFileAllocation\n", 0);
-    DebugTrace( 0, Dbg, "  FcbOrDcb  =             %8lx\n", FcbOrDcb);
-    DebugTrace( 0, Dbg, "  DesiredAllocationSize = %8lx\n", DesiredAllocationSize);
-
-    //
-    //  If we haven't yet set the correct AllocationSize, do so.
-    //
-
-    if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT)  {
-
-        FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
-    }
-
-    //
-    //  Check for the benign case that the desired allocation is already
-    //  within the allocation size.
-    //
-
-    if (DesiredAllocationSize <= FcbOrDcb->Header.AllocationSize.LowPart) {
-
-        DebugTrace(0, Dbg, "Desired size within current allocation.\n", 0);
-
-        DebugTrace(-1, Dbg, "FatAddFileAllocation -> (VOID)\n", 0);
-        return;
-    }
-
-    DebugTrace( 0, Dbg, "InitialAllocation = %08lx.\n", FcbOrDcb->Header.AllocationSize.LowPart);
-
-    //
-    //  Get a chunk of disk space that will fullfill our needs.  If there
-    //  was no initial allocation, start from the hint in the Vcb, otherwise
-    //  try to allocate from the cluster after the initial allocation.
-    //
-    //  If there was no initial allocation to the file, we can just use the
-    //  Mcb in the FcbOrDcb, otherwise we have to use a new one, and merge
-    //  it to the one in the FcbOrDcb.
-    //
-
-    Vcb = FcbOrDcb->Vcb;
-
-    _SEH2_TRY {
-
-        if (FcbOrDcb->Header.AllocationSize.LowPart == 0) {
-
-            LBO FirstLboOfFile;
-
-            ASSERT( FcbOrDcb->FcbCondition == FcbGood );
-
-            FatGetDirentFromFcbOrDcb( IrpContext,
-                                      FcbOrDcb,
-                                      &Dirent,
-                                      &Bcb );
-
-            ASSERT( Bcb != NULL );
-
-            //
-            //  Set this dirty right now since this call can fail.
-            //
-
-            FatSetDirtyBcb( IrpContext, Bcb, Vcb, TRUE );
-
-
-            FatAllocateDiskSpace( IrpContext,
-                                  Vcb,
-                                  0,
-                                  &DesiredAllocationSize,
-                                  FALSE,
-                                  &FcbOrDcb->Mcb );
-
-            UnwindWeAllocatedDiskSpace = TRUE;
-            McbToCleanup = &FcbOrDcb->Mcb;
-
-            //
-            //  We have to update the dirent and FcbOrDcb copies of
-            //  FirstClusterOfFile since before it was 0
-            //
-
-            FatLookupMcbEntry( FcbOrDcb->Vcb,
-                               &FcbOrDcb->Mcb,
-                               0,
-                               &FirstLboOfFile,
-                               (PULONG)NULL,
-                               NULL );
-
-            DebugTrace( 0, Dbg, "First Lbo of file will be %08lx.\n", FirstLboOfFile );
-
-            FcbOrDcb->FirstClusterOfFile = FatGetIndexFromLbo( Vcb, FirstLboOfFile );
-
-            Dirent->FirstClusterOfFile = (USHORT)FcbOrDcb->FirstClusterOfFile;
-
-            if ( FatIsFat32(Vcb) ) {
-
-                Dirent->FirstClusterOfFileHi = (USHORT)(FcbOrDcb->FirstClusterOfFile >> 16);
-            }
-
-            //
-            //   Note the size of the allocation we need to tell the cache manager about.
-            //
-
-            NewAllocation = DesiredAllocationSize;
-
-        } else {
-
-            LBO LastAllocatedLbo;
-            VBO DontCare;
-
-            //
-            //  Get the first cluster following the current allocation.  It is possible
-            //  the Mcb is empty (or short, etc.) so we need to be slightly careful
-            //  about making sure we don't lie with the hint.
-            //
-
-            (void)FatLookupLastMcbEntry( FcbOrDcb->Vcb, &FcbOrDcb->Mcb, &DontCare, &LastAllocatedLbo, NULL );
-
-            //
-            //  Try to get some disk space starting from there.
-            //
-
-            NewAllocation = DesiredAllocationSize - FcbOrDcb->Header.AllocationSize.LowPart;
-
-            FsRtlInitializeLargeMcb( &NewMcb, PagedPool );
-            UnwindWeInitializedMcb = TRUE;
-            McbToCleanup = &NewMcb;
-
-            FatAllocateDiskSpace( IrpContext,
-                                  Vcb,
-                                  (LastAllocatedLbo != ~0  ?
-                                   FatGetIndexFromLbo(Vcb,LastAllocatedLbo + 1) :
-                                   0),
-                                  &NewAllocation,
-                                  FALSE,
-                                  &NewMcb );
-
-            UnwindWeAllocatedDiskSpace = TRUE;
-        }
-
-        //
-        //  Now that we increased the allocation of the file, mark it in the
-        //  FcbOrDcb.  Carefully prepare to handle an inability to grow the cache
-        //  structures.
-        //
-
-        FcbOrDcb->Header.AllocationSize.LowPart += NewAllocation;
-
-        //
-        //  Handle the maximal file case, where we may have just wrapped.  Note
-        //  that this must be the precise boundary case wrap, i.e. by one byte,
-        //  so that the new allocation is actually one byte "less" as far as we're
-        //  concerned.  This is important for the extension case.
-        //
-
-        if (FcbOrDcb->Header.AllocationSize.LowPart == 0) {
-
-            NewAllocation -= 1;
-            FcbOrDcb->Header.AllocationSize.LowPart = 0xffffffff;
-        }
-
-        UnwindAllocationSizeSet = TRUE;
-
-        //
-        //  Inform the cache manager to increase the section size
-        //
-
-        if ( ARGUMENT_PRESENT(FileObject) && CcIsFileCached(FileObject) ) {
-
-            CcSetFileSizes( FileObject,
-                            (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
-            UnwindCacheManagerInformed = TRUE;
-        }
-
-        //
-        //  In the extension case, we have held off actually gluing the new
-        //  allocation onto the file.  This simplifies exception cleanup since
-        //  if it was already added and the section grow failed, we'd have to
-        //  do extra work to unglue it.  This way, we can assume that if we
-        //  raise the only thing we need to do is deallocate the disk space.
-        //
-        //  Merge the allocation now.
-        //
-
-        if (FcbOrDcb->Header.AllocationSize.LowPart != NewAllocation) {
-
-            //
-            //  Tack the new Mcb onto the end of the FcbOrDcb one.
-            //
-
-            FatMergeAllocation( IrpContext,
-                                Vcb,
-                                &FcbOrDcb->Mcb,
-                                &NewMcb );
-        }
-
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatAddFileAllocation );
-
-        //
-        //  Give FlushFileBuffer a clue here.
-        //
-
-        SetFlag(FcbOrDcb->FcbState, FCB_STATE_FLUSH_FAT);
-
-        //
-        //  If we were dogged trying to complete this operation, we need to go
-        //  back various things out.
-        //
-
-        if (_SEH2_AbnormalTermination()) {
-
-            //
-            //  Pull off the allocation size we tried to add to this object if
-            //  we failed to grow cache structures or Mcb structures.
-            //
-
-            if (UnwindAllocationSizeSet) {
-
-                FcbOrDcb->Header.AllocationSize.LowPart -= NewAllocation;
-            }
-
-            if (UnwindCacheManagerInformed) {
-
-                CcSetFileSizes( FileObject,
-                                (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
-            }
-
-            //
-            //  In the case of initial allocation, we used the Fcb's Mcb and have
-            //  to clean that up as well as the FAT chain references.
-            //
-
-            if (FcbOrDcb->Header.AllocationSize.LowPart == 0) {
-
-                if (Dirent != NULL) {
-
-                    FcbOrDcb->FirstClusterOfFile = 0;
-                    Dirent->FirstClusterOfFile = 0;
-
-                    if ( FatIsFat32(Vcb) ) {
-
-                        Dirent->FirstClusterOfFileHi = 0;
-                    }
-                }
-            }
-
-            //
-            //  ... and drop the dirent Bcb if we got it.  Do it now
-            //  so we can afford to take the exception if we have to.
-            //
-
-            FatUnpinBcb( IrpContext, Bcb );
-
-            _SEH2_TRY {
-
-                //
-                //  Note this can re-raise.
-                //
-
-                if ( UnwindWeAllocatedDiskSpace ) {
-
-                    FatDeallocateDiskSpace( IrpContext, Vcb, McbToCleanup );
-                }
-
-            } _SEH2_FINALLY {
-
-                //
-                //  We always want to clean up the non-initial allocation temporary Mcb,
-                //  otherwise we have the Fcb's Mcb and we just truncate it away.
-                //
-
-                if (UnwindWeInitializedMcb == TRUE) {
-
-                    //
-                    //  Note that we already know a raise is in progress.  No danger
-                    //  of encountering the normal case code below and doing this again.
-                    //
-
-                    FsRtlUninitializeLargeMcb( McbToCleanup );
-
-                } else {
-
-                    if (McbToCleanup) {
-
-                        FsRtlTruncateLargeMcb( McbToCleanup, 0 );
-                    }
-                }
-            } _SEH2_END;
-        }
-
-        DebugTrace(-1, Dbg, "FatAddFileAllocation -> (VOID)\n", 0);
-    } _SEH2_END;
-
-    //
-    //  Non-exceptional cleanup we always want to do.  In handling the re-raise possibilities
-    //  during exceptions we had to make sure these two steps always happened there beforehand.
-    //  So now we handle the usual case.
-    //
-
-    FatUnpinBcb( IrpContext, Bcb );
-
-    if (UnwindWeInitializedMcb == TRUE) {
-
-        FsRtlUninitializeLargeMcb( &NewMcb );
-    }
-}
-
-
-VOID
-FatTruncateFileAllocation (
-    IN PIRP_CONTEXT IrpContext,
-    IN PFCB FcbOrDcb,
-    IN ULONG DesiredAllocationSize
-    )
-
-/*++
-
-Routine Description:
-
-    This routine truncates the allocation to the specified file/directory.
-
-    If the file is already smaller than the indicated size then this procedure
-    is effectively a noop.
-
-
-Arguments:
-
-    FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being modified
-               This parameter must not specify the root dcb.
-
-    DesiredAllocationSize - Supplies the maximum size, in bytes, that we want
-                            allocated to the file/directory.  It is rounded
-                            up to the nearest cluster.
-
-Return Value:
-
-    VOID - TRUE if the operation completed and FALSE if it had to
-        block but could not.
-
---*/
-
-{
-    PVCB Vcb;
-    PBCB Bcb = NULL;
-    LARGE_MCB RemainingMcb;
-    ULONG BytesPerCluster;
-    PDIRENT Dirent = NULL;
-    BOOLEAN UpdatedDirent = FALSE;
-
-    ULONG UnwindInitialAllocationSize;
-    ULONG UnwindInitialFirstClusterOfFile;
-    BOOLEAN UnwindWeAllocatedMcb = FALSE;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatTruncateFileAllocation\n", 0);
-    DebugTrace( 0, Dbg, "  FcbOrDcb  =             %8lx\n", FcbOrDcb);
-    DebugTrace( 0, Dbg, "  DesiredAllocationSize = %8lx\n", DesiredAllocationSize);
-
-    //
-    //  If the Fcb isn't in good condition, we have no business whacking around on
-    //  the disk after "its" clusters.
-    //
-    //  Inspired by a Prefix complaint.
-    //
-
-    ASSERT( FcbOrDcb->FcbCondition == FcbGood );
-
-    //
-    //  If we haven't yet set the correct AllocationSize, do so.
-    //
-
-    if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT)  {
-
-        FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
-    }
-
-    //
-    //  Round up the Desired Allocation Size to the next cluster size
-    //
-
-    Vcb = FcbOrDcb->Vcb;
-
-    BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
-
-    //
-    //  Note if the desired allocation is zero, to distinguish this from
-    //  the wrap case below.
-    //
-
-    if (DesiredAllocationSize != 0) {
-
-        DesiredAllocationSize = (DesiredAllocationSize + (BytesPerCluster - 1)) &
-                                ~(BytesPerCluster - 1);
-        //
-        //  Check for the benign case that the file is already smaller than
-        //  the desired truncation.  Note that if it wraps, then a) it was
-        //  specifying an offset in the maximally allocatable cluster and
-        //  b) we're not asking to extend the file, either.  So stop.
-        //
-
-        if (DesiredAllocationSize == 0 ||
-            DesiredAllocationSize >= FcbOrDcb->Header.AllocationSize.LowPart) {
-
-            DebugTrace(0, Dbg, "Desired size within current allocation.\n", 0);
-
-            DebugTrace(-1, Dbg, "FatTruncateFileAllocation -> (VOID)\n", 0);
-            return;
-        }
-
-    }
-
-    UnwindInitialAllocationSize = FcbOrDcb->Header.AllocationSize.LowPart;
-    UnwindInitialFirstClusterOfFile = FcbOrDcb->FirstClusterOfFile;
-
-    //
-    //  Update the FcbOrDcb allocation size.  If it is now zero, we have the
-    //  additional task of modifying the FcbOrDcb and Dirent copies of
-    //  FirstClusterInFile.
-    //
-    //  Note that we must pin the dirent before actually deallocating the
-    //  disk space since, in unwind, it would not be possible to reallocate
-    //  deallocated disk space as someone else may have reallocated it and
-    //  may cause an exception when you try to get some more disk space.
-    //  Thus FatDeallocateDiskSpace must be the final dangerous operation.
-    //
-
-    _SEH2_TRY {
-
-        FcbOrDcb->Header.AllocationSize.QuadPart = DesiredAllocationSize;
-
-        //
-        //  Special case 0
-        //
-
-        if (DesiredAllocationSize == 0) {
-
-            //
-            //  We have to update the dirent and FcbOrDcb copies of
-            //  FirstClusterOfFile since before it was 0
-            //
-
-            ASSERT( FcbOrDcb->FcbCondition == FcbGood );
-
-            FatGetDirentFromFcbOrDcb( IrpContext, FcbOrDcb, &Dirent, &Bcb );
-
-            ASSERT( Dirent && Bcb );
-
-            Dirent->FirstClusterOfFile = 0;
-
-            if (FatIsFat32(Vcb)) {
-
-                Dirent->FirstClusterOfFileHi = 0;
-            }
-
-            FcbOrDcb->FirstClusterOfFile = 0;
-
-            FatSetDirtyBcb( IrpContext, Bcb, Vcb, TRUE );
-            UpdatedDirent = TRUE;
-
-            FatDeallocateDiskSpace( IrpContext, Vcb, &FcbOrDcb->Mcb );
-
-            FatRemoveMcbEntry( FcbOrDcb->Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF );
-
-        } else {
-
-            //
-            //  Split the existing allocation into two parts, one we will keep, and
-            //  one we will deallocate.
-            //
-
-            FsRtlInitializeLargeMcb( &RemainingMcb, PagedPool );
-            UnwindWeAllocatedMcb = TRUE;
-
-            FatSplitAllocation( IrpContext,
-                                Vcb,
-                                &FcbOrDcb->Mcb,
-                                DesiredAllocationSize,
-                                &RemainingMcb );
-
-            FatDeallocateDiskSpace( IrpContext, Vcb, &RemainingMcb );
-
-            FsRtlUninitializeLargeMcb( &RemainingMcb );
-        }
-
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatTruncateFileAllocation );
-
-        //
-        //  Is this really the right backout strategy?  It would be nice if we could
-        //  pretend the truncate worked if we knew that the file had gotten into
-        //  a consistent state.  Leaving dangled clusters is probably quite preferable.
-        //
-
-        if ( _SEH2_AbnormalTermination() ) {
-
-            FcbOrDcb->Header.AllocationSize.LowPart = UnwindInitialAllocationSize;
-
-            if ( (DesiredAllocationSize == 0) && (Dirent != NULL)) {
-
-                if (UpdatedDirent)  {
-
-                    //
-                    //  If the dirent has been updated ok and marked dirty,  then we
-                    //  failed in deallocatediscspace,  and don't know what state
-                    //  the on disc fat chain is in.  So we throw away the mcb,
-                    //  and potentially loose a few clusters until the next
-                    //  chkdsk.  The operation has succeeded,  but the exception
-                    //  will still propogate.  5.1
-                    //
-
-                    FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF );
-                    FcbOrDcb->Header.AllocationSize.QuadPart = 0;
-                }
-                else  {
-
-                    Dirent->FirstClusterOfFile = (USHORT)UnwindInitialFirstClusterOfFile;
-
-                    if ( FatIsFat32(Vcb) ) {
-
-                        Dirent->FirstClusterOfFileHi =
-                                (USHORT)(UnwindInitialFirstClusterOfFile >> 16);
-                    }
-
-                    FcbOrDcb->FirstClusterOfFile = UnwindInitialFirstClusterOfFile;
-                }
-            }
-
-            if ( UnwindWeAllocatedMcb ) {
-
-                FsRtlUninitializeLargeMcb( &RemainingMcb );
-            }
-
-            //
-            //  Note that in the non zero truncation case,  we will also
-            //  leak clusters.  However, apart from this, the in memory and on disc
-            //  structures will agree.
-        }
-
-        FatUnpinBcb( IrpContext, Bcb );
-
-        //
-        //  Give FlushFileBuffer a clue here.
-        //
-
-        SetFlag(FcbOrDcb->FcbState, FCB_STATE_FLUSH_FAT);
-
-        DebugTrace(-1, Dbg, "FatTruncateFileAllocation -> (VOID)\n", 0);
-    } _SEH2_END;
-}
-
-
-VOID
-FatLookupFileAllocationSize (
-    IN PIRP_CONTEXT IrpContext,
-    IN PFCB FcbOrDcb
-    )
-
-/*++
-
-Routine Description:
-
-    This routine retrieves the current file allocatio size for the
-    specified file/directory.
-
-Arguments:
-
-    FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being modified
-
---*/
-
-{
-    LBO Lbo;
-    ULONG ByteCount;
-    BOOLEAN DontCare;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatLookupAllocationSize\n", 0);
-    DebugTrace( 0, Dbg, "  FcbOrDcb  =      %8lx\n", FcbOrDcb);
-
-    //
-    //  We call FatLookupFileAllocation with Vbo of 0xffffffff - 1.
-    //
-
-    FatLookupFileAllocation( IrpContext,
-                             FcbOrDcb,
-                             MAXULONG - 1,
-                             &Lbo,
-                             &ByteCount,
-                             &DontCare,
-                             &DontCare,
-                             NULL );
-
-    //
-    //  FileSize was set at Fcb creation time from the contents of the directory entry,
-    //  and we are only now looking up the real length of the allocation chain.  If it
-    //  cannot be contained, this is trash.  Probably more where that came from.
-    //
-
-    if (FcbOrDcb->Header.FileSize.LowPart > FcbOrDcb->Header.AllocationSize.LowPart) {
-
-        FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
-        FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
-    }
-
-    DebugTrace(-1, Dbg, "FatLookupFileAllocationSize -> (VOID)\n", 0);
-    return;
-}
-
-
-VOID
-FatAllocateDiskSpace (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN ULONG AbsoluteClusterHint,
-    IN PULONG ByteCount,
-    IN BOOLEAN ExactMatchRequired,
-    OUT PLARGE_MCB Mcb
-    )
-
-/*++
-
-Routine Description:
-
-    This procedure allocates additional disk space and builds an mcb
-    representing the newly allocated space.  If the space cannot be
-    allocated then this procedure raises an appropriate status.
-
-    Searching starts from the hint index in the Vcb unless an alternative
-    non-zero hint is given in AlternateClusterHint.  If we are using the
-    hint field in the Vcb, it is set to the cluster following our allocation
-    when we are done.
-
-    Disk space can only be allocated in cluster units so this procedure
-    will round up any byte count to the next cluster boundary.
-
-    Pictorially what is done is the following (where ! denotes the end of
-    the fat chain (i.e., FAT_CLUSTER_LAST)):
-
-
-        Mcb (empty)
-
-    becomes
-
-        Mcb |--a--|--b--|--c--!
-
-                            ^
-        ByteCount ----------+
-
-Arguments:
-
-    Vcb - Supplies the VCB being modified
-
-    AbsoluteClusterHint  - Supplies an alternate hint index to start the
-                           search from.  If this is zero we use, and update,
-                           the Vcb hint field.
-
-    ByteCount - Supplies the number of bytes that we are requesting, and
-                receives the number of bytes that we got.
-
-    ExactMatchRequired - Caller should set this to TRUE if only the precise run requested
-                 is acceptable.
-
-    Mcb - Receives the MCB describing the newly allocated disk space.  The
-          caller passes in an initialized Mcb that is filled in by this procedure.
-
- Return Value:
-
-    TRUE  - Allocated ok
-    FALSE - Failed to allocate exactly as requested (=> ExactMatchRequired was TRUE)
-
---*/
-
-{
-    UCHAR LogOfBytesPerCluster;
-    ULONG BytesPerCluster;
-    ULONG StartingCluster;
-    ULONG ClusterCount;
-    ULONG WindowRelativeHint;
-#if DBG
-#ifndef __REACTOS__
-    ULONG i;
-#endif
-    ULONG PreviousClear;
-#endif
-
-    PFAT_WINDOW Window;
-    BOOLEAN Wait;
-    BOOLEAN Result = TRUE;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatAllocateDiskSpace\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb        = %8lx\n", Vcb);
-    DebugTrace( 0, Dbg, "  *ByteCount = %8lx\n", *ByteCount);
-    DebugTrace( 0, Dbg, "  Mcb        = %8lx\n", Mcb);
-    DebugTrace( 0, Dbg, "  Hint       = %8lx\n", AbsoluteClusterHint);
-
-    ASSERT((AbsoluteClusterHint <= Vcb->AllocationSupport.NumberOfClusters + 2) && (1 != AbsoluteClusterHint));
-
-    //
-    //  Make sure byte count is not zero
-    //
-
-    if (*ByteCount == 0) {
-
-        DebugTrace(0, Dbg, "Nothing to allocate.\n", 0);
-
-        DebugTrace(-1, Dbg, "FatAllocateDiskSpace -> (VOID)\n", 0);
-        return;
-    }
-
-    //
-    //  Compute the cluster count based on the byte count, rounding up
-    //  to the next cluster if there is any remainder.  Note that the
-    //  pathalogical case BytesCount == 0 has been eliminated above.
-    //
-
-    LogOfBytesPerCluster = Vcb->AllocationSupport.LogOfBytesPerCluster;
-    BytesPerCluster = 1 << LogOfBytesPerCluster;
-
-    *ByteCount = (*ByteCount + (BytesPerCluster - 1))
-                            & ~(BytesPerCluster - 1);
-
-    //
-    //  If ByteCount is NOW zero, then we were asked for the maximal
-    //  filesize (or at least for bytes in the last allocatable sector).
-    //
-
-    if (*ByteCount == 0) {
-
-        *ByteCount = 0xffffffff;
-        ClusterCount =  1 << (32 - LogOfBytesPerCluster);
-
-    } else {
-
-        ClusterCount = (*ByteCount >> LogOfBytesPerCluster);
-    }
-
-    //
-    //  Make sure there are enough free clusters to start with, and
-    //  take them now so that nobody else takes them from us.
-    //
-
-    ExAcquireResourceSharedLite(&Vcb->ChangeBitMapResource, TRUE);
-    FatLockFreeClusterBitMap( Vcb );
-
-    if (ClusterCount <= Vcb->AllocationSupport.NumberOfFreeClusters) {
-
-        Vcb->AllocationSupport.NumberOfFreeClusters -= ClusterCount;
-
-    } else {
-
-        FatUnlockFreeClusterBitMap( Vcb );
-        ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
-
-        DebugTrace(0, Dbg, "Disk Full.  Raise Status.\n", 0);
-        FatRaiseStatus( IrpContext, STATUS_DISK_FULL );
-    }
-
-    //
-    //  Did the caller supply a hint?
-    //
-
-    if ((0 != AbsoluteClusterHint) && (AbsoluteClusterHint < (Vcb->AllocationSupport.NumberOfClusters + 2)))  {
-
-        if (Vcb->NumberOfWindows > 1)  {
-
-            //
-            //  If we're being called upon to allocate clusters outside the
-            //  current window (which happens only via MoveFile), it's a problem.
-            //  We address this by changing the current window to be the one which
-            //  contains the alternate cluster hint.  Note that if the user's
-            //  request would cross a window boundary, he doesn't really get what
-            //  he wanted.
-            //
-
-            if (AbsoluteClusterHint < Vcb->CurrentWindow->FirstCluster ||
-                AbsoluteClusterHint > Vcb->CurrentWindow->LastCluster) {
-
-                ULONG BucketNum = FatWindowOfCluster( AbsoluteClusterHint );
-
-                ASSERT( BucketNum < Vcb->NumberOfWindows);
-
-                //
-                //  Drop our shared lock on the ChangeBitMapResource,  and pick it up again
-                //  exclusive in preparation for making the window swap.
-                //
-
-                FatUnlockFreeClusterBitMap(Vcb);
-                ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
-                ExAcquireResourceExclusiveLite(&Vcb->ChangeBitMapResource, TRUE);
-                FatLockFreeClusterBitMap(Vcb);
-
-                Window = &Vcb->Windows[BucketNum];
-
-                //
-                //  Again,  test the current window against the one we want - some other
-                //  thread could have sneaked in behind our backs and kindly set it to the one
-                //  we need,  when we dropped and reacquired the ChangeBitMapResource above.
-                //
-
-                if (Window != Vcb->CurrentWindow)  {
-
-                    _SEH2_TRY {
-
-                        Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-                        SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-
-                        //
-                        //  Change to the new window (update Vcb->CurrentWindow) and scan it
-                        //  to build up a freespace bitmap etc.
-                        //
-
-                        FatExamineFatEntries( IrpContext, Vcb,
-                                              0,
-                                              0,
-                                              FALSE,
-                                              Window,
-                                              NULL);
-
-                    } _SEH2_FINALLY {
-
-                        if (!Wait) {
-
-                            ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-                        }
-
-                        if (_SEH2_AbnormalTermination()) {
-
-                            //
-                            //  We will have raised as a result of failing to pick up the
-                            //  chunk of the FAT for this window move.  Release our resources
-                            //  and return the cluster count to the volume.
-                            //
-
-                            Vcb->AllocationSupport.NumberOfFreeClusters += ClusterCount;
-
-                            FatUnlockFreeClusterBitMap( Vcb );
-                            ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
-                        }
-                    } _SEH2_END;
-                }
-            }
-
-            //
-            //  Make the hint cluster number relative to the base of the current window...
-            //
-            //  Currentwindow->Firstcluster is baised by +2 already,  so we will lose the
-            //  bias already in AbsoluteClusterHint.  Put it back....
-            //
-
-            WindowRelativeHint = AbsoluteClusterHint - Vcb->CurrentWindow->FirstCluster + 2;
-        }
-        else {
-
-            //
-            //  Only one 'window',  ie fat16/12.  No modification necessary.
-            //
-
-            WindowRelativeHint = AbsoluteClusterHint;
-        }
-    }
-    else {
-
-        //
-        //  Either no hint supplied,  or it was out of range,  so grab one from the Vcb
-        //
-        //  NOTE: Clusterhint in the Vcb is not guaranteed to be set (may be -1)
-        //
-
-        WindowRelativeHint = Vcb->ClusterHint;
-        AbsoluteClusterHint = 0;
-
-        //
-        //  Vcb hint may not have been initialized yet.  Force to valid cluster.
-        //
-
-        if (-1 == WindowRelativeHint)  {
-
-            WindowRelativeHint = 2;
-        }
-    }
-
-    ASSERT((WindowRelativeHint >= 2) && (WindowRelativeHint < Vcb->FreeClusterBitMap.SizeOfBitMap + 2));
-
-    //
-    //  Keep track of the window we're allocating from, so we can clean
-    //  up correctly if the current window changes after we unlock the
-    //  bitmap.
-    //
-
-    Window = Vcb->CurrentWindow;
-
-    //
-    //  Try to find a run of free clusters large enough for us.
-    //
-
-    StartingCluster = FatFindFreeClusterRun( IrpContext,
-                                             Vcb,
-                                             ClusterCount,
-                                             WindowRelativeHint );
-    //
-    //  If the above call was successful, we can just update the fat
-    //  and Mcb and exit.  Otherwise we have to look for smaller free
-    //  runs.
-    //
-    //  This test is a bit funky. Note that the error return from
-    //  RtlFindClearBits is -1, and adding two to that is 1.
-    //
-
-    if ((StartingCluster != 1) &&
-        ((0 == AbsoluteClusterHint) || (StartingCluster == WindowRelativeHint))
-    )  {
-
-#if DBG
-        PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
-#endif // DBG
-
-        //
-        //  Take the clusters we found, and unlock the bit map.
-        //
-
-        FatReserveClusters(IrpContext, Vcb, StartingCluster, ClusterCount);
-
-        Window->ClustersFree -= ClusterCount;
-
-        StartingCluster += Window->FirstCluster;
-        StartingCluster -= 2;
-
-        ASSERT( PreviousClear - ClusterCount == Window->ClustersFree );
-
-        FatUnlockFreeClusterBitMap( Vcb );
-
-        //
-        //  Note that this call will never fail since there is always
-        //  room for one entry in an empty Mcb.
-        //
-
-        FatAddMcbEntry( Vcb, Mcb,
-                        0,
-                        FatGetLboFromIndex( Vcb, StartingCluster ),
-                        *ByteCount);
-        _SEH2_TRY {
-
-            //
-            //  Update the fat.
-            //
-
-            FatAllocateClusters(IrpContext, Vcb,
-                                StartingCluster,
-                                ClusterCount);
-
-        } _SEH2_FINALLY {
-
-            DebugUnwind( FatAllocateDiskSpace );
-
-            //
-            //  If the allocate clusters failed, remove the run from the Mcb,
-            //  unreserve the clusters, and reset the free cluster count.
-            //
-
-            if (_SEH2_AbnormalTermination()) {
-
-                FatRemoveMcbEntry( Vcb, Mcb, 0, *ByteCount );
-
-                FatLockFreeClusterBitMap( Vcb );
-
-                //  Only clear bits if the bitmap window is the same.
-
-                if (Window == Vcb->CurrentWindow) {
-
-                    //  Both values (startingcluster and window->firstcluster) are
-                    //  already biased by 2,  so will cancel,  so we need to add in the 2 again.
-
-                    FatUnreserveClusters( IrpContext, Vcb,
-                                          StartingCluster - Window->FirstCluster + 2,
-                                          ClusterCount );
-                }
-
-                Window->ClustersFree += ClusterCount;
-                Vcb->AllocationSupport.NumberOfFreeClusters += ClusterCount;
-
-                FatUnlockFreeClusterBitMap( Vcb );
-            }
-
-            ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
-        } _SEH2_END;
-
-    } else {
-
-        //
-        //  Note that Index is a zero-based window-relative number.  When appropriate
-        //  it'll get converted into a true cluster number and put in Cluster, which
-        //  will be a volume relative true cluster number.
-        //
-
-        ULONG Index;
-        ULONG Cluster;
-        ULONG CurrentVbo;
-        ULONG PriorLastCluster;
-        ULONG BytesFound;
-
-        ULONG ClustersFound = 0;
-        ULONG ClustersRemaining;
-
-        BOOLEAN LockedBitMap = FALSE;
-        BOOLEAN SelectNextContigWindow = FALSE;
-
-        //
-        //  Drop our shared lock on the ChangeBitMapResource,  and pick it up again
-        //  exclusive in preparation for making a window swap.
-        //
-
-        FatUnlockFreeClusterBitMap(Vcb);
-        ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
-        ExAcquireResourceExclusiveLite(&Vcb->ChangeBitMapResource, TRUE);
-        FatLockFreeClusterBitMap(Vcb);
-        LockedBitMap = TRUE;
-
-        _SEH2_TRY {
-
-            if ( ExactMatchRequired && (1 == Vcb->NumberOfWindows))  {
-
-                //
-                //  Give up right now,  there are no more windows to search!  RtlFindClearBits
-                //  searchs the whole bitmap,  so we would have found any contiguous run
-                //  large enough.
-                //
-
-                try_leave( Result = FALSE);
-            }
-
-            //
-            //  While the request is still incomplete, look for the largest
-            //  run of free clusters, mark them taken, allocate the run in
-            //  the Mcb and Fat, and if this isn't the first time through
-            //  the loop link it to prior run on the fat.  The Mcb will
-            //  coalesce automatically.
-            //
-
-            ClustersRemaining = ClusterCount;
-            CurrentVbo = 0;
-            PriorLastCluster = 0;
-
-            while (ClustersRemaining != 0) {
-
-                //
-                //  If we just entered the loop, the bit map is already locked
-                //
-
-                if ( !LockedBitMap ) {
-
-                    FatLockFreeClusterBitMap( Vcb );
-                    LockedBitMap = TRUE;
-                }
-
-                //
-                //  Find the largest run of free clusters.  If the run is
-                //  bigger than we need, only use what we need.  Note that
-                //  this will then be the last while() iteration.
-                //
-
-                // 12/3/95: need to bias bitmap by 2 bits for the defrag
-                // hooks and the below macro became impossible to do without in-line
-                // procedures.
-                //
-                // ClustersFound = FatLongestFreeClusterRun( IrpContext, Vcb, &Index );
-
-                ClustersFound = 0;
-
-                if (!SelectNextContigWindow)  {
-
-                    if ( 0 != WindowRelativeHint)  {
-
-                        ULONG Desired = Vcb->FreeClusterBitMap.SizeOfBitMap - (WindowRelativeHint - 2);
-
-                        //
-                        //  We will try to allocate contiguously.  Try from the current hint the to
-                        //  end of current window.  Don't try for more than we actually need.
-                        //
-
-                        if (Desired > ClustersRemaining)  {
-
-                            Desired = ClustersRemaining;
-                        }
-
-                        if (RtlAreBitsClear(  &Vcb->FreeClusterBitMap,
-                                              WindowRelativeHint - 2,
-                                              Desired))
-                        {
-                            //
-                            //  Clusters from hint->...windowend are free.  Take them.
-                            //
-
-                            Index = WindowRelativeHint - 2;
-                            ClustersFound = Desired;
-
-                            if (FatIsFat32(Vcb))  {
-
-                                //
-                                //  We're now up against the end of the current window,  so indicate that we
-                                //  want the next window in the sequence next time around.  (If we're not up
-                                //  against the end of the window,  then we got what we needed and won't be
-                                //  coming around again anyway).
-                                //
-
-                                SelectNextContigWindow = TRUE;
-                                WindowRelativeHint = 2;
-                            }
-                            else {
-
-                                //
-                                //  FAT 12/16 - we've run up against the end of the volume.  Clear the
-                                //  hint,  since we now have no idea where to look.
-                                //
-
-                                WindowRelativeHint = 0;
-                            }
-#if DBG
-                            PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
-#endif // DBG
-                        }
-                        else  {
-
-                            if (ExactMatchRequired)  {
-
-                                //
-                                //  If our caller required an exact match,  then we're hosed.  Bail out now.
-                                //
-
-                                try_leave( Result = FALSE);
-                            }
-
-                            //
-                            //  Hint failed,  drop back to pot luck
-                            //
-
-                            WindowRelativeHint = 0;
-                        }
-                    }
-
-                    if ((0 == WindowRelativeHint) && (0 == ClustersFound)) {
-
-                        if (ClustersRemaining <= Vcb->CurrentWindow->ClustersFree)  {
-
-                            //
-                            //  The remaining allocation could be satisfied entirely from this
-                            //  window.  We will ask only for what we need,  to try and avoid
-                            //  unnecessarily fragmenting large runs of space by always using
-                            //  (part of) the largest run we can find.  This call will return the
-                            //  first run large enough.
-                            //
-
-                            Index = RtlFindClearBits( &Vcb->FreeClusterBitMap,  ClustersRemaining,  0);
-
-                            if (-1 != Index)  {
-
-                                ClustersFound = ClustersRemaining;
-                            }
-                        }
-
-                        if (0 == ClustersFound)  {
-
-                            //
-                            //  Still nothing,  so just take the largest free run we can find.
-                            //
-
-                            ClustersFound = RtlFindLongestRunClear( &Vcb->FreeClusterBitMap, &Index );
-
-                        }
-#if DBG
-                        PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
-#endif // DBG
-                        if (ClustersFound >= ClustersRemaining) {
-
-                            ClustersFound = ClustersRemaining;
-                        }
-                        else {
-
-                            //
-                            //  If we just ran up to the end of a window,  set up a hint that
-                            //  we'd like the next consecutive window after this one. (FAT32 only)
-                            //
-
-                            if ( ((Index + ClustersFound) == Vcb->FreeClusterBitMap.SizeOfBitMap) &&
-                                 FatIsFat32( Vcb)
-                               )  {
-
-                                SelectNextContigWindow = TRUE;
-                                WindowRelativeHint = 2;
-                            }
-                        }
-                    }
-                }
-
-                if (ClustersFound == 0) {
-
-                    ULONG FaveWindow = 0;
-                    BOOLEAN SelectedWindow;
-
-                    //
-                    //  If we found no free clusters on a single-window FAT,
-                    //  there was a bad problem with the free cluster count.
-                    //
-
-                    if (1 == Vcb->NumberOfWindows) {
-
-                        FatBugCheck( 0, 5, 0 );
-                    }
-
-                    //
-                    //  Switch to a new bucket.  Possibly the next one if we're
-                    //  currently on a roll (allocating contiguously)
-                    //
-
-                    SelectedWindow = FALSE;
-
-                    if ( SelectNextContigWindow)  {
-
-                        ULONG NextWindow;
-
-                        NextWindow = (((ULONG)((PUCHAR)Vcb->CurrentWindow - (PUCHAR)Vcb->Windows)) / sizeof( FAT_WINDOW)) + 1;
-
-                        if ((NextWindow < Vcb->NumberOfWindows) &&
-                            ( Vcb->Windows[ NextWindow].ClustersFree > 0)
-                           )  {
-
-                            FaveWindow = NextWindow;
-                            SelectedWindow = TRUE;
-                        }
-                        else  {
-
-                            if (ExactMatchRequired)  {
-
-                                //
-                                //  Some dope tried to allocate a run past the end of the volume...
-                                //
-
-                                try_leave( Result = FALSE);
-                            }
-
-                            //
-                            //  Give up on the contiguous allocation attempts
-                            //
-
-                            WindowRelativeHint = 0;
-                        }
-
-                        SelectNextContigWindow = FALSE;
-                    }
-
-                    if (!SelectedWindow)  {
-
-                        //
-                        //  Select a new window to begin allocating from
-                        //
-
-                        FaveWindow = FatSelectBestWindow( Vcb);
-                    }
-
-                    //
-                    //  By now we'd better have found a window with some free clusters
-                    //
-
-                    if (0 == Vcb->Windows[ FaveWindow].ClustersFree) {
-
-                        FatBugCheck( 0, 5, 1 );
-                    }
-
-                    Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-
-                    FatExamineFatEntries( IrpContext, Vcb,
-                                          0,
-                                          0,
-                                          FALSE,
-                                          &Vcb->Windows[FaveWindow],
-                                          NULL);
-
-                    if (!Wait) {
-
-                        ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-                    }
-
-                    //
-                    //  Now we'll just go around the loop again, having switched windows,
-                    //  and allocate....
-                    //
-#if DBG
-                    PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
-#endif //DBG
-                }       // if (clustersfound == 0)
-                else  {
-
-                    //
-                    //  Take the clusters we found, convert our index to a cluster number
-                    //  and unlock the bit map.
-                    //
-
-                    Window = Vcb->CurrentWindow;
-
-                    FatReserveClusters( IrpContext, Vcb, (Index + 2), ClustersFound );
-
-                    Cluster = Index + Window->FirstCluster;
-
-                    Window->ClustersFree -= ClustersFound;
-                    ASSERT( PreviousClear - ClustersFound == Window->ClustersFree );
-
-                    FatUnlockFreeClusterBitMap( Vcb );
-                    LockedBitMap = FALSE;
-
-                    //
-                    //  Add the newly alloced run to the Mcb.
-                    //
-
-                    BytesFound = ClustersFound << LogOfBytesPerCluster;
-
-                    FatAddMcbEntry( Vcb, Mcb,
-                                    CurrentVbo,
-                                    FatGetLboFromIndex( Vcb, Cluster ),
-                                    BytesFound );
-
-                    //
-                    //  Connect the last allocated run with this one, and allocate
-                    //  this run on the Fat.
-                    //
-
-                    if (PriorLastCluster != 0) {
-
-                        FatSetFatEntry( IrpContext,
-                                        Vcb,
-                                        PriorLastCluster,
-                                        (FAT_ENTRY)Cluster );
-                    }
-
-                    //
-                    //  Update the fat
-                    //
-
-                    FatAllocateClusters( IrpContext, Vcb, Cluster, ClustersFound );
-
-                    //
-                    //  Prepare for the next iteration.
-                    //
-
-                    CurrentVbo += BytesFound;
-                    ClustersRemaining -= ClustersFound;
-                    PriorLastCluster = Cluster + ClustersFound - 1;
-                }
-            }  // while (clustersremaining)
-
-        } _SEH2_FINALLY {
-
-            DebugUnwind( FatAllocateDiskSpace );
-
-            ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
-
-            //
-            //  Is there any unwinding to do?
-            //
-
-            if ( _SEH2_AbnormalTermination() || (FALSE == Result)) {
-
-                //
-                //  Flag to the caller that they're getting nothing
-                //
-
-                *ByteCount = 0;
-
-                //
-                //  There are three places we could have taken this exception:
-                //  when switching the window (FatExamineFatEntries), adding
-                //  a found run to the Mcb (FatAddMcbEntry), or when writing
-                //  the changes to the FAT (FatSetFatEntry).  In the first case
-                //  we don't have anything to unwind before deallocation, and
-                //  can detect this by seeing if we have the ClusterBitmap
-                //  mutex out.
-
-                if (!LockedBitMap) {
-
-                    FatLockFreeClusterBitMap( Vcb );
-
-                    //
-                    //  In these cases, we have the possiblity that the FAT
-                    //  window is still in place and we need to clear the bits.
-                    //  If the Mcb entry isn't there (we raised trying to add
-                    //  it), the effect of trying to remove it is a noop.
-                    //
-
-                    if (Window == Vcb->CurrentWindow) {
-
-                        //
-                        //  Cluster reservation works on cluster 2 based window-relative
-                        //  numbers, so we must convert.  The subtraction will lose the
-                        //  cluster 2 base, so bias the result.
-                        //
-
-                        FatUnreserveClusters( IrpContext, Vcb,
-                                              (Cluster - Window->FirstCluster) + 2,
-                                              ClustersFound );
-                    }
-
-                    //
-                    //  Note that FatDeallocateDiskSpace will take care of adjusting
-                    //  to account for the entries in the Mcb.  All we have to account
-                    //  for is the last run that didn't make it.
-                    //
-
-                    Window->ClustersFree += ClustersFound;
-                    Vcb->AllocationSupport.NumberOfFreeClusters += ClustersFound;
-
-                    FatUnlockFreeClusterBitMap( Vcb );
-
-                    FatRemoveMcbEntry( Vcb, Mcb, CurrentVbo, BytesFound );
-
-                } else {
-
-                    //
-                    //  Just drop the mutex now - we didn't manage to do anything
-                    //  that needs to be backed out.
-                    //
-
-                    FatUnlockFreeClusterBitMap( Vcb );
-                }
-
-                _SEH2_TRY {
-
-                    //
-                    //  Now we have tidied up, we are ready to just send the Mcb
-                    //  off to deallocate disk space
-                    //
-
-                    FatDeallocateDiskSpace( IrpContext, Vcb, Mcb );
-
-                } _SEH2_FINALLY {
-
-                    //
-                    //  Now finally (really), remove all the entries from the mcb
-                    //
-
-                    FatRemoveMcbEntry( Vcb, Mcb, 0, 0xFFFFFFFF );
-                } _SEH2_END;
-            }
-
-            DebugTrace(-1, Dbg, "FatAllocateDiskSpace -> (VOID)\n", 0);
-
-        } _SEH2_END; // finally
-    }
-
-    return;
-}
-
-
-VOID
-FatDeallocateDiskSpace (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN PLARGE_MCB Mcb
-    )
-
-/*++
-
-Routine Description:
-
-    This procedure deallocates the disk space denoted by an input
-    mcb.  Note that the input MCB does not need to necessarily describe
-    a chain that ends with a FAT_CLUSTER_LAST entry.
-
-    Pictorially what is done is the following
-
-        Fat |--a--|--b--|--c--|
-        Mcb |--a--|--b--|--c--|
-
-    becomes
-
-        Fat |--0--|--0--|--0--|
-        Mcb |--a--|--b--|--c--|
-
-Arguments:
-
-    Vcb - Supplies the VCB being modified
-
-    Mcb - Supplies the MCB describing the disk space to deallocate.  Note
-          that Mcb is unchanged by this procedure.
-
-
-Return Value:
-
-    None.
-
---*/
-
-{
-    LBO Lbo;
-    VBO Vbo;
-
-    ULONG RunsInMcb;
-    ULONG ByteCount;
-    ULONG ClusterCount;
-    ULONG ClusterIndex;
-    ULONG McbIndex;
-
-    UCHAR LogOfBytesPerCluster;
-
-    PFAT_WINDOW Window;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatDeallocateDiskSpace\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb = %8lx\n", Vcb);
-    DebugTrace( 0, Dbg, "  Mcb = %8lx\n", Mcb);
-
-    LogOfBytesPerCluster = Vcb->AllocationSupport.LogOfBytesPerCluster;
-
-    RunsInMcb = FsRtlNumberOfRunsInLargeMcb( Mcb );
-
-    if ( RunsInMcb == 0 ) {
-
-        DebugTrace(-1, Dbg, "FatDeallocateDiskSpace -> (VOID)\n", 0);
-        return;
-    }
-
-    _SEH2_TRY {
-
-        //
-        //  Run though the Mcb, freeing all the runs in the fat.
-        //
-        //  We do this in two steps (first update the fat, then the bitmap
-        //  (which can't fail)) to prevent other people from taking clusters
-        //  that we need to re-allocate in the event of unwind.
-        //
-
-        ExAcquireResourceSharedLite(&Vcb->ChangeBitMapResource, TRUE);
-
-        RunsInMcb = FsRtlNumberOfRunsInLargeMcb( Mcb );
-
-        for ( McbIndex = 0; McbIndex < RunsInMcb; McbIndex++ ) {
-
-            FatGetNextMcbEntry( Vcb, Mcb, McbIndex, &Vbo, &Lbo, &ByteCount );
-
-            //
-            //  Assert that Fat files have no holes.
-            //
-
-            ASSERT( Lbo != 0 );
-
-            //
-            //  Write FAT_CLUSTER_AVAILABLE to each cluster in the run.
-            //
-
-            ClusterCount = ByteCount >> LogOfBytesPerCluster;
-            ClusterIndex = FatGetIndexFromLbo( Vcb, Lbo );
-
-            FatFreeClusters( IrpContext, Vcb, ClusterIndex, ClusterCount );
-        }
-
-        //
-        //  From now on, nothing can go wrong .... (as in raise)
-        //
-
-        FatLockFreeClusterBitMap( Vcb );
-
-        for ( McbIndex = 0; McbIndex < RunsInMcb; McbIndex++ ) {
-
-            ULONG ClusterEnd;
-            ULONG MyStart, MyLength, count;
-#if DBG
-#ifndef __REACTOS__
-            ULONG PreviousClear, i;
-#else
-            ULONG i;
-#endif
-#endif
-
-            FatGetNextMcbEntry( Vcb, Mcb, McbIndex, &Vbo, &Lbo, &ByteCount );
-
-            //
-            //  Mark the bits clear in the FreeClusterBitMap.
-            //
-
-            ClusterCount = ByteCount >> LogOfBytesPerCluster;
-            ClusterIndex = FatGetIndexFromLbo( Vcb, Lbo );
-
-            Window = Vcb->CurrentWindow;
-
-            //
-            //  If we've divided the bitmap, elide bitmap manipulation for
-            //  runs that are outside the current bucket.
-            //
-
-            ClusterEnd = ClusterIndex + ClusterCount - 1;
-
-            if (!(ClusterIndex > Window->LastCluster ||
-                  ClusterEnd  < Window->FirstCluster)) {
-
-                //
-                //  The run being freed overlaps the current bucket, so we'll
-                //  have to clear some bits.
-                //
-
-                if (ClusterIndex < Window->FirstCluster &&
-                    ClusterEnd > Window->LastCluster) {
-
-                    MyStart = Window->FirstCluster;
-                    MyLength = Window->LastCluster - Window->FirstCluster + 1;
-
-                } else if (ClusterIndex < Window->FirstCluster) {
-
-                    MyStart = Window->FirstCluster;
-                    MyLength = ClusterEnd - Window->FirstCluster + 1;
-
-                } else {
-
-                    //
-                    //  The range being freed starts in the bucket, and may possibly
-                    //  extend beyond the bucket.
-                    //
-
-                    MyStart = ClusterIndex;
-
-                    if (ClusterEnd <= Window->LastCluster) {
-
-                        MyLength = ClusterCount;
-
-                    } else {
-
-                        MyLength = Window->LastCluster - ClusterIndex + 1;
-                    }
-                }
-
-                if (MyLength == 0) {
-
-                    continue;
-                }
-
-#if DBG
-#ifndef __REACTOS__
-                PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
-#endif
-
-
-                //
-                //  Verify that the Bits are all really set.
-                //
-
-                ASSERT( MyStart + MyLength - Window->FirstCluster <= Vcb->FreeClusterBitMap.SizeOfBitMap );
-
-                for (i = 0; i < MyLength; i++) {
-
-                    ASSERT( RtlCheckBit(&Vcb->FreeClusterBitMap,
-                            MyStart - Window->FirstCluster + i) == 1 );
-                }
-#endif // DBG
-
-                FatUnreserveClusters( IrpContext, Vcb,
-                                      MyStart - Window->FirstCluster + 2,
-                                      MyLength );
-            }
-
-            //
-            //  Adjust the ClustersFree count for each bitmap window, even the ones
-            //  that are not the current window.
-            //
-
-            if (FatIsFat32(Vcb)) {
-
-                Window = &Vcb->Windows[FatWindowOfCluster( ClusterIndex )];
-
-            } else {
-
-                Window = &Vcb->Windows[0];
-            }
-
-            MyStart = ClusterIndex;
-
-            for (MyLength = ClusterCount; MyLength > 0; MyLength -= count) {
-
-                count = FatMin(Window->LastCluster - MyStart + 1, MyLength);
-                Window->ClustersFree += count;
-
-                //
-                //  If this was not the last window this allocation spanned,
-                //  advance to the next.
-                //
-
-                if (MyLength != count) {
-
-                    Window++;
-                    MyStart = Window->FirstCluster;
-                }
-            }
-
-            //
-            //  Deallocation is now complete.  Adjust the free cluster count.
-            //
-
-            Vcb->AllocationSupport.NumberOfFreeClusters += ClusterCount;
-        }
-
-#if DBG
-        if (Vcb->CurrentWindow->ClustersFree !=
-               RtlNumberOfClearBits(&Vcb->FreeClusterBitMap)) {
-
-            DbgPrint("%x vs %x\n",  Vcb->CurrentWindow->ClustersFree,
-                RtlNumberOfClearBits(&Vcb->FreeClusterBitMap));
-
-            DbgPrint("%x for %x\n", ClusterIndex, ClusterCount);
-        }
-#endif
-
-        FatUnlockFreeClusterBitMap( Vcb );
-
-
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatDeallocateDiskSpace );
-
-        //
-        //  Is there any unwinding to do?
-        //
-
-        ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
-
-        if ( _SEH2_AbnormalTermination() ) {
-
-            LBO Lbo;
-            VBO Vbo;
-
-            ULONG Index;
-            ULONG Clusters;
-            ULONG FatIndex;
-            ULONG PriorLastIndex;
-
-            //
-            //  For each entry we already deallocated, reallocate it,
-            //  chaining together as nessecary.  Note that we continue
-            //  up to and including the last "for" iteration even though
-            //  the SetFatRun could not have been successful.  This
-            //  allows us a convienent way to re-link the final successful
-            //  SetFatRun.
-            //
-            //  It is possible that the reason we got here will prevent us
-            //  from succeeding in this operation.
-            //
-
-            PriorLastIndex = 0;
-
-            for (Index = 0; Index <= McbIndex; Index++) {
-
-                FatGetNextMcbEntry(Vcb, Mcb, Index, &Vbo, &Lbo, &ByteCount);
-
-                FatIndex = FatGetIndexFromLbo( Vcb, Lbo );
-                Clusters = ByteCount >> LogOfBytesPerCluster;
-
-                //
-                //  We must always restore the prior iteration's last
-                //  entry, pointing it to the first cluster of this run.
-                //
-
-                if (PriorLastIndex != 0) {
-
-                    FatSetFatEntry( IrpContext,
-                                    Vcb,
-                                    PriorLastIndex,
-                                    (FAT_ENTRY)FatIndex );
-                }
-
-                //
-                //  If this is not the last entry (the one that failed)
-                //  then reallocate the disk space on the fat.
-                //
-
-                if ( Index < McbIndex ) {
-
-                    FatAllocateClusters(IrpContext, Vcb, FatIndex, Clusters);
-
-                    PriorLastIndex = FatIndex + Clusters - 1;
-                }
-            }
-        }
-
-        DebugTrace(-1, Dbg, "FatDeallocateDiskSpace -> (VOID)\n", 0);
-    } _SEH2_END;
-
-    return;
-}
-
-
-VOID
-FatSplitAllocation (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN OUT PLARGE_MCB Mcb,
-    IN VBO SplitAtVbo,
-    OUT PLARGE_MCB RemainingMcb
-    )
-
-/*++
-
-Routine Description:
-
-    This procedure takes a single mcb and splits its allocation into
-    two separate allocation units.  The separation must only be done
-    on cluster boundaries, otherwise we bugcheck.
-
-    On the disk this actually works by inserting a FAT_CLUSTER_LAST into
-    the last index of the first part being split out.
-
-    Pictorially what is done is the following (where ! denotes the end of
-    the fat chain (i.e., FAT_CLUSTER_LAST)):
-
-
-        Mcb          |--a--|--b--|--c--|--d--|--e--|--f--|
-
-                                        ^
-        SplitAtVbo ---------------------+
-
-        RemainingMcb (empty)
-
-    becomes
-
-        Mcb          |--a--|--b--|--c--!
-
-
-        RemainingMcb |--d--|--e--|--f--|
-
-Arguments:
-
-    Vcb - Supplies the VCB being modified
-
-    Mcb - Supplies the MCB describing the allocation being split into
-          two parts.  Upon return this Mcb now contains the first chain.
-
-    SplitAtVbo - Supplies the VBO of the first byte for the second chain
-                 that we creating.
-
-    RemainingMcb - Receives the MCB describing the second chain of allocated
-                   disk space.  The caller passes in an initialized Mcb that
-                   is filled in by this procedure STARTING AT VBO 0.
-
-Return Value:
-
-    VOID - TRUE if the operation completed and FALSE if it had to
-               block but could not.
-
---*/
-
-{
-    VBO SourceVbo;
-    VBO TargetVbo;
-    VBO DontCare;
-
-    LBO Lbo;
-
-    ULONG ByteCount;
-    ULONG BytesPerCluster;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatSplitAllocation\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb          = %8lx\n", Vcb);
-    DebugTrace( 0, Dbg, "  Mcb          = %8lx\n", Mcb);
-    DebugTrace( 0, Dbg, "  SplitAtVbo   = %8lx\n", SplitAtVbo);
-    DebugTrace( 0, Dbg, "  RemainingMcb = %8lx\n", RemainingMcb);
-
-    BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
-
-    //
-    //  Assert that the split point is cluster alligned
-    //
-
-    ASSERT( (SplitAtVbo & (BytesPerCluster - 1)) == 0 );
-
-    //
-    //  We should never be handed an empty source MCB and asked to split
-    //  at a non zero point.
-    //
-
-    ASSERT( !((0 != SplitAtVbo) && (0 == FsRtlNumberOfRunsInLargeMcb( Mcb))));
-
-    //
-    //  Assert we were given an empty target Mcb.
-    //
-
-    //
-    //  This assert is commented out to avoid hitting in the Ea error
-    //  path.  In that case we will be using the same Mcb's to split the
-    //  allocation that we used to merge them.  The target Mcb will contain
-    //  the runs that the split will attempt to insert.
-    //
-    //
-    //  ASSERT( FsRtlNumberOfRunsInMcb( RemainingMcb ) == 0 );
-    //
-
-    _SEH2_TRY {
-
-        //
-        //  Move the runs after SplitAtVbo from the souce to the target
-        //
-
-        SourceVbo = SplitAtVbo;
-        TargetVbo = 0;
-
-        while (FatLookupMcbEntry(Vcb, Mcb, SourceVbo, &Lbo, &ByteCount, NULL)) {
-
-            FatAddMcbEntry( Vcb, RemainingMcb, TargetVbo, Lbo, ByteCount );
-
-            FatRemoveMcbEntry( Vcb, Mcb, SourceVbo, ByteCount );
-
-            TargetVbo += ByteCount;
-            SourceVbo += ByteCount;
-
-            //
-            //  If SourceVbo overflows, we were actually snipping off the end
-            //  of the maximal file ... and are now done.
-            //
-
-            if (SourceVbo == 0) {
-
-                break;
-            }
-        }
-
-        //
-        //  Mark the last pre-split cluster as a FAT_LAST_CLUSTER
-        //
-
-        if ( SplitAtVbo != 0 ) {
-
-            FatLookupLastMcbEntry( Vcb, Mcb, &DontCare, &Lbo, NULL );
-
-            FatSetFatEntry( IrpContext,
-                            Vcb,
-                            FatGetIndexFromLbo( Vcb, Lbo ),
-                            FAT_CLUSTER_LAST );
-        }
-
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatSplitAllocation );
-
-        //
-        //  If we got an exception, we must glue back together the Mcbs
-        //
-
-        if ( _SEH2_AbnormalTermination() ) {
-
-            TargetVbo = SplitAtVbo;
-            SourceVbo = 0;
-
-            while (FatLookupMcbEntry(Vcb, RemainingMcb, SourceVbo, &Lbo, &ByteCount, NULL)) {
-
-                FatAddMcbEntry( Vcb, Mcb, TargetVbo, Lbo, ByteCount );
-
-                FatRemoveMcbEntry( Vcb, RemainingMcb, SourceVbo, ByteCount );
-
-                TargetVbo += ByteCount;
-                SourceVbo += ByteCount;
-            }
-        }
-
-        DebugTrace(-1, Dbg, "FatSplitAllocation -> (VOID)\n", 0);
-    } _SEH2_END;
-
-    return;
-}
-
-
-VOID
-FatMergeAllocation (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN OUT PLARGE_MCB Mcb,
-    IN PLARGE_MCB SecondMcb
-    )
-
-/*++
-
-Routine Description:
-
-    This routine takes two separate allocations described by two MCBs and
-    joins them together into one allocation.
-
-    Pictorially what is done is the following (where ! denotes the end of
-    the fat chain (i.e., FAT_CLUSTER_LAST)):
-
-
-        Mcb       |--a--|--b--|--c--!
-
-        SecondMcb |--d--|--e--|--f--|
-
-    becomes
-
-        Mcb       |--a--|--b--|--c--|--d--|--e--|--f--|
-
-        SecondMcb |--d--|--e--|--f--|
-
-
-Arguments:
-
-    Vcb - Supplies the VCB being modified
-
-    Mcb - Supplies the MCB of the first allocation that is being modified.
-          Upon return this Mcb will also describe the newly enlarged
-          allocation
-
-    SecondMcb - Supplies the ZERO VBO BASED MCB of the second allocation
-                that is being appended to the first allocation.  This
-                procedure leaves SecondMcb unchanged.
-
-Return Value:
-
-    VOID - TRUE if the operation completed and FALSE if it had to
-        block but could not.
-
---*/
-
-{
-    VBO SpliceVbo;
-    LBO SpliceLbo;
-
-    VBO SourceVbo;
-    VBO TargetVbo;
-
-    LBO Lbo;
-
-    ULONG ByteCount;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatMergeAllocation\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb       = %8lx\n", Vcb);
-    DebugTrace( 0, Dbg, "  Mcb       = %8lx\n", Mcb);
-    DebugTrace( 0, Dbg, "  SecondMcb = %8lx\n", SecondMcb);
-
-    _SEH2_TRY {
-
-        //
-        //  Append the runs from SecondMcb to Mcb
-        //
-
-        (void)FatLookupLastMcbEntry( Vcb, Mcb, &SpliceVbo, &SpliceLbo, NULL );
-
-        SourceVbo = 0;
-        TargetVbo = SpliceVbo + 1;
-
-        while (FatLookupMcbEntry(Vcb, SecondMcb, SourceVbo, &Lbo, &ByteCount, NULL)) {
-
-            FatAddMcbEntry( Vcb, Mcb, TargetVbo, Lbo, ByteCount );
-
-            SourceVbo += ByteCount;
-            TargetVbo += ByteCount;
-        }
-
-        //
-        //  Link the last pre-merge cluster to the first cluster of SecondMcb
-        //
-
-        FatLookupMcbEntry( Vcb, SecondMcb, 0, &Lbo, (PULONG)NULL, NULL );
-
-        FatSetFatEntry( IrpContext,
-                        Vcb,
-                        FatGetIndexFromLbo( Vcb, SpliceLbo ),
-                        (FAT_ENTRY)FatGetIndexFromLbo( Vcb, Lbo ) );
-
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatMergeAllocation );
-
-        //
-        //  If we got an exception, we must remove the runs added to Mcb
-        //
-
-        if ( _SEH2_AbnormalTermination() ) {
-
-            ULONG CutLength;
-
-            if ((CutLength = TargetVbo - (SpliceVbo + 1)) != 0) {
-
-                FatRemoveMcbEntry( Vcb, Mcb, SpliceVbo + 1, CutLength);
-            }
-        }
-
-        DebugTrace(-1, Dbg, "FatMergeAllocation -> (VOID)\n", 0);
-    } _SEH2_END;
-
-    return;
-}
-
-
-//
-//  Internal support routine
-//
-
-CLUSTER_TYPE
-FatInterpretClusterType (
-    IN PVCB Vcb,
-    IN FAT_ENTRY Entry
-    )
-
-/*++
-
-Routine Description:
-
-    This procedure tells the caller how to interpret the input fat table
-    entry.  It will indicate if the fat cluster is available, resereved,
-    bad, the last one, or the another fat index.  This procedure can deal
-    with both 12 and 16 bit fat.
-
-Arguments:
-
-    Vcb - Supplies the Vcb to examine, yields 12/16 bit info
-
-    Entry - Supplies the fat entry to examine
-
-Return Value:
-
-    CLUSTER_TYPE - Is the type of the input Fat entry
-
---*/
-
-{
-    DebugTrace(+1, Dbg, "InterpretClusterType\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb   = %8lx\n", Vcb);
-    DebugTrace( 0, Dbg, "  Entry = %8lx\n", Entry);
-
-    PAGED_CODE();
-
-    switch(Vcb->AllocationSupport.FatIndexBitSize ) {
-    case 32:
-        Entry &= FAT32_ENTRY_MASK;
-        break;
-
-    case 12:
-        ASSERT( Entry <= 0xfff );
-        if (Entry >= 0x0ff0) {
-            Entry |= 0x0FFFF000;
-        }
-        break;
-
-    default:
-    case 16:
-        ASSERT( Entry <= 0xffff );
-        if (Entry >= 0x0fff0) {
-            Entry |= 0x0FFF0000;
-        }
-        break;
-    }
-
-    if (Entry == FAT_CLUSTER_AVAILABLE) {
-
-        DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterAvailable\n", 0);
-
-        return FatClusterAvailable;
-
-    } else if (Entry < FAT_CLUSTER_RESERVED) {
-
-        DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterNext\n", 0);
-
-        return FatClusterNext;
-
-    } else if (Entry < FAT_CLUSTER_BAD) {
-
-        DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterReserved\n", 0);
-
-        return FatClusterReserved;
-
-    } else if (Entry == FAT_CLUSTER_BAD) {
-
-        DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterBad\n", 0);
-
-        return FatClusterBad;
-
-    } else {
-
-        DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterLast\n", 0);
-
-        return FatClusterLast;
-    }
-}
-
-
-//
-//  Internal support routine
-//
-
-VOID
-FatLookupFatEntry (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN ULONG FatIndex,
-    IN OUT PULONG FatEntry,
-    IN OUT PFAT_ENUMERATION_CONTEXT Context
-    )
-
-/*++
-
-Routine Description:
-
-    This routine takes an index into the fat and gives back the value
-    in the Fat at this index.  At any given time, for a 16 bit fat, this
-    routine allows only one page per volume of the fat to be pinned in
-    memory.  For a 12 bit bit fat, the entire fat (max 6k) is pinned.  This
-    extra layer of caching makes the vast majority of requests very
-    fast.  The context for this caching stored in a structure in the Vcb.
-
-Arguments:
-
-    Vcb - Supplies the Vcb to examine, yields 12/16 bit info,
-          fat access context, etc.
-
-    FatIndex - Supplies the fat index to examine.
-
-    FatEntry - Receives the fat entry pointed to by FatIndex.  Note that
-               it must point to non-paged pool.
-
-    Context - This structure keeps track of a page of pinned fat between calls.
-
---*/
-
-{
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatLookupFatEntry\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb      = %8lx\n", Vcb);
-    DebugTrace( 0, Dbg, "  FatIndex = %4x\n", FatIndex);
-    DebugTrace( 0, Dbg, "  FatEntry = %8lx\n", FatEntry);
-
-    //
-    //  Make sure they gave us a valid fat index.
-    //
-
-    FatVerifyIndexIsValid(IrpContext, Vcb, FatIndex);
-
-    //
-    //  Case on 12 or 16 bit fats.
-    //
-    //  In the 12 bit case (mostly floppies) we always have the whole fat
-    //  (max 6k bytes) pinned during allocation operations.  This is possibly
-    //  a wee bit slower, but saves headaches over fat entries with 8 bits
-    //  on one page, and 4 bits on the next.
-    //
-    //  The 16 bit case always keeps the last used page pinned until all
-    //  operations are done and it is unpinned.
-    //
-
-    //
-    //  DEAL WITH 12 BIT CASE
-    //
-
-    if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
-
-        //
-        //  Check to see if the fat is already pinned, otherwise pin it.
-        //
-
-        if (Context->Bcb == NULL) {
-
-            FatReadVolumeFile( IrpContext,
-                               Vcb,
-                               FatReservedBytes( &Vcb->Bpb ),
-                               FatBytesPerFat( &Vcb->Bpb ),
-                               &Context->Bcb,
-                               &Context->PinnedPage );
-        }
-
-        //
-        //  Load the return value.
-        //
-
-
-        FatLookup12BitEntry( Context->PinnedPage, FatIndex, FatEntry );
-
-    } else if (Vcb->AllocationSupport.FatIndexBitSize == 32) {
-
-        //
-        //  DEAL WITH 32 BIT CASE
-        //
-
-        ULONG PageEntryOffset;
-        ULONG OffsetIntoVolumeFile;
-
-        //
-        //  Initialize two local variables that help us.
-        //
-        OffsetIntoVolumeFile = FatReservedBytes(&Vcb->Bpb) + FatIndex * sizeof(FAT_ENTRY);
-        PageEntryOffset = (OffsetIntoVolumeFile % PAGE_SIZE) / sizeof(FAT_ENTRY);
-
-        //
-        //  Check to see if we need to read in a new page of fat
-        //
-
-        if ((Context->Bcb == NULL) ||
-            (OffsetIntoVolumeFile / PAGE_SIZE != Context->VboOfPinnedPage / PAGE_SIZE)) {
-
-            //
-            //  The entry wasn't in the pinned page, so must we unpin the current
-            //  page (if any) and read in a new page.
-            //
-
-            FatUnpinBcb( IrpContext, Context->Bcb );
-
-            FatReadVolumeFile( IrpContext,
-                               Vcb,
-                               OffsetIntoVolumeFile & ~(PAGE_SIZE - 1),
-                               PAGE_SIZE,
-                               &Context->Bcb,
-                               &Context->PinnedPage );
-
-            Context->VboOfPinnedPage = OffsetIntoVolumeFile & ~(PAGE_SIZE - 1);
-        }
-
-        //
-        //  Grab the fat entry from the pinned page, and return
-        //
-
-        *FatEntry = ((PULONG)(Context->PinnedPage))[PageEntryOffset] & FAT32_ENTRY_MASK;
-
-    } else {
-
-        //
-        //  DEAL WITH 16 BIT CASE
-        //
-
-        ULONG PageEntryOffset;
-        ULONG OffsetIntoVolumeFile;
-
-        //
-        //  Initialize two local variables that help us.
-        //
-
-        OffsetIntoVolumeFile = FatReservedBytes(&Vcb->Bpb) + FatIndex * sizeof(USHORT);
-        PageEntryOffset = (OffsetIntoVolumeFile % PAGE_SIZE) / sizeof(USHORT);
-
-        //
-        //  Check to see if we need to read in a new page of fat
-        //
-
-        if ((Context->Bcb == NULL) ||
-            (OffsetIntoVolumeFile / PAGE_SIZE != Context->VboOfPinnedPage / PAGE_SIZE)) {
-
-            //
-            //  The entry wasn't in the pinned page, so must we unpin the current
-            //  page (if any) and read in a new page.
-            //
-
-            FatUnpinBcb( IrpContext, Context->Bcb );
-
-            FatReadVolumeFile( IrpContext,
-                               Vcb,
-                               OffsetIntoVolumeFile & ~(PAGE_SIZE - 1),
-                               PAGE_SIZE,
-                               &Context->Bcb,
-                               &Context->PinnedPage );
-
-            Context->VboOfPinnedPage = OffsetIntoVolumeFile & ~(PAGE_SIZE - 1);
-        }
-
-        //
-        //  Grab the fat entry from the pinned page, and return
-        //
-
-        *FatEntry = ((PUSHORT)(Context->PinnedPage))[PageEntryOffset];
-    }
-
-    DebugTrace(-1, Dbg, "FatLookupFatEntry -> (VOID)\n", 0);
-    return;
-}
-
-
-VOID
-FatSetFatEntry (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN ULONG FatIndex,
-    IN FAT_ENTRY FatEntry
-    )
-
-/*++
-
-Routine Description:
-
-    This routine takes an index into the fat and puts a value in the Fat
-    at this index.  The routine special cases 12, 16 and 32 bit fats.  In
-    all cases we go to the cache manager for a piece of the fat.
-
-    We have a special form of this call for setting the DOS-style dirty bit.
-    Unlike the dirty bit in the boot sector, we do not go to special effort
-    to make sure that this hits the disk synchronously - if the system goes
-    down in the window between the dirty bit being set in the boot sector
-    and the FAT index zero dirty bit being lazy written, then life is tough.
-
-    The only possible scenario is that Win9x may see what it thinks is a clean
-    volume that really isn't (hopefully Memphis will pay attention to our dirty
-    bit as well). The dirty bit will get out quickly, and if heavy activity is
-    occurring, then the dirty bit should actually be there virtually all of the
-    time since the act of cleaning the volume is the "rare" occurance.
-
-    There are synchronization concerns that would crop up if we tried to make
-    this synchronous. This thread may already own the Bcb shared for the first
-    sector of the FAT (so we can't get it exclusive for a writethrough). This
-    would require some more serious replumbing to work around than I want to
-    consider at this time.
-
-    We can and do, however, synchronously set the bit clean.
-
-    At this point the reader should understand why the NT dirty bit is where it is.
-
-Arguments:
-
-    Vcb - Supplies the Vcb to examine, yields 12/16/32 bit info, etc.
-
-    FatIndex - Supplies the destination fat index.
-
-    FatEntry - Supplies the source fat entry.
-
---*/
-
-{
-    LBO Lbo;
-    PBCB Bcb = NULL;
-    ULONG SectorSize;
-    ULONG OffsetIntoVolumeFile;
-    ULONG WasWait = TRUE;
-    BOOLEAN RegularOperation = TRUE;
-    BOOLEAN CleaningOperation = FALSE;
-    BOOLEAN ReleaseMutex = FALSE;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatSetFatEntry\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb      = %8lx\n", Vcb);
-    DebugTrace( 0, Dbg, "  FatIndex = %4x\n", FatIndex);
-    DebugTrace( 0, Dbg, "  FatEntry = %4x\n", FatEntry);
-
-    //
-    //  Make sure they gave us a valid fat index if this isn't the special
-    //  clean-bit modifying call.
-    //
-
-    if (FatIndex == FAT_DIRTY_BIT_INDEX) {
-
-        //
-        //  We are setting the clean bit state.  Of course, we could
-        //  have corruption that would cause us to try to fiddle the
-        //  reserved index - we guard against this by having the
-        //  special entry values use the reserved high 4 bits that
-        //  we know that we'll never try to set.
-        //
-
-        //
-        //  We don't want to repin the FAT pages involved here.  Just
-        //  let the lazy writer hit them when it can.
-        //
-
-        RegularOperation = FALSE;
-
-        switch (FatEntry) {
-            case FAT_CLEAN_VOLUME:
-                FatEntry = FAT_CLEAN_ENTRY;
-                CleaningOperation = TRUE;
-                break;
-
-            case FAT_DIRTY_VOLUME:
-                switch (Vcb->AllocationSupport.FatIndexBitSize) {
-                    case 12:
-                        FatEntry = FAT12_DIRTY_ENTRY;
-                        break;
-
-                    case 32:
-                        FatEntry = FAT32_DIRTY_ENTRY;
-                        break;
-
-                    default:
-                        FatEntry = FAT16_DIRTY_ENTRY;
-                        break;
-                }
-                break;
-
-            default:
-                FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
-                break;
-        }
-
-        //
-        //  Disable dirtying semantics for the duration of this operation.  Force this
-        //  operation to wait for the duration.
-        //
-
-        WasWait = FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
-        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT | IRP_CONTEXT_FLAG_DISABLE_DIRTY );
-
-    } else {
-
-        ASSERT( !(FatEntry & ~FAT32_ENTRY_MASK) );
-        FatVerifyIndexIsValid(IrpContext, Vcb, FatIndex);
-    }
-
-    //
-    //  Set Sector Size
-    //
-
-    SectorSize = 1 << Vcb->AllocationSupport.LogOfBytesPerSector;
-
-    //
-    //  Case on 12 or 16 bit fats.
-    //
-    //  In the 12 bit case (mostly floppies) we always have the whole fat
-    //  (max 6k bytes) pinned during allocation operations.  This is possibly
-    //  a wee bit slower, but saves headaches over fat entries with 8 bits
-    //  on one page, and 4 bits on the next.
-    //
-    //  In the 16 bit case we only read the page that we need to set the fat
-    //  entry.
-    //
-
-    //
-    //  DEAL WITH 12 BIT CASE
-    //
-
-    _SEH2_TRY {
-
-        if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
-
-            PVOID PinnedFat;
-
-            //
-            //  Make sure we have a valid entry
-            //
-
-            FatEntry &= 0xfff;
-
-            //
-            //  We read in the entire fat.  Note that using prepare write marks
-            //  the bcb pre-dirty, so we don't have to do it explicitly.
-            //
-
-            OffsetIntoVolumeFile = FatReservedBytes( &Vcb->Bpb ) + FatIndex * 3 / 2;
-
-            FatPrepareWriteVolumeFile( IrpContext,
-                                       Vcb,
-                                       FatReservedBytes( &Vcb->Bpb ),
-                                       FatBytesPerFat( &Vcb->Bpb ),
-                                       &Bcb,
-                                       &PinnedFat,
-                                       RegularOperation,
-                                       FALSE );
-
-            //
-            //  Mark the sector(s) dirty in the DirtyFatMcb.  This call is
-            //  complicated somewhat for the 12 bit case since a single
-            //  entry write can span two sectors (and pages).
-            //
-            //  Get the Lbo for the sector where the entry starts, and add it to
-            //  the dirty fat Mcb.
-            //
-
-            Lbo = OffsetIntoVolumeFile & ~(SectorSize - 1);
-
-            FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize);
-
-            //
-            //  If the entry started on the last byte of the sector, it continues
-            //  to the next sector, so mark the next sector dirty as well.
-            //
-            //  Note that this entry will simply coalese with the last entry,
-            //  so this operation cannot fail.  Also if we get this far, we have
-            //  made it, so no unwinding will be needed.
-            //
-
-            if ( (OffsetIntoVolumeFile & (SectorSize - 1)) == (SectorSize - 1) ) {
-
-                Lbo += SectorSize;
-
-                FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize );
-            }
-
-            //
-            //  Store the entry into the fat; we need a little synchonization
-            //  here and can't use a spinlock since the bytes might not be
-            //  resident.
-            //
-
-            FatLockFreeClusterBitMap( Vcb );
-            ReleaseMutex = TRUE;
-
-            FatSet12BitEntry( PinnedFat, FatIndex, FatEntry );
-
-            FatUnlockFreeClusterBitMap( Vcb );
-            ReleaseMutex = FALSE;
-
-        } else if (Vcb->AllocationSupport.FatIndexBitSize == 32) {
-
-            //
-            //  DEAL WITH 32 BIT CASE
-            //
-
-            PULONG PinnedFatEntry32;
-
-            //
-            //  Read in a new page of fat
-            //
-
-            OffsetIntoVolumeFile = FatReservedBytes( &Vcb->Bpb ) +
-                                   FatIndex * sizeof( FAT_ENTRY );
-
-            FatPrepareWriteVolumeFile( IrpContext,
-                                       Vcb,
-                                       OffsetIntoVolumeFile,
-                                       sizeof(FAT_ENTRY),
-                                       &Bcb,
-                                       (PVOID *)&PinnedFatEntry32,
-                                       RegularOperation,
-                                       FALSE );
-            //
-            //  Mark the sector dirty in the DirtyFatMcb
-            //
-
-            Lbo = OffsetIntoVolumeFile & ~(SectorSize - 1);
-
-            FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize);
-
-            //
-            //  Store the FatEntry to the pinned page.
-            //
-            //  Preserve the reserved bits in FAT32 entries in the file heap.
-            //
-
-#ifdef ALPHA
-            FatLockFreeClusterBitMap( Vcb );
-            ReleaseMutex = TRUE;
-#endif // ALPHA
-
-            if (FatIndex != FAT_DIRTY_BIT_INDEX) {
-
-                *PinnedFatEntry32 = ((*PinnedFatEntry32 & ~FAT32_ENTRY_MASK) | FatEntry);
-
-            } else {
-
-                *PinnedFatEntry32 = FatEntry;
-            }
-
-#ifdef ALPHA
-            FatUnlockFreeClusterBitMap( Vcb );
-            ReleaseMutex = FALSE;
-#endif // ALPHA
-
-        } else {
-
-            //
-            //  DEAL WITH 16 BIT CASE
-            //
-
-            PUSHORT PinnedFatEntry;
-
-            //
-            //  Read in a new page of fat
-            //
-
-            OffsetIntoVolumeFile = FatReservedBytes( &Vcb->Bpb ) +
-                                   FatIndex * sizeof(USHORT);
-
-            FatPrepareWriteVolumeFile( IrpContext,
-                                       Vcb,
-                                       OffsetIntoVolumeFile,
-                                       sizeof(USHORT),
-                                       &Bcb,
-                                       (PVOID *)&PinnedFatEntry,
-                                       RegularOperation,
-                                       FALSE );
-            //
-            //  Mark the sector dirty in the DirtyFatMcb
-            //
-
-            Lbo = OffsetIntoVolumeFile & ~(SectorSize - 1);
-
-            FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize);
-
-            //
-            //  Store the FatEntry to the pinned page.
-            //
-            //  We need extra synchronization here for broken architectures
-            //  like the ALPHA that don't support atomic 16 bit writes.
-            //
-
-#ifdef ALPHA
-            FatLockFreeClusterBitMap( Vcb );
-            ReleaseMutex = TRUE;
-#endif // ALPHA
-
-            *PinnedFatEntry = (USHORT)FatEntry;
-
-#ifdef ALPHA
-            FatUnlockFreeClusterBitMap( Vcb );
-            ReleaseMutex = FALSE;
-#endif // ALPHA
-        }
-
-    } _SEH2_FINALLY {
-
-        DebugUnwind( FatSetFatEntry );
-
-        //
-        //  Re-enable volume dirtying in case this was a dirty bit operation.
-        //
-
-        ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_DIRTY );
-
-        //
-        //  Make this operation asynchronous again if needed.
-        //
-
-        if (!WasWait) {
-
-            ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
-        }
-
-        //
-        //  If we still somehow have the Mutex, release it.
-        //
-
-        if (ReleaseMutex) {
-
-            ASSERT( _SEH2_AbnormalTermination() );
-
-            FatUnlockFreeClusterBitMap( Vcb );
-        }
-
-        //
-        //  Unpin the Bcb.  For cleaning operations, we make this write-through.
-        //
-
-        if (CleaningOperation && Bcb) {
-
-            IO_STATUS_BLOCK IgnoreStatus;
-
-            CcRepinBcb( Bcb );
-            CcUnpinData( Bcb );
-            DbgDoit( IrpContext->PinCount -= 1 );
-            CcUnpinRepinnedBcb( Bcb, TRUE, &IgnoreStatus );
-
-        } else {
-
-            FatUnpinBcb(IrpContext, Bcb);
-        }
-
-        DebugTrace(-1, Dbg, "FatSetFatEntry -> (VOID)\n", 0);
-    } _SEH2_END;
-
-    return;
-}
-
-
-//
-//  Internal support routine
-//
-
-VOID
-FatSetFatRun (
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN ULONG StartingFatIndex,
-    IN ULONG ClusterCount,
-    IN BOOLEAN ChainTogether
-    )
-
-/*++
-
-Routine Description:
-
-    This routine sets a continuous run of clusters in the fat.  If ChainTogether
-    is TRUE, then the clusters are linked together as in normal Fat fasion,
-    with the last cluster receiving FAT_CLUSTER_LAST.  If ChainTogether is
-    FALSE, all the entries are set to FAT_CLUSTER_AVAILABLE, effectively
-    freeing all the clusters in the run.
-
-Arguments:
-
-    Vcb - Supplies the Vcb to examine, yields 12/16 bit info, etc.
-
-    StartingFatIndex - Supplies the destination fat index.
-
-    ClusterCount - Supplies the number of contiguous clusters to work on.
-
-    ChainTogether - Tells us whether to fill the entries with links, or
-                    FAT_CLUSTER_AVAILABLE
-
-
-Return Value:
-
-    VOID
-
---*/
-
-{
-#define MAXCOUNTCLUS 0x10000
-#define COUNTSAVEDBCBS ((MAXCOUNTCLUS * sizeof(FAT_ENTRY) / PAGE_SIZE) + 2)
-    PBCB SavedBcbs[COUNTSAVEDBCBS][2];
-
-    ULONG SectorSize;
-    ULONG Cluster;
-
-    LBO StartSectorLbo;
-    LBO FinalSectorLbo;
-    LBO Lbo;
-
-    PVOID PinnedFat;
-
-#ifndef __REACTOS__
-    ULONG StartingPage;
-#endif
-
-    BOOLEAN ReleaseMutex = FALSE;
-
-    ULONG SavedStartingFatIndex = StartingFatIndex;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "FatSetFatRun\n", 0);
-    DebugTrace( 0, Dbg, "  Vcb              = %8lx\n", Vcb);
-    DebugTrace( 0, Dbg, "  StartingFatIndex = %8x\n", StartingFatIndex);
-    DebugTrace( 0, Dbg, "  ClusterCount     = %8lx\n", ClusterCount);
-    DebugTrace( 0, Dbg, "  ChainTogether    = %s\n", ChainTogether ? "TRUE":"FALSE");
-
-    //
-    //  Make sure they gave us a valid fat run.
-    //
-
-    FatVerifyIndexIsValid(IrpContext, Vcb, StartingFatIndex);
-    FatVerifyIndexIsValid(IrpContext, Vcb, StartingFatIndex + ClusterCount - 1);
-
-    //
-    //  Check special case
-    //
-
-    if (ClusterCount == 0) {
-
-        DebugTrace(-1, Dbg, "FatSetFatRun -> (VOID)\n", 0);
-        return;
-    }
-
-    //
-    //  Set Sector Size
-    //
-
-    SectorSize = 1 << Vcb->AllocationSupport.LogOfBytesPerSector;
-
-    //
-    //  Case on 12 or 16 bit fats.
-    //
-    //  In the 12 bit case (mostly floppies) we always have the whole fat
-    //  (max 6k bytes) pinned during allocation operations.  This is possibly
-    //  a wee bit slower, but saves headaches over fat entries with 8 bits
-    //  on one page, and 4 bits on the next.
-    //
-    //  In the 16 bit case we only read one page at a time, as needed.
-    //
-
-    //
-    //  DEAL WITH 12 BIT CASE
-    //
-
-    _SEH2_TRY {
-
-        if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
-
-#ifndef __REACTOS__
-            StartingPage = 0;
-#endif
-
-            //
-            //  We read in the entire fat.  Note that using prepare write marks
-            //  the bcb pre-dirty, so we don't have to do it explicitly.
-            //
-
-            RtlZeroMemory( &SavedBcbs[0], 2 * sizeof(PBCB) * 2);
-
-            FatPrepareWriteVolumeFile( IrpContext,
-                                       Vcb,
-                                       FatReservedBytes( &Vcb->Bpb ),
-                                       FatBytesPerFat( &Vcb->Bpb ),
-                                       &SavedBcbs[0][0],
-                                       &PinnedFat,
-                                       TRUE,
-                                       FALSE );
-
-            //
-            //  Mark the affected sectors dirty.  Note that FinalSectorLbo is
-            //  the Lbo of the END of the entry (Thus * 3 + 2).  This makes sure
-            //  we catch the case of a dirty fat entry straddling a sector boundry.
-            //
-            //  Note that if the first AddMcbEntry succeeds, all following ones
-            //  will simply coalese, and thus also succeed.
-            //
-
-            StartSectorLbo = (FatReservedBytes( &Vcb->Bpb ) + StartingFatIndex * 3 / 2)
-                             & ~(SectorSize - 1);
-
-            FinalSectorLbo = (FatReservedBytes( &Vcb->Bpb ) + ((StartingFatIndex +
-                             ClusterCount) * 3 + 2) / 2) & ~(SectorSize - 1);
-
-            for (Lbo = StartSectorLbo; Lbo <= FinalSectorLbo; Lbo += SectorSize) {
-
-                FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize );
-            }
-
-            //
-            //  Store the entries into the fat; we need a little
-            //  synchonization here and can't use a spinlock since the bytes
-            //  might not be resident.
-            //
-
-            FatLockFreeClusterBitMap( Vcb );
-            ReleaseMutex = TRUE;
-
-            for (Cluster = StartingFatIndex;
-                 Cluster < StartingFatIndex + ClusterCount - 1;
-                 Cluster++) {
-
-                FatSet12BitEntry( PinnedFat,
-                                  Cluster,
-                                  ChainTogether ? Cluster + 1 : FAT_CLUSTER_AVAILABLE );
-            }
-
-            //
-            //  Save the last entry
-            //
-
-            FatSet12BitEntry( PinnedFat,
-                              Cluster,
-                              ChainTogether ?
-                              FAT_CLUSTER_LAST & 0xfff : FAT_CLUSTER_AVAILABLE );
-
-            FatUnlockFreeClusterBitMap( Vcb );
-            ReleaseMutex = FALSE;
-
-        } else if (Vcb->AllocationSupport.FatIndexBitSize == 32) {
-
-            //
-            //  DEAL WITH 32 BIT CASE
-            //
-
-            for (;;) {
-
-                VBO StartOffsetInVolume;
-                VBO FinalOffsetInVolume;
-
-                ULONG Page;
-                ULONG FinalCluster;
-                PULONG FatEntry;
-                ULONG ClusterCountThisRun;
-
-                StartOffsetInVolume = FatReservedBytes(&Vcb->Bpb) +
-                                            StartingFatIndex * sizeof(FAT_ENTRY);
-
-                if (ClusterCount > MAXCOUNTCLUS) {
-                    ClusterCountThisRun = MAXCOUNTCLUS;
-                } else {
-                    ClusterCountThisRun = ClusterCount;
-                }
-
-                FinalOffsetInVolume = StartOffsetInVolume +
-                                            (ClusterCountThisRun -  1) * sizeof(FAT_ENTRY);
-
-#ifndef __REACTOS__
-                StartingPage = StartOffsetInVolume / PAGE_SIZE;
-#endif
-
-                {
-                    ULONG NumberOfPages;
-                    ULONG Offset;
-
-                    NumberOfPages = (FinalOffsetInVolume / PAGE_SIZE) -
-                                    (StartOffsetInVolume / PAGE_SIZE) + 1;
-
-                    RtlZeroMemory( &SavedBcbs[0][0], (NumberOfPages + 1) * sizeof(PBCB) * 2 );
-
-                    for ( Page = 0, Offset = StartOffsetInVolume & ~(PAGE_SIZE - 1);
-                          Page < NumberOfPages;
-                          Page++, Offset += PAGE_SIZE ) {
-
-                        FatPrepareWriteVolumeFile( IrpContext,
-                                                   Vcb,
-                                                   Offset,
-                                                   PAGE_SIZE,
-                                                   &SavedBcbs[Page][0],
-                                                   (PVOID *)&SavedBcbs[Page][1],
-                                                   TRUE,
-                                                   FALSE );
-
-                        if (Page == 0) {
-
-                            FatEntry = (PULONG)((PUCHAR)SavedBcbs[0][1] +
-                                                (StartOffsetInVolume % PAGE_SIZE));
-                        }
-                    }
-                }
-
-                //
-                //  Mark the run dirty
-                //
-
-                StartSectorLbo = StartOffsetInVolume & ~(SectorSize - 1);
-                FinalSectorLbo = FinalOffsetInVolume & ~(SectorSize - 1);
-
-                for (Lbo = StartSectorLbo; Lbo <= FinalSectorLbo; Lbo += SectorSize) {
-
-                    FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO)Lbo, Lbo, SectorSize );
-                }
-
-                //
-                //  Store the entries
-                //
-                //  We need extra synchronization here for broken architectures
-                //  like the ALPHA that don't support atomic 16 bit writes.
-                //
-
-#ifdef ALPHA
-                FatLockFreeClusterBitMap( Vcb );
-                ReleaseMutex = TRUE;
-#endif // ALPHA
-
-                FinalCluster = StartingFatIndex + ClusterCountThisRun - 1;
-                Page = 0;
-
-                for (Cluster = StartingFatIndex;
-                     Cluster <= FinalCluster;
-                     Cluster++, FatEntry++) {
-
-                    //
-                    //  If we just crossed a page boundry (as opposed to starting
-                    //  on one), update our idea of FatEntry.
-
-                    if ( (((ULONG_PTR)FatEntry & (PAGE_SIZE-1)) == 0) &&
-                         (Cluster != StartingFatIndex) ) {
-
-                        Page += 1;
-                        FatEntry = (PULONG)SavedBcbs[Page][1];
-                    }
-
-                    *FatEntry = ChainTogether ? (FAT_ENTRY)(Cluster + 1) :
-                                                FAT_CLUSTER_AVAILABLE;
-                }
-
-                //
-                //  Fix up the last entry if we were chaining together
-                //
-
-                if ((ClusterCount <= MAXCOUNTCLUS) &&
-                    ChainTogether ) {
-
-                    *(FatEntry-1) = FAT_CLUSTER_LAST;
-                }
-
-#ifdef ALPHA
-                FatUnlockFreeClusterBitMap( Vcb );
-                ReleaseMutex = FALSE;
-#endif // ALPHA
-
-                {
-                    ULONG i = 0;
-                    //
-                    //  Unpin the Bcbs
-                    //
-
-                    while ( SavedBcbs[i][0] != NULL ) {
-
-                        FatUnpinBcb( IrpContext, SavedBcbs[i][0] );
-                        SavedBcbs[i][0] = NULL;
-
-                        i += 1;
-                    }
-                }
-
-                if (ClusterCount <= MAXCOUNTCLUS) {
-
-                    break;
-
-                } else {
-
-                    StartingFatIndex += MAXCOUNTCLUS;
-                    ClusterCount -= MAXCOUNTCLUS;
-                }
-            }
-
-        } else {
-
-            //
-            //  DEAL WITH 16 BIT CASE
-            //
-
-            VBO StartOffsetInVolume;
-            VBO FinalOffsetInVolume;
-
-            ULONG Page;
-            ULONG FinalCluster;
-            PUSHORT FatEntry;
-
-            StartOffsetInVolume = FatReservedBytes(&Vcb->Bpb) +
-                                        StartingFatIndex * sizeof(USHORT);
-
-            FinalOffsetInVolume = StartOffsetInVolume +
-                                        (ClusterCount - 1) * sizeof(USHORT);
-
-#ifndef __REACTOS__
-            StartingPage = StartOffsetInVolume / PAGE_SIZE;
-#endif
-
-            //
-            //  Read in one page of fat at a time.  We cannot read in the
-            //  all of the fat we need because of cache manager limitations.
-            //
-            //  SavedBcb was initialized to be able to hold the largest
-            //  possible number of pages in a fat plus and extra one to
-            //  accomadate the boot sector, plus one more to make sure there
-            //  is enough room for the RtlZeroMemory below that needs the mark
-            //  the first Bcb after all the ones we will use as an end marker.
-            //
-
-            {
-                ULONG NumberOfPages;
-                ULONG Offset;
-
-                NumberOfPages = (FinalOffsetInVolume / PAGE_SIZE) -
-                                (StartOffsetInVolume / PAGE_SIZE) + 1;
-
-                RtlZeroMemory( &SavedBcbs[0][0], (NumberOfPages + 1) * sizeof(PBCB) * 2 );
-
-                for ( Page = 0, Offset = StartOffsetInVolume & ~(PAGE_SIZE - 1);
-                      Page < NumberOfPages;
-                      Page++, Offset += PAGE_SIZE ) {
-
-                    FatPrepareWriteVolumeFile( IrpContext,
-                                               Vcb,
-                                               Offset,
-                                               PAGE_SIZE,
-                                               &SavedBcbs[Page][0],
-                                               (PVOID *)&SavedBcbs[Page][1],
-                                               TRUE,
-                                               FALSE );
-
-                    if (Page == 0) {
-
-                        FatEntry = (PUSHORT)((PUCHAR)SavedBcbs[0][1] +
-                                            (StartOffsetInVolume % PAGE_SIZE));
-                    }
-                }
-            }
-
-            //
-            //  Mark the run dirty
-            //
-
-            StartSectorLbo = StartOffsetInVolume & ~(SectorSize - 1);
-            FinalSectorLbo = FinalOffsetInVolume & ~(SectorSize - 1);
-
-            for (Lbo = StartSectorLbo; Lbo <= FinalSectorLbo; Lbo += SectorSize) {
-
-                FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize );
-            }
-
-            //
-            //  Store the entries
-            //
-            //  We need extra synchronization here for broken architectures
-            //  like the ALPHA that don't support atomic 16 bit writes.
-            //
-
-#ifdef ALPHA
-            FatLockFreeClusterBitMap( Vcb );
-            ReleaseMutex = TRUE;
-#endif // ALPHA
-
-            FinalCluster = StartingFatIndex + ClusterCount - 1;
-            Page = 0;
-
-            for (Cluster = StartingFatIndex;
-                 Cluster <= FinalCluster;
-                 Cluster++, FatEntry++) {
-
-                //
-                //  If we just crossed a page boundry (as opposed to starting
-                //  on one), update our idea of FatEntry.
-
-                if ( (((ULONG_PTR)FatEntry & (PAGE_SIZE-1)) == 0) &&
-                     (Cluster != StartingFatIndex) ) {
-
-                    Page += 1;
-                    FatEntry = (PUSHORT)SavedBcbs[Page][1];
-                }
-
-                *FatEntry = (USHORT) (ChainTogether ? (FAT_ENTRY)(Cluster + 1) :
-                                                      FAT_CLUSTER_AVAILABLE);
-            }
-
-            //
-            //  Fix up the last entry if we were chaining together
-            //
-
-            if ( ChainTogether ) {
-
-                *(FatEntry-1) = (USHORT)FAT_CLUSTER_LAST;
-            }
-#ifdef ALPHA
-            FatUnlockFreeClusterBitMap( Vcb );
-            ReleaseMutex = FALSE;
-#endif // ALPHA
-        }
-
-    } _SEH2_FINALLY {
-
-        ULONG i = 0;
-
-        DebugUnwind( FatSetFatRun );
-
-        //
-        //  If we still somehow have the Mutex, release it.
-        //
-
-        if (ReleaseMutex) {
-
-            ASSERT( _SEH2_AbnormalTermination() );
-
-            FatUnlockFreeClusterBitMap( Vcb );
-        }
-
-        //
-        //  Unpin the Bcbs
-        //
-
-        while ( SavedBcbs[i][0] != NULL ) {
-
-            FatUnpinBcb( IrpContext, SavedBcbs[i][0] );
-
-            i += 1;
-        }
-
-        //
-        //  At this point nothing in this finally clause should have raised.
-        //  So, now comes the unsafe (sigh) stuff.
-        //
-
-        if ( _SEH2_AbnormalTermination() &&
-            (Vcb->AllocationSupport.FatIndexBitSize == 32) ) {
-
-            //
-            //  Fat32 unwind
-            //
-            //  This case is more complex because the FAT12 and FAT16 cases
-            //  pin all the needed FAT pages (128K max), after which it
-            //  can't fail, before changing any FAT entries.  In the Fat32
-            //  case, it may not be practical to pin all the needed FAT
-            //  pages, because that could span many megabytes.  So Fat32
-            //  attacks in chunks, and if a failure occurs once the first
-            //  chunk has been updated, we have to back out the updates.
-            //
-            //  The unwind consists of walking back over each FAT entry we
-            //  have changed, setting it back to the previous value.  Note
-            //  that the previous value with either be FAT_CLUSTER_AVAILABLE
-            //  (if ChainTogether==TRUE) or a simple link to the successor
-            //  (if ChainTogether==FALSE).
-            //
-            //  We concede that any one of these calls could fail too; our
-            //  objective is to make this case no more likely than the case
-            //  for a file consisting of multiple disjoint runs.
-            //
-
-            while ( StartingFatIndex > SavedStartingFatIndex ) {
-
-                StartingFatIndex--;
-
-                FatSetFatEntry( IrpContext, Vcb, StartingFatIndex,
-                    ChainTogether ?
-                        StartingFatIndex + 1 : FAT_CLUSTER_AVAILABLE );
-            }
-        }
-
-        DebugTrace(-1, Dbg, "FatSetFatRun -> (VOID)\n", 0);
-    } _SEH2_END;
-
-    return;
-}
-
-
-//
-//  Internal support routine
-//
-
-UCHAR
-FatLogOf (
-    IN ULONG Value
-    )
-
-/*++
-
-Routine Description:
-
-    This routine just computes the base 2 log of an integer.  It is only used
-    on objects that are know to be powers of two.
-
-Arguments:
-
-    Value - The value to take the base 2 log of.
-
-Return Value:
-
-    UCHAR - The base 2 log of Value.
-
---*/
-
-{
-    UCHAR Log = 0;
-
-    PAGED_CODE();
-
-    DebugTrace(+1, Dbg, "LogOf\n", 0);
-    DebugTrace( 0, Dbg, "  Value = %8lx\n", Value);
-
-    //
-    //  Knock bits off until we we get a one at position 0
-    //
-
-    while ( (Value & 0xfffffffe) != 0 ) {
-
-        Log++;
-        Value >>= 1;
-    }
-
-    //
-    //  If there was more than one bit set, the file system messed up,
-    //  Bug Check.
-    //
-
-    if (Value != 0x1) {
-
-        DebugTrace( 0, Dbg, "Received non power of 2.\n", 0);
-
-        FatBugCheck( Value, Log, 0 );
-    }
-
-    DebugTrace(-1, Dbg, "LogOf -> %8lx\n", Log);
-
-    return Log;
-}
-
-
-VOID
-FatExamineFatEntries(
-    IN PIRP_CONTEXT IrpContext,
-    IN PVCB Vcb,
-    IN ULONG StartIndex OPTIONAL,
-    IN ULONG EndIndex OPTIONAL,
-    IN BOOLEAN SetupWindows,
-    IN PFAT_WINDOW SwitchToWindow OPTIONAL,
-    IN PULONG BitMapBuffer OPTIONAL
-    )
-/*++
-
-Routine Description:
-
-    This routine handles scanning a segment of the FAT into in-memory structures.
-
-    There are three fundamental cases, with variations depending on the FAT type:
-
-    1) During volume setup, FatSetupAllocations
-
... 63110 lines suppressed ...