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; }
//int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsigned end) int jffs2_commit_write (struct inode *d_inode, struct page *pg, unsigned start, unsigned end) { /* Actually commit the write from the page cache page we're looking at. * For now, we write the full page out each time. It sucks, but it's simple */ struct inode *inode = d_inode; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_raw_inode *ri; int ret = 0; uint32_t writtenlen = 0; D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end)); ri = jffs2_alloc_raw_inode(); if (!ri) { D1(printk(KERN_DEBUG "jffs2_commit_write(): Allocation of raw inode failed\n")); return -ENOMEM; } /* Set the fields that the generic jffs2_write_inode_range() code can't find */ ri->ino = cpu_to_je32(inode->i_ino); ri->mode = cpu_to_jemode(inode->i_mode); ri->uid = cpu_to_je16(inode->i_uid); ri->gid = cpu_to_je16(inode->i_gid); ri->isize = cpu_to_je32((uint32_t)inode->i_size); ri->atime = ri->ctime = ri->mtime = cpu_to_je32(cyg_timestamp()); ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + start, (pg->index << PAGE_CACHE_SHIFT) + start, end - start, &writtenlen); if (ret) { /* There was an error writing. */ SetPageError(pg); } if (writtenlen) { if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) { inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; inode->i_ctime = inode->i_mtime = je32_to_cpu(ri->ctime); } } jffs2_free_raw_inode(ri); if (start+writtenlen < end) { /* generic_file_write has written more to the page cache than we've actually written to the medium. Mark the page !Uptodate so that it gets reread */ D1(printk(KERN_DEBUG "jffs2_commit_write(): Not all bytes written. Marking page !uptodate\n")); SetPageError(pg); ClearPageUptodate(pg); } D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret)); return writtenlen?writtenlen:ret; }
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; }
//int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, unsigned end) int jffs2_prepare_write (struct inode *d_inode, struct page *pg, unsigned start, unsigned end) { struct inode *inode = d_inode; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT; int ret = 0; D1(printk(KERN_DEBUG "jffs2_prepare_write()\n")); if (pageofs > inode->i_size) { /* Make new hole frag from old EOF to new page */ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; uint32_t phys_ofs, alloc_len; D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs)); ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); if (ret) return ret; down(&f->sem); memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); ri.totlen = cpu_to_je32(sizeof(ri)); ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); ri.mode = cpu_to_jemode(inode->i_mode); ri.uid = cpu_to_je16(inode->i_uid); ri.gid = cpu_to_je16(inode->i_gid); ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); ri.atime = ri.ctime = ri.mtime = cpu_to_je32(cyg_timestamp()); ri.offset = cpu_to_je32(inode->i_size); ri.dsize = cpu_to_je32(pageofs - inode->i_size); ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); ri.data_crc = cpu_to_je32(0); fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, NULL); jffs2_complete_reservation(c); if (IS_ERR(fn)) { ret = PTR_ERR(fn); up(&f->sem); return ret; } ret = jffs2_add_full_dnode_to_inode(c, f, fn); if (f->metadata) { jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_free_full_dnode(f->metadata); f->metadata = NULL; } if (ret) { D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret)); jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); up(&f->sem); return ret; } inode->i_size = pageofs; up(&f->sem); } /* Read in the page if it wasn't already present, unless it's a whole page */ // eCos has no concept of uptodate and by default always reads pages afresh if (!Page_Uptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { down(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); up(&f->sem); } D1(printk(KERN_DEBUG "end prepare_write()\n")); return ret; }
int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct _inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen, phys_ofs; int ret; mode |= S_IFDIR; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ namelen = strlen(d_name); ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } f = JFFS2_INODE_INFO(inode); ri->data_crc = cpu_to_je32(0); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); inode->i_nlink = 0; jffs2_iput(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); jffs2_complete_reservation(c); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { /* Eep. */ inode->i_nlink = 0; jffs2_iput(inode); return ret; } rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); inode->i_nlink = 0; jffs2_iput(inode); return -ENOMEM; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); rd->pino = cpu_to_je32(dir_i->i_ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(inode->i_ino); rd->mctime = cpu_to_je32(cyg_timestamp()); rd->nsize = namelen; rd->type = DT_DIR; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, phys_ofs, ALLOC_NORMAL); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ up(&dir_f->sem); inode->i_nlink = 0; jffs2_iput(inode); return PTR_ERR(fd); } /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); jffs2_iput(inode); return 0; }
static int fatfs_rename(cyg_mtab_entry *mte, cyg_dir dir1, const char *name1, cyg_dir dir2, const char *name2) { fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; fatfs_dirsearch_t ds1, ds2; int err; CYG_TRACE5(TFS, "rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'", mte, dir1, name1, dir2, name2); init_dirsearch(&ds1, disk, (fatfs_node_t *)dir1, name1); err = fatfs_find(&ds1); if (err != ENOERR) return err; #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES // if the file is read only fail with permission error if (S_FATFS_ISRDONLY(ds1.node->dentry.attrib)) return EPERM; #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES // Protect the found nodes from being reused // by the search for the ds2 dir/node pair fatfs_node_ref(disk, ds1.dir); fatfs_node_ref(disk, ds1.node); init_dirsearch(&ds2, disk, (fatfs_node_t *) dir2, name2); err = fatfs_find(&ds2); // Check if the target name already exists if (err == ENOERR && ds2.last) { err = EEXIST; goto out; } // Check if the target dir doesn't exist if (err == ENOENT && !ds2.last) goto out; // Check if the target and the source are the same if (ds1.node == ds2.node) { err = ENOERR; goto out; } err = fatfs_rename_file(disk, &ds1.dir->dentry, &ds1.node->dentry, &ds2.dir->dentry, ds2.name, ds2.namelen); fatfs_node_rehash(disk, ds1.node); out: // Unreference previousely protected nodes fatfs_node_unref(disk, ds1.dir); fatfs_node_unref(disk, ds1.node); if (err == ENOERR) { ds1.dir->dentry.atime = ds1.dir->dentry.mtime = ds2.dir->dentry.atime = ds2.dir->dentry.mtime = cyg_timestamp(); } return err; }
static int fatfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name, int mode, cyg_file *file) { fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; fatfs_node_t *node = NULL; fatfs_fd_t *fd; fatfs_dirsearch_t ds; int err; CYG_TRACE5(TFS, "open mte=%p dir=%p name='%s' mode=%d file=%p", mte, dir, name, mode, file); init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); if (err == ENOENT) { if (ds.last && (mode & O_CREAT)) { fatfs_dir_entry_t new_file_dentry; // No node there, if the O_CREAT bit is set then we must // create a new one. The dir and name fields of the dirsearch // object will have been updated so we know where to put it. CYG_TRACE1(TFS, "creating new file '%s'", name); err = fatfs_create_file(disk, &ds.dir->dentry, ds.name, ds.namelen, &new_file_dentry); if (err != ENOERR) return err; node = fatfs_node_alloc(disk, &new_file_dentry); if (NULL == node) return EMFILE; // Update directory times ds.dir->dentry.atime = ds.dir->dentry.mtime = cyg_timestamp(); err = ENOERR; } } else if (err == ENOERR) { // The node exists. If the O_CREAT and O_EXCL bits are set, we // must fail the open if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) err = EEXIST; else node = ds.node; } if (err == ENOERR && (mode & O_TRUNC)) { // If the O_TRUNC bit is set we must clean out the file data CYG_TRACE0(TFS, "truncating file"); fatfs_trunc_file(disk, &node->dentry); } if (err != ENOERR) return err; if (S_ISDIR(node->dentry.mode)) return EISDIR; #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES // if the file is read only and is opened for writing // fail with permission error if (S_FATFS_ISRDONLY(node->dentry.attrib) && (mode & O_WRONLY)) return EACCES; #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES // Allocate file object private data and // make a reference to this file node fd = alloc_fatfs_fd(disk, node); if (NULL == fd) return EMFILE; fatfs_node_ref(disk, node); // Initialize the file object if (mode & O_APPEND) fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size); file->f_flag |= mode & CYG_FILE_MODE_MASK; file->f_type = CYG_FILE_TYPE_FILE; file->f_ops = &fatfs_fileops; file->f_offset = (mode & O_APPEND) ? node->dentry.size : 0; file->f_data = (CYG_ADDRWORD) fd; file->f_xops = 0; return ENOERR; }
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; }