csum.c revision 77b3e9871877fce9908b0696250787fd6ea61af9
1ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos/*
2ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos * csum.c --- checksumming of ext3 structures
3ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos *
4ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos * Copyright (C) 2006 Cluster File Systems, Inc.
5470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o * Copyright (C) 2006, 2007 by Andreas Dilger <adilger@clusterfs.com>
6ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos *
7ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos * %Begin-Header%
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
9543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
10ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos * %End-Header%
11ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos */
12ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
13d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h"
140eeec8ac61bf1eaa31533b2be825cd75580829c9Theodore Ts'o#if HAVE_SYS_TYPES_H
150eeec8ac61bf1eaa31533b2be825cd75580829c9Theodore Ts'o#include <sys/types.h>
160eeec8ac61bf1eaa31533b2be825cd75580829c9Theodore Ts'o#endif
170eeec8ac61bf1eaa31533b2be825cd75580829c9Theodore Ts'o
18ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#include "ext2_fs.h"
19ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#include "ext2fs.h"
20ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#include "crc16.h"
21ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#include <assert.h>
22ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
23ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#ifndef offsetof
24ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
25ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#endif
26ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
27ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#ifdef DEBUG
28ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#define STATIC
29ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#else
30ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#define STATIC static
31ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#endif
32ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
33a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wongstatic __u32 ext2fs_mmp_csum(ext2_filsys fs, struct mmp_struct *mmp)
34a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong{
35a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	int offset = offsetof(struct mmp_struct, mmp_checksum);
36a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
37a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	return ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)mmp, offset);
38a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong}
39a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
40a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wongint ext2fs_mmp_csum_verify(ext2_filsys fs, struct mmp_struct *mmp)
41a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong{
42a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	__u32 calculated;
43a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
4477b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
45a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong		return 1;
46a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
47a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	calculated = ext2fs_mmp_csum(fs, mmp);
48a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
49a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	return ext2fs_le32_to_cpu(mmp->mmp_checksum) == calculated;
50a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong}
51a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
52a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wongerrcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp)
53a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong{
54a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	__u32 crc;
55a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
5677b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
57a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong		return 0;
58a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
59a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	crc = ext2fs_mmp_csum(fs, mmp);
60a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	mmp->mmp_checksum = ext2fs_cpu_to_le32(crc);
61a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
62a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	return 0;
63a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong}
64a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
651eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wongint ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb)
661eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong{
6777b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
681eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong		return 1;
691eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong
701eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong	return sb->s_checksum_type == EXT2_CRC32C_CHKSUM;
711eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong}
721eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong
73894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'ostatic __u32 ext2fs_superblock_csum(ext2_filsys fs EXT2FS_ATTR((unused)),
74894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o				    struct ext2_super_block *sb)
75d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong{
76d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	int offset = offsetof(struct ext2_super_block, s_checksum);
77d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
78d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	return ext2fs_crc32c_le(~0, (unsigned char *)sb, offset);
79d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong}
80d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
812432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong/* NOTE: The input to this function MUST be in LE order */
82d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wongint ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb)
83d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong{
842432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	__u32 flag, calculated;
85d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
862432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	if (fs->flags & EXT2_FLAG_SWAP_BYTES)
872432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong		flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM;
882432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	else
892432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong		flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
902432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong
912432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag))
92d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong		return 1;
93d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
94d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	calculated = ext2fs_superblock_csum(fs, sb);
95d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
96d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	return ext2fs_le32_to_cpu(sb->s_checksum) == calculated;
97d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong}
98d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
992432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong/* NOTE: The input to this function MUST be in LE order */
100d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wongerrcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
101d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong				     struct ext2_super_block *sb)
102d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong{
1032432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	__u32 flag, crc;
104d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
1052432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	if (fs->flags & EXT2_FLAG_SWAP_BYTES)
1062432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong		flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM;
1072432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	else
1082432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong		flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
1092432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong
1102432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag))
111d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong		return 0;
112d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
113d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	crc = ext2fs_superblock_csum(fs, sb);
114d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	sb->s_checksum = ext2fs_cpu_to_le32(crc);
115d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
116d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	return 0;
117d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong}
118d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
119894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'ostatic errcode_t ext2fs_ext_attr_block_csum(ext2_filsys fs,
120894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o					    ext2_ino_t inum EXT2FS_ATTR((unused)),
12139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					    blk64_t block,
12239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					    struct ext2_ext_attr_header *hdr,
12339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					    __u32 *crc)
12439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong{
12539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	char *buf = (char *)hdr;
1261b8c4c1b45482363e29bd4cca483d84645f8ac9dAndreas Dilger	__u32 old_crc = hdr->h_checksum;
12739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
12839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	hdr->h_checksum = 0;
12939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	block = ext2fs_cpu_to_le64(block);
13039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&block,
13139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				sizeof(block));
13239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, fs->blocksize);
13339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	hdr->h_checksum = old_crc;
13439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
13539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	return 0;
13639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong}
13739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
13839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wongint ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
13939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				      blk64_t block,
14039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				      struct ext2_ext_attr_header *hdr)
14139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong{
14239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	__u32 calculated;
14339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	errcode_t retval;
14439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
14577b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
14639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		return 1;
14739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
14839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &calculated);
14939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	if (retval)
15039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		return 0;
15139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
15239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	return ext2fs_le32_to_cpu(hdr->h_checksum) == calculated;
15339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong}
15439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
15539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wongerrcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
15639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					 blk64_t block,
15739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					 struct ext2_ext_attr_header *hdr)
15839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong{
15939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	errcode_t retval;
16039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	__u32 crc;
16139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
16277b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
16339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		return 0;
16439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
16539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &crc);
16639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	if (retval)
16739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		return retval;
16839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	hdr->h_checksum = ext2fs_cpu_to_le32(crc);
16939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	return 0;
17039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong}
17139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
172dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic __u16 do_nothing16(__u16 x)
173dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
174dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return x;
175dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
176dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
177dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic __u16 disk_to_host16(__u16 x)
178dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
179dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return ext2fs_le16_to_cpu(x);
180dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
181dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
182dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic errcode_t __get_dx_countlimit(ext2_filsys fs,
183dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				     struct ext2_dir_entry *dirent,
184dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				     struct ext2_dx_countlimit **cc,
185dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				     int *offset,
186dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				     int need_swab)
187dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
188dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dir_entry *dp;
189dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_root_info *root;
190dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_countlimit *c;
191dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	int count_offset, max_sane_entries;
192dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	unsigned int rec_len;
193dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	__u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16);
194dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
195dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	rec_len = translate(dirent->rec_len);
196dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
197dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (rec_len == fs->blocksize && translate(dirent->name_len) == 0)
198dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		count_offset = 8;
199dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	else if (rec_len == 12) {
200894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o		dp = (struct ext2_dir_entry *)(((char *)dirent) + rec_len);
201dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		rec_len = translate(dp->rec_len);
202dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		if (rec_len != fs->blocksize - 12)
203dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong			return EXT2_ET_DB_NOT_FOUND;
204894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o		root = (struct ext2_dx_root_info *)(((char *)dp + 12));
205dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		if (root->reserved_zero ||
206dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		    root->info_length != sizeof(struct ext2_dx_root_info))
207dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong			return EXT2_ET_DB_NOT_FOUND;
208dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		count_offset = 32;
209dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	} else
210dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return EXT2_ET_DB_NOT_FOUND;
211dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
212894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o	c = (struct ext2_dx_countlimit *)(((char *)dirent) + count_offset);
213dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	max_sane_entries = (fs->blocksize - count_offset) /
214dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong			   sizeof(struct ext2_dx_entry);
215dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (ext2fs_le16_to_cpu(c->limit) > max_sane_entries ||
216dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	    ext2fs_le16_to_cpu(c->count) > max_sane_entries)
217dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
218dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
219dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (offset)
220dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		*offset = count_offset;
221dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (cc)
222dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		*cc = c;
223dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
224dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return 0;
225dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
226dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
227dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongerrcode_t ext2fs_get_dx_countlimit(ext2_filsys fs,
228dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				   struct ext2_dir_entry *dirent,
229dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				   struct ext2_dx_countlimit **cc,
230dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				   int *offset)
231dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
232dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return __get_dx_countlimit(fs, dirent, cc, offset, 0);
233dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
234dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
23581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongvoid ext2fs_initialize_dirent_tail(ext2_filsys fs,
23681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				   struct ext2_dir_entry_tail *t)
23781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
23881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	memset(t, 0, sizeof(struct ext2_dir_entry_tail));
23981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	ext2fs_set_rec_len(fs, sizeof(struct ext2_dir_entry_tail),
24081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong			   (struct ext2_dir_entry *)t);
24181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	t->det_reserved_name_len = EXT2_DIR_NAME_LEN_CSUM;
24281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
24381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
24481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongstatic errcode_t __get_dirent_tail(ext2_filsys fs,
24581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				   struct ext2_dir_entry *dirent,
24681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				   struct ext2_dir_entry_tail **tt,
24781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				   int need_swab)
24881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
24981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_dir_entry *d;
25081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	void *top;
25181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_dir_entry_tail *t;
25281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	unsigned int rec_len;
25381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	errcode_t retval = 0;
25481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	__u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16);
25581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
25681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	d = dirent;
25781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	top = EXT2_DIRENT_TAIL(dirent, fs->blocksize);
25881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
25981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	rec_len = translate(d->rec_len);
26081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	while (rec_len && !(rec_len & 0x3)) {
261894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o		d = (struct ext2_dir_entry *)(((char *)d) + rec_len);
26281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		if ((void *)d >= top)
26381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong			break;
26481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		rec_len = translate(d->rec_len);
26581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	}
26681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
26781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (d != top)
26881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
26981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
27081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	t = (struct ext2_dir_entry_tail *)d;
27181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (t->det_reserved_zero1 ||
27281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	    translate(t->det_rec_len) != sizeof(struct ext2_dir_entry_tail) ||
27381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	    translate(t->det_reserved_name_len) != EXT2_DIR_NAME_LEN_CSUM)
27481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
27581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
27681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (tt)
27781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		*tt = t;
27881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return retval;
27981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
28081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
28181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongint ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent)
28281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
28381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return __get_dirent_tail(fs, dirent, NULL, 0) == 0;
28481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
28581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
28681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongstatic errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum,
28781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				    struct ext2_dir_entry *dirent, __u32 *crc,
28881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				    int size)
28981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
29081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	errcode_t retval;
29181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	char *buf = (char *)dirent;
29281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	__u32 gen;
29381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_inode inode;
29481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
29581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = ext2fs_read_inode(fs, inum, &inode);
29681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
29781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return retval;
29881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
29981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	inum = ext2fs_cpu_to_le32(inum);
30081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	gen = ext2fs_cpu_to_le32(inode.i_generation);
30181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
30281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				sizeof(inum));
30381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
30481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size);
30581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
30681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return 0;
30781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
30881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
30981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongint ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum,
31081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong			      struct ext2_dir_entry *dirent)
31181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
31281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	errcode_t retval;
31381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	__u32 calculated;
31481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_dir_entry_tail *t;
31581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
31681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = __get_dirent_tail(fs, dirent, &t, 1);
31781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
31881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 1;
31981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
32081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	/*
32181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	 * The checksum field is overlaid with the dirent->name field
32281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	 * so the swapfs.c functions won't change the endianness.
32381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	 */
32481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = ext2fs_dirent_csum(fs, inum, dirent, &calculated,
325894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o				    (char *)t - (char *)dirent);
32681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
32781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 0;
32881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return ext2fs_le32_to_cpu(t->det_checksum) == calculated;
32981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
33081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
33181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongstatic errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum,
33281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong					struct ext2_dir_entry *dirent)
33381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
33481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	errcode_t retval;
33581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	__u32 crc;
33681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_dir_entry_tail *t;
33781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
33881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = __get_dirent_tail(fs, dirent, &t, 1);
33981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
34081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return retval;
34181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
34281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	/* swapfs.c functions don't change the checksum endianness */
34381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = ext2fs_dirent_csum(fs, inum, dirent, &crc,
344894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o				    (char *)t - (char *)dirent);
34581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
34681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return retval;
34781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	t->det_checksum = ext2fs_cpu_to_le32(crc);
34881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return 0;
34981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
35081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
351dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
352dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				struct ext2_dir_entry *dirent,
353dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				__u32 *crc, int count_offset, int count,
354dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				struct ext2_dx_tail *t)
355dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
356dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	errcode_t retval;
357dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	char *buf = (char *)dirent;
358dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	int size;
359dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	__u32 old_csum, gen;
360dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_inode inode;
361dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
362dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	size = count_offset + (count * sizeof(struct ext2_dx_entry));
363dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	old_csum = t->dt_checksum;
364dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t->dt_checksum = 0;
365dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
366dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = ext2fs_read_inode(fs, inum, &inode);
367dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
368dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return retval;
369dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
370dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	inum = ext2fs_cpu_to_le32(inum);
371dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	gen = ext2fs_cpu_to_le32(inode.i_generation);
372dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
373dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				sizeof(inum));
374dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
375dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size);
376dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)t,
377dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				sizeof(struct ext2_dx_tail));
378dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t->dt_checksum = old_csum;
379dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
380dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return 0;
381dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
382dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
383dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum,
384dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				 struct ext2_dir_entry *dirent)
385dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
386dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	__u32 calculated;
387dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	errcode_t retval;
388dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_countlimit *c;
389dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_tail *t;
390dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	int count_offset, limit, count;
391dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
392dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
393dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
394dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return 1;
395dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	limit = ext2fs_le16_to_cpu(c->limit);
396dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	count = ext2fs_le16_to_cpu(c->count);
397dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
398dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	    fs->blocksize - sizeof(struct ext2_dx_tail))
399dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return 0;
400dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	/* htree structs are accessed in LE order */
401dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
402dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, count_offset,
403dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				count, t);
404dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
405dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return 0;
406dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
407dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return ext2fs_le32_to_cpu(t->dt_checksum) == calculated;
408dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
409dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
410dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum,
411dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				    struct ext2_dir_entry *dirent)
412dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
413dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	__u32 crc;
414dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	errcode_t retval = 0;
415dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_countlimit *c;
416dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_tail *t;
417dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	int count_offset, limit, count;
418dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
419dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
420dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
421dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return retval;
422dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	limit = ext2fs_le16_to_cpu(c->limit);
423dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	count = ext2fs_le16_to_cpu(c->count);
424dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
425dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	    fs->blocksize - sizeof(struct ext2_dx_tail))
426dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
427dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
428dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
429dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	/* htree structs are accessed in LE order */
430dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = ext2fs_dx_csum(fs, inum, dirent, &crc, count_offset, count, t);
431dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
432dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return retval;
433dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t->dt_checksum = ext2fs_cpu_to_le32(crc);
434dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return retval;
435dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
436dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
43781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongint ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
43881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				 struct ext2_dir_entry *dirent)
43981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
44077b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
44181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 1;
44281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
44381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
44481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return ext2fs_dirent_csum_verify(fs, inum, dirent);
44581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0)
44681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return ext2fs_dx_csum_verify(fs, inum, dirent);
44781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
44881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return 0;
44981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
45081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
45181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongerrcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
45281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				    struct ext2_dir_entry *dirent)
45381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
45477b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
45581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 0;
45681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
45781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
45881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return ext2fs_dirent_csum_set(fs, inum, dirent);
45981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0)
46081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return ext2fs_dx_csum_set(fs, inum, dirent);
46181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
46281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)
46381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 0;
46481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
46581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
46681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
46741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong#define EXT3_EXTENT_TAIL_OFFSET(hdr)	(sizeof(struct ext3_extent_header) + \
46841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	(sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
46941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
47041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wongstatic struct ext3_extent_tail *get_extent_tail(struct ext3_extent_header *h)
47141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong{
472894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o	return (struct ext3_extent_tail *)(((char *)h) +
47341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong					   EXT3_EXTENT_TAIL_OFFSET(h));
47441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong}
47541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
47641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wongstatic errcode_t ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum,
47741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong					  struct ext3_extent_header *eh,
47841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong					  __u32 *crc)
47941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong{
48041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	int size;
48141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	__u32 gen;
48241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	errcode_t retval;
48341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	struct ext2_inode inode;
48441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
48541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	size = EXT3_EXTENT_TAIL_OFFSET(eh) + offsetof(struct ext3_extent_tail,
48641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong						      et_checksum);
48741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
48841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	retval = ext2fs_read_inode(fs, inum, &inode);
48941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	if (retval)
49041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return retval;
49141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	inum = ext2fs_cpu_to_le32(inum);
49241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	gen = ext2fs_cpu_to_le32(inode.i_generation);
49341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
49441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong				sizeof(inum));
49541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
49641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)eh, size);
49741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
49841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	return 0;
49941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong}
50041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
50141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wongint ext2fs_extent_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
50241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong				    struct ext3_extent_header *eh)
50341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong{
50441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	errcode_t retval;
50541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	__u32 provided, calculated;
50641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	struct ext3_extent_tail *t = get_extent_tail(eh);
50741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
50841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	/*
50941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 * The extent tree structures are accessed in LE order, so we must
51041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 * swap the checksum bytes here.
51141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 */
51277b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
51341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return 1;
51441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
51541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	provided = ext2fs_le32_to_cpu(t->et_checksum);
51641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	retval = ext2fs_extent_block_csum(fs, inum, eh, &calculated);
51741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	if (retval)
51841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return 0;
51941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
52041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	return provided == calculated;
52141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong}
52241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
52341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wongerrcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
52441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong				       struct ext3_extent_header *eh)
52541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong{
52641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	errcode_t retval;
52741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	__u32 crc;
52841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	struct ext3_extent_tail *t = get_extent_tail(eh);
52941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
53077b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
53141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return 0;
53241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
53341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	/*
53441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 * The extent tree structures are accessed in LE order, so we must
53541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 * swap the checksum bytes here.
53641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 */
53741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	retval = ext2fs_extent_block_csum(fs, inum, eh, &crc);
53841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	if (retval)
53941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return retval;
54041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	t->et_checksum = ext2fs_cpu_to_le32(crc);
54141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	return retval;
54241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong}
54341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
544a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wongint ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
545a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong				    char *bitmap, int size)
546a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong{
547a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
548a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong			ext2fs_group_desc(fs, fs->group_desc, group);
549a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	__u32 provided, calculated;
550a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
55177b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
552a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		return 1;
553a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	provided = gdp->bg_inode_bitmap_csum_lo;
554a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap,
555a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong				      size);
556a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
557a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		provided |= (__u32)gdp->bg_inode_bitmap_csum_hi << 16;
558a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	else
559a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		calculated &= 0xFFFF;
560a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
561a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	return provided == calculated;
562a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong}
563a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
564a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wongerrcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
565a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong				       char *bitmap, int size)
566a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong{
567a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	__u32 crc;
568a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
569a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong			ext2fs_group_desc(fs, fs->group_desc, group);
570a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
57177b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
572a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		return 0;
573a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
574a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size);
575a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	gdp->bg_inode_bitmap_csum_lo = crc & 0xFFFF;
576a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
577a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		gdp->bg_inode_bitmap_csum_hi = crc >> 16;
578a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
579a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	return 0;
580a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong}
581a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
582e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wongint ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
583e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong				    char *bitmap, int size)
584e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong{
585e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
586e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong			ext2fs_group_desc(fs, fs->group_desc, group);
587e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	__u32 provided, calculated;
588e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
58977b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
590e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		return 1;
591e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	provided = gdp->bg_block_bitmap_csum_lo;
592e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap,
593e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong				      size);
594e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
595e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		provided |= (__u32)gdp->bg_block_bitmap_csum_hi << 16;
596e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	else
597e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		calculated &= 0xFFFF;
598e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
599e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	return provided == calculated;
600e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong}
601e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
602e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wongerrcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
603e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong				       char *bitmap, int size)
604e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong{
605e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	__u32 crc;
606e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
607e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong			ext2fs_group_desc(fs, fs->group_desc, group);
608e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
60977b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
610e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		return 0;
611e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
612e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size);
613e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	gdp->bg_block_bitmap_csum_lo = crc & 0xFFFF;
614e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
615e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		gdp->bg_block_bitmap_csum_hi = crc >> 16;
616e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
617e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	return 0;
618e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong}
619e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
62037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wongstatic errcode_t ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
62137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong			       struct ext2_inode_large *inode,
62237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong			       __u32 *crc, int has_hi)
62337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong{
62437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u32 gen;
62537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	struct ext2_inode_large *desc = inode;
62637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	size_t size = fs->super->s_inode_size;
62737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u16 old_lo;
62837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u16 old_hi = 0;
62937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
63037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	old_lo = inode->i_checksum_lo;
63137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	inode->i_checksum_lo = 0;
63237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (has_hi) {
63337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		old_hi = inode->i_checksum_hi;
63437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		inode->i_checksum_hi = 0;
63537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	}
63637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
63737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	inum = ext2fs_cpu_to_le32(inum);
63837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	gen = inode->i_generation;
63937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
64037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong				sizeof(inum));
64137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
64237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)desc, size);
64337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
64437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	inode->i_checksum_lo = old_lo;
64537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (has_hi)
64637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		inode->i_checksum_hi = old_hi;
64737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	return 0;
64837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong}
64937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
65037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wongint ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
65137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong			     struct ext2_inode_large *inode)
65237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong{
65337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	errcode_t retval;
65437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u32 provided, calculated;
655894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o	unsigned int i, has_hi;
65697fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	char *cp;
65737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
65837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (fs->super->s_creator_os != EXT2_OS_LINUX ||
65977b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	    !ext2fs_has_feature_metadata_csum(fs->super))
66037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		return 1;
66137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
66237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
66337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		  inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END);
66437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
66537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	provided = ext2fs_le16_to_cpu(inode->i_checksum_lo);
66637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	retval = ext2fs_inode_csum(fs, inum, inode, &calculated, has_hi);
66737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (retval)
66837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		return 0;
66937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (has_hi) {
67037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		__u32 hi = ext2fs_le16_to_cpu(inode->i_checksum_hi);
67137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		provided |= hi << 16;
67237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	} else
67337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		calculated &= 0xFFFF;
67437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
67597fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	if (provided == calculated)
67697fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o		return 1;
67797fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o
67897fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	/*
67997fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * If the checksum didn't match, it's possible it was due to
68097fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * the inode being all zero's.  It's unlikely this is the
68197fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * case, but it can happen.  So check for it here.  (We only
68297fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * check the base inode since that's good enough, and it's not
68397fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * worth the bother to figure out how much of the extended
68497fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * inode, if any, is present.)
68597fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 */
68697fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	for (cp = (char *) inode, i = 0;
68797fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	     i < sizeof(struct ext2_inode);
68897fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	     cp++, i++)
68997fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o		if (*cp)
69097fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o			return 0;
69197fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	return 1;		/* Inode must have been all zero's */
69237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong}
69337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
69437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wongerrcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
69537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong			   struct ext2_inode_large *inode)
69637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong{
69737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	errcode_t retval;
69837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u32 crc;
69937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	int has_hi;
70037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
70137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (fs->super->s_creator_os != EXT2_OS_LINUX ||
70277b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	    !ext2fs_has_feature_metadata_csum(fs->super))
70337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		return 0;
70437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
70537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
70637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		  inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END);
70737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
70837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	retval = ext2fs_inode_csum(fs, inum, inode, &crc, has_hi);
70937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (retval)
71037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		return retval;
71137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	inode->i_checksum_lo = ext2fs_cpu_to_le16(crc & 0xFFFF);
71237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (has_hi)
71337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		inode->i_checksum_hi = ext2fs_cpu_to_le16(crc >> 16);
71437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	return 0;
71537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong}
71637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
71787141781aabb4dc01359428d2feecdc7f43eeac0Theodore Ts'o__u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
718ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
7192bc30417541deffca795db8ec4e7f7ccb616dc3fAndreas Dilger	struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
7202bc30417541deffca795db8ec4e7f7ccb616dc3fAndreas Dilger							 group);
72171715a5a9ad409df162dbb58a4c3b6fd2c5868d5Theodore Ts'o	size_t offset, size = EXT2_DESC_SIZE(fs->super);
722ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	__u16 crc = 0;
723ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#ifdef WORDS_BIGENDIAN
7245b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	struct ext4_group_desc swabdesc;
7252ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	size_t save_size = size;
7262ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
7272ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	struct ext2_group_desc *save_desc = desc;
728ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
7295b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	/* Have to swab back to little-endian to do the checksum */
7302ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	if (size > ext4_bg_size)
7312ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o		size = ext4_bg_size;
7325b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	memcpy(&swabdesc, desc, size);
7332ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
7345b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	desc = (struct ext2_group_desc *) &swabdesc;
7355b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	group = ext2fs_swab32(group);
736ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#endif
7375b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong
73877b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (ext2fs_has_feature_metadata_csum(fs->super)) {
7395b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		/* new metadata csum code */
7405b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		__u16 old_crc;
7415b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		__u32 crc32;
7425b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong
7435b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		old_crc = desc->bg_checksum;
7445b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		desc->bg_checksum = 0;
7455b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		crc32 = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&group,
7465b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong					 sizeof(group));
7475b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		crc32 = ext2fs_crc32c_le(crc32, (unsigned char *)desc,
7485b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong					 size);
7495b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		desc->bg_checksum = old_crc;
750b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#ifdef WORDS_BIGENDIAN
751b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o		if (save_size > ext4_bg_size)
7522ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o			crc32 = ext2fs_crc32c_le(crc32,
7532432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong				     (unsigned char *)save_desc + ext4_bg_size,
7542432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	                             save_size - ext4_bg_size);
755b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#endif
7565b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		crc = crc32 & 0xFFFF;
7575b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		goto out;
758ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	}
759ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
7605b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	/* old crc16 code */
7612ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	offset = offsetof(struct ext2_group_desc, bg_checksum);
7625b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	crc = ext2fs_crc16(~0, fs->super->s_uuid,
7635b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong			   sizeof(fs->super->s_uuid));
7645b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	crc = ext2fs_crc16(crc, &group, sizeof(group));
7655b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	crc = ext2fs_crc16(crc, desc, offset);
7665b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	offset += sizeof(desc->bg_checksum); /* skip checksum */
7675b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	/* for checksum of struct ext4_group_desc do the rest...*/
7685b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	if (offset < size) {
7695b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		crc = ext2fs_crc16(crc, (char *)desc + offset,
7705b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong				   size - offset);
7715b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	}
7722ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o#ifdef WORDS_BIGENDIAN
7732ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	/*
7742ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	 * If the size of the bg descriptor is greater than 64
7752ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	 * bytes, which is the size of the traditional ext4 bg
7762ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	 * descriptor, checksum the rest of the descriptor here
7772ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	 */
7782ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	if (save_size > ext4_bg_size)
7792ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o		crc = ext2fs_crc16(crc, (char *)save_desc + ext4_bg_size,
7802ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o				   save_size - ext4_bg_size);
7812ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o#endif
7825b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong
7835b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wongout:
784ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	return crc;
785ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
786ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
787ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santosint ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
788ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
7895b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	if (ext2fs_has_group_desc_csum(fs) &&
790d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	    (ext2fs_bg_checksum(fs, group) !=
7914729455f0a68f2fa0a83ec8460d1d4bccba9dcfaTheodore Ts'o	     ext2fs_group_desc_csum(fs, group)))
792ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos		return 0;
793ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
794ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	return 1;
795ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
796ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
797ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santosvoid ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
798ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
7995b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	if (!ext2fs_has_group_desc_csum(fs))
800d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		return;
801d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson
802d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	/* ext2fs_bg_checksum_set() sets the actual checksum field but
803d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	 * does not calculate the checksum itself. */
804d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	ext2fs_bg_checksum_set(fs, group, ext2fs_group_desc_csum(fs, group));
805ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
806ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
807ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santosstatic __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap,
808ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos				   __u32 inodes_per_grp, dgrp_t grp_no)
809ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
810ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	ext2_ino_t i, start_ino, end_ino;
811ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
812ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	start_ino = grp_no * inodes_per_grp + 1;
813ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	end_ino = start_ino + inodes_per_grp - 1;
814ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
815ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	for (i = end_ino; i >= start_ino; i--) {
8168f82ef9860339039b54a324be137fbc09b762358Valerie Aurora Henson		if (ext2fs_fast_test_inode_bitmap2(bitmap, i))
817ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos			return i - start_ino + 1;
818ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	}
819ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	return inodes_per_grp;
820ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
821ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
822ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos/* update the bitmap flags, set the itable high watermark, and calculate
823ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos * checksums for the group descriptors */
824f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilgererrcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
825ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
826ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	struct ext2_super_block *sb = fs->super;
8278895f43a60269464f654e9d87c28768875cd703aTheodore Ts'o	int dirty = 0;
828ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	dgrp_t i;
829ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
830f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger	if (!fs->inode_map)
831f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger		return EXT2_ET_NO_INODE_BITMAP;
832f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger
8335b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	if (!ext2fs_has_group_desc_csum(fs))
834f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger		return 0;
835ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
836d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	for (i = 0; i < fs->group_desc_count; i++) {
837d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o		__u32 old_csum = ext2fs_bg_checksum(fs, i);
838d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o		__u32 old_unused = ext2fs_bg_itable_unused(fs, i);
839d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o		__u32 old_flags = ext2fs_bg_flags(fs, i);
840d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o		__u32 old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i);
841c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong		__u32 old_free_blocks_count = ext2fs_bg_free_blocks_count(fs, i);
842c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong
843c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong		if (old_free_blocks_count == sb->s_blocks_per_group &&
844c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong		    i != fs->group_desc_count - 1)
845c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong			ext2fs_bg_flags_set(fs, i, EXT2_BG_BLOCK_UNINIT);
846ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
847d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		if (old_free_inodes_count == sb->s_inodes_per_group) {
848d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
849d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			ext2fs_bg_itable_unused_set(fs, i, sb->s_inodes_per_group);
85016b851cdae98244e117fe91d93b267fcad1102b3Theodore Ts'o		} else {
851d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			int unused =
852d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson				sb->s_inodes_per_group -
853ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos				find_last_inode_ingrp(fs->inode_map,
854d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson						      sb->s_inodes_per_group, i);
855d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson
856d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			ext2fs_bg_flags_clear(fs, i, EXT2_BG_INODE_UNINIT);
857d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			ext2fs_bg_itable_unused_set(fs, i, unused);
858ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos		}
859ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
860ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos		ext2fs_group_desc_csum_set(fs, i);
861d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		if (old_flags != ext2fs_bg_flags(fs, i))
86280fc4e698a308de22ace6179f45e0bb67befa74bAndreas Dilger			dirty = 1;
863d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		if (old_unused != ext2fs_bg_itable_unused(fs, i))
86480fc4e698a308de22ace6179f45e0bb67befa74bAndreas Dilger			dirty = 1;
865d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		if (old_csum != ext2fs_bg_checksum(fs, i))
866ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos			dirty = 1;
867ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	}
868ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	if (dirty)
869ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos		ext2fs_mark_super_dirty(fs);
870f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger	return 0;
871ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
872470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
873470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#ifdef DEBUG
874c816ecb204a32e67788738e050ff2b14a721672bEric Sandeen#include "e2p/e2p.h"
875c816ecb204a32e67788738e050ff2b14a721672bEric Sandeen
876470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'ovoid print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
877470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o{
878470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	__u16 crc1, crc2, crc3;
879470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	dgrp_t swabgroup;
880b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
881b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o							 group);
882b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	size_t size = EXT2_DESC_SIZE(fs->super);
883470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	struct ext2_super_block *sb = fs->super;
8841d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	int offset = offsetof(struct ext2_group_desc, bg_checksum);
885470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#ifdef WORDS_BIGENDIAN
8861d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	struct ext4_group_desc swabdesc;
887b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	struct ext2_group_desc *save_desc = desc;
888b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
889b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	size_t save_size = size;
8901d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o#endif
891470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
8921d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o#ifdef WORDS_BIGENDIAN
893470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	/* Have to swab back to little-endian to do the checksum */
894b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	if (size > ext4_bg_size)
895b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o		size = ext4_bg_size;
8961d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	memcpy(&swabdesc, desc, size);
8971d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
8981d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	desc = (struct ext2_group_desc *) &swabdesc;
899470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
900470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	swabgroup = ext2fs_swab32(group);
901470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#else
902470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	swabgroup = group;
903470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#endif
904470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
905470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	crc1 = ext2fs_crc16(~0, sb->s_uuid, sizeof(fs->super->s_uuid));
906470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	crc2 = ext2fs_crc16(crc1, &swabgroup, sizeof(swabgroup));
9071d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	crc3 = ext2fs_crc16(crc2, desc, offset);
9081d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	offset += sizeof(desc->bg_checksum); /* skip checksum */
9091d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	/* for checksum of struct ext4_group_desc do the rest...*/
9101d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	if (offset < size)
9111d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o		crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset);
912b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#ifdef WORDS_BIGENDIAN
913b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	if (save_size > ext4_bg_size)
914b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o		crc3 = ext2fs_crc16(crc3, (char *)save_desc + ext4_bg_size,
915b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o				    save_size - ext4_bg_size);
916b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#endif
9171d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o
918f797cf3e37b476aac593fe9a9f4630448d335332Andreas Dilger	printf("%s UUID %s=%04x, grp %u=%04x: %04x=%04x\n",
919562f264243f4d4385910b6f06872730214977736Theodore Ts'o	       msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2, crc3,
920c816ecb204a32e67788738e050ff2b14a721672bEric Sandeen	       ext2fs_group_desc_csum(fs, group));
921470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o}
922470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
923470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'ounsigned char sb_uuid[16] = { 0x4f, 0x25, 0xe8, 0xcf, 0xe7, 0x97, 0x48, 0x23,
924470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o			      0xbe, 0xfa, 0xa7, 0x88, 0x4b, 0xae, 0xec, 0xdb };
925470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
926470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'oint main(int argc, char **argv)
927470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o{
928470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	struct ext2_super_block param;
929470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	errcode_t		retval;
930470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	ext2_filsys		fs;
931470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	int			i;
932470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	__u16 csum1, csum2, csum_known = 0xd3a4;
933470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
934470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	memset(&param, 0, sizeof(param));
9354efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	ext2fs_blocks_count_set(&param, 32768);
936b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#if 0
937b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT;
938b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	param.s_desc_size = 128;
939b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	csum_known = 0x5b6e;
940b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#endif
941470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
9428f82ef9860339039b54a324be137fbc09b762358Valerie Aurora Henson	retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
943470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o				   test_io_manager, &fs);
944470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (retval) {
945470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		com_err("setup", retval,
946470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o			"While initializing filesystem");
947470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
948470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
949470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	memcpy(fs->super->s_uuid, sb_uuid, 16);
950470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	fs->super->s_feature_ro_compat = EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
951470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
952470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	for (i=0; i < fs->group_desc_count; i++) {
953d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_block_bitmap_loc_set(fs, i, 124);
954d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_inode_bitmap_loc_set(fs, i, 125);
955d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_inode_table_loc_set(fs, i, 126);
956d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_bg_free_blocks_count_set(fs, i, 31119);
957d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_bg_free_inodes_count_set(fs, i, 15701);
958d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_bg_used_dirs_count_set(fs, i, 2);
959e633b58ac75f2f544b7d6572e37d4b63da31e59cEric Sandeen		ext2fs_bg_flags_zap(fs, i);
960470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	};
961470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
962470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum1 = ext2fs_group_desc_csum(fs, 0);
963470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum0000", fs, 0);
964470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
965470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 != csum_known) {
966470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksum for group 0 should be %04x\n", csum_known);
967470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
968470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
969470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum2 = ext2fs_group_desc_csum(fs, 1);
970470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum0001", fs, 1);
971470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 == csum2) {
972470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums for different groups shouldn't match\n");
973470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
974470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
975470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum2 = ext2fs_group_desc_csum(fs, 2);
976470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csumffff", fs, 2);
977470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 == csum2) {
978470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums for different groups shouldn't match\n");
979470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
980470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
981d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	ext2fs_bg_checksum_set(fs, 0, csum1);
982470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum2 = ext2fs_group_desc_csum(fs, 0);
983470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum_set", fs, 0);
984470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 != csum2) {
985470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums should not depend on checksum field\n");
986470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
987470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
988470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (!ext2fs_group_desc_csum_verify(fs, 0)) {
989470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums should verify against gd_checksum\n");
990470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
991470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
992470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	memset(fs->super->s_uuid, 0x30, sizeof(fs->super->s_uuid));
993470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("new_uuid", fs, 0);
994470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (ext2fs_group_desc_csum_verify(fs, 0) != 0) {
995470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums for different filesystems shouldn't match\n");
996470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
997470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
998d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	csum1 = ext2fs_group_desc_csum(fs, 0);
999d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	ext2fs_bg_checksum_set(fs, 0, csum1);
1000470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum_new", fs, 0);
1001d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	ext2fs_bg_free_blocks_count_set(fs, 0, 1);
1002470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum2 = ext2fs_group_desc_csum(fs, 0);
1003470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum_blk", fs, 0);
1004470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 == csum2) {
1005470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums for different data shouldn't match\n");
1006470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
1007470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
1008470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
1009470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	return 0;
1010470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o}
1011470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#endif
1012