163db34c8SAxel Dörfler/*
2275463f4SAxel Dörfler * Copyright 2008-2010, Axel D��rfler, axeld@pinc-software.de.
363db34c8SAxel Dörfler * Distributed under the terms of the MIT License.
463db34c8SAxel Dörfler */
563db34c8SAxel Dörfler#ifndef EXT2_H
663db34c8SAxel Dörfler#define EXT2_H
763db34c8SAxel Dörfler
863db34c8SAxel Dörfler
90680840aSAxel Dörfler#include <sys/stat.h>
100680840aSAxel Dörfler
1163db34c8SAxel Dörfler#include <ByteOrder.h>
1263db34c8SAxel Dörfler#include <fs_interface.h>
13b026d219SFrançois Revol#include <KernelExport.h>
1463db34c8SAxel Dörfler
1563db34c8SAxel Dörfler
1645af882dSJérôme Duvaltypedef uint64 fileblock_t;		// file block number
1745af882dSJérôme Duvaltypedef uint64 fsblock_t;		// filesystem block number
1845af882dSJérôme Duval
1945af882dSJérôme Duval
2063db34c8SAxel Dörfler#define EXT2_SUPER_BLOCK_OFFSET	1024
2163db34c8SAxel Dörfler
2263db34c8SAxel Dörflerstruct ext2_super_block {
2363db34c8SAxel Dörfler	uint32	num_inodes;
2463db34c8SAxel Dörfler	uint32	num_blocks;
2563db34c8SAxel Dörfler	uint32	reserved_blocks;
2663db34c8SAxel Dörfler	uint32	free_blocks;
2763db34c8SAxel Dörfler	uint32	free_inodes;
2863db34c8SAxel Dörfler	uint32	first_data_block;
2963db34c8SAxel Dörfler	uint32	block_shift;
3063db34c8SAxel Dörfler	uint32	fragment_shift;
3163db34c8SAxel Dörfler	uint32	blocks_per_group;
3263db34c8SAxel Dörfler	uint32	fragments_per_group;
3363db34c8SAxel Dörfler	uint32	inodes_per_group;
3463db34c8SAxel Dörfler	uint32	mount_time;
3563db34c8SAxel Dörfler	uint32	write_time;
3663db34c8SAxel Dörfler	uint16	mount_count;
3763db34c8SAxel Dörfler	uint16	max_mount_count;
3863db34c8SAxel Dörfler	uint16	magic;
3963db34c8SAxel Dörfler	uint16	state;
4063db34c8SAxel Dörfler	uint16	error_handling;
4163db34c8SAxel Dörfler	uint16	minor_revision_level;
4263db34c8SAxel Dörfler	uint32	last_check_time;
4363db34c8SAxel Dörfler	uint32	check_interval;
4463db34c8SAxel Dörfler	uint32	creator_os;
4563db34c8SAxel Dörfler	uint32	revision_level;
4663db34c8SAxel Dörfler	uint16	reserved_blocks_uid;
4763db34c8SAxel Dörfler	uint16	reserved_blocks_gid;
4863db34c8SAxel Dörfler	uint32	first_inode;
4963db34c8SAxel Dörfler	uint16	inode_size;
5063db34c8SAxel Dörfler	uint16	block_group;
5163db34c8SAxel Dörfler	uint32	compatible_features;
5263db34c8SAxel Dörfler	uint32	incompatible_features;
5313de3d07SAxel Dörfler	uint32	read_only_features;
5463db34c8SAxel Dörfler	uint8	uuid[16];
5563db34c8SAxel Dörfler	char	name[16];
5663db34c8SAxel Dörfler	char	last_mount_point[64];
5763db34c8SAxel Dörfler	uint32	algorithm_usage_bitmap;
5863db34c8SAxel Dörfler	uint8	preallocated_blocks;
5963db34c8SAxel Dörfler	uint8	preallocated_directory_blocks;
60d482c34eSJérôme Duval	uint16	reserved_gdt_blocks;
6113de3d07SAxel Dörfler
6263db34c8SAxel Dörfler	// journaling ext3 support
6363db34c8SAxel Dörfler	uint8	journal_uuid[16];
6463db34c8SAxel Dörfler	uint32	journal_inode;
6563db34c8SAxel Dörfler	uint32	journal_device;
6663db34c8SAxel Dörfler	uint32	last_orphan;
6763db34c8SAxel Dörfler	uint32	hash_seed[4];
6863db34c8SAxel Dörfler	uint8	default_hash_version;
6963db34c8SAxel Dörfler	uint8	_reserved1;
7021451bd3SJérôme Duval	uint16	group_descriptor_size;
7163db34c8SAxel Dörfler	uint32	default_mount_options;
7263db34c8SAxel Dörfler	uint32	first_meta_block_group;
73275463f4SAxel Dörfler	uint32	fs_creation_time;
74275463f4SAxel Dörfler	uint32	journal_inode_backup[17];
75275463f4SAxel Dörfler
76275463f4SAxel Dörfler	// ext4 support
77d8772e0cSJérôme Duval	uint32	num_blocks_high;
78d8772e0cSJérôme Duval	uint32	reserved_blocks_high;
79d8772e0cSJérôme Duval	uint32	free_blocks_high;
80275463f4SAxel Dörfler	uint16	min_inode_size;
81275463f4SAxel Dörfler	uint16	want_inode_size;
82275463f4SAxel Dörfler	uint32	flags;
83275463f4SAxel Dörfler	uint16	raid_stride;
84275463f4SAxel Dörfler	uint16	mmp_interval;
85275463f4SAxel Dörfler	uint64	mmp_block;
86275463f4SAxel Dörfler	uint32	raid_stripe_width;
87275463f4SAxel Dörfler	uint8	groups_per_flex_shift;
88ce4e12caSJérôme Duval	uint8	checksum_type;
89275463f4SAxel Dörfler	uint16	_reserved4;
90ce4e12caSJérôme Duval	uint64	kb_written;
91ce4e12caSJérôme Duval	uint32	_reserved5[60];
92ce4e12caSJérôme Duval	uint32	checksum_seed;
93ce4e12caSJérôme Duval	uint32	_reserved6[98];
94ce4e12caSJérôme Duval	uint32	checksum;
9563db34c8SAxel Dörfler
9663db34c8SAxel Dörfler	uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); }
97919f9c41SJérôme Duval	uint16 State() const { return B_LENDIAN_TO_HOST_INT16(state); }
98919f9c41SJérôme Duval	uint32 RevisionLevel() const { return B_LENDIAN_TO_HOST_INT16(revision_level); }
9963db34c8SAxel Dörfler	uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; }
10063db34c8SAxel Dörfler	uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); }
101d8772e0cSJérôme Duval	uint64 NumBlocks(bool has64bits) const
102d8772e0cSJérôme Duval	{
103d8772e0cSJérôme Duval		uint64 blocks = B_LENDIAN_TO_HOST_INT32(num_blocks);
104d8772e0cSJérôme Duval		if (has64bits)
105d8772e0cSJérôme Duval			blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32);
106d8772e0cSJérôme Duval		return blocks;
107d8772e0cSJérôme Duval	}
10863db34c8SAxel Dörfler	uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); }
109d8772e0cSJérôme Duval	uint64 FreeBlocks(bool has64bits) const
110d8772e0cSJérôme Duval	{
111d8772e0cSJérôme Duval		uint64 blocks = B_LENDIAN_TO_HOST_INT32(free_blocks);
112d8772e0cSJérôme Duval		if (has64bits)
113d8772e0cSJérôme Duval			blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(free_blocks_high) << 32);
114d8772e0cSJérôme Duval		return blocks;
115d8772e0cSJérôme Duval	}
116ce4e12caSJérôme Duval	uint64 ReservedBlocks(bool has64bits) const
117ce4e12caSJérôme Duval	{
118ce4e12caSJérôme Duval		uint64 blocks = B_LENDIAN_TO_HOST_INT32(reserved_blocks);
119ce4e12caSJérôme Duval		if (has64bits)
120ce4e12caSJérôme Duval			blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(reserved_blocks_high) << 32);
121ce4e12caSJérôme Duval		return blocks;
122ce4e12caSJérôme Duval	}
12363db34c8SAxel Dörfler	uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); }
12463db34c8SAxel Dörfler	uint32 FirstDataBlock() const
12563db34c8SAxel Dörfler		{ return B_LENDIAN_TO_HOST_INT32(first_data_block); }
12663db34c8SAxel Dörfler	uint32 BlocksPerGroup() const
12763db34c8SAxel Dörfler		{ return B_LENDIAN_TO_HOST_INT32(blocks_per_group); }
128ce4e12caSJérôme Duval	uint32 FragmentsPerGroup() const
129ce4e12caSJérôme Duval		{ return B_LENDIAN_TO_HOST_INT32(fragments_per_group); }
13063db34c8SAxel Dörfler	uint32 InodesPerGroup() const
13163db34c8SAxel Dörfler		{ return B_LENDIAN_TO_HOST_INT32(inodes_per_group); }
13263db34c8SAxel Dörfler	uint32 FirstMetaBlockGroup() const
13363db34c8SAxel Dörfler		{ return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); }
13463db34c8SAxel Dörfler	uint32 CompatibleFeatures() const
13563db34c8SAxel Dörfler		{ return B_LENDIAN_TO_HOST_INT32(compatible_features); }
13663db34c8SAxel Dörfler	uint32 ReadOnlyFeatures() const
13713de3d07SAxel Dörfler		{ return B_LENDIAN_TO_HOST_INT32(read_only_features); }
13863db34c8SAxel Dörfler	uint32 IncompatibleFeatures() const
13963db34c8SAxel Dörfler		{ return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
140d482c34eSJérôme Duval	uint16 ReservedGDTBlocks() const
141d482c34eSJérôme Duval		{ return B_LENDIAN_TO_HOST_INT16(reserved_gdt_blocks); }
142a1b0ec30SJérôme Duval	ino_t  JournalInode() const
143a1b0ec30SJérôme Duval		{ return B_LENDIAN_TO_HOST_INT32(journal_inode); }
144a1b0ec30SJérôme Duval	ino_t  LastOrphan() const
145a1b0ec30SJérôme Duval		{ return (ino_t)B_LENDIAN_TO_HOST_INT32(last_orphan); }
146919f9c41SJérôme Duval	uint32 HashSeed(uint8 i) const
147919f9c41SJérôme Duval		{ return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
14821451bd3SJérôme Duval	uint16 GroupDescriptorSize() const
14921451bd3SJérôme Duval		{ return B_LENDIAN_TO_HOST_INT16(group_descriptor_size); }
15063db34c8SAxel Dörfler
151a1b0ec30SJérôme Duval	void SetFreeInodes(uint32 freeInodes)
152a1b0ec30SJérôme Duval		{ free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); }
153d8772e0cSJérôme Duval	void SetFreeBlocks(uint64 freeBlocks, bool has64bits)
154d8772e0cSJérôme Duval	{
155d8772e0cSJérôme Duval		free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks & 0xffffffff);
156d8772e0cSJérôme Duval		if (has64bits)
1570ce7ab1eSJérôme Duval			free_blocks_high = B_HOST_TO_LENDIAN_INT32(freeBlocks >> 32);
158d8772e0cSJérôme Duval	}
159a1b0ec30SJérôme Duval	void SetLastOrphan(ino_t id)
160a1b0ec30SJérôme Duval		{ last_orphan = B_HOST_TO_LENDIAN_INT32((uint32)id); }
161cbda783eSAdrien Destugues	void SetReadOnlyFeatures(uint32 readOnlyFeatures)
162cbda783eSAdrien Destugues		{ read_only_features = B_HOST_TO_LENDIAN_INT32(readOnlyFeatures); }
1630ce7ab1eSJérôme Duval
16463db34c8SAxel Dörfler	bool IsValid();
16563db34c8SAxel Dörfler		// implemented in Volume.cpp
16663db34c8SAxel Dörfler} _PACKED;
16763db34c8SAxel Dörfler
168ce4e12caSJérôme Duval
16963db34c8SAxel Dörfler#define EXT2_OLD_REVISION		0
17063db34c8SAxel Dörfler#define EXT2_DYNAMIC_REVISION	1
17163db34c8SAxel Dörfler
172919f9c41SJérôme Duval#define EXT2_MAX_REVISION		EXT2_DYNAMIC_REVISION
173919f9c41SJérôme Duval
174919f9c41SJérôme Duval#define EXT2_FS_STATE_VALID		1	// File system was cleanly unmounted
175919f9c41SJérôme Duval#define EXT2_FS_STATE_ERROR		2	// File system has errors
176919f9c41SJérôme Duval#define EXT2_FS_STATE_ORPHAN	3	// Orphans are being recovered
177919f9c41SJérôme Duval
17863db34c8SAxel Dörfler// compatible features
179431a51ccSAxel Dörfler#define EXT2_FEATURE_DIRECTORY_PREALLOCATION	0x0001
180431a51ccSAxel Dörfler#define EXT2_FEATURE_IMAGIC_INODES				0x0002
181431a51ccSAxel Dörfler#define EXT2_FEATURE_HAS_JOURNAL				0x0004
182431a51ccSAxel Dörfler#define EXT2_FEATURE_EXT_ATTR					0x0008
183431a51ccSAxel Dörfler#define EXT2_FEATURE_RESIZE_INODE				0x0010
184431a51ccSAxel Dörfler#define EXT2_FEATURE_DIRECTORY_INDEX			0x0020
185ce4e12caSJérôme Duval#define EXT2_FEATURE_SPARSESUPER2				0x0200
18663db34c8SAxel Dörfler
18763db34c8SAxel Dörfler// read-only compatible features
188431a51ccSAxel Dörfler#define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER		0x0001
1897babd0d5SJérôme Duval#define EXT2_READ_ONLY_FEATURE_LARGE_FILE		0x0002
190431a51ccSAxel Dörfler#define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY	0x0004
191de66992bSJérôme Duval#define EXT2_READ_ONLY_FEATURE_HUGE_FILE		0x0008
19221451bd3SJérôme Duval#define EXT2_READ_ONLY_FEATURE_GDT_CSUM			0x0010
19321451bd3SJérôme Duval#define EXT2_READ_ONLY_FEATURE_DIR_NLINK		0x0020
19421451bd3SJérôme Duval#define EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE		0x0040
195ce4e12caSJérôme Duval#define EXT2_READ_ONLY_FEATURE_QUOTA			0x0100
196ce4e12caSJérôme Duval#define EXT2_READ_ONLY_FEATURE_BIGALLOC			0x0200
197ce4e12caSJérôme Duval#define EXT4_READ_ONLY_FEATURE_METADATA_CSUM	0x0400
198ce4e12caSJérôme Duval#define EXT4_READ_ONLY_FEATURE_READONLY			0x1000
199ce4e12caSJérôme Duval#define EXT4_READ_ONLY_FEATURE_PROJECT			0x2000
20063db34c8SAxel Dörfler
20163db34c8SAxel Dörfler// incompatible features
202431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION	0x0001
203431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE		0x0002
204431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_RECOVER		0x0004
205431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_JOURNAL		0x0008
206431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_META_GROUP	0x0010
207431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_EXTENTS		0x0040
208431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_64BIT			0x0080
209431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_MMP			0x0100
210431a51ccSAxel Dörfler#define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP	0x0200
211ce4e12caSJérôme Duval#define EXT2_INCOMPATIBLE_FEATURE_EA_INODE		0x0400
212ce4e12caSJérôme Duval#define EXT2_INCOMPATIBLE_FEATURE_DIR_DATA		0x1000
213ce4e12caSJérôme Duval#define EXT2_INCOMPATIBLE_FEATURE_CSUM_SEED		0x2000
214ce4e12caSJérôme Duval#define EXT2_INCOMPATIBLE_FEATURE_LARGEDIR		0x4000
215ce4e12caSJérôme Duval#define EXT2_INCOMPATIBLE_FEATURE_INLINE_DATA	0x8000
216ce4e12caSJérôme Duval#define EXT2_INCOMPATIBLE_FEATURE_ENCRYPT		0x10000
21763db34c8SAxel Dörfler
21863db34c8SAxel Dörfler// states
21963db34c8SAxel Dörfler#define EXT2_STATE_VALID						0x01
22063db34c8SAxel Dörfler#define	EXT2_STATE_INVALID						0x02
22163db34c8SAxel Dörfler
222d8772e0cSJérôme Duval#define EXT2_BLOCK_GROUP_NORMAL_SIZE			32
223d8772e0cSJérôme Duval
224141e1aadSJérôme Duval// block group flags
225141e1aadSJérôme Duval#define EXT2_BLOCK_GROUP_INODE_UNINIT	0x1
226141e1aadSJérôme Duval#define EXT2_BLOCK_GROUP_BLOCK_UNINIT	0x2
227141e1aadSJérôme Duval
228141e1aadSJérôme Duval
22963db34c8SAxel Dörflerstruct ext2_block_group {
23063db34c8SAxel Dörfler	uint32	block_bitmap;
23163db34c8SAxel Dörfler	uint32	inode_bitmap;
23263db34c8SAxel Dörfler	uint32	inode_table;
23363db34c8SAxel Dörfler	uint16	free_blocks;
23463db34c8SAxel Dörfler	uint16	free_inodes;
23563db34c8SAxel Dörfler	uint16	used_directories;
236d8772e0cSJérôme Duval	uint16	flags;
237ce4e12caSJérôme Duval	uint32	exclude_bitmap;
238ce4e12caSJérôme Duval	uint16	block_bitmap_csum;
239ce4e12caSJérôme Duval	uint16	inode_bitmap_csum;
240d8772e0cSJérôme Duval	uint16	unused_inodes;
241d8772e0cSJérôme Duval	uint16	checksum;
2420ce7ab1eSJérôme Duval
243d8772e0cSJérôme Duval	// ext4
244d8772e0cSJérôme Duval	uint32	block_bitmap_high;
245d8772e0cSJérôme Duval	uint32	inode_bitmap_high;
246d8772e0cSJérôme Duval	uint32	inode_table_high;
247d8772e0cSJérôme Duval	uint16	free_blocks_high;
248d8772e0cSJérôme Duval	uint16	free_inodes_high;
249d8772e0cSJérôme Duval	uint16	used_directories_high;
250d8772e0cSJérôme Duval	uint16	unused_inodes_high;
251ce4e12caSJérôme Duval	uint32	exclude_bitmap_high;
252ce4e12caSJérôme Duval	uint16	block_bitmap_csum_high;
253ce4e12caSJérôme Duval	uint16	inode_bitmap_csum_high;
254ce4e12caSJérôme Duval	uint32	_reserved;
255d8772e0cSJérôme Duval
25645af882dSJérôme Duval	fsblock_t BlockBitmap(bool has64bits) const
257d8772e0cSJérôme Duval	{
258d8772e0cSJérôme Duval		uint64 block = B_LENDIAN_TO_HOST_INT32(block_bitmap);
259d8772e0cSJérôme Duval		if (has64bits)
260d8772e0cSJérôme Duval			block |=
261d8772e0cSJérôme Duval				((uint64)B_LENDIAN_TO_HOST_INT32(block_bitmap_high) << 32);
262d8772e0cSJérôme Duval		return block;
263d8772e0cSJérôme Duval	}
26445af882dSJérôme Duval	fsblock_t InodeBitmap(bool has64bits) const
265d8772e0cSJérôme Duval	{
266d8772e0cSJérôme Duval		uint64 bitmap = B_LENDIAN_TO_HOST_INT32(inode_bitmap);
267d8772e0cSJérôme Duval		if (has64bits)
268d8772e0cSJérôme Duval			bitmap |=
269d8772e0cSJérôme Duval				((uint64)B_LENDIAN_TO_HOST_INT32(inode_bitmap_high) << 32);
270d8772e0cSJérôme Duval		return bitmap;
271d8772e0cSJérôme Duval	}
272d8772e0cSJérôme Duval	uint64 InodeTable(bool has64bits) const
273d8772e0cSJérôme Duval	{
274d8772e0cSJérôme Duval		uint64 table = B_LENDIAN_TO_HOST_INT32(inode_table);
275d8772e0cSJérôme Duval		if (has64bits)
276d8772e0cSJérôme Duval			table |= ((uint64)B_LENDIAN_TO_HOST_INT32(inode_table_high) << 32);
277d8772e0cSJérôme Duval		return table;
278d8772e0cSJérôme Duval	}
279d8772e0cSJérôme Duval	uint32 FreeBlocks(bool has64bits) const
280d8772e0cSJérôme Duval	{
281d8772e0cSJérôme Duval		uint32 blocks = B_LENDIAN_TO_HOST_INT16(free_blocks);
282d8772e0cSJérôme Duval		if (has64bits)
2830ce7ab1eSJérôme Duval			blocks |=
284d8772e0cSJérôme Duval				((uint32)B_LENDIAN_TO_HOST_INT16(free_blocks_high) << 16);
285d8772e0cSJérôme Duval		return blocks;
286d8772e0cSJérôme Duval	}
287d8772e0cSJérôme Duval	uint32 FreeInodes(bool has64bits) const
288d8772e0cSJérôme Duval	{
289d8772e0cSJérôme Duval		uint32 inodes = B_LENDIAN_TO_HOST_INT16(free_inodes);
290d8772e0cSJérôme Duval		if (has64bits)
2910ce7ab1eSJérôme Duval			inodes |=
292d8772e0cSJérôme Duval				((uint32)B_LENDIAN_TO_HOST_INT16(free_inodes_high) << 16);
293d8772e0cSJérôme Duval		return inodes;
294d8772e0cSJérôme Duval	}
295d8772e0cSJérôme Duval	uint32 UsedDirectories(bool has64bits) const
296d8772e0cSJérôme Duval	{
297d8772e0cSJérôme Duval		uint32 dirs = B_LENDIAN_TO_HOST_INT16(used_directories);
298d8772e0cSJérôme Duval		if (has64bits)
2990ce7ab1eSJérôme Duval			dirs |=
300d8772e0cSJérôme Duval				((uint32)B_LENDIAN_TO_HOST_INT16(used_directories_high) << 16);
301d8772e0cSJérôme Duval		return dirs;
302d8772e0cSJérôme Duval	}
303141e1aadSJérôme Duval	uint16 Flags() const { return B_LENDIAN_TO_HOST_INT16(flags); }
30479de91c1SJérôme Duval	uint32 UnusedInodes(bool has64bits) const
30579de91c1SJérôme Duval	{
30679de91c1SJérôme Duval		uint32 inodes = B_LENDIAN_TO_HOST_INT16(unused_inodes);
30779de91c1SJérôme Duval		if (has64bits)
3080ce7ab1eSJérôme Duval			inodes |=
30979de91c1SJérôme Duval				((uint32)B_LENDIAN_TO_HOST_INT16(unused_inodes_high) << 16);
31079de91c1SJérôme Duval		return inodes;
31179de91c1SJérôme Duval	}
3120ce7ab1eSJérôme Duval
313d8772e0cSJérôme Duval
314d8772e0cSJérôme Duval	void SetFreeBlocks(uint32 freeBlocks, bool has64bits)
315d8772e0cSJérôme Duval	{
316d8772e0cSJérôme Duval		free_blocks = B_HOST_TO_LENDIAN_INT16(freeBlocks) & 0xffff;
317d8772e0cSJérôme Duval		if (has64bits)
318d8772e0cSJérôme Duval			free_blocks_high = B_HOST_TO_LENDIAN_INT16(freeBlocks >> 16);
319d8772e0cSJérôme Duval	}
320d8772e0cSJérôme Duval
321d8772e0cSJérôme Duval	void SetFreeInodes(uint32 freeInodes, bool has64bits)
322d8772e0cSJérôme Duval	{
323d8772e0cSJérôme Duval		free_inodes = B_HOST_TO_LENDIAN_INT16(freeInodes) & 0xffff;
324d8772e0cSJérôme Duval		if (has64bits)
325d8772e0cSJérôme Duval			free_inodes_high = B_HOST_TO_LENDIAN_INT16(freeInodes >> 16);
326d8772e0cSJérôme Duval	}
327d8772e0cSJérôme Duval
328d8772e0cSJérôme Duval	void SetUsedDirectories(uint16 usedDirectories, bool has64bits)
329d8772e0cSJérôme Duval	{
330d8772e0cSJérôme Duval		used_directories = B_HOST_TO_LENDIAN_INT16(usedDirectories& 0xffff);
331d8772e0cSJérôme Duval		if (has64bits)
332d8772e0cSJérôme Duval			used_directories_high =
333d8772e0cSJérôme Duval				B_HOST_TO_LENDIAN_INT16(usedDirectories >> 16);
334d8772e0cSJérôme Duval	}
335141e1aadSJérôme Duval
336141e1aadSJérôme Duval	void SetFlags(uint16 newFlags)
337141e1aadSJérôme Duval	{
338141e1aadSJérôme Duval		flags = B_HOST_TO_LENDIAN_INT16(newFlags);
339141e1aadSJérôme Duval	}
34079de91c1SJérôme Duval
34179de91c1SJérôme Duval	void SetUnusedInodes(uint32 unusedInodes, bool has64bits)
34279de91c1SJérôme Duval	{
34379de91c1SJérôme Duval		unused_inodes = B_HOST_TO_LENDIAN_INT16(unusedInodes) & 0xffff;
34479de91c1SJérôme Duval		if (has64bits)
34579de91c1SJérôme Duval			unused_inodes_high = B_HOST_TO_LENDIAN_INT16(unusedInodes >> 16);
34679de91c1SJérôme Duval	}
347bac6cc8aSAxel Dörfler} _PACKED;
34863db34c8SAxel Dörfler
34963db34c8SAxel Dörfler#define EXT2_DIRECT_BLOCKS			12
35063db34c8SAxel Dörfler#define EXT2_ROOT_NODE				2
35163db34c8SAxel Dörfler#define EXT2_SHORT_SYMLINK_LENGTH	60
35263db34c8SAxel Dörfler
353b7cb8f8cSAxel Dörflerstruct ext2_data_stream {
354b7cb8f8cSAxel Dörfler	uint32 direct[EXT2_DIRECT_BLOCKS];
355b7cb8f8cSAxel Dörfler	uint32 indirect;
356b7cb8f8cSAxel Dörfler	uint32 double_indirect;
357b7cb8f8cSAxel Dörfler	uint32 triple_indirect;
358bac6cc8aSAxel Dörfler} _PACKED;
359b7cb8f8cSAxel Dörfler
36045af882dSJérôme Duval#define EXT2_EXTENT_MAGIC			0xf30a
36140e0165bSJérôme Duval#define EXT2_EXTENT_MAX_LENGTH		0x8000
36245af882dSJérôme Duval
36345af882dSJérôme Duvalstruct ext2_extent_header {
36445af882dSJérôme Duval	uint16 magic;
36545af882dSJérôme Duval	uint16 num_entries;
36645af882dSJérôme Duval	uint16 max_entries;
36745af882dSJérôme Duval	uint16 depth;
36845af882dSJérôme Duval	uint32 generation;
36945af882dSJérôme Duval	bool IsValid() const
37045af882dSJérôme Duval	{
37145af882dSJérôme Duval		return B_LENDIAN_TO_HOST_INT16(magic) == EXT2_EXTENT_MAGIC;
37245af882dSJérôme Duval	}
37345af882dSJérôme Duval	uint16 NumEntries() const { return B_LENDIAN_TO_HOST_INT16(num_entries); }
37445af882dSJérôme Duval	uint16 MaxEntries() const { return B_LENDIAN_TO_HOST_INT16(max_entries); }
37545af882dSJérôme Duval	uint16 Depth() const { return B_LENDIAN_TO_HOST_INT16(depth); }
37645af882dSJérôme Duval	uint32 Generation() const { return B_LENDIAN_TO_HOST_INT32(generation); }
37745af882dSJérôme Duval	void SetNumEntries(uint16 num)
37845af882dSJérôme Duval		{ num_entries = B_HOST_TO_LENDIAN_INT16(num); }
37945af882dSJérôme Duval	void SetMaxEntries(uint16 max)
38045af882dSJérôme Duval		{ max_entries = B_HOST_TO_LENDIAN_INT16(max); }
38145af882dSJérôme Duval	void SetDepth(uint16 _depth)
38245af882dSJérôme Duval		{ depth = B_HOST_TO_LENDIAN_INT16(_depth); }
38345af882dSJérôme Duval	void SetGeneration(uint32 _generation)
38445af882dSJérôme Duval		{ generation = B_HOST_TO_LENDIAN_INT32(_generation); }
38545af882dSJérôme Duval} _PACKED;
38645af882dSJérôme Duval
387ce4e12caSJérôme Duvalstruct ext2_extent_tail {
388ce4e12caSJérôme Duval	uint32 checksum;
389ce4e12caSJérôme Duval} _PACKED;
390ce4e12caSJérôme Duval
39145af882dSJérôme Duvalstruct ext2_extent_index {
39245af882dSJérôme Duval	uint32 logical_block;
39345af882dSJérôme Duval	uint32 physical_block;
39445af882dSJérôme Duval	uint16 physical_block_high;
39545af882dSJérôme Duval	uint16 _reserved;
39645af882dSJérôme Duval	uint32 LogicalBlock() const
39745af882dSJérôme Duval		{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
39845af882dSJérôme Duval	uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
39945af882dSJérôme Duval		| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
40045af882dSJérôme Duval	void SetLogicalBlock(uint32 block) {
40145af882dSJérôme Duval		logical_block = B_HOST_TO_LENDIAN_INT32(block); }
40245af882dSJérôme Duval	void SetPhysicalBlock(uint64 block) {
40345af882dSJérôme Duval		physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff);
40445af882dSJérôme Duval		physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); }
40545af882dSJérôme Duval} _PACKED;
40645af882dSJérôme Duval
40745af882dSJérôme Duvalstruct ext2_extent_entry {
40845af882dSJérôme Duval	uint32 logical_block;
40945af882dSJérôme Duval	uint16 length;
41045af882dSJérôme Duval	uint16 physical_block_high;
41145af882dSJérôme Duval	uint32 physical_block;
41245af882dSJérôme Duval	uint32 LogicalBlock() const
41345af882dSJérôme Duval		{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
4140ce7ab1eSJérôme Duval	uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length) == 0x8000
41545af882dSJérôme Duval		? 0x8000 : B_LENDIAN_TO_HOST_INT16(length) & 0x7fff; }
41645af882dSJérôme Duval	uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
41745af882dSJérôme Duval		| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
41845af882dSJérôme Duval	void SetLogicalBlock(uint32 block) {
41945af882dSJérôme Duval		logical_block = B_HOST_TO_LENDIAN_INT32(block); }
42045af882dSJérôme Duval	void SetLength(uint16 _length) {
42145af882dSJérôme Duval		length = B_HOST_TO_LENDIAN_INT16(_length) & 0x7fff; }
42245af882dSJérôme Duval	void SetPhysicalBlock(uint64 block) {
42345af882dSJérôme Duval		physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff);
42445af882dSJérôme Duval		physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); }
42545af882dSJérôme Duval} _PACKED;
42645af882dSJérôme Duval
42745af882dSJérôme Duvalstruct ext2_extent_stream {
42845af882dSJérôme Duval	ext2_extent_header extent_header;
42945af882dSJérôme Duval	union {
43045af882dSJérôme Duval		ext2_extent_entry extent_entries[4];
43145af882dSJérôme Duval		ext2_extent_index extent_index[4];
43245af882dSJérôme Duval	};
43345af882dSJérôme Duval} _PACKED;
43445af882dSJérôme Duval
4356bfb10d3SJérôme Duval#define EXT2_INODE_NORMAL_SIZE		128
436d482c34eSJérôme Duval#define EXT2_INODE_MAX_LINKS		65000
4376bfb10d3SJérôme Duval
43863db34c8SAxel Dörflerstruct ext2_inode {
43963db34c8SAxel Dörfler	uint16	mode;
44063db34c8SAxel Dörfler	uint16	uid;
44163db34c8SAxel Dörfler	uint32	size;
44263db34c8SAxel Dörfler	uint32	access_time;
4436bfb10d3SJérôme Duval	uint32	change_time;
44463db34c8SAxel Dörfler	uint32	modification_time;
44563db34c8SAxel Dörfler	uint32	deletion_time;
44663db34c8SAxel Dörfler	uint16	gid;
44763db34c8SAxel Dörfler	uint16	num_links;
44863db34c8SAxel Dörfler	uint32	num_blocks;
44963db34c8SAxel Dörfler	uint32	flags;
4506bfb10d3SJérôme Duval	uint32	version;
45163db34c8SAxel Dörfler	union {
452b7cb8f8cSAxel Dörfler		ext2_data_stream stream;
45363db34c8SAxel Dörfler		char symlink[EXT2_SHORT_SYMLINK_LENGTH];
45445af882dSJérôme Duval		ext2_extent_stream extent_stream;
455b7cb8f8cSAxel Dörfler	};
45663db34c8SAxel Dörfler	uint32	generation;
45763db34c8SAxel Dörfler	uint32	file_access_control;
4580680840aSAxel Dörfler	union {
4590680840aSAxel Dörfler		// for directories vs. files
4600680840aSAxel Dörfler		uint32	directory_access_control;
4610680840aSAxel Dörfler		uint32	size_high;
4620680840aSAxel Dörfler	};
46363db34c8SAxel Dörfler	uint32	fragment;
464de66992bSJérôme Duval	union {
465de66992bSJérôme Duval		struct {
466de66992bSJérôme Duval			uint8	fragment_number;
467de66992bSJérôme Duval			uint8	fragment_size;
468de66992bSJérôme Duval		};
469de66992bSJérôme Duval		uint16 num_blocks_high;
470de66992bSJérôme Duval	};
471ce4e12caSJérôme Duval	uint16	file_access_control_high;
47263db34c8SAxel Dörfler	uint16	uid_high;
47363db34c8SAxel Dörfler	uint16	gid_high;
474ce4e12caSJérôme Duval	uint16	checksum;
475ce4e12caSJérôme Duval	uint16	reserved;
4760ce7ab1eSJérôme Duval
4776bfb10d3SJérôme Duval	// extra attributes
478275463f4SAxel Dörfler	uint16	extra_inode_size;
479ce4e12caSJérôme Duval	uint16	checksum_high;
4806bfb10d3SJérôme Duval	uint32	change_time_extra;
4816bfb10d3SJérôme Duval	uint32	modification_time_extra;
4826bfb10d3SJérôme Duval	uint32	access_time_extra;
4836bfb10d3SJérôme Duval	uint32	creation_time;
4846bfb10d3SJérôme Duval	uint32	creation_time_extra;
4856bfb10d3SJérôme Duval	uint32	version_high;
48663db34c8SAxel Dörfler
48763db34c8SAxel Dörfler	uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
48863db34c8SAxel Dörfler	uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
4890680840aSAxel Dörfler	uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
490a1b0ec30SJérôme Duval	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
491de66992bSJérôme Duval	uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
492de66992bSJérôme Duval		| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
49363db34c8SAxel Dörfler
4946bfb10d3SJérôme Duval	static void _DecodeTime(struct timespec *timespec, uint32 time,
4956bfb10d3SJérôme Duval		uint32 time_extra, bool extra)
4966bfb10d3SJérôme Duval	{
4976bfb10d3SJérôme Duval		timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time);
4986bfb10d3SJérôme Duval		if (extra && sizeof(timespec->tv_sec) > 4)
4990ce7ab1eSJérôme Duval			timespec->tv_sec |=
5006bfb10d3SJérôme Duval				(uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32;
5016bfb10d3SJérôme Duval		if (extra)
5026bfb10d3SJérôme Duval			timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2;
5036bfb10d3SJérôme Duval		else
5046bfb10d3SJérôme Duval			timespec->tv_nsec = 0;
5056bfb10d3SJérôme Duval	}
5060ce7ab1eSJérôme Duval
5070ce7ab1eSJérôme Duval	void GetModificationTime(struct timespec *timespec, bool extra) const
5080ce7ab1eSJérôme Duval		{ _DecodeTime(timespec, modification_time, modification_time_extra,
5096bfb10d3SJérôme Duval			extra); }
5100ce7ab1eSJérôme Duval	void GetAccessTime(struct timespec *timespec, bool extra) const
5116bfb10d3SJérôme Duval		{ _DecodeTime(timespec, access_time, access_time_extra, extra); }
5126bfb10d3SJérôme Duval	void GetChangeTime(struct timespec *timespec, bool extra) const
5136bfb10d3SJérôme Duval		{ _DecodeTime(timespec, change_time, change_time_extra, extra); }
5146bfb10d3SJérôme Duval	void GetCreationTime(struct timespec *timespec, bool extra) const
5156bfb10d3SJérôme Duval	{
5166bfb10d3SJérôme Duval		if (extra)
5176bfb10d3SJérôme Duval			_DecodeTime(timespec, creation_time, creation_time_extra, extra);
5186bfb10d3SJérôme Duval		else {
5196bfb10d3SJérôme Duval			timespec->tv_sec = 0;
5206bfb10d3SJérôme Duval			timespec->tv_nsec = 0;
5216bfb10d3SJérôme Duval		}
5226bfb10d3SJérôme Duval	}
5236bfb10d3SJérôme Duval	time_t DeletionTime() const
5246bfb10d3SJérôme Duval		{ return B_LENDIAN_TO_HOST_INT32(deletion_time); }
5256bfb10d3SJérôme Duval
5266bfb10d3SJérôme Duval	static uint32 _EncodeTime(const struct timespec *timespec)
5276bfb10d3SJérôme Duval	{
5286bfb10d3SJérôme Duval		uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc;
5296bfb10d3SJérôme Duval		if (sizeof(timespec->tv_sec) > 4)
5306bfb10d3SJérôme Duval			time |= (uint64)timespec->tv_sec >> 32;
5316bfb10d3SJérôme Duval		return B_HOST_TO_LENDIAN_INT32(time);
5326bfb10d3SJérôme Duval	}
5330ce7ab1eSJérôme Duval
5346bfb10d3SJérôme Duval	void SetModificationTime(const struct timespec *timespec, bool extra)
5356bfb10d3SJérôme Duval	{
5366bfb10d3SJérôme Duval		modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
5376bfb10d3SJérôme Duval		if (extra)
5386bfb10d3SJérôme Duval			modification_time_extra = _EncodeTime(timespec);
5396bfb10d3SJérôme Duval	}
540