📄 allocsup.c
字号:
LBO LastAllocatedLbo;
VBO DontCare;
//
// Get the first cluster following the current allocation. It is possible
// the Mcb is empty (or short, etc.) so we need to be slightly careful
// about making sure we don't lie with the hint.
//
(void)FatLookupLastMcbEntry( FcbOrDcb->Vcb, &FcbOrDcb->Mcb, &DontCare, &LastAllocatedLbo, NULL );
//
// Try to get some disk space starting from there.
//
NewAllocation = DesiredAllocationSize - FcbOrDcb->Header.AllocationSize.LowPart;
FsRtlInitializeLargeMcb( &NewMcb, PagedPool );
UnwindWeInitializedMcb = TRUE;
McbToCleanup = &NewMcb;
FatAllocateDiskSpace( IrpContext,
Vcb,
(LastAllocatedLbo != ~0 ?
FatGetIndexFromLbo(Vcb,LastAllocatedLbo + 1) :
0),
&NewAllocation,
FALSE,
&NewMcb );
UnwindWeAllocatedDiskSpace = TRUE;
}
//
// Now that we increased the allocation of the file, mark it in the
// FcbOrDcb. Carefully prepare to handle an inability to grow the cache
// structures.
//
FcbOrDcb->Header.AllocationSize.LowPart += NewAllocation;
//
// Handle the maximal file case, where we may have just wrapped. Note
// that this must be the precise boundary case wrap, i.e. by one byte,
// so that the new allocation is actually one byte "less" as far as we're
// concerned. This is important for the extension case.
//
if (FcbOrDcb->Header.AllocationSize.LowPart == 0) {
NewAllocation -= 1;
FcbOrDcb->Header.AllocationSize.LowPart = 0xffffffff;
}
UnwindAllocationSizeSet = TRUE;
//
// Inform the cache manager to increase the section size
//
if ( ARGUMENT_PRESENT(FileObject) && CcIsFileCached(FileObject) ) {
CcSetFileSizes( FileObject,
(PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
UnwindCacheManagerInformed = TRUE;
}
//
// In the extension case, we have held off actually gluing the new
// allocation onto the file. This simplifies exception cleanup since
// if it was already added and the section grow failed, we'd have to
// do extra work to unglue it. This way, we can assume that if we
// raise the only thing we need to do is deallocate the disk space.
//
// Merge the allocation now.
//
if (FcbOrDcb->Header.AllocationSize.LowPart != NewAllocation) {
//
// Tack the new Mcb onto the end of the FcbOrDcb one.
//
FatMergeAllocation( IrpContext,
Vcb,
&FcbOrDcb->Mcb,
&NewMcb );
}
} finally {
DebugUnwind( FatAddFileAllocation );
//
// Give FlushFileBuffer/Cleanup a clue here, regardless of success/fail..
//
SetFlag(FcbOrDcb->FcbState, FCB_STATE_FLUSH_FAT);
//
// If we were dogged trying to complete this operation, we need to go
// back various things out.
//
if (AbnormalTermination()) {
//
// Pull off the allocation size we tried to add to this object if
// we failed to grow cache structures or Mcb structures.
//
if (UnwindAllocationSizeSet) {
FcbOrDcb->Header.AllocationSize.LowPart -= NewAllocation;
}
if (UnwindCacheManagerInformed) {
CcSetFileSizes( FileObject,
(PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
}
//
// In the case of initial allocation, we used the Fcb's Mcb and have
// to clean that up as well as the FAT chain references.
//
if (FcbOrDcb->Header.AllocationSize.LowPart == 0) {
if (Dirent != NULL) {
FcbOrDcb->FirstClusterOfFile = 0;
Dirent->FirstClusterOfFile = 0;
if ( FatIsFat32(Vcb) ) {
Dirent->FirstClusterOfFileHi = 0;
}
}
}
//
// ... and drop the dirent Bcb if we got it. Do it now
// so we can afford to take the exception if we have to.
//
FatUnpinBcb( IrpContext, Bcb );
try {
//
// Note this can re-raise.
//
if ( UnwindWeAllocatedDiskSpace ) {
FatDeallocateDiskSpace( IrpContext, Vcb, McbToCleanup );
}
} finally {
//
// We always want to clean up the non-initial allocation temporary Mcb,
// otherwise we have the Fcb's Mcb and we just truncate it away.
//
if (UnwindWeInitializedMcb == TRUE) {
//
// Note that we already know a raise is in progress. No danger
// of encountering the normal case code below and doing this again.
//
FsRtlUninitializeLargeMcb( McbToCleanup );
} else {
if (McbToCleanup) {
FsRtlTruncateLargeMcb( McbToCleanup, 0 );
}
}
}
}
DebugTrace(-1, Dbg, "FatAddFileAllocation -> (VOID)\n", 0);
}
//
// Non-exceptional cleanup we always want to do. In handling the re-raise possibilities
// during exceptions we had to make sure these two steps always happened there beforehand.
// So now we handle the usual case.
//
FatUnpinBcb( IrpContext, Bcb );
if (UnwindWeInitializedMcb == TRUE) {
FsRtlUninitializeLargeMcb( &NewMcb );
}
}
VOID
FatTruncateFileAllocation (
IN PIRP_CONTEXT IrpContext,
IN PFCB FcbOrDcb,
IN ULONG DesiredAllocationSize
)
/*++
Routine Description:
This routine truncates the allocation to the specified file/directory.
If the file is already smaller than the indicated size then this procedure
is effectively a noop.
Arguments:
FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being modified
This parameter must not specify the root dcb.
DesiredAllocationSize - Supplies the maximum size, in bytes, that we want
allocated to the file/directory. It is rounded
up to the nearest cluster.
Return Value:
VOID - TRUE if the operation completed and FALSE if it had to
block but could not.
--*/
{
PVCB Vcb;
PBCB Bcb = NULL;
LARGE_MCB RemainingMcb;
ULONG BytesPerCluster;
PDIRENT Dirent = NULL;
BOOLEAN UpdatedDirent = FALSE;
ULONG UnwindInitialAllocationSize;
ULONG UnwindInitialFirstClusterOfFile;
BOOLEAN UnwindWeAllocatedMcb = FALSE;
PAGED_CODE();
DebugTrace(+1, Dbg, "FatTruncateFileAllocation\n", 0);
DebugTrace( 0, Dbg, " FcbOrDcb = %8lx\n", FcbOrDcb);
DebugTrace( 0, Dbg, " DesiredAllocationSize = %8lx\n", DesiredAllocationSize);
//
// If the Fcb isn't in good condition, we have no business whacking around on
// the disk after "its" clusters.
//
// Inspired by a Prefix complaint.
//
ASSERT( FcbOrDcb->FcbCondition == FcbGood );
//
// If we haven't yet set the correct AllocationSize, do so.
//
if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
}
//
// Round up the Desired Allocation Size to the next cluster size
//
Vcb = FcbOrDcb->Vcb;
BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
//
// Note if the desired allocation is zero, to distinguish this from
// the wrap case below.
//
if (DesiredAllocationSize != 0) {
DesiredAllocationSize = (DesiredAllocationSize + (BytesPerCluster - 1)) &
~(BytesPerCluster - 1);
//
// Check for the benign case that the file is already smaller than
// the desired truncation. Note that if it wraps, then a) it was
// specifying an offset in the maximally allocatable cluster and
// b) we're not asking to extend the file, either. So stop.
//
if (DesiredAllocationSize == 0 ||
DesiredAllocationSize >= FcbOrDcb->Header.AllocationSize.LowPart) {
DebugTrace(0, Dbg, "Desired size within current allocation.\n", 0);
DebugTrace(-1, Dbg, "FatTruncateFileAllocation -> (VOID)\n", 0);
return;
}
}
UnwindInitialAllocationSize = FcbOrDcb->Header.AllocationSize.LowPart;
UnwindInitialFirstClusterOfFile = FcbOrDcb->FirstClusterOfFile;
//
// Update the FcbOrDcb allocation size. If it is now zero, we have the
// additional task of modifying the FcbOrDcb and Dirent copies of
// FirstClusterInFile.
//
// Note that we must pin the dirent before actually deallocating the
// disk space since, in unwind, it would not be possible to reallocate
// deallocated disk space as someone else may have reallocated it and
// may cause an exception when you try to get some more disk space.
// Thus FatDeallocateDiskSpace must be the final dangerous operation.
//
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, FALSE, &Dirent, &Bcb );
Dirent->FirstClusterOfFile = 0;
if (FatIsFat32(Vcb)) {
Dirent->FirstClusterOfFileHi = 0;
}
FcbOrDcb->FirstClusterOfFile = 0;
FatSetDirtyBcb( IrpContext, Bcb, Vcb, TRUE );
UpdatedDirent = TRUE;
FatDeallocateDiskSpace( IrpContext, Vcb, &FcbOrDcb->Mcb );
FatRemoveMcbEntry( FcbOrDcb->Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF );
} else {
//
// Split the existing allocation into two parts, one we will keep, and
// one we will deallocate.
//
FsRtlInitializeLargeMcb( &RemainingMcb, PagedPool );
UnwindWeAllocatedMcb = TRUE;
FatSplitAllocation( IrpContext,
Vcb,
&FcbOrDcb->Mcb,
DesiredAllocationSize,
&RemainingMcb );
FatDeallocateDiskSpace( IrpContext, Vcb, &RemainingMcb );
FsRtlUninitializeLargeMcb( &RemainingMcb );
}
} finally {
DebugUnwind( FatTruncateFileAllocation );
//
// Is this really the right backout strategy? It would be nice if we could
// pretend the truncate worked if we knew that the file had gotten into
// a consistent state. Leaving dangled clusters is probably quite preferable.
//
if ( AbnormalTermination() ) {
FcbOrDcb->Header.AllocationSize.LowPart = UnwindInitialAllocationSize;
if ( (DesiredAllocationSize == 0) && (Dirent != NULL)) {
if (UpdatedDirent) {
//
// If the dirent has been updated ok and marked dirty, then we
// failed in deallocatediscspace, and don't know what state
// the on disc fat chain is in. So we throw away the mcb,
// and potentially loose a few clusters until the next
// chkdsk. The operation has succeeded, but the exception
// will still propogate. 5.1
//
FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF );
FcbOrDcb->Header.AllocationSize.QuadPart = 0;
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -