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

📄 apiext.c

📁 嵌入式操作系统Nucleus Plus中使用的文件系统
💻 C
字号:
/*
* 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.
*/
/* APIEXT.C - Extensions to the API */

#include "pcdisk.h"

IMPORT PFILE_SYSTEM_USER fs_current_user_structure(void);

/* PC_CLUSTER_SIZE  - Return the number of bytes per cluster for a drive

 Description
        This function will return the cluster size mounted device
        named in the argument. 
        

 Returns
    The cluster size or zero if the device is not mounted.

*****************************************************************************/
COUNT pc_cluster_size(TEXT *drive)                               /*__fn__*/
{
COUNT drive_no;
DDRIVE *pdrive;

    /* get drive no */
    if ( *drive && (*(drive+1) == ':'))
    {
        drive_no = (COUNT) (*drive - 'A');
        pdrive = pc_drno2dr(drive_no);
        if (pdrive)
            return(pdrive->bytespcluster);
    }
    return(0);
}

/******************************************************************************
    PO_EXTEND_FILE  - Extend a file by N contiguous clusters.

 Description
        Given a file descriptor, n_clusters clusters and method, extend the file and
        update the file size.

        Method may be one of the following:
            PC_FIRST_FIT  - The first free chain >= n_clusters is alloced
            PC_BEST_FIT   - The smallest chain   >= n_clusters is alloced
            PC_WORST_FIT  - The largest chain    >= n_clusters is alloced

        Note: PC_FIRST_FIT is significantly faster than the others

        See: pc_find_contig_clusters()

 Returns
    0xffff if an error occured.
    Returns n_clusters if the file was extended. Otherwise it returns the largest
    free chain available. If it n_clusters is not returned the files was not extended.

    If the return value is not n_clusters fs_user->p_errno will be set with one of the following:


    Note: FIRST_FIT is the highest prformance option

    PENBADF        - File descriptor invalid or open read only
    PENOSPC        - IO failure
    
*****************************************************************************/

UCOUNT po_extend_file(PCFD fd, UCOUNT n_clusters, COUNT method) /* __fn__ */
{
    UCOUNT ret_val;
    UCOUNT clno;
    UCOUNT n_alloced;
    UCOUNT largest_chain;
    UCOUNT first_cluster;
    UCOUNT last_cluster_in_chain;
    UCOUNT i;
    ULONG ltemp;
    PC_FILE *pfile;
    DDRIVE *pdr;
    PC_FS_ENTER()     /* Must be last line in declarations */
    CHECK_USER(UCOUNT, 0xffff) /* Check if a valid user if multitasking */

    if (!n_clusters)
    {
        fs_user->p_errno = 0;
        ret_val = 0;
        goto return_error;
    }

    /* Assume error to start */
    fs_user->p_errno = PENOSPC;
    ret_val = 0xffff;
    /* Get the FILE. Second argument is ignored */
    pfile = pc_fd2file(fd, NO);
    /* Make sure we have write privilages. Make sure we got a  count */
    if ( (!pfile) || !n_clusters || !((pfile->flag & PO_WRONLY) || (pfile->flag & PO_RDWR)))
    {
        fs_user->p_errno = PEBADF;
        goto return_error;
    }


    /* From here on we exit through alloc_done so we will unlock these resources */
    pdr = pfile->pobj->pdrive;
    PC_DRIVE_ENTER(pdr->driveno, NO)
    PC_INODE_ENTER(pfile->pobj->finode, YES) /* Exclusive */
    PC_FAT_ENTER(pdr->driveno)
    /* Make sure our file pointer is ok */
    _synch_file_ptrs(pfile);

        /* Find the end of the file's chain */
    last_cluster_in_chain = 0;  
    clno = pfile->fptr_cluster;
    while (clno)
    {
        last_cluster_in_chain = clno;
        clno = pc_clnext(pdr , clno);
    }

        /* Now allocate clusters. To find the free space we look in three 
           regions until we find space:
            1 we look from the last cluster in the file to the end of the fat
            (skip 1 if there is no chain)
            2 we look from the beginning of the data area to the end of the fat
            3 we look from the beginning of the fat area to the end of the fat
        */

    n_alloced     = 0;
    largest_chain = 0;
    clno = last_cluster_in_chain;
    if (!clno)
        clno = pdr->free_contig_base;
    while (clno)
    {
        n_alloced =  pc_find_contig_clusters(pdr, clno, &first_cluster, n_clusters, method);
        if (n_alloced == 0xffff)
            goto alloc_done;
        else if (n_alloced >= n_clusters)
            break;                      /* We got our chain */
        else
        {
            /* We didn't get enough space. keep track of the biggest chain.
               Don't need to store first_cluster since we won't alocate chains
               smaller than what we need */
            if (largest_chain < n_alloced)  
                largest_chain = n_alloced;
        }
        /* If we were searching between from the end of the  file and end of fat
           look from the beginning of the file data area */
        if (clno == last_cluster_in_chain)
            clno = pdr->free_contig_base;
        /* If we were searching between the beginning of the file data area
           and end of fat  look from the fat */
        else if (clno == pdr->free_contig_base)
            clno = 2;
        else  /* We've looked everywhere. No luck */
            break;
    }

    if (n_alloced < n_clusters)
    {
        /* We didn't get what we asked for so we return the biggest free
           contiguous chain */
        ret_val = largest_chain;
        goto alloc_done;
    }
    /* else */

    /* We found a large enough contiguos group of clusters */
    /* Turn them into a chain */
    clno = first_cluster;
    for (i = 0; i < (n_clusters-1); i++, clno++)
    {
        /* Link the current cluster to the next one */
        if (!pc_pfaxx(pdr, clno, (UCOUNT) (clno+1) ))
            goto alloc_done;
    }
    /* Terminate the list */        
    if (!pc_pfaxx(pdr, clno, 0xffff))
        goto alloc_done;

    if (last_cluster_in_chain)
    {
        /* The file already has clusters in it. Append our new chain */
        if (!pc_pfaxx(pdr, last_cluster_in_chain, first_cluster))
            goto alloc_done;
    }
    else
    {
        /* Put our chain into the directory entry */
        pfile->pobj->finode->fcluster = first_cluster;
        /* Use synch_pointers to set our file pointers up */
        pfile->fptr_cluster = 0;        /* This is already true but... */
        pfile->fptr_block = 0;
        pfile->fptr = 0;
    }
    
    /* Now recalculate the file size */
    ltemp = n_clusters;
    ltemp <<= (pdr->log2_secpalloc + 9);
    pfile->pobj->finode->fsize += ltemp;
    /* call synch to take care of both the eof condition and the case where 
       we just alloced the beginning of the chain */
    _synch_file_ptrs(pfile);

    /* Flush the fat */
    if (!pc_flushfat(pdr->driveno))
        goto alloc_done;
    /* Write the directory entry */
    if (!pc_update_inode(pfile->pobj) )
        goto alloc_done;
    /* It worked !  Set the return to the number of clusters requested */
    ret_val = n_clusters;
    fs_user->p_errno = 0;
    /* All code exits through here. ret_val determines if the function was 
       successful. If 0xffff it's an error. If n_clusters it's a success and
       the file is expanded. Otherwise the return value */
alloc_done:
    PC_FAT_EXIT(pdr->driveno) 
    PC_INODE_EXIT(pfile->pobj->finode)
    PC_DRIVE_EXIT(pdr->driveno)
return_error:
    /* Restore the kernel state */
    PC_FS_EXIT()
    return(ret_val);
}


/******************************************************************************
    PC_FIND_CONTIG_CLUSTERS  - Find at least MIN_CLUSTER clusters.


 Description
        Using the provided method, search the FAT from start_pt to the
        end for a free contiguous chain of at least MIN_CLUSTERS. If less
        than MIN_CLUSTERS are found the largest free chain in the region is
        returned.

        There are three possible methods:
            PC_FIRST_FIT  - The first free chain >= MIN_CLUSTERS is returned
            PC_BEST_FIT   - The smallest chain   >= MIN_CLUSTERS is returned
            PC_WORST_FIT  - The largest chain    >= MIN_CLUSTERS is returned
        
        Choose the method that will work best for you.

        Note: PC_FIRST_FIT is significantly faster faster than the others
    
        NOTE: The chain is not created. The caller must convert the 
        clusters to an allocated chain.

 Returns
    Returns the number of contiguous clusters found up to MIN_CLUSTERS.
    *pchain contains the cluster number at the beginning of the chain.
    On error return 0xffff
    Example: 
        Get the largest free chain on the disk:
        large = pc_find_contig_clusters(pdr, 2, &chain, 0xffff, PC_FIRST_FIT);

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

UCOUNT pc_find_contig_clusters(DDRIVE *pdr, UCOUNT startpt, UCOUNT  *pchain, UCOUNT min_clusters, COUNT method) /* __fn__ */
{
UCOUNT i;
UCOUNT value;
UCOUNT best_chain;
UCOUNT best_size;
UCOUNT chain_start;
UCOUNT chain_size;
UCOUNT largest_size;
UCOUNT largest_chain;
UCOUNT endpt;

    best_chain = 0;
    best_size = 0;
    chain_start = 0;
    chain_size = 0;
    largest_size  = 0;
    largest_chain = 0;
    endpt = pdr->maxfindex;

    for (i = startpt; i <= endpt; i++)
    {
        if (!pc_faxx(pdr, i, &value) ) 
            return(0xffff);             /* IO error .. oops */
        if (value == 0)
        {   
            /* Cluster is free. Run some tests on it. */
            if (chain_start)
            {
                /* We're in a contiguous region already. Bump the count */
                chain_size++;
            }
            else
            {
                /* Just starting a contiguous region */
                chain_size = 1;
                chain_start = i;
            }
            /* If using first fit see if we crossed the threshold */
            if (method == PC_FIRST_FIT)
            {
                if (chain_size >= min_clusters)
                {
                    best_chain = chain_start;
                    best_size = chain_size;
                    break;
                }
            }
        }       /* if value == 0*/
        /* Did we just finish scanning a contiguous chain ?? */
        if (chain_size && ((value != 0) || (i == endpt)) )
        {
            /* Remember the largest chain */
            if (chain_size > largest_size)
            {
                largest_size  = chain_size;
                largest_chain = chain_start;
            }
            if (method == PC_BEST_FIT)
            {
                if (chain_size == min_clusters)
                {
                    /* The chain is exactly the size we need take it. */
                    best_chain = chain_start;
                    best_size = chain_size;
                    break;
                }
                if (chain_size > min_clusters)
                {
                    if (!best_chain || (chain_size < best_size))
                    {
                        /* Chain is closest to what we need so far note it. */
                        best_size = chain_size;
                        best_chain = chain_start;
                    }
                }
            }   /* if BEST_FIT */
            else if (method == PC_WORST_FIT)
            {
                if (chain_size >= min_clusters)
                {
                    if (!best_chain || chain_size > best_size)
                    {
                        best_size = chain_size;
                        best_chain = chain_start;
                    }
                }
            }   /* if WORST_FIT */
/* 
*           else if (method == PC_BEST_FIT)
*               ;
*/
            chain_size = 0;
            chain_start = 0;
        } /* if (chain_size && ((value != 0) || (i == endpt)) ) */
    }     /*     for (i = startpt; i <= endpt; i++) */

    /* If we have a best chain return it here. Else return the largest chain */
    if (best_chain)
    {
        *pchain = best_chain;
        return(best_size);
    }
    else
    {
        *pchain = largest_chain;
        return(largest_size);
    }
}

⌨️ 快捷键说明

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