Skip to contentSkip to conversation

e2fsprogs: Additions in EA checking

PATCH New Kalpak Shah 1 participant 1 message May 2, 2007

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 e2fsprogs: Additions in EA checking

Hi,

This patch makes the following changes to EA checking:

1) Allow in-inode EAs to have a hash.
2) Connect zero-length inodes that have an EA to lost+found.
3) Addition of hash function for EAs

e2fsck/e2fsck.h +3 -0
Index: e2fsprogs-1.40/e2fsck/e2fsck.h
===================================================================
@@ -475,6 +475,9 @@ extern void init_resource_track(struct r
 extern int inode_has_valid_blocks(struct ext2_inode *inode);
 extern void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
 			      struct ext2_inode * inode, const char * proc);
+extern void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
+				   struct ext2_inode *inode,
+				   const int bufsize, const char *proc);
 extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
 			       struct ext2_inode * inode, const char * proc);
 extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
e2fsck/pass1.c +27 -8
Index: e2fsprogs-1.40/e2fsck/pass1.c
===================================================================
@@ -250,8 +250,8 @@ static void check_ea_in_inode(e2fsck_t c
 	int problem = 0;
 
 	inode = (struct ext2_inode_large *) pctx->inode;
-	storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
-		inode->i_extra_isize;
+	storage_size = EXT2_INODE_SIZE(ctx->fs->super) -
+		EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize;
 	start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
 		inode->i_extra_isize + sizeof(__u32);
 	end = (char *) inode + EXT2_INODE_SIZE(ctx->fs->super);
@@ -263,6 +263,7 @@ static void check_ea_in_inode(e2fsck_t c
 	remain = storage_size - sizeof(__u32); 
 
 	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+		__u32 hash;
 
 		/* header eats this space */
 		remain -= sizeof(struct ext2_ext_attr_entry);
@@ -291,8 +292,11 @@ static void check_ea_in_inode(e2fsck_t c
 			goto fix;
 		}
 		
-		/* e_hash must be 0 in inode's ea */
-		if (entry->e_hash != 0) {
+		hash = ext2fs_ext_attr_hash_entry(entry,
+						  start + entry->e_value_offs);
+
+		/* e_hash may be 0 in older inode's ea */
+		if (entry->e_hash != 0 && entry->e_hash != hash) {
 			pctx->num = entry->e_hash;
 			problem = PR_1_ATTR_HASH;
 			goto fix;
@@ -307,9 +311,6 @@ fix:
 	 * it seems like a corruption. it's very unlikely we could repair
 	 * EA(s) in automatic fashion -bzzz
 	 */
-#if 0
-	problem = PR_1_ATTR_HASH;
-#endif
 	if (problem == 0 || !fix_problem(ctx, problem, pctx))
 		return;
 
@@ -1357,10 +1358,13 @@ static int check_ext_attr(e2fsck_t ctx, 
 	entry = (struct ext2_ext_attr_entry *)(header+1);
 	end = block_buf + fs->blocksize;
 	while ((char *)entry < end && *(__u32 *)entry) {
+		__u32 hash;
+
 		if (region_allocate(region, (char *)entry - (char *)header,
 			           EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
 			if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
 				goto clear_extattr;
+			break;
 		}
 		if ((ctx->ext_attr_ver == 1 &&
 		     (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
@@ -1368,6 +1372,7 @@ static int check_ext_attr(e2fsck_t ctx, 
 		     entry->e_name_index == 0)) {
 			if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
 				goto clear_extattr;
+			break;
 		}
 		if (entry->e_value_block != 0) {
 			if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
@@ -1379,6 +1384,17 @@ static int check_ext_attr(e2fsck_t ctx, 
 			if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
 				goto clear_extattr;
 		}
+
+		hash = ext2fs_ext_attr_hash_entry(entry, block_buf +
+							 entry->e_value_offs);
+
+		if (entry->e_hash != hash) {
+			pctx->num = entry->e_hash;
+			if (fix_problem(ctx, PR_1_ATTR_HASH, pctx))
+				goto clear_extattr;
+			entry->e_hash = hash;
+		}
+
 		entry = EXT2_EXT_ATTR_NEXT(entry);
 	}
 	if (region_allocate(region, (char *)entry - (char *)header, 4)) {
@@ -1500,8 +1516,11 @@ static void check_blocks(e2fsck_t ctx, s
 		}
 	}
 
-	if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
+	if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf)) {
+		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+			goto out;
 		pb.num_blocks++;
+	}
 
 	if (ext2fs_inode_has_valid_blocks(inode))
 		pctx->errcode = ext2fs_block_iterate2(fs, ino,
e2fsck/pass4.c +34 -18

122 lines not on this page · raw message

e2fsck/util.c +14 -0
Index: e2fsprogs-1.40/e2fsck/util.c
===================================================================
@@ -361,6 +361,20 @@ void e2fsck_read_inode(e2fsck_t ctx, uns
 	}
 }
 
+void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino,
+			    struct ext2_inode *inode, int bufsize,
+			    const char *proc)
+{
+	int retval;
+
+	retval = ext2fs_read_inode_full(ctx->fs, ino, inode, bufsize);
+	if (retval) {
+		com_err("ext2fs_read_inode_full", retval,
+			_("while reading inode %ld in %s"), ino, proc);
+		fatal_error(ctx, 0);
+	}
+}
+
 extern void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
 			       struct ext2_inode * inode, int bufsize,
 			       const char *proc)
lib/ext2fs/ext2_ext_attr.h +1 -1
Index: e2fsprogs-1.40/lib/ext2fs/ext2_ext_attr.h
===================================================================
@@ -30,7 +30,7 @@ struct ext2_ext_attr_entry {
 	__u32	e_value_block;	/* disk block attribute is stored on (n/i) */
 	__u32	e_value_size;	/* size of attribute value */
 	__u32	e_hash;		/* hash value of name and value */
-#if 0
+#if 1
 	char	e_name[0];	/* attribute name */
 #endif
 };
lib/ext2fs/ext2fs.h +4 -0
Index: e2fsprogs-1.40/lib/ext2fs/ext2fs.h
===================================================================
@@ -83,10 +83,12 @@ typedef __u32		ext2_dirhash_t;
 #include "com_err.h"
 #include "ext2_io.h"
 #include "ext2_err.h"
+#include "ext2_ext_attr.h"
 #else
 #include <et/com_err.h>
 #include <ext2fs/ext2_io.h>
 #include <ext2fs/ext2_err.h>
+#include <ext2fs/ext2_ext_attr.h>
 #endif
 
 /*
@@ -714,6 +716,8 @@ extern errcode_t ext2fs_dup_handle(ext2_
 extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
 
 /* ext_attr.c */
+extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry,
+					void *data);
 extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
 extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
 				       void *buf);
lib/ext2fs/ext_attr.c +36 -0
Index: e2fsprogs-1.40/lib/ext2fs/ext_attr.c
===================================================================
@@ -23,6 +23,42 @@
 
 #include "ext2fs.h"
 
+#define NAME_HASH_SHIFT 5
+#define VALUE_HASH_SHIFT 16
+
+/*
+ * ext2_xattr_hash_entry()
+ *
+ * Compute the hash of an extended attribute.
+ */
+__u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
+{
+	__u32 hash = 0;
+	char *name = entry->e_name;
+	int n;
+
+	for (n = 0; n < entry->e_name_len; n++) {
+		hash = (hash << NAME_HASH_SHIFT) ^
+		       (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
+		       *name++;
+	}
+
+	if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+		__u32 *value = (__u32 *)data;
+		for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
+			 EXT2_EXT_ATTR_PAD_BITS; n; n--) {
+			hash = (hash << VALUE_HASH_SHIFT) ^
+			       (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
+			       *value++;
+		}
+	}
+
+	return hash;
+}
+
+#undef NAME_HASH_SHIFT
+#undef VALUE_HASH_SHIFT
+
 errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
 {
 	errcode_t	retval;
lib/ext2fs/swapfs.c +2 -0
Index: e2fsprogs-1.40/lib/ext2fs/swapfs.c
===================================================================
@@ -110,6 +110,7 @@ void ext2fs_swap_ext_attr(char *to, char
 		to_header->h_magic    = ext2fs_swab32(from_header->h_magic);
 		to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
 		to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
+		to_header->h_hash     = ext2fs_swab32(from_header->h_hash);
 		for (n=0; n<4; n++)
 			to_header->h_reserved[n] =
 				ext2fs_swab32(from_header->h_reserved[n]);
@@ -124,6 +125,7 @@ void ext2fs_swap_ext_attr(char *to, char
 			ext2fs_swab32(from_entry->e_value_block);
 		to_entry->e_value_size  =	
 			ext2fs_swab32(from_entry->e_value_size);
+		to_entry->e_hash = ext2fs_swab32(from_entry->e_hash);
 		from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
 		to_entry   = EXT2_EXT_ATTR_NEXT(to_entry);
 	}

Thanks,
Kalpak.