Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 9383e745e23602bc45f9c92184feea59 > files > 109

gfs2-utils-0.1.62-28.el5.src.rpm

commit 4e102cbef05a8d57b063b56346ca439cd580c924
Author: Abhijith Das <adas@redhat.com>
Date:   Fri Apr 30 10:47:09 2010 -0500

    gfs2_convert: gfs2_convert doesn't convert indirectly-pointed extended attributes correctly
    
    When the extended attributes for a file don't fit
    in one fs block, the dinode->di_eattr block becomes
    an indirect block that contains pointers to blocks
    that actually contain the xattrs. The gfs1 indirect
    block header is different (larger) than that of gfs2
    and this causes an incorrect conversion. The
    resulting gfs2 filesystem cannot display the xattrs
    because of leading nulls in the indirect block. This
    patch adjusts this correctly.
    
    Resolves: rhbz#576040
    Signed-off-by: Abhi Das <adas@redhat.com>

diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 0379d33..f28aac4 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -948,6 +948,45 @@ static int fix_cdpn_symlink(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, s
 
 	return ret;
 }
+
+/*
+ * fix_xattr -
+ * Extended attributes can be either direct (in the ip->i_di.di_eattr block) or
+ * then can be at a maximum of 1 indirect level. Multiple levels of indirection
+ * are not supported. If the di_eattr block contains extended attribute data,
+ * i.e block type = GFS_METATYPE_EA, we ignore it.
+ * If the di_eattr block contains block pointers to extended attributes we need
+ * to fix the header. gfs1 uses gfs_indirect as the header which is 64 bytes
+ * bigger than gfs2_meta_header that gfs2 uses.
+ */
+static int fix_xattr(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, struct gfs2_inode *ip)
+{
+	int ret = 0, len, old_hdr_sz, new_hdr_sz;
+	struct gfs2_buffer_head *eabh;
+	char *buf;
+
+	/* Read in the i_di.di_eattr block */
+	eabh = bread(sbp, ip->i_di.di_eattr);
+        if (!gfs2_check_meta(eabh, GFS_METATYPE_IN)) {/* if it is an indirect block */
+		len = sbp->bsize - sizeof(struct gfs_indirect);
+		buf = malloc(len);
+		if (!buf) {
+			log_crit("Error: out of memory.\n");
+			return -1;
+		}
+		old_hdr_sz = sizeof(struct gfs_indirect);
+		new_hdr_sz = sizeof(struct gfs2_meta_header);
+		memcpy(buf, eabh->b_data + old_hdr_sz, sbp->bsize - old_hdr_sz);
+		memset(eabh->b_data + new_hdr_sz, 0, sbp->bsize - new_hdr_sz);
+		memcpy(eabh->b_data + new_hdr_sz, buf, len);
+		free(buf);
+		bmodified(eabh);
+	}
+        brelse(eabh);
+
+	return ret;
+}
+
 /* ------------------------------------------------------------------------- */
 /* adjust_inode - change an inode from gfs1 to gfs2                          */
 /*                                                                           */
@@ -1039,6 +1078,12 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
 			if (ret)
 				return -1;
 		}
+		/* Check for extended attributes */
+		if (inode->i_di.di_eattr) {
+			ret = fix_xattr(sbp, bh, inode);
+			if (ret)
+				return -1;
+		}
 	}
 	
 	bmodified(inode->i_bh);