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

📄 fatfs.c

📁 嵌入式FAT文件系统
💻 C
📖 第 1 页 / 共 4 页
字号:
// Set FAT file system attributes for specified file

static int
fatfs_get_attrib(cyg_mtab_entry  *mte,
                 cyg_dir          dir,
                 const char      *name,
                 cyg_fs_attrib_t * const file_attrib)
{
    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
    fatfs_dirsearch_t  ds;
    int                err;

    CYG_TRACE4(TFS, "get_attrib mte=%p dir=%p name='%s' buf=%x", 
                    mte, dir, name, file_attrib);

    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);

    err = fatfs_find(&ds);
    if (err != ENOERR)
        return err;

    // Get the attribute field
    CYG_CHECK_DATA_PTR(file_attrib,"Invalid destination attribute pointer");
    *file_attrib = ds.node->dentry.attrib;

    return ENOERR;
}
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES

// -------------------------------------------------------------------------
// fatfs_getinfo()
// Getinfo. Support for attrib

static int 
fatfs_getinfo(cyg_mtab_entry *mte, 
              cyg_dir         dir, 
              const char     *name,
              int             key, 
              void           *buf, 
              int             len)
{
    int err = EINVAL;

    CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
                    mte, dir, name, key, buf, len);
    switch( key )
    {
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
        case FS_INFO_ATTRIB:
            err = fatfs_get_attrib(mte, dir, name, (cyg_fs_attrib_t*)buf);
            break;
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
#if defined(CYGSEM_FILEIO_INFO_DISK_USAGE)
        case FS_INFO_DISK_USAGE: {
	  cyg_uint32 total_clusters;
	  cyg_uint32 free_clusters;
	  struct cyg_fs_disk_usage *usage = (struct cyg_fs_disk_usage *) buf;
	  fatfs_disk_t  *disk   = (fatfs_disk_t *) mte->data;

	  err = fatfs_get_disk_usage(disk, &total_clusters, &free_clusters);
	  if (err)
	    return err;
	  usage->total_blocks = total_clusters; 
	  usage->free_blocks = free_clusters;
	  usage->block_size = disk->cluster_size;
	  break;
	}
#endif
        default:
            err = EINVAL;
            break;
    }
    return err;
}

// -------------------------------------------------------------------------
// fatfs_setinfo()
// Setinfo. Support for fssync and attrib

static int 
fatfs_setinfo(cyg_mtab_entry *mte, 
              cyg_dir         dir, 
              const char     *name,
              int             key, 
              void           *buf, 
              int             len)
{
    int err = EINVAL;

    CYG_TRACE6(TFS, "setinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
                    mte, dir, name, key, buf, len);

    switch( key )
    {
        case FS_INFO_SYNC:
            err = cyg_blib_sync(&(((fatfs_disk_t *) mte->data)->blib));
            break;
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
        case FS_INFO_ATTRIB:
            err = fatfs_set_attrib(mte, dir, name, *(cyg_fs_attrib_t *)buf);
            break;
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
        default:
            err = EINVAL;
            break;
    }
    return err;
}

//==========================================================================
// File operations

// -------------------------------------------------------------------------
// fatfs_fo_read()
// Read data from the file.

static int 
fatfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
    fatfs_disk_t  *disk   = (fatfs_disk_t *) fp->f_mte->data;
    fatfs_fd_t    *fd     = (fatfs_fd_t *)   fp->f_data;
    fatfs_node_t  *node   = fd->node;
    cyg_uint32     pos    = fp->f_offset;
    ssize_t        resid  = uio->uio_resid;
    int            i;

    CYG_TRACE3(TFO, "read fp=%p uio=%p pos=%d", fp, uio, pos);

    // Loop over the io vectors until there are none left

    for (i = 0; i < uio->uio_iovcnt; i++)
    {
        cyg_iovec  *iov  = &uio->uio_iov[i];
        char       *buf  = (char *) iov->iov_base;
        off_t       len  = iov->iov_len;

        // Loop over each vector filling it with data from the file
        
        while (len > 0 && pos < node->dentry.size)
        {
            cyg_uint32 l = len;
            int        err;

            // Adjust size to end of file if necessary
            if (l > node->dentry.size-pos)
                l = node->dentry.size-pos;

            err = fatfs_read_data(disk, &node->dentry, &fd->pos, buf, &l);
            if (err != ENOERR)
                return err;

            // Update working vars

            len   -= l;
            buf   += l;
            pos   += l;
            resid -= l;
        }
    }

    // We successfully read some data, update the access time, 
    // file offset and transfer residue

    node->dentry.atime = cyg_timestamp(); 
    uio->uio_resid     = resid;
    fp->f_offset       = (off_t) pos;

    return ENOERR;
}

// -------------------------------------------------------------------------
// fatfs_fo_write()
// Write data to file.

static int 
fatfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
    fatfs_disk_t  *disk   = (fatfs_disk_t *) fp->f_mte->data;
    fatfs_fd_t    *fd     = (fatfs_fd_t *)   fp->f_data;
    fatfs_node_t  *node   = fd->node;
    cyg_uint32     pos    = fp->f_offset;
    ssize_t        resid  = uio->uio_resid;
    int            err    = ENOERR;
    int            i;

    CYG_TRACE3(TFO, "write fp=%p uio=%p pos=%d", fp, uio, pos);
    
    // If the APPEND mode bit was supplied, force all writes to
    // the end of the file
    if (fp->f_flag & CYG_FAPPEND)
    {
        fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
        pos = fp->f_offset = node->dentry.size;
    }
    
    // Check that pos is within current file size, or at the very end
    if (pos < 0 || pos > node->dentry.size)
        return EINVAL;
   
    // Now loop over the iovecs until they are all done, or we get an error
    
    for (i = 0; i < uio->uio_iovcnt; i++)
    {
        cyg_iovec  *iov  = &uio->uio_iov[i];
        char       *buf  = (char *) iov->iov_base;
        off_t       len  = iov->iov_len;
 
        // Loop over the vector writing it to the file 
        // until it has all been done

        while (len > 0)
        {
            cyg_uint32 l = len;

            err = fatfs_write_data(disk, &node->dentry, &fd->pos, buf, &l);

            // Update working vars

            len   -= l;
            buf   += l;
            pos   += l;
            resid -= l;

            // Stop writing if there is no more space in the file
            if (err == ENOSPC)
                break;
            
            if (err != ENOERR)
                return err;
        }
    }        

    // We wrote some data successfully, update the modified and access
    // times of the node, increase its size appropriately, and update
    // the file offset and transfer residue.

    node->dentry.mtime = 
    node->dentry.atime = cyg_timestamp();

    if (pos > node->dentry.size)
        node->dentry.size = pos;

    uio->uio_resid = resid;
    fp->f_offset   = (off_t) pos;

    return err;
}

// -------------------------------------------------------------------------
// fatfs_fo_lseek()
// Seek to a new file position.

static int 
fatfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)
{
    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
    off_t          pos   = *apos;
    int            err;
    
    CYG_TRACE3(TFO, "lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence);

    switch (whence)
    {
        case SEEK_SET:
            // Pos is already where we want to be
            break;
         case SEEK_CUR:
            // Add pos to current offset
            pos += fp->f_offset;
            break;
         case SEEK_END:
            // Add pos to file size
            pos += fd->node->dentry.size;
            break;
         default:
            return EINVAL;
    }

    // Check that pos is still within current file size, 
    // or at the very end
    if (pos < 0 || pos > fd->node->dentry.size)
        return EINVAL;
  
    // All OK, set fp offset and return new position
    
    err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, pos);

    if (ENOERR == err)
        *apos = fp->f_offset = pos;
    
    CYG_TRACE2(TFO, "lseek fp=%p new pos=%d", fp, *apos);

    return err;
}

// -------------------------------------------------------------------------
// fatfs_fo_ioctl()
// Handle ioctls. Currently none are defined.

static int 
fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data)
{
    CYG_TRACE3(TFO, "ioctl fp=%p com=%x data=%x", fp, com, data);
    return EINVAL;
}

// -------------------------------------------------------------------------
// fatfs_fo_fsync().
// Force the file out to data storage.

static int 
fatfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
{
    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
    fatfs_node_t  *node  = fd->node;
    int            err;
    
    CYG_TRACE2(TFO, "fsync fp=%p mode=%d", fp, mode);

    err = fatfs_write_dir_entry(disk, &node->dentry);

    if (ENOERR == err)
        err = cyg_blib_sync(&disk->blib);
    
    return err;
}

// -------------------------------------------------------------------------
// fatfs_fo_close()
// Close a file.

static int
fatfs_fo_close(struct CYG_FILE_TAG *fp)
{    
    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
    fatfs_node_t  *node  = fd->node;
    int            err   = ENOERR;

    CYG_TRACE1(TFO, "close fp=%p", fp);

    // Write file attributes to disk, unreference 
    // the file node and free its private data

    if (node != disk->root)
        err = fatfs_write_dir_entry(disk, &node->dentry);

    fatfs_node_unref(disk, node);    

    free_fatfs_fd(fd);
    
    return err;
}

// -------------------------------------------------------------------------
// fatfs_fo_fstat()
// Get file status.

static int
fatfs_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
{
    fatfs_fd_t    *fd    = (fatfs_fd_t *) fp->f_data;
    fatfs_node_t  *node  = fd->node;
    
    CYG_TRACE2(TFO, "fstat fp=%p buf=%p", fp, buf);

    // Fill in the status

    buf->st_mode   = node->dentry.mode;
    buf->st_ino    = (ino_t) node->dentry.cluster;
    buf->st_dev    = 0;
    buf->st_nlink  = 1;
    buf->st_uid    = 0;
    buf->st_gid    = 0;
    buf->st_size   = node->dentry.size;
    buf->st_atime  = node->dentry.atime;
    buf->st_mtime  = node->dentry.mtime;
    buf->st_ctime  = node->dentry.ctime;

    return ENOERR;
}

// -------------------------------------------------------------------------
// fatfs_fo_getinfo()
// Get info.

static int
fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
{
    CYG_TRACE4(TFO, "getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
    return EINVAL;
}

// -------------------------------------------------------------------------
// fatfs_fo_setinfo()
// Set info.

static int
fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
{
    CYG_TRACE4(TFO, "setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
    return EINVAL;
}

//==========================================================================
// Directory operations

// -------------------------------------------------------------------------
// fatfs_fo_dirread()
// Read a single directory entry from a file.
 static fatfs_dir_entry_t  dirread_dentry;
static int 
fatfs_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
    fatfs_disk_t      *disk    = (fatfs_disk_t *)  fp->f_mte->data;
    fatfs_fd_t        *fd      = (fatfs_fd_t *)    fp->f_data;
    struct dirent     *ent     = (struct dirent *) uio->uio_iov[0].iov_base;
    char              *nbuf    = ent->d_name;
    off_t              len     = uio->uio_iov[0].iov_len;
  
    int                err;
    memset(&dirread_dentry,0,sizeof(fatfs_dir_entry_t));
    CYG_TRACE3(TFO, "dirread fp=%p uio=%p pos=%d", fp, uio, fp->f_offset);

    if (len < sizeof(struct dirent))
        return EINVAL;

    err = fatfs_read_dir_entry(disk, &fd->node->dentry, &fd->pos, &dirread_dentry);

    if (err != ENOERR)
        return (err == EEOF ? ENOERR : err);
    if(dirread_dentry.longfilename[0]==0)
    {
    	strcpy(nbuf, dirread_dentry.filename);
    }
    else
    {
	strcpy(nbuf, dirread_dentry.longfilename);
     }
    fd->node->dentry.atime  = cyg_timestamp();
    uio->uio_resid         -= sizeof(struct dirent);
    fp->f_offset++;
    
    return ENOERR;
}

// -------------------------------------------------------------------------
// fatfs_fo_dirlseek()
// Seek directory to start.

static int 
fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence)
{
    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
    int            err;
    
    CYG_TRACE2(TFO, "dirlseek fp=%p whence=%d", fp, whence);

    // Only allow SEEK_SET to zero
    
    if (whence != SEEK_SET || *pos != 0)
        return EINVAL;
   
    err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, 0);

    if (ENOERR == err)
        *pos = fp->f_offset = 0;
    
    return err;
}

// -------------------------------------------------------------------------
// EOF fatfs.c

⌨️ 快捷键说明

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