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

📄 lowl.c

📁 nucleus 文件系统,内核和彩色图形系统,在小系统上非常好用
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright Peter Van Oudenaren , 1993
* 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. 

    BUGS FIXED: pc_clalloc - Now checks up to pc_clhint. 

    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_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_pfpword          -   Get a value from the swap cache.
    pc_pfgword          -   Put a value to 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.
    pc_drive_enter      -   Set a drive inuse. Grab exclusive if requested.
    pc_drive_exit       -   Decrement inuse count. Wake up anyone waiting.
    pc_inode_enter      -   Set an inode inuse. Grab exclusive if requested.
    pc_inode_exit       -   Decrement inuse count. Wake up anyone waiting.
    pc_fat_enter        -   Set a Fat inuse. Grab exclusive if requested.
    pc_fat_exit         -   Decrement inuse count. Wake up anyone waiting.
    pc_generic_enter    -   Called by pc_xxxx_enter
    pc_generic_exit     -   Decrement inuse count. Wake up anyone waiting.
    partition_init      -   Interpret a partition table

*/        

#include "pcdisk.h"

IMPORT PFILE_SYSTEM_USER fs_user;
IMPORT DDRIVE  *mem_drives_structures;

IMPORT _PC_BDEVSW pc_bdevsw[];

/******************************************************************************
    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.

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

UCOUNT pc_alloc_chain(DDRIVE *pdr, UCOUNT *pstart_cluster, UCOUNT n_clusters) /*__fn__*/
{
    UCOUNT start_cluster;
    UCOUNT first_new_cluster;
    UCOUNT clno;
    UCOUNT n_contig;
    UCOUNT value;

    start_cluster = *pstart_cluster;

    if (start_cluster)
    {
        if (start_cluster < 2)                 return (0);
        if (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. */
    
    clno = 0;
    if (start_cluster)
        clno = pc_find_free_cluster(pdr, start_cluster, pdr->maxfindex);

    /* Check the most likely place to find contiguous space */
    if (!clno)
        if (!start_cluster || start_cluster < pdr->free_contig_pointer)
            clno = pc_find_free_cluster(pdr, pdr->free_contig_pointer, pdr->maxfindex);

    /* Check the area of the disk beyond where we typically write fragments */
    if (!clno)
        if (!start_cluster || start_cluster < pdr->free_contig_base)
            clno = pc_find_free_cluster(pdr, pdr->free_contig_base, pdr->free_contig_pointer);

    /* 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);
    if (!clno)
        return(0);

    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,(UCOUNT)(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, (UCOUNT)(clno+1)))
            return (0);
        n_contig += 1;              /* Yep.. we got another */
        clno += 1;                  /* Up the FAT table */
    }
    /* Terminate the list we just made */        
    if (!pc_pfaxx(pdr, clno, 0xffff))
        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 = (UCOUNT)(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 -= n_contig;

    return(n_contig);
}

/* Find the first free cluster in a range */
UCOUNT pc_find_free_cluster(DDRIVE *pdr, UCOUNT startpt, UCOUNT endpt)/*__fn__*/
{
UCOUNT i;
UCOUNT value;

    for (i = startpt; i < endpt; i++)
    {
        if ( !pc_faxx(pdr, i, &value) ) 
            return(0);
        if (value == 0)
            return(i);
    }
    return(0);
}
/***************************************************************************
    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.

****************************************************************************/
 
UCOUNT pc_clalloc(DDRIVE *pdr, UCOUNT clhint)                       /*__fn__*/
{
    UCOUNT clno;

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

    clno = 0;
    /* 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)
    {
        if (clno != 2)
            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_pfaxx(pdr, clno, 0xffff))
        return (0);

    if (pdr->known_free_clusters)
      pdr->known_free_clusters -= 1;

    return(clno);
}
 
/****************************************************************************
    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.

****************************************************************************/
 
UCOUNT  pc_clgrow(DDRIVE *pdr, UCOUNT  clno)                        /*__fn__*/
{
    UCOUNT nxt;
    UCOUNT 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((UCOUNT) 0);
    /* Attach it to the current cluster if not at the begining of the chain */
    if (clno)
        if (!pc_pfaxx(pdr, clno, nxt))
            return((UCOUNT) 0);

    return(nxt);
}

/***************************************************************************
    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 */
UCOUNT pc_clnext(DDRIVE *pdr, UCOUNT  clno)                        /*__fn__*/
{
    UCOUNT nxt;

    /* Get the value at clno. return 0 on any io errors */
    if (! pc_faxx(pdr,clno,&nxt) )
        return ( (UCOUNT) 0 );

    if (pdr->fasize == 3)       /* 3 nibble ? */
    {
        if ( (0xff7 < nxt) && (nxt <= 0xfff) )
            nxt = 0;                            /* end of chain */
    }
    else
    {
        if (0xfff7 < nxt)
            nxt = 0;                            /* end of chain */
    }
    return(nxt);
}

/****************************************************************************
    PC_CLRELEASE - Return a cluster to the pool of free space on a disk

 Description
    Given a DDRIVE and a cluster, mark the cluster in the file allocation
    table as free. It will be used again by calls to pc_clalloc().

 Returns
     Nothing


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

/* Return a cluster to the free list */
VOID pc_clrelease(DDRIVE   *pdr, UCOUNT  clno)                        /*__fn__*/
{

    /* Don't catch any lower level errors here. You'll catch them soon enough */
    if (pc_pfaxx(pdr, clno, 0x0000))        /* Mark it as free */
    {
        /* If freeing in the "contiguous" region reset the "hint" if we
           free space earlier than it. */
        if (clno >= pdr->free_contig_base && clno <= pdr->free_contig_pointer)
             pdr->free_contig_pointer = clno;

        if (pdr->known_free_clusters)
            pdr->known_free_clusters += 1;
    }
}

/***************************************************************************
    PC_FAXX - Get the value store in the FAT at clno.

⌨️ 快捷键说明

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