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

📄 inode.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   fs/cifs/inode.c * *   Copyright (C) International Business Machines  Corp., 2002,2003 *   Author(s): Steve French (sfrench@us.ibm.com) * *   This library is free software; you can redistribute it and/or modify *   it under the terms of the GNU Lesser General Public License as published *   by the Free Software Foundation; either version 2.1 of the License, or *   (at your option) any later version. * *   This library 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 Lesser General Public License for more details. * *   You should have received a copy of the GNU Lesser General Public License *   along with this library; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/fs.h>#include <linux/buffer_head.h>#include <linux/stat.h>#include <linux/pagemap.h>#include <asm/div64.h>#include "cifsfs.h"#include "cifspdu.h"#include "cifsglob.h"#include "cifsproto.h"#include "cifs_debug.h"#include "cifs_fs_sb.h"extern int is_size_safe_to_change(struct cifsInodeInfo *);intcifs_get_inode_info_unix(struct inode **pinode,			 const unsigned char *search_path,			 struct super_block *sb,int xid){	int rc = 0;	FILE_UNIX_BASIC_INFO findData;	struct cifsTconInfo *pTcon;	struct inode *inode;	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);	char *tmp_path;	pTcon = cifs_sb->tcon;	cFYI(1, (" Getting info on %s ", search_path));	/* we could have done a find first instead but this returns more info */	rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,				  cifs_sb->local_nls);	/* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */	if (rc) {		if (rc == -EREMOTE) {			tmp_path =			    kmalloc(strnlen				    (pTcon->treeName,				     MAX_TREE_SIZE + 1) +				    strnlen(search_path, MAX_PATHCONF) + 1,				    GFP_KERNEL);			if (tmp_path == NULL) {				return -ENOMEM;			}        /* have to skip first of the double backslash of UNC name */			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);				strncat(tmp_path, search_path, MAX_PATHCONF);			rc = connect_to_dfs_path(xid, pTcon->ses,						 /* treename + */ tmp_path,						 cifs_sb->local_nls);			kfree(tmp_path);			/* BB fix up inode etc. */		} else if (rc) {			return rc;		}	} else {		struct cifsInodeInfo *cifsInfo;		__u32 type = le32_to_cpu(findData.Type);		__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);		__u64 end_of_file = le64_to_cpu(findData.EndOfFile);		/* get new inode */		if (*pinode == NULL) {			*pinode = new_inode(sb);			if(*pinode == NULL) 				return -ENOMEM;			insert_inode_hash(*pinode);		}					inode = *pinode;		cifsInfo = CIFS_I(inode);		cFYI(1, (" Old time %ld ", cifsInfo->time));		cifsInfo->time = jiffies;		cFYI(1, (" New time %ld ", cifsInfo->time));		atomic_set(&cifsInfo->inUse,1);	/* ok to set on every refresh of inode */		inode->i_atime =		    cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));		inode->i_mtime =		    cifs_NTtimeToUnix(le64_to_cpu				(findData.LastModificationTime));		inode->i_ctime =		    cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));		inode->i_mode = le64_to_cpu(findData.Permissions);		if (type == UNIX_FILE) {			inode->i_mode |= S_IFREG;		} else if (type == UNIX_SYMLINK) {			inode->i_mode |= S_IFLNK;		} else if (type == UNIX_DIR) {			inode->i_mode |= S_IFDIR;		} else if (type == UNIX_CHARDEV) {			inode->i_mode |= S_IFCHR;			inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),				le64_to_cpu(findData.DevMinor) & MINORMASK);		} else if (type == UNIX_BLOCKDEV) {			inode->i_mode |= S_IFBLK;			inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),				le64_to_cpu(findData.DevMinor) & MINORMASK);		} else if (type == UNIX_FIFO) {			inode->i_mode |= S_IFIFO;		} else if (type == UNIX_SOCKET) {			inode->i_mode |= S_IFSOCK;		}		inode->i_uid = le64_to_cpu(findData.Uid);		inode->i_gid = le64_to_cpu(findData.Gid);		inode->i_nlink = le64_to_cpu(findData.Nlinks);		if(is_size_safe_to_change(cifsInfo)) {		/* can not safely change the file size here if the 		   client is writing to it due to potential races */			i_size_write(inode, end_of_file);/* blksize needs to be multiple of two. So safer to default to blksize	and blkbits set in superblock so 2**blkbits and blksize will match *//*		inode->i_blksize =		    (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/		/* This seems incredibly stupid but it turns out that		i_blocks is not related to (i_size / i_blksize), instead a		size of 512 is required to be used for calculating num blocks */		 /*		inode->i_blocks = 	                (inode->i_blksize - 1 + num_of_bytes) >> inode->i_blkbits;*/		/* 512 bytes (2**9) is the fake blocksize that must be used */		/* for this calculation */			inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;		}		if (num_of_bytes < end_of_file)			cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));		cFYI(1,		     ("Size %ld and blocks %ld ",		      (unsigned long) inode->i_size, inode->i_blocks));		if (S_ISREG(inode->i_mode)) {			cFYI(1, (" File inode "));			inode->i_op = &cifs_file_inode_ops;			inode->i_fop = &cifs_file_ops;			inode->i_data.a_ops = &cifs_addr_ops;		} else if (S_ISDIR(inode->i_mode)) {			cFYI(1, (" Directory inode"));			inode->i_op = &cifs_dir_inode_ops;			inode->i_fop = &cifs_dir_ops;		} else if (S_ISLNK(inode->i_mode)) {			cFYI(1, (" Symbolic Link inode "));			inode->i_op = &cifs_symlink_inode_ops;/* tmp_inode->i_fop = *//* do not need to set to anything */		} else {			cFYI(1, (" Init special inode "));			init_special_inode(inode, inode->i_mode,					   inode->i_rdev);		}	}	return rc;}intcifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, 		FILE_ALL_INFO * pfindData, struct super_block *sb, int xid){	int rc = 0;	struct cifsTconInfo *pTcon;	struct inode *inode;	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);	char *tmp_path;	char *buf = NULL;	pTcon = cifs_sb->tcon;	cFYI(1,("Getting info on %s ", search_path));	if((pfindData == NULL) && (*pinode != NULL)) {		if(CIFS_I(*pinode)->clientCanCacheRead) {			cFYI(1,("No need to revalidate inode sizes on cached file "));			return rc;		}	}	/* if file info not passed in then get it from server */	if(pfindData == NULL) {		buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);		if(buf == NULL)			return -ENOMEM;		pfindData = (FILE_ALL_INFO *)buf;	/* could do find first instead but this returns more info */		rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,			      cifs_sb->local_nls);	}	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */	if (rc) {		if (rc == -EREMOTE) {			tmp_path =			    kmalloc(strnlen				    (pTcon->treeName,				     MAX_TREE_SIZE + 1) +				    strnlen(search_path, MAX_PATHCONF) + 1,				    GFP_KERNEL);			if (tmp_path == NULL) {				if(buf)					kfree(buf);				return -ENOMEM;			}			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);			strncat(tmp_path, search_path, MAX_PATHCONF);			rc = connect_to_dfs_path(xid, pTcon->ses,						 /* treename + */ tmp_path,						 cifs_sb->local_nls);			kfree(tmp_path);			/* BB fix up inode etc. */		} else if (rc) {			if(buf)				kfree(buf);			return rc;		}	} else {		struct cifsInodeInfo *cifsInfo;		__u32 attr = le32_to_cpu(pfindData->Attributes);		/* get new inode */		if (*pinode == NULL) {			*pinode = new_inode(sb);			if(*pinode == NULL)				return -ENOMEM;			insert_inode_hash(*pinode);		}		inode = *pinode;		cifsInfo = CIFS_I(inode);		cifsInfo->cifsAttrs = attr;		cFYI(1, (" Old time %ld ", cifsInfo->time));		cifsInfo->time = jiffies;		cFYI(1, (" New time %ld ", cifsInfo->time));/* blksize needs to be multiple of two. So safer to default to blksize        and blkbits set in superblock so 2**blkbits and blksize will match *//*		inode->i_blksize =		    (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/		/* Linux can not store file creation time unfortunately so we ignore it */		inode->i_atime =		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));		inode->i_mtime =		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));		inode->i_ctime =		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));		cFYI(0,		     (" Attributes came in as 0x%x ", attr));		/* set default mode. will override for dirs below */		if(atomic_read(&cifsInfo->inUse) == 0)			/* new inode, can safely set these fields */			inode->i_mode = cifs_sb->mnt_file_mode;		if (attr & ATTR_REPARSE) {	/* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */			inode->i_mode |= S_IFLNK;		} else if (attr & ATTR_DIRECTORY) {	/* override default perms since we do not do byte range locking on dirs */			inode->i_mode = cifs_sb->mnt_dir_mode;			inode->i_mode |= S_IFDIR;		} else {			inode->i_mode |= S_IFREG;			/* treat the dos attribute of read-only as read-only mode e.g. 555 */			if(cifsInfo->cifsAttrs & ATTR_READONLY)				inode->i_mode &= ~(S_IWUGO);   /* BB add code here - validate if device or weird share or device type? */		}		if(is_size_safe_to_change(cifsInfo)) {		/* can not safely change the file size here if the 		client is writing to it due to potential races */			i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));		/* 512 bytes (2**9) is the fake blocksize that must be used */		/* for this calculation */			inode->i_blocks = (512 - 1 + le64_to_cpu(pfindData->AllocationSize))				 >> 9;		}		inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);		/* BB fill in uid and gid here? with help from winbind? 			or retrieve from NTFS stream extended attribute */		if(atomic_read(&cifsInfo->inUse) == 0) {			inode->i_uid = cifs_sb->mnt_uid;			inode->i_gid = cifs_sb->mnt_gid;			/* set so we do not keep refreshing these fields with			bad data after user has changed them in memory */			atomic_set(&cifsInfo->inUse,1);		}				if (S_ISREG(inode->i_mode)) {			cFYI(1, (" File inode "));			inode->i_op = &cifs_file_inode_ops;			inode->i_fop = &cifs_file_ops;			inode->i_data.a_ops = &cifs_addr_ops;		} else if (S_ISDIR(inode->i_mode)) {			cFYI(1, (" Directory inode "));			inode->i_op = &cifs_dir_inode_ops;			inode->i_fop = &cifs_dir_ops;		} else if (S_ISLNK(inode->i_mode)) {			cFYI(1, (" Symbolic Link inode "));			inode->i_op = &cifs_symlink_inode_ops;		} else {			init_special_inode(inode, inode->i_mode,					   inode->i_rdev);		}	}	if(buf)	    kfree(buf);	return rc;}voidcifs_read_inode(struct inode *inode){				/* gets root inode */	int xid;	struct cifs_sb_info *cifs_sb;	cifs_sb = CIFS_SB(inode->i_sb);	xid = GetXid();	if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)		cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);	else		cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);	/* can not call macro FreeXid here since in a void func */	_FreeXid(xid);}intcifs_unlink(struct inode *inode, struct dentry *direntry){	int rc = 0;	int xid;	struct cifs_sb_info *cifs_sb;	struct cifsTconInfo *pTcon;	char *full_path = NULL;	struct cifsInodeInfo *cifsInode;	FILE_BASIC_INFO * pinfo_buf;	cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));	xid = GetXid();	cifs_sb = CIFS_SB(inode->i_sb);	pTcon = cifs_sb->tcon;/* Unlink can be called from rename so we can not grab	the sem here since we deadlock otherwise *//*	down(&direntry->d_sb->s_vfs_rename_sem);*/	full_path = build_path_from_dentry(direntry);/*	up(&direntry->d_sb->s_vfs_rename_sem);*/	if(full_path == NULL) {		FreeXid(xid);		return -ENOMEM;	}	rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);	if (!rc) {		direntry->d_inode->i_nlink--;	} else if (rc == -ENOENT) {		d_drop(direntry);	} else if (rc == -ETXTBSY) {		int oplock = FALSE;		__u16 netfid;		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, 				CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,				&netfid, &oplock, NULL, cifs_sb->local_nls);		if(rc==0) {			CIFSSMBRenameOpenFile(xid,pTcon,netfid,				NULL, cifs_sb->local_nls);			CIFSSMBClose(xid, pTcon, netfid);			direntry->d_inode->i_nlink--;		}	} else if (rc == -EACCES) {		/* try only if r/o attribute set in local lookup data? */		pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);		if(pinfo_buf) {			memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));        		/* ATTRS set to normal clears r/o bit */			pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);			rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,				cifs_sb->local_nls);			kfree(pinfo_buf);		}		if(rc==0) {			rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);			if (!rc) {				direntry->d_inode->i_nlink--;			} else if (rc == -ETXTBSY) {				int oplock = FALSE;				__u16 netfid;				rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,						CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,						&netfid, &oplock, NULL, cifs_sb->local_nls);				if(rc==0) {					CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);					CIFSSMBClose(xid, pTcon, netfid);		                        direntry->d_inode->i_nlink--;				}			/* BB if rc = -ETXTBUSY goto the rename logic BB */			}		}	}	cifsInode = CIFS_I(direntry->d_inode);	cifsInode->time = 0;	/* will force revalidate to get info when needed */	direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =	    CURRENT_TIME;	cifsInode = CIFS_I(inode);	cifsInode->time = 0;	/* force revalidate of dir as well */	if (full_path)		kfree(full_path);	FreeXid(xid);	return rc;}intcifs_mkdir(struct inode *inode, struct dentry *direntry, int mode){	int rc = 0;	int xid;	struct cifs_sb_info *cifs_sb;	struct cifsTconInfo *pTcon;	char *full_path = NULL;	struct inode *newinode = NULL;	cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));	xid = GetXid();	cifs_sb = CIFS_SB(inode->i_sb);	pTcon = cifs_sb->tcon;	down(&inode->i_sb->s_vfs_rename_sem);	full_path = build_path_from_dentry(direntry);	up(&inode->i_sb->s_vfs_rename_sem);	if(full_path == NULL) {		FreeXid(xid);		return -ENOMEM;	}	/* BB add setting the equivalent of mode via CreateX w/ACLs */	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);	if (rc) {		cFYI(1, ("cifs_mkdir returned 0x%x ", rc));		d_drop(direntry);	} else {		inode->i_nlink++;		if (pTcon->ses->capabilities & CAP_UNIX)			rc = cifs_get_inode_info_unix(&newinode, full_path,						      inode->i_sb,xid);		else			rc = cifs_get_inode_info(&newinode, full_path,NULL,						 inode->i_sb,xid);		direntry->d_op = &cifs_dentry_ops;		d_instantiate(direntry, newinode);		if(direntry->d_inode)			direntry->d_inode->i_nlink = 2;		if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,						(__u64)current->euid,  						(__u64)current->egid,						0 /* dev_t */,						cifs_sb->local_nls);

⌨️ 快捷键说明

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