Whamcloud - gitweb
libext2fs, libe2p, misc: git rid of jfs_user.h
[tools/e2fsprogs.git] / lib / ext2fs / csum.c
index 607f74a..6dcefb9 100644 (file)
@@ -81,12 +81,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 +99,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);
@@ -721,29 +731,22 @@ errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
 
 __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);
-
 #ifdef WORDS_BIGENDIAN
        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 */
+       if (size > ext4_bg_size)
+               size = ext4_bg_size;
        memcpy(&swabdesc, desc, size);
-       ext2fs_swap_group_desc2(fs,
-                               (struct ext2_group_desc *) &swabdesc);
+       ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
        desc = (struct ext2_group_desc *) &swabdesc;
-
        group = ext2fs_swab32(group);
 #endif
 
@@ -760,13 +763,18 @@ __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t 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 = crc32 & 0xFFFF;
                goto out;
        }
 
        /* old crc16 code */
-       size_t offset = offsetof(struct ext2_group_desc, bg_checksum);
+       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));
@@ -777,6 +785,16 @@ __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
                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;
@@ -836,6 +854,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);
@@ -870,22 +893,22 @@ void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
 {
        __u16 crc1, crc2, crc3;
        dgrp_t swabgroup;
-       struct ext2_group_desc *desc;
-       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
 
-       desc = ext2fs_group_desc(fs, fs->group_desc, group);
-       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;
@@ -902,6 +925,11 @@ void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
        /* 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",
               msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2, crc3,
@@ -921,6 +949,11 @@ int main(int argc, char **argv)
 
        memset(&param, 0, sizeof(param));
        ext2fs_blocks_count_set(&param, 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, &param,
                                   test_io_manager, &fs);