📄 allocsup.c
字号:
Dirent->FirstClusterOfFile = (USHORT)UnwindInitialFirstClusterOfFile;
if ( FatIsFat32(Vcb) ) {
Dirent->FirstClusterOfFileHi =
(USHORT)(UnwindInitialFirstClusterOfFile >> 16);
}
FcbOrDcb->FirstClusterOfFile = UnwindInitialFirstClusterOfFile;
}
}
if ( UnwindWeAllocatedMcb ) {
FsRtlUninitializeLargeMcb( &RemainingMcb );
}
//
// Note that in the non zero truncation case, we will also
// leak clusters. However, apart from this, the in memory and on disc
// structures will agree.
}
FatUnpinBcb( IrpContext, Bcb );
//
// Give FlushFileBuffer/Cleanup a clue here, regardless of success/fail.
//
SetFlag(FcbOrDcb->FcbState, FCB_STATE_FLUSH_FAT);
DebugTrace(-1, Dbg, "FatTruncateFileAllocation -> (VOID)\n", 0);
}
}
VOID
FatLookupFileAllocationSize (
IN PIRP_CONTEXT IrpContext,
IN PFCB FcbOrDcb
)
/*++
Routine Description:
This routine retrieves the current file allocatio size for the
specified file/directory.
Arguments:
FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being modified
--*/
{
LBO Lbo;
ULONG ByteCount;
BOOLEAN DontCare;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatLookupAllocationSize\n", 0);
DebugTrace( 0, Dbg, " FcbOrDcb = %8lx\n", FcbOrDcb);
//
// We call FatLookupFileAllocation with Vbo of 0xffffffff - 1.
//
FatLookupFileAllocation( IrpContext,
FcbOrDcb,
MAXULONG - 1,
&Lbo,
&ByteCount,
&DontCare,
&DontCare,
NULL );
//
// FileSize was set at Fcb creation time from the contents of the directory entry,
// and we are only now looking up the real length of the allocation chain. If it
// cannot be contained, this is trash. Probably more where that came from.
//
if (FcbOrDcb->Header.FileSize.LowPart > FcbOrDcb->Header.AllocationSize.LowPart) {
FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
}
DebugTrace(-1, Dbg, "FatLookupFileAllocationSize -> (VOID)\n", 0);
return;
}
VOID
FatAllocateDiskSpace (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb,
IN ULONG AbsoluteClusterHint,
IN PULONG ByteCount,
IN BOOLEAN ExactMatchRequired,
OUT PLARGE_MCB Mcb
)
/*++
Routine Description:
This procedure allocates additional disk space and builds an mcb
representing the newly allocated space. If the space cannot be
allocated then this procedure raises an appropriate status.
Searching starts from the hint index in the Vcb unless an alternative
non-zero hint is given in AlternateClusterHint. If we are using the
hint field in the Vcb, it is set to the cluster following our allocation
when we are done.
Disk space can only be allocated in cluster units so this procedure
will round up any byte count to the next cluster boundary.
Pictorially what is done is the following (where ! denotes the end of
the fat chain (i.e., FAT_CLUSTER_LAST)):
Mcb (empty)
becomes
Mcb |--a--|--b--|--c--!
^
ByteCount ----------+
Arguments:
Vcb - Supplies the VCB being modified
AbsoluteClusterHint - Supplies an alternate hint index to start the
search from. If this is zero we use, and update,
the Vcb hint field.
ByteCount - Supplies the number of bytes that we are requesting, and
receives the number of bytes that we got.
ExactMatchRequired - Caller should set this to TRUE if only the precise run requested
is acceptable.
Mcb - Receives the MCB describing the newly allocated disk space. The
caller passes in an initialized Mcb that is filled in by this procedure.
Return Value:
TRUE - Allocated ok
FALSE - Failed to allocate exactly as requested (=> ExactMatchRequired was TRUE)
--*/
{
UCHAR LogOfBytesPerCluster;
ULONG BytesPerCluster;
ULONG StartingCluster;
ULONG ClusterCount;
ULONG WindowRelativeHint;
#if DBG
ULONG i;
ULONG PreviousClear;
#endif
PFAT_WINDOW Window;
BOOLEAN Wait;
BOOLEAN Result = TRUE;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatAllocateDiskSpace\n", 0);
DebugTrace( 0, Dbg, " Vcb = %8lx\n", Vcb);
DebugTrace( 0, Dbg, " *ByteCount = %8lx\n", *ByteCount);
DebugTrace( 0, Dbg, " Mcb = %8lx\n", Mcb);
DebugTrace( 0, Dbg, " Hint = %8lx\n", AbsoluteClusterHint);
ASSERT((AbsoluteClusterHint <= Vcb->AllocationSupport.NumberOfClusters + 2) && (1 != AbsoluteClusterHint));
//
// Make sure byte count is not zero
//
if (*ByteCount == 0) {
DebugTrace(0, Dbg, "Nothing to allocate.\n", 0);
DebugTrace(-1, Dbg, "FatAllocateDiskSpace -> (VOID)\n", 0);
return;
}
//
// Compute the cluster count based on the byte count, rounding up
// to the next cluster if there is any remainder. Note that the
// pathalogical case BytesCount == 0 has been eliminated above.
//
LogOfBytesPerCluster = Vcb->AllocationSupport.LogOfBytesPerCluster;
BytesPerCluster = 1 << LogOfBytesPerCluster;
*ByteCount = (*ByteCount + (BytesPerCluster - 1))
& ~(BytesPerCluster - 1);
//
// If ByteCount is NOW zero, then we were asked for the maximal
// filesize (or at least for bytes in the last allocatable sector).
//
if (*ByteCount == 0) {
*ByteCount = 0xffffffff;
ClusterCount = 1 << (32 - LogOfBytesPerCluster);
} else {
ClusterCount = (*ByteCount >> LogOfBytesPerCluster);
}
//
// Make sure there are enough free clusters to start with, and
// take them now so that nobody else takes them from us.
//
ExAcquireResourceSharedLite(&Vcb->ChangeBitMapResource, TRUE);
FatLockFreeClusterBitMap( Vcb );
if (ClusterCount <= Vcb->AllocationSupport.NumberOfFreeClusters) {
Vcb->AllocationSupport.NumberOfFreeClusters -= ClusterCount;
} else {
FatUnlockFreeClusterBitMap( Vcb );
ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
DebugTrace(0, Dbg, "Disk Full. Raise Status.\n", 0);
FatRaiseStatus( IrpContext, STATUS_DISK_FULL );
}
//
// Did the caller supply a hint?
//
if ((0 != AbsoluteClusterHint) && (AbsoluteClusterHint < (Vcb->AllocationSupport.NumberOfClusters + 2))) {
if (Vcb->NumberOfWindows > 1) {
//
// If we're being called upon to allocate clusters outside the
// current window (which happens only via MoveFile), it's a problem.
// We address this by changing the current window to be the one which
// contains the alternate cluster hint. Note that if the user's
// request would cross a window boundary, he doesn't really get what
// he wanted.
//
if (AbsoluteClusterHint < Vcb->CurrentWindow->FirstCluster ||
AbsoluteClusterHint > Vcb->CurrentWindow->LastCluster) {
ULONG BucketNum = FatWindowOfCluster( AbsoluteClusterHint );
ASSERT( BucketNum < Vcb->NumberOfWindows);
//
// Drop our shared lock on the ChangeBitMapResource, and pick it up again
// exclusive in preparation for making the window swap.
//
FatUnlockFreeClusterBitMap(Vcb);
ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
ExAcquireResourceExclusiveLite(&Vcb->ChangeBitMapResource, TRUE);
FatLockFreeClusterBitMap(Vcb);
Window = &Vcb->Windows[BucketNum];
//
// Again, test the current window against the one we want - some other
// thread could have sneaked in behind our backs and kindly set it to the one
// we need, when we dropped and reacquired the ChangeBitMapResource above.
//
if (Window != Vcb->CurrentWindow) {
try {
Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
//
// Change to the new window (update Vcb->CurrentWindow) and scan it
// to build up a freespace bitmap etc.
//
FatExamineFatEntries( IrpContext, Vcb,
0,
0,
FALSE,
Window,
NULL);
} finally {
if (!Wait) {
ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
}
if (AbnormalTermination()) {
//
// We will have raised as a result of failing to pick up the
// chunk of the FAT for this window move. Release our resources
// and return the cluster count to the volume.
//
Vcb->AllocationSupport.NumberOfFreeClusters += ClusterCount;
FatUnlockFreeClusterBitMap( Vcb );
ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
}
}
}
}
//
// Make the hint cluster number relative to the base of the current window...
//
// Currentwindow->Firstcluster is baised by +2 already, so we will lose the
// bias already in AbsoluteClusterHint. Put it back....
//
WindowRelativeHint = AbsoluteClusterHint - Vcb->CurrentWindow->FirstCluster + 2;
}
else {
//
// Only one 'window', ie fat16/12. No modification necessary.
//
WindowRelativeHint = AbsoluteClusterHint;
}
}
else {
//
// Either no hint supplied, or it was out of range, so grab one from the Vcb
//
// NOTE: Clusterhint in the Vcb is not guaranteed to be set (may be -1)
//
WindowRelativeHint = Vcb->ClusterHint;
AbsoluteClusterHint = 0;
//
// Vcb hint may not have been initialized yet. Force to valid cluster.
//
if (-1 == WindowRelativeHint) {
WindowRelativeHint = 2;
}
}
ASSERT((WindowRelativeHint >= 2) && (WindowRelativeHint < Vcb->FreeClusterBitMap.SizeOfBitMap + 2));
//
// Keep track of the window we're allocating from, so we can clean
// up correctly if the current window changes after we unlock the
// bitmap.
//
Window = Vcb->CurrentWindow;
//
// Try to find a run of free clusters large enough for us.
//
StartingCluster = FatFindFreeClusterRun( IrpContext,
Vcb,
ClusterCount,
WindowRelativeHint );
//
// If the above call was successful, we can just update the fat
// and Mcb and exit. Otherwise we have to look for smaller free
// runs.
//
// This test is a bit funky. Note that the error return from
// RtlFindClearBits is -1, and adding two to that is 1.
//
if ((StartingCluster != 1) &&
((0 == AbsoluteClusterHint) || (StartingCluster == WindowRelativeHint))
) {
#if DBG
PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
#endif // DBG
//
// Take the clusters we found, and unlock the bit map.
//
FatReserveClusters(IrpContext, Vcb, StartingCluste
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -