]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - lib/ext2fs/csum.c
Merge branch 'master' into next
[thirdparty/e2fsprogs.git] / lib / ext2fs / csum.c
CommitLineData
ca2634a4
JS
1/*
2 * csum.c --- checksumming of ext3 structures
3 *
4 * Copyright (C) 2006 Cluster File Systems, Inc.
470e737a 5 * Copyright (C) 2006, 2007 by Andreas Dilger <adilger@clusterfs.com>
ca2634a4
JS
6 *
7 * %Begin-Header%
543547a5
TT
8 * This file may be redistributed under the terms of the GNU Library
9 * General Public License, version 2.
ca2634a4
JS
10 * %End-Header%
11 */
12
0eeec8ac
TT
13#if HAVE_SYS_TYPES_H
14#include <sys/types.h>
15#endif
16
ca2634a4
JS
17#include "ext2_fs.h"
18#include "ext2fs.h"
19#include "crc16.h"
20#include <assert.h>
21
22#ifndef offsetof
23#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
24#endif
25
26#ifdef DEBUG
27#define STATIC
28#else
29#define STATIC static
30#endif
31
32STATIC __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
33{
34 __u16 crc = 0;
35 struct ext2_group_desc *desc;
1d18a55c
TT
36 size_t size;
37
38 size = fs->super->s_desc_size;
39 if (size < EXT2_MIN_DESC_SIZE)
40 size = EXT2_MIN_DESC_SIZE;
41 if (size > sizeof(struct ext4_group_desc)) {
42 printf("%s: illegal s_desc_size(%zd)\n", __func__, size);
43 size = sizeof(struct ext4_group_desc);
44 }
ca2634a4 45
d7cca6b0 46 desc = ext2fs_group_desc(fs, fs->group_desc, group);
ca2634a4
JS
47
48 if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
49 int offset = offsetof(struct ext2_group_desc, bg_checksum);
50
51#ifdef WORDS_BIGENDIAN
1d18a55c 52 struct ext4_group_desc swabdesc;
ca2634a4
JS
53
54 /* Have to swab back to little-endian to do the checksum */
1d18a55c
TT
55 memcpy(&swabdesc, desc, size);
56 ext2fs_swap_group_desc2(fs,
57 (struct ext2_group_desc *) &swabdesc);
58 desc = (struct ext2_group_desc *) &swabdesc;
ca2634a4
JS
59
60 group = ext2fs_swab32(group);
61#endif
c4dcb1c1
TT
62 crc = ext2fs_crc16(~0, fs->super->s_uuid,
63 sizeof(fs->super->s_uuid));
64 crc = ext2fs_crc16(crc, &group, sizeof(group));
65 crc = ext2fs_crc16(crc, desc, offset);
ca2634a4 66 offset += sizeof(desc->bg_checksum); /* skip checksum */
ca2634a4 67 /* for checksum of struct ext4_group_desc do the rest...*/
1d18a55c 68 if (offset < size) {
c4dcb1c1 69 crc = ext2fs_crc16(crc, (char *)desc + offset,
1d18a55c 70 size - offset);
ca2634a4
JS
71 }
72 }
73
74 return crc;
75}
76
77int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
78{
4729455f
TT
79 if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
80 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
d7cca6b0 81 (ext2fs_bg_checksum(fs, group) !=
4729455f 82 ext2fs_group_desc_csum(fs, group)))
ca2634a4
JS
83 return 0;
84
85 return 1;
86}
87
88void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
89{
d7cca6b0
VAH
90 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
91 EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
92 return;
93
94 /* ext2fs_bg_checksum_set() sets the actual checksum field but
95 * does not calculate the checksum itself. */
96 ext2fs_bg_checksum_set(fs, group, ext2fs_group_desc_csum(fs, group));
ca2634a4
JS
97}
98
99static __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap,
100 __u32 inodes_per_grp, dgrp_t grp_no)
101{
102 ext2_ino_t i, start_ino, end_ino;
103
104 start_ino = grp_no * inodes_per_grp + 1;
105 end_ino = start_ino + inodes_per_grp - 1;
106
107 for (i = end_ino; i >= start_ino; i--) {
8f82ef98 108 if (ext2fs_fast_test_inode_bitmap2(bitmap, i))
ca2634a4
JS
109 return i - start_ino + 1;
110 }
111 return inodes_per_grp;
112}
113
114/* update the bitmap flags, set the itable high watermark, and calculate
115 * checksums for the group descriptors */
f628acea 116errcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
ca2634a4
JS
117{
118 struct ext2_super_block *sb = fs->super;
8895f43a 119 int dirty = 0;
ca2634a4
JS
120 dgrp_t i;
121
f628acea
AD
122 if (!fs->inode_map)
123 return EXT2_ET_NO_INODE_BITMAP;
124
16b851cd
TT
125 if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
126 EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
f628acea 127 return 0;
ca2634a4 128
d7cca6b0
VAH
129 for (i = 0; i < fs->group_desc_count; i++) {
130 unsigned int old_csum = ext2fs_bg_checksum(fs, i);
131 int old_unused = ext2fs_bg_itable_unused(fs, i);
132 unsigned int old_flags = ext2fs_bg_flags(fs, i);
133 int old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i);
ca2634a4 134
d7cca6b0
VAH
135 if (old_free_inodes_count == sb->s_inodes_per_group) {
136 ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
137 ext2fs_bg_itable_unused_set(fs, i, sb->s_inodes_per_group);
16b851cd 138 } else {
d7cca6b0
VAH
139 int unused =
140 sb->s_inodes_per_group -
ca2634a4 141 find_last_inode_ingrp(fs->inode_map,
d7cca6b0
VAH
142 sb->s_inodes_per_group, i);
143
144 ext2fs_bg_flags_clear(fs, i, EXT2_BG_INODE_UNINIT);
145 ext2fs_bg_itable_unused_set(fs, i, unused);
ca2634a4
JS
146 }
147
ca2634a4 148 ext2fs_group_desc_csum_set(fs, i);
d7cca6b0 149 if (old_flags != ext2fs_bg_flags(fs, i))
80fc4e69 150 dirty = 1;
d7cca6b0 151 if (old_unused != ext2fs_bg_itable_unused(fs, i))
80fc4e69 152 dirty = 1;
d7cca6b0 153 if (old_csum != ext2fs_bg_checksum(fs, i))
ca2634a4
JS
154 dirty = 1;
155 }
156 if (dirty)
157 ext2fs_mark_super_dirty(fs);
f628acea 158 return 0;
ca2634a4 159}
470e737a
TT
160
161#ifdef DEBUG
162void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
163{
164 __u16 crc1, crc2, crc3;
165 dgrp_t swabgroup;
cf828f1a 166 struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc, group);
1d18a55c 167 size_t size;
470e737a 168 struct ext2_super_block *sb = fs->super;
1d18a55c 169 int offset = offsetof(struct ext2_group_desc, bg_checksum);
470e737a 170#ifdef WORDS_BIGENDIAN
1d18a55c
TT
171 struct ext4_group_desc swabdesc;
172#endif
470e737a 173
1d18a55c
TT
174 size = fs->super->s_desc_size;
175 if (size < EXT2_MIN_DESC_SIZE)
176 size = EXT2_MIN_DESC_SIZE;
177 if (size > sizeof(struct ext4_group_desc))
178 size = sizeof(struct ext4_group_desc);
179#ifdef WORDS_BIGENDIAN
470e737a 180 /* Have to swab back to little-endian to do the checksum */
1d18a55c
TT
181 memcpy(&swabdesc, desc, size);
182 ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
183 desc = (struct ext2_group_desc *) &swabdesc;
470e737a
TT
184
185 swabgroup = ext2fs_swab32(group);
186#else
187 swabgroup = group;
188#endif
189
190 crc1 = ext2fs_crc16(~0, sb->s_uuid, sizeof(fs->super->s_uuid));
191 crc2 = ext2fs_crc16(crc1, &swabgroup, sizeof(swabgroup));
1d18a55c
TT
192 crc3 = ext2fs_crc16(crc2, desc, offset);
193 offset += sizeof(desc->bg_checksum); /* skip checksum */
194 /* for checksum of struct ext4_group_desc do the rest...*/
195 if (offset < size)
196 crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset);
197
470e737a
TT
198 printf("%s: UUID %016Lx%016Lx(%04x), grp %u(%04x): %04x=%04x\n",
199 msg, *(long long *)&sb->s_uuid, *(long long *)&sb->s_uuid[8],
200 crc1, group, crc2, crc3, ext2fs_group_desc_csum(fs, group));
201}
202
203unsigned char sb_uuid[16] = { 0x4f, 0x25, 0xe8, 0xcf, 0xe7, 0x97, 0x48, 0x23,
204 0xbe, 0xfa, 0xa7, 0x88, 0x4b, 0xae, 0xec, 0xdb };
205
206int main(int argc, char **argv)
207{
208 struct ext2_super_block param;
209 errcode_t retval;
210 ext2_filsys fs;
211 int i;
212 __u16 csum1, csum2, csum_known = 0xd3a4;
213
214 memset(&param, 0, sizeof(param));
4efbac6f 215 ext2fs_blocks_count_set(&param, 32768);
470e737a 216
8f82ef98 217 retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
470e737a
TT
218 test_io_manager, &fs);
219 if (retval) {
220 com_err("setup", retval,
221 "While initializing filesystem");
222 exit(1);
223 }
224 memcpy(fs->super->s_uuid, sb_uuid, 16);
225 fs->super->s_feature_ro_compat = EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
226
227 for (i=0; i < fs->group_desc_count; i++) {
d7cca6b0
VAH
228 ext2fs_block_bitmap_loc_set(fs, i, 124);
229 ext2fs_inode_bitmap_loc_set(fs, i, 125);
230 ext2fs_inode_table_loc_set(fs, i, 126);
231 ext2fs_bg_free_blocks_count_set(fs, i, 31119);
232 ext2fs_bg_free_inodes_count_set(fs, i, 15701);
233 ext2fs_bg_used_dirs_count_set(fs, i, 2);
e633b58a 234 ext2fs_bg_flags_zap(fs, i);
470e737a
TT
235 };
236
237 csum1 = ext2fs_group_desc_csum(fs, 0);
238 print_csum("csum0000", fs, 0);
239
240 if (csum1 != csum_known) {
241 printf("checksum for group 0 should be %04x\n", csum_known);
242 exit(1);
243 }
244 csum2 = ext2fs_group_desc_csum(fs, 1);
245 print_csum("csum0001", fs, 1);
246 if (csum1 == csum2) {
247 printf("checksums for different groups shouldn't match\n");
248 exit(1);
249 }
250 csum2 = ext2fs_group_desc_csum(fs, 2);
251 print_csum("csumffff", fs, 2);
252 if (csum1 == csum2) {
253 printf("checksums for different groups shouldn't match\n");
254 exit(1);
255 }
d7cca6b0 256 ext2fs_bg_checksum_set(fs, 0, csum1);
470e737a
TT
257 csum2 = ext2fs_group_desc_csum(fs, 0);
258 print_csum("csum_set", fs, 0);
259 if (csum1 != csum2) {
260 printf("checksums should not depend on checksum field\n");
261 exit(1);
262 }
263 if (!ext2fs_group_desc_csum_verify(fs, 0)) {
264 printf("checksums should verify against gd_checksum\n");
265 exit(1);
266 }
267 memset(fs->super->s_uuid, 0x30, sizeof(fs->super->s_uuid));
268 print_csum("new_uuid", fs, 0);
269 if (ext2fs_group_desc_csum_verify(fs, 0) != 0) {
270 printf("checksums for different filesystems shouldn't match\n");
271 exit(1);
272 }
d7cca6b0
VAH
273 csum1 = ext2fs_group_desc_csum(fs, 0);
274 ext2fs_bg_checksum_set(fs, 0, csum1);
470e737a 275 print_csum("csum_new", fs, 0);
d7cca6b0 276 ext2fs_bg_free_blocks_count_set(fs, 0, 1);
470e737a
TT
277 csum2 = ext2fs_group_desc_csum(fs, 0);
278 print_csum("csum_blk", fs, 0);
279 if (csum1 == csum2) {
280 printf("checksums for different data shouldn't match\n");
281 exit(1);
282 }
283
284 return 0;
285}
286#endif