XP did not have a WDK. Did you mean XP IFS?
Best regards, Alex Ionescu
On Thu, Nov 23, 2017 at 4:04 AM, Pierre Schweitzer pierre@reactos.org wrote:
https://git.reactos.org/?p=reactos.git;a=commitdiff;h= a913501626e599fba9d702149896f36046832deb
commit a913501626e599fba9d702149896f36046832deb Author: Pierre Schweitzer pierre@reactos.org AuthorDate: Thu Nov 23 15:04:05 2017 +0100
[FASTFAT_NEW] This is not permitted by WDK license. We should rather import from MS GitHub and backport to NT5.2.
drivers/filesystems/fastfat_new/CMakeLists.txt | 44 - drivers/filesystems/fastfat_new/acchksup.c | 374 -- drivers/filesystems/fastfat_new/allocsup.c | 5001 ------------------ drivers/filesystems/fastfat_new/cachesup.c | 1814 ------- drivers/filesystems/fastfat_new/cleanup.c | 1027 ---- drivers/filesystems/fastfat_new/close.c | 1224 ----- drivers/filesystems/fastfat_new/create.c | 5684
drivers/filesystems/fastfat_new/devctrl.c | 308 -- drivers/filesystems/fastfat_new/deviosup.c | 3284 ------------ drivers/filesystems/fastfat_new/dirctrl.c | 1526 ------ drivers/filesystems/fastfat_new/dirsup.c | 3647 ------------- drivers/filesystems/fastfat_new/dumpsup.c | 381 -- drivers/filesystems/fastfat_new/ea.c | 2013 ------- drivers/filesystems/fastfat_new/easup.c | 3811 -------------- drivers/filesystems/fastfat_new/fastfat.rc | 5 - drivers/filesystems/fastfat_new/fat.h | 729 --- drivers/filesystems/fastfat_new/fatdata.c | 1424 ----- drivers/filesystems/fastfat_new/fatdata.h | 328 -- drivers/filesystems/fastfat_new/fatinit.c | 675 --- drivers/filesystems/fastfat_new/fatprocs.h | 2817 ---------- drivers/filesystems/fastfat_new/fatprocssrc.c | 1 - drivers/filesystems/fastfat_new/fatstruc.h | 1614 ------ drivers/filesystems/fastfat_new/fileinfo.c | 4635 ---------------- drivers/filesystems/fastfat_new/filobsup.c | 547 -- drivers/filesystems/fastfat_new/flush.c | 1261 ----- drivers/filesystems/fastfat_new/fsctrl.c | 6726
drivers/filesystems/fastfat_new/fspdisp.c | 472 -- drivers/filesystems/fastfat_new/lfn.h | 56 - drivers/filesystems/fastfat_new/lockctrl.c | 726 --- drivers/filesystems/fastfat_new/namesup.c | 1021 ---- drivers/filesystems/fastfat_new/nodetype.h | 193 - drivers/filesystems/fastfat_new/pnp.c | 815 --- drivers/filesystems/fastfat_new/read.c | 1649 ------ drivers/filesystems/fastfat_new/resrcsup.c | 807 --- drivers/filesystems/fastfat_new/shutdown.c | 304 -- drivers/filesystems/fastfat_new/sources | 45 - drivers/filesystems/fastfat_new/splaysup.c | 504 -- drivers/filesystems/fastfat_new/strucsup.c | 3626 ------------- drivers/filesystems/fastfat_new/timesup.c | 364 -- drivers/filesystems/fastfat_new/verfysup.c | 1853 ------- drivers/filesystems/fastfat_new/volinfo.c | 1272 ----- drivers/filesystems/fastfat_new/workque.c | 362 -- drivers/filesystems/fastfat_new/write.c | 2830 ---------- 43 files changed, 67799 deletions(-)
diff --git a/drivers/filesystems/fastfat_new/CMakeLists.txt b/drivers/filesystems/fastfat_new/CMakeLists.txt deleted file mode 100644 index f21d829e63..0000000000 --- a/drivers/filesystems/fastfat_new/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@
-list(APPEND SOURCE
- acchksup.c
- allocsup.c
- cachesup.c
- cleanup.c
- close.c
- create.c
- devctrl.c
- deviosup.c
- dirctrl.c
- dirsup.c
- dumpsup.c
- ea.c
- easup.c
- fatdata.c
- fatinit.c
- fatprocssrc.c
- fileinfo.c
- filobsup.c
- flush.c
- fsctrl.c
- fspdisp.c
- lockctrl.c
- namesup.c
- pnp.c
- read.c
- resrcsup.c
- shutdown.c
- splaysup.c
- strucsup.c
- timesup.c
- verfysup.c
- volinfo.c
- workque.c
- write.c
- fatprocs.h)
-add_library(fastfat SHARED ${SOURCE} fastfat.rc) -set_module_type(fastfat kernelmodedriver) -target_link_libraries(fastfat ${PSEH_LIB} memcmp) -add_importlibs(fastfat ntoskrnl hal) -add_pch(fastfat fatprocs.h SOURCE) -add_cd_file(TARGET fastfat DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/drivers/filesystems/fastfat_new/acchksup.c b/drivers/filesystems/fastfat_new/acchksup.c deleted file mode 100644 index b0c78a81a4..0000000000 --- a/drivers/filesystems/fastfat_new/acchksup.c +++ /dev/null @@ -1,374 +0,0 @@ -/*++
-Copyright (c) 1989-2000 Microsoft Corporation
-Module Name:
- AcChkSup.c
-Abstract:
- This module implements the FAT access checking routine
---*/
-#include "fatprocs.h"
-// -// Our debug trace level -//
-#define Dbg (DEBUG_TRACE_ACCHKSUP)
-NTSTATUS -FatCreateRestrictEveryoneToken(
- IN PACCESS_TOKEN Token,
- OUT PACCESS_TOKEN *RestrictedToken
- );
-#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, FatCheckFileAccess) -#pragma alloc_text(PAGE, FatCreateRestrictEveryoneToken) -#pragma alloc_text(PAGE, FatExplicitDeviceAccessGranted) -#endif
-BOOLEAN -FatCheckFileAccess (
- PIRP_CONTEXT IrpContext,
- IN UCHAR DirentAttributes,
- IN PACCESS_MASK DesiredAccess
- )
-/*++
-Routine Description:
- This routine checks if a desired access is allowed to a file
represented
- by the specified DirentAttriubutes.
-Arguments:
- DirentAttributes - Supplies the Dirent attributes to check access for
- DesiredAccess - Supplies the desired access mask that we are checking
for
-Return Value:
- BOOLEAN - TRUE if access is allowed and FALSE otherwise
---*/
-{
- BOOLEAN Result;
- DebugTrace(+1, Dbg, "FatCheckFileAccess\n", 0);
- DebugTrace( 0, Dbg, "DirentAttributes = %8lx\n", DirentAttributes);
- DebugTrace( 0, Dbg, "DesiredAccess = %8lx\n", *DesiredAccess);
- //
- // This procedures is programmed like a string of filters each
- // filter checks to see if some access is allowed, if it is not
allowed
- // the filter return FALSE to the user without further checks
otherwise
- // it moves on to the next filter. The filter check is to check for
- // desired access flags that are not allowed for a particular dirent
- //
- Result = TRUE;
- _SEH2_TRY {
//// Check for Volume ID or Device Dirents, these are not alloweduser
// 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 blackballthat
// we do not understand. The model of filesystems using ACLs isthat
// 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, weblackball
// 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 sidNULL, // Do not create any restricted sidsNULL, // Do not delete any privilegesRestrictedToken // 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 %xh\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:
- First window with >50% free clusters
- First empty window
- 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 takeit,
// 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 thetwo 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 inthe 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 clusteralligned.
// The assumption here, is that only whole clusters of Vbos andLbos
// are mapped in the Mcb.//ASSERT( ((CurrentLbo - Vcb->AllocationSupport.FileAreaLbo)% BytesPerCluster ==
- &&
(CurrentVbo % BytesPerCluster == 0) );//// Starting from the first Vbo after the last Mcb entry, scanthrough
// the Fat looking for our Vbo. We continue through the Fatuntil we
// hit a noncontiguity beyond the desired Vbo, or the lastcluster.
//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 -> FatCorrupt. 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 Mcbcontained an
// entry, then FirstLboOfCurrentRun was set on the first// iteration through the loop. Thus ifFirstLboOfCurrentRun
// is 0, then there was an Mcb entry and we are on ourfirst
// 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, thusAllocationSize
// must be too large.//// Note that, when we finally arrive here, CurrentVbo isactually
// the first Vbo beyond the file allocation andCurrentLbo is
// meaningless.//DebugTrace( 0, Dbg, "Read last cluster of file.\n", 0);//// Detect the case of the maximal file. Note that thisreally isn't
// a proper Vbo - those are zero-based, and this is aone-based number.
// The maximal file, of 2^32 - 1 bytes, has a maximumbyte 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 havefound
// the Vbo. If we haven't, seeing as we checked VBO// against AllocationSize, the real disk allocation isless
// than that of AllocationSize. This comes about whenthe
// real allocation is not yet known, and AllocaitonSize// contains MAXULONG.//// KLUDGE! - If we were called byFatLookupFileAllocationSize
// Vbo is set to MAXULONG - 1, and AllocationSize to thelookup
// hint. Thus we merrily go along looking for a matchthat isn't
// there, but in the meantime building an Mcb. If thisis
// 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 terminatedon 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 weare beyond
// the desired Vbo, this is the end of the run, so setLastCluster
// and exit the loop.//case FatClusterNext://// This is the loop check. The Vbo must not be biggerthan the size of
// the volume, and the Vbo must not have a) wrapped andb) not been at the
// very last cluster in the chain, for the case of themaximal 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 nextrun,
// we see if the run we just added encompases thedesired
// 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 towhere we
// ended. Since partial-lookup cases will occur withoutexclusive
// 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->FirstClusterOfFile16);
}//// Note the size of the allocation we need to tell thecache 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 beslightly 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
- :
0),&NewAllocation,FALSE,&NewMcb );UnwindWeAllocatedDiskSpace = TRUE;}//// Now that we increased the allocation of the file, mark it inthe
// FcbOrDcb. Carefully prepare to handle an inability to growthe cache
// structures.//FcbOrDcb->Header.AllocationSize.LowPart += NewAllocation;//// Handle the maximal file case, where we may have justwrapped. Note
// that this must be the precise boundary case wrap, i.e. by onebyte,
// so that the new allocation is actually one byte "less" as faras 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 thenew
// allocation onto the file. This simplifies exception cleanupsince
// if it was already added and the section grow failed, we'dhave to
// do extra work to unglue it. This way, we can assume that ifwe
// raise the only thing we need to do is deallocate the diskspace.
//// 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 needto go
// back various things out.//if (_SEH2_AbnormalTermination()) {//// Pull off the allocation size we tried to add to thisobject 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 Mcband 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 allocationtemporary Mcb,
// otherwise we have the Fcb's Mcb and we just truncateit away.
//if (UnwindWeInitializedMcb == TRUE) {//// Note that we already know a raise is inprogress. No danger
// of encountering the normal case code below anddoing 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 isrounded
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 smallerthan
// 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 currentallocation.\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 willkeep, 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 niceif we could
// pretend the truncate worked if we knew that the file hadgotten into
// a consistent state. Leaving dangled clusters is probablyquite preferable.
//if ( _SEH2_AbnormalTermination() ) {FcbOrDcb->Header.AllocationSize.LowPart =UnwindInitialAllocationSize;
if ( (DesiredAllocationSize == 0) && (Dirent != NULL)) {if (UpdatedDirent) {//// If the dirent has been updated ok and markeddirty, then we
// failed in deallocatediscspace, and don't knowwhat state
// the on disc fat chain is in. So we throw awaythe mcb,
// and potentially loose a few clusters until thenext
// chkdsk. The operation has succeeded, but theexception
// 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)(UnwindInitialFirstClusterOfFile16);
}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 memoryand 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, andupdate,
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 thisprocedure.
- 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
- && (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 outsidethe
// current window (which happens only via MoveFile), it's aproblem.
// We address this by changing the current window to be theone which
// contains the alternate cluster hint. Note that if theuser's
// request would cross a window boundary, he doesn't reallyget 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 wewant - some other
// thread could have sneaked in behind our backs andkindly set it to the one
// we need, when we dropped and reacquired theChangeBitMapResource 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 (updateVcb->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 offailing to pick up the
// chunk of the FAT for this window move.Release our resources
// and return the cluster count to thevolume.
//Vcb->AllocationSupport.NumberOfFreeClusters+= ClusterCount;
FatUnlockFreeClusterBitMap( Vcb );ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
}} _SEH2_END;}}//// Make the hint cluster number relative to the base of thecurrent window...
//// Currentwindow->Firstcluster is baised by +2 already, sowe will lose the
// bias already in AbsoluteClusterHint. Put it back....//WindowRelativeHint = AbsoluteClusterHint -Vcb->CurrentWindow->FirstCluster + 2;
}else {//// Only one 'window', ie fat16/12. No modificationnecessary.
//WindowRelativeHint = AbsoluteClusterHint;}- }
- else {
//// Either no hint supplied, or it was out of range, so grabone from the Vcb
//// NOTE: Clusterhint in the Vcb is not guaranteed to be set (maybe -1)
//WindowRelativeHint = Vcb->ClusterHint;AbsoluteClusterHint = 0;//// Vcb hint may not have been initialized yet. Force to validcluster.
//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 theMcb,
// 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 andwindow->firstcluster) are
// already biased by 2, so will cancel, so we needto 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. Whenappropriate
// it'll get converted into a true cluster number and put inCluster, 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 pickit 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 tosearch! RtlFindClearBits
// searchs the whole bitmap, so we would have found anycontiguous run
// large enough.//try_leave( Result = FALSE);}//// While the request is still incomplete, look for thelargest
// 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 alreadylocked
//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 dowithout 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. Tryfrom the current hint the to
// end of current window. Don't try for morethan we actually need.
//if (Desired > ClustersRemaining) {Desired = ClustersRemaining;}if (RtlAreBitsClear( &Vcb->FreeClusterBitMap,WindowRelativeHint - 2,Desired)){//// Clusters from hint->...windowend arefree. Take them.
//Index = WindowRelativeHint - 2;ClustersFound = Desired;if (FatIsFat32(Vcb)) {//// We're now up against the end of thecurrent window, so indicate that we
// want the next window in the sequencenext time around. (If we're not up
// against the end of the window, thenwe 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 theend of the volume. Clear the
// hint, since we now have no ideawhere to look.
//WindowRelativeHint = 0;}-#if DBG
PreviousClear = RtlNumberOfClearBits(&Vcb->FreeClusterBitMap ); -#endif // DBG
}else {if (ExactMatchRequired) {//// If our caller required an exactmatch, 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 besatisfied entirely from this
// window. We will ask only for what weneed, to try and avoid
// unnecessarily fragmenting large runs ofspace 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 largestfree 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 awindow, set up a hint that
// we'd like the next consecutive windowafter 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-windowFAT,
// there was a bad problem with the free clustercount.
//if (1 == Vcb->NumberOfWindows) {FatBugCheck( 0, 5, 0 );}//// Switch to a new bucket. Possibly the next one ifwe'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 runpast the end of the volume...
//try_leave( Result = FALSE);}//// Give up on the contiguous allocationattempts
//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 somefree 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, havingswitched windows,
// and allocate....//-#if DBG
PreviousClear = RtlNumberOfClearBits(&Vcb->FreeClusterBitMap ); -#endif //DBG
} // if (clustersfound == 0)else {//// Take the clusters we found, convert our index toa 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, andallocate
// 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 thisexception:
// when switching the window (FatExamineFatEntries),adding
// a found run to the Mcb (FatAddMcbEntry), or whenwriting
// the changes to the FAT (FatSetFatEntry). In thefirst 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 theFAT
// window is still in place and we need to clear thebits.
// If the Mcb entry isn't there (we raised trying toadd
// it), the effect of trying to remove it is a noop.//if (Window == Vcb->CurrentWindow) {//// Cluster reservation works on cluster 2 basedwindow-relative
// numbers, so we must convert. The subtractionwill lose the
// cluster 2 base, so bias the result.//FatUnreserveClusters( IrpContext, Vcb,(Cluster -Window->FirstCluster) + 2,
ClustersFound );}//// Note that FatDeallocateDiskSpace will take careof adjusting
// to account for the entries in the Mcb. All wehave 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 doanything
// that needs to be backed out.//FatUnlockFreeClusterBitMap( Vcb );}_SEH2_TRY {//// Now we have tidied up, we are ready to just sendthe Mcb
// off to deallocate disk space//FatDeallocateDiskSpace( IrpContext, Vcb, Mcb );} _SEH2_FINALLY {//// Now finally (really), remove all the entries fromthe 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 takingclusters
// 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, sowe'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, andmay 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 allocationspanned,
// advance to the next.//if (MyLength != count) {Window++;MyStart = Window->FirstCluster;}}//// Deallocation is now complete. Adjust the free clustercount.
//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 Mcbthat
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 theend
// 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 enlargedallocation- SecondMcb - Supplies the ZERO VBO BASED MCB of the second allocation
that is being appended to the first allocation. Thisprocedure 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 ofSecondMcb
//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 thecurrent
// 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 thecurrent
// 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 thisoperation. 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 writemarks
// 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, andadd 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, itcontinues
// to the next sector, so mark the next sector dirty as well.//// Note that this entry will simply coalese with the lastentry,
// 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
- ) {
Lbo += SectorSize;FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo,SectorSize );
}//// Store the entry into the fat; we need a littlesynchonization
// 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 fileheap.
//-#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 brokenarchitectures
// 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 bitoperation.
//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 thiswrite-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 writemarks
// 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 thatFinalSectorLbo is
// the Lbo of the END of the entry (Thus * 3 + 2). Thismakes sure
// we catch the case of a dirty fat entry straddling asector boundry.
//// Note that if the first AddMcbEntry succeeds, allfollowing 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 thebytes
// 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 brokenarchitectures
// like the ALPHA that don't support atomic 16 bitwrites.
//-#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 tostarting
// 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 managerlimitations.
//// 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 surethere
// is enough room for the RtlZeroMemory below that needs themark
// the first Bcb after all the ones we will use as an endmarker.
//{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 brokenarchitectures
// 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 tostarting
// 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
- :
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 haveraised.
// 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 FAT16cases
// 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 beFAT_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 thecase
// 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:
- During volume setup, FatSetupAllocations
... 63110 lines suppressed ...