[Ocfs2-tools-devel] [PATCH 3/4] Ocfs2-tools: Fix bug for fswreck to handle corruption of inlined directory correctly.

Joel Becker Joel.Becker at oracle.com
Thu Jul 2 14:24:15 PDT 2009


On Fri, Jun 26, 2009 at 10:49:21AM +0800, Tristan Ye wrote:
> +struct dirent_corrupt_struct  {
> +
> +	const char	*oldname;
> +	const char      *name;
> +	int             namelen;
> +	int             done;
> +	int		reserved;
> +};

	Let's add oldnamelen as the length of oldname and
then use namelen as the length of name.  This makes it clear.  Then in
corrupt_match_dirent...

> +static int corrupt_match_dirent(struct dirent_corrupt_struct *dcs,
> +				struct ocfs2_dir_entry *dirent)
>  {
> -	struct ocfs2_dir_entry *de1 = NULL;
> -	uint32_t offset = 0;
> -	uint16_t rec_len = OCFS2_DIR_REC_LEN(namelen);
> -
> -	while (1) {
> -		if ((de->inode == 0 && de->rec_len >= rec_len) ||
> -		    (de->rec_len >= 
> -			(OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
> -			offset += de->rec_len;
> -			if (de->inode) {
> -			de1 = (struct ocfs2_dir_entry *)((char *) de +
> -				OCFS2_DIR_REC_LEN(de->name_len));
> -			de1->rec_len = de->rec_len -
> -				OCFS2_DIR_REC_LEN(de->name_len);
> -			de->rec_len = OCFS2_DIR_REC_LEN(de->name_len);
> -			de = de1;
> -			}
> -			de->file_type = OCFS2_FT_UNKNOWN;
> -			de->inode = blkno;
> -			ocfs2_set_de_type(de, mode);
> -			de->name_len = namelen;
> -			memcpy(de->name, name, namelen);
> -			break;
> -		}
> -		offset += de->rec_len;
> -		de = (struct ocfs2_dir_entry *) ((char *) de + de->rec_len);
> -		if (offset >= fs->fs_blocksize)
> -			FSWRK_FATAL("no space for the new dirent");
> -	}
> +	if (!dcs->oldname)
> +		return 1;
>  
> -	*retent = de;
> -	return;
> +	if (((dirent->name_len & 0xFF) != dcs->namelen))
> +		return 0;

	We compare dcs->oldnamelen here.

> +static int rename_dirent_proc(struct ocfs2_dir_entry *dirent,
> +			      int        offset,
> +			      int        blocksize,
> +			      char       *buf,
> +			      void       *priv_data)
>  {
> -	errcode_t ret;
> -	char *buf = NULL;
> -	uint64_t blkno, tmp_blkno;
> -	uint64_t contig;
> -	ocfs2_cached_inode *cinode = NULL;
> -	struct ocfs2_dir_entry *de = NULL, *newent = NULL;
> -	char name[OCFS2_MAX_FILENAME_LEN];
> -	int namelen;
> -	mode_t mode;
> +	struct  dirent_corrupt_struct *dcs = (struct dirent_corrupt_struct *) priv_data;
>  
> -	ret = ocfs2_read_cached_inode(fs, dir, &cinode);
> -	if (ret)
> -		FSWRK_COM_FATAL(progname, ret);
> +	if (!corrupt_match_dirent(dcs, dirent))
> +		return 0;
> +	
> +	strcpy(dirent->name, dcs->name);

	Here you store dcs->name, but what if dcs->name is not the same
length as dirent->name?  Currently fswreck only does a corruption of
'.' -> 'a', so the length is the same.  But the limitation is not
obvious.  You can do one of two things:

1) The easy thing is to make the limitation explicit.  At the top of
rename_dirent() you check that dcs->oldnamelen == dcs->namelen or you
FSWRECK_FATAL.

2) The fancier thing would be to check here if dcs->namelen fits inside
the dirent (that is, dcs->namelen <= (dirent->rec_len - offsetof(struct
ocfs2_dir_entry, name))).  If it fits, you store the new name and new
namelen.  If it does not, you FATAL.

Joel

-- 

Life's Little Instruction Book #274

	"Leave everything a little better than you found it."

Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127



More information about the Ocfs2-tools-devel mailing list