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

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  dir.c * *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke *  Copyright (C) 1997 by Volker Lendecke * *  Please add a note about your changes to smbfs in the ChangeLog file. */#include <linux/time.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/smp_lock.h>#include <linux/ctype.h>#include <linux/net.h>#include <linux/sched.h>#include <linux/smb_fs.h>#include <linux/smb_mount.h>#include <linux/smbno.h>#include "smb_debug.h"#include "proto.h"static int smb_readdir(struct file *, void *, filldir_t);static int smb_dir_open(struct inode *, struct file *);static struct dentry *smb_lookup(struct inode *, struct dentry *, struct nameidata *);static int smb_create(struct inode *, struct dentry *, int, struct nameidata *);static int smb_mkdir(struct inode *, struct dentry *, int);static int smb_rmdir(struct inode *, struct dentry *);static int smb_unlink(struct inode *, struct dentry *);static int smb_rename(struct inode *, struct dentry *,		      struct inode *, struct dentry *);static int smb_make_node(struct inode *,struct dentry *,int,dev_t);static int smb_link(struct dentry *, struct inode *, struct dentry *);const struct file_operations smb_dir_operations ={	.read		= generic_read_dir,	.readdir	= smb_readdir,	.ioctl		= smb_ioctl,	.open		= smb_dir_open,};const struct inode_operations smb_dir_inode_operations ={	.create		= smb_create,	.lookup		= smb_lookup,	.unlink		= smb_unlink,	.mkdir		= smb_mkdir,	.rmdir		= smb_rmdir,	.rename		= smb_rename,	.getattr	= smb_getattr,	.setattr	= smb_notify_change,};const struct inode_operations smb_dir_inode_operations_unix ={	.create		= smb_create,	.lookup		= smb_lookup,	.unlink		= smb_unlink,	.mkdir		= smb_mkdir,	.rmdir		= smb_rmdir,	.rename		= smb_rename,	.getattr	= smb_getattr,	.setattr	= smb_notify_change,	.symlink	= smb_symlink,	.mknod		= smb_make_node,	.link		= smb_link,};/* * Read a directory, using filldir to fill the dirent memory. * smb_proc_readdir does the actual reading from the smb server. * * The cache code is almost directly taken from ncpfs */static int smb_readdir(struct file *filp, void *dirent, filldir_t filldir){	struct dentry *dentry = filp->f_path.dentry;	struct inode *dir = dentry->d_inode;	struct smb_sb_info *server = server_from_dentry(dentry);	union  smb_dir_cache *cache = NULL;	struct smb_cache_control ctl;	struct page *page = NULL;	int result;	ctl.page  = NULL;	ctl.cache = NULL;	VERBOSE("reading %s/%s, f_pos=%d\n",		DENTRY_PATH(dentry),  (int) filp->f_pos);	result = 0;	lock_kernel();	switch ((unsigned int) filp->f_pos) {	case 0:		if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)			goto out;		filp->f_pos = 1;		/* fallthrough */	case 1:		if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR) < 0)			goto out;		filp->f_pos = 2;	}	/*	 * Make sure our inode is up-to-date.	 */	result = smb_revalidate_inode(dentry);	if (result)		goto out;	page = grab_cache_page(&dir->i_data, 0);	if (!page)		goto read_really;	ctl.cache = cache = kmap(page);	ctl.head  = cache->head;	if (!PageUptodate(page) || !ctl.head.eof) {		VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",			 DENTRY_PATH(dentry), PageUptodate(page),ctl.head.eof);		goto init_cache;	}	if (filp->f_pos == 2) {		if (jiffies - ctl.head.time >= SMB_MAX_AGE(server))			goto init_cache;		/*		 * N.B. ncpfs checks mtime of dentry too here, we don't.		 *   1. common smb servers do not update mtime on dir changes		 *   2. it requires an extra smb request		 *      (revalidate has the same timeout as ctl.head.time)		 *		 * Instead smbfs invalidates its own cache on local changes		 * and remote changes are not seen until timeout.		 */	}	if (filp->f_pos > ctl.head.end)		goto finished;	ctl.fpos = filp->f_pos + (SMB_DIRCACHE_START - 2);	ctl.ofs  = ctl.fpos / SMB_DIRCACHE_SIZE;	ctl.idx  = ctl.fpos % SMB_DIRCACHE_SIZE;	for (;;) {		if (ctl.ofs != 0) {			ctl.page = find_lock_page(&dir->i_data, ctl.ofs);			if (!ctl.page)				goto invalid_cache;			ctl.cache = kmap(ctl.page);			if (!PageUptodate(ctl.page))				goto invalid_cache;		}		while (ctl.idx < SMB_DIRCACHE_SIZE) {			struct dentry *dent;			int res;			dent = smb_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);			unlock_page(ctl.page);			page_cache_release(ctl.page);			ctl.page = NULL;		}		ctl.idx  = 0;		ctl.ofs += 1;	}invalid_cache:	if (ctl.page) {		kunmap(ctl.page);		unlock_page(ctl.page);		page_cache_release(ctl.page);		ctl.page = NULL;	}	ctl.cache = cache;init_cache:	smb_invalidate_dircache_entries(dentry);	ctl.head.time = jiffies;	ctl.head.eof = 0;	ctl.fpos = 2;	ctl.ofs = 0;	ctl.idx = SMB_DIRCACHE_START;	ctl.filled = 0;	ctl.valid  = 1;read_really:	result = server->ops->readdir(filp, dirent, filldir, &ctl);	if (result == -ERESTARTSYS && page)		ClearPageUptodate(page);	if (ctl.idx == -1)		goto invalid_cache;	/* retry */	ctl.head.end = ctl.fpos - 1;	ctl.head.eof = ctl.valid;finished:	if (page) {		cache->head = ctl.head;		kunmap(page);		if (result != -ERESTARTSYS)			SetPageUptodate(page);		unlock_page(page);		page_cache_release(page);	}	if (ctl.page) {		kunmap(ctl.page);		SetPageUptodate(ctl.page);		unlock_page(ctl.page);		page_cache_release(ctl.page);	}out:	unlock_kernel();	return result;}static intsmb_dir_open(struct inode *dir, struct file *file){	struct dentry *dentry = file->f_path.dentry;	struct smb_sb_info *server;	int error = 0;	VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,		file->f_path.dentry->d_name.name);	/*	 * Directory timestamps in the core protocol aren't updated	 * when a file is added, so we give them a very short TTL.	 */	lock_kernel();	server = server_from_dentry(dentry);	if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) {		unsigned long age = jiffies - SMB_I(dir)->oldmtime;		if (age > 2*HZ)			smb_invalid_dir_cache(dir);	}	/*	 * Note: in order to allow the smbmount process to open the	 * mount point, we only revalidate if the connection is valid or	 * if the process is trying to access something other than the root.	 */	if (server->state == CONN_VALID || !IS_ROOT(dentry))		error = smb_revalidate_inode(dentry);	unlock_kernel();	return error;}/* * Dentry operations routines */static int smb_lookup_validate(struct dentry *, struct nameidata *);static int smb_hash_dentry(struct dentry *, struct qstr *);static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);static int smb_delete_dentry(struct dentry *);static struct dentry_operations smbfs_dentry_operations ={	.d_revalidate	= smb_lookup_validate,	.d_hash		= smb_hash_dentry,	.d_compare	= smb_compare_dentry,	.d_delete	= smb_delete_dentry,};static struct dentry_operations smbfs_dentry_operations_case ={	.d_revalidate	= smb_lookup_validate,	.d_delete	= smb_delete_dentry,};/* * This is the callback when the dcache has a lookup hit. */static intsmb_lookup_validate(struct dentry * dentry, struct nameidata *nd){	struct smb_sb_info *server = server_from_dentry(dentry);	struct inode * inode = dentry->d_inode;	unsigned long age = jiffies - dentry->d_time;	int valid;	/*	 * The default validation is based on dentry age:	 * we believe in dentries for a few seconds.  (But each	 * successful server lookup renews the timestamp.)	 */	valid = (age <= SMB_MAX_AGE(server));#ifdef SMBFS_DEBUG_VERBOSE	if (!valid)		VERBOSE("%s/%s not valid, age=%lu\n", 			DENTRY_PATH(dentry), age);#endif	if (inode) {		lock_kernel();		if (is_bad_inode(inode)) {			PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));			valid = 0;		} else if (!valid)			valid = (smb_revalidate_inode(dentry) == 0);		unlock_kernel();	} else {		/*		 * What should we do for negative dentries?		 */	}	return valid;}static int smb_hash_dentry(struct dentry *dir, struct qstr *this){	unsigned long hash;	int i;	hash = init_name_hash();	for (i=0; i < this->len ; i++)		hash = partial_name_hash(tolower(this->name[i]), hash);	this->hash = end_name_hash(hash);  	return 0;}static intsmb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b){	int i, result = 1;

⌨️ 快捷键说明

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