Whamcloud - gitweb
20b235a443b966b3a68f388c884958024d1d480a
[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 (fs->group_desc[group].bg_checksum != 
64             ext2fs_group_desc_csum(fs, group))
65                 return 0;
66
67         return 1;
68 }
69
70 void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
71 {
72         fs->group_desc[group].bg_checksum = ext2fs_group_desc_csum(fs, group);
73 }
74
75 static __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap,
76                                    __u32 inodes_per_grp, dgrp_t grp_no)
77 {
78         ext2_ino_t i, start_ino, end_ino;
79
80         start_ino = grp_no * inodes_per_grp + 1;
81         end_ino = start_ino + inodes_per_grp - 1;
82
83         for (i = end_ino; i >= start_ino; i--) {
84                 if (ext2fs_fast_test_inode_bitmap(bitmap, i))
85                         return i - start_ino + 1;
86         }
87         return inodes_per_grp;
88 }
89
90 /* update the bitmap flags, set the itable high watermark, and calculate
91  * checksums for the group descriptors */
92 errcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
93 {
94         struct ext2_super_block *sb = fs->super;
95         struct ext2_group_desc *bg = fs->group_desc;
96         int blks, dirty = 0;
97         dgrp_t i;
98
99         if (!fs->inode_map)
100                 return EXT2_ET_NO_INODE_BITMAP;
101
102         if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
103                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
104                 return 0;
105
106         for (i = 0; i < fs->group_desc_count; i++, bg++) {
107                 int old_csum = bg->bg_checksum;
108                 int old_unused = bg->bg_itable_unused;
109                 int old_flags = bg->bg_flags;
110
111                 if (bg->bg_free_inodes_count == sb->s_inodes_per_group) {
112                         bg->bg_flags |= EXT2_BG_INODE_UNINIT;
113                         bg->bg_itable_unused = sb->s_inodes_per_group;
114                 } else {
115                         bg->bg_flags &= ~EXT2_BG_INODE_UNINIT;
116                         bg->bg_itable_unused = sb->s_inodes_per_group -
117                                 find_last_inode_ingrp(fs->inode_map,
118                                                       sb->s_inodes_per_group,i);
119                 }
120
121                 ext2fs_group_desc_csum_set(fs, i);
122                 if (old_flags != bg->bg_flags)
123                         dirty = 1;
124                 if (old_unused != bg->bg_itable_unused)
125                         dirty = 1;
126                 if (old_csum != bg->bg_checksum)
127                         dirty = 1;
128         }
129         if (dirty)
130                 ext2fs_mark_super_dirty(fs);
131         return 0;
132 }