⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inode.c

📁 linux core 函数例程
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************/

/*
 *	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/namei.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 + -