diff options
Diffstat (limited to 'fs/xfs/libxfs')
| -rw-r--r-- | fs/xfs/libxfs/xfs_dir2.c | 39 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_dir2.h | 8 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_inode_buf.c | 10 | 
3 files changed, 37 insertions, 20 deletions
| diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c index c58d72c220f5..2f389d366e93 100644 --- a/fs/xfs/libxfs/xfs_dir2.c +++ b/fs/xfs/libxfs/xfs_dir2.c @@ -36,21 +36,29 @@  struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };  /* - * @mode, if set, indicates that the type field needs to be set up. - * This uses the transformation from file mode to DT_* as defined in linux/fs.h - * for file type specification. This will be propagated into the directory - * structure if appropriate for the given operation and filesystem config. + * Convert inode mode to directory entry filetype   */ -const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = { -	[0]			= XFS_DIR3_FT_UNKNOWN, -	[S_IFREG >> S_SHIFT]    = XFS_DIR3_FT_REG_FILE, -	[S_IFDIR >> S_SHIFT]    = XFS_DIR3_FT_DIR, -	[S_IFCHR >> S_SHIFT]    = XFS_DIR3_FT_CHRDEV, -	[S_IFBLK >> S_SHIFT]    = XFS_DIR3_FT_BLKDEV, -	[S_IFIFO >> S_SHIFT]    = XFS_DIR3_FT_FIFO, -	[S_IFSOCK >> S_SHIFT]   = XFS_DIR3_FT_SOCK, -	[S_IFLNK >> S_SHIFT]    = XFS_DIR3_FT_SYMLINK, -}; +unsigned char xfs_mode_to_ftype(int mode) +{ +	switch (mode & S_IFMT) { +	case S_IFREG: +		return XFS_DIR3_FT_REG_FILE; +	case S_IFDIR: +		return XFS_DIR3_FT_DIR; +	case S_IFCHR: +		return XFS_DIR3_FT_CHRDEV; +	case S_IFBLK: +		return XFS_DIR3_FT_BLKDEV; +	case S_IFIFO: +		return XFS_DIR3_FT_FIFO; +	case S_IFSOCK: +		return XFS_DIR3_FT_SOCK; +	case S_IFLNK: +		return XFS_DIR3_FT_SYMLINK; +	default: +		return XFS_DIR3_FT_UNKNOWN; +	} +}  /*   * ASCII case-insensitive (ie. A-Z) support for directories that was @@ -631,7 +639,8 @@ xfs_dir2_isblock(  	if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))  		return rval;  	rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize; -	ASSERT(rval == 0 || args->dp->i_d.di_size == args->geo->blksize); +	if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize) +		return -EFSCORRUPTED;  	*vp = rval;  	return 0;  } diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h index 0197590fa7d7..d6e6d9d16f6c 100644 --- a/fs/xfs/libxfs/xfs_dir2.h +++ b/fs/xfs/libxfs/xfs_dir2.h @@ -18,6 +18,9 @@  #ifndef __XFS_DIR2_H__  #define __XFS_DIR2_H__ +#include "xfs_da_format.h" +#include "xfs_da_btree.h" +  struct xfs_defer_ops;  struct xfs_da_args;  struct xfs_inode; @@ -32,10 +35,9 @@ struct xfs_dir2_data_unused;  extern struct xfs_name	xfs_name_dotdot;  /* - * directory filetype conversion tables. + * Convert inode mode to directory entry filetype   */ -#define S_SHIFT 12 -extern const unsigned char xfs_mode_to_ftype[]; +extern unsigned char xfs_mode_to_ftype(int mode);  /*   * directory operations vector for encode/decode routines diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c index dd483e2767f7..d93f9d918cfc 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.c +++ b/fs/xfs/libxfs/xfs_inode_buf.c @@ -29,6 +29,7 @@  #include "xfs_icache.h"  #include "xfs_trans.h"  #include "xfs_ialloc.h" +#include "xfs_dir2.h"  /*   * Check that none of the inode's in the buffer have a next @@ -386,6 +387,7 @@ xfs_dinode_verify(  	xfs_ino_t		ino,  	struct xfs_dinode	*dip)  { +	uint16_t		mode;  	uint16_t		flags;  	uint64_t		flags2; @@ -396,8 +398,12 @@ xfs_dinode_verify(  	if (be64_to_cpu(dip->di_size) & (1ULL << 63))  		return false; -	/* No zero-length symlinks. */ -	if (S_ISLNK(be16_to_cpu(dip->di_mode)) && dip->di_size == 0) +	mode = be16_to_cpu(dip->di_mode); +	if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN) +		return false; + +	/* No zero-length symlinks/dirs. */ +	if ((S_ISLNK(mode) || S_ISDIR(mode)) && dip->di_size == 0)  		return false;  	/* only version 3 or greater inodes are extensively verified here */ |