📄 inode.c
字号:
save_and_cli (flags); error = prom_setprop (node, op->name, op->value, op->len + 1); restore_flags (flags); if (error <= 0) printk (KERN_WARNING "openpromfs: " "Couldn't write property %s\n", op->name); } else if ((op->flag & OPP_BINARY) || !op->len) { save_and_cli (flags); error = prom_setprop (node, op->name, op->value, op->len); restore_flags (flags); if (error <= 0) printk (KERN_WARNING "openpromfs: " "Couldn't write property %s\n", op->name); } else { printk (KERN_WARNING "openpromfs: " "Unknown property type of %s\n", op->name); } } unlock_kernel(); kfree (filp->private_data); return 0;}static struct file_operations openpromfs_prop_ops = { read: property_read, write: property_write, release: property_release,};static struct file_operations openpromfs_nodenum_ops = { read: nodenum_read,};static struct file_operations openprom_operations = { read: generic_read_dir, readdir: openpromfs_readdir,};static struct inode_operations openprom_alias_inode_operations = { create: openpromfs_create, lookup: openpromfs_lookup, unlink: openpromfs_unlink,};static struct inode_operations openprom_inode_operations = { lookup: openpromfs_lookup,};static int lookup_children(u16 n, const char * name, int len){ int ret; u16 node; for (; n != 0xffff; n = nodes[n].next) { node = nodes[n].child; if (node != 0xffff) { char buffer[128]; int i; char *p; while (node != 0xffff) { if (prom_getname (nodes[node].node, buffer, 128) >= 0) { i = strlen (buffer); if ((len == i) && !strncmp (buffer, name, len)) return NODE2INO(node); p = strchr (buffer, '@'); if (p && (len == p - buffer) && !strncmp (buffer, name, len)) return NODE2INO(node); } node = nodes[node].next; } } else continue; ret = lookup_children (nodes[n].child, name, len); if (ret) return ret; } return 0;}static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentry){ int ino = 0;#define OPFSL_DIR 0#define OPFSL_PROPERTY 1#define OPFSL_NODENUM 2 int type = 0; char buffer[128]; char *p; const char *name; u32 n; u16 dirnode; unsigned int len; int i; struct inode *inode; char buffer2[64]; inode = NULL; name = dentry->d_name.name; len = dentry->d_name.len; if (name [0] == '.' && len == 5 && !strncmp (name + 1, "node", 4)) { ino = NODEP2INO(NODE(dir->i_ino).first_prop); type = OPFSL_NODENUM; } if (!ino) { u16 node = NODE(dir->i_ino).child; while (node != 0xffff) { if (prom_getname (nodes[node].node, buffer, 128) >= 0) { i = strlen (buffer); if (len == i && !strncmp (buffer, name, len)) { ino = NODE2INO(node); type = OPFSL_DIR; break; } p = strchr (buffer, '@'); if (p && (len == p - buffer) && !strncmp (buffer, name, len)) { ino = NODE2INO(node); type = OPFSL_DIR; break; } } node = nodes[node].next; } } n = NODE(dir->i_ino).node; dirnode = dir->i_ino - OPENPROM_FIRST_INO; if (!ino) { int j = NODEP2INO(NODE(dir->i_ino).first_prop); if (dirnode != aliases) { for (p = prom_firstprop (n, buffer2); p && *p; p = prom_nextprop (n, p, buffer2)) { j++; if ((len == strlen (p)) && !strncmp (p, name, len)) { ino = j; type = OPFSL_PROPERTY; break; } } } else { int k; for (k = 0; k < aliases_nodes; k++) { j++; if (alias_names [k] && (len == strlen (alias_names [k])) && !strncmp (alias_names [k], name, len)) { ino = j; type = OPFSL_PROPERTY; break; } } } } if (!ino) { ino = lookup_children (NODE(dir->i_ino).child, name, len); if (ino) type = OPFSL_DIR; else return ERR_PTR(-ENOENT); } inode = iget (dir->i_sb, ino); if (!inode) return ERR_PTR(-EINVAL); switch (type) { case OPFSL_DIR: inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; if (ino == OPENPROM_FIRST_INO + aliases) { inode->i_mode |= S_IWUSR; inode->i_op = &openprom_alias_inode_operations; } else inode->i_op = &openprom_inode_operations; inode->i_fop = &openprom_operations; inode->i_nlink = 2; break; case OPFSL_NODENUM: inode->i_mode = S_IFREG | S_IRUGO; inode->i_fop = &openpromfs_nodenum_ops; inode->i_nlink = 1; inode->u.generic_ip = (void *)(long)(n); break; case OPFSL_PROPERTY: if ((dirnode == options) && (len == 17) && !strncmp (name, "security-password", 17)) inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; else { inode->i_mode = S_IFREG | S_IRUGO; if (dirnode == options || dirnode == aliases) { if (len != 4 || strncmp (name, "name", 4)) inode->i_mode |= S_IWUSR; } } inode->i_fop = &openpromfs_prop_ops; inode->i_nlink = 1; if (inode->i_size < 0) inode->i_size = 0; inode->u.generic_ip = (void *)(long)(((u16)dirnode) | (((u16)(ino - NODEP2INO(NODE(dir->i_ino).first_prop) - 1)) << 16)); break; } inode->i_gid = 0; inode->i_uid = 0; d_add(dentry, inode); return NULL;}static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir){ struct inode *inode = filp->f_dentry->d_inode; unsigned int ino; u32 n; int i, j; char buffer[128]; u16 node; char *p; char buffer2[64]; ino = inode->i_ino; i = filp->f_pos; switch (i) { case 0: if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) return 0; i++; filp->f_pos++; /* fall thru */ case 1: if (filldir(dirent, "..", 2, i, (NODE(ino).parent == 0xffff) ? OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent), DT_DIR) < 0) return 0; i++; filp->f_pos++; /* fall thru */ default: i -= 2; node = NODE(ino).child; while (i && node != 0xffff) { node = nodes[node].next; i--; } while (node != 0xffff) { if (prom_getname (nodes[node].node, buffer, 128) < 0) return 0; if (filldir(dirent, buffer, strlen(buffer), filp->f_pos, NODE2INO(node), DT_DIR) < 0) return 0; filp->f_pos++; node = nodes[node].next; } j = NODEP2INO(NODE(ino).first_prop); if (!i) { if (filldir(dirent, ".node", 5, filp->f_pos, j, DT_REG) < 0) return 0; filp->f_pos++; } else i--; n = NODE(ino).node; if (ino == OPENPROM_FIRST_INO + aliases) { for (j++; i < aliases_nodes; i++, j++) { if (alias_names [i]) { if (filldir (dirent, alias_names [i], strlen (alias_names [i]), filp->f_pos, j, DT_REG) < 0) return 0; filp->f_pos++; } } } else { for (p = prom_firstprop (n, buffer2); p && *p; p = prom_nextprop (n, p, buffer2)) { j++; if (i) i--; else { if (filldir(dirent, p, strlen(p), filp->f_pos, j, DT_REG) < 0) return 0; filp->f_pos++; } } } } return 0;}static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode){ char *p; struct inode *inode; if (!dir) return -ENOENT; if (dentry->d_name.len > 256) return -EINVAL; if (aliases_nodes == ALIASES_NNODES) return -EIO; p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL); if (!p) return -ENOMEM; strncpy (p, dentry->d_name.name, dentry->d_name.len); p [dentry->d_name.len] = 0; alias_names [aliases_nodes++] = p; inode = iget (dir->i_sb, NODEP2INO(NODE(dir->i_ino).first_prop) + aliases_nodes); if (!inode) return -EINVAL; inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR; inode->i_fop = &openpromfs_prop_ops; inode->i_nlink = 1; if (inode->i_size < 0) inode->i_size = 0; inode->u.generic_ip = (void *)(long)(((u16)aliases) | (((u16)(aliases_nodes - 1)) << 16)); d_instantiate(dentry, inode); return 0;}static int openpromfs_unlink (struct inode *dir, struct dentry *dentry){ unsigned int len; char *p; const char *name; int i; name = dentry->d_name.name; len = dentry->d_name.len; for (i = 0; i < aliases_nodes; i++) if ((strlen (alias_names [i]) == len) && !strncmp (name, alias_names[i], len)) { char buffer[512]; p = alias_names [i]; alias_names [i] = NULL; kfree (p); strcpy (buffer, "nvunalias "); memcpy (buffer + 10, name, len); buffer [10 + len] = 0; prom_feval (buffer); } return 0;}/* {{{ init section */#ifndef MODULEstatic int __init check_space (u16 n)#elsestatic int check_space (u16 n)#endif{ unsigned long pages; if ((1 << alloced) * PAGE_SIZE < (n + 2) * sizeof(openpromfs_node)) { pages = __get_free_pages (GFP_KERNEL, alloced + 1); if (!pages) return -1; if (nodes) { memcpy ((char *)pages, (char *)nodes, (1 << alloced) * PAGE_SIZE); free_pages ((unsigned long)nodes, alloced); } alloced++; nodes = (openpromfs_node *)pages; } return 0;}#ifndef MODULEstatic u16 __init get_nodes (u16 parent, u32 node)#elsestatic u16 get_nodes (u16 parent, u32 node)#endif{ char *p; u16 n = last_node++, i; char buffer[64]; if (check_space (n) < 0) return 0xffff; nodes[n].parent = parent; nodes[n].node = node; nodes[n].next = 0xffff; nodes[n].child = 0xffff; nodes[n].first_prop = first_prop++; if (!parent) { char buffer[8]; int j; if ((j = prom_getproperty (node, "name", buffer, 8)) >= 0) { buffer[j] = 0; if (!strcmp (buffer, "options")) options = n; else if (!strcmp (buffer, "aliases")) aliases = n; } } if (n != aliases) for (p = prom_firstprop (node, buffer); p && p != (char *)-1 && *p; p = prom_nextprop (node, p, buffer)) first_prop++; else { char *q; for (p = prom_firstprop (node, buffer); p && p != (char *)-1 && *p; p = prom_nextprop (node, p, buffer)) { if (aliases_nodes == ALIASES_NNODES) break; for (i = 0; i < aliases_nodes; i++) if (!strcmp (p, alias_names [i])) break; if (i < aliases_nodes) continue; q = kmalloc (strlen (p) + 1, GFP_KERNEL); if (!q) return 0xffff; strcpy (q, p); alias_names [aliases_nodes++] = q; } first_prop += ALIASES_NNODES; } node = prom_getchild (node); if (node) { parent = get_nodes (n, node); if (parent == 0xffff) return 0xffff; nodes[n].child = parent; while ((node = prom_getsibling (node)) != 0) { i = get_nodes (n, node); if (i == 0xffff) return 0xffff; nodes[parent].next = i; parent = i; } } return n;}static void openprom_read_inode(struct inode * inode){ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; if (inode->i_ino == OPENPROM_ROOT_INO) { inode->i_op = &openprom_inode_operations; inode->i_fop = &openprom_operations; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; }}static int openprom_statfs(struct super_block *sb, struct statfs *buf){ buf->f_type = OPENPROM_SUPER_MAGIC; buf->f_bsize = PAGE_SIZE/sizeof(long); /* ??? */ buf->f_bfree = 0; buf->f_bavail = 0; buf->f_ffree = 0; buf->f_namelen = NAME_MAX; return 0;}static struct super_operations openprom_sops = { read_inode: openprom_read_inode, statfs: openprom_statfs,};struct super_block *openprom_read_super(struct super_block *s,void *data, int silent){ struct inode * root_inode; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = OPENPROM_SUPER_MAGIC; s->s_op = &openprom_sops; root_inode = iget(s, OPENPROM_ROOT_INO); if (!root_inode) goto out_no_root; s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto out_no_root; return s;out_no_root: printk("openprom_read_super: get root inode failed\n"); iput(root_inode); return NULL;}static DECLARE_FSTYPE(openprom_fs_type, "openpromfs", openprom_read_super, 0);static int __init init_openprom_fs(void){ nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0); if (!nodes) { printk (KERN_WARNING "openpromfs: can't get free page\n"); return -EIO; } if (get_nodes (0xffff, prom_root_node) == 0xffff) { printk (KERN_WARNING "openpromfs: couldn't setup tree\n"); return -EIO; } nodes[last_node].first_prop = first_prop; return register_filesystem(&openprom_fs_type);}static void __exit exit_openprom_fs(void){ int i; unregister_filesystem(&openprom_fs_type); free_pages ((unsigned long)nodes, alloced); for (i = 0; i < aliases_nodes; i++) if (alias_names [i]) kfree (alias_names [i]); nodes = NULL;}EXPORT_NO_SYMBOLS;module_init(init_openprom_fs)module_exit(exit_openprom_fs)MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -