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

📄 dir.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  dir.c * *  Copyright (C) 1995, 1996 by Volker Lendecke *  Modified for big endian by J.F. Chadima and David S. Miller *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache *  Modified 1998, 1999 Wolfram Pienkoss for NLS *  Modified 1999 Wolfram Pienkoss for directory caching * */#include <linux/config.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/mm.h>#include <asm/uaccess.h>#include <asm/byteorder.h>#include <linux/locks.h>#include <linux/smp_lock.h>#include <linux/ncp_fs.h>#include "ncplib_kernel.h"static void ncp_read_volume_list(struct file *, void *, filldir_t,				struct ncp_cache_control *);static void ncp_do_readdir(struct file *, void *, filldir_t,				struct ncp_cache_control *);static int ncp_readdir(struct file *, void *, filldir_t);static int ncp_create(struct inode *, struct dentry *, int);static struct dentry *ncp_lookup(struct inode *, struct dentry *);static int ncp_unlink(struct inode *, struct dentry *);static int ncp_mkdir(struct inode *, struct dentry *, int);static int ncp_rmdir(struct inode *, struct dentry *);static int ncp_rename(struct inode *, struct dentry *,	  	      struct inode *, struct dentry *);#ifdef CONFIG_NCPFS_EXTRASextern int ncp_symlink(struct inode *, struct dentry *, const char *);#endif		      struct file_operations ncp_dir_operations ={	read:		generic_read_dir,	readdir:	ncp_readdir,	ioctl:		ncp_ioctl,};struct inode_operations ncp_dir_inode_operations ={	create:		ncp_create,	lookup:		ncp_lookup,	unlink:		ncp_unlink,#ifdef CONFIG_NCPFS_EXTRAS	symlink:	ncp_symlink,#endif	mkdir:		ncp_mkdir,	rmdir:		ncp_rmdir,	rename:		ncp_rename,	setattr:	ncp_notify_change,};/* * Dentry operations routines */static int ncp_lookup_validate(struct dentry *, int);static int ncp_hash_dentry(struct dentry *, struct qstr *);static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);static int ncp_delete_dentry(struct dentry *);struct dentry_operations ncp_dentry_operations ={	d_revalidate:	ncp_lookup_validate,	d_hash:		ncp_hash_dentry,	d_compare:	ncp_compare_dentry,	d_delete:	ncp_delete_dentry,};/* * Note: leave the hash unchanged if the directory * is case-sensitive. */static int ncp_hash_dentry(struct dentry *dentry, struct qstr *this){	struct nls_table *t;	unsigned long hash;	int i;	t = NCP_IO_TABLE(dentry);	if (!ncp_case_sensitive(dentry->d_inode)) {		hash = init_name_hash();		for (i=0; i<this->len ; i++)			hash = partial_name_hash(ncp_tolower(t, this->name[i]),									hash);		this->hash = end_name_hash(hash);	}	return 0;}static intncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b){	if (a->len != b->len)		return 1;	if (ncp_case_sensitive(dentry->d_inode))		return strncmp(a->name, b->name, a->len);	return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len);}/* * This is the callback from dput() when d_count is going to 0. * We use this to unhash dentries with bad inodes. * Closing files can be safely postponed until iput() - it's done there anyway. */static intncp_delete_dentry(struct dentry * dentry){	struct inode *inode = dentry->d_inode;	if (inode) {		if (is_bad_inode(inode))			return 1;	} else	{	/* N.B. Unhash negative dentries? */	}	return 0;}static inline intncp_single_volume(struct ncp_server *server){	return (server->m.mounted_vol[0] != '\0');}static inline int ncp_is_server_root(struct inode *inode){	return (!ncp_single_volume(NCP_SERVER(inode)) &&		inode == inode->i_sb->s_root->d_inode);}/* * This is the callback when the dcache has a lookup hit. */#ifdef CONFIG_NCPFS_STRONG/* try to delete a readonly file (NW R bit set) */static intncp_force_unlink(struct inode *dir, struct dentry* dentry){        int res=0x9c,res2;	struct nw_modify_dos_info info;	__u32 old_nwattr;	struct inode *inode;	memset(&info, 0, sizeof(info));	        /* remove the Read-Only flag on the NW server */	inode = dentry->d_inode;	old_nwattr = NCP_FINFO(inode)->nwattr;	info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);	res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);	if (res2)		goto leave_me;        /* now try again the delete operation */        res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);        if (res)  /* delete failed, set R bit again */        {		info.attributes = old_nwattr;		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);		if (res2)                        goto leave_me;        }leave_me:        return(res);}#endif	/* CONFIG_NCPFS_STRONG */#ifdef CONFIG_NCPFS_STRONGstatic intncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,                 struct inode *new_dir, struct dentry* new_dentry, char *_new_name){	struct nw_modify_dos_info info;        int res=0x90,res2;	struct inode *old_inode = old_dentry->d_inode;	__u32 old_nwattr = NCP_FINFO(old_inode)->nwattr;	__u32 new_nwattr = 0; /* shut compiler warning */	int old_nwattr_changed = 0;	int new_nwattr_changed = 0;	memset(&info, 0, sizeof(info));	        /* remove the Read-Only flag on the NW server */	info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);	res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);	if (!res2)		old_nwattr_changed = 1;	if (new_dentry && new_dentry->d_inode) {		new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;		info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);		if (!res2)			new_nwattr_changed = 1;	}        /* now try again the rename operation */	/* but only if something really happened */	if (new_nwattr_changed || old_nwattr_changed) {	        res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),        	                                    old_dir, _old_name,                	                            new_dir, _new_name);	} 	if (res)		goto leave_me;	/* file was successfully renamed, so:	   do not set attributes on old file - it no longer exists	   copy attributes from old file to new */	new_nwattr_changed = old_nwattr_changed;	new_nwattr = old_nwattr;	old_nwattr_changed = 0;	leave_me:;	if (old_nwattr_changed) {		info.attributes = old_nwattr;		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);		/* ignore errors */	}	if (new_nwattr_changed)	{		info.attributes = new_nwattr;		res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);		/* ignore errors */	}        return(res);}#endif	/* CONFIG_NCPFS_STRONG */static int__ncp_lookup_validate(struct dentry * dentry, int flags){	struct ncp_server *server;	struct inode *dir = dentry->d_parent->d_inode;	struct ncp_entry_info finfo;	int res, val = 0, len = dentry->d_name.len + 1;	__u8 __name[len];	if (!dentry->d_inode || !dir)		goto finished;	server = NCP_SERVER(dir);	if (!ncp_conn_valid(server))		goto finished;	/*	 * Inspired by smbfs:	 * The default validation is based on dentry age:	 * We set the max age at mount time.  (But each	 * successful server lookup renews the timestamp.)	 */	val = NCP_TEST_AGE(server, dentry);	if (val)		goto finished;	DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n",		dentry->d_parent->d_name.name, dentry->d_name.name,		NCP_GET_AGE(dentry));	if (ncp_is_server_root(dir)) {		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,						len-1, 1);		if (!res)			res = ncp_lookup_volume(server, __name, &(finfo.i));	} else {		res = ncp_io2vol(server, __name, &len, dentry->d_name.name,						len-1, !ncp_preserve_case(dir));		if (!res)			res = ncp_obtain_info(server, dir, __name, &(finfo.i));	}	DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n",		dentry->d_parent->d_name.name, __name, res);	/*	 * If we didn't find it, or if it has a different dirEntNum to	 * what we remember, it's not valid any more.	 */	if (!res) {		if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) {			ncp_new_dentry(dentry);			val=1;		} else			DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");		ncp_update_inode2(dentry->d_inode, &finfo);	}finished:	DDPRINTK("ncp_lookup_validate: result=%d\n", val);	return val;}static intncp_lookup_validate(struct dentry * dentry, int flags){	int res;	lock_kernel();	res = __ncp_lookup_validate(dentry, flags);	unlock_kernel();	return res;}static struct dentry *ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos){	struct dentry *dent = dentry;	struct list_head *next;	if (d_validate(dent, parent)) {		if (dent->d_name.len <= NCP_MAXPATHLEN &&		    (unsigned long)dent->d_fsdata == fpos) {			if (!dent->d_inode) {				dput(dent);				dent = NULL;			}			return dent;		}		dput(dent);	}	/* If a pointer is invalid, we search the dentry. */	spin_lock(&dcache_lock);	next = parent->d_subdirs.next;	while (next != &parent->d_subdirs) {		dent = list_entry(next, struct dentry, d_child);		if ((unsigned long)dent->d_fsdata == fpos) {			if (dent->d_inode)				dget_locked(dent);			else				dent = NULL;			spin_unlock(&dcache_lock);			goto out;		}		next = next->next;	}	spin_unlock(&dcache_lock);	return NULL;out:	return dent;}static time_t ncp_obtain_mtime(struct dentry *dentry){	struct inode *inode = dentry->d_inode;	struct ncp_server *server = NCP_SERVER(inode);	struct nw_info_struct i;	if (!ncp_conn_valid(server) || ncp_is_server_root(inode))		return 0;	if (ncp_obtain_info(server, inode, NULL, &i))		return 0;	return ncp_date_dos2unix(le16_to_cpu(i.modifyTime),						le16_to_cpu(i.modifyDate));}static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir){	struct dentry *dentry = filp->f_dentry;	struct inode *inode = dentry->d_inode;	struct page *page = NULL;	struct ncp_server *server = NCP_SERVER(inode);	union  ncp_dir_cache *cache = NULL;	struct ncp_cache_control ctl;	int result, mtime_valid = 0;	time_t mtime = 0;	ctl.page  = NULL;	ctl.cache = NULL;	DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n",		dentry->d_parent->d_name.name, dentry->d_name.name,		(int) filp->f_pos);	result = -EIO;	if (!ncp_conn_valid(server))		goto out;	result = 0;	if (filp->f_pos == 0) {		if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))			goto out;		filp->f_pos = 1;	}	if (filp->f_pos == 1) {		if (filldir(dirent, "..", 2, 1,				dentry->d_parent->d_inode->i_ino, DT_DIR))			goto out;		filp->f_pos = 2;	}	page = grab_cache_page(&inode->i_data, 0);	if (!page)		goto read_really;	ctl.cache = cache = kmap(page);	ctl.head  = cache->head;	if (!Page_Uptodate(page) || !ctl.head.eof)		goto init_cache;	if (filp->f_pos == 2) {		if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))			goto init_cache;		mtime = ncp_obtain_mtime(dentry);		mtime_valid = 1;		if ((!mtime) || (mtime != ctl.head.mtime))			goto init_cache;	}	if (filp->f_pos > ctl.head.end)		goto finished;	ctl.fpos = filp->f_pos + (NCP_DIRCACHE_START - 2);	ctl.ofs  = ctl.fpos / NCP_DIRCACHE_SIZE;	ctl.idx  = ctl.fpos % NCP_DIRCACHE_SIZE;	for (;;) {		if (ctl.ofs != 0) {			ctl.page = find_lock_page(&inode->i_data, ctl.ofs);			if (!ctl.page)				goto invalid_cache;			ctl.cache = kmap(ctl.page);			if (!Page_Uptodate(ctl.page))				goto invalid_cache;		}		while (ctl.idx < NCP_DIRCACHE_SIZE) {			struct dentry *dent;			int res;			dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],						dentry, filp->f_pos);			if (!dent)				goto invalid_cache;			res = filldir(dirent, dent->d_name.name,					dent->d_name.len, filp->f_pos,					dent->d_inode->i_ino, DT_UNKNOWN);			dput(dent);			if (res)				goto finished;			filp->f_pos += 1;			ctl.idx += 1;			if (filp->f_pos > ctl.head.end)				goto finished;		}		if (ctl.page) {			kunmap(ctl.page);			SetPageUptodate(ctl.page);			UnlockPage(ctl.page);			page_cache_release(ctl.page);			ctl.page = NULL;		}		ctl.idx  = 0;		ctl.ofs += 1;	}invalid_cache:	if (ctl.page) {		kunmap(ctl.page);		UnlockPage(ctl.page);		page_cache_release(ctl.page);		ctl.page = NULL;	}	ctl.cache = cache;init_cache:	ncp_invalidate_dircache_entries(dentry);	if (!mtime_valid) {		mtime = ncp_obtain_mtime(dentry);		mtime_valid = 1;	}	ctl.head.mtime = mtime;	ctl.head.time = jiffies;	ctl.head.eof = 0;	ctl.fpos = 2;	ctl.ofs = 0;	ctl.idx = NCP_DIRCACHE_START;	ctl.filled = 0;	ctl.valid  = 1;read_really:	if (ncp_is_server_root(inode)) {		ncp_read_volume_list(filp, dirent, filldir, &ctl);	} else {		ncp_do_readdir(filp, dirent, filldir, &ctl);	}	ctl.head.end = ctl.fpos - 1;	ctl.head.eof = ctl.valid;finished:	if (page) {		cache->head = ctl.head;		kunmap(page);		SetPageUptodate(page);		UnlockPage(page);		page_cache_release(page);	}	if (ctl.page) {		kunmap(ctl.page);		SetPageUptodate(ctl.page);		UnlockPage(ctl.page);		page_cache_release(ctl.page);	}out:	return result;}static intncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,		struct ncp_cache_control *ctrl, struct ncp_entry_info *entry){	struct dentry *newdent, *dentry = filp->f_dentry;	struct inode *newino, *inode = dentry->d_inode;	struct ncp_cache_control ctl = *ctrl;	struct qstr qname;	int valid = 0;	int hashed = 0;	ino_t ino = 0;	__u8 __name[256];	qname.len = 256;	if (ncp_vol2io(NCP_SERVER(inode), __name, &qname.len,			entry->i.entryName, entry->i.nameLen,			!ncp_preserve_entry_case(inode, entry->i.NSCreator)))		return 1; /* I'm not sure */	qname.name = __name;	qname.hash = full_name_hash(qname.name, qname.len);	if (dentry->d_op && dentry->d_op->d_hash)		if (dentry->d_op->d_hash(dentry, &qname) != 0)			goto end_advance;	newdent = d_lookup(dentry, &qname);	if (!newdent) {		newdent = d_alloc(dentry, &qname);		if (!newdent)			goto end_advance;	} else {		hashed = 1;		memcpy((char *) newdent->d_name.name, qname.name,							newdent->d_name.len);	}

⌨️ 快捷键说明

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