xref: /haiku/src/add-ons/kernel/file_systems/ext2/ext2.h (revision 97f11716bfaa0f385eb0e28a52bf56a5023b9e99)
1 /*
2  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 #ifndef EXT2_H
6 #define EXT2_H
7 
8 
9 #include <sys/stat.h>
10 
11 #include <ByteOrder.h>
12 #include <fs_interface.h>
13 #include <KernelExport.h>
14 
15 
16 typedef uint64 fileblock_t;		// file block number
17 typedef uint64 fsblock_t;		// filesystem block number
18 
19 
20 #define EXT2_SUPER_BLOCK_OFFSET	1024
21 
22 struct ext2_super_block {
23 	uint32	num_inodes;
24 	uint32	num_blocks;
25 	uint32	reserved_blocks;
26 	uint32	free_blocks;
27 	uint32	free_inodes;
28 	uint32	first_data_block;
29 	uint32	block_shift;
30 	uint32	fragment_shift;
31 	uint32	blocks_per_group;
32 	uint32	fragments_per_group;
33 	uint32	inodes_per_group;
34 	uint32	mount_time;
35 	uint32	write_time;
36 	uint16	mount_count;
37 	uint16	max_mount_count;
38 	uint16	magic;
39 	uint16	state;
40 	uint16	error_handling;
41 	uint16	minor_revision_level;
42 	uint32	last_check_time;
43 	uint32	check_interval;
44 	uint32	creator_os;
45 	uint32	revision_level;
46 	uint16	reserved_blocks_uid;
47 	uint16	reserved_blocks_gid;
48 	uint32	first_inode;
49 	uint16	inode_size;
50 	uint16	block_group;
51 	uint32	compatible_features;
52 	uint32	incompatible_features;
53 	uint32	read_only_features;
54 	uint8	uuid[16];
55 	char	name[16];
56 	char	last_mount_point[64];
57 	uint32	algorithm_usage_bitmap;
58 	uint8	preallocated_blocks;
59 	uint8	preallocated_directory_blocks;
60 	uint16	reserved_gdt_blocks;
61 
62 	// journaling ext3 support
63 	uint8	journal_uuid[16];
64 	uint32	journal_inode;
65 	uint32	journal_device;
66 	uint32	last_orphan;
67 	uint32	hash_seed[4];
68 	uint8	default_hash_version;
69 	uint8	_reserved1;
70 	uint16	group_descriptor_size;
71 	uint32	default_mount_options;
72 	uint32	first_meta_block_group;
73 	uint32	fs_creation_time;
74 	uint32	journal_inode_backup[17];
75 
76 	// ext4 support
77 	uint32	num_blocks_high;
78 	uint32	reserved_blocks_high;
79 	uint32	free_blocks_high;
80 	uint16	min_inode_size;
81 	uint16	want_inode_size;
82 	uint32	flags;
83 	uint16	raid_stride;
84 	uint16	mmp_interval;
85 	uint64	mmp_block;
86 	uint32	raid_stripe_width;
87 	uint8	groups_per_flex_shift;
88 	uint8	checksum_type;
89 	uint16	_reserved4;
90 	uint64	kb_written;
91 	uint32	_reserved5[60];
92 	uint32	checksum_seed;
93 	uint32	_reserved6[98];
94 	uint32	checksum;
95 
Magicext2_super_block96 	uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); }
Stateext2_super_block97 	uint16 State() const { return B_LENDIAN_TO_HOST_INT16(state); }
RevisionLevelext2_super_block98 	uint32 RevisionLevel() const { return B_LENDIAN_TO_HOST_INT16(revision_level); }
BlockShiftext2_super_block99 	uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; }
NumInodesext2_super_block100 	uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); }
NumBlocksext2_super_block101 	uint64 NumBlocks(bool has64bits) const
102 	{
103 		uint64 blocks = B_LENDIAN_TO_HOST_INT32(num_blocks);
104 		if (has64bits)
105 			blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32);
106 		return blocks;
107 	}
FreeInodesext2_super_block108 	uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); }
FreeBlocksext2_super_block109 	uint64 FreeBlocks(bool has64bits) const
110 	{
111 		uint64 blocks = B_LENDIAN_TO_HOST_INT32(free_blocks);
112 		if (has64bits)
113 			blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(free_blocks_high) << 32);
114 		return blocks;
115 	}
ReservedBlocksext2_super_block116 	uint64 ReservedBlocks(bool has64bits) const
117 	{
118 		uint64 blocks = B_LENDIAN_TO_HOST_INT32(reserved_blocks);
119 		if (has64bits)
120 			blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(reserved_blocks_high) << 32);
121 		return blocks;
122 	}
InodeSizeext2_super_block123 	uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); }
FirstDataBlockext2_super_block124 	uint32 FirstDataBlock() const
125 		{ return B_LENDIAN_TO_HOST_INT32(first_data_block); }
BlocksPerGroupext2_super_block126 	uint32 BlocksPerGroup() const
127 		{ return B_LENDIAN_TO_HOST_INT32(blocks_per_group); }
FragmentsPerGroupext2_super_block128 	uint32 FragmentsPerGroup() const
129 		{ return B_LENDIAN_TO_HOST_INT32(fragments_per_group); }
InodesPerGroupext2_super_block130 	uint32 InodesPerGroup() const
131 		{ return B_LENDIAN_TO_HOST_INT32(inodes_per_group); }
FirstMetaBlockGroupext2_super_block132 	uint32 FirstMetaBlockGroup() const
133 		{ return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); }
CompatibleFeaturesext2_super_block134 	uint32 CompatibleFeatures() const
135 		{ return B_LENDIAN_TO_HOST_INT32(compatible_features); }
ReadOnlyFeaturesext2_super_block136 	uint32 ReadOnlyFeatures() const
137 		{ return B_LENDIAN_TO_HOST_INT32(read_only_features); }
IncompatibleFeaturesext2_super_block138 	uint32 IncompatibleFeatures() const
139 		{ return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
ReservedGDTBlocksext2_super_block140 	uint16 ReservedGDTBlocks() const
141 		{ return B_LENDIAN_TO_HOST_INT16(reserved_gdt_blocks); }
JournalInodeext2_super_block142 	ino_t  JournalInode() const
143 		{ return B_LENDIAN_TO_HOST_INT32(journal_inode); }
LastOrphanext2_super_block144 	ino_t  LastOrphan() const
145 		{ return (ino_t)B_LENDIAN_TO_HOST_INT32(last_orphan); }
HashSeedext2_super_block146 	uint32 HashSeed(uint8 i) const
147 		{ return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
GroupDescriptorSizeext2_super_block148 	uint16 GroupDescriptorSize() const
149 		{ return B_LENDIAN_TO_HOST_INT16(group_descriptor_size); }
150 
SetFreeInodesext2_super_block151 	void SetFreeInodes(uint32 freeInodes)
152 		{ free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); }
SetFreeBlocksext2_super_block153 	void SetFreeBlocks(uint64 freeBlocks, bool has64bits)
154 	{
155 		free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks & 0xffffffff);
156 		if (has64bits)
157 			free_blocks_high = B_HOST_TO_LENDIAN_INT32(freeBlocks >> 32);
158 	}
SetLastOrphanext2_super_block159 	void SetLastOrphan(ino_t id)
160 		{ last_orphan = B_HOST_TO_LENDIAN_INT32((uint32)id); }
SetReadOnlyFeaturesext2_super_block161 	void SetReadOnlyFeatures(uint32 readOnlyFeatures)
162 		{ read_only_features = B_HOST_TO_LENDIAN_INT32(readOnlyFeatures); }
163 
164 	bool IsValid();
165 		// implemented in Volume.cpp
166 } _PACKED;
167 
168 
169 #define EXT2_OLD_REVISION		0
170 #define EXT2_DYNAMIC_REVISION	1
171 
172 #define EXT2_MAX_REVISION		EXT2_DYNAMIC_REVISION
173 
174 #define EXT2_FS_STATE_VALID		0x1	// File system was cleanly unmounted
175 #define EXT2_FS_STATE_ERROR		0x2	// File system has errors
176 #define EXT2_FS_STATE_ORPHAN	0x4	// Orphans are being recovered
177 
178 // compatible features
179 #define EXT2_FEATURE_DIRECTORY_PREALLOCATION	0x0001
180 #define EXT2_FEATURE_IMAGIC_INODES				0x0002
181 #define EXT2_FEATURE_HAS_JOURNAL				0x0004
182 #define EXT2_FEATURE_EXT_ATTR					0x0008
183 #define EXT2_FEATURE_RESIZE_INODE				0x0010
184 #define EXT2_FEATURE_DIRECTORY_INDEX			0x0020
185 #define EXT2_FEATURE_SPARSESUPER2				0x0200
186 
187 // read-only compatible features
188 #define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER		0x0001
189 #define EXT2_READ_ONLY_FEATURE_LARGE_FILE		0x0002
190 #define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY	0x0004
191 #define EXT2_READ_ONLY_FEATURE_HUGE_FILE		0x0008
192 #define EXT2_READ_ONLY_FEATURE_GDT_CSUM			0x0010
193 #define EXT2_READ_ONLY_FEATURE_DIR_NLINK		0x0020
194 #define EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE		0x0040
195 #define EXT2_READ_ONLY_FEATURE_QUOTA			0x0100
196 #define EXT2_READ_ONLY_FEATURE_BIGALLOC			0x0200
197 #define EXT4_READ_ONLY_FEATURE_METADATA_CSUM	0x0400
198 #define EXT4_READ_ONLY_FEATURE_READONLY			0x1000
199 #define EXT4_READ_ONLY_FEATURE_PROJECT			0x2000
200 
201 // incompatible features
202 #define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION	0x0001
203 #define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE		0x0002
204 #define EXT2_INCOMPATIBLE_FEATURE_RECOVER		0x0004
205 #define EXT2_INCOMPATIBLE_FEATURE_JOURNAL		0x0008
206 #define EXT2_INCOMPATIBLE_FEATURE_META_GROUP	0x0010
207 #define EXT2_INCOMPATIBLE_FEATURE_EXTENTS		0x0040
208 #define EXT2_INCOMPATIBLE_FEATURE_64BIT			0x0080
209 #define EXT2_INCOMPATIBLE_FEATURE_MMP			0x0100
210 #define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP	0x0200
211 #define EXT2_INCOMPATIBLE_FEATURE_EA_INODE		0x0400
212 #define EXT2_INCOMPATIBLE_FEATURE_DIR_DATA		0x1000
213 #define EXT2_INCOMPATIBLE_FEATURE_CSUM_SEED		0x2000
214 #define EXT2_INCOMPATIBLE_FEATURE_LARGEDIR		0x4000
215 #define EXT2_INCOMPATIBLE_FEATURE_INLINE_DATA	0x8000
216 #define EXT2_INCOMPATIBLE_FEATURE_ENCRYPT		0x10000
217 
218 // states
219 #define EXT2_STATE_VALID						0x01
220 #define	EXT2_STATE_INVALID						0x02
221 
222 #define EXT2_BLOCK_GROUP_NORMAL_SIZE			32
223 
224 // block group flags
225 #define EXT2_BLOCK_GROUP_INODE_UNINIT	0x1
226 #define EXT2_BLOCK_GROUP_BLOCK_UNINIT	0x2
227 
228 
229 struct ext2_block_group {
230 	uint32	block_bitmap;
231 	uint32	inode_bitmap;
232 	uint32	inode_table;
233 	uint16	free_blocks;
234 	uint16	free_inodes;
235 	uint16	used_directories;
236 	uint16	flags;
237 	uint32	exclude_bitmap;
238 	uint16	block_bitmap_csum;
239 	uint16	inode_bitmap_csum;
240 	uint16	unused_inodes;
241 	uint16	checksum;
242 
243 	// ext4
244 	uint32	block_bitmap_high;
245 	uint32	inode_bitmap_high;
246 	uint32	inode_table_high;
247 	uint16	free_blocks_high;
248 	uint16	free_inodes_high;
249 	uint16	used_directories_high;
250 	uint16	unused_inodes_high;
251 	uint32	exclude_bitmap_high;
252 	uint16	block_bitmap_csum_high;
253 	uint16	inode_bitmap_csum_high;
254 	uint32	_reserved;
255 
BlockBitmapext2_block_group256 	fsblock_t BlockBitmap(bool has64bits) const
257 	{
258 		uint64 block = B_LENDIAN_TO_HOST_INT32(block_bitmap);
259 		if (has64bits)
260 			block |=
261 				((uint64)B_LENDIAN_TO_HOST_INT32(block_bitmap_high) << 32);
262 		return block;
263 	}
InodeBitmapext2_block_group264 	fsblock_t InodeBitmap(bool has64bits) const
265 	{
266 		uint64 bitmap = B_LENDIAN_TO_HOST_INT32(inode_bitmap);
267 		if (has64bits)
268 			bitmap |=
269 				((uint64)B_LENDIAN_TO_HOST_INT32(inode_bitmap_high) << 32);
270 		return bitmap;
271 	}
InodeTableext2_block_group272 	uint64 InodeTable(bool has64bits) const
273 	{
274 		uint64 table = B_LENDIAN_TO_HOST_INT32(inode_table);
275 		if (has64bits)
276 			table |= ((uint64)B_LENDIAN_TO_HOST_INT32(inode_table_high) << 32);
277 		return table;
278 	}
FreeBlocksext2_block_group279 	uint32 FreeBlocks(bool has64bits) const
280 	{
281 		uint32 blocks = B_LENDIAN_TO_HOST_INT16(free_blocks);
282 		if (has64bits)
283 			blocks |=
284 				((uint32)B_LENDIAN_TO_HOST_INT16(free_blocks_high) << 16);
285 		return blocks;
286 	}
FreeInodesext2_block_group287 	uint32 FreeInodes(bool has64bits) const
288 	{
289 		uint32 inodes = B_LENDIAN_TO_HOST_INT16(free_inodes);
290 		if (has64bits)
291 			inodes |=
292 				((uint32)B_LENDIAN_TO_HOST_INT16(free_inodes_high) << 16);
293 		return inodes;
294 	}
UsedDirectoriesext2_block_group295 	uint32 UsedDirectories(bool has64bits) const
296 	{
297 		uint32 dirs = B_LENDIAN_TO_HOST_INT16(used_directories);
298 		if (has64bits)
299 			dirs |=
300 				((uint32)B_LENDIAN_TO_HOST_INT16(used_directories_high) << 16);
301 		return dirs;
302 	}
Flagsext2_block_group303 	uint16 Flags() const { return B_LENDIAN_TO_HOST_INT16(flags); }
UnusedInodesext2_block_group304 	uint32 UnusedInodes(bool has64bits) const
305 	{
306 		uint32 inodes = B_LENDIAN_TO_HOST_INT16(unused_inodes);
307 		if (has64bits)
308 			inodes |=
309 				((uint32)B_LENDIAN_TO_HOST_INT16(unused_inodes_high) << 16);
310 		return inodes;
311 	}
312 
313 
SetFreeBlocksext2_block_group314 	void SetFreeBlocks(uint32 freeBlocks, bool has64bits)
315 	{
316 		free_blocks = B_HOST_TO_LENDIAN_INT16(freeBlocks) & 0xffff;
317 		if (has64bits)
318 			free_blocks_high = B_HOST_TO_LENDIAN_INT16(freeBlocks >> 16);
319 	}
320 
SetFreeInodesext2_block_group321 	void SetFreeInodes(uint32 freeInodes, bool has64bits)
322 	{
323 		free_inodes = B_HOST_TO_LENDIAN_INT16(freeInodes) & 0xffff;
324 		if (has64bits)
325 			free_inodes_high = B_HOST_TO_LENDIAN_INT16(freeInodes >> 16);
326 	}
327 
SetUsedDirectoriesext2_block_group328 	void SetUsedDirectories(uint16 usedDirectories, bool has64bits)
329 	{
330 		used_directories = B_HOST_TO_LENDIAN_INT16(usedDirectories& 0xffff);
331 		if (has64bits)
332 			used_directories_high =
333 				B_HOST_TO_LENDIAN_INT16(usedDirectories >> 16);
334 	}
335 
SetFlagsext2_block_group336 	void SetFlags(uint16 newFlags)
337 	{
338 		flags = B_HOST_TO_LENDIAN_INT16(newFlags);
339 	}
340 
SetUnusedInodesext2_block_group341 	void SetUnusedInodes(uint32 unusedInodes, bool has64bits)
342 	{
343 		unused_inodes = B_HOST_TO_LENDIAN_INT16(unusedInodes) & 0xffff;
344 		if (has64bits)
345 			unused_inodes_high = B_HOST_TO_LENDIAN_INT16(unusedInodes >> 16);
346 	}
347 } _PACKED;
348 
349 #define EXT2_DIRECT_BLOCKS			12
350 #define EXT2_ROOT_NODE				2
351 #define EXT2_SHORT_SYMLINK_LENGTH	60
352 
353 struct ext2_data_stream {
354 	uint32 direct[EXT2_DIRECT_BLOCKS];
355 	uint32 indirect;
356 	uint32 double_indirect;
357 	uint32 triple_indirect;
358 } _PACKED;
359 
360 #define EXT2_EXTENT_MAGIC			0xf30a
361 #define EXT2_EXTENT_MAX_LENGTH		0x8000
362 
363 struct ext2_extent_header {
364 	uint16 magic;
365 	uint16 num_entries;
366 	uint16 max_entries;
367 	uint16 depth;
368 	uint32 generation;
IsValidext2_extent_header369 	bool IsValid() const
370 	{
371 		return B_LENDIAN_TO_HOST_INT16(magic) == EXT2_EXTENT_MAGIC;
372 	}
NumEntriesext2_extent_header373 	uint16 NumEntries() const { return B_LENDIAN_TO_HOST_INT16(num_entries); }
MaxEntriesext2_extent_header374 	uint16 MaxEntries() const { return B_LENDIAN_TO_HOST_INT16(max_entries); }
Depthext2_extent_header375 	uint16 Depth() const { return B_LENDIAN_TO_HOST_INT16(depth); }
Generationext2_extent_header376 	uint32 Generation() const { return B_LENDIAN_TO_HOST_INT32(generation); }
SetNumEntriesext2_extent_header377 	void SetNumEntries(uint16 num)
378 		{ num_entries = B_HOST_TO_LENDIAN_INT16(num); }
SetMaxEntriesext2_extent_header379 	void SetMaxEntries(uint16 max)
380 		{ max_entries = B_HOST_TO_LENDIAN_INT16(max); }
SetDepthext2_extent_header381 	void SetDepth(uint16 _depth)
382 		{ depth = B_HOST_TO_LENDIAN_INT16(_depth); }
SetGenerationext2_extent_header383 	void SetGeneration(uint32 _generation)
384 		{ generation = B_HOST_TO_LENDIAN_INT32(_generation); }
385 } _PACKED;
386 
387 struct ext2_extent_tail {
388 	uint32 checksum;
389 } _PACKED;
390 
391 struct ext2_extent_index {
392 	uint32 logical_block;
393 	uint32 physical_block;
394 	uint16 physical_block_high;
395 	uint16 _reserved;
LogicalBlockext2_extent_index396 	uint32 LogicalBlock() const
397 		{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
PhysicalBlockext2_extent_index398 	uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
399 		| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
SetLogicalBlockext2_extent_index400 	void SetLogicalBlock(uint32 block) {
401 		logical_block = B_HOST_TO_LENDIAN_INT32(block); }
SetPhysicalBlockext2_extent_index402 	void SetPhysicalBlock(uint64 block) {
403 		physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff);
404 		physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); }
405 } _PACKED;
406 
407 struct ext2_extent_entry {
408 	uint32 logical_block;
409 	uint16 length;
410 	uint16 physical_block_high;
411 	uint32 physical_block;
LogicalBlockext2_extent_entry412 	uint32 LogicalBlock() const
413 		{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
Lengthext2_extent_entry414 	uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length) == 0x8000
415 		? 0x8000 : B_LENDIAN_TO_HOST_INT16(length) & 0x7fff; }
PhysicalBlockext2_extent_entry416 	uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
417 		| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
SetLogicalBlockext2_extent_entry418 	void SetLogicalBlock(uint32 block) {
419 		logical_block = B_HOST_TO_LENDIAN_INT32(block); }
SetLengthext2_extent_entry420 	void SetLength(uint16 _length) {
421 		length = B_HOST_TO_LENDIAN_INT16(_length) & 0x7fff; }
SetPhysicalBlockext2_extent_entry422 	void SetPhysicalBlock(uint64 block) {
423 		physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff);
424 		physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); }
425 } _PACKED;
426 
427 struct ext2_extent_stream {
428 	ext2_extent_header extent_header;
429 	union {
430 		ext2_extent_entry extent_entries[4];
431 		ext2_extent_index extent_index[4];
432 	};
433 } _PACKED;
434 
435 #define EXT2_INODE_NORMAL_SIZE		128
436 #define EXT2_INODE_MAX_LINKS		65000
437 
438 struct ext2_inode {
439 	uint16	mode;
440 	uint16	uid;
441 	uint32	size;
442 	uint32	access_time;
443 	uint32	change_time;
444 	uint32	modification_time;
445 	uint32	deletion_time;
446 	uint16	gid;
447 	uint16	num_links;
448 	uint32	num_blocks;
449 	uint32	flags;
450 	uint32	version;
451 	union {
452 		ext2_data_stream stream;
453 		char symlink[EXT2_SHORT_SYMLINK_LENGTH];
454 		ext2_extent_stream extent_stream;
455 	};
456 	uint32	generation;
457 	uint32	file_access_control;
458 	union {
459 		// for directories vs. files
460 		uint32	directory_access_control;
461 		uint32	size_high;
462 	};
463 	uint32	fragment;
464 	union {
465 		struct {
466 			uint8	fragment_number;
467 			uint8	fragment_size;
468 		};
469 		uint16 num_blocks_high;
470 	};
471 	uint16	file_access_control_high;
472 	uint16	uid_high;
473 	uint16	gid_high;
474 	uint16	checksum;
475 	uint16	reserved;
476 
477 	// extra attributes
478 	uint16	extra_inode_size;
479 	uint16	checksum_high;
480 	uint32	change_time_extra;
481 	uint32	modification_time_extra;
482 	uint32	access_time_extra;
483 	uint32	creation_time;
484 	uint32	creation_time_extra;
485 	uint32	version_high;
486 	uint32	project_id;
487 
Modeext2_inode488 	uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
Flagsext2_inode489 	uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
NumLinksext2_inode490 	uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
NumBlocksext2_inode491 	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
NumBlocks64ext2_inode492 	uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
493 		| ((uint64)B_LENDIAN_TO_HOST_INT16(num_blocks_high) << 32); }
494 
_DecodeTimeext2_inode495 	static void _DecodeTime(struct timespec *timespec, uint32 time,
496 		uint32 time_extra, bool extra)
497 	{
498 		timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time);
499 		if (extra && sizeof(timespec->tv_sec) > 4)
500 			timespec->tv_sec |=
501 				(uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32;
502 		if (extra)
503 			timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2;
504 		else
505 			timespec->tv_nsec = 0;
506 	}
507 
GetModificationTimeext2_inode508 	void GetModificationTime(struct timespec *timespec, bool extra) const
509 		{ _DecodeTime(timespec, modification_time, modification_time_extra,
510 			extra); }
GetAccessTimeext2_inode511 	void GetAccessTime(struct timespec *timespec, bool extra) const
512 		{ _DecodeTime(timespec, access_time, access_time_extra, extra); }
GetChangeTimeext2_inode513 	void GetChangeTime(struct timespec *timespec, bool extra) const
514 		{ _DecodeTime(timespec, change_time, change_time_extra, extra); }
GetCreationTimeext2_inode515 	void GetCreationTime(struct timespec *timespec, bool extra) const
516 	{
517 		if (extra)
518 			_DecodeTime(timespec, creation_time, creation_time_extra, extra);
519 		else {
520 			timespec->tv_sec = 0;
521 			timespec->tv_nsec = 0;
522 		}
523 	}
DeletionTimeext2_inode524 	time_t DeletionTime() const
525 		{ return B_LENDIAN_TO_HOST_INT32(deletion_time); }
526 
_EncodeTimeext2_inode527 	static uint32 _EncodeTime(const struct timespec *timespec)
528 	{
529 		uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc;
530 		if (sizeof(timespec->tv_sec) > 4)
531 			time |= (uint64)timespec->tv_sec >> 32;
532 		return B_HOST_TO_LENDIAN_INT32(time);
533 	}
534 
SetModificationTimeext2_inode535 	void SetModificationTime(const struct timespec *timespec, bool extra)
536 	{
537 		modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
538 		if (extra)
539 			modification_time_extra = _EncodeTime(timespec);
540 	}
SetAccessTimeext2_inode541 	void SetAccessTime(const struct timespec *timespec, bool extra)
542 	{
543 		access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
544 		if (extra)
545 			access_time_extra = _EncodeTime(timespec);
546 	}
SetChangeTimeext2_inode547 	void SetChangeTime(const struct timespec *timespec, bool extra)
548 	{
549 		change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
550 		if (extra)
551 			change_time_extra = _EncodeTime(timespec);
552 	}
SetCreationTimeext2_inode553 	void SetCreationTime(const struct timespec *timespec, bool extra)
554 	{
555 		if (extra) {
556 			creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
557 			creation_time_extra =
558 				B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec);
559 		}
560 	}
SetDeletionTimeext2_inode561 	void SetDeletionTime(time_t deletionTime)
562 	{
563 		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
564 	}
565 
NextOrphanext2_inode566 	ino_t  NextOrphan() const { return (ino_t)DeletionTime(); }
567 
Sizeext2_inode568 	off_t Size() const
569 	{
570 		if (S_ISREG(Mode())) {
571 			return B_LENDIAN_TO_HOST_INT32(size)
572 				| ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32);
573 		}
574 
575 		return B_LENDIAN_TO_HOST_INT32(size);
576 	}
577 
ExtendedAttributesBlockext2_inode578 	uint32 ExtendedAttributesBlock() const
579 	{	return B_LENDIAN_TO_HOST_INT32(file_access_control);}
580 
ExtraInodeSizeext2_inode581 	uint16 ExtraInodeSize() const
582 		{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
583 
UserIDext2_inode584 	uint32 UserID() const
585 	{
586 		return B_LENDIAN_TO_HOST_INT16(uid)
587 			| (B_LENDIAN_TO_HOST_INT16(uid_high) << 16);
588 	}
589 
GroupIDext2_inode590 	uint32 GroupID() const
591 	{
592 		return B_LENDIAN_TO_HOST_INT16(gid)
593 			| (B_LENDIAN_TO_HOST_INT16(gid_high) << 16);
594 	}
595 
SetModeext2_inode596 	void SetMode(uint16 newMode)
597 	{
598 		mode = B_LENDIAN_TO_HOST_INT16(newMode);
599 	}
600 
UpdateModeext2_inode601 	void UpdateMode(uint16 newMode, uint16 mask)
602 	{
603 		SetMode((Mode() & ~mask) | (newMode & mask));
604 	}
605 
ClearFlagext2_inode606 	void ClearFlag(uint32 mask)
607 	{
608 		flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
609 	}
610 
SetFlagext2_inode611 	void SetFlag(uint32 mask)
612 	{
613 		flags |= B_HOST_TO_LENDIAN_INT32(mask);
614 	}
615 
SetFlagsext2_inode616 	void SetFlags(uint32 newFlags)
617 	{
618 		flags = B_HOST_TO_LENDIAN_INT32(newFlags);
619 	}
620 
SetNumLinksext2_inode621 	void SetNumLinks(uint16 numLinks)
622 	{
623 		num_links = B_HOST_TO_LENDIAN_INT16(numLinks);
624 	}
625 
SetNumBlocksext2_inode626 	void SetNumBlocks(uint32 numBlocks)
627 	{
628 		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
629 	}
630 
SetNumBlocks64ext2_inode631 	void SetNumBlocks64(uint64 numBlocks)
632 	{
633 		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff);
634 		num_blocks_high = B_HOST_TO_LENDIAN_INT16(numBlocks >> 32);
635 	}
636 
SetNextOrphanext2_inode637 	void SetNextOrphan(ino_t id)
638 	{
639 		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id);
640 	}
641 
SetSizeext2_inode642 	void SetSize(off_t newSize)
643 	{
644 		size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF);
645 		if (S_ISREG(Mode()))
646 			size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32);
647 	}
648 
SetUserIDext2_inode649 	void SetUserID(uint32 newUID)
650 	{
651 		uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF);
652 		uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16);
653 	}
654 
SetGroupIDext2_inode655 	void SetGroupID(uint32 newGID)
656 	{
657 		gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF);
658 		gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16);
659 	}
660 
SetExtendedAttributesBlockext2_inode661 	void SetExtendedAttributesBlock(uint32 block)
662 	{
663 		file_access_control = B_HOST_TO_LENDIAN_INT32(block);
664 	}
665 
SetExtraInodeSizeext2_inode666 	void SetExtraInodeSize(uint16 newSize)
667 	{
668 		extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize);
669 	}
670 } _PACKED;
671 
672 #define EXT2_SUPER_BLOCK_MAGIC			0xef53
673 
674 // flags
675 #define EXT2_INODE_SECURE_DELETION		0x00000001
676 #define EXT2_INODE_UNDELETE				0x00000002
677 #define EXT2_INODE_COMPRESSED			0x00000004
678 #define EXT2_INODE_SYNCHRONOUS			0x00000008
679 #define EXT2_INODE_IMMUTABLE			0x00000010
680 #define EXT2_INODE_APPEND_ONLY			0x00000020
681 #define EXT2_INODE_NO_DUMP				0x00000040
682 #define EXT2_INODE_NO_ACCESS_TIME		0x00000080
683 #define EXT2_INODE_DIRTY				0x00000100
684 #define EXT2_INODE_COMPRESSED_BLOCKS	0x00000200
685 #define EXT2_INODE_DO_NOT_COMPRESS		0x00000400
686 #define EXT2_INODE_COMPRESSION_ERROR	0x00000800
687 #define EXT2_INODE_BTREE				0x00001000
688 #define EXT2_INODE_INDEXED				0x00001000
689 #define EXT2_INODE_JOURNAL_DATA			0x00004000
690 #define EXT2_INODE_NO_MERGE_TAIL		0x00008000
691 #define EXT2_INODE_DIR_SYNCH			0x00010000
692 #define EXT2_INODE_HUGE_FILE			0x00040000
693 #define EXT2_INODE_EXTENTS				0x00080000
694 #define EXT2_INODE_LARGE_EA				0x00200000
695 #define EXT2_INODE_EOF_BLOCKS			0x00400000
696 #define EXT2_INODE_INLINE_DATA			0x10000000
697 #define EXT2_INODE_RESERVED				0x80000000
698 
699 #define EXT2_INODE_INHERITED (EXT2_INODE_SECURE_DELETION | EXT2_INODE_UNDELETE \
700 	| EXT2_INODE_COMPRESSED | EXT2_INODE_SYNCHRONOUS | EXT2_INODE_IMMUTABLE \
701 	| EXT2_INODE_APPEND_ONLY | EXT2_INODE_NO_DUMP | EXT2_INODE_NO_ACCESS_TIME \
702 	| EXT2_INODE_DO_NOT_COMPRESS | EXT2_INODE_JOURNAL_DATA \
703 	| EXT2_INODE_NO_MERGE_TAIL | EXT2_INODE_DIR_SYNCH)
704 
705 #define EXT2_NAME_LENGTH	255
706 
707 #define EXT2_DIR_PAD		4
708 #define EXT2_DIR_ROUND		(EXT2_DIR_PAD - 1)
709 #define EXT2_DIR_REC_LEN(namelen)	(((namelen) + 8 + EXT2_DIR_ROUND) \
710 										& ~EXT2_DIR_ROUND)
711 
712 struct ext2_dir_entry {
713 	uint32	inode_id;
714 	uint16	length;
715 	uint8	name_length;
716 	uint8	file_type;
717 	char	name[EXT2_NAME_LENGTH];
718 
InodeIDext2_dir_entry719 	uint32	InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
Lengthext2_dir_entry720 	uint16	Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
NameLengthext2_dir_entry721 	uint8	NameLength() const { return name_length; }
FileTypeext2_dir_entry722 	uint8	FileType() const { return file_type; }
723 
SetInodeIDext2_dir_entry724 	void	SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
725 
SetLengthext2_dir_entry726 	void	SetLength(uint16 newLength/*uint8 nameLength*/)
727 	{
728 		length = B_HOST_TO_LENDIAN_INT16(newLength);
729 		/*name_length = nameLength;
730 
731 		if (nameLength % 4 == 0) {
732 			length = B_HOST_TO_LENDIAN_INT16(
733 				(short)(nameLength + MinimumSize()));
734 		} else {
735 			length = B_HOST_TO_LENDIAN_INT16(
736 				(short)(nameLength % 4 + 1 + MinimumSize()));
737 		}*/
738 	}
739 
IsValidext2_dir_entry740 	bool IsValid() const
741 	{
742 		return Length() > MinimumSize();
743 			// There is no maximum size, as the last entry spans until the
744 			// end of the block
745 	}
746 
MinimumSizeext2_dir_entry747 	static size_t MinimumSize()
748 	{
749 		return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH;
750 	}
751 } _PACKED;
752 
753 struct ext2_dir_entry_tail {
754 	uint32	zero1;
755 	uint16	twelve;
756 	uint8	zero2;
757 	uint8	hexade;
758 	uint32	checksum;
759 } _PACKED;
760 
761 struct ext2_htree_tail {
762 	uint32	reserved;
763 	uint32	checksum;
764 } _PACKED;
765 
766 // file types
767 #define EXT2_TYPE_UNKNOWN		0
768 #define EXT2_TYPE_FILE			1
769 #define EXT2_TYPE_DIRECTORY		2
770 #define EXT2_TYPE_CHAR_DEVICE	3
771 #define EXT2_TYPE_BLOCK_DEVICE	4
772 #define EXT2_TYPE_FIFO			5
773 #define EXT2_TYPE_SOCKET		6
774 #define EXT2_TYPE_SYMLINK		7
775 
776 #define EXT2_XATTR_MAGIC		0xea020000
777 #define EXT2_XATTR_ROUND		((1 << 2) - 1)
778 #define EXT2_XATTR_NAME_LENGTH	255
779 
780 #define EXT2_XATTR_INDEX_USER	1
781 
782 struct ext2_xattr_header {
783 	uint32	magic;
784 	uint32	refcount;
785 	uint32	blocks;		// must be 1 for ext2
786 	uint32	hash;
787 	uint32	checksum;
788 	uint32	reserved[3];	// zero
789 
IsValidext2_xattr_header790 	bool IsValid() const
791 	{
792 		return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC
793 			&& B_LENDIAN_TO_HOST_INT32(blocks) == 1
794 			&& refcount <= 1024;
795 	}
796 
Dumpext2_xattr_header797 	void Dump() const {
798 		for (unsigned int i = 0; i < Length(); i++)
799 			dprintf("%02x ", ((uint8 *)this)[i]);
800 		dprintf("\n");
801 	}
802 
Lengthext2_xattr_header803 	static size_t Length()
804 	{
805 		return sizeof(ext2_xattr_header);
806 	}
807 };
808 
809 struct ext2_xattr_entry {
810 	uint8	name_length;
811 	uint8	name_index;
812 	uint16	value_offset;
813 	uint32	value_block;	// must be zero for ext2
814 	uint32	value_size;
815 	uint32	hash;
816 	char	name[EXT2_XATTR_NAME_LENGTH];
817 
NameLengthext2_xattr_entry818 	uint8 NameLength() const { return name_length; }
NameIndexext2_xattr_entry819 	uint8 NameIndex() const { return name_index; }
ValueOffsetext2_xattr_entry820 	uint16 ValueOffset() const { return
821 			B_LENDIAN_TO_HOST_INT16(value_offset); }
ValueSizeext2_xattr_entry822 	uint32 ValueSize() const { return
823 			B_LENDIAN_TO_HOST_INT32(value_size); }
824 
825 	// padded sizes
Lengthext2_xattr_entry826 	uint32 Length() const { return (MinimumSize() + NameLength()
827 		+ EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; }
828 
IsValidext2_xattr_entry829 	bool IsValid() const
830 	{
831 		return NameLength() > 0 && value_block == 0;
832 			// There is no maximum size, as the last entry spans until the
833 			// end of the block
834 	}
835 
836 	void Dump(bool full=false) const {
837 		for (unsigned int i = 0; i < (full ? sizeof(*this) : MinimumSize()); i++)
838 			dprintf("%02x ", ((uint8 *)this)[i]);
839 		dprintf("\n");
840 	}
841 
MinimumSizeext2_xattr_entry842 	static size_t MinimumSize()
843 	{
844 		return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH;
845 	}
846 } _PACKED;
847 
848 
849 struct file_cookie {
850 	bigtime_t	last_notification;
851 	off_t		last_size;
852 	int			open_mode;
853 };
854 
855 
856 #define EXT2_OPEN_MODE_USER_MASK		0x7fffffff
857 
858 #define INODE_NOTIFICATION_INTERVAL		10000000LL
859 
860 
861 extern fs_volume_ops gExt2VolumeOps;
862 extern fs_vnode_ops gExt2VnodeOps;
863 
864 #endif	// EXT2_H
865