Whamcloud - gitweb
libext2fs: add gnu.translator support
[tools/e2fsprogs.git] / lib / ext2fs / csum.c
index 9f08c38..9b0b790 100644 (file)
 #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);
@@ -41,8 +51,7 @@ int ext2fs_mmp_csum_verify(ext2_filsys fs, struct mmp_struct *mmp)
 {
        __u32 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;
 
        calculated = ext2fs_mmp_csum(fs, mmp);
@@ -54,8 +63,7 @@ errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp)
 {
        __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;
 
        crc = ext2fs_mmp_csum(fs, mmp);
@@ -66,8 +74,7 @@ errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp)
 
 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;
@@ -81,12 +88,17 @@ static __u32 ext2fs_superblock_csum(ext2_filsys fs EXT2FS_ATTR((unused)),
        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 (!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 1;
 
        calculated = ext2fs_superblock_csum(fs, sb);
@@ -94,13 +106,18 @@ int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *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);
@@ -135,8 +152,7 @@ int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
        __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);
@@ -153,8 +169,7 @@ errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
        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);
@@ -251,14 +266,15 @@ static errcode_t __get_dirent_tail(ext2_filsys fs,
        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 *)(((char *)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;
 
@@ -275,7 +291,8 @@ static errcode_t __get_dirent_tail(ext2_filsys fs,
 
 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,
@@ -432,8 +449,7 @@ static errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum,
 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)
@@ -447,8 +463,7 @@ int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
 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)
@@ -506,8 +521,7 @@ int ext2fs_extent_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
         * 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);
@@ -525,8 +539,7 @@ errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
        __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;
 
        /*
@@ -547,13 +560,12 @@ int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
                        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;
@@ -568,13 +580,12 @@ errcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
        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;
@@ -587,13 +598,12 @@ int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
                        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;
@@ -608,13 +618,12 @@ errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
        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;
@@ -626,7 +635,7 @@ static errcode_t ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
 {
        __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;
 
@@ -658,9 +667,7 @@ int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
        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 &&
@@ -702,9 +709,7 @@ 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 &&
@@ -723,8 +728,7 @@ __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 size = EXT2_DESC_SIZE(fs->super);
-       size_t offset;
+       size_t offset, size = EXT2_DESC_SIZE(fs->super);
        __u16 crc = 0;
 #ifdef WORDS_BIGENDIAN
        struct ext4_group_desc swabdesc;
@@ -741,8 +745,7 @@ __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
        group = ext2fs_swab32(group);
 #endif
 
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       if (ext2fs_has_feature_metadata_csum(fs->super)) {
                /* new metadata csum code */
                __u16 old_crc;
                __u32 crc32;
@@ -757,8 +760,8 @@ __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
 #ifdef WORDS_BIGENDIAN
                if (save_size > ext4_bg_size)
                        crc32 = ext2fs_crc32c_le(crc32,
-                                          (char *)save_desc + ext4_bg_size,
-                                          save_size - ext4_bg_size);
+                                    (unsigned char *)save_desc + ext4_bg_size,
+                                    save_size - ext4_bg_size);
 #endif
                crc = crc32 & 0xFFFF;
                goto out;
@@ -845,6 +848,11 @@ errcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
                __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);
@@ -1007,6 +1015,7 @@ int main(int argc, char **argv)
                printf("checksums for different data shouldn't match\n");
                exit(1);
        }
+       ext2fs_free(fs);
 
        return 0;
 }