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

📄 namei.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/umsdos/namei.c * *      Written 1993 by Jacques Gelinas  *      Inspired from linux/fs/msdos/... by Werner Almesberger * * Maintain and access the --linux alternate directory file. */ /*  * You are in the maze of twisted functions - half of them shouldn't  * be here...  */#include <linux/errno.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/stat.h>#include <linux/string.h>#include <linux/msdos_fs.h>#include <linux/umsdos_fs.h>#include <linux/slab.h>#define UMSDOS_DIR_LOCK#ifdef UMSDOS_DIR_LOCKstatic inline void u_sleep_on (struct inode *dir){	sleep_on (&dir->u.umsdos_i.dir_info.p);}static inline void u_wake_up (struct inode *dir){    	wake_up (&dir->u.umsdos_i.dir_info.p);}/* * Wait for creation exclusivity. * Return 0 if the dir was already available. * Return 1 if a wait was necessary. * When 1 is return, it means a wait was done. It does not * mean the directory is available. */static int umsdos_waitcreate (struct inode *dir){	int ret = 0;	if (dir->u.umsdos_i.dir_info.creating	    && dir->u.umsdos_i.dir_info.pid != current->pid) {	    	PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", dir->u.umsdos_i.dir_info.pid, current->pid));	    	u_sleep_on (dir);		ret = 1;	}	return ret;}/* * Wait for any lookup process to finish */static void umsdos_waitlookup (struct inode *dir){	while (dir->u.umsdos_i.dir_info.looking) {	    	u_sleep_on (dir);	}}/* * Lock all other process out of this directory. *//* #Specification: file creation / not atomic * File creation is a two step process. First we create (allocate) * an entry in the EMD file and then (using the entry offset) we * build a unique name for MSDOS. We create this name in the msdos * space. *  * We have to use semaphore (sleep_on/wake_up) to prevent lookup * into a directory when we create a file or directory and to * prevent creation while a lookup is going on. Since many lookup * may happen at the same time, the semaphore is a counter. *  * Only one creation is allowed at the same time. This protection * may not be necessary. The problem arise mainly when a lookup * or a readdir is done while a file is partially created. The * lookup process see that as a "normal" problem and silently * erase the file from the EMD file. Normal because a file * may be erased during a MSDOS session, but not removed from * the EMD file. *  * The locking is done on a directory per directory basis. Each * directory inode has its wait_queue. *  * For some operation like hard link, things even get worse. Many * creation must occur at once (atomic). To simplify the design * a process is allowed to recursively lock the directory for * creation. The pid of the locking process is kept along with * a counter so a second level of locking is granted or not. */void umsdos_lockcreate (struct inode *dir){	/*	 * Wait for any creation process to finish except	 * if we (the process) own the lock	 */	while (umsdos_waitcreate (dir) != 0);	dir->u.umsdos_i.dir_info.creating++;	dir->u.umsdos_i.dir_info.pid = current->pid;	umsdos_waitlookup (dir);}/* * Lock all other process out of those two directories. */static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){	/*	 * We must check that both directory are available before	 * locking anyone of them. This is to avoid some deadlock.	 * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing	 * this to me.	 */	while (1) {		if (umsdos_waitcreate (dir1) == 0		    && umsdos_waitcreate (dir2) == 0) {			/* We own both now */			dir1->u.umsdos_i.dir_info.creating++;			dir1->u.umsdos_i.dir_info.pid = current->pid;			dir2->u.umsdos_i.dir_info.creating++;			dir2->u.umsdos_i.dir_info.pid = current->pid;			break;		}	}	umsdos_waitlookup (dir1);	umsdos_waitlookup (dir2);}/* * Wait until creation is finish in this directory. */void umsdos_startlookup (struct inode *dir){	while (umsdos_waitcreate (dir) != 0);	dir->u.umsdos_i.dir_info.looking++;}/* * Unlock the directory. */void umsdos_unlockcreate (struct inode *dir){	dir->u.umsdos_i.dir_info.creating--;	if (dir->u.umsdos_i.dir_info.creating < 0) {		printk ("UMSDOS: dir->u.umsdos_i.dir_info.creating < 0: %d"			,dir->u.umsdos_i.dir_info.creating);	}    	u_wake_up (dir);}/* * Tell directory lookup is over. */void umsdos_endlookup (struct inode *dir){	dir->u.umsdos_i.dir_info.looking--;	if (dir->u.umsdos_i.dir_info.looking < 0) {		printk ("UMSDOS: dir->u.umsdos_i.dir_info.looking < 0: %d"			,dir->u.umsdos_i.dir_info.looking);	}    	u_wake_up (dir);}#elsestatic void umsdos_lockcreate (struct inode *dir){}static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}void umsdos_startlookup (struct inode *dir){}static void umsdos_unlockcreate (struct inode *dir){}void umsdos_endlookup (struct inode *dir){}#endifstatic int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,				int errcod){	int ret = 0;	if (umsdos_is_pseudodos (dir, dentry)) {		/* #Specification: pseudo root / any file creation /DOS		 * The pseudo sub-directory /DOS can't be created!		 * EEXIST is returned.		 * 		 * The pseudo sub-directory /DOS can't be removed!		 * EPERM is returned.		 */		ret = errcod;	}	return ret;}/* * Add a new file (ordinary or special) into the alternate directory. * The file is added to the real MSDOS directory. If successful, it * is then added to the EMD file. *  * Return the status of the operation. 0 mean success. * * #Specification: create / file exists in DOS * Here is a situation: we are trying to create a file with * UMSDOS. The file is unknown to UMSDOS but already * exists in the DOS directory. *  * Here is what we are NOT doing: *  * We could silently assume that everything is fine * and allows the creation to succeed. *  * It is possible not all files in the partition * are meant to be visible from linux. By trying to create * those file in some directory, one user may get access * to those file without proper permissions. Looks like * a security hole to me. Off course sharing a file system * with DOS is some kind of security hole :-) *  * So ? *  * We return EEXIST in this case. * The same is true for directory creation. */static int umsdos_create_any (struct inode *dir, struct dentry *dentry,				int mode, int rdev, char flags){	struct dentry *fake;	struct inode *inode;	int ret;	struct umsdos_info info;	ret = umsdos_nevercreat (dir, dentry, -EEXIST);	if (ret)		goto out;	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);	if (ret)		goto out;	info.entry.mode = mode;	info.entry.rdev = rdev;	info.entry.flags = flags;	info.entry.uid = current->fsuid;	info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;	info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;	info.entry.nlink = 1;	ret = umsdos_newentry (dentry->d_parent, &info);	if (ret)		goto out;	/* do a real lookup to get the short name dentry */	fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);	ret = PTR_ERR(fake);	if (IS_ERR(fake))		goto out_remove;	/* should not exist yet ... */	ret = -EEXIST;	if (fake->d_inode)		goto out_remove_dput;	ret = msdos_create (dir, fake, S_IFREG | 0777);	if (ret)		goto out_remove_dput;	inode = fake->d_inode;	atomic_inc(&inode->i_count);	d_instantiate (dentry, inode);	dput(fake);	if (atomic_read(&inode->i_count) > 1) {		printk(KERN_WARNING			"umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n",			dentry->d_parent->d_name.name, dentry->d_name.name,			inode->i_ino, atomic_read(&inode->i_count));	}	umsdos_lookup_patch_new(dentry, &info);out:	return ret;	/* Creation failed ... remove the EMD entry */out_remove_dput:	dput(fake);out_remove:	if (ret == -EEXIST)		printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",			dentry->d_parent->d_name.name, info.fake.fname);	umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));	goto out;}/* * Add a new file into the alternate directory. * The file is added to the real MSDOS directory. If successful, it * is then added to the EMD file. *  * Return the status of the operation. 0 mean success. */int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode){	return umsdos_create_any (dir, dentry, mode, 0, 0);}/* * Initialise the new_entry from the old for a rename operation. * (Only useful for umsdos_rename_f() below). */static void umsdos_ren_init (struct umsdos_info *new_info,			     struct umsdos_info *old_info){	new_info->entry.mode = old_info->entry.mode;	new_info->entry.rdev = old_info->entry.rdev;	new_info->entry.uid = old_info->entry.uid;	new_info->entry.gid = old_info->entry.gid;	new_info->entry.ctime = old_info->entry.ctime;	new_info->entry.atime = old_info->entry.atime;	new_info->entry.mtime = old_info->entry.mtime;	new_info->entry.flags = old_info->entry.flags;	new_info->entry.nlink = old_info->entry.nlink;}/* * Rename a file (move) in the file system. */ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,			    struct inode *new_dir, struct dentry *new_dentry,			    int flags){	struct inode *old_inode = old_dentry->d_inode;	struct dentry *old, *new, *old_emd;	int err, ret;	struct umsdos_info old_info;	struct umsdos_info new_info; 	ret = -EPERM;	err = umsdos_parse (old_dentry->d_name.name,				old_dentry->d_name.len, &old_info);	if (err)		goto out;	err = umsdos_parse (new_dentry->d_name.name,				new_dentry->d_name.len, &new_info);	if (err)		goto out;	/* Get the EMD dentry for the old parent */	old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);	ret = PTR_ERR(old_emd);	if (IS_ERR(old_emd))		goto out;	umsdos_lockcreate2 (old_dir, new_dir);	ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);	if (ret)		goto out_unlock;	err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);	if (err == 0) {		/* check whether it _really_ exists ... */		ret = -EEXIST;		if (new_dentry->d_inode)			goto out_unlock;		/* bogus lookup? complain and fix up the EMD ... */		printk(KERN_WARNING			"umsdos_rename_f: entry %s/%s exists, inode NULL??\n",			new_dentry->d_parent->d_name.name, new_info.entry.name);		err = umsdos_delentry(new_dentry->d_parent, &new_info,					S_ISDIR(new_info.entry.mode));	}	umsdos_ren_init (&new_info, &old_info);	if (flags)		new_info.entry.flags = flags;	ret = umsdos_newentry (new_dentry->d_parent, &new_info);	if (ret)		goto out_unlock;	/* If we're moving a hardlink, drop it first */	if (old_info.entry.flags & UMSDOS_HLINK) {		d_drop(old_dentry);	}	old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname, 					old_info.fake.len);	ret = PTR_ERR(old);	if (IS_ERR(old))		goto out_unlock;	/* make sure it's the same inode! */	ret = -ENOENT;	/*	 * note: for hardlinks they will be different!	 *  old_inode will contain inode of .LINKxxx file containing data, and	 *  old->d_inode will contain inode of file containing path to .LINKxxx file	 */	if (!(old_info.entry.flags & UMSDOS_HLINK)) {	 	if (old->d_inode != old_inode) 			goto out_dput;	}	new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, 					new_info.fake.len);	ret = PTR_ERR(new);	if (IS_ERR(new))		goto out_dput;	/* Do the msdos-level rename */	ret = msdos_rename (old_dir, old, new_dir, new);	dput(new);	/* If the rename failed, remove the new EMD entry */	if (ret != 0) {		umsdos_delentry (new_dentry->d_parent, &new_info,				 S_ISDIR (new_info.entry.mode));		goto out_dput;	}	/*	 * Rename successful ... remove the old name from the EMD.	 * Note that we use the EMD parent here, as the old dentry	 * may have moved to a new parent ...	 */	err = umsdos_delentry (old_emd->d_parent, &old_info,				S_ISDIR (old_info.entry.mode));	if (err) {		/* Failed? Complain a bit, but don't fail the operation */		printk(KERN_WARNING 			"umsdos_rename_f: delentry %s/%s failed, error=%d\n",			old_emd->d_parent->d_name.name, old_info.entry.name,			err);	}	/*	 * Update f_pos so notify_change will succeed	 * if the file was already in use.	 */	umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);	/* dput() the dentry if we haven't already */out_dput:	dput(old);out_unlock:	dput(old_emd);	umsdos_unlockcreate (old_dir);	umsdos_unlockcreate (new_dir);out:	Printk ((" _ret=%d\n", ret));	return ret;}/* * Setup a Symbolic link or a (pseudo) hard link * Return a negative error code or 0 if OK. *//* #Specification: symbolic links / strategy * A symbolic link is simply a file which holds a path. It is * implemented as a normal MSDOS file (not very space efficient :-() *  * I see two different ways to do this: One is to place the link data * in unused entries of the EMD file; the other is to have a separate * file dedicated to hold all symbolic links data. *  * Let's go for simplicity... *//* * AV. Should be called with dir->i_sem down. */static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,			const char *symname, int mode, char flags){	int ret, len;	ret = umsdos_create_any (dir, dentry, mode, 0, flags);	if (ret) {		printk(KERN_WARNING			"umsdos_symlink: create failed, ret=%d\n", ret);		goto out;	}	len = strlen (symname) + 1;	ret = block_symlink(dentry->d_inode, symname, len);	if (ret < 0)		goto out_unlink;out:	return ret;out_unlink:	printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");	UMSDOS_unlink (dir, dentry);	d_drop(dentry);	goto out;}/* * Setup a Symbolic link. * Return a negative error code or 0 if OK. */int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,		 const char *symname){	return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);}/* * Add a link to an inode in a directory */int UMSDOS_link (struct dentry *olddentry, struct inode *dir,		 struct dentry *dentry){	struct inode *oldinode = olddentry->d_inode;	struct inode *olddir = olddentry->d_parent->d_inode;	struct dentry *temp;	char *path;	unsigned long buffer;	int ret;	struct umsdos_info old_info;	struct umsdos_info hid_info;#ifdef UMSDOS_DEBUG_VERBOSEprintk("umsdos_link: new %s/%s -> %s/%s\n",dentry->d_parent->d_name.name, dentry->d_name.name, olddentry->d_parent->d_name.name, olddentry->d_name.name);#endif 	ret = -EPERM;	if (S_ISDIR (oldinode->i_mode))		goto out;	ret = umsdos_nevercreat (dir, dentry, -EPERM);	if (ret)		goto out;	ret = -ENOMEM;	buffer = get_free_page(GFP_KERNEL);	if (!buffer)		goto out;	/*	 * Lock the link parent if it's not the same directory.	 */	ret = -EDEADLOCK;	if (olddir != dir) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -