📄 inode.c
字号:
/*****************************************************************************//* * inode.c -- Inode/Dentry functions for the USB device file system. * * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History: * 0.1 04.01.2000 Created * 0.2 10.12.2001 converted to use the vfs layer better *//*****************************************************************************/#include <linux/config.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/mount.h>#include <linux/pagemap.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/usb.h>#include <linux/namei.h>#include <linux/usbdevice_fs.h>#include <linux/smp_lock.h>#include <linux/parser.h>#include <linux/notifier.h>#include <asm/byteorder.h>#include "usb.h"#include "hcd.h"static struct super_operations usbfs_ops;static struct file_operations default_file_operations;static struct vfsmount *usbfs_mount;static int usbfs_mount_count; /* = 0 */static int ignore_mount = 0;static struct dentry *devices_usbfs_dentry;static int num_buses; /* = 0 */static uid_t devuid; /* = 0 */static uid_t busuid; /* = 0 */static uid_t listuid; /* = 0 */static gid_t devgid; /* = 0 */static gid_t busgid; /* = 0 */static gid_t listgid; /* = 0 */static umode_t devmode = S_IWUSR | S_IRUGO;static umode_t busmode = S_IXUGO | S_IRUGO;static umode_t listmode = S_IRUGO;enum { Opt_devuid, Opt_devgid, Opt_devmode, Opt_busuid, Opt_busgid, Opt_busmode, Opt_listuid, Opt_listgid, Opt_listmode, Opt_err,};static match_table_t tokens = { {Opt_devuid, "devuid=%u"}, {Opt_devgid, "devgid=%u"}, {Opt_devmode, "devmode=%o"}, {Opt_busuid, "busuid=%u"}, {Opt_busgid, "busgid=%u"}, {Opt_busmode, "busmode=%o"}, {Opt_listuid, "listuid=%u"}, {Opt_listgid, "listgid=%u"}, {Opt_listmode, "listmode=%o"}, {Opt_err, NULL}};static int parse_options(struct super_block *s, char *data){ char *p; int option; /* (re)set to defaults. */ devuid = 0; busuid = 0; listuid = 0; devgid = 0; busgid = 0; listgid = 0; devmode = S_IWUSR | S_IRUGO; busmode = S_IXUGO | S_IRUGO; listmode = S_IRUGO; while ((p = strsep(&data, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; int token; if (!*p) continue; token = match_token(p, tokens, args); switch (token) { case Opt_devuid: if (match_int(&args[0], &option)) return -EINVAL; devuid = option; break; case Opt_devgid: if (match_int(&args[0], &option)) return -EINVAL; devgid = option; break; case Opt_devmode: if (match_octal(&args[0], &option)) return -EINVAL; devmode = option & S_IRWXUGO; break; case Opt_busuid: if (match_int(&args[0], &option)) return -EINVAL; busuid = option; break; case Opt_busgid: if (match_int(&args[0], &option)) return -EINVAL; busgid = option; break; case Opt_busmode: if (match_octal(&args[0], &option)) return -EINVAL; busmode = option & S_IRWXUGO; break; case Opt_listuid: if (match_int(&args[0], &option)) return -EINVAL; listuid = option; break; case Opt_listgid: if (match_int(&args[0], &option)) return -EINVAL; listgid = option; break; case Opt_listmode: if (match_octal(&args[0], &option)) return -EINVAL; listmode = option & S_IRWXUGO; break; default: err("usbfs: unrecognised mount option \"%s\" " "or missing value\n", p); return -EINVAL; } } return 0;}static void update_special(struct dentry *special){ special->d_inode->i_uid = listuid; special->d_inode->i_gid = listgid; special->d_inode->i_mode = S_IFREG | listmode;}static void update_dev(struct dentry *dev){ dev->d_inode->i_uid = devuid; dev->d_inode->i_gid = devgid; dev->d_inode->i_mode = S_IFREG | devmode;}static void update_bus(struct dentry *bus){ struct dentry *dev = NULL; bus->d_inode->i_uid = busuid; bus->d_inode->i_gid = busgid; bus->d_inode->i_mode = S_IFDIR | busmode; down(&bus->d_inode->i_sem); list_for_each_entry(dev, &bus->d_subdirs, d_child) if (dev->d_inode) update_dev(dev); up(&bus->d_inode->i_sem);}static void update_sb(struct super_block *sb){ struct dentry *root = sb->s_root; struct dentry *bus = NULL; if (!root) return; down(&root->d_inode->i_sem); list_for_each_entry(bus, &root->d_subdirs, d_child) { if (bus->d_inode) { switch (S_IFMT & bus->d_inode->i_mode) { case S_IFDIR: update_bus(bus); break; case S_IFREG: update_special(bus); break; default: warn("Unknown node %s mode %x found on remount!\n",bus->d_name.name,bus->d_inode->i_mode); break; } } } up(&root->d_inode->i_sem);}static int remount(struct super_block *sb, int *flags, char *data){ /* If this is not a real mount, * i.e. it's a simple_pin_fs from create_special_files, * then ignore it. */ if (ignore_mount) return 0; if (parse_options(sb, data)) { warn("usbfs: mount parameter error:"); return -EINVAL; } if (usbfs_mount && usbfs_mount->mnt_sb) update_sb(usbfs_mount->mnt_sb); return 0;}static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t dev){ struct inode *inode = new_inode(sb); if (inode) { inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { default: init_special_inode(inode, mode, dev); break; case S_IFREG: inode->i_fop = &default_file_operations; break; case S_IFDIR: inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inode->i_nlink++; break; } } return inode; }/* SMP-safe */static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode, dev_t dev){ struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); int error = -EPERM; if (dentry->d_inode) return -EEXIST; if (inode) { d_instantiate(dentry, inode); dget(dentry); error = 0; } return error;}static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode){ int res; mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; res = usbfs_mknod (dir, dentry, mode, 0); if (!res) dir->i_nlink++; return res;}static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode){ mode = (mode & S_IALLUGO) | S_IFREG; return usbfs_mknod (dir, dentry, mode, 0);}static inline int usbfs_positive (struct dentry *dentry){ return dentry->d_inode && !d_unhashed(dentry);}static int usbfs_empty (struct dentry *dentry){ struct list_head *list; spin_lock(&dcache_lock); list_for_each(list, &dentry->d_subdirs) { struct dentry *de = list_entry(list, struct dentry, d_child); if (usbfs_positive(de)) { spin_unlock(&dcache_lock); return 0; } } spin_unlock(&dcache_lock); return 1;}static int usbfs_unlink (struct inode *dir, struct dentry *dentry){ struct inode *inode = dentry->d_inode; down(&inode->i_sem); dentry->d_inode->i_nlink--; dput(dentry); up(&inode->i_sem); d_delete(dentry); return 0;}static int usbfs_rmdir(struct inode *dir, struct dentry *dentry){ int error = -ENOTEMPTY; struct inode * inode = dentry->d_inode; down(&inode->i_sem); dentry_unhash(dentry); if (usbfs_empty(dentry)) { dentry->d_inode->i_nlink -= 2; dput(dentry); inode->i_flags |= S_DEAD; dir->i_nlink--; error = 0; } up(&inode->i_sem); if (!error) d_delete(dentry); dput(dentry); return error;}/* default file operations */static ssize_t default_read_file (struct file *file, char __user *buf, size_t count, loff_t *ppos){ return 0;}static ssize_t default_write_file (struct file *file, const char __user *buf, size_t count, loff_t *ppos){ return count;}static loff_t default_file_lseek (struct file *file, loff_t offset, int orig){ loff_t retval = -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -