windows-nt/Source/XPSP1/NT/base/fs/utils/ufat/inc/fat.hxx
2020-09-26 16:20:57 +08:00

1090 lines
19 KiB
C++

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
fat.hxx
Abstract:
This class models a file allocation table. The composition is of
virtual functions because there are two different kinds of file
allocation tables. A user of this class will be able to manipulate
the FAT regardless of the implementation.
Author:
Norbert P. Kusters (norbertk) 6-Dec-90
--*/
#if !defined(FAT_DEFN)
#define FAT_DEFN
#include "secrun.hxx"
#if defined ( _AUTOCHECK_ )
#define UFAT_EXPORT
#elif defined ( _UFAT_MEMBER_ )
#define UFAT_EXPORT __declspec(dllexport)
#else
#define UFAT_EXPORT __declspec(dllimport)
#endif
//
// Forward references
//
DECLARE_CLASS( FAT );
DECLARE_CLASS( BITVECTOR );
CONST ULONG FirstDiskCluster = 2;
CONST ULONG MaxNumClusForSmallFat = 4086;
// - flags to denote three state FAT type
CONST ULONG MinNumClusForFat32 = 65526; // Min # Fat32 clusters is 65525
// The largest FAT16 entry goes
// up to 65527
CONST fFat12 = 12;
CONST fFat16 = 16;
CONST fFat32 = 32;
class FAT : public SECRUN {
public:
DECLARE_CONSTRUCTOR(FAT);
VIRTUAL
~FAT(
);
NONVIRTUAL
BOOLEAN
Initialize(
IN OUT PMEM Mem,
IN OUT PLOG_IO_DP_DRIVE Drive,
IN LBN StartSector,
IN ULONG NumOfEntries,
IN ULONG NumSectors DEFAULT 0
);
NONVIRTUAL
BOOLEAN
Initialize(
IN OUT PSECRUN Srun,
IN OUT PMEM Mem,
IN OUT PLOG_IO_DP_DRIVE Drive,
IN LBN StartSector,
IN ULONG NumOfEntries,
IN ULONG NumSectors DEFAULT 0
);
NONVIRTUAL
ULONG
QueryEntry(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
VOID
SetEntry(
IN ULONG ClusterNumber,
IN ULONG Value
);
NONVIRTUAL
BOOLEAN
IsInRange(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
BOOLEAN
IsClusterFree(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
VOID
SetClusterFree(
IN ULONG ClusterNumber
);
NONVIRTUAL
BOOLEAN
IsEndOfChain(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
VOID
SetEndOfChain(
IN ULONG ClusterNumber
);
NONVIRTUAL
BOOLEAN
IsClusterBad(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
VOID
SetClusterBad(
IN ULONG ClusterNumber
);
NONVIRTUAL
BOOLEAN
IsClusterReserved(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
VOID
SetClusterReserved(
IN ULONG ClusterNumber
);
NONVIRTUAL
VOID
SetEarlyEntries(
IN UCHAR MediaByte
);
NONVIRTUAL
UCHAR
QueryMediaByte(
) CONST;
NONVIRTUAL
ULONG
QueryFreeClusters(
) CONST;
NONVIRTUAL
ULONG
QueryBadClusters(
) CONST;
NONVIRTUAL
ULONG
QueryReservedClusters(
) CONST;
NONVIRTUAL
UFAT_EXPORT
ULONG
QueryAllocatedClusters(
) CONST;
NONVIRTUAL
UFAT_EXPORT
ULONG
QueryNthCluster(
IN ULONG StartingCluster,
IN ULONG Index
) CONST;
NONVIRTUAL
UFAT_EXPORT
ULONG
QueryLengthOfChain(
IN ULONG StartingCluster,
OUT PULONG LastCluster DEFAULT NULL
) CONST;
NONVIRTUAL
ULONG
QueryLengthOfChain(
IN ULONG StartingCluster,
IN ULONG EndingCluster
) CONST;
NONVIRTUAL
ULONG
QueryPrevious(
IN ULONG Cluster
) CONST;
NONVIRTUAL
VOID
Scrub(
OUT PBOOLEAN ChangesMade DEFAULT NULL
);
NONVIRTUAL
VOID
ScrubChain(
IN ULONG StartingCluster,
OUT PBOOLEAN ChangesMade
);
NONVIRTUAL
VOID
ScrubChain(
IN ULONG StartingCluster,
OUT PBITVECTOR UsedClusters,
OUT PBOOLEAN ChangesMade,
OUT PBOOLEAN CrossLinkDetected,
OUT PULONG CrossLinkPreviousCluster
);
NONVIRTUAL
BOOLEAN
IsValidChain(
IN ULONG StartingCluster
) CONST;
NONVIRTUAL
UFAT_EXPORT
ULONG
AllocChain(
IN ULONG Length,
OUT PULONG LastCluster DEFAULT NULL
);
NONVIRTUAL
ULONG
ReAllocChain(
IN ULONG StartOfChain,
IN ULONG NewLength,
OUT PULONG LastCluster DEFAULT NULL
);
NONVIRTUAL
UFAT_EXPORT
VOID
FreeChain(
IN ULONG StartOfChain
);
NONVIRTUAL
ULONG
RemoveChain(
IN ULONG PreceedingCluster,
IN ULONG LastCluster
);
NONVIRTUAL
VOID
InsertChain(
IN ULONG StartOfChain,
IN ULONG EndOfChain,
IN ULONG PreceedingCluster
);
NONVIRTUAL
ULONG
InsertChain(
IN ULONG StartOfChain,
IN ULONG Cluster
);
NONVIRTUAL
ULONG
QueryAllocatedClusterCount(
VOID
) ;
NONVIRTUAL
VOID
InvalidateAllocatedClusterCount(
VOID
) ;
private:
NONVIRTUAL
VOID
Construct(
);
NONVIRTUAL
VOID
Destroy(
);
NONVIRTUAL
ULONG
Index(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
UFAT_EXPORT
ULONG
Index12(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
ULONG
Index16(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
ULONG
Index32(
IN ULONG ClusterNumber
) CONST;
NONVIRTUAL
VOID
Set(
IN ULONG ClusterNumber,
IN ULONG Value
);
NONVIRTUAL
UFAT_EXPORT
VOID
Set12(
IN ULONG ClusterNumber,
IN ULONG Value
);
NONVIRTUAL
VOID
Set16(
IN ULONG ClusterNumber,
IN ULONG Value
);
NONVIRTUAL
VOID
Set32(
IN ULONG ClusterNumber,
IN ULONG Value
);
PVOID _fat;
ULONG _num_entries;
ULONG _low_end_of_chain; // 0xFFF8 or 0x0FF8
ULONG _end_of_chain; // 0xFFFF or 0x0FFF
ULONG _bad_cluster; // 0xFFF7 or 0x0FF7
ULONG _low_reserved; // 0xFFF0 or 0x0FF0
ULONG _high_reserved; // 0xFFF6 or 0x0FF6
UCHAR _fat_bits; // Replacing _is_big with count of bits in FAT entry
// BOOLEAN _is_big; // Boolean TRUE for FAT16, FALSE for FAT12
ULONG _AllocatedClusters; // Count of allocated clusters
};
INLINE
BOOLEAN
FAT::IsInRange(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine computes whether or not ClusterNumber is a cluster on
the disk.
Arguments:
ClusterNumber - Supplies the cluster to be checked.
Return Value:
FALSE - The cluster is not on the disk.
TRUE - The cluster is on the disk.
--*/
{
return (FirstDiskCluster <= ClusterNumber && ClusterNumber < _num_entries);
}
INLINE
ULONG
FAT::Index16(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine indexes the FAT as 16 bit little endian entries.
Arguments:
ClusterNumber - Supplies the FAT entry desired.
Return Value:
The value of the FAT entry at ClusterNumber.
--*/
{
//DebugAssert(IsInRange(ClusterNumber));
return (ULONG )(((PUSHORT) _fat)[ClusterNumber]);
}
INLINE
ULONG
FAT::Index32(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine indexes the FAT as 32 bit little endian entries.
Arguments:
ClusterNumber - Supplies the FAT entry desired.
Return Value:
The value of the 32 (actually 28) bit FAT entry at ClusterNumber.
--*/
{
//DebugAssert(IsInRange(ClusterNumber));
return (((PULONG) _fat)[ClusterNumber]) & 0x0FFFFFFF;
}
INLINE
ULONG
FAT::Index(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine indexes the FAT as 16 bit or 12 bit little endian entries.
Arguments:
ClusterNumber - Supplies the FAT entry desired.
Return Value:
The value of the FAT entry at ClusterNumber.
--*/
{
if (fFat12 == _fat_bits)
return Index12(ClusterNumber);
else if (fFat16 == _fat_bits)
return Index16(ClusterNumber);
else
return Index32(ClusterNumber);
}
INLINE
VOID
FAT::Set16(
IN ULONG ClusterNumber,
IN ULONG Value
)
/*++
Routine Description:
This routine sets the ClusterNumber'th 16 bit FAT entry to Value.
Arguments:
ClusterNumber - Supplies the FAT entry to set.
Value - Supplies the value to set the FAT entry to.
Return Value:
None.
--*/
{
//DebugAssert(IsInRange(ClusterNumber));
((PUSHORT) _fat)[ClusterNumber] = (USHORT)Value;
_AllocatedClusters = 0xFFFFFFFF;
}
INLINE
VOID
FAT::Set32(
IN ULONG ClusterNumber,
IN ULONG Value
)
/*++
Routine Description:
This routine sets the ClusterNumber'th 32 (actually 28) bit FAT entry to Value.
Arguments:
ClusterNumber - Supplies the FAT entry to set.
Value - Supplies the value to set the FAT entry to.
Return Value:
None.
--*/
{
//DebugAssert(IsInRange(ClusterNumber));
((PULONG) _fat)[ClusterNumber] &= 0xF0000000;
((PULONG) _fat)[ClusterNumber] |= (Value & 0x0FFFFFFF);
_AllocatedClusters = 0xFFFFFFFF;
}
INLINE
VOID
FAT::Set(
IN ULONG ClusterNumber,
IN ULONG Value
)
/*++
Routine Description:
This routine sets the ClusterNumber'th 12 bit or 16 bit FAT entry to Value.
Arguments:
ClusterNumber - Supplies the FAT entry to set.
Value - Supplies the value to set the FAT entry to.
Return Value:
None.
--*/
{
if (fFat12 == _fat_bits)
Set12(ClusterNumber, Value);
else if (fFat16 == _fat_bits)
Set16(ClusterNumber, Value);
else
Set32(ClusterNumber, Value);
}
INLINE
ULONG
FAT::QueryEntry(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine returns the FAT value for ClusterNumber.
Arguments:
ClusterNumber - Supplies an index into the FAT.
Return Value:
The FAT table entry at offset ClusterNumber.
--*/
{
return Index(ClusterNumber);
}
INLINE
ULONG
FAT::QueryAllocatedClusterCount(
)
/*++
Routine Description:
This routine computes the total number of clusters for the volume.
which are allocated.
Arguments:
None.
Return Value:
The total number of allocated clusters for the volume.
--*/
{
if(_AllocatedClusters == 0xFFFFFFFF)
{
if(_fat == NULL) {
return(0);
}
_AllocatedClusters = FAT::QueryAllocatedClusters();
}
return _AllocatedClusters;
}
INLINE
VOID
FAT::InvalidateAllocatedClusterCount(
)
/*++
Routine Description:
This routine invalidates trhe cached allocated clusters count so that the next
call to QueryAllocatedClusterCount will re-compute it.
Arguments:
None.
Return Value:
None.
--*/
{
_AllocatedClusters = 0xFFFFFFFF;
return;
}
INLINE
VOID
FAT::SetEntry(
IN ULONG ClusterNumber,
IN ULONG Value
)
/*++
Routine Description:
This routine sets the FAT entry at ClusterNumber to Value.
Arguments:
ClusterNumber - Supplies the position in the FAT to update.
Value - Supplies the new value for that position.
Return Value:
None.
--*/
{
Set(ClusterNumber, Value);
}
INLINE
BOOLEAN
FAT::IsClusterFree(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine computes whether of not ClusterNumber is a free cluster.
Arguments:
ClusterNumber - Supplies the cluster to be checked.
Return Value:
FALSE - The cluster is not free.
TRUE - The cluster is free.
--*/
{
return Index(ClusterNumber) == 0;
}
INLINE
VOID
FAT::SetClusterFree(
IN ULONG ClusterNumber
)
/*++
Routine Description:
This routine marks the cluster ClusterNumber as free on the FAT.
Arguments:
ClusterNumber - Supplies the number of the cluster to mark free.
Return Value:
None.
--*/
{
Set(ClusterNumber, 0);
}
INLINE
BOOLEAN
FAT::IsEndOfChain(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine computes whether or not the cluster ClusterNumber is the
end of its cluster chain.
Arguments:
ClusterNumber - Supplies the cluster to be checked.
Return Value:
FALSE - The cluster is not the end of a chain.
TRUE - The cluster is the end of a chain.
--*/
{
return Index(ClusterNumber) >= _low_end_of_chain;
}
INLINE
VOID
FAT::SetEndOfChain(
IN ULONG ClusterNumber
)
/*++
Routine Description:
This routine sets the cluster ClusterNumber to the end of its cluster
chain.
Arguments:
ClusterNumber - Supplies the cluster to be set to end of chain.
Return Value:
None.
--*/
{
Set(ClusterNumber, _end_of_chain);
}
INLINE
BOOLEAN
FAT::IsClusterBad(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine computes whether or not cluster ClusterNumber is bad.
Arguments:
ClusterNumber - Supplies the number of the cluster to be checked.
Return Value:
FALSE - The cluster is good.
TRUE - The cluster is bad.
--*/
{
return Index(ClusterNumber) == _bad_cluster;
}
INLINE
VOID
FAT::SetClusterBad(
IN ULONG ClusterNumber
)
/*++
Routine Description:
This routine sets the cluster ClusterNumber to bad on the FAT.
Arguments:
ClusterNumber - Supplies the cluster number to mark bad.
Return Value:
None.
--*/
{
Set(ClusterNumber, _bad_cluster);
}
INLINE
BOOLEAN
FAT::IsClusterReserved(
IN ULONG ClusterNumber
) CONST
/*++
Routine Description:
This routine computes whether or not the cluster ClusterNumber is
a reserved cluster.
Arguments:
ClusterNumber - Supplies the cluster to check.
Return Value:
FALSE - The cluster is not reserved.
TRUE - The cluster is reserved.
--*/
{
return Index(ClusterNumber) >= _low_reserved &&
Index(ClusterNumber) <= _high_reserved;
}
INLINE
VOID
FAT::SetClusterReserved(
IN ULONG ClusterNumber
)
/*++
Routine Description:
This routine marks the cluster ClusterNumber as reserved in the FAT.
Arguments:
ClusterNumber - Supplies the cluster to mark reserved.
Return Value:
None.
--*/
{
Set(ClusterNumber, _low_reserved);
}
INLINE
UCHAR
FAT::QueryMediaByte(
) CONST
/*++
Routine Description:
The media byte for the partition is stored in the first character of the
FAT. This routine will return its value provided that the two following
bytes are 0xFF.
Arguments:
None.
Return Value:
The media byte for the partition.
--*/
{
PUCHAR p;
p = (PUCHAR) _fat;
DebugAssert(p);
return (p[2] == 0xFF && p[1] == 0xFF && ((fFat12 != _fat_bits) ? (0x0F == (p[3] & 0x0F)) : TRUE)) ? p[0] : 0;
}
INLINE
VOID
FAT::SetEarlyEntries(
IN UCHAR MediaByte
)
/*++
Routine Description:
This routine sets the first two FAT entries as required by the
FAT file system. The first byte gets set to the media descriptor.
The remaining bytes gets set to FF.
Arguments:
MediaByte - Supplies the media byte for the volume.
Return Value:
None.
--*/
{
PUCHAR p;
p = (PUCHAR) _fat;
DebugAssert(p);
p[0] = MediaByte;
p[1] = p[2] = 0xFF;
if (fFat32 == _fat_bits) {
p[3] = 0x0F;
p[4] = 0xFF;
p[5] = 0xFF;
p[6] = 0xFF;
p[7] = 0x0F;
#if 0
// allocate cluster 2 for the root (set 2=end of chain)
p[8] = 0xFF;
p[9] = 0xFF;
p[10] = 0xFF;
p[11] = 0x0F;
#endif
} else if (fFat16 == _fat_bits) {
p[3] = 0xFF;
}
_AllocatedClusters = 0xFFFFFFFF;
}
INLINE
ULONG
FAT::RemoveChain(
IN ULONG PreceedingCluster,
IN ULONG LastCluster
)
/*++
Routine Description:
This routine removes a subchain of length 'Length' from a containing
chain. This routine cannot remove subchains beginning at the head
of the containing chain. To do this use the routine named
'SplitChain'.
This routine returns the number of the first cluster of the
removed subchain. The FAT is edited so that the removed subchain
is promoted to a full chain.
Arguments:
PreceedingCluster - Supplies the cluster which preceeds the one to be
removed in the chain.
LastCluster - Supplies the last cluster of the chain to remove.
Return Value:
The cluster number for the head of the chain removed.
--*/
{
ULONG r;
r = QueryEntry(PreceedingCluster);
SetEntry(PreceedingCluster, QueryEntry(LastCluster));
SetEndOfChain(LastCluster);
return r;
}
INLINE
VOID
FAT::InsertChain(
IN ULONG StartOfChain,
IN ULONG EndOfChain,
IN ULONG PreceedingCluster
)
/*++
Routine Description:
This routine inserts one chain into another chain. This routine
cannot insert a chain at the head of another chain. To do this
use the routine named 'JoinChains'.
Arguments:
StartOfChain - Supplies the first cluster of the chain to insert.
EndOfChain - Supplies the last cluster of the chain to insert.
PreceedingCluster - Supplies the cluster immediately preceeding the
position where the chain is to be inserted.
Return Value:
None.
--*/
{
SetEntry(EndOfChain, QueryEntry(PreceedingCluster));
SetEntry(PreceedingCluster, StartOfChain);
}
INLINE
ULONG
FAT::InsertChain(
IN ULONG StartOfChain,
IN ULONG Cluster
)
/*++
Routine Description:
This routine inserts one cluster at the head of a chain.
Arguments:
StartOfChain - Supplies the first cluster of the chain to insert.
Cluster - Supplies the cluster to be inserted
Return Value:
ULONG - The new head of the chain (i.e. Cluster )
--*/
{
if ( StartOfChain ) {
SetEntry( Cluster, StartOfChain );
} else {
SetEndOfChain( Cluster );
}
return Cluster;
}
#endif // FAT_DEFN