Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}