blk64_t *quota_blocks)
{
struct ext2_inode inode;
- __u32 hash;
+ __u32 hash, signed_hash;
errcode_t retval;
/* Check if inode is within valid range */
e2fsck_read_inode(ctx, entry->e_value_inum, &inode, "pass1");
- retval = ext2fs_ext_attr_hash_entry2(ctx->fs, entry, NULL, &hash);
+ retval = ext2fs_ext_attr_hash_entry3(ctx->fs, entry, NULL, &hash,
+ &signed_hash);
if (retval) {
com_err("check_large_ea_inode", retval,
_("while hashing entry with e_value_inum = %u"),
fatal_error(ctx, 0);
}
- if (hash == entry->e_hash) {
+ if ((hash == entry->e_hash) || (signed_hash == entry->e_hash)) {
*quota_blocks = size_to_quota_blocks(ctx->fs,
entry->e_value_size);
} else {
}
hash = ext2fs_ext_attr_hash_entry(entry,
- start + entry->e_value_offs);
+ start + entry->e_value_offs);
+ if (entry->e_hash != 0 && entry->e_hash != hash)
+ hash = ext2fs_ext_attr_hash_entry_signed(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) {
hash = ext2fs_ext_attr_hash_entry(entry, block_buf +
entry->e_value_offs);
+ if (entry->e_hash != hash)
+ hash = ext2fs_ext_attr_hash_entry_signed(entry,
+ block_buf + entry->e_value_offs);
if (entry->e_hash != hash) {
pctx->num = entry->e_hash;
/* ext_attr.c */
extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry,
void *data);
+extern __u32 ext2fs_ext_attr_hash_entry_signed(struct ext2_ext_attr_entry *entry,
+ void *data);
extern errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs,
struct ext2_ext_attr_entry *entry,
void *data, __u32 *hash);
+extern errcode_t ext2fs_ext_attr_hash_entry3(ext2_filsys fs,
+ struct ext2_ext_attr_entry *entry,
+ void *data, __u32 *hash,
+ __u32 *signed_hash);
extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
extern errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block,
void *buf);
__u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
{
__u32 hash = 0;
- char *name = ((char *) entry) + sizeof(struct ext2_ext_attr_entry);
+ unsigned char *name = (((unsigned char *) entry) +
+ sizeof(struct ext2_ext_attr_entry));
int n;
for (n = 0; n < entry->e_name_len; n++) {
return hash;
}
+__u32 ext2fs_ext_attr_hash_entry_signed(struct ext2_ext_attr_entry *entry,
+ void *data)
+{
+ __u32 hash = 0;
+ signed char *name = (((signed char *) entry) +
+ sizeof(struct ext2_ext_attr_entry));
+ int n;
+
+ for (n = 0; n < entry->e_name_len; n++) {
+ hash = (hash << NAME_HASH_SHIFT) ^
+ (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
+ *name++;
+ }
+
+ /* The hash needs to be calculated on the data in little-endian. */
+ if (entry->e_value_inum == 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)) ^
+ ext2fs_le32_to_cpu(*value++);
+ }
+ }
+
+ return hash;
+}
+
+
/*
- * ext2fs_ext_attr_hash_entry2()
+ * ext2fs_ext_attr_hash_entry3()
*
- * Compute the hash of an extended attribute.
- * This version of the function supports hashing entries that reference
- * external inodes (ea_inode feature).
+ * Compute the hash of an extended attribute. This version of the
+ * function supports hashing entries that reference external inodes
+ * (ea_inode feature) as well as calculating the old legacy signed
+ * hash variant.
*/
-errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs,
+errcode_t ext2fs_ext_attr_hash_entry3(ext2_filsys fs,
struct ext2_ext_attr_entry *entry,
- void *data, __u32 *hash)
+ void *data, __u32 *hash,
+ __u32 *signed_hash)
{
*hash = ext2fs_ext_attr_hash_entry(entry, data);
+ if (signed_hash)
+ *signed_hash = ext2fs_ext_attr_hash_entry_signed(entry, data);
if (entry->e_value_inum) {
__u32 ea_inode_hash;
*hash = (*hash << VALUE_HASH_SHIFT) ^
(*hash >> (8*sizeof(*hash) - VALUE_HASH_SHIFT)) ^
ea_inode_hash;
+ if (signed_hash)
+ *signed_hash = (*signed_hash << VALUE_HASH_SHIFT) ^
+ (*signed_hash >> (8*sizeof(*hash) -
+ VALUE_HASH_SHIFT)) ^
+ ea_inode_hash;
}
return 0;
}
+/*
+ * ext2fs_ext_attr_hash_entry2()
+ *
+ * Compute the hash of an extended attribute.
+ * This version of the function supports hashing entries that reference
+ * external inodes (ea_inode feature).
+ */
+errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs,
+ struct ext2_ext_attr_entry *entry,
+ void *data, __u32 *hash)
+{
+ return ext2fs_ext_attr_hash_entry3(fs, entry, data, hash, NULL);
+}
+
#undef NAME_HASH_SHIFT
#undef VALUE_HASH_SHIFT
/* e_hash may be 0 in older inode's ea */
if (entry->e_hash != 0) {
- __u32 hash;
+ __u32 hash, signed_hash;
+
void *data = (entry->e_value_inum != 0) ?
0 : value_start + entry->e_value_offs;
- err = ext2fs_ext_attr_hash_entry2(handle->fs, entry,
- data, &hash);
+ err = ext2fs_ext_attr_hash_entry3(handle->fs, entry,
+ data, &hash,
+ &signed_hash);
if (err)
return err;
- if (entry->e_hash != hash) {
+ if ((entry->e_hash != hash) &&
+ (entry->e_hash != signed_hash)) {
struct ext2_inode child;
/* Check whether this is an old Lustre-style