📄 inode.c
字号:
} stored++; offset = nextfh & ROMFH_MASK; }out: unlock_kernel(); return stored;}static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ unsigned long offset, maxoff; int fslen, res; struct inode *inode; char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ struct romfs_inode ri; const char *name; /* got from dentry */ int len; res = -EACCES; /* placeholder for "no data here" */ offset = dir->i_ino & ROMFH_MASK; lock_kernel(); if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) goto out; maxoff = romfs_maxsize(dir->i_sb); offset = be32_to_cpu(ri.spec) & ROMFH_MASK; /* OK, now find the file whose name is in "dentry" in the * directory specified by "dir". */ name = dentry->d_name.name; len = dentry->d_name.len; for(;;) { if (!offset || offset >= maxoff) goto out0; if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) goto out; /* try to match the first 16 bytes of name */ fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE); if (len < ROMFH_SIZE) { if (len == fslen) { /* both are shorter, and same size */ romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1); if (strncmp (name, fsname, len) == 0) break; } } else if (fslen >= ROMFH_SIZE) { /* both are longer; XXX optimize max size */ fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1); if (len == fslen) { romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1); if (strncmp(name, fsname, len) == 0) break; } } /* next entry */ offset = be32_to_cpu(ri.next) & ROMFH_MASK; } /* Hard link handling */ if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD) offset = be32_to_cpu(ri.spec) & ROMFH_MASK; if ((inode = iget(dir->i_sb, offset))) goto outi; /* * it's a bit funky, _lookup needs to return an error code * (negative) or a NULL, both as a dentry. ENOENT should not * be returned, instead we need to create a negative dentry by * d_add(dentry, NULL); and return 0 as no error. * (Although as I see, it only matters on writable file * systems). */out0: inode = NULL;outi: res = 0; d_add (dentry, inode);out: unlock_kernel(); return ERR_PTR(res);}/* * Ok, we do readpage, to be able to execute programs. Unfortunately, * we can't use bmap, since we may have looser alignments. */static intromfs_readpage(struct file *file, struct page * page){ struct inode *inode = page->mapping->host; loff_t offset, avail, readlen; void *buf; int result = -EIO; page_cache_get(page); lock_kernel(); buf = kmap(page); if (!buf) goto err_out; /* 32 bit warning -- but not for us :) */ offset = page_offset(page); if (offset < i_size_read(inode)) { avail = inode->i_size-offset; readlen = min_t(unsigned long, avail, PAGE_SIZE); if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) { if (readlen < PAGE_SIZE) { memset(buf + readlen,0,PAGE_SIZE-readlen); } SetPageUptodate(page); result = 0; } } if (result) { memset(buf, 0, PAGE_SIZE); SetPageError(page); } flush_dcache_page(page); unlock_page(page); kunmap(page);err_out: page_cache_release(page); unlock_kernel(); return result;}/* Mapping from our types to the kernel */static const struct address_space_operations romfs_aops = { .readpage = romfs_readpage};static const struct file_operations romfs_dir_operations = { .read = generic_read_dir, .readdir = romfs_readdir,};static const struct inode_operations romfs_dir_inode_operations = { .lookup = romfs_lookup,};static mode_t romfs_modemap[] ={ 0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777, S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644};static voidromfs_read_inode(struct inode *i){ int nextfh, ino; struct romfs_inode ri; ino = i->i_ino & ROMFH_MASK; i->i_mode = 0; /* Loop for finding the real hard link */ for(;;) { if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) { printk("romfs: read error for inode 0x%x\n", ino); return; } /* XXX: do romfs_checksum here too (with name) */ nextfh = be32_to_cpu(ri.next); if ((nextfh & ROMFH_TYPE) != ROMFH_HRD) break; ino = be32_to_cpu(ri.spec) & ROMFH_MASK; } i->i_nlink = 1; /* Hard to decide.. */ i->i_size = be32_to_cpu(ri.size); i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0; i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0; i->i_uid = i->i_gid = 0; /* Precalculate the data offset */ ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN); if (ino >= 0) ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK); else ino = 0; ROMFS_I(i)->i_metasize = ino; ROMFS_I(i)->i_dataoffset = ino+(i->i_ino&ROMFH_MASK); /* Compute permissions */ ino = romfs_modemap[nextfh & ROMFH_TYPE]; /* only "normal" files have ops */ switch (nextfh & ROMFH_TYPE) { case 1: i->i_size = ROMFS_I(i)->i_metasize; i->i_op = &romfs_dir_inode_operations; i->i_fop = &romfs_dir_operations; if (nextfh & ROMFH_EXEC) ino |= S_IXUGO; i->i_mode = ino; break; case 2: i->i_fop = &generic_ro_fops; i->i_data.a_ops = &romfs_aops; if (nextfh & ROMFH_EXEC) ino |= S_IXUGO; i->i_mode = ino; break; case 3: i->i_op = &page_symlink_inode_operations; i->i_data.a_ops = &romfs_aops; i->i_mode = ino | S_IRWXUGO; break; default: /* depending on MBZ for sock/fifos */ nextfh = be32_to_cpu(ri.spec); init_special_inode(i, ino, MKDEV(nextfh>>16,nextfh&0xffff)); }}static struct kmem_cache * romfs_inode_cachep;static struct inode *romfs_alloc_inode(struct super_block *sb){ struct romfs_inode_info *ei; ei = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode;}static void romfs_destroy_inode(struct inode *inode){ kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));}static void init_once(struct kmem_cache *cachep, void *foo){ struct romfs_inode_info *ei = foo; inode_init_once(&ei->vfs_inode);}static int init_inodecache(void){ romfs_inode_cachep = kmem_cache_create("romfs_inode_cache", sizeof(struct romfs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), init_once); if (romfs_inode_cachep == NULL) return -ENOMEM; return 0;}static void destroy_inodecache(void){ kmem_cache_destroy(romfs_inode_cachep);}static int romfs_remount(struct super_block *sb, int *flags, char *data){ *flags |= MS_RDONLY; return 0;}static const struct super_operations romfs_ops = { .alloc_inode = romfs_alloc_inode, .destroy_inode = romfs_destroy_inode, .read_inode = romfs_read_inode, .statfs = romfs_statfs, .remount_fs = romfs_remount,};static int romfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt){ return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super, mnt);}static struct file_system_type romfs_fs_type = { .owner = THIS_MODULE, .name = "romfs", .get_sb = romfs_get_sb, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV,};static int __init init_romfs_fs(void){ int err = init_inodecache(); if (err) goto out1; err = register_filesystem(&romfs_fs_type); if (err) goto out; return 0;out: destroy_inodecache();out1: return err;}static void __exit exit_romfs_fs(void){ unregister_filesystem(&romfs_fs_type); destroy_inodecache();}/* Yes, works even as a module... :) */module_init(init_romfs_fs)module_exit(exit_romfs_fs)MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -