📄 fs-ecos.c
字号:
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 = &mtab[0]; m != &mtab_end; m++) { // stop if there are more than the configured maximum if (m - &mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) { m = &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); err = jffs2_read_super(jffs2_sb); if (err) { 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")); jffs2_erase_pending_blocks(c); } 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;}// -------------------------------------------------------------------------// 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); D2(printf("jffs2_umount\n")); // Decrement the mount count jffs2_sb->s_mount_count--; // Only really umount if this is the only mount if (jffs2_sb->s_mount_count == 0) { // Check for open/inuse root or any cached inodes//if( root->i_count != 1 || root->i_cache_next != NULL) // root icount was set to 1 on mount if (root->i_cache_next != NULL) // root icount was set to 1 on mount return EBUSY; dec_refcnt(root); // Time to free the root inode //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 root pointer mte->root = CYG_DIR_NULL; 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")); } 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")); icache_evict((struct inode *) mte->root, (struct inode *) dir); init_dirsearch(&ds, (struct inode *) dir, name); err = jffs2_find(&ds); if (err == ENOENT) { if (ds.last && (mode & O_CREAT)) { unsigned long hash; struct qstr this; unsigned int c; const char *hashname; // 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. hashname = ds.name; this.name = hashname; c = *(const unsigned char *) hashname; hash = init_name_hash(); do { hashname++; hash = partial_name_hash(c, hash); c = *(const unsigned char *) hashname; } while (c && (c != '/')); this.len = hashname - (const char *) this.name; this.hash = end_name_hash(hash); err = jffs2_create(ds.dir, &this, 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; } } else if (err == ENOERR) { // The node exists. If the O_CREAT and O_EXCL bits are set, we // must fail the open. if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) err = EEXIST; else node = ds.node; } if (err == ENOERR && (mode & O_TRUNC)) { 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(); } if (err != ENOERR) return err; // Check that we actually have a file here if (S_ISDIR(node->i_mode)) return EISDIR; node->i_count++; // Count successful open // Initialize 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;}// -------------------------------------------------------------------------// 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){ unsigned long hash; struct qstr this; unsigned int c; const char *hashname; jffs2_dirsearch ds; int err; D2(printf("jffs2_ops_unlink\n")); icache_evict((struct inode *) mte->root, (struct inode *) dir); init_dirsearch(&ds, (struct inode *) dir, name); err = jffs2_find(&ds); if (err != ENOERR) return err; // Cannot unlink directories, use rmdir() instead if (S_ISDIR(ds.node->i_mode)) return EPERM; // Delete it from its directory hashname = ds.name; this.name = hashname; c = *(const unsigned char *) hashname; hash = init_name_hash(); do { hashname++; hash = partial_name_hash(c, hash); c = *(const unsigned char *) hashname; } while (c && (c != '/')); this.len = hashname - (const char *) this.name; this.hash = end_name_hash(hash); err = jffs2_unlink(ds.dir, ds.node, &this); 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; struct inode *node = NULL; int err; D2(printf("jffs2_ops_mkdir\n")); icache_evict((struct inode *) mte->root, (struct inode *) dir); init_dirsearch(&ds, (struct inode *) dir, name); err = jffs2_find(&ds); if (err == ENOENT) { if (ds.last) { unsigned long hash; struct qstr this; unsigned int c; const char *hashname; // The entry does not exist, and it is the last element in // the pathname, so we can create it here. hashname = ds.name; this.name = hashname; c = *(const unsigned char *) hashname; hash = init_name_hash(); do { hashname++; hash = partial_name_hash(c, hash); c = *(const unsigned char *) hashname; } while (c && (c != '/')); this.len = hashname - (const char *) this.name; this.hash = end_name_hash(hash); err = jffs2_mkdir(ds.dir, &this, 0, &node); if (err != 0) return ENOSPC; } // If this was not the last element, then and intermediate // directory does not exist. } else { // If there we no error, something already exists with that // name, so we cannot create another one. if (err == ENOERR) err = EEXIST; } return err;}// -------------------------------------------------------------------------// jffs2_ops_rmdir()// Remove a directory.static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name){ unsigned long hash; struct qstr this; unsigned int c; const char *hashname; jffs2_dirsearch ds; int err; D2(printf("jffs2_ops_rmdir\n")); icache_evict((struct inode *) mte->root, (struct inode *) dir); init_dirsearch(&ds, (struct inode *) dir, name); err = jffs2_find(&ds); if (err != ENOERR) return err; // Check that this is actually a directory. if (!S_ISDIR(ds.node->i_mode)) return EPERM; // Delete the entry. hashname = ds.name; this.name = hashname; c = *(const unsigned char *) hashname; hash = init_name_hash(); do { hashname++; hash = partial_name_hash(c, hash); c = *(const unsigned char *) hashname; } while (c && (c != '/')); this.len = hashname - (const char *) this.name; this.hash = end_name_hash(hash); err = jffs2_rmdir(ds.dir, ds.node, &this); return err; return ENOERR;}// -------------------------------------------------------------------------// 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){ unsigned long hash; struct qstr this1, this2; unsigned int c; const char *hashname; 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) 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) return err; // Null rename, just return if (ds1.node == ds2.node) return ENOERR; hashname = ds1.name; this1.name = hashname; c = *(const unsigned char *) hashname; hash = init_name_hash(); do { hashname++; hash = partial_name_hash(c, hash); c = *(const unsigned char *) hashname; } while (c && (c != '/')); this1.len = hashname - (const char *) this1.name; this1.hash = end_name_hash(hash); hashname = ds2.name; this2.name = hashname; c = *(const unsigned char *) hashname; hash = init_name_hash(); do { hashname++; hash = partial_name_hash(c, hash); c = *(const unsigned char *) hashname; } while (c && (c != '/')); this2.len = hashname - (const char *) this2.name; this2.hash = end_name_hash(hash); // 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)) return EISDIR; if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) return ENOTDIR; // Now delete the destination directory entry err = jffs2_unlink(ds2.dir, ds2.node, &this2); if (err != 0) return err; } // 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, &this1, ds2.dir, &this2); // Update directory times if (err == 0) ds1.dir->i_ctime = ds1.dir->i_mtime = ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp(); 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){ unsigned long hash; struct qstr this; unsigned int c; const char *hashname; 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) return err; init_dirsearch(&ds2, (struct inode *) dir2, name2); err = jffs2_find(&ds2); // Don't allow links to existing objects if (err == ENOERR) return EEXIST; // Allow through links to non-existing terminal objects if (ds2.last && err == ENOENT) ds2.node = NULL, err = ENOERR; if (err != ENOERR) return err; // Now we know that there is no existing node at the destination, // make a new direntry at the destination. hashname = ds2.name; this.name = hashname; c = *(const unsigned char *) hashname; hash = init_name_hash(); do { hashname++; hash = partial_name_hash(c, hash); c = *(const unsigned char *) hashname; } while (c && (c != '/')); this.len = hashname - (const char *) this.name; this.hash = end_name_hash(hash); err = jffs2_link(ds2.dir, ds1.node, &this);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -