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

📄 nu_file.c

📁 嵌入式操作系统Nucleus Plus中使用的文件系统
💻 C
📖 第 1 页 / 共 5 页
字号:

    /* Assume success until something fails */
    ret_val = YES;

    /* Get the FILE. We don't want it if an error has occured */    
    pfile = pc_fd2file(fd, NO);

    /* Make sure we have write privilages */
    if ( (!pfile) ||  !((pfile->flag & PO_WRONLY) || (pfile->flag & PO_RDWR)))
    {
        fs_user->p_errno = PEBADF;
        ret_val = NO;
        goto return_error;
    }

    pdrive = pfile->pobj->pdrive;
    PC_DRIVE_ENTER(pdrive->driveno, NO)  /* Register drive in use */

    /* Grab exclusive access to the file */
    PC_INODE_ENTER(pfile->pobj->finode, YES)

    /* Can only truncate a file that you hold exclusively */
    if (pfile->pobj->finode->opencount > 1)
    {
        ret_val = NO;
        fs_user->p_errno = PESHARE;
        goto errex;
    }

    /* Set the cluster and block file pointers if not already set */
    _synch_file_ptrs(pfile);

	/* Call the internal seek routine that we share with NU_Seek. Seek to
       offset from the origin of zero. */
    offset = _po_lseek(pfile, offset, PSEEK_SET);

    if (offset == -1 || ((ULONG)offset >= pfile->pobj->finode->fsize))
    {
        ret_val = NO;
    }
    else
    {
        /* Are we on a cluster boundary ? */
        if (!(offset & pdrive->byte_into_cl_mask))
        {
        /* Free the current cluster and beyond since we're on a cluster boundary. */
            first_cluster_to_release = pfile->fptr_cluster; 

            /* Find the previous cluster so we can terminate the chain */

            PC_FAT_ENTER(pdrive->driveno)   /* claim the fat for alloc */
            clno = pfile->pobj->finode->fcluster;
            last_cluster_in_chain = clno;
            while (clno != first_cluster_to_release)
            {
                last_cluster_in_chain = clno;
                clno = pc_clnext(pdrive , clno);
                if (clno == 0)
                {
                    PC_FAT_EXIT(pdrive->driveno) 
                    ret_val = NO;
                    fs_user->p_errno = PENOSPC;
                    goto errex;
                }
            }
            PC_FAT_EXIT(pdrive->driveno) 
            /* Set ptr_cluster to last in chain so read&write will work right */
            pfile->fptr_cluster = last_cluster_in_chain;
            if (last_cluster_in_chain)
                pfile->fptr_block = pc_cl2sector(pdrive, last_cluster_in_chain);
            else
                pfile->fptr_block = 0;
            pfile->at_eof = YES;
        }
        else        /* Simple case. we aren't on a cluster boundary. Just free*/
        {           /* The chain beyond us and terminate the list */
            PC_FAT_ENTER(pdrive->driveno)  /* claim the fat */
            last_cluster_in_chain = pfile->fptr_cluster;
            first_cluster_to_release = pc_clnext(pdrive, pfile->fptr_cluster);
            PC_FAT_EXIT(pdrive->driveno) 
            pfile->at_eof = YES;
        }

        /*  Now update the directory entry. */
        pfile->pobj->finode->fsize = offset;
        if (!offset)    /* If the file goes to zero size unlink the chain */
        {
            pfile->pobj->finode->fcluster = 0;
            pfile->fptr_cluster = 0;
            pfile->fptr_block = 0;
            pfile->fptr = 0;
            pfile->at_eof = NO;
            /* We're freeing the whole chain so we don't mark last_cluster in chain */
            last_cluster_in_chain = 0;
        }
        if (!pc_update_inode(pfile->pobj))
        {
            ret_val = NO;
            fs_user->p_errno = PENOSPC;
            goto errex;
        }

        /* Terminate the chain and free the lost chain part */
        PC_FAT_ENTER(pfile->pobj->pdrive->driveno)

        /* Free the rest of the chain */
        if (first_cluster_to_release)
        {
            /* Release the chain */
            pc_freechain(pfile->pobj->pdrive, first_cluster_to_release);
        }
        /* Null terminate the chain */
        if (last_cluster_in_chain)
        {
            if (!pc_pfaxx(pdrive, last_cluster_in_chain, 0xffff))
            {
                ret_val = NO;
                fs_user->p_errno = PENOSPC;
            }
        }

        if (!pc_flushfat(pfile->pobj->pdrive->driveno))
        {
            ret_val = NO;
            fs_user->p_errno = PENOSPC;
        }
        PC_FAT_EXIT(pfile->pobj->pdrive->driveno) 
    }

errex:
    PC_INODE_EXIT(pfile->pobj->finode)
    PC_DRIVE_EXIT(pdrive->driveno)
return_error:      /* No only errors return through here. Everything does. */
    /* Restore the kernel state */
    PC_FS_EXIT()
    return(ret_val);
}


/**************************************************************************
    _PO_LSEEK    -  Move file pointer (internal)

 Description
	Behaves as NU_Seek but takes a file instead of a file descriptor.
    
    Attempting to seek beyond end of file puts the file pointer one
    byte past eof. 
    
    All setting up such as drive_enter and drobj_enter should have been done
    before calling here. 

    Called By:
    
	NU_Seek and NU_Truncate.

 Returns
    Returns the new offset or -1 on error.

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

    PENBADF        - File descriptor invalid
    PEINVAL        - Seek to negative file pointer attempted.

  History
  
    NAME            DATE        REMARKS
    
    S. Murrill      11/14/96    Changed _po_lseek() so that a seek to end of 
                                file works correctly when the file ends at the
                                end of a cluster (SPR216)
    
*****************************************************************************/

LONG _po_lseek(PC_FILE *pfile, LONG offset, COUNT origin)            /*__fn__*/
{
    LONG   file_pointer;
    DDRIVE *pdrive;
    BOOL   past_file;
    COUNT  log2_bytespcluster;
    ULONG  ltemp;
    ULONG  ltemp2;
    UCOUNT n_clusters_to_seek;
    UCOUNT n_clusters;
    UCOUNT first_cluster;
    LONG   ret_val;
    ULONG  alloced_size;

    fs_user->p_errno = 0;    

    pdrive = pfile->pobj->pdrive;
    /* If file is zero size'd. were there */
    if (!(pfile->pobj->finode->fsize))
    {
        ret_val = 0L;
        goto errex;
    }

    if (origin == PSEEK_SET)        /*    offset from begining of file */
        file_pointer = offset;
    else if (origin == PSEEK_CUR)    /* offset from current file pointer */
    {
        file_pointer = (LONG) pfile->fptr;
        file_pointer += offset;
    }
    else if (origin == PSEEK_END)    /*     offset from end of file */
    {
        file_pointer = (LONG) pfile->pobj->finode->fsize;
        file_pointer += offset;
    }
    else    /* Illegal origin */
    {
        fs_user->p_errno = PEINVAL;
        ret_val = -1L;
        goto errex;
    }

    if (file_pointer < 0L)
    {
        fs_user->p_errno = PEINVAL;
        ret_val = -1L;
        goto errex;
    }

    if (file_pointer > (LONG) pfile->pobj->finode->fsize)
    {
        file_pointer = (LONG) pfile->pobj->finode->fsize;
        past_file = YES;
    }
    else
        past_file = NO;

    log2_bytespcluster = (COUNT) (pdrive->log2_secpalloc + 9);

    /* How many clusters do we need to seek */
    /* use the current cluster as the starting point if we can */
    if (file_pointer >= (LONG)pfile->fptr)
    {
        first_cluster = pfile->fptr_cluster;
        ltemp  = file_pointer >> log2_bytespcluster;
        ltemp2 = pfile->fptr  >> log2_bytespcluster;
        n_clusters_to_seek = (UCOUNT) (ltemp - ltemp2);
    }
    else
    {
        /* seek from the beginning */
        first_cluster = pfile->pobj->finode->fcluster;
        ltemp = file_pointer >> log2_bytespcluster;
        n_clusters_to_seek = (UCOUNT) ltemp;
    }

    while (n_clusters_to_seek)
    {
        PC_FAT_ENTER(pdrive->driveno) 
        n_clusters = pc_get_chain(pdrive, first_cluster,
                                  &first_cluster, n_clusters_to_seek);
        PC_FAT_EXIT(pdrive->driveno) 

        if (!n_clusters)
        {
             fs_user->p_errno = PEINVAL;
             ret_val = -1L;
             goto errex;
        }
    
        n_clusters_to_seek -= n_clusters;
    }

    pfile->fptr_cluster = first_cluster;
    pfile->fptr_block = pc_cl2sector(pdrive, first_cluster);
    pfile->fptr= file_pointer;

    /* If seeking to the end of file see if we are beyond the allocated size of 
       the file. If we are we set the at_eof flag so we know to try to move the
       cluster pointer in case another file instance extends the file */
    if (past_file)
    {
        /* Round the file size up to its cluster size by adding in clustersize-1
           and masking off the low bits */
        alloced_size =  (pfile->pobj->finode->fsize + pdrive->byte_into_cl_mask) &
                         ~(pdrive->byte_into_cl_mask);
        /* If the file pointer is beyond the space allocated to the file note it
           since we may need to adjust this file's cluster and block pointers
           later if someone else extends the file behind our back */
        if (pfile->fptr >= alloced_size)
            pfile->at_eof = YES;
        else
            pfile->at_eof = NO;
    }
    else
        pfile->at_eof = NO;

    ret_val = pfile->fptr;
errex:
                    /* No only errors return through here. Everything does. */
    return(ret_val);
}

/* Internal version of NU_Flush() called by NU_Flush and NU_Close */
BOOL _po_flush(PC_FILE *pfile)                                        /*__fn__*/
{
    BOOL ret_val;

    /* Start by assuming success */
    ret_val = YES;
    fs_user->p_errno = 0;    

    /* Convert to native and overwrite the existing inode*/
    if (!pc_update_inode(pfile->pobj))
    {
        ret_val = NO;
        fs_user->p_errno = PENOSPC;
    }
    else
    {
        /* Flush the file allocation table */
        PC_FAT_ENTER(pfile->pobj->pdrive->driveno)
        if (!pc_flushfat(pfile->pobj->pdrive->driveno))
        {
            ret_val = NO;
            fs_user->p_errno = PENOSPC;
        }
        PC_FAT_EXIT(pfile->pobj->pdrive->driveno)
    }
    return(ret_val);
}


/****************************************************************************
    PO_FLUSH  -  Flush a file.

 Description
    Flush the file updating the disk.

 Returns
    Returns YES if all went well otherwise it returns NO and fs_user->p_errno is set to
    one of these values

    PENBADF     - Invalid file descriptor
    PENOSPC     - IO error occured
****************************************************************************/

BOOL NU_Flush(PCFD fd)												/*__fn__*/
{
    PC_FILE *pfile;
    BOOL ret_val;
    PC_FS_ENTER()     /* Must be last line in declarations */
    CHECK_USER(BOOL, 0) /* Check if a valid user if multitasking */

    /* Start by assuming success */
    ret_val = YES;
    fs_user->p_errno = 0;    

    /* Get the FILE. Take it even if an error has occured */    
    if ( (pfile = pc_fd2file(fd, YES)) == NULL)
    {
        fs_user->p_errno = PEBADF;
        ret_val = NO;
        goto return_error;
    }
    
    PC_DRIVE_ENTER(pfile->pobj->pdrive->driveno, NO)  /* Register drive in use */

    if (pfile->flag & ( PO_RDWR | PO_WRONLY ) )
    {
        /* Claim exclusive access on flush */
        PC_INODE_ENTER(pfile->pobj->finode, YES)
        if (!_po_flush(pfile))
            ret_val = NO;
        PC_INODE_EXIT(pfile->pobj->finode)
    }
    PC_DRIVE_EXIT(pfile->pobj->pdrive->driveno)
return_error:      /* Not only errors return through here. Everything does. */
    /* Restore the kernel state */
    PC_FS_EXIT()
    return(ret_val);
}

/****************************************************************************
    PO_CLOSE  -  Close a file.

 Description
    Close the file updating the disk and freeing all core associated with FD.

 Returns
    Returns 0 if all went well otherwise it returns -1 and fs_user->p_errno is set to
    one of these values

    PENBADF     - Invalid file descriptor
    PENOSPC     - IO error occured
****************************************************************************/

INT NU_Close(PCFD fd)												/*__fn__*/
{
    PC_FILE *pfile;
    INT ret_val;
    COUNT driveno;
    PC_FS_ENTER()     /* Must be last line in declarations */
    CHECK_USER(INT, -1) /* Check if a valid user if multitasking */

⌨️ 快捷键说明

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