[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.
Alex Ionescu
ionucu at videotron.ca
Fri Nov 24 21:13:16 UTC 2017
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 ...
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.reactos.org/pipermail/ros-dev/attachments/20171124/7fdcc623/attachment-0001.html>
More information about the Ros-dev
mailing list