[ros-dev] [ros-diffs] [reactos] 01/01: [FASTFAT_NEW] This is not permitted by WDK license. We should rather import from MS GitHub and backport to NT5.2.

Pierre Schweitzer pierre at reactos.org
Sat Nov 25 09:36:45 UTC 2017


Hey Alex,

It was taken from W7 WDK. In that one, you had a FastFAT sample for
WNET, WLH, W7 and WXP. That's the later I took.

Cheers,
Pierre

Le 24/11/2017 à 22:12, Alex Ionescu a écrit :
> 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 at reactos.org>
> wrote:
> 
>> https://git.reactos.org/?p=reactos.git;a=commitdiff;h=
>> a913501626e599fba9d702149896f36046832deb
>>
>> commit a913501626e599fba9d702149896f36046832deb
>> Author: Pierre Schweitzer <pierre at 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 ...
>>
>>
> 


-- 
Pierre Schweitzer <pierre at reactos.org>
System & Network Administrator
Senior Kernel Developer
ReactOS Deutschland e.V.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://www.reactos.org/pipermail/ros-dev/attachments/20171125/16eff317/attachment-0001.sig>


More information about the Ros-dev mailing list