📄 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 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 *//*****************************************************************************/#define __NO_VERSION__#include <linux/config.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/pagemap.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/usb.h>#include <linux/usbdevice_fs.h>#include <linux/smp_lock.h>#include <asm/byteorder.h>static struct super_operations usbfs_ops;static struct file_operations default_file_operations;static struct inode_operations usbfs_dir_inode_operations;static struct vfsmount *usbfs_mount;static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;static int mount_count; /* = 0 */static struct dentry *devices_dentry;static struct dentry *drivers_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;static int parse_options(struct super_block *s, char *data){ char *curopt = NULL, *value; while ((curopt = strsep(&data, ",")) != NULL) { if (!*curopt) continue; if ((value = strchr(curopt, '=')) != NULL) *value++ = 0; if (!strcmp(curopt, "devuid")) { if (!value || !value[0]) return -EINVAL; devuid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "devgid")) { if (!value || !value[0]) return -EINVAL; devgid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "devmode")) { if (!value || !value[0]) return -EINVAL; devmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; if (*value) return -EINVAL; } if (!strcmp(curopt, "busuid")) { if (!value || !value[0]) return -EINVAL; busuid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "busgid")) { if (!value || !value[0]) return -EINVAL; busgid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "busmode")) { if (!value || !value[0]) return -EINVAL; busmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; if (*value) return -EINVAL; } if (!strcmp(curopt, "listuid")) { if (!value || !value[0]) return -EINVAL; listuid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "listgid")) { if (!value || !value[0]) return -EINVAL; listgid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "listmode")) { if (!value || !value[0]) return -EINVAL; listmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; if (*value) return -EINVAL; } } return 0;}/* --------------------------------------------------------------------- */static struct inode *usbfs_get_inode (struct super_block *sb, int mode, int 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_rdev = NODEV; 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 = &usbfs_dir_inode_operations; inode->i_fop = &simple_dir_operations; break; } } return inode; }/* SMP-safe */static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode, int dev){ struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); int error = -ENOSPC; if (inode) { d_instantiate(dentry, inode); dget(dentry); error = 0; } return error;}static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode){ return usbfs_mknod (dir, dentry, mode | S_IFDIR, 0);}static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode){ return usbfs_mknod (dir, dentry, mode | S_IFREG, 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){ int error = -ENOTEMPTY; if (usbfs_empty(dentry)) { struct inode *inode = dentry->d_inode; lock_kernel(); inode->i_nlink--; unlock_kernel(); dput(dentry); error = 0; } return error;}#define usbfs_rmdir usbfs_unlink/* default file operations */static ssize_t default_read_file (struct file *file, char *buf, size_t count, loff_t *ppos){ return 0;}static ssize_t default_write_file (struct file *file, const char *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; lock_kernel(); switch(orig) { case 0: if (offset > 0) { file->f_pos = offset; retval = file->f_pos; } break; case 1: if ((offset + file->f_pos) > 0) { file->f_pos += offset; retval = file->f_pos; } break; default: break; } unlock_kernel(); return retval;}static int default_open (struct inode *inode, struct file *filp){ if (inode->u.generic_ip) filp->private_data = inode->u.generic_ip; return 0;}static struct file_operations default_file_operations = { read: default_read_file, write: default_write_file, open: default_open, llseek: default_file_lseek,};static struct inode_operations usbfs_dir_inode_operations = { create: usbfs_create, lookup: simple_lookup, unlink: usbfs_unlink, mkdir: usbfs_mkdir, rmdir: usbfs_rmdir,};static struct super_operations usbfs_ops = { statfs: simple_statfs, put_inode: force_delete,};static int usbfs_fill_super(struct super_block *sb, void *data, int silent){ struct inode *inode; struct dentry *root; if (parse_options(sb, data)) { warn("usbfs: mount parameter error:"); return -EINVAL; } sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = USBDEVICE_SUPER_MAGIC; sb->s_op = &usbfs_ops; inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); if (!inode) { dbg("%s: could not get inode!\n",__FUNCTION__); return -ENOMEM; } root = d_alloc_root(inode); if (!root) { dbg("%s: could not get root dentry!\n",__FUNCTION__); iput(inode); return -ENOMEM; } sb->s_root = root; return 0;}/** * fs_create_by_name - create a file, given a name * @name: name of file * @mode: type of file * @parent: dentry of directory to create it in * @dentry: resulting dentry of file * * There is a bit of overhead in creating a file - basically, we * have to hash the name of the file, then look it up. This will * prevent files of the same name. * We then call the proper vfs_ function to take care of all the * file creation details. * This function handles both regular files and directories. */static int fs_create_by_name (const char *name, mode_t mode, struct dentry *parent, struct dentry **dentry){ struct dentry *d = NULL; struct qstr qstr; int error; /* If the parent is not specified, we create it in the root. * We need the root dentry to do this, which is in the super * block. A pointer to that is in the struct vfsmount that we * have around. */ if (!parent ) { if (usbfs_mount && usbfs_mount->mnt_sb) { parent = usbfs_mount->mnt_sb->s_root; } } if (!parent) { dbg("Ah! can not find a parent!\n"); return -EFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -