📄 fatfs.c
字号:
// 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 + -