static int fatfs_umount(cyg_mtab_entry *mte) { fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; fatfs_node_t *root = (fatfs_node_t *) mte->root; CYG_TRACE3(TFS, "umount mte=%p %d live nodes %d dead nodes", mte, fatfs_get_live_node_count(disk), fatfs_get_dead_node_count(disk)); if (root->refcnt > 1) return EBUSY; if (fatfs_get_live_node_count(disk) != 1) return EBUSY; fatfs_node_unref(disk, root); fatfs_node_cache_flush(disk); // FIXME: cache delete can fail if cache can't be synced cyg_blib_delete(&disk->blib); free(disk->bcache_mem); free(disk); mte->root = CYG_DIR_NULL; mte->data = (CYG_ADDRWORD) NULL; CYG_TRACE0(TFS, "disk umounted"); return ENOERR; }
static int fatfs_unlink(cyg_mtab_entry *mte, cyg_dir dir, const char *name) { fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; fatfs_dirsearch_t ds; int err; CYG_TRACE3(TFS, "unlink mte=%p dir=%p name='%s'", mte, dir, name); init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name); err = fatfs_find(&ds); if (err != ENOERR) return err; if (ds.node->refcnt > 0) return EBUSY; #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES // if the file is read only fail with permission error if (S_FATFS_ISRDONLY(ds.node->dentry.attrib)) return EPERM; #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES err = fatfs_delete_file(disk, &ds.node->dentry); if (err == ENOERR) fatfs_node_free(disk, ds.node); return err; }
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; fatfs_dir_entry_t dentry; int err; 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, &dentry); if (err != ENOERR) return (err == EEOF ? ENOERR : err); strcpy(nbuf, dentry.filename); #ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE ent->d_type = dentry.mode; #endif fd->node->dentry.atime = cyg_timestamp(); uio->uio_resid -= sizeof(struct dirent); fp->f_offset++; return ENOERR; }
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; }
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; }
static int fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name) { fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; fatfs_dirsearch_t ds; int err; CYG_TRACE3(TFS, "mkdir mte=%p dir=%p name='%s'", mte, dir, name); init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); if (err == ENOENT) { if (ds.last) { fatfs_dir_entry_t new_dir_dentry; // The entry does not exist, and it is the last element in // the pathname, so we can create it here err = fatfs_create_dir(disk, &ds.dir->dentry, ds.name, ds.namelen, &new_dir_dentry); if (err != ENOERR) return err; fatfs_node_alloc(disk, &new_dir_dentry); return ENOERR; } } else if (err == ENOERR) { return EEXIST; } return err; }
fatfs_node_t* fatfs_node_find(fatfs_disk_t *disk, const char *name, unsigned int namelen, unsigned int parent_cluster) { fatfs_node_t *node; CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(name); node = node_hash_find(&disk->node_hash, name, namelen, parent_cluster); NODE_FIND_CHECK(); CYG_TRACE3(TNC, "node name=%s pcluster=%d %s found in cache\n", name, parent_cluster, ((node != NULL) ? "" : "not")); return node; }
static int fatfs_rmdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name) { fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; fatfs_dirsearch_t ds; int err; fatfs_node_t *node; CYG_TRACE3(TFS, "rmdir mte=%p dir=%p name='%s'", mte, dir, name); init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); if (err != ENOERR) return err; if (!S_ISDIR(ds.node->dentry.mode)) return EPERM; if (ds.node->refcnt > 0) return EBUSY; err = fatfs_delete_file(disk, &ds.node->dentry); if (err == ENOERR) { node = fatfs_node_find( disk, ".", 1, ds.node->dentry.cluster ); if (node != NULL) fatfs_node_free(disk, node); node = fatfs_node_find( disk, "..", 2, ds.node->dentry.cluster ); if (node != NULL) fatfs_node_free(disk, node); fatfs_node_free(disk, ds.node); } return err; }
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; }
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; }