[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