Whamcloud - gitweb
libext2fs: Don't check the group checksum when !GDT_CSUM
[tools/e2fsprogs.git] / lib / ext2fs / csum.c
1 /*
2  * csum.c --- checksumming of ext3 structures
3  *
4  * Copyright (C) 2006 Cluster File Systems, Inc.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
11
12 #include "ext2_fs.h"
13 #include "ext2fs.h"
14 #include "crc16.h"
15 #include <assert.h>
16
17 #ifndef offsetof
18 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
19 #endif
20
21 #ifdef DEBUG
22 #define STATIC
23 #else
24 #define STATIC static
25 #endif
26
27 STATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
28 {
29         __u16 crc = 0;
30         struct ext2_group_desc *desc;
31
32         desc = &fs->group_desc[group];
33
34         if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
35                 int offset = offsetof(struct ext2_group_desc, bg_checksum);
36
37 #ifdef WORDS_BIGENDIAN
38                 struct ext2_group_desc swabdesc = *desc;
39
40                 /* Have to swab back to little-endian to do the checksum */
41                 ext2fs_swap_group_desc(&swabdesc);
42                 desc = &swabdesc;
43
44                 group = ext2fs_swab32(group);
45 #endif
46                 crc = crc16(~0, fs->super->s_uuid, sizeof(fs->super->s_uuid));
47                 crc = crc16(crc, &group, sizeof(group));
48                 crc = crc16(crc, desc, offset);
49                 offset += sizeof(desc->bg_checksum); /* skip checksum */
50                 assert(offset == sizeof(*desc));
51                 /* for checksum of struct ext4_group_desc do the rest...*/
52                 if (offset < fs->super->s_desc_size) {
53                         crc = crc16(crc, (char *)desc + offset,
54                                     fs->super->s_desc_size - offset);
55                 }
56         }
57
58         return crc;
59 }
60
61 int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
62 {
63         if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
64                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
65             (fs->group_desc[group].bg_checksum != 
66              ext2fs_group_desc_csum(fs, group)))
67                 return 0;
68
69         return 1;
70 }
71
72 void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
73 {
74         if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
75                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
76                 fs->group_desc[group].bg_checksum =
77                         ext2fs_group_desc_csum(fs, group);
78 }
79
80 static __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap,
81                                    __u32 inodes_per_grp, dgrp_t grp_no)
82 {
83         ext2_ino_t i, start_ino, end_ino;
84
85         start_ino = grp_no * inodes_per_grp + 1;
86         end_ino = start_ino + inodes_per_grp - 1;
87
88         for (i = end_ino; i >= start_ino; i--) {
89                 if (ext2fs_fast_test_inode_bitmap(bitmap, i))
90                         return i - start_ino + 1;
91         }
92         return inodes_per_grp;
93 }
94
95 /* update the bitmap flags, set the itable high watermark, and calculate
96  * checksums for the group descriptors */
97 errcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
98 {
99         struct ext2_super_block *sb = fs->super;
100         struct ext2_group_desc *bg = fs->group_desc;
101         int dirty = 0;
102         dgrp_t i;
103
104         if (!fs->inode_map)
105                 return EXT2_ET_NO_INODE_BITMAP;
106
107         if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
108                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
109                 return 0;
110
111         for (i = 0; i < fs->group_desc_count; i++, bg++) {
112                 int old_csum = bg->bg_checksum;
113                 int old_unused = bg->bg_itable_unused;
114                 int old_flags = bg->bg_flags;
115
116                 if (bg->bg_free_inodes_count == sb->s_inodes_per_group) {
117                         bg->bg_flags |= EXT2_BG_INODE_UNINIT;
118                         bg->bg_itable_unused = sb->s_inodes_per_group;
119                 } else {
120                         bg->bg_flags &= ~EXT2_BG_INODE_UNINIT;
121                         bg->bg_itable_unused = sb->s_inodes_per_group -
122                                 find_last_inode_ingrp(fs->inode_map,
123                                                       sb->s_inodes_per_group,i);
124                 }
125
126                 ext2fs_group_desc_csum_set(fs, i);
127                 if (old_flags != bg->bg_flags)
128                         dirty = 1;
129                 if (old_unused != bg->bg_itable_unused)
130                         dirty = 1;
131                 if (old_csum != bg->bg_checksum)
132                         dirty = 1;
133         }
134         if (dirty)
135                 ext2fs_mark_super_dirty(fs);
136         return 0;
137 }