#define STATIC static
#endif
+void ext2fs_init_csum_seed(ext2_filsys fs)
+{
+ if (ext2fs_has_feature_csum_seed(fs->super))
+ fs->csum_seed = fs->super->s_checksum_seed;
+ else if (ext2fs_has_feature_metadata_csum(fs->super) ||
+ ext2fs_has_feature_ea_inode(fs->super))
+ fs->csum_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid,
+ sizeof(fs->super->s_uuid));
+}
+
+static __u32 ext2fs_mmp_csum(ext2_filsys fs, struct mmp_struct *mmp)
+{
+ int offset = offsetof(struct mmp_struct, mmp_checksum);
+
+ return ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)mmp, offset);
+}
+
+int ext2fs_mmp_csum_verify(ext2_filsys fs, struct mmp_struct *mmp)
+{
+ __u32 calculated;
+
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
+ return 1;
+
+ calculated = ext2fs_mmp_csum(fs, mmp);
+
+ return ext2fs_le32_to_cpu(mmp->mmp_checksum) == calculated;
+}
+
+errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp)
+{
+ __u32 crc;
+
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
+ return 0;
+
+ crc = ext2fs_mmp_csum(fs, mmp);
+ mmp->mmp_checksum = ext2fs_cpu_to_le32(crc);
+
+ return 0;
+}
+
int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb)
{
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 1;
return sb->s_checksum_type == EXT2_CRC32C_CHKSUM;
}
-static __u32 ext2fs_superblock_csum(ext2_filsys fs, struct ext2_super_block *sb)
+static __u32 ext2fs_superblock_csum(ext2_filsys fs EXT2FS_ATTR((unused)),
+ struct ext2_super_block *sb)
{
int offset = offsetof(struct ext2_super_block, s_checksum);
return ext2fs_crc32c_le(~0, (unsigned char *)sb, offset);
}
+/* NOTE: The input to this function MUST be in LE order */
int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb)
{
- __u32 calculated;
+ __u32 flag, calculated;
+
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES)
+ flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM;
+ else
+ flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag))
return 1;
calculated = ext2fs_superblock_csum(fs, sb);
return ext2fs_le32_to_cpu(sb->s_checksum) == calculated;
}
+/* NOTE: The input to this function MUST be in LE order */
errcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
struct ext2_super_block *sb)
{
- __u32 crc;
+ __u32 flag, crc;
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (fs->flags & EXT2_FLAG_SWAP_BYTES)
+ flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM;
+ else
+ flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
+
+ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag))
return 0;
crc = ext2fs_superblock_csum(fs, sb);
return 0;
}
-static errcode_t ext2fs_ext_attr_block_csum(ext2_filsys fs, ext2_ino_t inum,
+static errcode_t ext2fs_ext_attr_block_csum(ext2_filsys fs,
+ ext2_ino_t inum EXT2FS_ATTR((unused)),
blk64_t block,
struct ext2_ext_attr_header *hdr,
__u32 *crc)
{
- errcode_t retval;
char *buf = (char *)hdr;
- __u32 gen, old_crc = hdr->h_checksum;
- struct ext2_inode inode;
+ __u32 old_crc = hdr->h_checksum;
hdr->h_checksum = 0;
block = ext2fs_cpu_to_le64(block);
__u32 calculated;
errcode_t retval;
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 1;
retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &calculated);
errcode_t retval;
__u32 crc;
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 0;
retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &crc);
if (rec_len == fs->blocksize && translate(dirent->name_len) == 0)
count_offset = 8;
else if (rec_len == 12) {
- dp = (struct ext2_dir_entry *)(((void *)dirent) + rec_len);
+ dp = (struct ext2_dir_entry *)(((char *)dirent) + rec_len);
rec_len = translate(dp->rec_len);
if (rec_len != fs->blocksize - 12)
return EXT2_ET_DB_NOT_FOUND;
- root = (struct ext2_dx_root_info *)(((void *)dp + 12));
+ root = (struct ext2_dx_root_info *)(((char *)dp + 12));
if (root->reserved_zero ||
root->info_length != sizeof(struct ext2_dx_root_info))
return EXT2_ET_DB_NOT_FOUND;
} else
return EXT2_ET_DB_NOT_FOUND;
- c = (struct ext2_dx_countlimit *)(((void *)dirent) + count_offset);
+ c = (struct ext2_dx_countlimit *)(((char *)dirent) + count_offset);
max_sane_entries = (fs->blocksize - count_offset) /
sizeof(struct ext2_dx_entry);
if (ext2fs_le16_to_cpu(c->limit) > max_sane_entries ||
d = dirent;
top = EXT2_DIRENT_TAIL(dirent, fs->blocksize);
- rec_len = translate(d->rec_len);
- while (rec_len && !(rec_len & 0x3)) {
- d = (struct ext2_dir_entry *)(((void *)d) + rec_len);
- if ((void *)d >= top)
- break;
+ while ((void *) d < top) {
rec_len = translate(d->rec_len);
+ if ((rec_len < 8) || (rec_len & 0x03))
+ return EXT2_ET_DIR_CORRUPTED;
+ d = (struct ext2_dir_entry *)(((char *)d) + rec_len);
}
+ if ((char *)d > ((char *)dirent + fs->blocksize))
+ return EXT2_ET_DIR_CORRUPTED;
if (d != top)
return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
int ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent)
{
- return __get_dirent_tail(fs, dirent, NULL, 0) == 0;
+ return __get_dirent_tail(fs, dirent, NULL, 0) !=
+ EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
}
static errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum,
* so the swapfs.c functions won't change the endianness.
*/
retval = ext2fs_dirent_csum(fs, inum, dirent, &calculated,
- (void *)t - (void *)dirent);
+ (char *)t - (char *)dirent);
if (retval)
return 0;
return ext2fs_le32_to_cpu(t->det_checksum) == calculated;
/* swapfs.c functions don't change the checksum endianness */
retval = ext2fs_dirent_csum(fs, inum, dirent, &crc,
- (void *)t - (void *)dirent);
+ (char *)t - (char *)dirent);
if (retval)
return retval;
t->det_checksum = ext2fs_cpu_to_le32(crc);
int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
struct ext2_dir_entry *dirent)
{
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 1;
if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
struct ext2_dir_entry *dirent)
{
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 0;
if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
static struct ext3_extent_tail *get_extent_tail(struct ext3_extent_header *h)
{
- return (struct ext3_extent_tail *)(((void *)h) +
+ return (struct ext3_extent_tail *)(((char *)h) +
EXT3_EXTENT_TAIL_OFFSET(h));
}
* The extent tree structures are accessed in LE order, so we must
* swap the checksum bytes here.
*/
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 1;
provided = ext2fs_le32_to_cpu(t->et_checksum);
__u32 crc;
struct ext3_extent_tail *t = get_extent_tail(eh);
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 0;
/*
ext2fs_group_desc(fs, fs->group_desc, group);
__u32 provided, calculated;
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 1;
provided = gdp->bg_inode_bitmap_csum_lo;
calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap,
size);
- if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
+ if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
provided |= (__u32)gdp->bg_inode_bitmap_csum_hi << 16;
else
calculated &= 0xFFFF;
struct ext4_group_desc *gdp = (struct ext4_group_desc *)
ext2fs_group_desc(fs, fs->group_desc, group);
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 0;
crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size);
gdp->bg_inode_bitmap_csum_lo = crc & 0xFFFF;
- if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
+ if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
gdp->bg_inode_bitmap_csum_hi = crc >> 16;
return 0;
ext2fs_group_desc(fs, fs->group_desc, group);
__u32 provided, calculated;
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 1;
provided = gdp->bg_block_bitmap_csum_lo;
calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap,
size);
- if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
+ if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
provided |= (__u32)gdp->bg_block_bitmap_csum_hi << 16;
else
calculated &= 0xFFFF;
struct ext4_group_desc *gdp = (struct ext4_group_desc *)
ext2fs_group_desc(fs, fs->group_desc, group);
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 0;
crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size);
gdp->bg_block_bitmap_csum_lo = crc & 0xFFFF;
- if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
+ if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
gdp->bg_block_bitmap_csum_hi = crc >> 16;
return 0;
{
__u32 gen;
struct ext2_inode_large *desc = inode;
- size_t size = fs->super->s_inode_size;
+ size_t size = EXT2_INODE_SIZE(fs->super);
__u16 old_lo;
__u16 old_hi = 0;
{
errcode_t retval;
__u32 provided, calculated;
- int has_hi;
+ unsigned int i, has_hi;
+ char *cp;
- if (fs->super->s_creator_os != EXT2_OS_LINUX ||
- !EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 1;
has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
} else
calculated &= 0xFFFF;
- return provided == calculated;
+ if (provided == calculated)
+ return 1;
+
+ /*
+ * If the checksum didn't match, it's possible it was due to
+ * the inode being all zero's. It's unlikely this is the
+ * case, but it can happen. So check for it here. (We only
+ * check the base inode since that's good enough, and it's not
+ * worth the bother to figure out how much of the extended
+ * inode, if any, is present.)
+ */
+ for (cp = (char *) inode, i = 0;
+ i < sizeof(struct ext2_inode);
+ cp++, i++)
+ if (*cp)
+ return 0;
+ return 1; /* Inode must have been all zero's */
}
errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
__u32 crc;
int has_hi;
- if (fs->super->s_creator_os != EXT2_OS_LINUX ||
- !EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ if (!ext2fs_has_feature_metadata_csum(fs->super))
return 0;
has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
__u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
{
+ struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
+ group);
+ size_t offset, size = EXT2_DESC_SIZE(fs->super);
__u16 crc = 0;
- struct ext2_group_desc *desc;
- size_t size;
-
- size = fs->super->s_desc_size;
- if (size < EXT2_MIN_DESC_SIZE)
- size = EXT2_MIN_DESC_SIZE;
- if (size > sizeof(struct ext4_group_desc)) {
- /* This should never happen, but cap it for safety's sake */
- size = sizeof(struct ext4_group_desc);
- }
-
- desc = ext2fs_group_desc(fs, fs->group_desc, group);
-
- if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
- size_t offset = offsetof(struct ext2_group_desc, bg_checksum);
-
#ifdef WORDS_BIGENDIAN
- struct ext4_group_desc swabdesc;
+ struct ext4_group_desc swabdesc;
+ size_t save_size = size;
+ const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
+ struct ext2_group_desc *save_desc = desc;
- /* Have to swab back to little-endian to do the checksum */
- memcpy(&swabdesc, desc, size);
- ext2fs_swap_group_desc2(fs,
- (struct ext2_group_desc *) &swabdesc);
- desc = (struct ext2_group_desc *) &swabdesc;
+ /* Have to swab back to little-endian to do the checksum */
+ if (size > ext4_bg_size)
+ size = ext4_bg_size;
+ memcpy(&swabdesc, desc, size);
+ ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
+ desc = (struct ext2_group_desc *) &swabdesc;
+ group = ext2fs_swab32(group);
+#endif
- group = ext2fs_swab32(group);
+ if (ext2fs_has_feature_metadata_csum(fs->super)) {
+ /* new metadata csum code */
+ __u16 old_crc;
+ __u32 crc32;
+
+ old_crc = desc->bg_checksum;
+ desc->bg_checksum = 0;
+ crc32 = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&group,
+ sizeof(group));
+ crc32 = ext2fs_crc32c_le(crc32, (unsigned char *)desc,
+ size);
+ desc->bg_checksum = old_crc;
+#ifdef WORDS_BIGENDIAN
+ if (save_size > ext4_bg_size)
+ crc32 = ext2fs_crc32c_le(crc32,
+ (unsigned char *)save_desc + ext4_bg_size,
+ save_size - ext4_bg_size);
#endif
- crc = ext2fs_crc16(~0, fs->super->s_uuid,
- sizeof(fs->super->s_uuid));
- crc = ext2fs_crc16(crc, &group, sizeof(group));
- crc = ext2fs_crc16(crc, desc, offset);
- offset += sizeof(desc->bg_checksum); /* skip checksum */
- /* for checksum of struct ext4_group_desc do the rest...*/
- if (offset < size) {
- crc = ext2fs_crc16(crc, (char *)desc + offset,
- size - offset);
- }
+ crc = crc32 & 0xFFFF;
+ goto out;
}
+ /* old crc16 code */
+ offset = offsetof(struct ext2_group_desc, bg_checksum);
+ crc = ext2fs_crc16(~0, fs->super->s_uuid,
+ sizeof(fs->super->s_uuid));
+ crc = ext2fs_crc16(crc, &group, sizeof(group));
+ crc = ext2fs_crc16(crc, desc, offset);
+ offset += sizeof(desc->bg_checksum); /* skip checksum */
+ /* for checksum of struct ext4_group_desc do the rest...*/
+ if (offset < size) {
+ crc = ext2fs_crc16(crc, (char *)desc + offset,
+ size - offset);
+ }
+#ifdef WORDS_BIGENDIAN
+ /*
+ * If the size of the bg descriptor is greater than 64
+ * bytes, which is the size of the traditional ext4 bg
+ * descriptor, checksum the rest of the descriptor here
+ */
+ if (save_size > ext4_bg_size)
+ crc = ext2fs_crc16(crc, (char *)save_desc + ext4_bg_size,
+ save_size - ext4_bg_size);
+#endif
+
+out:
return crc;
}
int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
{
- if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
+ if (ext2fs_has_group_desc_csum(fs) &&
(ext2fs_bg_checksum(fs, group) !=
ext2fs_group_desc_csum(fs, group)))
return 0;
void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
{
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+ if (!ext2fs_has_group_desc_csum(fs))
return;
/* ext2fs_bg_checksum_set() sets the actual checksum field but
if (!fs->inode_map)
return EXT2_ET_NO_INODE_BITMAP;
- if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+ if (!ext2fs_has_group_desc_csum(fs))
return 0;
for (i = 0; i < fs->group_desc_count; i++) {
__u32 old_unused = ext2fs_bg_itable_unused(fs, i);
__u32 old_flags = ext2fs_bg_flags(fs, i);
__u32 old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i);
+ __u32 old_free_blocks_count = ext2fs_bg_free_blocks_count(fs, i);
+
+ if (old_free_blocks_count == sb->s_blocks_per_group &&
+ i != fs->group_desc_count - 1)
+ ext2fs_bg_flags_set(fs, i, EXT2_BG_BLOCK_UNINIT);
if (old_free_inodes_count == sb->s_inodes_per_group) {
ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
{
__u16 crc1, crc2, crc3;
dgrp_t swabgroup;
- struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc, group);
- size_t size;
+ struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
+ group);
+ size_t size = EXT2_DESC_SIZE(fs->super);
struct ext2_super_block *sb = fs->super;
int offset = offsetof(struct ext2_group_desc, bg_checksum);
#ifdef WORDS_BIGENDIAN
struct ext4_group_desc swabdesc;
+ struct ext2_group_desc *save_desc = desc;
+ const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
+ size_t save_size = size;
#endif
- size = fs->super->s_desc_size;
- if (size < EXT2_MIN_DESC_SIZE)
- size = EXT2_MIN_DESC_SIZE;
- if (size > sizeof(struct ext4_group_desc))
- size = sizeof(struct ext4_group_desc);
#ifdef WORDS_BIGENDIAN
/* Have to swab back to little-endian to do the checksum */
+ if (size > ext4_bg_size)
+ size = ext4_bg_size;
memcpy(&swabdesc, desc, size);
ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
desc = (struct ext2_group_desc *) &swabdesc;
/* for checksum of struct ext4_group_desc do the rest...*/
if (offset < size)
crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset);
+#ifdef WORDS_BIGENDIAN
+ if (save_size > ext4_bg_size)
+ crc3 = ext2fs_crc16(crc3, (char *)save_desc + ext4_bg_size,
+ save_size - ext4_bg_size);
+#endif
- printf("%s: UUID %s(%04x), grp %u(%04x): %04x=%04x\n",
+ printf("%s UUID %s=%04x, grp %u=%04x: %04x=%04x\n",
msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2, crc3,
ext2fs_group_desc_csum(fs, group));
}
memset(¶m, 0, sizeof(param));
ext2fs_blocks_count_set(¶m, 32768);
+#if 0
+ param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT;
+ param.s_desc_size = 128;
+ csum_known = 0x5b6e;
+#endif
retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m,
test_io_manager, &fs);
printf("checksums for different data shouldn't match\n");
exit(1);
}
+ ext2fs_free(fs);
return 0;
}