xfs_dir.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,224 行 · 第 1/3 页

C
1,224
字号
/* * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like.  Any license provided herein, whether implied or * otherwise, applies only to this software file.  Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA  94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */#include "xfs.h"#include "xfs_macros.h"#include "xfs_types.h"#include "xfs_inum.h"#include "xfs_log.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_dir.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_alloc_btree.h"#include "xfs_bmap_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_alloc.h"#include "xfs_btree.h"#include "xfs_attr_sf.h"#include "xfs_dir_sf.h"#include "xfs_dir2_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_bmap.h"#include "xfs_da_btree.h"#include "xfs_dir_leaf.h"#include "xfs_error.h"/* * xfs_dir.c * * Provide the external interfaces to manage directories. *//*======================================================================== * Function prototypes for the kernel. *========================================================================*//* * Functions for the dirops interfaces. */static void	xfs_dir_mount(struct xfs_mount *mp);static int	xfs_dir_isempty(struct xfs_inode *dp);static int	xfs_dir_init(struct xfs_trans *trans,			     struct xfs_inode *dir,			     struct xfs_inode *parent_dir);static int	xfs_dir_createname(struct xfs_trans *trans,				   struct xfs_inode *dp,				   char *name_string,				   int name_len,				   xfs_ino_t inode_number,				   xfs_fsblock_t *firstblock,				   xfs_bmap_free_t *flist,				   xfs_extlen_t total);static int	xfs_dir_lookup(struct xfs_trans *tp,			       struct xfs_inode *dp,			       char *name_string,			       int name_length,			       xfs_ino_t *inode_number);static int	xfs_dir_removename(struct xfs_trans *trans,				   struct xfs_inode *dp,				   char *name_string,				   int name_length,				   xfs_ino_t ino,				   xfs_fsblock_t *firstblock,				   xfs_bmap_free_t *flist,				   xfs_extlen_t total);static int	xfs_dir_getdents(struct xfs_trans *tp,				 struct xfs_inode *dp,				 struct uio *uiop,				 int *eofp);static int	xfs_dir_replace(struct xfs_trans *tp,				struct xfs_inode *dp,				char *name_string,				int name_length,				xfs_ino_t inode_number,				xfs_fsblock_t *firstblock,				xfs_bmap_free_t *flist,				xfs_extlen_t total);static int	xfs_dir_canenter(struct xfs_trans *tp,				 struct xfs_inode *dp,				 char *name_string,				 int name_length);static int	xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp,						  xfs_dinode_t *dip);xfs_dirops_t xfsv1_dirops = {	.xd_mount			= xfs_dir_mount,	.xd_isempty			= xfs_dir_isempty,	.xd_init			= xfs_dir_init,	.xd_createname			= xfs_dir_createname,	.xd_lookup			= xfs_dir_lookup,	.xd_removename			= xfs_dir_removename,	.xd_getdents			= xfs_dir_getdents,	.xd_replace			= xfs_dir_replace,	.xd_canenter			= xfs_dir_canenter,	.xd_shortform_validate_ondisk	= xfs_dir_shortform_validate_ondisk,	.xd_shortform_to_single		= xfs_dir_shortform_to_leaf,};/* * Internal routines when dirsize == XFS_LBSIZE(mp). */STATIC int xfs_dir_leaf_lookup(xfs_da_args_t *args);STATIC int xfs_dir_leaf_removename(xfs_da_args_t *args, int *number_entries,						 int *total_namebytes);STATIC int xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp,					     uio_t *uio, int *eofp,					     xfs_dirent_t *dbp,					     xfs_dir_put_t put);STATIC int xfs_dir_leaf_replace(xfs_da_args_t *args);/* * Internal routines when dirsize > XFS_LBSIZE(mp). */STATIC int xfs_dir_node_addname(xfs_da_args_t *args);STATIC int xfs_dir_node_lookup(xfs_da_args_t *args);STATIC int xfs_dir_node_removename(xfs_da_args_t *args);STATIC int xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp,					     uio_t *uio, int *eofp,					     xfs_dirent_t *dbp,					     xfs_dir_put_t put);STATIC int xfs_dir_node_replace(xfs_da_args_t *args);#if defined(XFS_DIR_TRACE)ktrace_t *xfs_dir_trace_buf;#endif/*======================================================================== * Overall external interface routines. *========================================================================*/xfs_dahash_t	xfs_dir_hash_dot, xfs_dir_hash_dotdot;/* * One-time startup routine called from xfs_init(). */voidxfs_dir_startup(void){	xfs_dir_hash_dot = xfs_da_hashname(".", 1);	xfs_dir_hash_dotdot = xfs_da_hashname("..", 2);}/* * Initialize directory-related fields in the mount structure. */static voidxfs_dir_mount(xfs_mount_t *mp){	uint shortcount, leafcount, count;	mp->m_dirversion = 1;	shortcount = (mp->m_attroffset - (uint)sizeof(xfs_dir_sf_hdr_t)) /		     (uint)sizeof(xfs_dir_sf_entry_t);	leafcount = (XFS_LBSIZE(mp) - (uint)sizeof(xfs_dir_leaf_hdr_t)) /		    ((uint)sizeof(xfs_dir_leaf_entry_t) +		     (uint)sizeof(xfs_dir_leaf_name_t));	count = shortcount > leafcount ? shortcount : leafcount;	mp->m_dircook_elog = xfs_da_log2_roundup(count + 1);	ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog);	mp->m_dir_node_ents = mp->m_attr_node_ents =		(XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) /		(uint)sizeof(xfs_da_node_entry_t);	mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100;	mp->m_dirblksize = mp->m_sb.sb_blocksize;	mp->m_dirblkfsbs = 1;}/* * Return 1 if directory contains only "." and "..". */static intxfs_dir_isempty(xfs_inode_t *dp){	xfs_dir_sf_hdr_t *hdr;	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	if (dp->i_d.di_size == 0)		return(1);	if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))		return(0);	hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data;	return(hdr->count == 0);}/* * Initialize a directory with its "." and ".." entries. */static intxfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir){	xfs_da_args_t args;	int error;	memset((char *)&args, 0, sizeof(args));	args.dp = dir;	args.trans = trans;	ASSERT((dir->i_d.di_mode & S_IFMT) == S_IFDIR);	if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino)))		return error;	return(xfs_dir_shortform_create(&args, parent_dir->i_ino));}/* * Generic handler routine to add a name to a directory. * Transitions directory from shortform to Btree as necessary. */static int							/* error */xfs_dir_createname(xfs_trans_t *trans, xfs_inode_t *dp, char *name,		   int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock,		   xfs_bmap_free_t *flist, xfs_extlen_t total){	xfs_da_args_t args;	int retval, newsize, done;	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum)))		return (retval);	XFS_STATS_INC(xs_dir_create);	/*	 * Fill in the arg structure for this request.	 */	args.name = name;	args.namelen = namelen;	args.hashval = xfs_da_hashname(name, namelen);	args.inumber = inum;	args.dp = dp;	args.firstblock = firstblock;	args.flist = flist;	args.total = total;	args.whichfork = XFS_DATA_FORK;	args.trans = trans;	args.justcheck = 0;	args.addname = args.oknoent = 1;	/*	 * Decide on what work routines to call based on the inode size.	 */	done = 0;	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {		newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen);		if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) {			retval = xfs_dir_shortform_addname(&args);			done = 1;		} else {			if (total == 0)				return XFS_ERROR(ENOSPC);			retval = xfs_dir_shortform_to_leaf(&args);			done = retval != 0;		}	}	if (!done && xfs_bmap_one_block(dp, XFS_DATA_FORK)) {		retval = xfs_dir_leaf_addname(&args);		done = retval != ENOSPC;		if (!done) {			if (total == 0)				return XFS_ERROR(ENOSPC);			retval = xfs_dir_leaf_to_node(&args);			done = retval != 0;		}	}	if (!done) {		retval = xfs_dir_node_addname(&args);	}	return(retval);}/* * Generic handler routine to check if a name can be added to a directory, * without adding any blocks to the directory. */static int							/* error */xfs_dir_canenter(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen){	xfs_da_args_t args;	int retval, newsize;	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	/*	 * Fill in the arg structure for this request.	 */	args.name = name;	args.namelen = namelen;	args.hashval = xfs_da_hashname(name, namelen);	args.inumber = 0;	args.dp = dp;	args.firstblock = NULL;	args.flist = NULL;	args.total = 0;	args.whichfork = XFS_DATA_FORK;	args.trans = trans;	args.justcheck = args.addname = args.oknoent = 1;	/*	 * Decide on what work routines to call based on the inode size.	 */	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {		newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen);		if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp))			retval = 0;		else			retval = XFS_ERROR(ENOSPC);	} else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {		retval = xfs_dir_leaf_addname(&args);	} else {		retval = xfs_dir_node_addname(&args);	}	return(retval);}/* * Generic handler routine to remove a name from a directory. * Transitions directory from Btree to shortform as necessary. */static int							/* error */xfs_dir_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name,		   int namelen, xfs_ino_t ino, xfs_fsblock_t *firstblock,		   xfs_bmap_free_t *flist, xfs_extlen_t total){	xfs_da_args_t args;	int count, totallen, newsize, retval;	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);	XFS_STATS_INC(xs_dir_remove);	/*	 * Fill in the arg structure for this request.	 */	args.name = name;	args.namelen = namelen;	args.hashval = xfs_da_hashname(name, namelen);	args.inumber = ino;	args.dp = dp;	args.firstblock = firstblock;	args.flist = flist;	args.total = total;	args.whichfork = XFS_DATA_FORK;	args.trans = trans;	args.justcheck = args.addname = args.oknoent = 0;	/*	 * Decide on what work routines to call based on the inode size.	 */	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {		retval = xfs_dir_shortform_removename(&args);	} else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {		retval = xfs_dir_leaf_removename(&args, &count, &totallen);		if (retval == 0) {			newsize = XFS_DIR_SF_ALLFIT(count, totallen);			if (newsize <= XFS_IFORK_DSIZE(dp)) {				retval = xfs_dir_leaf_to_shortform(&args);			}		}	} else {		retval = xfs_dir_node_removename(&args);	}	return(retval);}static int							/* error */xfs_dir_lookup(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen,				   xfs_ino_t *inum){

⌨️ 快捷键说明

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