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