Whamcloud - gitweb
Merge branch 'maint' into next
[tools/e2fsprogs.git] / lib / ext2fs / csum.c
index 7f5d779..607f74a 100644 (file)
 #define STATIC static
 #endif
 
+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 (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               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 (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               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,
@@ -39,7 +73,8 @@ int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb)
        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);
 
@@ -74,15 +109,14 @@ errcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
        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);
@@ -158,11 +192,11 @@ static errcode_t __get_dx_countlimit(ext2_filsys fs,
        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;
@@ -170,7 +204,7 @@ static errcode_t __get_dx_countlimit(ext2_filsys fs,
        } 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 ||
@@ -219,7 +253,7 @@ static errcode_t __get_dirent_tail(ext2_filsys fs,
 
        rec_len = translate(d->rec_len);
        while (rec_len && !(rec_len & 0x3)) {
-               d = (struct ext2_dir_entry *)(((void *)d) + rec_len);
+               d = (struct ext2_dir_entry *)(((char *)d) + rec_len);
                if ((void *)d >= top)
                        break;
                rec_len = translate(d->rec_len);
@@ -283,7 +317,7 @@ int ext2fs_dirent_csum_verify(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;
@@ -302,7 +336,7 @@ static errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum,
 
        /* 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);
@@ -432,7 +466,7 @@ errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
 
 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));
 }
 
@@ -621,7 +655,8 @@ int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
 {
        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,
@@ -641,7 +676,23 @@ int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
        } 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,
@@ -819,7 +870,7 @@ void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
 {
        __u16 crc1, crc2, crc3;
        dgrp_t swabgroup;
-       struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc, group);
+       struct ext2_group_desc *desc;
        size_t size;
        struct ext2_super_block *sb = fs->super;
        int offset = offsetof(struct ext2_group_desc, bg_checksum);
@@ -827,6 +878,7 @@ void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
        struct ext4_group_desc swabdesc;
 #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;
@@ -851,7 +903,7 @@ void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
        if (offset < size)
                crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset);
 
-       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));
 }