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

📄 lowl.c

📁 ertfs文件系统里面既有完整ucos程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1996
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* LOWL.C - Low level File allocation table management functions. 

    Routines in this file include:

    pc_alloc_chain      -   Allocate a chain from the FAT.
    pc_find_free_cluster-   Find the first free cluster in a given range.
    pc_clalloc          -   Allocate a single cluster in the fragmented region.
    pc_clgrow           -   Grow a directory chain in the fragmented region.
    pc_clnext           -   Get the next cluster in a chain.
    pc_clrelease        -   Return a cluster to the free list.
    pc_faxx             -   Get a value from the FAT.
    pc_flushfat         -   Make sure the FAT is up to date on disk.
    pc_freechain        -   Release a chain to the free list.
    pc_cl_truncate      -   Truncate a cluster chain.
    pc_get_chain        -   Return contiguous clusters in a chain.
    pc_pfaxx            -   Put a value to the FAT.
    pc_pfswap           -   Swap a block of the FAT into the cache.
    pc_fword            -   Get or put a value from the swap cache.
    pc_pfflush          -   Flush the swap cache to disk.
    pc_gblk0            -   Read block zero and set up internal structures.
    pc_clzero           -   Write zeroes to a cluster on disk.
    pc_drno2dr          -   Convert a drive number to a drive structure.
    pc_dskfree          -   Free resources associated with a drive.
    pc_ifree            -   Calculate free space from the FAT.
    pc_sec2cluster      -   Convert a sector number to a cluster value.
    pc_sec2index        -   Convert a sector number to a cluster offset.
    pc_cl2sector        -   Convert a cluster value to a sector number.
    partition_init      -   Interpret a partition table

*/      

#ifndef __PCDISK__  /* This allows us to build the lib with subroutines split */
#include <pcdisk.h>
#endif


RTFS_FILE(allocch.c, pc_alloc_chain)
#ifndef __PCDISK__  /* This allows us to build the lib with subroutines split */
#include <pcdisk.h>
#endif

/******************************************************************************
    PC_ALLOC_CHAIN  -  Allocate as many contiguous clusters as possible.

 Description
        Reserve up to n_clusters contiguous clusters from the FAT and
        return the number of contiguous clusters reserved.
        If pstart_cluster points to a valid cluster link the new chain
        to it.
    
 Returns
    Returns the number of contiguous clusters found. Or zero on an error.
    pstart_cluster contains the address of the start of the chain on
    return.

*****************************************************************************/
#if (RTFS_WRITE)

/* ======================================================================
A bug was just reported in rtfs where it was possible on a fairly full disk 
to have a write fail reporting no space on the drive when there really is
enough space. The problem happens when the following condition is 
true. A file is open for writing and there are no more free clusters 
available in the file allocation table between the last cluster used by 
the file and the and the end of the FAT .. and .. the first 1 / 32 of the 
drive is also already filled up. RTFS favors putting directory information
in the first 1/32 of the drive so this region doesn't usually fill up.

The bug is quite old and has only recently been discovered.

To fix the problem replace the contents of the routine pc_alloc_chain() 
in lowl.c with this code.
*/
CLUSTERTYPE pc_alloc_chain(DDRIVE *pdr, CLUSTERTYPE *pstart_cluster, CLUSTERTYPE n_clusters) /*__fn__*/
{
    CLUSTERTYPE start_cluster;
    CLUSTERTYPE first_new_cluster;
    CLUSTERTYPE clno;
    CLUSTERTYPE n_contig;
    CLUSTERTYPE value;
    CLUSTERTYPE last_cluster;   /* NEW for 5/18/97 bug fix */

    start_cluster = *pstart_cluster;

    if (start_cluster && 
        ( (start_cluster < 2) || (start_cluster > pdr->maxfindex) ) )
        return (0);

    /* If the user provided a cluster we find the next cluster beyond that
        one. Otherwise we look at the disk structure and find the next 
        free cluster in the free cluster region after the current best guess
        of the region. If that fails we look to the beginning of the region
        and if that fails we look in the non-contiguous region. */

/* Begin changes for the 5/18/97 bug fix   */
    clno = 0;
/* NEW   */
    if (start_cluster)
    {
        /* search from the start_cluster hint to the end of the fat   */
        clno = pc_find_free_cluster(pdr, start_cluster, pdr->maxfindex);
        /* If we search again search only to the start_cluster   */
        last_cluster = start_cluster;
    }
    else
        /* When we search again search to the end   */
        last_cluster = pdr->maxfindex;
    /* Check the most likely place to find contiguous space   */
    if (!clno)
    {
/* NEW   */
        if (!start_cluster || start_cluster >= pdr->free_contig_pointer) 
        {
        /* search from free_contig_pointer to start_cluster or maxfindex whichever 
           is less */
            clno = pc_find_free_cluster(pdr, pdr->free_contig_pointer, last_cluster);
        /* If we search again search only to the free_contig_pointer   */
            last_cluster = pdr->free_contig_pointer;
        }
    }
    /* Check the area of the disk beyond where we typically write fragments   */
    if (!clno)
    {
    /* NEW   */
        if (!start_cluster || start_cluster > pdr->free_contig_base)
        /* search from free_contig_base to start_cluster or free_contig_pointer whichever 
           is less */
            clno = pc_find_free_cluster(pdr, pdr->free_contig_base, last_cluster);
    }
    /* Check the beginning of the  the disk where we typically write fragments   */
    if (!clno)
        clno = pc_find_free_cluster(pdr, 2, pdr->free_contig_base);
    /* We didn't find any clusters. Scan the whole fat again this should
       never work but we did have a bug in this area once before ... */
     if (!clno)
        clno = pc_find_free_cluster(pdr, 2, pdr->maxfindex);
    if (!clno)
        return(0);
/* End changes for the 5/18/97 bug fix   */

    first_new_cluster = clno;
    value = 0;
    n_contig = 1;

    /* look up the FAT. If the next cluster is free we link to it
        and up the contig count. */
    while ( (n_contig < n_clusters) && (clno < pdr->maxfindex) )
    {
        if (!pc_faxx(pdr,(CLUSTERTYPE)(clno+1), &value))
            return(0);

        /* If the next cluster is in-use we're done.   */
        if (value)
            break;

        /* Link the current cluster to the next one   */
        if (!pc_pfaxx(pdr, clno, (CLUSTERTYPE)(clno+1)))
            return (0);
        n_contig += (CLUSTERTYPE)1; /* Yep.. we got another */
        clno += (CLUSTERTYPE)1;     /* Up the FAT table */
    }
    /* Terminate the list we just made          */
    if (!pc_pfaxxterm(pdr, clno))
        return (0);

    /* Update the hint of most likeley place to find a free cluster   */
    if ((clno < pdr->maxfindex) && (clno >= pdr->free_contig_pointer))
        pdr->free_contig_pointer = (CLUSTERTYPE)(clno+1);

    /* If we were handed a starting cluster we have to stitch our new
        chain after it. */
    if (start_cluster)
    {
        if (!pc_pfaxx(pdr, start_cluster, first_new_cluster))
            return (0);
    }

    *pstart_cluster = first_new_cluster;

    if (pdr->known_free_clusters)
        pdr->known_free_clusters = (CLUSTERTYPE)(pdr->known_free_clusters - n_contig);

    return(n_contig);
}
#endif

RTFS_FILE(fndfrcl.c, pc_find_free_cluster)

#ifndef __PCDISK__  /* This allows us to build the lib with subroutines split */
#include <pcdisk.h>
#endif

#if (RTFS_WRITE)
/* Find the first free cluster in a range                        */
/* Note: The caller locks the fat before calling this routine    */
CLUSTERTYPE pc_find_free_cluster(DDRIVE *pdr, CLUSTERTYPE startpt, CLUSTERTYPE endpt)/*__fn__*/
{
CLUSTERTYPE i;
CLUSTERTYPE value;

    for (i = startpt; i < endpt; i++)
    {
        if ( !pc_faxx(pdr, i, &value) ) 
            return(0);
        if (value == 0)
            return(i);
    }
    return(0);
}
#endif
RTFS_FILE(clalloc.c, pc_clalloc)

#ifndef __PCDISK__  /* This allows us to build the lib with subroutines split */
#include <pcdisk.h>
#endif
#if (RTFS_WRITE)
#if (RTFS_SUBDIRS)
/***************************************************************************
    PC_CLALLOC - Reserve and return the next free cluster on a drive

 Description
    Given a DDRIVE, mark the next available cluster in the file allocation 
    table as used and return the associated cluster number. Clhint provides
    a means of selecting clusters that are near eachother. This should 
    reduce fragmentation.

    NOTE: This routine is used to allocate single cluster chunks for
            maintaining directories. We artificially break the disks into
            two regions. The first region is where single clusters chunks
            used in directory files come from. These are allocated by this
            routine only. Data file clusters are allocated by pc_alloc_chain.
            
            THE DISK IS NOT REALLY PARTITIONED. If this routine runs out of
            space in the first region it grabs a cluster from the second 
            region.
 Returns
    Return a new cluster number or 0 if the disk is full.

****************************************************************************/
/* Note: The caller locks the fat before calling this routine   */
CLUSTERTYPE pc_clalloc(DDRIVE *pdr, CLUSTERTYPE clhint)                     /*__fn__*/
{
    CLUSTERTYPE clno;

    if (clhint < 2)
        clhint = 2;
    if (clhint >= pdr->free_contig_base)
        clhint = 2;

    /* Look in the "fragmentable" region first from clhint up   */
    clno = pc_find_free_cluster(pdr, clhint, pdr->free_contig_base);
    /* Look in the  "fragmentable" region up to clhint   */
    if (!clno)
        clno = pc_find_free_cluster(pdr, 2, clhint);

    /* Look in the contiguos region if the "fragmentable" region is full   */
    if (!clno)
        clno = pc_find_free_cluster(pdr, pdr->free_contig_base, pdr->maxfindex);
    if (!clno)
        return(0);
    
    /* Mark the cluster in use   */
    if (!pc_pfaxxterm(pdr, clno))   /* FAT32 */
        return (0);

    if (pdr->known_free_clusters)
    {
#if (FAT32)
        pdr->known_free_clusters -= (long)1;
#else
        pdr->known_free_clusters -= (word)1;
#endif
    }

    return(clno);
}
#endif
#endif

RTFS_FILE(clgrow.c, pc_clgrow)

#ifndef __PCDISK__  /* This allows us to build the lib with subroutines split */
#include <pcdisk.h>
#endif
 
/****************************************************************************
    PC_CLGROW - Extend a cluster chain and return the next free cluster

 Description
    Given a DDRIVE and a cluster, extend the chain containing the cluster
    by allocating a new cluster and linking clno to it. If clno is zero
    assume it is the start of a new file and allocate a new cluster.

    Note: The chain is traversed to the end before linking in the new 
            cluster. The new cluster terminates the chain.
 Returns
    Return a new cluster number or 0 if the disk is full.

****************************************************************************/
#if (RTFS_WRITE)
#if (RTFS_SUBDIRS)

/* Note: The caller locks the fat before calling this routine   */
CLUSTERTYPE  pc_clgrow(DDRIVE *pdr, CLUSTERTYPE  clno)                      /*__fn__*/
{
    CLUSTERTYPE nxt;
    CLUSTERTYPE nextcluster;

    /* Make sure we are at the end of chain   */
    if (clno)   
    {
        nextcluster = pc_clnext(pdr , clno);
        while (nextcluster)
        {
            clno = nextcluster;
            nextcluster = pc_clnext(pdr , clno);
        }
    }


    /* Get a cluster, clno provides a hint for more efficient cluster
        allocation */
    nxt = pc_clalloc(pdr,clno);
    if (!nxt)
        return((CLUSTERTYPE) 0);
    /* Attach it to the current cluster if not at the begining of the chain   */
    if (clno)
        if (!pc_pfaxx(pdr, clno, nxt))
            return((CLUSTERTYPE) 0);
    return(nxt);
}
#endif
#endif
RTFS_FILE(clnext.c, pc_clnext)

#ifndef __PCDISK__  /* This allows us to build the lib with subroutines split */
#include <pcdisk.h>
#endif

/***************************************************************************
    PC_CLNEXT - Return the next cluster in a cluster chain
                    

 Description
    Given a DDRIVE and a cluster number, return the next cluster in the 
    chain containing clno. Return 0 on end of chain.

 Returns
    Return a new cluster number or 0 on end of chain.

****************************************************************************/

/* Return the next cluster in a chain or ZERO   */
CLUSTERTYPE pc_clnext(DDRIVE *pdr, CLUSTERTYPE  clno)                        /*__fn__ - FAT32*/
{
    CLUSTERTYPE nxt; /*FAT32*/
#if (FAT32)
    dword _Oxffffffful;
#endif
    /* Get the value at clno. return 0 on any io errors   */
    if (! pc_faxx(pdr,clno,&nxt) )
        return (0);

    if (pdr->fasize == 3)       /* 3 nibble ? */
    {
        if ( (0xff7 < nxt) && (nxt <= 0xfff) )
            nxt = 0;                            /* end of chain */
    }
    else
#if (FAT32)
    if (pdr->fasize == 8)
    {
        _Oxffffffful = 0x0ffffffful;
        nxt &= _Oxffffffful;
        if ( nxt == 0x0ffffffful )
            nxt = 0;                            /* end of chain */
    }
    else
#endif
    {
#if (FAT32)
        if ( (nxt >= (CLUSTERTYPE)0xfff7) && (nxt <= (CLUSTERTYPE)0xffff) )
#else

⌨️ 快捷键说明

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