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

📄 nu_file.c

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

/***************************************************************************
    PO_WRITE    -  Write to a file.

 Description
    Attempt to write count bytes from buf to the current file pointer of file
    at fd. The file pointer is updated.

 Returns
    Returns the number of bytes written 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 or open read only
    PENOSPC        - Write failed. Presumably because of no space

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

COUNT NU_Write(PCFD fd, UTINY *buf, UCOUNT count)					 /*__fn__*/
{
    PC_FILE *pfile;
    DDRIVE *pdrive;
    UCOUNT block_in_cluster;
    UCOUNT byte_offset_in_block;
    UCOUNT next_cluster;
    ULONG  saved_ptr;
    ULONG  saved_ptr_block;        
    UCOUNT saved_ptr_cluster;        
    ULONG  ltemp;
    UCOUNT n_bytes;
    UCOUNT n_to_write;
    UCOUNT n_left;
    UCOUNT n_blocks_left;
    UCOUNT n_clusters;
    ULONG  alloced_size;
    ULONG  block_to_write;
    char   local_buf[512];
    UCOUNT ret_val;
    PC_FS_ENTER()     /* Must be last line in declarations */
    CHECK_USER(UCOUNT, 0) /* Check if a valid user if multitasking */

    fs_user->p_errno = 0;

    /* Get the FILE. Second argument is ignored */
    if ( (pfile = pc_fd2file(fd, NO)) == NULL)
    {
        fs_user->p_errno = PEBADF;
        ret_val = (UCOUNT) ~0;
        goto return_error;
    }
    
    if (!((pfile->flag & PO_WRONLY) || (pfile->flag & PO_RDWR)))
    {
        fs_user->p_errno = PEBADF;
        ret_val = (UCOUNT) ~0;
        goto return_error;
    }
    /* Return 0 (none written) on bad args */
    if (!count || !buf)
    {
        ret_val = 0;
        goto return_error;
    }

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

    /* Only one process may write at a time */
    PC_INODE_ENTER(pfile->pobj->finode, YES)

    /* if the  file is zero sized make sure the current cluster pointer
       is invalid */
    if (!pfile->pobj->finode->fsize)
        pfile->fptr_cluster = 0;

    /* Set the cluster and block file pointers if not already set */
    _synch_file_ptrs(pfile);
    saved_ptr = pfile->fptr;
    saved_ptr_block = pfile->fptr_block;        
    saved_ptr_cluster = pfile->fptr_cluster;        

    /* calculate initial values */
    n_left = count;

    /* 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);

    while (n_left)
    {
        block_in_cluster = (UCOUNT) (pfile->fptr & pdrive->byte_into_cl_mask);
        block_in_cluster >>= 9;

        if (pfile->fptr >= alloced_size)
        {
            /* Extending the file */

            n_blocks_left = (UCOUNT) ((n_left + 511) >> 9);
            /* how many clusters are left-
             *  assume 1 for the current cluster.
             *   subtract out the blocks in the current
             *   round up by adding secpalloc-1 and then
             *   divide by sectors per cluster

              |  n_clusters = 1 + 
              |      (n_blocks_left-
              |          (pdrive->secpalloc-block_in_cluster)
              |          + pdrive->secpalloc-1) >> pdrive->log2_secpalloc;
                ==>
             */
            n_clusters = ( UCOUNT) (1 + 
            ((n_blocks_left + block_in_cluster -1) >> pdrive->log2_secpalloc));

            /* Call pc_alloc_chain to build a chain up to n_cluster clusters
               long. Return the first cluster in pfile->fptr_cluster and
               return the # of clusters in the chain. If pfile->fptr_cluster
               is non zero link the current cluster to the new one */

            PC_FAT_ENTER(pdrive->driveno) 
            n_clusters = pc_alloc_chain(pdrive, &(pfile->fptr_cluster), n_clusters);
            PC_FAT_EXIT(pdrive->driveno) 

            if (!n_clusters)
               goto ret_bad_f;

            /* Calculate the last cluster in this chain. */
            next_cluster = (UCOUNT) (pfile->fptr_cluster + n_clusters -1);

            /* link the chain to the directory object if just starting */
            if (!pfile->pobj->finode->fcluster)
                pfile->pobj->finode->fcluster = pfile->fptr_cluster;
            
            /* calculate the new block pointer */
            pfile->fptr_block = pc_cl2sector(pdrive, pfile->fptr_cluster);
    
            /* calculate amount of space used by the file */
            ltemp = n_clusters << pdrive->log2_secpalloc; ltemp <<= 9;
            alloced_size += ltemp;
        }
        else        /* Not extending the file. (writing inside the file) */
        {
            n_blocks_left = (UCOUNT) ((n_left + 511) >> 9);

            /* how many clusters are left-
             *  assume 1 for the current cluster.
             *   subtract out the blocks in the current
             *   round up by adding secpalloc-1 and then
             *   divide by sectors per cluster

              |  n_clusters = 1 + 
              |      (n_blocks_left-
              |          (pdrive->secpalloc-block_in_cluster)
              |          + pdrive->secpalloc-1) >> pdrive->log2_secpalloc;
                ==>
            */
           n_clusters = (UCOUNT) (1 + 
               ((n_blocks_left + block_in_cluster -1) >> pdrive->log2_secpalloc));
                
           /* how many contiguous clusters can we get ? <= n_clusters */
           PC_FAT_ENTER(pdrive->driveno) 
    
           n_clusters = pc_get_chain(pdrive, pfile->fptr_cluster,
                                          &next_cluster, n_clusters);
           PC_FAT_EXIT(pdrive->driveno) 

           if (!n_clusters)
               goto ret_bad_f;
        }

        /* Are we inside a block */
        if ( (pfile->fptr & 0x1ffL) || (n_left < 512) )
        {
            block_in_cluster = (UCOUNT) (pfile->fptr & pdrive->byte_into_cl_mask);
            block_in_cluster >>= 9;
            block_to_write = pfile->fptr_block + block_in_cluster;

           byte_offset_in_block = (UCOUNT) (pfile->fptr & 0x1ffL);

           /* Copy source data to the local buffer */
           n_bytes = (UCOUNT) (512 - byte_offset_in_block);
           if (n_bytes > n_left)
               n_bytes = n_left;

           /* Read */
           PC_DRIVE_IO_ENTER(pdrive->driveno)
           if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, block_to_write, local_buf, 1, YES) )
           {
                PC_DRIVE_IO_EXIT(pdrive->driveno)
                goto ret_bad_f;
           }
           copybuff(&local_buf[byte_offset_in_block], buf, n_bytes);
           /* Write */
           if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, block_to_write, local_buf, 1, NO) )
           {
                PC_DRIVE_IO_EXIT(pdrive->driveno)
                goto ret_bad_f;
           }
           PC_DRIVE_IO_EXIT(pdrive->driveno)

           buf += n_bytes;
           n_left -= n_bytes;
           pfile->fptr += n_bytes;

            /* Are we on a cluster boundary  ? */
           if (!(pfile->fptr & pdrive->byte_into_cl_mask))
           {
               if (--n_clusters)             /* If contiguous */
               {
                    pfile->fptr_block += pdrive->secpalloc;
                    pfile->fptr_cluster += 1;
               }
               else
               {
/* NOTE:            Put the next cluster into the pointer. If we had
                    alloced a chain this value is the last cluster in 
                    the chain and does not concur with the byte file pointer.
                    This is not a problem since the cluster pointer is known 
                    to be off at this point any (fptr>=alloced_size) */
                    pfile->fptr_cluster = next_cluster;
                    pfile->fptr_block = pc_cl2sector(pdrive, next_cluster);
                }   /* if (--nclusters) {} else {}; */
            }       /* if (!(pfile->fptr & byte_into_cl_mask)) */
        }           /* if ( (pfile->fptr & 0x1ff) || (n_left < 512) ) */

        if (n_clusters && (n_left>511))
        {
            /* If we get here we need to write contiguous blocks */
            block_in_cluster = (UCOUNT) (pfile->fptr & pdrive->byte_into_cl_mask);
            block_in_cluster >>= 9;
            block_to_write = pfile->fptr_block + block_in_cluster;
            /* how many do we write ? */
            n_blocks_left = (UCOUNT) (n_left >> 9);
            n_to_write = (UCOUNT) ((n_clusters << pdrive->log2_secpalloc) - block_in_cluster);

            if (n_to_write > n_blocks_left)
            {
                n_to_write = n_blocks_left;

             /* If we are not writing to the end of the chain we may not
                advance the cluster pointer to the beginning of the next
                chain. We add in block_in_cluster so we account for the
                partial cluster we've already seen */
                next_cluster = (UCOUNT) (pfile->fptr_cluster +
                                 ((n_to_write+block_in_cluster) >>  pdrive->log2_secpalloc));
            }
            PC_DRIVE_IO_ENTER(pdrive->driveno)
            if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, block_to_write, buf, n_to_write, NO))
            {
                 PC_DRIVE_IO_EXIT(pdrive->driveno)
                 goto ret_bad_f;
            }
            PC_DRIVE_IO_EXIT(pdrive->driveno)
            n_bytes = (UCOUNT) (n_to_write << 9);

            buf += n_bytes;  n_left -= n_bytes;
            pfile->fptr += n_bytes;

/* See note above */
            pfile->fptr_cluster = next_cluster;
            pfile->fptr_block   = pc_cl2sector(pdrive, next_cluster);
        }
    }       /* while n_left */

    if (pfile->fptr > pfile->pobj->finode->fsize)
        pfile->pobj->finode->fsize = pfile->fptr;
    /* 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;
        
    PC_INODE_EXIT(pfile->pobj->finode)
    PC_DRIVE_EXIT(pdrive->driveno)

    /* Restore the kernel state */
    PC_FS_EXIT()
    return(count);

ret_bad_f:
    /* Restore pointers and return */
    pfile->fptr = saved_ptr;
    pfile->fptr_block = saved_ptr_block;        
    pfile->fptr_cluster = saved_ptr_cluster;        
    fs_user->p_errno = PENOSPC;
    PC_INODE_EXIT(pfile->pobj->finode)      /* Release excl use of finode */
    PC_DRIVE_EXIT(pdrive->driveno)          /* Release non-excl use of drive */
    ret_val = (UCOUNT) ~0;
return_error:
    /* Restore the kernel state */
    PC_FS_EXIT()
    return(ret_val);
}

/**************************************************************************
    PO_LSEEK    -  Move file pointer

 Description
    Move the file pointer offset bytes from the origin described by 
    origin. The file pointer is set according to the following rules.

    Origin               Rule
    PSEEK_SET            offset from begining of file
    PSEEK_CUR            offset from current file pointer
    PSEEK_END            offset from end of file

    Attempting to seek beyond end of file puts the file pointer one
    byte past eof. 

 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.

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

LONG NU_Seek(PCFD fd, LONG offset, COUNT origin)				   /*__fn__*/
{
    PC_FILE *pfile;
    DDRIVE *pdrive;
    LONG   ret_val;
    PC_FS_ENTER()     /* Must be last line in declarations */
    CHECK_USER(LONG, -1) /* Check if a valid user if multitasking */

    fs_user->p_errno = 0;    

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

    if (!pfile)
    {
        fs_user->p_errno = PEBADF;
        ret_val = -1L;
        goto return_error;
    }

    pdrive = pfile->pobj->pdrive;
    PC_DRIVE_ENTER(pdrive->driveno, NO)  /* Register drive in use */
    /* Grab exclusive access to the drobj */
    PC_INODE_ENTER(pfile->pobj->finode, YES)

    /* 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_Truncate */
    ret_val =  _po_lseek(pfile, offset, origin);

    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);
}

/**************************************************************************
    NU_Truncate    -  Truncate an open file.

 Description
    Move the file pointer offset bytes from the beginning of the file
    and truncate the file beyond that point by adjusting the file size
    and freeing the cluster chain past the file pointer.
 
 Returns
    Returns YES if successful otherwise NO

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

    PENBADF        - File descriptor invalid or open read only
    PENOSPC        - IO error
    PEINVAL        - Invalid offset
    PESHARE        - Can not truncate a file open by more than one handle.

---------

    BobB             2/18/99    Changed name of po_truncate to NU_Truncate

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

BOOL NU_Truncate(PCFD fd, LONG offset)                                /*__fn__*/
{
    PC_FILE *pfile;
    DDRIVE *pdrive;
    BOOL   ret_val;
    UCOUNT first_cluster_to_release;
    UCOUNT last_cluster_in_chain;
    UCOUNT clno;
    PC_FS_ENTER()     /* Must be last line in declarations */
    CHECK_USER(BOOL, 0) /* Check if a valid user if multitasking */

    fs_user->p_errno = 0;    

⌨️ 快捷键说明

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