📄 fs-ecos.c
字号:
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 (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
err = jffs2_read_super(jffs2_sb);
if (err) {
if (--n_fs_mounted == 0)
jffs2_destroy_slab_caches();
free(jffs2_sb);
free(c->inocache_list);
return err;
}
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
}
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));
return ENOERR;
}
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)
{
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;
free(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"));
} else {
jffs2_sb->s_mount_count--;
}
if (--n_fs_mounted == 0)
jffs2_destroy_slab_caches();
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)
{
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;
#ifndef CYGOPT_FS_JFFS2_WRITE
if (mode & (O_CREAT|O_TRUNC|O_WRONLY))
return EROFS;
#endif
init_dirsearch(&ds, (struct _inode *) dir, name);
err = jffs2_find(&ds);
if (err == ENOENT) {
#ifdef CYGOPT_FS_JFFS2_WRITE
if (ds.last && (mode & O_CREAT)) {
// 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.
err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node);
if (err != 0) {
//Possible orphaned inode on the flash - but will be gc'd
return err;
}
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;
}
// Finished with the directory now
jffs2_iput(ds.dir);
if (err != ENOERR)
return err;
// Check that we actually have a file here
if (S_ISDIR(node->i_mode)) {
jffs2_iput(node);
return EISDIR;
}
#ifdef CYGOPT_FS_JFFS2_WRITE
if (mode & O_TRUNC) {
struct jffs2_inode_info *f = JFFS2_INODE_INFO(node);
struct jffs2_sb_info *c = JFFS2_SB_INFO(node->i_sb);
// If the O_TRUNC bit is set we must clean out the file data.
node->i_size = 0;
jffs2_truncate_fraglist(c, &f->fragtree, 0);
// Update file times
node->i_ctime = node->i_mtime = cyg_timestamp();
}
#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;
}
#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)
{
jffs2_dirsearch ds;
int err;
D2(printf("jffs2_ops_unlink\n"));
init_dirsearch(&ds, (struct _inode *) dir, name);
err = jffs2_find(&ds);
if (err != ENOERR) {
jffs2_iput(ds.dir);
return err;
}
// Cannot unlink directories, use rmdir() instead
if (S_ISDIR(ds.node->i_mode)) {
jffs2_iput(ds.dir);
jffs2_iput(ds.node);
return EPERM;
}
// 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;
D2(printf("jffs2_ops_mkdir\n"));
init_dirsearch(&ds, (struct _inode *) dir, name);
err = jffs2_find(&ds);
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.
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.
} else {
// If there we no error, something already exists with that
// name, so we cannot create another one.
jffs2_iput(ds.node);
if (err == ENOERR)
err = EEXIST;
}
jffs2_iput(ds.dir);
return err;
}
// -------------------------------------------------------------------------
// jffs2_ops_rmdir()
// Remove a directory.
static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
{
jffs2_dirsearch ds;
int err;
D2(printf("jffs2_ops_rmdir\n"));
init_dirsearch(&ds, (struct _inode *) dir, name);
err = jffs2_find(&ds);
if (err != ENOERR) {
jffs2_iput(ds.dir);
return err;
}
// Check that this is actually a directory.
if (!S_ISDIR(ds.node->i_mode)) {
jffs2_iput(ds.dir);
jffs2_iput(ds.node);
return EPERM;
}
err = jffs2_rmdir(ds.dir, ds.node, ds.name);
jffs2_iput(ds.dir);
jffs2_iput(ds.node);
return -err;
}
// -------------------------------------------------------------------------
// jffs2_ops_rename()
// Rename a file/dir.
static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
const char *name1, cyg_dir dir2, const char *name2)
{
jffs2_dirsearch ds1, ds2;
int err;
D2(printf("jffs2_ops_rename\n"));
init_dirsearch(&ds1, (struct _inode *) dir1, name1);
err = jffs2_find(&ds1);
if (err != ENOERR) {
jffs2_iput(ds1.dir);
return err;
}
init_dirsearch(&ds2, (struct _inode *) dir2, name2);
err = jffs2_find(&ds2);
// Allow through renames to non-existent objects.
if (ds2.last && err == ENOENT) {
ds2.node = NULL;
err = ENOERR;
}
if (err != ENOERR) {
jffs2_iput(ds1.dir);
jffs2_iput(ds1.node);
jffs2_iput(ds2.dir);
return err;
}
// Null rename, just return
if (ds1.node == ds2.node) {
err = ENOERR;
goto out;
}
// First deal with any entry that is at the destination
if (ds2.node) {
// Check that we are renaming like-for-like
if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) {
err = EISDIR;
goto out;
}
if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) {
err = ENOTDIR;
goto out;
}
// 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;
}
// 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);
jffs2_iput(ds1.node);
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 */
}
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;
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, name1);
err = jffs2_find(&ds1);
if (err != ENOERR) {
jffs2_iput(ds1.dir);
return err;
}
init_dirsearch(&ds2, (struct _inode *) dir2, name2);
err = jffs2_find(&ds2);
// 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;
}
// Allow through links to non-existing terminal objects
if (ds2.last && err == ENOENT) {
ds2.node = NULL;
err = ENOERR;
}
if (err != ENOERR) {
jffs2_iput(ds1.dir);
jffs2_iput(ds1.node);
jffs2_iput(ds2.dir);
return err;
}
// Now we know that there is no existing node at the destination,
// make a new direntry at the destination.
err = jffs2_link(ds1.node, ds2.dir, ds2.name);
if (err == 0)
ds1.node->i_ctime =
ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
jffs2_iput(ds1.dir);
jffs2_iput(ds1.node);
jffs2_iput(ds2.dir);
return -err;
}
#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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -