diff options
Diffstat (limited to 'cpukit/libfs/src/jffs2/src/fs-rtems.c')
-rw-r--r-- | cpukit/libfs/src/jffs2/src/fs-rtems.c | 2518 |
1 files changed, 960 insertions, 1558 deletions
diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c index c38b71906c..376c77f45f 100644 --- a/cpukit/libfs/src/jffs2/src/fs-rtems.c +++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c @@ -1,11 +1,16 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Free Software Foundation, Inc. + * Copyright © 2001-2003 Free Software Foundation, Inc. + * Copyright © 2001-2007 Red Hat, Inc. + * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> + * Copyright © 2013 embedded brains GmbH <rtems@embedded-brains.de> * * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com> * Contributors: David Woodhouse, Nick Garnett, Richard Panton. * + * Port to the RTEMS by embedded brains GmbH. + * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: fs-ecos.c,v 1.44 2005/07/24 15:29:57 dedekind Exp $ @@ -19,164 +24,38 @@ #include "compr.h" #include <errno.h> #include <string.h> -#include <cyg/io/config_keys.h> - -#if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && \ - (defined (__arm__) || defined (_mips)) -#error This compiler is known to be broken. Please see: -#error "http://ecos.sourceware.org/ml/ecos-patches/2003-08/msg00006.html" -#endif - -//========================================================================== -// Forward definitions - -// Filesystem operations -static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte); -static int jffs2_umount(cyg_mtab_entry * mte); -static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - int mode, cyg_file * fte); -#ifdef CYGOPT_FS_JFFS2_WRITE -static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, - const char *name); -static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name); -static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name); -static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1, - const char *name1, cyg_dir dir2, const char *name2); -static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1, - cyg_dir dir2, const char *name2, int type); -#endif -static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - cyg_file * fte); -static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - cyg_dir * dir_out); -static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - struct stat *buf); -static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - int key, void *buf, int len); -static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - int key, void *buf, int len); - -// File operations -static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); -#ifdef CYGOPT_FS_JFFS2_WRITE -static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); -#endif -static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence); -static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, - CYG_ADDRWORD data); -static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode); -static int jffs2_fo_close(struct CYG_FILE_TAG *fp); -static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf); -static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, - int len); -static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, - int len); - -// Directory operations -static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); -static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence); - +#include <assert.h> +#include <rtems/libio_.h> + +/* Ensure that the JFFS2 values are identical to the POSIX defines */ + +RTEMS_STATIC_ASSERT(DT_DIR == (S_IFDIR >> 12), DT_DIR); +RTEMS_STATIC_ASSERT(DT_LNK == (S_IFLNK >> 12), DT_LNK); +RTEMS_STATIC_ASSERT(DT_REG == (S_IFREG >> 12), DT_REG); + +RTEMS_STATIC_ASSERT(00400 == S_IRUSR, S_IRUSR); +RTEMS_STATIC_ASSERT(00200 == S_IWUSR, S_IWUSR); +RTEMS_STATIC_ASSERT(00100 == S_IXUSR, S_IXUSR); +RTEMS_STATIC_ASSERT(00040 == S_IRGRP, S_IRGRP); +RTEMS_STATIC_ASSERT(00020 == S_IWGRP, S_IWGRP); +RTEMS_STATIC_ASSERT(00010 == S_IXGRP, S_IXGRP); +RTEMS_STATIC_ASSERT(00004 == S_IROTH, S_IROTH); +RTEMS_STATIC_ASSERT(00002 == S_IWOTH, S_IWOTH); +RTEMS_STATIC_ASSERT(00001 == S_IXOTH, S_IXOTH); + +RTEMS_STATIC_ASSERT(0140000 == S_IFSOCK, S_IFSOCK); +RTEMS_STATIC_ASSERT(0120000 == S_IFLNK, S_IFLNK); +RTEMS_STATIC_ASSERT(0100000 == S_IFREG, S_IFREG); +RTEMS_STATIC_ASSERT(0060000 == S_IFBLK, S_IFBLK); +RTEMS_STATIC_ASSERT(0040000 == S_IFDIR, S_IFDIR); +RTEMS_STATIC_ASSERT(0020000 == S_IFCHR, S_IFCHR); +RTEMS_STATIC_ASSERT(0010000 == S_IFIFO, S_IFIFO); +RTEMS_STATIC_ASSERT(0004000 == S_ISUID, S_ISUID); +RTEMS_STATIC_ASSERT(0002000 == S_ISGID, S_ISGID); +RTEMS_STATIC_ASSERT(0001000 == S_ISVTX, S_ISVTX); static int jffs2_read_inode (struct _inode *inode); static void jffs2_clear_inode (struct _inode *inode); -static int jffs2_truncate_file (struct _inode *inode); - -//========================================================================== -// Filesystem table entries - -// ------------------------------------------------------------------------- -// Fstab entry. -// This defines the entry in the filesystem table. -// For simplicity we use _FILESYSTEM synchronization for all accesses since -// we should never block in any filesystem operations. - -#ifdef CYGOPT_FS_JFFS2_WRITE -FSTAB_ENTRY(jffs2_fste, "jffs2", 0, - CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM, - jffs2_mount, - jffs2_umount, - jffs2_open, - jffs2_ops_unlink, - jffs2_ops_mkdir, - jffs2_ops_rmdir, - jffs2_ops_rename, - jffs2_ops_link, - jffs2_opendir, - jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo); -#else -FSTAB_ENTRY(jffs2_fste, "jffs2", 0, - CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM, - jffs2_mount, - jffs2_umount, - jffs2_open, - (cyg_fsop_unlink *)cyg_fileio_erofs, - (cyg_fsop_mkdir *)cyg_fileio_erofs, - (cyg_fsop_rmdir *)cyg_fileio_erofs, - (cyg_fsop_rename *)cyg_fileio_erofs, - (cyg_fsop_link *)cyg_fileio_erofs, - jffs2_opendir, - jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo); -#endif - -// ------------------------------------------------------------------------- -// File operations. -// This set of file operations are used for normal open files. - -static cyg_fileops jffs2_fileops = { - jffs2_fo_read, -#ifdef CYGOPT_FS_JFFS2_WRITE - jffs2_fo_write, -#else - (cyg_fileop_write *) cyg_fileio_erofs, -#endif - jffs2_fo_lseek, - jffs2_fo_ioctl, - cyg_fileio_seltrue, - jffs2_fo_fsync, - jffs2_fo_close, - jffs2_fo_fstat, - jffs2_fo_getinfo, - jffs2_fo_setinfo -}; - -// ------------------------------------------------------------------------- -// Directory file operations. -// This set of operations are used for open directories. Most entries -// point to error-returning stub functions. Only the read, lseek and -// close entries are functional. - -static cyg_fileops jffs2_dirops = { - jffs2_fo_dirread, - (cyg_fileop_write *) cyg_fileio_enosys, - jffs2_fo_dirlseek, - (cyg_fileop_ioctl *) cyg_fileio_enosys, - cyg_fileio_seltrue, - (cyg_fileop_fsync *) cyg_fileio_enosys, - jffs2_fo_close, - (cyg_fileop_fstat *) cyg_fileio_enosys, - (cyg_fileop_getinfo *) cyg_fileio_enosys, - (cyg_fileop_setinfo *) cyg_fileio_enosys -}; - -//========================================================================== -// STATIC VARIABLES !!! - -static unsigned char gc_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure -static unsigned char n_fs_mounted = 0; // a counter to track the number of jffs2 instances mounted - -//========================================================================== -// Directory operations - -struct jffs2_dirsearch { - struct _inode *dir; // directory to search - const unsigned char *path; // path to follow - struct _inode *node; // Node found - const unsigned char *name; // last name fragment used - int namelen; // name fragment length - cyg_bool last; // last name in path? -}; - -typedef struct jffs2_dirsearch jffs2_dirsearch; //========================================================================== // Ref count and nlink management @@ -214,1550 +93,1157 @@ static void icache_evict(struct _inode *root_i, struct _inode *i) } } -//========================================================================== -// Directory search - // ------------------------------------------------------------------------- -// init_dirsearch() -// Initialize a dirsearch object to start a search - -static void init_dirsearch(jffs2_dirsearch * ds, - struct _inode *dir, const unsigned char *name) +// jffs2_fo_write() +// Write data to file. +static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri, + unsigned long offset) { - D2(printf("init_dirsearch name = %s\n", name)); - D2(printf("init_dirsearch dir = %x\n", dir)); - - dir->i_count++; - ds->dir = dir; - ds->path = name; - ds->node = dir; - ds->name = name; - ds->namelen = 0; - ds->last = false; -} - -// ------------------------------------------------------------------------- -// find_entry() -// Search a single directory for the next name in a path and update the -// dirsearch object appropriately. + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_full_dnode *fn; + uint32_t alloc_len; + int ret = 0; -static int find_entry(jffs2_dirsearch * ds) -{ - struct _inode *dir = ds->dir; - const unsigned char *name = ds->path; - const unsigned char *n = name; - char namelen = 0; - struct _inode *d; + /* Make new hole frag from old EOF to new page */ + D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", + (unsigned int)inode->i_size, offset)); - D2(printf("find_entry\n")); + ret = jffs2_reserve_space(c, sizeof(*ri), &alloc_len, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) + return ret; - // check that we really have a directory - if (!S_ISDIR(dir->i_mode)) - return ENOTDIR; + mutex_lock(&f->sem); - // Isolate the next element of the path name. - while (*n != '\0' && *n != '/') - n++, namelen++; + 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)); - // Check if this is the last path element. - while( *n == '/') n++; - if (*n == '\0') - ds->last = true; + ri->version = cpu_to_je32(++f->highest_version); + ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset)); - // update name in dirsearch object - ds->name = name; - ds->namelen = namelen; + ri->offset = cpu_to_je32(inode->i_size); + ri->dsize = cpu_to_je32(offset - 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, ALLOC_NORMAL); + jffs2_complete_reservation(c); + if (IS_ERR(fn)) { + ret = PTR_ERR(fn); + mutex_unlock(&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); + mutex_unlock(&f->sem); + return ret; + } + inode->i_size = offset; + mutex_unlock(&f->sem); + return 0; +} - if (name[0] == '.') - switch (namelen) { - default: - break; - case 2: - // Dot followed by not Dot, treat as any other name - if (name[1] != '.') - break; - // Dot Dot - // Move back up the search path - D2(printf("find_entry found ..\n")); - ds->dir = ds->node; - ds->node = ds->dir->i_parent; - ds->node->i_count++; - return ENOERR; - case 1: - // Dot is consumed - D2(printf("find_entry found .\n")); - ds->node = ds->dir; - ds->dir->i_count++; - return ENOERR; +static int jffs2_do_setattr (struct _inode *inode, struct iattr *iattr) +{ + struct jffs2_full_dnode *old_metadata, *new_metadata; + 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; + unsigned char *mdata = NULL; + int mdatalen = 0; + unsigned int ivalid; + uint32_t alloclen; + int ret; + int alloc_type = ALLOC_NORMAL; + + jffs2_dbg(1, "%s(): ino #%lu\n", __func__, inode->i_ino); + + /* Special cases - we don't want more than one data node + for these types on the medium at any time. So setattr + must read the original data associated with the node + (i.e. the device numbers or the target name) and write + it out again with the appropriate data attached */ + if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { + return -EIO; + } else if (S_ISLNK(inode->i_mode)) { + mutex_lock(&f->sem); + mdatalen = f->metadata->size; + mdata = kmalloc(f->metadata->size, GFP_USER); + if (!mdata) { + mutex_unlock(&f->sem); + return -ENOMEM; } + ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); + if (ret) { + mutex_unlock(&f->sem); + kfree(mdata); + return ret; + } + mutex_unlock(&f->sem); + jffs2_dbg(1, "%s(): Writing %d bytes of symlink target\n", + __func__, mdatalen); + } - // Here we have the name and its length set up. - // Search the directory for a matching entry - - D2(printf("find_entry for name = %s\n", ds->path)); - d = jffs2_lookup(dir, name, namelen); - D2(printf("find_entry got dir = %x\n", d)); - - if (d == NULL) - return ENOENT; - if (IS_ERR(d)) - return -PTR_ERR(d); - - // If it's a new directory inode, increase refcount on its parent - if (S_ISDIR(d->i_mode) && !d->i_parent) { - d->i_parent = dir; - dir->i_count++; + ri = jffs2_alloc_raw_inode(); + if (!ri) { + if (S_ISLNK(inode->i_mode)) + kfree(mdata); + return -ENOMEM; } - // pass back the node we have found - ds->node = d; - return ENOERR; + ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) { + jffs2_free_raw_inode(ri); + if (S_ISLNK(inode->i_mode)) + kfree(mdata); + return ret; + } + mutex_lock(&f->sem); + ivalid = iattr->ia_valid; -} + ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); + ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); -// ------------------------------------------------------------------------- -// jffs2_find() -// Main interface to directory search code. This is used in all file -// level operations to locate the object named by the pathname. + ri->ino = cpu_to_je32(inode->i_ino); + ri->version = cpu_to_je32(++f->highest_version); -// Returns with use count incremented on both the sought object and -// the directory it was found in -static int jffs2_find(jffs2_dirsearch * d) -{ - int err; + ri->uid = cpu_to_je16((ivalid & ATTR_UID)? + from_kuid(&init_user_ns, iattr->ia_uid):i_uid_read(inode)); + ri->gid = cpu_to_je16((ivalid & ATTR_GID)? + from_kgid(&init_user_ns, iattr->ia_gid):i_gid_read(inode)); + + if (ivalid & ATTR_MODE) + ri->mode = cpu_to_jemode(iattr->ia_mode); + else + ri->mode = cpu_to_jemode(inode->i_mode); + + + ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size); + ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime)); + ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime)); + ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime)); + + ri->offset = cpu_to_je32(0); + ri->csize = ri->dsize = cpu_to_je32(mdatalen); + ri->compr = JFFS2_COMPR_NONE; + if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { + /* It's an extension. Make it a hole node */ + ri->compr = JFFS2_COMPR_ZERO; + ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); + ri->offset = cpu_to_je32(inode->i_size); + } else if (ivalid & ATTR_SIZE && !iattr->ia_size) { + /* For truncate-to-zero, treat it as deletion because + it'll always be obsoleting all previous nodes */ + alloc_type = ALLOC_DELETION; + } + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + if (mdatalen) + ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); + else + ri->data_crc = cpu_to_je32(0); + + new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type); + if (S_ISLNK(inode->i_mode)) + kfree(mdata); + + if (IS_ERR(new_metadata)) { + jffs2_complete_reservation(c); + jffs2_free_raw_inode(ri); + mutex_unlock(&f->sem); + return PTR_ERR(new_metadata); + } + /* It worked. Update the inode */ + inode->i_atime = ITIME(je32_to_cpu(ri->atime)); + inode->i_ctime = ITIME(je32_to_cpu(ri->ctime)); + inode->i_mtime = ITIME(je32_to_cpu(ri->mtime)); + inode->i_mode = jemode_to_cpu(ri->mode); + i_uid_write(inode, je16_to_cpu(ri->uid)); + i_gid_write(inode, je16_to_cpu(ri->gid)); - D2(printf("jffs2_find for path =%s\n", d->path)); - // Short circuit empty paths - if (*(d->path) == '\0') { - d->node->i_count++; - return ENOERR; - } + old_metadata = f->metadata; - // iterate down directory tree until we find the object - // we want. - for (;;) { - err = find_entry(d); + if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) + jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size); - if (err != ENOERR) - return err; + if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { + jffs2_add_full_dnode_to_inode(c, f, new_metadata); + inode->i_size = iattr->ia_size; + f->metadata = NULL; + } else { + f->metadata = new_metadata; + } + if (old_metadata) { + jffs2_mark_node_obsolete(c, old_metadata->raw); + jffs2_free_full_dnode(old_metadata); + } + jffs2_free_raw_inode(ri); - if (d->last) - return ENOERR; + mutex_unlock(&f->sem); + jffs2_complete_reservation(c); - /* We're done with it, although it we found a subdir that - will have caused the refcount to have been increased */ - jffs2_iput(d->dir); + /* We have to do the truncate_setsize() without f->sem held, since + some pages may be locked and waiting for it in readpage(). + We are protected from a simultaneous write() extending i_size + back past iattr->ia_size, because do_truncate() holds the + generic inode semaphore. */ + if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { + truncate_setsize(inode, iattr->ia_size); + } - // Update dirsearch object to search next directory. - d->dir = d->node; - d->path += d->namelen; - while (*(d->path) == '/') - d->path++; // skip dirname separators - } + return 0; } -//========================================================================== -// Pathconf support -// This function provides support for pathconf() and fpathconf(). +typedef struct { + struct super_block sb; + struct jffs2_inode_cache *inode_cache[]; +} rtems_jffs2_fs_info; -static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info) +static void rtems_jffs2_do_lock(const struct super_block *sb) { - int err = ENOERR; - D2(printf("jffs2_pathconf\n")); - - switch (info->name) { - case _PC_LINK_MAX: - info->value = LINK_MAX; - break; - - case _PC_MAX_CANON: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_MAX_INPUT: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_NAME_MAX: - info->value = NAME_MAX; - break; - - case _PC_PATH_MAX: - info->value = PATH_MAX; - break; - - case _PC_PIPE_BUF: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_ASYNC_IO: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_CHOWN_RESTRICTED: - info->value = -1; // not supported - err = EINVAL; - break; - - case _PC_NO_TRUNC: - info->value = 0; - break; - - case _PC_PRIO_IO: - info->value = 0; - break; - - case _PC_SYNC_IO: - info->value = 0; - break; - - case _PC_VDISABLE: - info->value = -1; // not supported - err = EINVAL; - break; - - default: - err = EINVAL; - break; - } - - return err; + rtems_status_code sc = rtems_semaphore_obtain(sb->s_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + assert(sc == RTEMS_SUCCESSFUL); } -//========================================================================== -// Filesystem operations - -// ------------------------------------------------------------------------- -// jffs2_mount() -// Process a mount request. This mainly creates a root for the -// filesystem. -static int jffs2_read_super(struct super_block *sb) +static void rtems_jffs2_do_unlock(const struct super_block *sb) { - struct jffs2_sb_info *c; - Cyg_ErrNo err; - cyg_uint32 len; - cyg_io_flash_getconfig_devsize_t ds; - cyg_io_flash_getconfig_blocksize_t bs; + rtems_status_code sc = rtems_semaphore_release(sb->s_mutex); + assert(sc == RTEMS_SUCCESSFUL); +} - D1(printk(KERN_DEBUG "jffs2: read_super\n")); +static void rtems_jffs2_free_directory_entries(struct _inode *inode) +{ + struct jffs2_full_dirent *current = inode->jffs2_i.dents; - c = JFFS2_SB_INFO(sb); + while (current != NULL) { + struct jffs2_full_dirent *victim = current; - len = sizeof (ds); - err = cyg_io_get_config(sb->s_dev, - CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len); - if (err != ENOERR) { - D1(printf - ("jffs2: cyg_io_get_config failed to get dev size: %d\n", - err)); - return err; - } - len = sizeof (bs); - bs.offset = 0; - err = cyg_io_get_config(sb->s_dev, - CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len); - if (err != ENOERR) { - D1(printf - ("jffs2: cyg_io_get_config failed to get block size: %d\n", - err)); - return err; + current = victim->next; + jffs2_free_full_dirent(victim); } +} - c->sector_size = bs.block_size; - c->flash_size = ds.dev_size; - c->cleanmarker_size = sizeof(struct jffs2_unknown_node); - - err = jffs2_do_mount_fs(c); - if (err) - return -err; - - D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n")); - sb->s_root = jffs2_iget(sb, 1); - if (IS_ERR(sb->s_root)) { - D1(printk(KERN_WARNING "get root inode failed\n")); - err = PTR_ERR(sb->s_root); - sb->s_root = NULL; - goto out_nodes; +static void rtems_jffs2_flash_control_destroy(rtems_jffs2_flash_control *fc) +{ + if (fc->destroy != NULL) { + (*fc->destroy)(fc); } - - return 0; - - out_nodes: - jffs2_free_ino_caches(c); - jffs2_free_raw_node_refs(c); - free(c->blocks); - - return err; } - -static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte) +static void rtems_jffs2_compressor_control_destroy(rtems_jffs2_compressor_control *cc) { - extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end; - struct super_block *jffs2_sb = NULL; - struct jffs2_sb_info *c; - cyg_mtab_entry *m; - cyg_io_handle_t t; - Cyg_ErrNo err; - - D2(printf("jffs2_mount\n")); - - err = cyg_io_lookup(mte->devname, &t); - if (err != ENOERR) - return -err; - - // Iterate through the mount table to see if we're mounted - // FIXME: this should be done better - perhaps if the superblock - // can be stored as an inode in the icache. - for (m = &cyg_mtab[0]; m != &cyg_mtab_end; m++) { - // stop if there are more than the configured maximum - if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) { - m = &cyg_mtab_end; - break; - } - if (m->valid && strcmp(m->fsname, "jffs2") == 0 && - strcmp(m->devname, mte->devname) == 0) { - jffs2_sb = (struct super_block *) m->data; - } + if (cc != NULL && cc->destroy != NULL) { + (*cc->destroy)(cc); } +} - if (jffs2_sb == NULL) { - jffs2_sb = malloc(sizeof (struct super_block)); - - if (jffs2_sb == NULL) - return ENOMEM; - - c = JFFS2_SB_INFO(jffs2_sb); - memset(jffs2_sb, 0, sizeof (struct super_block)); - jffs2_sb->s_dev = t; - - c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE); - if (!c->inocache_list) { - free(jffs2_sb); - return ENOMEM; - } - memset(c->inocache_list, 0, sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE); - if (n_fs_mounted++ == 0) { - jffs2_create_slab_caches(); // No error check, cannot fail - jffs2_compressors_init(); - } - err = jffs2_read_super(jffs2_sb); +static void rtems_jffs2_free_fs_info(rtems_jffs2_fs_info *fs_info, bool do_mount_fs_was_successful) +{ + struct super_block *sb = &fs_info->sb; + struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - if (err) { - if (--n_fs_mounted == 0) { - jffs2_destroy_slab_caches(); - jffs2_compressors_exit(); - } - - free(jffs2_sb); - free(c->inocache_list); - return err; - } + if (do_mount_fs_was_successful) { + jffs2_free_ino_caches(c); + jffs2_free_raw_node_refs(c); + free(c->blocks); + } - jffs2_sb->s_root->i_parent = jffs2_sb->s_root; // points to itself, no dotdot paths above mountpoint - jffs2_sb->s_root->i_cache_prev = NULL; // root inode, so always null - jffs2_sb->s_root->i_cache_next = NULL; - jffs2_sb->s_root->i_count = 1; // Ensures the root inode is always in ram until umount - - D2(printf("jffs2_mount erasing pending blocks\n")); -#ifdef CYGOPT_FS_JFFS2_WRITE - if (!jffs2_is_readonly(c)) - jffs2_erase_pending_blocks(c,0); -#endif -#ifdef CYGOPT_FS_JFFS2_GCTHREAD - jffs2_start_garbage_collect_thread(c); -#endif + if (sb->s_mutex != 0) { + rtems_status_code sc = rtems_semaphore_delete(sb->s_mutex); + assert(sc == RTEMS_SUCCESSFUL); } - mte->data = (CYG_ADDRWORD) jffs2_sb; - jffs2_sb->s_mount_count++; - mte->root = (cyg_dir) jffs2_sb->s_root; - D2(printf("jffs2_mounted superblock at %x\n", mte->root)); + rtems_jffs2_flash_control_destroy(fs_info->sb.s_flash_control); + rtems_jffs2_compressor_control_destroy(fs_info->sb.s_compressor_control); - return ENOERR; + free(fs_info); } -extern cyg_dir cyg_cdir_dir; -extern cyg_mtab_entry *cyg_cdir_mtab_entry; - -// ------------------------------------------------------------------------- -// jffs2_umount() -// Unmount the filesystem. - -static int jffs2_umount(cyg_mtab_entry * mte) +static int rtems_jffs2_eno_to_rv_and_errno(int eno) { - struct _inode *root = (struct _inode *) mte->root; - struct super_block *jffs2_sb = root->i_sb; - struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb); - struct jffs2_full_dirent *fd, *next; - - D2(printf("jffs2_umount\n")); - - // Only really umount if this is the only mount - if (jffs2_sb->s_mount_count == 1) { - icache_evict(root, NULL); - if (root->i_cache_next != NULL) { - struct _inode *inode = root; - printf("Refuse to unmount.\n"); - while (inode) { - printf("Ino #%u has use count %d\n", - inode->i_ino, inode->i_count); - inode = inode->i_cache_next; - } - // root icount was set to 1 on mount - return EBUSY; - } - if (root->i_count == 2 && - cyg_cdir_mtab_entry == mte && - cyg_cdir_dir == (cyg_dir)root && - !strcmp(mte->name, "/")) { - /* If we were mounted on root, there's no - way for the cwd to change out and free - the file system for unmounting. So we hack - it -- if cwd is '/' we unset it. Perhaps - we should allow chdir(NULL) to unset - cyg_cdir_dir? */ - cyg_cdir_dir = CYG_DIR_NULL; - jffs2_iput(root); - } - /* Argh. The fileio code sets this; never clears it */ - if (cyg_cdir_mtab_entry == mte) - cyg_cdir_mtab_entry = NULL; - - if (root->i_count != 1) { - printf("Ino #1 has use count %d\n", - root->i_count); - return EBUSY; - } -#ifdef CYGOPT_FS_JFFS2_GCTHREAD - jffs2_stop_garbage_collect_thread(c); -#endif - jffs2_iput(root); // Time to free the root inode - - // free directory entries - for (fd = root->jffs2_i.dents; fd; fd = next) { - next=fd->next; - jffs2_free_full_dirent(fd); - } - - free(root); - //Clear root inode - //root_i = NULL; - - // Clean up the super block and root inode - jffs2_free_ino_caches(c); - jffs2_free_raw_node_refs(c); - free(c->blocks); - free(c->inocache_list); - free(jffs2_sb); - // Clear superblock & root pointer - mte->root = CYG_DIR_NULL; - mte->data = 0; - mte->fs->data = 0; // fstab entry, visible to all mounts. No current mount - // That's all folks. - D2(printf("jffs2_umount No current mounts\n")); + if (eno == 0) { + return 0; } else { - jffs2_sb->s_mount_count--; - } - if (--n_fs_mounted == 0) { - jffs2_destroy_slab_caches(); - jffs2_compressors_exit(); + errno = eno; + + return -1; } - return ENOERR; } -// ------------------------------------------------------------------------- -// jffs2_open() -// Open a file for reading or writing. - -static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - int mode, cyg_file * file) +static struct _inode *rtems_jffs2_get_inode_by_location( + const rtems_filesystem_location_info_t *loc +) { + return loc->node_access; +} - jffs2_dirsearch ds; - struct _inode *node = NULL; - int err; - - D2(printf("jffs2_open\n")); - - /* If no chdir has been called and we were the first file system - mounted, we get called with dir == NULL. Deal with it */ - if (!dir) - dir = mte->root; +static struct _inode *rtems_jffs2_get_inode_by_iop( + const rtems_libio_t *iop +) +{ + return iop->pathinfo.node_access; +} -#ifndef CYGOPT_FS_JFFS2_WRITE - if (mode & (O_CREAT|O_TRUNC|O_WRONLY)) - return EROFS; -#endif - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *) name); +static int rtems_jffs2_fstat( + const rtems_filesystem_location_info_t *loc, + struct stat *buf +) +{ + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); - err = jffs2_find(&ds); + rtems_jffs2_do_lock(inode->i_sb); - if (err == ENOENT) { -#ifdef CYGOPT_FS_JFFS2_WRITE - if (ds.last && (mode & O_CREAT)) { + buf->st_blksize = PAGE_SIZE; + buf->st_mode = inode->i_mode; + buf->st_ino = inode->i_ino; + buf->st_nlink = inode->i_nlink; + buf->st_uid = inode->i_uid; + buf->st_gid = inode->i_gid; + buf->st_size = inode->i_size; + buf->st_atime = inode->i_atime; + buf->st_mtime = inode->i_mtime; + buf->st_ctime = inode->i_ctime; - // 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. + rtems_jffs2_do_unlock(inode->i_sb); - err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node); + return 0; +} - if (err != 0) { - //Possible orphaned inode on the flash - but will be gc'd - jffs2_iput(ds.dir); - return -err; - } +static int rtems_jffs2_fill_dirent(struct dirent *de, off_t off, uint32_t ino, const char *name) +{ + int eno = 0; + size_t len; - err = ENOERR; - } -#endif - } 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)) { - jffs2_iput(ds.node); - err = EEXIST; - } else - node = ds.node; - } + memset(de, 0, sizeof(*de)); - // Finished with the directory now - jffs2_iput(ds.dir); + de->d_off = off * sizeof(*de); + de->d_reclen = sizeof(*de); + de->d_ino = ino; - if (err != ENOERR) - return err; + len = strlen(name); + de->d_namlen = len; - // Check that we actually have a file here - if (S_ISDIR(node->i_mode)) { - jffs2_iput(node); - return EISDIR; + if (len < sizeof(de->d_name) - 1) { + memcpy(&de->d_name[0], name, len); + } else { + eno = EOVERFLOW; } - // If the O_TRUNC bit is set we must clean out the file data. - if (mode & O_TRUNC) { -#ifdef CYGOPT_FS_JFFS2_WRITE - err = jffs2_truncate_file(node); - if (err) { - jffs2_iput(node); - return err; - } -#else - jffs2_iput(node); - return EROFS; -#endif - } - - // Initialise the file object - file->f_flag |= mode & CYG_FILE_MODE_MASK; - file->f_type = CYG_FILE_TYPE_FILE; - file->f_ops = &jffs2_fileops; - file->f_offset = (mode & O_APPEND) ? node->i_size : 0; - file->f_data = (CYG_ADDRWORD) node; - file->f_xops = 0; - - return ENOERR; + return eno; } -#ifdef CYGOPT_FS_JFFS2_WRITE -// ------------------------------------------------------------------------- -// jffs2_ops_unlink() -// Remove a file link from its directory. - -static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, const char *name) +static ssize_t rtems_jffs2_dir_read(rtems_libio_t *iop, void *buf, size_t len) { - jffs2_dirsearch ds; - int err; - - D2(printf("jffs2_ops_unlink\n")); - - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *)name); - - err = jffs2_find(&ds); - - if (err != ENOERR) { - jffs2_iput(ds.dir); - return err; + struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct dirent *de = buf; + off_t fd_off = 2; + int eno = 0; + struct jffs2_full_dirent *fd; + off_t begin; + off_t end; + off_t off; + + rtems_jffs2_do_lock(inode->i_sb); + + fd = f->dents; + begin = iop->offset; + end = begin + len / sizeof(*de); + off = begin; + + if (off == 0 && off < end) { + eno = rtems_jffs2_fill_dirent(de, off, inode->i_ino, "."); + assert(eno == 0); + ++off; + ++de; } - // Cannot unlink directories, use rmdir() instead - if (S_ISDIR(ds.node->i_mode)) { - jffs2_iput(ds.dir); - jffs2_iput(ds.node); - return EPERM; + if (off == 1 && off < end) { + eno = rtems_jffs2_fill_dirent(de, off, inode->i_parent->i_ino, ".."); + assert(eno == 0); + ++off; + ++de; } - // Delete it from its directory - - err = jffs2_unlink(ds.dir, ds.node, ds.name); - jffs2_iput(ds.dir); - jffs2_iput(ds.node); - - return -err; -} - -// ------------------------------------------------------------------------- -// jffs2_ops_mkdir() -// Create a new directory. - -static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name) -{ - jffs2_dirsearch ds; - int err; + while (eno == 0 && off < end && fd != NULL) { + if (fd->ino != 0) { + if (off == fd_off) { + eno = rtems_jffs2_fill_dirent(de, off, fd->ino, fd->name); + ++off; + ++de; + } - D2(printf("jffs2_ops_mkdir\n")); + ++fd_off; + } - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *)name); + fd = fd->next; + } - err = jffs2_find(&ds); + rtems_jffs2_do_unlock(inode->i_sb); - if (err == ENOENT) { - if (ds.last) { - // The entry does not exist, and it is the last element in - // the pathname, so we can create it here. + if (eno == 0) { + iop->offset = off; - err = -jffs2_mkdir(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR); - } - // If this was not the last element, then an intermediate - // directory does not exist. + return (off - begin) * sizeof(*de); } else { - // If there we no error, something already exists with that - // name, so we cannot create another one. - if (err == ENOERR) { - jffs2_iput(ds.node); - err = EEXIST; - } + return rtems_jffs2_eno_to_rv_and_errno(eno); } - jffs2_iput(ds.dir); - return err; } -// ------------------------------------------------------------------------- -// jffs2_ops_rmdir() -// Remove a directory. +static const rtems_filesystem_file_handlers_r rtems_jffs2_directory_handlers = { + .open_h = rtems_filesystem_default_open, + .close_h = rtems_filesystem_default_close, + .read_h = rtems_jffs2_dir_read, + .write_h = rtems_filesystem_default_write, + .ioctl_h = rtems_filesystem_default_ioctl, + .lseek_h = rtems_filesystem_default_lseek_directory, + .fstat_h = rtems_jffs2_fstat, + .ftruncate_h = rtems_filesystem_default_ftruncate_directory, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl +}; -static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name) +static ssize_t rtems_jffs2_file_read(rtems_libio_t *iop, void *buf, size_t len) { - jffs2_dirsearch ds; - int err; + struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + int err = 0; + off_t pos; - D2(printf("jffs2_ops_rmdir\n")); + rtems_jffs2_do_lock(inode->i_sb); - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *)name); + pos = iop->offset; - err = jffs2_find(&ds); + if (pos >= inode->i_size) { + len = 0; + } else { + uint32_t pos_32 = (uint32_t) pos; + uint32_t max_available = inode->i_size - pos_32; - if (err != ENOERR) { - jffs2_iput(ds.dir); - return err; + if (len > max_available) { + len = max_available; + } + + err = jffs2_read_inode_range(c, f, buf, pos_32, len); } - // Check that this is actually a directory. - if (!S_ISDIR(ds.node->i_mode)) { - jffs2_iput(ds.dir); - jffs2_iput(ds.node); - return EPERM; + if (err == 0) { + iop->offset += len; } - err = jffs2_rmdir(ds.dir, ds.node, ds.name); + rtems_jffs2_do_unlock(inode->i_sb); - jffs2_iput(ds.dir); - jffs2_iput(ds.node); - return -err; -} + if (err == 0) { + return (ssize_t) len; + } else { + errno = -err; -// ------------------------------------------------------------------------- -// jffs2_ops_rename() -// Rename a file/dir. + return -1; + } +} -static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1, - const char *name1, cyg_dir dir2, const char *name2) +static ssize_t rtems_jffs2_file_write(rtems_libio_t *iop, const void *buf, size_t len) { - jffs2_dirsearch ds1, ds2; - int err; + struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop); + 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; + uint32_t writtenlen; + off_t pos; + int eno = 0; - D2(printf("jffs2_ops_rename\n")); + memset(&ri, 0, sizeof(ri)); - init_dirsearch(&ds1, (struct _inode *) dir1, - (const unsigned char *)name1); + ri.ino = cpu_to_je32(f->inocache->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.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds()); - err = jffs2_find(&ds1); + rtems_jffs2_do_lock(inode->i_sb); - if (err != ENOERR) { - jffs2_iput(ds1.dir); - return err; + if ((iop->flags & LIBIO_FLAGS_APPEND) == 0) { + pos = iop->offset; + } else { + pos = inode->i_size; } - init_dirsearch(&ds2, (struct _inode *) dir2, - (const unsigned char *)name2); - - err = jffs2_find(&ds2); - - // Allow through renames to non-existent objects. - if (ds2.last && err == ENOENT) { - ds2.node = NULL; - err = ENOERR; + if (pos > inode->i_size) { + ri.version = cpu_to_je32(++f->highest_version); + eno = -jffs2_extend_file(inode, &ri, pos); } - if (err != ENOERR) { - jffs2_iput(ds1.dir); - jffs2_iput(ds1.node); - jffs2_iput(ds2.dir); - return err; - } + if (eno == 0) { + ri.isize = cpu_to_je32(inode->i_size); - // Null rename, just return - if (ds1.node == ds2.node) { - err = ENOERR; - goto out; + eno = -jffs2_write_inode_range(c, f, &ri, (void *) buf, pos, len, &writtenlen); } - // First deal with any entry that is at the destination - if (ds2.node) { - // Check that we are renaming like-for-like + if (eno == 0) { + pos += writtenlen; - if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) { - err = EISDIR; - goto out; - } + inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime); - if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) { - err = ENOTDIR; - goto out; + if (pos > inode->i_size) { + inode->i_size = pos; } - // Now delete the destination directory entry - /* Er, what happened to atomicity of rename()? */ - err = -jffs2_unlink(ds2.dir, ds2.node, ds2.name); - - if (err != 0) - goto out; + iop->offset = pos; + if (writtenlen != len) { + eno = ENOSPC; + } } - // Now we know that there is no clashing node at the destination, - // make a new direntry at the destination and delete the old entry - // at the source. - - err = -jffs2_rename(ds1.dir, ds1.node, ds1.name, ds2.dir, ds2.name); - - // Update directory times - if (!err) - ds1.dir->i_ctime = - ds1.dir->i_mtime = - ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp(); - out: - jffs2_iput(ds1.dir); - if (S_ISDIR(ds1.node->i_mode)) { - /* Renamed a directory to elsewhere... so fix up its - i_parent pointer and the i_counts of its old and - new parents. */ - jffs2_iput(ds1.node->i_parent); - ds1.node->i_parent = ds2.dir; - /* We effectively increase its use count by not... */ - } else { - jffs2_iput(ds2.dir); /* ... doing this */ - } - jffs2_iput(ds1.node); - if (ds2.node) - jffs2_iput(ds2.node); - - return err; -} -// ------------------------------------------------------------------------- -// jffs2_ops_link() -// Make a new directory entry for a file. - -static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1, - cyg_dir dir2, const char *name2, int type) -{ - jffs2_dirsearch ds1, ds2; - int err; + rtems_jffs2_do_unlock(inode->i_sb); - D2(printf("jffs2_ops_link\n")); - - // Only do hard links for now in this filesystem - if (type != CYG_FSLINK_HARD) - return EINVAL; - - init_dirsearch(&ds1, (struct _inode *) dir1, - (const unsigned char *) name1); - - err = jffs2_find(&ds1); + if (eno == 0) { + return writtenlen; + } else { + errno = eno; - if (err != ENOERR) { - jffs2_iput(ds1.dir); - return err; + return -1; } +} - init_dirsearch(&ds2, (struct _inode *) dir2, - (const unsigned char *) name2); +static int rtems_jffs2_file_ftruncate(rtems_libio_t *iop, off_t length) +{ + struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop); + struct iattr iattr; + int eno; - err = jffs2_find(&ds2); + iattr.ia_valid = ATTR_SIZE | ATTR_MTIME | ATTR_CTIME; + iattr.ia_size = length; + iattr.ia_mtime = get_seconds(); + iattr.ia_ctime = iattr.ia_mtime; - // Don't allow links to existing objects - if (err == ENOERR) { - jffs2_iput(ds1.dir); - jffs2_iput(ds1.node); - jffs2_iput(ds2.dir); - jffs2_iput(ds2.node); - return EEXIST; - } + rtems_jffs2_do_lock(inode->i_sb); - // Allow through links to non-existing terminal objects - if (ds2.last && err == ENOENT) { - ds2.node = NULL; - err = ENOERR; - } + eno = -jffs2_do_setattr(inode, &iattr); - if (err != ENOERR) { - jffs2_iput(ds1.dir); - jffs2_iput(ds1.node); - jffs2_iput(ds2.dir); - return err; - } + rtems_jffs2_do_unlock(inode->i_sb); - // Now we know that there is no existing node at the destination, - // make a new direntry at the destination. + return rtems_jffs2_eno_to_rv_and_errno(eno); +} - err = jffs2_link(ds1.node, ds2.dir, ds2.name); +static const rtems_filesystem_file_handlers_r rtems_jffs2_file_handlers = { + .open_h = rtems_filesystem_default_open, + .close_h = rtems_filesystem_default_close, + .read_h = rtems_jffs2_file_read, + .write_h = rtems_jffs2_file_write, + .ioctl_h = rtems_filesystem_default_ioctl, + .lseek_h = rtems_filesystem_default_lseek_file, + .fstat_h = rtems_jffs2_fstat, + .ftruncate_h = rtems_jffs2_file_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl +}; - if (err == 0) - ds1.node->i_ctime = - ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp(); +static const rtems_filesystem_file_handlers_r rtems_jffs2_link_handlers = { + .open_h = rtems_filesystem_default_open, + .close_h = rtems_filesystem_default_close, + .read_h = rtems_filesystem_default_read, + .write_h = rtems_filesystem_default_write, + .ioctl_h = rtems_filesystem_default_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_jffs2_fstat, + .ftruncate_h = rtems_filesystem_default_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl +}; - jffs2_iput(ds1.dir); - jffs2_iput(ds1.node); - jffs2_iput(ds2.dir); +static void rtems_jffs2_set_location(rtems_filesystem_location_info_t *loc, struct _inode *inode) +{ + loc->node_access = inode; - return -err; + switch (inode->i_mode & S_IFMT) { + case S_IFREG: + loc->handlers = &rtems_jffs2_file_handlers; + break; + case S_IFDIR: + loc->handlers = &rtems_jffs2_directory_handlers; + break; + case S_IFLNK: + loc->handlers = &rtems_jffs2_link_handlers; + break; + default: + loc->handlers = &rtems_filesystem_null_handlers; + break; + }; } -#endif /* CYGOPT_FS_JFFS2_WRITE */ -// ------------------------------------------------------------------------- -// jffs2_opendir() -// Open a directory for reading. -static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - cyg_file * file) +static bool rtems_jffs2_eval_is_directory( + rtems_filesystem_eval_path_context_t *ctx, + void *arg +) { - jffs2_dirsearch ds; - int err; - - D2(printf("jffs2_opendir\n")); - - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *) name); - - err = jffs2_find(&ds); - - jffs2_iput(ds.dir); - - if (err != ENOERR) - return err; - - // check it is really a directory. - if (!S_ISDIR(ds.node->i_mode)) { - jffs2_iput(ds.node); - return ENOTDIR; - } - - // Initialize the file object, setting the f_ops field to a - // special set of file ops. - - file->f_type = CYG_FILE_TYPE_FILE; - file->f_ops = &jffs2_dirops; - file->f_offset = 0; - file->f_data = (CYG_ADDRWORD) ds.node; - file->f_xops = 0; - - return ENOERR; + rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_get_currentloc(ctx); + struct _inode *inode = rtems_jffs2_get_inode_by_location(currentloc); + return S_ISDIR(inode->i_mode); } -// ------------------------------------------------------------------------- -// jffs2_chdir() -// Change directory support. - -static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - cyg_dir * dir_out) +static rtems_filesystem_eval_path_generic_status rtems_jffs2_eval_token( + rtems_filesystem_eval_path_context_t *ctx, + void *arg, + const char *token, + size_t tokenlen +) { - D2(printf("jffs2_chdir\n")); - - if (dir_out != NULL) { - // This is a request to get a new directory pointer in - // *dir_out. + rtems_filesystem_eval_path_generic_status status = + RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE; + rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_get_currentloc(ctx); + struct _inode *dir_i = rtems_jffs2_get_inode_by_location(currentloc); + bool access_ok = rtems_filesystem_eval_path_check_access( + ctx, + RTEMS_FS_PERMS_EXEC, + dir_i->i_mode, + dir_i->i_uid, + dir_i->i_gid + ); + + if (access_ok) { + struct _inode *entry_i; + + if (rtems_filesystem_is_current_directory(token, tokenlen)) { + entry_i = dir_i; + ++entry_i->i_count; + } else if (rtems_filesystem_is_parent_directory(token, tokenlen)) { + entry_i = dir_i->i_parent; + ++entry_i->i_count; + } else { + entry_i = jffs2_lookup(dir_i, token, (int) tokenlen); + } - jffs2_dirsearch ds; - int err; + if (IS_ERR(entry_i)) { + rtems_filesystem_eval_path_error(ctx, PTR_ERR(entry_i)); + } else if (entry_i != NULL) { + bool terminal = !rtems_filesystem_eval_path_has_path(ctx); + int eval_flags = rtems_filesystem_eval_path_get_flags(ctx); + bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0; - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *) name); + rtems_filesystem_eval_path_clear_token(ctx); - err = jffs2_find(&ds); - jffs2_iput(ds.dir); + if (S_ISLNK(entry_i->i_mode) && (follow_sym_link || !terminal)) { + struct jffs2_inode_info *f = JFFS2_INODE_INFO(entry_i); + const char *target = f->target; - if (err != ENOERR) - return err; + rtems_filesystem_eval_path_recursive(ctx, target, strlen(target)); - // check it is a directory - if (!S_ISDIR(ds.node->i_mode)) { - jffs2_iput(ds.node); - return ENOTDIR; - } - - // Pass it out - *dir_out = (cyg_dir) ds.node; - } else { - // If no output dir is required, this means that the mte and - // dir arguments are the current cdir setting and we should - // forget this fact. + jffs2_iput(entry_i); + } else { + if (S_ISDIR(entry_i->i_mode) && entry_i->i_parent == NULL) { + entry_i->i_parent = dir_i; + ++dir_i->i_count; + } - struct _inode *node = (struct _inode *) dir; + jffs2_iput(dir_i); + rtems_jffs2_set_location(currentloc, entry_i); - // Just decrement directory reference count. - jffs2_iput(node); + if (rtems_filesystem_eval_path_has_path(ctx)) { + status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE; + } + } + } else { + status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY; + } } - return ENOERR; + return status; } -// ------------------------------------------------------------------------- -// jffs2_stat() -// Get struct stat info for named object. +static const rtems_filesystem_eval_path_generic_config rtems_jffs2_eval_config = { + .is_directory = rtems_jffs2_eval_is_directory, + .eval_token = rtems_jffs2_eval_token +}; -static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - struct stat *buf) +static void rtems_jffs2_lock(const rtems_filesystem_mount_table_entry_t *mt_entry) { - jffs2_dirsearch ds; - int err; - - D2(printf("jffs2_stat\n")); - - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *) name); - - err = jffs2_find(&ds); - jffs2_iput(ds.dir); - - if (err != ENOERR) - return err; + const rtems_jffs2_fs_info *fs_info = mt_entry->fs_info; + const struct super_block *sb = &fs_info->sb; - // Fill in the status - buf->st_mode = ds.node->i_mode; - buf->st_ino = ds.node->i_ino; - buf->st_dev = 0; - buf->st_nlink = ds.node->i_nlink; - buf->st_uid = ds.node->i_uid; - buf->st_gid = ds.node->i_gid; - buf->st_size = ds.node->i_size; - buf->st_atime = ds.node->i_atime; - buf->st_mtime = ds.node->i_mtime; - buf->st_ctime = ds.node->i_ctime; + rtems_jffs2_do_lock(sb); +} - jffs2_iput(ds.node); +static void rtems_jffs2_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry) +{ + const rtems_jffs2_fs_info *fs_info = mt_entry->fs_info; + const struct super_block *sb = &fs_info->sb; - return ENOERR; + rtems_jffs2_do_unlock(sb); } -// ------------------------------------------------------------------------- -// jffs2_getinfo() -// Getinfo. Currently only support pathconf(). +static void rtems_jffs2_eval_path(rtems_filesystem_eval_path_context_t *ctx) +{ + rtems_filesystem_eval_path_generic(ctx, NULL, &rtems_jffs2_eval_config); +} -static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - int key, void *buf, int len) +static int rtems_jffs2_link( + const rtems_filesystem_location_info_t *parentloc, + const rtems_filesystem_location_info_t *targetloc, + const char *name, + size_t namelen +) { - jffs2_dirsearch ds; - int err; + struct _inode *old_d_inode = rtems_jffs2_get_inode_by_location(targetloc); + struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc); + int eno; - D2(printf("jffs2_getinfo\n")); + eno = -jffs2_link(old_d_inode, dir_i, name, namelen); - init_dirsearch(&ds, (struct _inode *) dir, - (const unsigned char *) name); + return rtems_jffs2_eno_to_rv_and_errno(eno); +} - err = jffs2_find(&ds); - jffs2_iput(ds.dir); +static bool rtems_jffs2_are_nodes_equal( + const rtems_filesystem_location_info_t *a, + const rtems_filesystem_location_info_t *b +) +{ + struct _inode *inode_a = rtems_jffs2_get_inode_by_location(a); + struct _inode *inode_b = rtems_jffs2_get_inode_by_location(b); - if (err != ENOERR) - return err; + return inode_a->i_ino == inode_b->i_ino; +} - switch (key) { - case FS_INFO_CONF: - err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf); - break; +static rtems_filesystem_node_types_t rtems_jffs2_node_type( + const rtems_filesystem_location_info_t *loc +) +{ + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); + rtems_filesystem_node_types_t type; - default: - err = EINVAL; + switch (inode->i_mode & S_IFMT) { + case S_IFDIR: + type = RTEMS_FILESYSTEM_DIRECTORY; + break; + case S_IFREG: + type = RTEMS_FILESYSTEM_MEMORY_FILE; + break; + case S_IFLNK: + type = RTEMS_FILESYSTEM_SYM_LINK; + break; + default: + type = RTEMS_FILESYSTEM_INVALID_NODE_TYPE; + break; } - jffs2_iput(ds.node); - return err; + return type; } -// ------------------------------------------------------------------------- -// jffs2_setinfo() -// Setinfo. Nothing to support here at present. - -static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, - int key, void *buf, int len) +static int rtems_jffs2_mknod( + const rtems_filesystem_location_info_t *parentloc, + const char *name, + size_t namelen, + mode_t mode, + dev_t dev +) { - // No setinfo keys supported at present + struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc); + int eno; - D2(printf("jffs2_setinfo\n")); + switch (mode & S_IFMT) { + case S_IFDIR: + eno = -jffs2_mknod(dir_i, name, namelen, mode, NULL, 0); + break; + case S_IFREG: + eno = -jffs2_create(dir_i, name, namelen, mode); + break; + default: + eno = EINVAL; + break; + } - return EINVAL; + return rtems_jffs2_eno_to_rv_and_errno(eno); } -//========================================================================== -// File operations - -// ------------------------------------------------------------------------- -// jffs2_fo_read() -// Read data from the file. - -static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +static int rtems_jffs2_cache_fd_name(struct _inode *inode, char **name, size_t *namelen) { - struct _inode *inode = (struct _inode *) fp->f_data; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - int i; - ssize_t resid = uio->uio_resid; - off_t pos = fp->f_offset; - - down(&f->sem); - - // Loop over the io vectors until there are none left - for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) { - int ret; - cyg_iovec *iov = &uio->uio_iov[i]; - off_t len = min(iov->iov_len, inode->i_size - pos); + struct super_block *sb = inode->i_sb; + char *fd_name = inode->i_fd->name; + size_t fd_namelen = strlen(fd_name); + int eno = 0; + + if (fd_namelen <= sizeof(sb->s_name_buf)) { + *namelen = fd_namelen; + *name = memcpy(&sb->s_name_buf[0], fd_name, fd_namelen); + } else { + eno = ENOMEM; + } - D2(printf("jffs2_fo_read inode size %d\n", inode->i_size)); + return eno; +} - ret = - jffs2_read_inode_range(c, f, - (unsigned char *) iov->iov_base, pos, - len); - if (ret) { - D1(printf - ("jffs2_fo_read(): read_inode_range failed %d\n", - ret)); - uio->uio_resid = resid; - up(&f->sem); - return -ret; +static int rtems_jffs2_rmnod( + const rtems_filesystem_location_info_t *parentloc, + const rtems_filesystem_location_info_t *loc +) +{ + struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc); + struct _inode *entry_i = rtems_jffs2_get_inode_by_location(loc); + char *name; + size_t namelen; + int eno = rtems_jffs2_cache_fd_name(entry_i, &name, &namelen); + + if (eno == 0) { + switch (dir_i->i_mode & S_IFMT) { + case S_IFDIR: + eno = -jffs2_rmdir(dir_i, entry_i, name, namelen); + break; + case S_IFREG: + eno = -jffs2_unlink(dir_i, entry_i, name, namelen); + break; + default: + eno = EINVAL; + break; } - resid -= len; - pos += len; } - // We successfully read some data, update the node's access time - // and update the file offset and transfer residue. + return rtems_jffs2_eno_to_rv_and_errno(eno); +} - inode->i_atime = cyg_timestamp(); +static int rtems_jffs2_fchmod( + const rtems_filesystem_location_info_t *loc, + mode_t mode +) +{ + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); + struct iattr iattr; + int eno; - uio->uio_resid = resid; - fp->f_offset = pos; + iattr.ia_valid = ATTR_MODE | ATTR_CTIME; + iattr.ia_mode = mode; + iattr.ia_ctime = get_seconds(); - up(&f->sem); + eno = -jffs2_do_setattr(inode, &iattr); - return ENOERR; + return rtems_jffs2_eno_to_rv_and_errno(eno); } - -#ifdef CYGOPT_FS_JFFS2_WRITE -// ------------------------------------------------------------------------- -// jffs2_fo_write() -// Write data to file. -static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri, - unsigned long offset) +static int rtems_jffs2_chown( + const rtems_filesystem_location_info_t *loc, + uid_t owner, + gid_t group +) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_full_dnode *fn; - uint32_t phys_ofs, alloc_len; - int ret = 0; + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); + struct iattr iattr; + int eno; - /* Make new hole frag from old EOF to new page */ - D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", - (unsigned int)inode->i_size, offset)); + iattr.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME; + iattr.ia_uid = owner; + iattr.ia_gid = group; + iattr.ia_ctime = get_seconds(); - ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); - if (ret) - return ret; + eno = -jffs2_do_setattr(inode, &iattr); - down(&f->sem); + return rtems_jffs2_eno_to_rv_and_errno(eno); +} - 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)); +static int rtems_jffs2_clonenode(rtems_filesystem_location_info_t *loc) +{ + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); - ri->version = cpu_to_je32(++f->highest_version); - ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset)); + ++inode->i_count; - ri->offset = cpu_to_je32(inode->i_size); - ri->dsize = cpu_to_je32(offset - 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, ALLOC_NORMAL); - 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 = offset; - up(&f->sem); return 0; } -// jffs2_fo_open() -// Truncate a file -static int jffs2_truncate_file (struct _inode *inode) +static void rtems_jffs2_freenode(const rtems_filesystem_location_info_t *loc) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_full_dnode *new_metadata, * old_metadata; - struct jffs2_raw_inode *ri; - uint32_t phys_ofs, alloclen; - int err; - - ri = jffs2_alloc_raw_inode(); - if (!ri) { - return ENOMEM; - } - err = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); - - if (err) { - jffs2_free_raw_inode(ri); - return err; - } - down(&f->sem); - 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(inode->i_ino); - ri->version = cpu_to_je32(++f->highest_version); - - ri->uid = cpu_to_je16(inode->i_uid); - ri->gid = cpu_to_je16(inode->i_gid); - ri->mode = cpu_to_jemode(inode->i_mode); - ri->isize = cpu_to_je32(0); - ri->atime = cpu_to_je32(inode->i_atime); - ri->mtime = cpu_to_je32(cyg_timestamp()); - ri->offset = cpu_to_je32(0); - ri->csize = ri->dsize = cpu_to_je32(0); - ri->compr = JFFS2_COMPR_NONE; - ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - ri->data_crc = cpu_to_je32(0); - new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, - phys_ofs, ALLOC_NORMAL); - if (IS_ERR(new_metadata)) { - jffs2_complete_reservation(c); - jffs2_free_raw_inode(ri); - up(&f->sem); - return PTR_ERR(new_metadata); - } - - /* It worked. Update the inode */ - inode->i_mtime = cyg_timestamp(); - inode->i_size = 0; - old_metadata = f->metadata; - jffs2_truncate_fragtree (c, &f->fragtree, 0); - f->metadata = new_metadata; - if (old_metadata) { - jffs2_mark_node_obsolete(c, old_metadata->raw); - jffs2_free_full_dnode(old_metadata); - } - jffs2_free_raw_inode(ri); - - up(&f->sem); - jffs2_complete_reservation(c); - - return 0; + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); + + jffs2_iput(inode); } -static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +static void rtems_jffs2_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry) { - struct _inode *inode = (struct _inode *) fp->f_data; - off_t pos = fp->f_offset; - ssize_t resid = uio->uio_resid; - struct jffs2_raw_inode ri; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - int i; + rtems_jffs2_fs_info *fs_info = mt_entry->fs_info; + struct _inode *root_i = mt_entry->mt_fs_root->location.node_access; - // If the APPEND mode bit was supplied, force all writes to - // the end of the file. - if (fp->f_flag & CYG_FAPPEND) - pos = fp->f_offset = inode->i_size; + icache_evict(root_i, NULL); + assert(root_i->i_cache_next == NULL); + assert(root_i->i_count == 1); + jffs2_iput(root_i); - if (pos < 0) - return EINVAL; - - memset(&ri, 0, sizeof(ri)); - - ri.ino = cpu_to_je32(f->inocache->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.atime = ri.ctime = ri.mtime = cpu_to_je32(cyg_timestamp()); - - if (pos > inode->i_size) { - int err; - ri.version = cpu_to_je32(++f->highest_version); - err = jffs2_extend_file(inode, &ri, pos); - if (err) - return -err; - } - ri.isize = cpu_to_je32(inode->i_size); + rtems_jffs2_free_directory_entries(root_i); + free(root_i); - // 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]; - unsigned char *buf = iov->iov_base; - off_t len = iov->iov_len; - - uint32_t writtenlen; - int err; - - D2(printf("jffs2_fo_write page_start_pos %d\n", pos)); - D2(printf("jffs2_fo_write transfer size %d\n", len)); - - err = jffs2_write_inode_range(c, f, &ri, buf, - pos, len, &writtenlen); - if (err) - return -err; - - if (writtenlen != len) - return ENOSPC; + rtems_jffs2_free_fs_info(fs_info, true); +} - pos += len; - resid -= len; +static int rtems_jffs2_rename( + const rtems_filesystem_location_info_t *oldparentloc, + const rtems_filesystem_location_info_t *oldloc, + const rtems_filesystem_location_info_t *newparentloc, + const char *name, + size_t namelen +) +{ + struct _inode *old_dir_i = rtems_jffs2_get_inode_by_location(oldparentloc); + struct _inode *new_dir_i = rtems_jffs2_get_inode_by_location(newparentloc); + struct _inode *d_inode = rtems_jffs2_get_inode_by_location(oldloc); + char *oldname; + size_t oldnamelen; + int eno = rtems_jffs2_cache_fd_name(d_inode, &oldname, &oldnamelen); + + if (eno == 0) { + eno = -jffs2_rename(old_dir_i, d_inode, oldname, oldnamelen, new_dir_i, name, namelen); } - // We wrote some data successfully, update the modified and access - // times of the inode, increase its size appropriately, and update - // the file offset and transfer residue. - inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime); - if (pos > inode->i_size) - inode->i_size = pos; - - uio->uio_resid = resid; - fp->f_offset = pos; - - return ENOERR; + return rtems_jffs2_eno_to_rv_and_errno(eno); } -#endif /* CYGOPT_FS_JFFS2_WRITE */ -// ------------------------------------------------------------------------- -// jffs2_fo_lseek() -// Seek to a new file position. - -static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * apos, int whence) +static int rtems_jffs2_statvfs( + const rtems_filesystem_location_info_t *loc, + struct statvfs *buf +) { - struct _inode *node = (struct _inode *) fp->f_data; - off_t pos = *apos; - - D2(printf("jffs2_fo_lseek\n")); - - 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 += node->i_size; - break; - - default: - return EINVAL; + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); + struct super_block *sb = inode->i_sb; + struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); + unsigned long avail; + + spin_lock(&c->erase_completion_lock); + avail = c->dirty_size + c->free_size; + if (avail > c->sector_size * c->resv_blocks_write) { + avail -= c->sector_size * c->resv_blocks_write; + } else { + avail = 0; } + spin_unlock(&c->erase_completion_lock); - if (pos < 0 ) - return EINVAL; + buf->f_bavail = avail >> PAGE_SHIFT; + buf->f_blocks = c->flash_size >> PAGE_SHIFT; + buf->f_bsize = 1UL << PAGE_SHIFT; + buf->f_fsid = JFFS2_SUPER_MAGIC; + buf->f_namemax = JFFS2_MAX_NAME_LEN; - // All OK, set fp offset and return new position. - *apos = fp->f_offset = pos; + buf->f_bfree = buf->f_bavail; + buf->f_frsize = buf->f_bsize; - return ENOERR; + return 0; } -// ------------------------------------------------------------------------- -// jffs2_fo_ioctl() -// Handle ioctls. Currently none are defined. - -static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, - CYG_ADDRWORD data) +static int rtems_jffs2_utime( + const rtems_filesystem_location_info_t *loc, + time_t actime, + time_t modtime +) { - // No Ioctls currenly defined. + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); + struct iattr iattr; + int eno; - D2(printf("jffs2_fo_ioctl\n")); + iattr.ia_valid = ATTR_ATIME | ATTR_MTIME | ATTR_CTIME; + iattr.ia_atime = actime; + iattr.ia_mtime = modtime; + iattr.ia_ctime = get_seconds(); - return EINVAL; -} + eno = -jffs2_do_setattr(inode, &iattr); -// ------------------------------------------------------------------------- -// jffs2_fo_fsync(). -// Force the file out to data storage. + return rtems_jffs2_eno_to_rv_and_errno(eno); +} -static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode) +static int rtems_jffs2_symlink( + const rtems_filesystem_location_info_t *parentloc, + const char *name, + size_t namelen, + const char *target +) { - // Data is always permanently where it belongs, nothing to do - // here. + struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc); + int eno; - D2(printf("jffs2_fo_fsync\n")); + eno = -jffs2_mknod(dir_i, name, namelen, S_IFLNK | S_IRWXUGO, target, strlen(target)); - return ENOERR; + return rtems_jffs2_eno_to_rv_and_errno(eno); } -// ------------------------------------------------------------------------- -// jffs2_fo_close() -// Close a file. We just decrement the refcnt and let it go away if -// that is all that is keeping it here. - -static int jffs2_fo_close(struct CYG_FILE_TAG *fp) +static ssize_t rtems_jffs2_readlink( + const rtems_filesystem_location_info_t *loc, + char *buf, + size_t bufsize +) { - struct _inode *node = (struct _inode *) fp->f_data; - - D2(printf("jffs2_fo_close\n")); - - jffs2_iput(node); + struct _inode *inode = rtems_jffs2_get_inode_by_location(loc); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + const char *target = f->target; + ssize_t i; - fp->f_data = 0; // zero data pointer + for (i = 0; i < (ssize_t) bufsize && target[i] != '\0'; ++i) { + buf[i] = target[i]; + } - return ENOERR; + return i; } -// ------------------------------------------------------------------------- -//jffs2_fo_fstat() -// Get file status. +static const rtems_filesystem_operations_table rtems_jffs2_ops = { + .lock_h = rtems_jffs2_lock, + .unlock_h = rtems_jffs2_unlock, + .eval_path_h = rtems_jffs2_eval_path, + .link_h = rtems_jffs2_link, + .are_nodes_equal_h = rtems_jffs2_are_nodes_equal, + .node_type_h = rtems_jffs2_node_type, + .mknod_h = rtems_jffs2_mknod, + .rmnod_h = rtems_jffs2_rmnod, + .fchmod_h = rtems_jffs2_fchmod, + .chown_h = rtems_jffs2_chown, + .clonenod_h = rtems_jffs2_clonenode, + .freenod_h = rtems_jffs2_freenode, + .mount_h = rtems_filesystem_default_mount, + .fsmount_me_h = rtems_jffs2_initialize, + .unmount_h = rtems_filesystem_default_unmount, + .fsunmount_me_h = rtems_jffs2_fsunmount, + .utime_h = rtems_jffs2_utime, + .symlink_h = rtems_jffs2_symlink, + .readlink_h = rtems_jffs2_readlink, + .rename_h = rtems_jffs2_rename, + .statvfs_h = rtems_jffs2_statvfs +}; -static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf) +static int calculate_inocache_hashsize(uint32_t flash_size) { - struct _inode *node = (struct _inode *) fp->f_data; - - D2(printf("jffs2_fo_fstat\n")); - - // Fill in the status - buf->st_mode = node->i_mode; - buf->st_ino = node->i_ino; - buf->st_dev = 0; - buf->st_nlink = node->i_nlink; - buf->st_uid = node->i_uid; - buf->st_gid = node->i_gid; - buf->st_size = node->i_size; - buf->st_atime = node->i_atime; - buf->st_mtime = node->i_mtime; - buf->st_ctime = node->i_ctime; - - return ENOERR; + /* + * Pick a inocache hash size based on the size of the medium. + * Count how many megabytes we're dealing with, apply a hashsize twice + * that size, but rounding down to the usual big powers of 2. And keep + * to sensible bounds. + */ + + int size_mb = flash_size / 1024 / 1024; + int hashsize = (size_mb * 2) & ~0x3f; + + if (hashsize < INOCACHE_HASHSIZE_MIN) + return INOCACHE_HASHSIZE_MIN; + if (hashsize > INOCACHE_HASHSIZE_MAX) + return INOCACHE_HASHSIZE_MAX; + + return hashsize; } -// ------------------------------------------------------------------------- -// jffs2_fo_getinfo() -// Get info. Currently only supports fpathconf(). - -static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, - int len) +int rtems_jffs2_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +) { - struct _inode *node = (struct _inode *) fp->f_data; + const rtems_jffs2_mount_data *jffs2_mount_data = data; + rtems_jffs2_flash_control *fc = jffs2_mount_data->flash_control; + int inocache_hashsize = calculate_inocache_hashsize(fc->flash_size); + rtems_jffs2_fs_info *fs_info = calloc( + 1, + sizeof(*fs_info) + (size_t) inocache_hashsize * sizeof(fs_info->inode_cache[0]) + ); + bool do_mount_fs_was_successful = false; + struct super_block *sb; + struct jffs2_sb_info *c; int err; - D2(printf("jffs2_fo_getinfo\n")); - - switch (key) { - case FS_INFO_CONF: - err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf); - break; - - default: - err = EINVAL; + if (fs_info != NULL) { + err = 0; + } else { + err = -ENOMEM; } - return err; - return ENOERR; -} - -// ------------------------------------------------------------------------- -// jffs2_fo_setinfo() -// Set info. Nothing supported here. - -static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, - int len) -{ - // No setinfo key supported at present - - D2(printf("jffs2_fo_setinfo\n")); - - return ENOERR; -} + sb = &fs_info->sb; + c = JFFS2_SB_INFO(sb); -//========================================================================== -// Directory operations + if (err == 0) { + uint32_t blocks = fc->flash_size / fc->block_size; -// ------------------------------------------------------------------------- -// jffs2_fo_dirread() -// Read a single directory entry from a file. + if ((fc->block_size * blocks) != fc->flash_size) { + fc->flash_size = fc->block_size * blocks; + pr_info("Flash size not aligned to erasesize, reducing to %dKiB\n", + fc->flash_size / 1024); + } -static __inline void filldir(char *nbuf, int nlen, const unsigned char *name, int namlen) -{ - int len = nlen < namlen ? nlen : namlen; - memcpy(nbuf, name, len); - nbuf[len] = '\0'; -} + if (fc->flash_size < 5*fc->block_size) { + pr_err("Too few erase blocks (%d)\n", + fc->flash_size / fc->block_size); + err = -EINVAL; + } + } -static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) -{ - struct _inode *d_inode = (struct _inode *) fp->f_data; - struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base; - char *nbuf = ent->d_name; -#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE - struct _inode *c_ino; -#endif - int nlen = sizeof (ent->d_name) - 1; - off_t len = uio->uio_iov[0].iov_len; - struct jffs2_inode_info *f; - struct jffs2_sb_info *c; - struct _inode *inode = d_inode; - struct jffs2_full_dirent *fd; - unsigned long offset, curofs; - int found = 1; + if (err == 0) { + rtems_status_code sc = rtems_semaphore_create( + rtems_build_name('J', 'F', 'F', 'S'), + 1, + RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_BINARY_SEMAPHORE, + 0, + &sb->s_mutex + ); - if (len < sizeof (struct dirent)) - return EINVAL; + err = sc == RTEMS_SUCCESSFUL ? 0 : -ENOMEM; + } - D1(printk - (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino)); + if (err == 0) { + sb->s_is_readonly = !mt_entry->writeable; + sb->s_flash_control = fc; + sb->s_compressor_control = jffs2_mount_data->compressor_control; - f = JFFS2_INODE_INFO(inode); - c = JFFS2_SB_INFO(inode->i_sb); + c->inocache_hashsize = inocache_hashsize; + c->inocache_list = &fs_info->inode_cache[0]; + c->sector_size = fc->block_size; + c->flash_size = fc->flash_size; + c->cleanmarker_size = sizeof(struct jffs2_unknown_node); - offset = fp->f_offset; - - if (offset == 0) { - D1(printk - (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino)); - filldir(nbuf, nlen, (const unsigned char *) ".", 1); -#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE - // Flags here are the same as jffs2_mkdir. Make sure - // d_type is the same as st_mode of calling stat. - ent->d_type = - jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR)); -#endif - goto out; - } - if (offset == 1) { - filldir(nbuf, nlen, (const unsigned char *) "..", 2); -#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE - // Flags here are the same as jffs2_mkdir. Make sure - // d_type is the same as st_mode of calling stat. - ent->d_type = - jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR)); -#endif - goto out; + err = jffs2_do_mount_fs(c); } - curofs = 1; - down(&f->sem); - for (fd = f->dents; fd; fd = fd->next) { - - curofs++; - /* First loop: curofs = 2; offset = 2 */ - if (curofs < offset) { - D2(printk - (KERN_DEBUG - "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", - fd->name, fd->ino, fd->type, curofs, offset)); - continue; - } - if (!fd->ino) { - D2(printk - (KERN_DEBUG "Skipping deletion dirent \"%s\"\n", - fd->name)); - offset++; - continue; - } - D2(printk - (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, - fd->name, fd->ino, fd->type)); - filldir(nbuf, nlen, fd->name, strlen((char *)fd->name)); -#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE - c_ino = jffs2_iget(inode->i_sb, fd->ino); - if(IS_ERR(c_ino)) { - D1(printk(KERN_WARNING "get entry inode failed\n")); - // fileio already set it to zero, so not needed here - // ent->d_type = 0; - } - else { - ent->d_type = c_ino->i_mode; - jffs2_iput(c_ino); + if (err == 0) { + do_mount_fs_was_successful = true; + + sb->s_root = jffs2_iget(sb, 1); + if (IS_ERR(sb->s_root)) { + err = PTR_ERR(sb->s_root); } -#endif - goto out_sem; } - /* Reached the end of the directory */ - found = 0; - out_sem: - up(&f->sem); - out: - fp->f_offset = ++offset; - if (found) { - uio->uio_resid -= sizeof (struct dirent); - } - return ENOERR; -} -// ------------------------------------------------------------------------- -// jffs2_fo_dirlseek() -// Seek directory to start. + if (err == 0) { + sb->s_root->i_parent = sb->s_root; -static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence) -{ - // Only allow SEEK_SET to zero + if (!jffs2_is_readonly(c)) { + jffs2_erase_pending_blocks(c, 0); + } - D2(printf("jffs2_fo_dirlseek\n")); + mt_entry->fs_info = fs_info; + mt_entry->ops = &rtems_jffs2_ops; + mt_entry->mt_fs_root->location.node_access = sb->s_root; + mt_entry->mt_fs_root->location.handlers = &rtems_jffs2_directory_handlers; - if (whence != SEEK_SET || *pos != 0) - return EINVAL; + return 0; + } else { + if (fs_info != NULL) { + rtems_jffs2_free_fs_info(fs_info, do_mount_fs_was_successful); + } else { + rtems_jffs2_flash_control_destroy(fc); + rtems_jffs2_compressor_control_destroy(jffs2_mount_data->compressor_control); + } - *pos = fp->f_offset = 0; + errno = -err; - return ENOERR; + return -1; + } } //========================================================================== @@ -1773,8 +1259,9 @@ unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, unsigned long offset, unsigned long *priv) { - /* FIXME: This works only with one file system mounted at a time */ int ret; + struct super_block *sb = OFNI_BS_2SFFJ(c); + unsigned char *gc_buffer = &sb->s_gc_buffer[0]; ret = jffs2_read_inode_range(c, f, gc_buffer, offset & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE); @@ -1870,7 +1357,7 @@ struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino) err = jffs2_read_inode(inode); if (err) { - printf("jffs2_read_inode() failed\n"); + printk("jffs2_read_inode() failed\n"); inode->i_nlink = 0; // free _this_ bad inode right now jffs2_iput(inode); inode = NULL; @@ -1890,10 +1377,7 @@ void jffs2_iput(struct _inode *i) // super.c jffs2_read_super, // and gc.c jffs2_garbage_collect_pass recurse: - if (!i) { - printf("jffs2_iput() called with NULL inode\n"); - // and let it fault... - } + assert(i != NULL); i->i_count--; @@ -1937,7 +1421,6 @@ void jffs2_iput(struct _inode *i) static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { memset(f, 0, sizeof(*f)); - init_MUTEX_LOCKED(&f->sem); } static void jffs2_clear_inode (struct _inode *inode) @@ -1978,7 +1461,8 @@ struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw memset(ri, 0, sizeof(*ri)); /* Set OS-specific defaults for new inodes */ - ri->uid = ri->gid = cpu_to_je16(0); + ri->uid = cpu_to_je16(geteuid()); + ri->gid = cpu_to_je16(getegid()); ri->mode = cpu_to_jemode(mode); ret = jffs2_do_new_inode (c, f, mode, ri); if (ret) { @@ -1988,7 +1472,7 @@ struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw inode->i_cache_prev->i_cache_next = inode->i_cache_next; if (inode->i_cache_next) inode->i_cache_next->i_cache_prev = inode->i_cache_prev; - up(&(f->sem)); + mutex_unlock(&(f->sem)); jffs2_clear_inode(inode); memset(inode, 0x6a, sizeof(*inode)); free(inode); @@ -1999,7 +1483,7 @@ struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw inode->i_mode = jemode_to_cpu(ri->mode); inode->i_gid = je16_to_cpu(ri->gid); inode->i_uid = je16_to_cpu(ri->uid); - inode->i_atime = inode->i_ctime = inode->i_mtime = cyg_timestamp(); + inode->i_atime = inode->i_ctime = inode->i_mtime = get_seconds(); ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime); inode->i_size = 0; @@ -2025,7 +1509,7 @@ static int jffs2_read_inode (struct _inode *inode) ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); if (ret) { - up(&f->sem); + mutex_unlock(&f->sem); return ret; } inode->i_mode = jemode_to_cpu(latest_node.mode); @@ -2036,8 +1520,8 @@ static int jffs2_read_inode (struct _inode *inode) inode->i_mtime = je32_to_cpu(latest_node.mtime); inode->i_ctime = je32_to_cpu(latest_node.ctime); - inode->i_nlink = f->inocache->nlink; - up(&f->sem); + inode->i_nlink = f->inocache->pino_nlink; + mutex_unlock(&f->sem); D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); return 0; @@ -2051,41 +1535,43 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c, } struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, - int inum, int nlink) + int inum, int unlinked) { struct _inode *inode; struct jffs2_inode_cache *ic; - if (!nlink) { + + if (unlinked) { /* The inode has zero nlink but its nodes weren't yet marked - obsolete. This has to be because we're still waiting for - the final (close() and) jffs2_iput() to happen. + obsolete. This has to be because we're still waiting for + the final (close() and) iput() to happen. - There's a possibility that the final jffs2_iput() could have + There's a possibility that the final iput() could have happened while we were contemplating. In order to ensure that we don't cause a new read_inode() (which would fail) for the inode in question, we use ilookup() in this case - instead of jffs2_iget(). + instead of iget(). - The nlink can't _become_ zero at this point because we're + The nlink can't _become_ zero at this point because we're holding the alloc_sem, and jffs2_do_unlink() would also need that while decrementing nlink on any inode. */ inode = ilookup(OFNI_BS_2SFFJ(c), inum); if (!inode) { - D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n", - inum)); + jffs2_dbg(1, "ilookup() failed for ino #%u; inode is probably deleted.\n", + inum); spin_lock(&c->inocache_lock); ic = jffs2_get_ino_cache(c, inum); if (!ic) { - D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum)); + jffs2_dbg(1, "Inode cache for ino #%u is gone\n", + inum); spin_unlock(&c->inocache_lock); return NULL; } if (ic->state != INO_STATE_CHECKEDABSENT) { /* Wait for progress. Don't just loop */ - D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n", - ic->ino, ic->state)); + jffs2_dbg(1, "Waiting for ino #%u in state %d\n", + ic->ino, ic->state); sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); } else { spin_unlock(&c->inocache_lock); @@ -2096,96 +1582,12 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, } else { /* Inode has links to it still; they're not going away because jffs2_do_unlink() would need the alloc_sem and we have it. - Just jffs2_iget() it, and if read_inode() is necessary that's OK. + Just iget() it, and if read_inode() is necessary that's OK. */ inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum); if (IS_ERR(inode)) - return (void *)inode; + return ERR_CAST(inode); } return JFFS2_INODE_INFO(inode); } - - - -uint32_t jffs2_from_os_mode(uint32_t osmode) -{ - uint32_t jmode = ((osmode & S_IRUSR)?00400:0) | - ((osmode & S_IWUSR)?00200:0) | - ((osmode & S_IXUSR)?00100:0) | - ((osmode & S_IRGRP)?00040:0) | - ((osmode & S_IWGRP)?00020:0) | - ((osmode & S_IXGRP)?00010:0) | - ((osmode & S_IROTH)?00004:0) | - ((osmode & S_IWOTH)?00002:0) | - ((osmode & S_IXOTH)?00001:0); - - switch (osmode & S_IFMT) { - case S_IFSOCK: - return jmode | 0140000; - case S_IFLNK: - return jmode | 0120000; - case S_IFREG: - return jmode | 0100000; - case S_IFBLK: - return jmode | 0060000; - case S_IFDIR: - return jmode | 0040000; - case S_IFCHR: - return jmode | 0020000; - case S_IFIFO: - return jmode | 0010000; - case S_ISUID: - return jmode | 0004000; - case S_ISGID: - return jmode | 0002000; -#ifdef S_ISVTX - case S_ISVTX: - return jmode | 0001000; -#endif - } - printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode); - BUG(); - return 0; -} - -uint32_t jffs2_to_os_mode (uint32_t jmode) -{ - uint32_t osmode = ((jmode & 00400)?S_IRUSR:0) | - ((jmode & 00200)?S_IWUSR:0) | - ((jmode & 00100)?S_IXUSR:0) | - ((jmode & 00040)?S_IRGRP:0) | - ((jmode & 00020)?S_IWGRP:0) | - ((jmode & 00010)?S_IXGRP:0) | - ((jmode & 00004)?S_IROTH:0) | - ((jmode & 00002)?S_IWOTH:0) | - ((jmode & 00001)?S_IXOTH:0); - - switch(jmode & 00170000) { - case 0140000: - return osmode | S_IFSOCK; - case 0120000: - return osmode | S_IFLNK; - case 0100000: - return osmode | S_IFREG; - case 0060000: - return osmode | S_IFBLK; - case 0040000: - return osmode | S_IFDIR; - case 0020000: - return osmode | S_IFCHR; - case 0010000: - return osmode | S_IFIFO; - case 0004000: - return osmode | S_ISUID; - case 0002000: - return osmode | S_ISGID; -#ifdef S_ISVTX - case 0001000: - return osmode | S_ISVTX; -#endif - } - printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode); - BUG(); - return 0; -} |