📄 allocsup.c
字号:
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
AllocSup.c
Abstract:
This module implements mappings to physical blocks on UDF media. The basic
structure used here is the Pcb, which contains lookup information for each
partition reference in the volume.
Author:
Dan Lovinger [DanLo] 5-Sep-1996
Revision History:
--*/
#include "UdfProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (UDFS_BUG_CHECK_ALLOCSUP)
//
// The local debug trace level
//
#define Dbg (UDFS_DEBUG_LEVEL_ALLOCSUP)
//
// Local support routines.
//
PPCB
UdfCreatePcb (
IN ULONG NumberOfPartitions
);
NTSTATUS
UdfLoadSparingTables(
PIRP_CONTEXT IrpContext,
PVCB Vcb,
PPCB Pcb,
ULONG Reference
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, UdfAddToPcb)
#pragma alloc_text(PAGE, UdfCompletePcb)
#pragma alloc_text(PAGE, UdfCreatePcb)
#pragma alloc_text(PAGE, UdfDeletePcb)
#pragma alloc_text(PAGE, UdfEquivalentPcb)
#pragma alloc_text(PAGE, UdfInitializePcb)
#pragma alloc_text(PAGE, UdfLookupAllocation)
#pragma alloc_text(PAGE, UdfLookupMetaVsnOfExtent)
#pragma alloc_text(PAGE, UdfLookupPsnOfExtent)
#endif
BOOLEAN
UdfLookupAllocation (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb,
IN LONGLONG FileOffset,
OUT PLONGLONG DiskOffset,
OUT PULONG ByteCount
)
/*++
Routine Description:
This routine looks through the mapping information for the file
to find the logical diskoffset and number of bytes at that offset.
This routine assumes we are looking up a valid range in the file. If
a mapping does not exist,
Arguments:
Fcb - Fcb representing this stream.
FileOffset - Lookup the allocation beginning at this point.
DiskOffset - Address to store the logical disk offset.
ByteCount - Address to store the number of contiguous bytes beginning
at DiskOffset above.
Return Value:
BOOLEAN - whether the extent is unrecorded data
--*/
{
PVCB Vcb;
BOOLEAN Recorded = TRUE;
BOOLEAN Result;
LARGE_INTEGER LocalPsn;
LARGE_INTEGER LocalSectorCount;
PAGED_CODE();
//
// Check inputs
//
ASSERT_IRP_CONTEXT( IrpContext );
ASSERT_FCB( Fcb );
//
// We will never be looking up the allocations of embedded objects.
//
ASSERT( !FlagOn( Fcb->FcbState, FCB_STATE_EMBEDDED_DATA ));
Vcb = Fcb->Vcb;
LocalPsn.QuadPart = LocalSectorCount.QuadPart = 0;
//
// Lookup the entry containing this file offset.
//
if (FlagOn( Fcb->FcbState, FCB_STATE_VMCB_MAPPING )) {
//
// Map this offset into the metadata stream.
//
ASSERT( SectorOffset( Vcb, FileOffset ) == 0 );
Result = UdfVmcbVbnToLbn( &Vcb->Vmcb,
SectorsFromBytes( Vcb, FileOffset ),
&LocalPsn.LowPart,
&LocalSectorCount.LowPart );
ASSERT( Result );
} else {
//
// Map this offset in a regular stream.
//
ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED ));
Result = FsRtlLookupLargeMcbEntry( &Fcb->Mcb,
LlSectorsFromBytes( Vcb, FileOffset ),
&LocalPsn.QuadPart,
&LocalSectorCount.QuadPart,
NULL,
NULL,
NULL );
}
//
// If within the Mcb then we use the data out of this entry and are nearly done.
//
if (Result) {
if ( LocalPsn.QuadPart == -1 ) {
//
// Regular files can have holey allocations which represent unrecorded extents. For
// such extents which are sandwiched in between recorded extents of the file, the Mcb
// package tells us that it found a valid mapping but that it doesn't correspond to
// any extents on the media yet. In this case, simply fake the disk offset. The
// returned sector count is accurate.
//
*DiskOffset = 0;
Recorded = FALSE;
} else {
//
// Now mimic the effects of physical sector sparing. This may shrink the size of the
// returned run if sparing interrupted the extent on disc.
//
ASSERT( LocalPsn.HighPart == 0 );
if (Vcb->Pcb->SparingMcb) {
LONGLONG SparingPsn;
LONGLONG SparingSectorCount;
if (FsRtlLookupLargeMcbEntry( Vcb->Pcb->SparingMcb,
LocalPsn.LowPart,
&SparingPsn,
&SparingSectorCount,
NULL,
NULL,
NULL )) {
//
// Only emit noise if we will really change anything as a result
// of the sparing table.
//
if (SparingPsn != -1 ||
SparingSectorCount < LocalSectorCount.QuadPart) {
DebugTrace(( 0, Dbg, "UdfLookupAllocation, spared [%x, +%x) onto [%x, +%x)\n",
LocalPsn.LowPart,
LocalSectorCount.LowPart,
(ULONG) SparingPsn,
(ULONG) SparingSectorCount ));
}
//
// If we did not land in a hole, map the sector.
//
if (SparingPsn != -1) {
LocalPsn.QuadPart = SparingPsn;
}
//
// The returned sector count now reduces the previous sector count.
// If we landed in a hole, this indicates that the trailing edge of
// the extent is spared, if not this indicates that the leading
// edge is spared.
//
if (SparingSectorCount < LocalSectorCount.QuadPart) {
LocalSectorCount.QuadPart = SparingSectorCount;
}
}
}
*DiskOffset = LlBytesFromSectors( Vcb, LocalPsn.QuadPart ) + SectorOffset( Vcb, FileOffset );
//
// Now we can apply method 2 fixups, which will again interrupt the size of the extent.
//
if (FlagOn( Vcb->VcbState, VCB_STATE_METHOD_2_FIXUP )) {
LARGE_INTEGER SectorsToRunout;
SectorsToRunout.QuadPart= UdfMethod2NextRunoutInSectors( Vcb, *DiskOffset );
if (SectorsToRunout.QuadPart < LocalSectorCount.QuadPart) {
LocalSectorCount.QuadPart = SectorsToRunout.QuadPart;
}
*DiskOffset = UdfMethod2TransformByteOffset( Vcb, *DiskOffset );
}
}
} else {
//
// We know that prior to this call the system has restricted IO to points within the
// the file data. Since we failed to find a mapping this is an unrecorded extent at
// the end of the file, so just conjure up a proper representation.
//
ASSERT( FileOffset < Fcb->FileSize.QuadPart );
*DiskOffset = 0;
LocalSectorCount.QuadPart = LlSectorsFromBytes( Vcb, Fcb->FileSize.QuadPart ) -
LlSectorsFromBytes( Vcb, FileOffset ) +
1;
Recorded = FALSE;
}
//
// Restrict to MAXULONG bytes of allocation
//
if (LocalSectorCount.QuadPart > SectorsFromBytes( Vcb, MAXULONG )) {
*ByteCount = MAXULONG;
} else {
*ByteCount = BytesFromSectors( Vcb, LocalSectorCount.LowPart );
}
*ByteCount -= SectorOffset( Vcb, FileOffset );
return Recorded;
}
VOID
UdfDeletePcb (
IN PPCB Pcb
)
/*++
Routine Description:
This routine deallocates a Pcb and all ancilliary structures.
Arguments:
Pcb - Pcb being deleted
Return Value:
None
--*/
{
PPARTITION Partition;
if (Pcb->SparingMcb) {
FsRtlUninitializeLargeMcb( Pcb->SparingMcb );
UdfFreePool( &Pcb->SparingMcb );
}
for (Partition = Pcb->Partition;
Partition < &Pcb->Partition[Pcb->Partitions];
Partition++) {
switch (Partition->Type) {
case Physical:
UdfFreePool( &Partition->Physical.PartitionDescriptor );
UdfFreePool( &Partition->Physical.SparingMap );
break;
case Virtual:
case Uninitialized:
break;
default:
ASSERT( FALSE );
break;
}
}
ExFreePool( Pcb );
}
NTSTATUS
UdfInitializePcb (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb,
IN OUT PPCB *Pcb,
IN PNSR_LVOL LVD
)
/*++
Routine Description:
This routine walks through the partition map of a Logical Volume Descriptor
and builds an intializing Pcb from it. The Pcb will be ready to be used
in searching for the partition descriptors of a volume.
Arguments:
Vcb - The volume this Pcb will pertain to
Pcb - Caller's pointer to the Pcb
LVD - The Logical Volume Descriptor being used
Return Value:
STATUS_SUCCESS if the partition map is good and the Pcb is built
STATUS_DISK_CORRUPT_ERROR if corrupt maps are found
STATUS_UNRECOGNIZED_VOLUME if noncompliant maps are found
--*/
{
PPARTMAP_UDF_GENERIC Map;
PPARTITION Partition;
BOOLEAN Found;
PAGED_CODE();
//
// Check the input parameters
//
ASSERT_OPTIONAL_PCB( *Pcb );
DebugTrace(( +1, Dbg,
"UdfInitializePcb, Lvd %08x\n",
LVD ));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -