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
332ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wongvoid ext2fs_init_csum_seed(ext2_filsys fs)
342ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wong{
352ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wong	if (ext2fs_has_feature_csum_seed(fs->super))
362ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wong		fs->csum_seed = fs->super->s_checksum_seed;
372ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wong	else if (ext2fs_has_feature_metadata_csum(fs->super))
382ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wong		fs->csum_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid,
392ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wong						 sizeof(fs->super->s_uuid));
402ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wong}
412ed0adbce68c0bbe7e1fc2cf23f009327f10441bDarrick J. Wong
42a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wongstatic __u32 ext2fs_mmp_csum(ext2_filsys fs, struct mmp_struct *mmp)
43a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong{
44a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	int offset = offsetof(struct mmp_struct, mmp_checksum);
45a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
46a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	return ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)mmp, offset);
47a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong}
48a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
49a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wongint ext2fs_mmp_csum_verify(ext2_filsys fs, struct mmp_struct *mmp)
50a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong{
51a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	__u32 calculated;
52a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
5377b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
54a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong		return 1;
55a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
56a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	calculated = ext2fs_mmp_csum(fs, mmp);
57a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
58a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	return ext2fs_le32_to_cpu(mmp->mmp_checksum) == calculated;
59a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong}
60a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
61a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wongerrcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp)
62a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong{
63a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	__u32 crc;
64a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
6577b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
66a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong		return 0;
67a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
68a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	crc = ext2fs_mmp_csum(fs, mmp);
69a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	mmp->mmp_checksum = ext2fs_cpu_to_le32(crc);
70a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
71a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong	return 0;
72a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong}
73a9620d8b308271ace63dd0787555fa715d09e0f8Darrick J. Wong
741eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wongint ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb)
751eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong{
7677b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
771eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong		return 1;
781eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong
791eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong	return sb->s_checksum_type == EXT2_CRC32C_CHKSUM;
801eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong}
811eedf3e52c2ae8f7ad2ad9c010ce5293e0b19ae3Darrick J. Wong
82894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'ostatic __u32 ext2fs_superblock_csum(ext2_filsys fs EXT2FS_ATTR((unused)),
83894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o				    struct ext2_super_block *sb)
84d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong{
85d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	int offset = offsetof(struct ext2_super_block, s_checksum);
86d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
87d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	return ext2fs_crc32c_le(~0, (unsigned char *)sb, offset);
88d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong}
89d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
902432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong/* NOTE: The input to this function MUST be in LE order */
91d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wongint ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb)
92d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong{
932432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	__u32 flag, calculated;
94d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
952432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	if (fs->flags & EXT2_FLAG_SWAP_BYTES)
962432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong		flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM;
972432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	else
982432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong		flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
992432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong
1002432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag))
101d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong		return 1;
102d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
103d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	calculated = ext2fs_superblock_csum(fs, sb);
104d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
105d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	return ext2fs_le32_to_cpu(sb->s_checksum) == calculated;
106d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong}
107d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
1082432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong/* NOTE: The input to this function MUST be in LE order */
109d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wongerrcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
110d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong				     struct ext2_super_block *sb)
111d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong{
1122432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	__u32 flag, crc;
113d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
1142432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	if (fs->flags & EXT2_FLAG_SWAP_BYTES)
1152432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong		flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM;
1162432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	else
1172432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong		flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
1182432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong
1192432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag))
120d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong		return 0;
121d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
122d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	crc = ext2fs_superblock_csum(fs, sb);
123d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	sb->s_checksum = ext2fs_cpu_to_le32(crc);
124d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
125d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong	return 0;
126d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong}
127d4ca3e40cabd4ec5124ab9aa958fa9e5337aed39Darrick J. Wong
128894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'ostatic errcode_t ext2fs_ext_attr_block_csum(ext2_filsys fs,
129894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o					    ext2_ino_t inum EXT2FS_ATTR((unused)),
13039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					    blk64_t block,
13139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					    struct ext2_ext_attr_header *hdr,
13239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					    __u32 *crc)
13339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong{
13439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	char *buf = (char *)hdr;
1351b8c4c1b45482363e29bd4cca483d84645f8ac9dAndreas Dilger	__u32 old_crc = hdr->h_checksum;
13639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
13739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	hdr->h_checksum = 0;
13839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	block = ext2fs_cpu_to_le64(block);
13939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&block,
14039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				sizeof(block));
14139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, fs->blocksize);
14239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	hdr->h_checksum = old_crc;
14339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
14439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	return 0;
14539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong}
14639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
14739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wongint ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
14839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				      blk64_t block,
14939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong				      struct ext2_ext_attr_header *hdr)
15039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong{
15139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	__u32 calculated;
15239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	errcode_t retval;
15339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
15477b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
15539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		return 1;
15639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
15739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &calculated);
15839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	if (retval)
15939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		return 0;
16039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
16139f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	return ext2fs_le32_to_cpu(hdr->h_checksum) == calculated;
16239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong}
16339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
16439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wongerrcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
16539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					 blk64_t block,
16639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong					 struct ext2_ext_attr_header *hdr)
16739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong{
16839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	errcode_t retval;
16939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	__u32 crc;
17039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
17177b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
17239f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		return 0;
17339f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
17439f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &crc);
17539f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	if (retval)
17639f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong		return retval;
17739f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	hdr->h_checksum = ext2fs_cpu_to_le32(crc);
17839f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong	return 0;
17939f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong}
18039f5659ae3a0d9105ecddddfda2800b7002febc3Darrick J. Wong
181dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic __u16 do_nothing16(__u16 x)
182dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
183dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return x;
184dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
185dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
186dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic __u16 disk_to_host16(__u16 x)
187dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
188dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return ext2fs_le16_to_cpu(x);
189dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
190dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
191dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic errcode_t __get_dx_countlimit(ext2_filsys fs,
192dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				     struct ext2_dir_entry *dirent,
193dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				     struct ext2_dx_countlimit **cc,
194dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				     int *offset,
195dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				     int need_swab)
196dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
197dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dir_entry *dp;
198dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_root_info *root;
199dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_countlimit *c;
200dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	int count_offset, max_sane_entries;
201dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	unsigned int rec_len;
202dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	__u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16);
203dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
204dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	rec_len = translate(dirent->rec_len);
205dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
206dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (rec_len == fs->blocksize && translate(dirent->name_len) == 0)
207dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		count_offset = 8;
208dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	else if (rec_len == 12) {
209894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o		dp = (struct ext2_dir_entry *)(((char *)dirent) + rec_len);
210dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		rec_len = translate(dp->rec_len);
211dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		if (rec_len != fs->blocksize - 12)
212dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong			return EXT2_ET_DB_NOT_FOUND;
213894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o		root = (struct ext2_dx_root_info *)(((char *)dp + 12));
214dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		if (root->reserved_zero ||
215dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		    root->info_length != sizeof(struct ext2_dx_root_info))
216dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong			return EXT2_ET_DB_NOT_FOUND;
217dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		count_offset = 32;
218dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	} else
219dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return EXT2_ET_DB_NOT_FOUND;
220dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
221894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o	c = (struct ext2_dx_countlimit *)(((char *)dirent) + count_offset);
222dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	max_sane_entries = (fs->blocksize - count_offset) /
223dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong			   sizeof(struct ext2_dx_entry);
224dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (ext2fs_le16_to_cpu(c->limit) > max_sane_entries ||
225dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	    ext2fs_le16_to_cpu(c->count) > max_sane_entries)
226dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
227dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
228dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (offset)
229dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		*offset = count_offset;
230dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (cc)
231dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		*cc = c;
232dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
233dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return 0;
234dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
235dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
236dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongerrcode_t ext2fs_get_dx_countlimit(ext2_filsys fs,
237dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				   struct ext2_dir_entry *dirent,
238dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				   struct ext2_dx_countlimit **cc,
239dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				   int *offset)
240dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
241dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return __get_dx_countlimit(fs, dirent, cc, offset, 0);
242dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
243dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
24481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongvoid ext2fs_initialize_dirent_tail(ext2_filsys fs,
24581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				   struct ext2_dir_entry_tail *t)
24681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
24781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	memset(t, 0, sizeof(struct ext2_dir_entry_tail));
24881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	ext2fs_set_rec_len(fs, sizeof(struct ext2_dir_entry_tail),
24981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong			   (struct ext2_dir_entry *)t);
25081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	t->det_reserved_name_len = EXT2_DIR_NAME_LEN_CSUM;
25181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
25281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
25381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongstatic errcode_t __get_dirent_tail(ext2_filsys fs,
25481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				   struct ext2_dir_entry *dirent,
25581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				   struct ext2_dir_entry_tail **tt,
25681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				   int need_swab)
25781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
25881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_dir_entry *d;
25981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	void *top;
26081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_dir_entry_tail *t;
26181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	unsigned int rec_len;
26281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	errcode_t retval = 0;
26381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	__u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16);
26481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
26581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	d = dirent;
26681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	top = EXT2_DIRENT_TAIL(dirent, fs->blocksize);
26781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
26881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	rec_len = translate(d->rec_len);
26981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	while (rec_len && !(rec_len & 0x3)) {
270894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o		d = (struct ext2_dir_entry *)(((char *)d) + rec_len);
27181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		if ((void *)d >= top)
27281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong			break;
27381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		rec_len = translate(d->rec_len);
27481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	}
27581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
27681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (d != top)
27781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
27881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
27981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	t = (struct ext2_dir_entry_tail *)d;
28081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (t->det_reserved_zero1 ||
28181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	    translate(t->det_rec_len) != sizeof(struct ext2_dir_entry_tail) ||
28281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	    translate(t->det_reserved_name_len) != EXT2_DIR_NAME_LEN_CSUM)
28381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
28481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
28581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (tt)
28681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		*tt = t;
28781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return retval;
28881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
28981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
29081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongint ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent)
29181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
29281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return __get_dirent_tail(fs, dirent, NULL, 0) == 0;
29381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
29481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
29581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongstatic errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum,
29681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				    struct ext2_dir_entry *dirent, __u32 *crc,
29781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				    int size)
29881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
29981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	errcode_t retval;
30081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	char *buf = (char *)dirent;
30181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	__u32 gen;
30281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_inode inode;
30381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
30481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = ext2fs_read_inode(fs, inum, &inode);
30581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
30681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return retval;
30781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
30881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	inum = ext2fs_cpu_to_le32(inum);
30981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	gen = ext2fs_cpu_to_le32(inode.i_generation);
31081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
31181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				sizeof(inum));
31281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
31381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size);
31481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
31581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return 0;
31681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
31781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
31881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongint ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum,
31981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong			      struct ext2_dir_entry *dirent)
32081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
32181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	errcode_t retval;
32281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	__u32 calculated;
32381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_dir_entry_tail *t;
32481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
32581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = __get_dirent_tail(fs, dirent, &t, 1);
32681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
32781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 1;
32881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
32981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	/*
33081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	 * The checksum field is overlaid with the dirent->name field
33181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	 * so the swapfs.c functions won't change the endianness.
33281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	 */
33381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = ext2fs_dirent_csum(fs, inum, dirent, &calculated,
334894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o				    (char *)t - (char *)dirent);
33581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
33681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 0;
33781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return ext2fs_le32_to_cpu(t->det_checksum) == calculated;
33881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
33981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
34081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongstatic errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum,
34181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong					struct ext2_dir_entry *dirent)
34281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
34381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	errcode_t retval;
34481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	__u32 crc;
34581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	struct ext2_dir_entry_tail *t;
34681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
34781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = __get_dirent_tail(fs, dirent, &t, 1);
34881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
34981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return retval;
35081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
35181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	/* swapfs.c functions don't change the checksum endianness */
35281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	retval = ext2fs_dirent_csum(fs, inum, dirent, &crc,
353894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o				    (char *)t - (char *)dirent);
35481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (retval)
35581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return retval;
35681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	t->det_checksum = ext2fs_cpu_to_le32(crc);
35781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return 0;
35881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
35981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
360dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
361dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				struct ext2_dir_entry *dirent,
362dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				__u32 *crc, int count_offset, int count,
363dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				struct ext2_dx_tail *t)
364dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
365dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	errcode_t retval;
366dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	char *buf = (char *)dirent;
367dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	int size;
368dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	__u32 old_csum, gen;
369dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_inode inode;
370dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
371dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	size = count_offset + (count * sizeof(struct ext2_dx_entry));
372dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	old_csum = t->dt_checksum;
373dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t->dt_checksum = 0;
374dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
375dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = ext2fs_read_inode(fs, inum, &inode);
376dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
377dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return retval;
378dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
379dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	inum = ext2fs_cpu_to_le32(inum);
380dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	gen = ext2fs_cpu_to_le32(inode.i_generation);
381dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
382dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				sizeof(inum));
383dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
384dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size);
385dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)t,
386dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				sizeof(struct ext2_dx_tail));
387dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t->dt_checksum = old_csum;
388dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
389dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return 0;
390dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
391dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
392dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum,
393dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				 struct ext2_dir_entry *dirent)
394dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
395dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	__u32 calculated;
396dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	errcode_t retval;
397dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_countlimit *c;
398dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_tail *t;
399dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	int count_offset, limit, count;
400dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
401dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
402dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
403dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return 1;
404dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	limit = ext2fs_le16_to_cpu(c->limit);
405dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	count = ext2fs_le16_to_cpu(c->count);
406dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
407dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	    fs->blocksize - sizeof(struct ext2_dx_tail))
408dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return 0;
409dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	/* htree structs are accessed in LE order */
410dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
411dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, count_offset,
412dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				count, t);
413dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
414dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return 0;
415dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
416dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return ext2fs_le32_to_cpu(t->dt_checksum) == calculated;
417dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
418dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
419dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wongstatic errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum,
420dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong				    struct ext2_dir_entry *dirent)
421dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong{
422dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	__u32 crc;
423dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	errcode_t retval = 0;
424dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_countlimit *c;
425dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	struct ext2_dx_tail *t;
426dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	int count_offset, limit, count;
427dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
428dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
429dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
430dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return retval;
431dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	limit = ext2fs_le16_to_cpu(c->limit);
432dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	count = ext2fs_le16_to_cpu(c->count);
433dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
434dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	    fs->blocksize - sizeof(struct ext2_dx_tail))
435dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
436dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
437dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
438dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	/* htree structs are accessed in LE order */
439dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	retval = ext2fs_dx_csum(fs, inum, dirent, &crc, count_offset, count, t);
440dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	if (retval)
441dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong		return retval;
442dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	t->dt_checksum = ext2fs_cpu_to_le32(crc);
443dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong	return retval;
444dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong}
445dc96de09d7356ef25448134445753aabfc1097daDarrick J. Wong
44681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongint ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
44781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				 struct ext2_dir_entry *dirent)
44881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
44977b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
45081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 1;
45181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
45281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
45381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return ext2fs_dirent_csum_verify(fs, inum, dirent);
45481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0)
45581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return ext2fs_dx_csum_verify(fs, inum, dirent);
45681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
45781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return 0;
45881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
45981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
46081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wongerrcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
46181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong				    struct ext2_dir_entry *dirent)
46281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong{
46377b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
46481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 0;
46581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
46681683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
46781683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return ext2fs_dirent_csum_set(fs, inum, dirent);
46881683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0)
46981683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return ext2fs_dx_csum_set(fs, inum, dirent);
47081683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
47181683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	if (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)
47281683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong		return 0;
47381683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong	return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
47481683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong}
47581683c6a32045cf04d76a024e6f1753535b97c22Darrick J. Wong
47641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong#define EXT3_EXTENT_TAIL_OFFSET(hdr)	(sizeof(struct ext3_extent_header) + \
47741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	(sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
47841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
47941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wongstatic struct ext3_extent_tail *get_extent_tail(struct ext3_extent_header *h)
48041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong{
481894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o	return (struct ext3_extent_tail *)(((char *)h) +
48241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong					   EXT3_EXTENT_TAIL_OFFSET(h));
48341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong}
48441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
48541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wongstatic errcode_t ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum,
48641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong					  struct ext3_extent_header *eh,
48741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong					  __u32 *crc)
48841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong{
48941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	int size;
49041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	__u32 gen;
49141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	errcode_t retval;
49241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	struct ext2_inode inode;
49341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
49441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	size = EXT3_EXTENT_TAIL_OFFSET(eh) + offsetof(struct ext3_extent_tail,
49541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong						      et_checksum);
49641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
49741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	retval = ext2fs_read_inode(fs, inum, &inode);
49841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	if (retval)
49941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return retval;
50041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	inum = ext2fs_cpu_to_le32(inum);
50141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	gen = ext2fs_cpu_to_le32(inode.i_generation);
50241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
50341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong				sizeof(inum));
50441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
50541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)eh, size);
50641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
50741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	return 0;
50841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong}
50941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
51041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wongint ext2fs_extent_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
51141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong				    struct ext3_extent_header *eh)
51241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong{
51341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	errcode_t retval;
51441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	__u32 provided, calculated;
51541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	struct ext3_extent_tail *t = get_extent_tail(eh);
51641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
51741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	/*
51841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 * The extent tree structures are accessed in LE order, so we must
51941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 * swap the checksum bytes here.
52041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 */
52177b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
52241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return 1;
52341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
52441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	provided = ext2fs_le32_to_cpu(t->et_checksum);
52541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	retval = ext2fs_extent_block_csum(fs, inum, eh, &calculated);
52641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	if (retval)
52741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return 0;
52841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
52941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	return provided == calculated;
53041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong}
53141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
53241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wongerrcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
53341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong				       struct ext3_extent_header *eh)
53441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong{
53541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	errcode_t retval;
53641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	__u32 crc;
53741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	struct ext3_extent_tail *t = get_extent_tail(eh);
53841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
53977b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
54041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return 0;
54141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
54241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	/*
54341275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 * The extent tree structures are accessed in LE order, so we must
54441275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 * swap the checksum bytes here.
54541275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	 */
54641275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	retval = ext2fs_extent_block_csum(fs, inum, eh, &crc);
54741275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	if (retval)
54841275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong		return retval;
54941275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	t->et_checksum = ext2fs_cpu_to_le32(crc);
55041275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong	return retval;
55141275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong}
55241275efeeebe46f68b7e3ffb3beb30ff479a2308Darrick J. Wong
553a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wongint ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
554a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong				    char *bitmap, int size)
555a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong{
556a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
557a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong			ext2fs_group_desc(fs, fs->group_desc, group);
558a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	__u32 provided, calculated;
559a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
56077b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
561a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		return 1;
562a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	provided = gdp->bg_inode_bitmap_csum_lo;
563a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap,
564a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong				      size);
565a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
566a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		provided |= (__u32)gdp->bg_inode_bitmap_csum_hi << 16;
567a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	else
568a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		calculated &= 0xFFFF;
569a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
570a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	return provided == calculated;
571a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong}
572a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
573a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wongerrcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
574a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong				       char *bitmap, int size)
575a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong{
576a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	__u32 crc;
577a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
578a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong			ext2fs_group_desc(fs, fs->group_desc, group);
579a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
58077b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
581a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		return 0;
582a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
583a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size);
584a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	gdp->bg_inode_bitmap_csum_lo = crc & 0xFFFF;
585a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
586a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong		gdp->bg_inode_bitmap_csum_hi = crc >> 16;
587a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
588a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong	return 0;
589a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong}
590a80ea34023e01b038314884dbf56165158b2b799Darrick J. Wong
591e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wongint ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
592e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong				    char *bitmap, int size)
593e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong{
594e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
595e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong			ext2fs_group_desc(fs, fs->group_desc, group);
596e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	__u32 provided, calculated;
597e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
59877b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
599e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		return 1;
600e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	provided = gdp->bg_block_bitmap_csum_lo;
601e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap,
602e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong				      size);
603e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
604e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		provided |= (__u32)gdp->bg_block_bitmap_csum_hi << 16;
605e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	else
606e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		calculated &= 0xFFFF;
607e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
608e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	return provided == calculated;
609e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong}
610e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
611e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wongerrcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
612e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong				       char *bitmap, int size)
613e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong{
614e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	__u32 crc;
615e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	struct ext4_group_desc *gdp = (struct ext4_group_desc *)
616e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong			ext2fs_group_desc(fs, fs->group_desc, group);
617e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
61877b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_metadata_csum(fs->super))
619e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		return 0;
620e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
621e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size);
622e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	gdp->bg_block_bitmap_csum_lo = crc & 0xFFFF;
623e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
624e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong		gdp->bg_block_bitmap_csum_hi = crc >> 16;
625e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
626e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong	return 0;
627e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong}
628e7dc95c6773fa0a49c54846ae609df1d8c2a7286Darrick J. Wong
62937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wongstatic errcode_t ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
63037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong			       struct ext2_inode_large *inode,
63137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong			       __u32 *crc, int has_hi)
63237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong{
63337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u32 gen;
63437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	struct ext2_inode_large *desc = inode;
63537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	size_t size = fs->super->s_inode_size;
63637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u16 old_lo;
63737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u16 old_hi = 0;
63837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
63937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	old_lo = inode->i_checksum_lo;
64037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	inode->i_checksum_lo = 0;
64137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (has_hi) {
64237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		old_hi = inode->i_checksum_hi;
64337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		inode->i_checksum_hi = 0;
64437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	}
64537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
64637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	inum = ext2fs_cpu_to_le32(inum);
64737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	gen = inode->i_generation;
64837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	*crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
64937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong				sizeof(inum));
65037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
65137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	*crc = ext2fs_crc32c_le(*crc, (unsigned char *)desc, size);
65237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
65337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	inode->i_checksum_lo = old_lo;
65437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (has_hi)
65537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		inode->i_checksum_hi = old_hi;
65637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	return 0;
65737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong}
65837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
65937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wongint ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
66037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong			     struct ext2_inode_large *inode)
66137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong{
66237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	errcode_t retval;
66337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u32 provided, calculated;
664894eaf85065f3a0ee023704eeba56799ec5bf6ebTheodore Ts'o	unsigned int i, has_hi;
66597fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	char *cp;
66637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
667c0495d96fd1f7015e7beb3d9363cbe949d133173Theodore Ts'o	if (!ext2fs_has_feature_metadata_csum(fs->super))
66837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		return 1;
66937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
67037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
67137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		  inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END);
67237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
67337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	provided = ext2fs_le16_to_cpu(inode->i_checksum_lo);
67437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	retval = ext2fs_inode_csum(fs, inum, inode, &calculated, has_hi);
67537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (retval)
67637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		return 0;
67737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (has_hi) {
67837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		__u32 hi = ext2fs_le16_to_cpu(inode->i_checksum_hi);
67937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		provided |= hi << 16;
68037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	} else
68137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		calculated &= 0xFFFF;
68237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
68397fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	if (provided == calculated)
68497fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o		return 1;
68597fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o
68697fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	/*
68797fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * If the checksum didn't match, it's possible it was due to
68897fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * the inode being all zero's.  It's unlikely this is the
68997fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * case, but it can happen.  So check for it here.  (We only
69097fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * check the base inode since that's good enough, and it's not
69197fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * worth the bother to figure out how much of the extended
69297fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 * inode, if any, is present.)
69397fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	 */
69497fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	for (cp = (char *) inode, i = 0;
69597fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	     i < sizeof(struct ext2_inode);
69697fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	     cp++, i++)
69797fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o		if (*cp)
69897fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o			return 0;
69997fac35094160261907eeb693498ef6ebd27283eTheodore Ts'o	return 1;		/* Inode must have been all zero's */
70037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong}
70137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
70237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wongerrcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
70337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong			   struct ext2_inode_large *inode)
70437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong{
70537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	errcode_t retval;
70637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	__u32 crc;
70737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	int has_hi;
70837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
709c0495d96fd1f7015e7beb3d9363cbe949d133173Theodore Ts'o	if (!ext2fs_has_feature_metadata_csum(fs->super))
71037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		return 0;
71137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
71237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
71337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		  inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END);
71437d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
71537d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	retval = ext2fs_inode_csum(fs, inum, inode, &crc, has_hi);
71637d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (retval)
71737d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		return retval;
71837d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	inode->i_checksum_lo = ext2fs_cpu_to_le16(crc & 0xFFFF);
71937d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	if (has_hi)
72037d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong		inode->i_checksum_hi = ext2fs_cpu_to_le16(crc >> 16);
72137d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong	return 0;
72237d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong}
72337d82b6a95e1912c452e77e84ead61e2812d2721Darrick J. Wong
72487141781aabb4dc01359428d2feecdc7f43eeac0Theodore Ts'o__u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
725ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
7262bc30417541deffca795db8ec4e7f7ccb616dc3fAndreas Dilger	struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
7272bc30417541deffca795db8ec4e7f7ccb616dc3fAndreas Dilger							 group);
72871715a5a9ad409df162dbb58a4c3b6fd2c5868d5Theodore Ts'o	size_t offset, size = EXT2_DESC_SIZE(fs->super);
729ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	__u16 crc = 0;
730ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#ifdef WORDS_BIGENDIAN
7315b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	struct ext4_group_desc swabdesc;
7322ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	size_t save_size = size;
7332ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
7342ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	struct ext2_group_desc *save_desc = desc;
735ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
7365b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	/* Have to swab back to little-endian to do the checksum */
7372ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	if (size > ext4_bg_size)
7382ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o		size = ext4_bg_size;
7395b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	memcpy(&swabdesc, desc, size);
7402ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
7415b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	desc = (struct ext2_group_desc *) &swabdesc;
7425b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	group = ext2fs_swab32(group);
743ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos#endif
7445b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong
74577b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (ext2fs_has_feature_metadata_csum(fs->super)) {
7465b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		/* new metadata csum code */
7475b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		__u16 old_crc;
7485b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		__u32 crc32;
7495b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong
7505b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		old_crc = desc->bg_checksum;
7515b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		desc->bg_checksum = 0;
7525b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		crc32 = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&group,
7535b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong					 sizeof(group));
7545b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		crc32 = ext2fs_crc32c_le(crc32, (unsigned char *)desc,
7555b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong					 size);
7565b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		desc->bg_checksum = old_crc;
757b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#ifdef WORDS_BIGENDIAN
758b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o		if (save_size > ext4_bg_size)
7592ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o			crc32 = ext2fs_crc32c_le(crc32,
7602432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong				     (unsigned char *)save_desc + ext4_bg_size,
7612432a41a58c03be4afdfb12f40e7b7cfe3255145Darrick J. Wong	                             save_size - ext4_bg_size);
762b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#endif
7635b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		crc = crc32 & 0xFFFF;
7645b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		goto out;
765ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	}
766ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
7675b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	/* old crc16 code */
7682ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	offset = offsetof(struct ext2_group_desc, bg_checksum);
7695b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	crc = ext2fs_crc16(~0, fs->super->s_uuid,
7705b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong			   sizeof(fs->super->s_uuid));
7715b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	crc = ext2fs_crc16(crc, &group, sizeof(group));
7725b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	crc = ext2fs_crc16(crc, desc, offset);
7735b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	offset += sizeof(desc->bg_checksum); /* skip checksum */
7745b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	/* for checksum of struct ext4_group_desc do the rest...*/
7755b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	if (offset < size) {
7765b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong		crc = ext2fs_crc16(crc, (char *)desc + offset,
7775b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong				   size - offset);
7785b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	}
7792ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o#ifdef WORDS_BIGENDIAN
7802ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	/*
7812ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	 * If the size of the bg descriptor is greater than 64
7822ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	 * bytes, which is the size of the traditional ext4 bg
7832ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	 * descriptor, checksum the rest of the descriptor here
7842ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	 */
7852ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o	if (save_size > ext4_bg_size)
7862ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o		crc = ext2fs_crc16(crc, (char *)save_desc + ext4_bg_size,
7872ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o				   save_size - ext4_bg_size);
7882ffccc82c4b9ed935e45118e325896b70e9e3eb0Theodore Ts'o#endif
7895b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong
7905b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wongout:
791ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	return crc;
792ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
793ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
794ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santosint ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
795ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
7965b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	if (ext2fs_has_group_desc_csum(fs) &&
797d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	    (ext2fs_bg_checksum(fs, group) !=
7984729455f0a68f2fa0a83ec8460d1d4bccba9dcfaTheodore Ts'o	     ext2fs_group_desc_csum(fs, group)))
799ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos		return 0;
800ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
801ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	return 1;
802ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
803ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
804ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santosvoid ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
805ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
8065b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	if (!ext2fs_has_group_desc_csum(fs))
807d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		return;
808d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson
809d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	/* ext2fs_bg_checksum_set() sets the actual checksum field but
810d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	 * does not calculate the checksum itself. */
811d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	ext2fs_bg_checksum_set(fs, group, ext2fs_group_desc_csum(fs, group));
812ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
813ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
814ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santosstatic __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap,
815ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos				   __u32 inodes_per_grp, dgrp_t grp_no)
816ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
817ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	ext2_ino_t i, start_ino, end_ino;
818ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
819ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	start_ino = grp_no * inodes_per_grp + 1;
820ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	end_ino = start_ino + inodes_per_grp - 1;
821ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
822ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	for (i = end_ino; i >= start_ino; i--) {
8238f82ef9860339039b54a324be137fbc09b762358Valerie Aurora Henson		if (ext2fs_fast_test_inode_bitmap2(bitmap, i))
824ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos			return i - start_ino + 1;
825ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	}
826ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	return inodes_per_grp;
827ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
828ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
829ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos/* update the bitmap flags, set the itable high watermark, and calculate
830ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos * checksums for the group descriptors */
831f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilgererrcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
832ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos{
833ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	struct ext2_super_block *sb = fs->super;
8348895f43a60269464f654e9d87c28768875cd703aTheodore Ts'o	int dirty = 0;
835ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	dgrp_t i;
836ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
837f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger	if (!fs->inode_map)
838f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger		return EXT2_ET_NO_INODE_BITMAP;
839f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger
8405b58dc2304f06953e1d8314ea570cc3befec95bcDarrick J. Wong	if (!ext2fs_has_group_desc_csum(fs))
841f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger		return 0;
842ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
843d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	for (i = 0; i < fs->group_desc_count; i++) {
844d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o		__u32 old_csum = ext2fs_bg_checksum(fs, i);
845d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o		__u32 old_unused = ext2fs_bg_itable_unused(fs, i);
846d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o		__u32 old_flags = ext2fs_bg_flags(fs, i);
847d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o		__u32 old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i);
848c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong		__u32 old_free_blocks_count = ext2fs_bg_free_blocks_count(fs, i);
849c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong
850c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong		if (old_free_blocks_count == sb->s_blocks_per_group &&
851c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong		    i != fs->group_desc_count - 1)
852c0ff3a21b6c3b30fbbe16280cf1808864f5803b7Darrick J. Wong			ext2fs_bg_flags_set(fs, i, EXT2_BG_BLOCK_UNINIT);
853ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
854d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		if (old_free_inodes_count == sb->s_inodes_per_group) {
855d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
856d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			ext2fs_bg_itable_unused_set(fs, i, sb->s_inodes_per_group);
85716b851cdae98244e117fe91d93b267fcad1102b3Theodore Ts'o		} else {
858d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			int unused =
859d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson				sb->s_inodes_per_group -
860ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos				find_last_inode_ingrp(fs->inode_map,
861d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson						      sb->s_inodes_per_group, i);
862d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson
863d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			ext2fs_bg_flags_clear(fs, i, EXT2_BG_INODE_UNINIT);
864d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson			ext2fs_bg_itable_unused_set(fs, i, unused);
865ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos		}
866ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos
867ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos		ext2fs_group_desc_csum_set(fs, i);
868d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		if (old_flags != ext2fs_bg_flags(fs, i))
86980fc4e698a308de22ace6179f45e0bb67befa74bAndreas Dilger			dirty = 1;
870d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		if (old_unused != ext2fs_bg_itable_unused(fs, i))
87180fc4e698a308de22ace6179f45e0bb67befa74bAndreas Dilger			dirty = 1;
872d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		if (old_csum != ext2fs_bg_checksum(fs, i))
873ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos			dirty = 1;
874ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	}
875ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos	if (dirty)
876ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos		ext2fs_mark_super_dirty(fs);
877f628acea2671dda839fc086f1017718e41e34ecaAndreas Dilger	return 0;
878ca2634a46ab9da85a3a015a7772770d9dbe5848eJose R. Santos}
879470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
880470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#ifdef DEBUG
881c816ecb204a32e67788738e050ff2b14a721672bEric Sandeen#include "e2p/e2p.h"
882c816ecb204a32e67788738e050ff2b14a721672bEric Sandeen
883470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'ovoid print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
884470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o{
885470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	__u16 crc1, crc2, crc3;
886470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	dgrp_t swabgroup;
887b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
888b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o							 group);
889b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	size_t size = EXT2_DESC_SIZE(fs->super);
890470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	struct ext2_super_block *sb = fs->super;
8911d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	int offset = offsetof(struct ext2_group_desc, bg_checksum);
892470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#ifdef WORDS_BIGENDIAN
8931d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	struct ext4_group_desc swabdesc;
894b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	struct ext2_group_desc *save_desc = desc;
895b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
896b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	size_t save_size = size;
8971d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o#endif
898470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
8991d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o#ifdef WORDS_BIGENDIAN
900470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	/* Have to swab back to little-endian to do the checksum */
901b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	if (size > ext4_bg_size)
902b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o		size = ext4_bg_size;
9031d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	memcpy(&swabdesc, desc, size);
9041d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
9051d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	desc = (struct ext2_group_desc *) &swabdesc;
906470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
907470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	swabgroup = ext2fs_swab32(group);
908470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#else
909470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	swabgroup = group;
910470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#endif
911470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
912470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	crc1 = ext2fs_crc16(~0, sb->s_uuid, sizeof(fs->super->s_uuid));
913470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	crc2 = ext2fs_crc16(crc1, &swabgroup, sizeof(swabgroup));
9141d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	crc3 = ext2fs_crc16(crc2, desc, offset);
9151d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	offset += sizeof(desc->bg_checksum); /* skip checksum */
9161d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	/* for checksum of struct ext4_group_desc do the rest...*/
9171d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o	if (offset < size)
9181d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o		crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset);
919b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#ifdef WORDS_BIGENDIAN
920b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	if (save_size > ext4_bg_size)
921b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o		crc3 = ext2fs_crc16(crc3, (char *)save_desc + ext4_bg_size,
922b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o				    save_size - ext4_bg_size);
923b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#endif
9241d18a55c528adf997d8edee60bd8003c822c55e8Theodore Ts'o
925f797cf3e37b476aac593fe9a9f4630448d335332Andreas Dilger	printf("%s UUID %s=%04x, grp %u=%04x: %04x=%04x\n",
926562f264243f4d4385910b6f06872730214977736Theodore Ts'o	       msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2, crc3,
927c816ecb204a32e67788738e050ff2b14a721672bEric Sandeen	       ext2fs_group_desc_csum(fs, group));
928470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o}
929470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
930470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'ounsigned char sb_uuid[16] = { 0x4f, 0x25, 0xe8, 0xcf, 0xe7, 0x97, 0x48, 0x23,
931470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o			      0xbe, 0xfa, 0xa7, 0x88, 0x4b, 0xae, 0xec, 0xdb };
932470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
933470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'oint main(int argc, char **argv)
934470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o{
935470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	struct ext2_super_block param;
936470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	errcode_t		retval;
937470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	ext2_filsys		fs;
938470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	int			i;
939470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	__u16 csum1, csum2, csum_known = 0xd3a4;
940470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
941470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	memset(&param, 0, sizeof(param));
9424efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	ext2fs_blocks_count_set(&param, 32768);
943b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#if 0
944b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT;
945b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	param.s_desc_size = 128;
946b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o	csum_known = 0x5b6e;
947b3c2a638139b5da7f63f7ebe450860918d297a39Theodore Ts'o#endif
948470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
9498f82ef9860339039b54a324be137fbc09b762358Valerie Aurora Henson	retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
950470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o				   test_io_manager, &fs);
951470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (retval) {
952470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		com_err("setup", retval,
953470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o			"While initializing filesystem");
954470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
955470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
956470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	memcpy(fs->super->s_uuid, sb_uuid, 16);
957470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	fs->super->s_feature_ro_compat = EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
958470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
959470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	for (i=0; i < fs->group_desc_count; i++) {
960d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_block_bitmap_loc_set(fs, i, 124);
961d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_inode_bitmap_loc_set(fs, i, 125);
962d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_inode_table_loc_set(fs, i, 126);
963d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_bg_free_blocks_count_set(fs, i, 31119);
964d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_bg_free_inodes_count_set(fs, i, 15701);
965d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson		ext2fs_bg_used_dirs_count_set(fs, i, 2);
966e633b58ac75f2f544b7d6572e37d4b63da31e59cEric Sandeen		ext2fs_bg_flags_zap(fs, i);
967470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	};
968470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
969470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum1 = ext2fs_group_desc_csum(fs, 0);
970470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum0000", fs, 0);
971470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
972470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 != csum_known) {
973470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksum for group 0 should be %04x\n", csum_known);
974470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
975470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
976470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum2 = ext2fs_group_desc_csum(fs, 1);
977470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum0001", fs, 1);
978470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 == csum2) {
979470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums for different groups shouldn't match\n");
980470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
981470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
982470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum2 = ext2fs_group_desc_csum(fs, 2);
983470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csumffff", fs, 2);
984470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 == csum2) {
985470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums for different groups shouldn't match\n");
986470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
987470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
988d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	ext2fs_bg_checksum_set(fs, 0, csum1);
989470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum2 = ext2fs_group_desc_csum(fs, 0);
990470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum_set", fs, 0);
991470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 != csum2) {
992470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums should not depend on checksum field\n");
993470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
994470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
995470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (!ext2fs_group_desc_csum_verify(fs, 0)) {
996470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums should verify against gd_checksum\n");
997470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
998470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
999470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	memset(fs->super->s_uuid, 0x30, sizeof(fs->super->s_uuid));
1000470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("new_uuid", fs, 0);
1001470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (ext2fs_group_desc_csum_verify(fs, 0) != 0) {
1002470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums for different filesystems shouldn't match\n");
1003470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
1004470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
1005d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	csum1 = ext2fs_group_desc_csum(fs, 0);
1006d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	ext2fs_bg_checksum_set(fs, 0, csum1);
1007470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum_new", fs, 0);
1008d7cca6b06f366f998ed43346f9b6fca9e163692fValerie Aurora Henson	ext2fs_bg_free_blocks_count_set(fs, 0, 1);
1009470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	csum2 = ext2fs_group_desc_csum(fs, 0);
1010470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	print_csum("csum_blk", fs, 0);
1011470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	if (csum1 == csum2) {
1012470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		printf("checksums for different data shouldn't match\n");
1013470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o		exit(1);
1014470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	}
1015470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o
1016470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o	return 0;
1017470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o}
1018470e737a872918afd9067de1ce92d571d5671d40Theodore Ts'o#endif
1019