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

📄 xfs_dir2_sf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
}/* * Add the new entry the "hard" way. * The caller has already converted to 8 byte inode numbers if necessary, * in which case we need to leave the i8count at 1. * Find a hole that the new entry will fit into, and copy * the first part of the entries, the new entry, and the last part of * the entries. *//* ARGSUSED */static voidxfs_dir2_sf_addname_hard(	xfs_da_args_t		*args,		/* operation arguments */	int			objchange,	/* changing inode number size */	int			new_isize)	/* new directory size */{	int			add_datasize;	/* data size need for new ent */	char			*buf;		/* buffer for old */	xfs_inode_t		*dp;		/* incore directory inode */	int			eof;		/* reached end of old dir */	int			nbytes;		/* temp for byte copies */	xfs_dir2_data_aoff_t	new_offset;	/* next offset value */	xfs_dir2_data_aoff_t	offset;		/* current offset value */	int			old_isize;	/* previous di_size */	xfs_dir2_sf_entry_t	*oldsfep;	/* entry in original dir */	xfs_dir2_sf_t		*oldsfp;	/* original shortform dir */	xfs_dir2_sf_entry_t	*sfep;		/* entry in new dir */	xfs_dir2_sf_t		*sfp;		/* new shortform dir */	/*	 * Copy the old directory to the stack buffer.	 */	dp = args->dp;	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	old_isize = (int)dp->i_d.di_size;	buf = kmem_alloc(old_isize, KM_SLEEP);	oldsfp = (xfs_dir2_sf_t *)buf;	memcpy(oldsfp, sfp, old_isize);	/*	 * Loop over the old directory finding the place we're going	 * to insert the new entry.	 * If it's going to end up at the end then oldsfep will point there.	 */	for (offset = XFS_DIR2_DATA_FIRST_OFFSET,	      oldsfep = xfs_dir2_sf_firstentry(oldsfp),	      add_datasize = xfs_dir2_data_entsize(args->namelen),	      eof = (char *)oldsfep == &buf[old_isize];	     !eof;	     offset = new_offset + xfs_dir2_data_entsize(oldsfep->namelen),	      oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep),	      eof = (char *)oldsfep == &buf[old_isize]) {		new_offset = xfs_dir2_sf_get_offset(oldsfep);		if (offset + add_datasize <= new_offset)			break;	}	/*	 * Get rid of the old directory, then allocate space for	 * the new one.  We do this so xfs_idata_realloc won't copy	 * the data.	 */	xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);	xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);	/*	 * Reset the pointer since the buffer was reallocated.	 */	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	/*	 * Copy the first part of the directory, including the header.	 */	nbytes = (int)((char *)oldsfep - (char *)oldsfp);	memcpy(sfp, oldsfp, nbytes);	sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);	/*	 * Fill in the new entry, and update the header counts.	 */	sfep->namelen = args->namelen;	xfs_dir2_sf_put_offset(sfep, offset);	memcpy(sfep->name, args->name, sfep->namelen);	xfs_dir2_sf_put_inumber(sfp, &args->inumber,		xfs_dir2_sf_inumberp(sfep));	sfp->hdr.count++;#if XFS_BIG_INUMS	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)		sfp->hdr.i8count++;#endif	/*	 * If there's more left to copy, do that.	 */	if (!eof) {		sfep = xfs_dir2_sf_nextentry(sfp, sfep);		memcpy(sfep, oldsfep, old_isize - nbytes);	}	kmem_free(buf, old_isize);	dp->i_d.di_size = new_isize;	xfs_dir2_sf_check(args);}/* * Decide if the new entry will fit at all. * If it will fit, pick between adding the new entry to the end (easy) * or somewhere else (hard). * Return 0 (won't fit), 1 (easy), 2 (hard). *//*ARGSUSED*/static int					/* pick result */xfs_dir2_sf_addname_pick(	xfs_da_args_t		*args,		/* operation arguments */	int			objchange,	/* inode # size changes */	xfs_dir2_sf_entry_t	**sfepp,	/* out(1): new entry ptr */	xfs_dir2_data_aoff_t	*offsetp)	/* out(1): new offset */{	xfs_inode_t		*dp;		/* incore directory inode */	int			holefit;	/* found hole it will fit in */	int			i;		/* entry number */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_dir2_data_aoff_t	offset;		/* data block offset */	xfs_dir2_sf_entry_t	*sfep;		/* shortform entry */	xfs_dir2_sf_t		*sfp;		/* shortform structure */	int			size;		/* entry's data size */	int			used;		/* data bytes used */	dp = args->dp;	mp = dp->i_mount;	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	size = xfs_dir2_data_entsize(args->namelen);	offset = XFS_DIR2_DATA_FIRST_OFFSET;	sfep = xfs_dir2_sf_firstentry(sfp);	holefit = 0;	/*	 * Loop over sf entries.	 * Keep track of data offset and whether we've seen a place	 * to insert the new entry.	 */	for (i = 0; i < sfp->hdr.count; i++) {		if (!holefit)			holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);		offset = xfs_dir2_sf_get_offset(sfep) +			 xfs_dir2_data_entsize(sfep->namelen);		sfep = xfs_dir2_sf_nextentry(sfp, sfep);	}	/*	 * Calculate data bytes used excluding the new entry, if this	 * was a data block (block form directory).	 */	used = offset +	       (sfp->hdr.count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) +	       (uint)sizeof(xfs_dir2_block_tail_t);	/*	 * If it won't fit in a block form then we can't insert it,	 * we'll go back, convert to block, then try the insert and convert	 * to leaf.	 */	if (used + (holefit ? 0 : size) > mp->m_dirblksize)		return 0;	/*	 * If changing the inode number size, do it the hard way.	 */#if XFS_BIG_INUMS	if (objchange) {		return 2;	}#else	ASSERT(objchange == 0);#endif	/*	 * If it won't fit at the end then do it the hard way (use the hole).	 */	if (used + size > mp->m_dirblksize)		return 2;	/*	 * Do it the easy way.	 */	*sfepp = sfep;	*offsetp = offset;	return 1;}#ifdef DEBUG/* * Check consistency of shortform directory, assert if bad. */static voidxfs_dir2_sf_check(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_inode_t		*dp;		/* incore directory inode */	int			i;		/* entry number */	int			i8count;	/* number of big inode#s */	xfs_ino_t		ino;		/* entry inode number */	int			offset;		/* data offset */	xfs_dir2_sf_entry_t	*sfep;		/* shortform dir entry */	xfs_dir2_sf_t		*sfp;		/* shortform structure */	dp = args->dp;	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	offset = XFS_DIR2_DATA_FIRST_OFFSET;	ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);	i8count = ino > XFS_DIR2_MAX_SHORT_INUM;	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);	     i < sfp->hdr.count;	     i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {		ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);		ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));		i8count += ino > XFS_DIR2_MAX_SHORT_INUM;		offset =			xfs_dir2_sf_get_offset(sfep) +			xfs_dir2_data_entsize(sfep->namelen);	}	ASSERT(i8count == sfp->hdr.i8count);	ASSERT(XFS_BIG_INUMS || i8count == 0);	ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);	ASSERT(offset +	       (sfp->hdr.count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +	       (uint)sizeof(xfs_dir2_block_tail_t) <=	       dp->i_mount->m_dirblksize);}#endif	/* DEBUG *//* * Create a new (shortform) directory. */int					/* error, always 0 */xfs_dir2_sf_create(	xfs_da_args_t	*args,		/* operation arguments */	xfs_ino_t	pino)		/* parent inode number */{	xfs_inode_t	*dp;		/* incore directory inode */	int		i8count;	/* parent inode is an 8-byte number */	xfs_dir2_sf_t	*sfp;		/* shortform structure */	int		size;		/* directory size */	xfs_dir2_trace_args_i("sf_create", args, pino);	dp = args->dp;	ASSERT(dp != NULL);	ASSERT(dp->i_d.di_size == 0);	/*	 * If it's currently a zero-length extent file,	 * convert it to local format.	 */	if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) {		dp->i_df.if_flags &= ~XFS_IFEXTENTS;	/* just in case */		dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;		xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);		dp->i_df.if_flags |= XFS_IFINLINE;	}	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);	ASSERT(dp->i_df.if_bytes == 0);	i8count = pino > XFS_DIR2_MAX_SHORT_INUM;	size = xfs_dir2_sf_hdr_size(i8count);	/*	 * Make a buffer for the data.	 */	xfs_idata_realloc(dp, size, XFS_DATA_FORK);	/*	 * Fill in the header,	 */	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	sfp->hdr.i8count = i8count;	/*	 * Now can put in the inode number, since i8count is set.	 */	xfs_dir2_sf_put_inumber(sfp, &pino, &sfp->hdr.parent);	sfp->hdr.count = 0;	dp->i_d.di_size = size;	xfs_dir2_sf_check(args);	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);	return 0;}int						/* error */xfs_dir2_sf_getdents(	xfs_inode_t		*dp,		/* incore directory inode */	void			*dirent,	xfs_off_t		*offset,	filldir_t		filldir){	int			i;		/* shortform entry number */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_dir2_dataptr_t	off;		/* current entry's offset */	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */	xfs_dir2_sf_t		*sfp;		/* shortform structure */	xfs_dir2_dataptr_t	dot_offset;	xfs_dir2_dataptr_t	dotdot_offset;	xfs_ino_t		ino;	mp = dp->i_mount;	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);	/*	 * Give up if the directory is way too short.	 */	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {		ASSERT(XFS_FORCED_SHUTDOWN(mp));		return XFS_ERROR(EIO);	}	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);	ASSERT(dp->i_df.if_u1.if_data != NULL);	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));	/*	 * If the block number in the offset is out of range, we're done.	 */	if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk)		return 0;	/*	 * Precalculate offsets for . and .. as we will always need them.	 *	 * XXX(hch): the second argument is sometimes 0 and sometimes	 * mp->m_dirdatablk.	 */	dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,					     XFS_DIR2_DATA_DOT_OFFSET);	dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,						XFS_DIR2_DATA_DOTDOT_OFFSET);	/*	 * Put . entry unless we're starting past it.	 */	if (*offset <= dot_offset) {		ino = dp->i_ino;#if XFS_BIG_INUMS		ino += mp->m_inoadd;#endif		if (filldir(dirent, ".", 1, dot_offset, ino, DT_DIR)) {			*offset = dot_offset;			return 0;		}	}	/*	 * Put .. entry unless we're starting past it.	 */	if (*offset <= dotdot_offset) {		ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);#if XFS_BIG_INUMS		ino += mp->m_inoadd;#endif		if (filldir(dirent, "..", 2, dotdot_offset, ino, DT_DIR)) {			*offset = dotdot_offset;			return 0;		}	}	/*	 * Loop while there are more entries and put'ing works.	 */	sfep = xfs_dir2_sf_firstentry(sfp);	for (i = 0; i < sfp->hdr.count; i++) {		off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,				xfs_dir2_sf_get_offset(sfep));		if (*offset > off) {			sfep = xfs_dir2_sf_nextentry(sfp, sfep);			continue;		}		ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));#if XFS_BIG_INUMS		ino += mp->m_inoadd;#endif		if (filldir(dirent, sfep->name, sfep->namelen,					    off, ino, DT_UNKNOWN)) {			*offset = off;			return 0;		}		sfep = xfs_dir2_sf_nextentry(sfp, sfep);	}	*offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);	return 0;}/* * Lookup an entry in a shortform directory. * Returns EEXIST if found, ENOENT if not found. */int						/* error */xfs_dir2_sf_lookup(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_inode_t		*dp;		/* incore directory inode */	int			i;		/* entry index */	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */	xfs_dir2_sf_t		*sfp;		/* shortform structure */	xfs_dir2_trace_args("sf_lookup", args);	xfs_dir2_sf_check(args);	dp = args->dp;	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);	/*	 * Bail out if the directory is way too short.	 */	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));		return XFS_ERROR(EIO);	}	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);	ASSERT(dp->i_df.if_u1.if_data != NULL);	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));	/*	 * Special case for .	 */	if (args->namelen == 1 && args->name[0] == '.') {		args->inumber = dp->i_ino;		return XFS_ERROR(EEXIST);	}

⌨️ 快捷键说明

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