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

📄 apiutil.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.
*/
/* APIUTIL.C - Contains support code for user api level source code.

    The following routines are included:

    pc_fd2file       -   Map a file descriptor to a file structure.
    pc_allocfile     -   Allocate a file structure.
    pc_freefile      -   Release a file structure.
    pc_free_all_fil  -   Release all file structures for a drive.
    pc_log_base_2    -   Calculate log2(N).
    pc_dskinit       -   Mount a disk.
    pc_idskclose     -   Unmount a disk.
    pc_get_cwd       -   Determine cwd string from current directory inode.
    pc_upstat        -   Copy directory entry info to a user's stat buffer  

*/

#include "posix.h"

IMPORT PFILE_SYSTEM_USER fs_current_user_structure(void);

IMPORT DDRIVE  *mem_drives_structures;
IMPORT PC_FILE  *mem_file_pool;
IMPORT _PC_BDEVSW pc_bdevsw[];

/****************************************************************************
    Miscelaneous File and file descriptor management functions

    These functions are private functions used by the po_ file io routines.

    pc_fd2file -
        Map a file descriptor to a file structure. Return null if the file is
        not open. If an error has occured on the file return NULL unless 
        allow_err is true.
    
    pc_allocfile -
        Allocate a file structure an return its handle. Return -1 if no more 
        handles are available.

    pc_freefile -
        Free all core associated with a file descriptor and make the descriptor
        available for future calls to allocfile.

    pc_free_all_fil -
*****************************************************************************/

/*    Map a file descriptor to a file structure. Return null if the file is
      not open. 
*/

PC_FILE *pc_fd2file(PCFD fd,BOOL allow_err)                           /*__fn__*/
{
    PC_FILE *pfile;
 
    allow_err = allow_err;   
    if (0 <= fd && fd <= NUSERFILES)
    {
        pfile = mem_file_pool+fd;
        if (pfile && !pfile->is_free)
        {
            return(pfile);
        }
    }
    return (NULL);
}

/* Assign zeroed out file structure to an FD and return the handle. Return 
   -1 on error. */
PCFD pc_allocfile()                                                  /*__fn__*/
{
    PC_FILE *pfile;
    PCFD i;
    
    pfile = mem_file_pool;

    for (i=0;i<NUSERFILES;i++, pfile++)
    {
        if (pfile->is_free)
        {
            pc_memfill(pfile, sizeof(PC_FILE), (UTINY) 0);
            return(i);
        }
    }
    return (-1);
}

/* Free core associated with a file descriptor. Release the FD for later use */
VOID pc_freefile(PCFD fd)                                           /*__fn__*/
{
    PC_FILE *pfile;

    if ( (pfile = pc_fd2file(fd, YES)) == NULL)
        return;
    if (pfile->pobj)
        pc_freeobj(pfile->pobj);
    pfile->is_free = YES;
}

/* Release all file descriptors associated with a drive and free up all core
   associated with the files
   called by dsk_close 
*/
VOID pc_free_all_fil(DDRIVE *pdrive)                                /*__fn__*/
{
    PC_FILE *pfile;
    PCFD i;

    for (i=0; i < NUSERFILES; i++)
    {
        pfile = pc_fd2file(i, YES);
        if (pfile)
        {
            if ((pfile->pobj) && (pfile->pobj->pdrive == pdrive))
            {
                /* print a debug message since in normal operation 
                   all files should be close closed before closing the drive */
                pc_report_error(PCERR_FSTOPEN);
                pc_freefile(i);
            }
        }
    }
}

/*****************************************************************************
    PC_DSKINIT -  Open a disk for business. (internal)


 Description
    Given a drive number, open the disk by reading all of the block zero
    information and the file allocation table. (called by pc_dskopen())
    

 Returns
    Returns YES if the disk was successfully initialized.

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

COUNT pc_log_base_2(UCOUNT n)                                       /*__fn__*/
{
COUNT log;

    log = 0;
    if (n <= 1)
        return(log);

    while(n)
    {
        log += 1;
        n >>= 1;
    }
    return((COUNT)(log-1));
}

BOOL pc_dskinit(COUNT driveno)                                      /*__fn__*/
{
    DDRIVE *pdr;
    struct pcblk0 bl0;
    UCOUNT  blocks_avail;
    UCOUNT  min_needed;

    /* Check drive number */
    if ((driveno < 0) || (driveno >= NDRIVES))
    {
        pc_report_error(PCERR_INITDRNO);
        return(NO);
    }

    if (!mem_drives_structures)
    {
        /* Failed: pc_meminit() must not have been called */
        pc_report_error(PCERR_INITCORE);
        return (NO);
    }

    pdr = mem_drives_structures+driveno;
    pdr->opencount += 1;
        /* Don't do anything on reopens */
    if (pdr->opencount > 1)
        return(YES);
    else
    {
        /* Zero the structure so all of our initial values are right */
        pc_memfill(pdr, sizeof(DDRIVE), (UTINY) 0);
        pdr->opencount = 1;
    }

    /* Clear the current working directory */
    fs_user->lcwd[driveno] = NULL;
    if (!pc_bdevsw[driveno].open_proc(driveno))
    {
        pc_report_error(PCERR_INITDEV);
 return_error:
        pdr->opencount = 0;
        return(NO);
    }

        
    /* Read block 0 */
    if (!pc_gblk0((UCOUNT) driveno, &bl0 ))
    {
        pc_report_error(PCERR_INITREAD);
        goto return_error;
    }

    /* Verify that we have a good dos formatted disk */
    if ( (bl0.jump != (UTINY) 0xE9) && (bl0.jump !=(UTINY) 0xEB) )
    {
        pc_report_error(PCERR_INITMEDI);
        goto return_error;
    }

    /* set up the drive structur from block 0 */
    pdr->secpalloc = bl0.secpalloc; /* sectors / cluster */
    pdr->secpfat = bl0.secpfat;     /* sectors / fat */
    pdr->numfats = bl0.numfats;     /* Number of fat copies */
    pdr->numroot = bl0.numroot;     /* Maximum number of root entries */
    pdr->numsecs = (BLOCKT) bl0.numsecs;    /* Total sectors on the disk */
    pdr->mediadesc =    bl0.mediadesc;  /* Media descriptor byte */
    pdr->secreserved = bl0.secreserved; /* sectors reserved */
    pdr->secptrk    = bl0.secptrk;      /* sectors per track */
    pdr->numhead    = bl0.numhead;      /* number of heads */
    pdr->numhide    =bl0.numhide;       /* # hidden sectors */

/* Check if running on a DOS (4.0) huge partition */
    /* If traditional total # sectors is zero, use value in extended BPB */
    if (pdr->numsecs == 0L)
        pdr->numsecs = bl0.numsecs2;                             /* (4.0) */

    /* derive some things */

            /* beginning of fat is just past reserved sectors */
    pdr->fatblock = (BLOCKT) bl0.secreserved;
        /* The first block of the root is just past the fat copies */
    pdr->rootblock = pdr->fatblock + pdr->secpfat * pdr->numfats;

        /* The first block of the cluster area is just past the root */
        /* Round up if we have to */
    pdr->firstclblock = pdr->rootblock +
                        (pdr->numroot + INOPBLOCK - 1)/INOPBLOCK;
    pdr->bytespcluster = (UCOUNT) (512 * pdr->secpalloc);

    /* bits to mask in to calculate byte offset in cluster from file pointer.
        AND file pointer with this to get byte offset in cluster a shift right
        9 to get block offset in cluster */
    pdr->byte_into_cl_mask = (ULONG) pdr->bytespcluster;
    pdr->byte_into_cl_mask -= 1L;

    /* save away log of sectors per alloc */
    pdr->log2_secpalloc = pc_log_base_2((UCOUNT)pdr->secpalloc);
    
    /*  Calculate the largest index in the file allocation table.
        Total # block in the cluster area)/Blockpercluster =='s total
        Number of clusters. Entries 0 & 1 are reserved so the highest
        valid fat index is 1 + total # clusters.
    */

    pdr->maxfindex = (UCOUNT)
            (1 + (pdr->numsecs - pdr->firstclblock)/pdr->secpalloc);
     /* if calculated size > fff0 set it to one less. fff0 to ffff are
        reserved values. */
    if (pdr->maxfindex >= 0xfff0)
        pdr->maxfindex = 0xffef;

     /* Create a hint for where we should write file data. We do this 
        because directories are allocated in one cluster chunks while
        file may allocate larger chunks. We Try to put directory 
        data at the beginning of the disk in a seperate region so we
        don't break the contiguous space further out */

     /* guess that 1/32nd of the disk will store directory info and the
        rest will be data. */
    pdr->free_contig_base = (UCOUNT) (pdr->maxfindex >> 5);
    if (pdr->free_contig_base < 2)
        pdr->free_contig_base = 2;
     /* set the pointer to where to look for free clusters to the contiguous
        area. On the first call to write this will hunt for the real free
        blocks. */
    pdr->free_contig_pointer = pdr->free_contig_base;

     /* Keep track of how much free space is on the drive. (This will
        speed up pc_free()) when calculating free space */
    pdr->known_free_clusters = 0;

    /* Initialize the fat management code */

        /* Nibbles/fat entry if < 4087 clusters then 12 bit else 16 */
    pdr->fasize = (UCOUNT) ((pdr->maxfindex < 4087) ? 3 : 4);

    /* 12 bit FAT require the whole fat in memory so set minimum blocks 
       needed to the fat size. For 16 bit fats we arbitrarilly set it
       to 12 blocks */

    if (pdr->fasize == 3)
        min_needed = pdr->secpfat;
    else
        min_needed = 12;

    /* Allocate between min_needed and pdr->secpfat blocks - the number 
       allocated is returned in blocks_avail. If < min_needed blocks
       are available it returns NULL */
    pdr->fat_swap_structure.data_array =
         pc_memory_fat_blocks_alloc(driveno, min_needed,pdr->secpfat, &blocks_avail);

    if (!pdr->fat_swap_structure.data_array)
    {
        pc_report_error(PCERR_FATCORE);
        goto return_error;
    }

    /* Remember how many blocks we alloced */
    pdr->fat_swap_structure.n_blocks_total = blocks_avail;
    if (blocks_avail == pdr->secpfat)
        pdr->use_fatbuf = 0;            /* Always true for 12 bit */
    else       
        pdr->use_fatbuf = 1;
    /* Set driveno now becuse the drive structure is valid */  
    pdr->driveno = driveno; 

    if (pdr->use_fatbuf)
    {
        /* Swap in item 0. (ie read the first page of the FAT) */
        if (!pc_pfswap(pdr, (UCOUNT) 0, NO))
        {
            pc_report_error(PCERR_FATREAD);
            pc_memory_fat_blocks_free(driveno, pdr->fat_swap_structure.data_array, blocks_avail);
            goto return_error;
        }
    }
    else
    {
        /* No fat swapping. We use  drive.fat_swap_structure elements
           to implement an in memory caching scheme. data_map[255] is used
           to indicate which blocks are dirty and data_array points to
           the buffer to hold the in memory fat */

        /* The dirty blocks table data_map[255] was zeroed when we zeroed
           the drive structure */
        /* Now read the fat */
        PC_DRIVE_IO_ENTER(driveno)
        if (!pc_bdevsw[driveno].io_proc(driveno,pdr->fatblock,pdr->fat_swap_structure.data_array,pdr->secpfat, YES) )
        {
            PC_DRIVE_IO_EXIT(driveno)
            pc_report_error(PCERR_FATREAD);
            pc_memory_fat_blocks_free(driveno, pdr->fat_swap_structure.data_array, blocks_avail);
            goto return_error;
        }
        PC_DRIVE_IO_EXIT(driveno)
    }
    return(YES);
}

/**************************************************************************
    PC_IDSKCLOSE -  Flush all buffers for a disk and free all core. (internal)
                       

 Description
    Given a valid drive number. Flush the file allocation table and purge any
    buffers or objects associated with the drive. (called by pc_dskclose)

 Returns
    Returns YES if all went well.

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

BOOL pc_idskclose(COUNT driveno)                                      /*__fn__*/
{
BOOL ret_val;

    /* Check drive number */
    if (pc_drno2dr(driveno))
    {
        PC_FAT_ENTER(driveno)
        ret_val = pc_flushfat(driveno);
        PC_FAT_EXIT(driveno)

        if (ret_val)        
        {
            /* Release the drive if opencount == 0 */
            pc_dskfree(driveno,NO);
            return(YES);
        }
    }
    return(NO);
}

/***************************************************************************
    PC_CWD -  Get the current working directory for a drive,

 Description
    Return the current directory inode for the drive represented by ddrive. 

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

/*  Get the current working directory and copy it into pobj */
DROBJ *pc_get_cwd(DDRIVE *pdrive)                                    /*__fn__*/
{
    DROBJ *pcwd;
    DROBJ *pobj;

    pobj = NULL;

    pcwd = fs_user->lcwd[pdrive->driveno];

    /* If no current working dir set it to the root */
    if (!pcwd)
    {
        pcwd = pc_get_root(pdrive);
        fs_user->lcwd[pdrive->driveno] = pcwd;
    }

    if (pcwd)
    {
        pobj = pc_allocobj();
        if (!pobj)
            return (NULL);
        /* Free the inode that comes with allocobj */
        pc_freei(pobj->finode);
        copybuff(pobj, pcwd, sizeof(DROBJ));
        pobj->finode->opencount += 1;
        return (pobj);
    }
    else    /* If no cwd is set error */
    {
        return(NULL);
    }
}

/****************************************************************************
    PC_UPSTAT - Copy private information to public fields for a DSTAT struc.

 Description
    Given a pointer to a DSTAT structure that contains a pointer to an 
    initialized DROBJ structure, load the public elements of DSTAT with
    name filesize, date of modification et al. (Called by pc_gfirst &
    pc_gnext)

 Returns
    Nothing


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

/* Copy internal stuf so the outside world can see it */
VOID pc_upstat(DSTAT *statobj)                                      /*__fn__*/
{
    DROBJ *pobj;
    FINODE *pi;
    pobj = statobj->pobj;

    pi = pobj->finode;
    
    copybuff( statobj->fname, pi->fname, 8);
    statobj->fname[8] = '\0';
    copybuff( statobj->fext, pi->fext, 3);
    statobj->fext[3] = '\0';

    statobj->fattribute = pi->fattribute;
    statobj->ftime = pi->ftime;
    statobj->fdate = pi->fdate;
    statobj->fsize = pi->fsize;
}

⌨️ 快捷键说明

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