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 + -
显示快捷键?