⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat.cxx

📁 EFI(Extensible Firmware Interface)是下一代BIOS
💻 CXX
📖 第 1 页 / 共 2 页
字号:
Return Value:

    The cluster number of the 'Index'th cluster in the cluster chain
    beginning with cluster 'StartingCluster' or 0.

--*/
{
    for (; Index; Index--) {

        if (!IsInRange(StartingCluster)) {
            return 0;
        }

        StartingCluster = QueryEntry(StartingCluster);
    }

    return StartingCluster;
}


UFAT_EXPORT
ULONG
FAT::QueryLengthOfChain(
    IN  ULONG    StartingCluster,
    OUT PULONG   LastCluster
    ) CONST
/*++

Routine Description:

    This routine computes the length of a cluster chain given the number
    of its first cluster.

    This routine depends on the chain being valid.  In particular, if the
    chain contains any cycles then this routine will not finish.  The
    routine 'ScrubChain' will turn an invalid chain into a valid one.

Arguments:

    StartingCluster - Supplies the first cluster of a cluster chain.
    LastCluster     - Returns the number of the last cluster in the chain.

Return Value:

    The length of the cluster chain beginning with 'StartingCluster'.

--*/
{
    ULONG    length;

    if (!StartingCluster) {
        if (LastCluster) {
            *LastCluster = 0;
        }
        return 0;
    }

    for (length = 1; IsInRange(StartingCluster) && !IsEndOfChain(StartingCluster); length++) {
        StartingCluster = QueryEntry(StartingCluster);
    }

    if (LastCluster) {
        *LastCluster = StartingCluster;
    }

    return length;
}


ULONG
FAT::QueryLengthOfChain(
    IN  ULONG    StartingCluster,
    IN  ULONG    EndingCluster
    ) CONST
/*++

Routine Description:

    This routine computes the length of a cluster chain given the number
    of its first cluster and the number of its last cluster.  To compute
    the length of a chain which is terminated by "end of chain", see
    the one parameter version of this routine above.  If 'EndingCluster'
    is not a member of the chain beginning with 'StartingCluster' then
    this routine will return 0.

    This routine depends on the chain being valid.

Arguments:

    StartingCluster - Supplies the first cluster of the cluster chain.
    EndingCluster   - Supplies the last cluster of the cluster chain.

Return Value:

    The length of the cluster chain beginning with 'StartingCluster' and
    ending with 'EndingCluster' or 0.

--*/
{
    ULONG    length;

    if (!StartingCluster) {
        return 0;
    }

    for (length = 1; StartingCluster != EndingCluster &&
                     !IsEndOfChain(StartingCluster); length++) {
        StartingCluster = QueryEntry(StartingCluster);
    }

    return StartingCluster == EndingCluster ? length : 0;
}


ULONG
FAT::QueryPrevious(
    IN  ULONG    Cluster
    ) CONST
/*++

Routine Description:

    Obtains the previous cluster in a chain, i.e. the cluster that
    references the given cluster.

Arguments:

    Cluster -   Supplies the cluster whose predecesor we're looking for.

Return Value:

    The predecesor of the given cluster. 0 if there is no predecesor.

--*/

{
    ULONG    i;

    DebugAssert( Cluster );

    if ( !IsClusterFree( Cluster ) ) {
        for (i = FirstDiskCluster; IsInRange(i); i++) {
            if ( QueryEntry(i) == Cluster ) {
                return i;
            }
        }
    }

    return 0;
}


VOID
FAT::Scrub(
    OUT PBOOLEAN    ChangesMade
    )
/*++

Routine Description:

    This routine goes through all of the FAT entries changing invalid values
    to reasonable values for the purposes of CHKDSK.

    Illegal FAT entries are those that are set out of disk range and that
    are not magic values.  This routine will set all illegal FAT entries to
    the "end of chain" magic value.

Arguments:

    ChangesMade - Returns TRUE if any changes were made to the FAT.

Return Value:

    None.

--*/
{
    ULONG    i;

    if (ChangesMade) {
        *ChangesMade = FALSE;
    }

    for (i = FirstDiskCluster; IsInRange(i); i++) {
        if (!IsInRange(QueryEntry(i)) &&
            !IsClusterFree(i) &&
            !IsEndOfChain(i) &&
            !IsClusterBad(i) &&
            !IsClusterReserved(i)) {

            SetEndOfChain(i);

            if (ChangesMade) {
                *ChangesMade = TRUE;
            }
        }
    }
}


VOID
FAT::ScrubChain(
    IN      ULONG        StartingCluster,
    OUT     PBOOLEAN     ChangesMade
    )
/*++

Routine Description:

    This routine goes through all of the FAT entries in the chain beginning
    with cluster 'StartingCluster'.  It is expected that all of the entries
    in this chain point to valid clusters on the disk.  This routine will
    mark the first invalid entry, if any, as the final cluster of the chain
    thus transforming the invalid chain into a valid one.

Arguments:

    StartingCluster - Supplies the first cluster of the chain to
                      scrub.
    ChangesMade     - Returns TRUE if changes were made to correct
                      the chain.

Return Value:

    None.

--*/
{
    ULONG    clus, next;

    DebugAssert(IsInRange(StartingCluster));
    DebugAssert(ChangesMade);

    *ChangesMade = FALSE;

    clus = StartingCluster;
    while (!IsEndOfChain(clus)) {

        next = QueryEntry(clus);
        if (!IsInRange(next) || IsClusterFree(next)) {
            SetEndOfChain(clus);
            *ChangesMade = TRUE;
            return;
        }

        clus = next;
    }
}


VOID
FAT::ScrubChain(
    IN      ULONG       StartingCluster,
    OUT     PBITVECTOR  FatBitMap,
    OUT     PBOOLEAN    ChangesMade,
    OUT     PBOOLEAN    CrossLinkDetected,
    OUT     PULONG      CrossLinkPreviousCluster
    )
/*++

Routine Description:

    This routine goes through all of the FAT entries in the chain beginning
    with cluster 'StartingCluster'.  It is expected that all of the entries
    in this chain point to valid clusters on the disk.  This routine will
    mark the first invalid entry, if any, as the final cluster of the chain
    thus transforming the invalid chain into a valid one.

    This routine will also eliminate any cycles in the cluster chain as well
    as detect cross-links.

Arguments:

    StartingCluster             - Supplies the first cluster of the chain to
                                    scrub.
    UsedClusters                - Supplies a bitvector marking all used
                                    clusters.
    ChangesMade                 - Returns TRUE if changes were made to correct
                                    the chain.
    CrossLinkDetected           - Returns TRUE if a cluster in the chain was
                                    already claimed in the 'FatBitMap'.
    CrossLinkPreviousCluster    - Returns the cluster number previous to the
                                    cross linked cluster number or 0 if the
                                    cross linked cluster number was the first
                                    in the chain.

Return Value:

    None.

--*/
{
    ULONG    clus, next;

    DebugAssert(IsInRange(StartingCluster));
    DebugAssert(ChangesMade);
    DebugAssert(CrossLinkDetected);
    DebugAssert(CrossLinkPreviousCluster);

    *ChangesMade = FALSE;
    *CrossLinkDetected = FALSE;

    if (FatBitMap->IsBitSet(StartingCluster)) {
        *CrossLinkDetected = TRUE;
        *CrossLinkPreviousCluster = 0;
        return;
    }

    clus = StartingCluster;
    while (!IsEndOfChain(clus)) {

        FatBitMap->SetBit(clus);

        next = QueryEntry(clus);
        if (!IsInRange(next) || IsClusterFree(next)) {
            SetEndOfChain(clus);
            *ChangesMade = TRUE;
            return;
        }

        if (FatBitMap->IsBitSet(next)) {

            if (clus == next) {       // Cluster points to itself.
                *ChangesMade = TRUE;
                SetEndOfChain(clus);
                return;
            }

            while (StartingCluster != clus) {

                if (StartingCluster == next) { // Cluster points to previous.
                    *ChangesMade = TRUE;
                    SetEndOfChain(clus);
                    return;
                }

                StartingCluster = QueryEntry(StartingCluster);
            }

            // Otherwise it's a cross link, not a cycle.

            *CrossLinkDetected = TRUE;
            *CrossLinkPreviousCluster = clus;
            return;
        }

        clus = next;
    }

    FatBitMap->SetBit(clus);
}

NONVIRTUAL
BOOLEAN
FAT::IsValidChain(
    IN  ULONG    StartingCluster
    ) CONST
/*++

Routine Description:

    This method determines whether the chain is valid, ie. that it
    consists of a chain of valid cluster numbers ending with an end
    of chain entry.

Arguments:

    StartingCluster - Supplies the first cluster of the chain.

Return Value:

    TRUE if the chain is valid.

--*/
{
    ULONG    current;
    ULONG    clusters_in_chain = 0;

    current = StartingCluster;

    for( ;; ) {

        if (!IsInRange(current) ||
            clusters_in_chain++ > _num_entries ) {

            // Either a bad entry or an infinite loop detected.
            //
            return FALSE;
        }

        if (IsEndOfChain(current)) {
            break;
        }

        current = QueryEntry(current);
    }

    return TRUE;
}


UFAT_EXPORT
ULONG
FAT::AllocChain(
    IN  ULONG    Length,
    OUT PULONG   LastCluster
    )
/*++

Routine Description:

    This routine attempts to allocate a chain of length 'Length' from the
    FAT.  If this routine is successful it will return the cluster number
    of the beginning of the chain.  Upon failure this routine will return
    0 and will make no changes to the FAT.

Arguments:

    Length      - Supplies the length of the chain desired.
    LastCluster - Returns the last cluster of the allocated chain.

Return Value:

    The cluster number of the beginning of the allocated chain or 0.

--*/
{
    ULONG    i, j;
    ULONG    start;
    ULONG    prev;

    if (!Length) {
        return 0;
    }

    start = 0;
    prev = 0;
    for (i = FirstDiskCluster; IsInRange(i); i++) {
        if (IsClusterFree(i)) {
            if (!start) {
                start = i;
            } else {
                SetEntry(prev, i);
            }
            prev = i;
            Length--;
            if (!Length) {
                SetEndOfChain(i);

                if (LastCluster) {
                    *LastCluster = i;
                }

                return start;
            }
        }
    }

    // There is not enough disk space for the chain so free what was taken.
    for (i = start; i != prev; ) {
        j = QueryEntry(i);
        SetClusterFree(i);
        i = j;
    }

    return 0;
}


ULONG
FAT::ReAllocChain(
    IN  ULONG    StartOfChain,
    IN  ULONG    NewLength,
    OUT PULONG   LastCluster
    )
/*++

Routine Description:

    This routine insures that the cluster chain beginning at cluster
    'StartOfChain' is of length greater than or equal to 'NewSize'.
    If it is not then this routine will attempt to grow the chain by
    allocating new clusters.  Failure to allocate sufficient clusters
    to grow the chain to 'NewSize' clusters will cause this routine to
    restore the chain to its original length and state.  This routine will
    return the current length of the chain : either the old length or the
    new length.  If an error occurs then 0 will be returned.

Arguments:

    StartOfChain    - Supplies the first cluster of the chain.
    NewLength       - Supplies the desired new length of the chain.
    LastCluster     - Returns the last cluster of the chain.

Return Value:

    The current length of the chain or 0.

--*/
{
    ULONG    length;
    ULONG    new_clusters_needed;
    ULONG    end_of_chain;
    ULONG    i, j;
    ULONG    start;

    if (!IsInRange(StartOfChain)) {
        return 0;
    }

    for (length = 1; !IsEndOfChain(StartOfChain); length++) {
        StartOfChain = QueryEntry(StartOfChain);
        if (!IsInRange(StartOfChain)) {
            return 0;
        }
    }

    if (length >= NewLength) {
        if (LastCluster) {
            *LastCluster = StartOfChain;
        }
        return length;
    }

    new_clusters_needed = NewLength - length;

    start = end_of_chain = StartOfChain;
    for (i = FirstDiskCluster; IsInRange(i); i++) {
        if (IsClusterFree(i)) {
            SetEntry(end_of_chain, i);
            end_of_chain = i;
            new_clusters_needed--;
            if (!new_clusters_needed) {
                SetEndOfChain(i);
                if (LastCluster) {
                    *LastCluster = i;
                }
                return NewLength;
            }
        }
    }

    // There is not enough disk space to lengthen the new chain so
    // settle for the old length.

    for (i = start; i != end_of_chain; ) {
        j = QueryEntry(i);
        SetClusterFree(i);
        i = j;
    }

    SetEndOfChain(start);

    if (LastCluster) {
        *LastCluster = start;
    }

    return length;
}


UFAT_EXPORT
VOID
FAT::FreeChain(
    IN  ULONG    StartOfChain
    )
/*++

Routine Description:

    This routine sets free all of the clusters in the cluster chain
    beginning with 'StartOfChain'.

Arguments:

    StartOfChain    - Supplies the first cluster of the chain to free.

Return Value:

    None.

--*/
{
    ULONG    tmp;

    while (!IsEndOfChain(StartOfChain)) {
        tmp = QueryEntry(StartOfChain);
        SetClusterFree(StartOfChain);
        StartOfChain = tmp;
    }
    SetClusterFree(StartOfChain);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -