xref: /haiku/src/add-ons/kernel/file_systems/ext2/ext2.h (revision 7457ccb4b2f4786525d3b7bda42598487d57ab7d)
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	_reserved3;
89 	uint16	_reserved4;
90 	uint32	_reserved5[162];
91 
92 	uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); }
93 	uint16 State() const { return B_LENDIAN_TO_HOST_INT16(state); }
94 	uint32 RevisionLevel() const { return B_LENDIAN_TO_HOST_INT16(revision_level); }
95 	uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; }
96 	uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); }
97 	uint64 NumBlocks(bool has64bits) const
98 	{
99 		uint64 blocks = B_LENDIAN_TO_HOST_INT32(num_blocks);
100 		if (has64bits)
101 			blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32);
102 		return blocks;
103 	}
104 	uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); }
105 	uint64 FreeBlocks(bool has64bits) const
106 	{
107 		uint64 blocks = B_LENDIAN_TO_HOST_INT32(free_blocks);
108 		if (has64bits)
109 			blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(free_blocks_high) << 32);
110 		return blocks;
111 	}
112 	uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); }
113 	uint32 FirstDataBlock() const
114 		{ return B_LENDIAN_TO_HOST_INT32(first_data_block); }
115 	uint32 BlocksPerGroup() const
116 		{ return B_LENDIAN_TO_HOST_INT32(blocks_per_group); }
117 	uint32 InodesPerGroup() const
118 		{ return B_LENDIAN_TO_HOST_INT32(inodes_per_group); }
119 	uint32 FirstMetaBlockGroup() const
120 		{ return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); }
121 	uint32 CompatibleFeatures() const
122 		{ return B_LENDIAN_TO_HOST_INT32(compatible_features); }
123 	uint32 ReadOnlyFeatures() const
124 		{ return B_LENDIAN_TO_HOST_INT32(read_only_features); }
125 	uint32 IncompatibleFeatures() const
126 		{ return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
127 	uint16 ReservedGDTBlocks() const
128 		{ return B_LENDIAN_TO_HOST_INT16(reserved_gdt_blocks); }
129 	ino_t  JournalInode() const
130 		{ return B_LENDIAN_TO_HOST_INT32(journal_inode); }
131 	ino_t  LastOrphan() const
132 		{ return (ino_t)B_LENDIAN_TO_HOST_INT32(last_orphan); }
133 	uint32 HashSeed(uint8 i) const
134 		{ return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
135 	uint16 GroupDescriptorSize() const
136 		{ return B_LENDIAN_TO_HOST_INT16(group_descriptor_size); }
137 
138 	void SetFreeInodes(uint32 freeInodes)
139 		{ free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); }
140 	void SetFreeBlocks(uint64 freeBlocks, bool has64bits)
141 	{
142 		free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks & 0xffffffff);
143 		if (has64bits)
144 			free_blocks_high = B_HOST_TO_LENDIAN_INT32(freeBlocks >> 32);
145 	}
146 	void SetLastOrphan(ino_t id)
147 		{ last_orphan = B_HOST_TO_LENDIAN_INT32((uint32)id); }
148 	void SetReadOnlyFeatures(uint32 readOnlyFeatures) const
149 		{ readOnlyFeatures = B_HOST_TO_LENDIAN_INT32(readOnlyFeatures); }
150 
151 	bool IsValid();
152 		// implemented in Volume.cpp
153 } _PACKED;
154 
155 #define EXT2_OLD_REVISION		0
156 #define EXT2_DYNAMIC_REVISION	1
157 
158 #define EXT2_MAX_REVISION		EXT2_DYNAMIC_REVISION
159 
160 #define EXT2_FS_STATE_VALID		1	// File system was cleanly unmounted
161 #define EXT2_FS_STATE_ERROR		2	// File system has errors
162 #define EXT2_FS_STATE_ORPHAN	3	// Orphans are being recovered
163 
164 // compatible features
165 #define EXT2_FEATURE_DIRECTORY_PREALLOCATION	0x0001
166 #define EXT2_FEATURE_IMAGIC_INODES				0x0002
167 #define EXT2_FEATURE_HAS_JOURNAL				0x0004
168 #define EXT2_FEATURE_EXT_ATTR					0x0008
169 #define EXT2_FEATURE_RESIZE_INODE				0x0010
170 #define EXT2_FEATURE_DIRECTORY_INDEX			0x0020
171 
172 // read-only compatible features
173 #define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER		0x0001
174 #define EXT2_READ_ONLY_FEATURE_LARGE_FILE		0x0002
175 #define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY	0x0004
176 #define EXT2_READ_ONLY_FEATURE_HUGE_FILE		0x0008
177 #define EXT2_READ_ONLY_FEATURE_GDT_CSUM			0x0010
178 #define EXT2_READ_ONLY_FEATURE_DIR_NLINK		0x0020
179 #define EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE		0x0040
180 
181 // incompatible features
182 #define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION	0x0001
183 #define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE		0x0002
184 #define EXT2_INCOMPATIBLE_FEATURE_RECOVER		0x0004
185 #define EXT2_INCOMPATIBLE_FEATURE_JOURNAL		0x0008
186 #define EXT2_INCOMPATIBLE_FEATURE_META_GROUP	0x0010
187 #define EXT2_INCOMPATIBLE_FEATURE_EXTENTS		0x0040
188 #define EXT2_INCOMPATIBLE_FEATURE_64BIT			0x0080
189 #define EXT2_INCOMPATIBLE_FEATURE_MMP			0x0100
190 #define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP	0x0200
191 
192 // states
193 #define EXT2_STATE_VALID						0x01
194 #define	EXT2_STATE_INVALID						0x02
195 
196 #define EXT2_BLOCK_GROUP_NORMAL_SIZE			32
197 #define EXT2_BLOCK_GROUP_64BIT_SIZE				64
198 
199 // block group flags
200 #define EXT2_BLOCK_GROUP_INODE_UNINIT	0x1
201 #define EXT2_BLOCK_GROUP_BLOCK_UNINIT	0x2
202 
203 
204 struct ext2_block_group {
205 	uint32	block_bitmap;
206 	uint32	inode_bitmap;
207 	uint32	inode_table;
208 	uint16	free_blocks;
209 	uint16	free_inodes;
210 	uint16	used_directories;
211 	uint16	flags;
212 	uint32	_reserved[2];
213 	uint16	unused_inodes;
214 	uint16	checksum;
215 
216 	// ext4
217 	uint32	block_bitmap_high;
218 	uint32	inode_bitmap_high;
219 	uint32	inode_table_high;
220 	uint16	free_blocks_high;
221 	uint16	free_inodes_high;
222 	uint16	used_directories_high;
223 	uint16	unused_inodes_high;
224 	uint32	_reserved2[3];
225 
226 	fsblock_t BlockBitmap(bool has64bits) const
227 	{
228 		uint64 block = B_LENDIAN_TO_HOST_INT32(block_bitmap);
229 		if (has64bits)
230 			block |=
231 				((uint64)B_LENDIAN_TO_HOST_INT32(block_bitmap_high) << 32);
232 		return block;
233 	}
234 	fsblock_t InodeBitmap(bool has64bits) const
235 	{
236 		uint64 bitmap = B_LENDIAN_TO_HOST_INT32(inode_bitmap);
237 		if (has64bits)
238 			bitmap |=
239 				((uint64)B_LENDIAN_TO_HOST_INT32(inode_bitmap_high) << 32);
240 		return bitmap;
241 	}
242 	uint64 InodeTable(bool has64bits) const
243 	{
244 		uint64 table = B_LENDIAN_TO_HOST_INT32(inode_table);
245 		if (has64bits)
246 			table |= ((uint64)B_LENDIAN_TO_HOST_INT32(inode_table_high) << 32);
247 		return table;
248 	}
249 	uint32 FreeBlocks(bool has64bits) const
250 	{
251 		uint32 blocks = B_LENDIAN_TO_HOST_INT16(free_blocks);
252 		if (has64bits)
253 			blocks |=
254 				((uint32)B_LENDIAN_TO_HOST_INT16(free_blocks_high) << 16);
255 		return blocks;
256 	}
257 	uint32 FreeInodes(bool has64bits) const
258 	{
259 		uint32 inodes = B_LENDIAN_TO_HOST_INT16(free_inodes);
260 		if (has64bits)
261 			inodes |=
262 				((uint32)B_LENDIAN_TO_HOST_INT16(free_inodes_high) << 16);
263 		return inodes;
264 	}
265 	uint32 UsedDirectories(bool has64bits) const
266 	{
267 		uint32 dirs = B_LENDIAN_TO_HOST_INT16(used_directories);
268 		if (has64bits)
269 			dirs |=
270 				((uint32)B_LENDIAN_TO_HOST_INT16(used_directories_high) << 16);
271 		return dirs;
272 	}
273 	uint16 Flags() const { return B_LENDIAN_TO_HOST_INT16(flags); }
274 	uint32 UnusedInodes(bool has64bits) const
275 	{
276 		uint32 inodes = B_LENDIAN_TO_HOST_INT16(unused_inodes);
277 		if (has64bits)
278 			inodes |=
279 				((uint32)B_LENDIAN_TO_HOST_INT16(unused_inodes_high) << 16);
280 		return inodes;
281 	}
282 
283 
284 	void SetFreeBlocks(uint32 freeBlocks, bool has64bits)
285 	{
286 		free_blocks = B_HOST_TO_LENDIAN_INT16(freeBlocks) & 0xffff;
287 		if (has64bits)
288 			free_blocks_high = B_HOST_TO_LENDIAN_INT16(freeBlocks >> 16);
289 	}
290 
291 	void SetFreeInodes(uint32 freeInodes, bool has64bits)
292 	{
293 		free_inodes = B_HOST_TO_LENDIAN_INT16(freeInodes) & 0xffff;
294 		if (has64bits)
295 			free_inodes_high = B_HOST_TO_LENDIAN_INT16(freeInodes >> 16);
296 	}
297 
298 	void SetUsedDirectories(uint16 usedDirectories, bool has64bits)
299 	{
300 		used_directories = B_HOST_TO_LENDIAN_INT16(usedDirectories& 0xffff);
301 		if (has64bits)
302 			used_directories_high =
303 				B_HOST_TO_LENDIAN_INT16(usedDirectories >> 16);
304 	}
305 
306 	void SetFlags(uint16 newFlags)
307 	{
308 		flags = B_HOST_TO_LENDIAN_INT16(newFlags);
309 	}
310 
311 	void SetUnusedInodes(uint32 unusedInodes, bool has64bits)
312 	{
313 		unused_inodes = B_HOST_TO_LENDIAN_INT16(unusedInodes) & 0xffff;
314 		if (has64bits)
315 			unused_inodes_high = B_HOST_TO_LENDIAN_INT16(unusedInodes >> 16);
316 	}
317 } _PACKED;
318 
319 #define EXT2_DIRECT_BLOCKS			12
320 #define EXT2_ROOT_NODE				2
321 #define EXT2_SHORT_SYMLINK_LENGTH	60
322 
323 struct ext2_data_stream {
324 	uint32 direct[EXT2_DIRECT_BLOCKS];
325 	uint32 indirect;
326 	uint32 double_indirect;
327 	uint32 triple_indirect;
328 } _PACKED;
329 
330 #define EXT2_EXTENT_MAGIC			0xf30a
331 #define EXT2_EXTENT_MAX_LENGTH		0x8000
332 
333 struct ext2_extent_header {
334 	uint16 magic;
335 	uint16 num_entries;
336 	uint16 max_entries;
337 	uint16 depth;
338 	uint32 generation;
339 	bool IsValid() const
340 	{
341 		return B_LENDIAN_TO_HOST_INT16(magic) == EXT2_EXTENT_MAGIC;
342 	}
343 	uint16 NumEntries() const { return B_LENDIAN_TO_HOST_INT16(num_entries); }
344 	uint16 MaxEntries() const { return B_LENDIAN_TO_HOST_INT16(max_entries); }
345 	uint16 Depth() const { return B_LENDIAN_TO_HOST_INT16(depth); }
346 	uint32 Generation() const { return B_LENDIAN_TO_HOST_INT32(generation); }
347 	void SetNumEntries(uint16 num)
348 		{ num_entries = B_HOST_TO_LENDIAN_INT16(num); }
349 	void SetMaxEntries(uint16 max)
350 		{ max_entries = B_HOST_TO_LENDIAN_INT16(max); }
351 	void SetDepth(uint16 _depth)
352 		{ depth = B_HOST_TO_LENDIAN_INT16(_depth); }
353 	void SetGeneration(uint32 _generation)
354 		{ generation = B_HOST_TO_LENDIAN_INT32(_generation); }
355 } _PACKED;
356 
357 struct ext2_extent_index {
358 	uint32 logical_block;
359 	uint32 physical_block;
360 	uint16 physical_block_high;
361 	uint16 _reserved;
362 	uint32 LogicalBlock() const
363 		{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
364 	uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
365 		| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
366 	void SetLogicalBlock(uint32 block) {
367 		logical_block = B_HOST_TO_LENDIAN_INT32(block); }
368 	void SetPhysicalBlock(uint64 block) {
369 		physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff);
370 		physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); }
371 } _PACKED;
372 
373 struct ext2_extent_entry {
374 	uint32 logical_block;
375 	uint16 length;
376 	uint16 physical_block_high;
377 	uint32 physical_block;
378 	uint32 LogicalBlock() const
379 		{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
380 	uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length) == 0x8000
381 		? 0x8000 : B_LENDIAN_TO_HOST_INT16(length) & 0x7fff; }
382 	uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
383 		| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
384 	void SetLogicalBlock(uint32 block) {
385 		logical_block = B_HOST_TO_LENDIAN_INT32(block); }
386 	void SetLength(uint16 _length) {
387 		length = B_HOST_TO_LENDIAN_INT16(_length) & 0x7fff; }
388 	void SetPhysicalBlock(uint64 block) {
389 		physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff);
390 		physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); }
391 } _PACKED;
392 
393 struct ext2_extent_stream {
394 	ext2_extent_header extent_header;
395 	union {
396 		ext2_extent_entry extent_entries[4];
397 		ext2_extent_index extent_index[4];
398 	};
399 } _PACKED;
400 
401 #define EXT2_INODE_NORMAL_SIZE		128
402 #define EXT2_INODE_MAX_LINKS		65000
403 
404 struct ext2_inode {
405 	uint16	mode;
406 	uint16	uid;
407 	uint32	size;
408 	uint32	access_time;
409 	uint32	change_time;
410 	uint32	modification_time;
411 	uint32	deletion_time;
412 	uint16	gid;
413 	uint16	num_links;
414 	uint32	num_blocks;
415 	uint32	flags;
416 	uint32	version;
417 	union {
418 		ext2_data_stream stream;
419 		char symlink[EXT2_SHORT_SYMLINK_LENGTH];
420 		ext2_extent_stream extent_stream;
421 	};
422 	uint32	generation;
423 	uint32	file_access_control;
424 	union {
425 		// for directories vs. files
426 		uint32	directory_access_control;
427 		uint32	size_high;
428 	};
429 	uint32	fragment;
430 	union {
431 		struct {
432 			uint8	fragment_number;
433 			uint8	fragment_size;
434 		};
435 		uint16 num_blocks_high;
436 	};
437 	uint16	_padding;
438 	uint16	uid_high;
439 	uint16	gid_high;
440 	uint32	_reserved2;
441 
442 	// extra attributes
443 	uint16	extra_inode_size;
444 	uint16	_padding2;
445 	uint32	change_time_extra;
446 	uint32	modification_time_extra;
447 	uint32	access_time_extra;
448 	uint32	creation_time;
449 	uint32	creation_time_extra;
450 	uint32	version_high;
451 
452 	uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
453 	uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
454 	uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
455 	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
456 	uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
457 		| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
458 
459 	static void _DecodeTime(struct timespec *timespec, uint32 time,
460 		uint32 time_extra, bool extra)
461 	{
462 		timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time);
463 		if (extra && sizeof(timespec->tv_sec) > 4)
464 			timespec->tv_sec |=
465 				(uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32;
466 		if (extra)
467 			timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2;
468 		else
469 			timespec->tv_nsec = 0;
470 	}
471 
472 	void GetModificationTime(struct timespec *timespec, bool extra) const
473 		{ _DecodeTime(timespec, modification_time, modification_time_extra,
474 			extra); }
475 	void GetAccessTime(struct timespec *timespec, bool extra) const
476 		{ _DecodeTime(timespec, access_time, access_time_extra, extra); }
477 	void GetChangeTime(struct timespec *timespec, bool extra) const
478 		{ _DecodeTime(timespec, change_time, change_time_extra, extra); }
479 	void GetCreationTime(struct timespec *timespec, bool extra) const
480 	{
481 		if (extra)
482 			_DecodeTime(timespec, creation_time, creation_time_extra, extra);
483 		else {
484 			timespec->tv_sec = 0;
485 			timespec->tv_nsec = 0;
486 		}
487 	}
488 	time_t DeletionTime() const
489 		{ return B_LENDIAN_TO_HOST_INT32(deletion_time); }
490 
491 	static uint32 _EncodeTime(const struct timespec *timespec)
492 	{
493 		uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc;
494 		if (sizeof(timespec->tv_sec) > 4)
495 			time |= (uint64)timespec->tv_sec >> 32;
496 		return B_HOST_TO_LENDIAN_INT32(time);
497 	}
498 
499 	void SetModificationTime(const struct timespec *timespec, bool extra)
500 	{
501 		modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
502 		if (extra)
503 			modification_time_extra = _EncodeTime(timespec);
504 	}
505 	void SetAccessTime(const struct timespec *timespec, bool extra)
506 	{
507 		access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
508 		if (extra)
509 			access_time_extra = _EncodeTime(timespec);
510 	}
511 	void SetChangeTime(const struct timespec *timespec, bool extra)
512 	{
513 		change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
514 		if (extra)
515 			change_time_extra = _EncodeTime(timespec);
516 	}
517 	void SetCreationTime(const struct timespec *timespec, bool extra)
518 	{
519 		if (extra) {
520 			creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
521 			creation_time_extra =
522 				B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec);
523 		}
524 	}
525 	void SetDeletionTime(time_t deletionTime)
526 	{
527 		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
528 	}
529 
530 	ino_t  NextOrphan() const { return (ino_t)DeletionTime(); }
531 
532 	off_t Size() const
533 	{
534 		if (S_ISREG(Mode())) {
535 			return B_LENDIAN_TO_HOST_INT32(size)
536 				| ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32);
537 		}
538 
539 		return B_LENDIAN_TO_HOST_INT32(size);
540 	}
541 
542 	uint32 ExtendedAttributesBlock() const
543 	{	return B_LENDIAN_TO_HOST_INT32(file_access_control);}
544 
545 	uint16 ExtraInodeSize() const
546 		{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
547 
548 	uint32 UserID() const
549 	{
550 		return B_LENDIAN_TO_HOST_INT16(uid)
551 			| (B_LENDIAN_TO_HOST_INT16(uid_high) << 16);
552 	}
553 
554 	uint32 GroupID() const
555 	{
556 		return B_LENDIAN_TO_HOST_INT16(gid)
557 			| (B_LENDIAN_TO_HOST_INT16(gid_high) << 16);
558 	}
559 
560 	void SetMode(uint16 newMode)
561 	{
562 		mode = B_LENDIAN_TO_HOST_INT16(newMode);
563 	}
564 
565 	void UpdateMode(uint16 newMode, uint16 mask)
566 	{
567 		SetMode((Mode() & ~mask) | (newMode & mask));
568 	}
569 
570 	void ClearFlag(uint32 mask)
571 	{
572 		flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
573 	}
574 
575 	void SetFlag(uint32 mask)
576 	{
577 		flags |= B_HOST_TO_LENDIAN_INT32(mask);
578 	}
579 
580 	void SetFlags(uint32 newFlags)
581 	{
582 		flags = B_HOST_TO_LENDIAN_INT32(newFlags);
583 	}
584 
585 	void SetNumLinks(uint16 numLinks)
586 	{
587 		num_links = B_HOST_TO_LENDIAN_INT16(numLinks);
588 	}
589 
590 	void SetNumBlocks(uint32 numBlocks)
591 	{
592 		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
593 	}
594 
595 	void SetNumBlocks64(uint64 numBlocks)
596 	{
597 		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff);
598 		num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32);
599 	}
600 
601 	void SetNextOrphan(ino_t id)
602 	{
603 		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id);
604 	}
605 
606 	void SetSize(off_t newSize)
607 	{
608 		size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF);
609 		if (S_ISREG(Mode()))
610 			size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32);
611 	}
612 
613 	void SetUserID(uint32 newUID)
614 	{
615 		uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF);
616 		uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16);
617 	}
618 
619 	void SetGroupID(uint32 newGID)
620 	{
621 		gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF);
622 		gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16);
623 	}
624 
625 	void SetExtendedAttributesBlock(uint32 block)
626 	{
627 		file_access_control = B_HOST_TO_LENDIAN_INT32(block);
628 	}
629 
630 	void SetExtraInodeSize(uint16 newSize)
631 	{
632 		extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize);
633 	}
634 } _PACKED;
635 
636 #define EXT2_SUPER_BLOCK_MAGIC			0xef53
637 
638 // flags
639 #define EXT2_INODE_SECURE_DELETION		0x00000001
640 #define EXT2_INODE_UNDELETE				0x00000002
641 #define EXT2_INODE_COMPRESSED			0x00000004
642 #define EXT2_INODE_SYNCHRONOUS			0x00000008
643 #define EXT2_INODE_IMMUTABLE			0x00000010
644 #define EXT2_INODE_APPEND_ONLY			0x00000020
645 #define EXT2_INODE_NO_DUMP				0x00000040
646 #define EXT2_INODE_NO_ACCESS_TIME		0x00000080
647 #define EXT2_INODE_DIRTY				0x00000100
648 #define EXT2_INODE_COMPRESSED_BLOCKS	0x00000200
649 #define EXT2_INODE_DO_NOT_COMPRESS		0x00000400
650 #define EXT2_INODE_COMPRESSION_ERROR	0x00000800
651 #define EXT2_INODE_BTREE				0x00001000
652 #define EXT2_INODE_INDEXED				0x00001000
653 #define EXT2_INODE_JOURNAL_DATA			0x00004000
654 #define EXT2_INODE_NO_MERGE_TAIL		0x00008000
655 #define EXT2_INODE_DIR_SYNCH			0x00010000
656 #define EXT2_INODE_HUGE_FILE			0x00040000
657 #define EXT2_INODE_EXTENTS				0x00080000
658 #define EXT2_INODE_LARGE_EA				0x00200000
659 #define EXT2_INODE_EOF_BLOCKS			0x00400000
660 #define EXT2_INODE_INLINE_DATA			0x10000000
661 #define EXT2_INODE_RESERVED				0x80000000
662 
663 #define EXT2_INODE_INHERITED (EXT2_INODE_SECURE_DELETION | EXT2_INODE_UNDELETE \
664 	| EXT2_INODE_COMPRESSED | EXT2_INODE_SYNCHRONOUS | EXT2_INODE_IMMUTABLE \
665 	| EXT2_INODE_APPEND_ONLY | EXT2_INODE_NO_DUMP | EXT2_INODE_NO_ACCESS_TIME \
666 	| EXT2_INODE_DO_NOT_COMPRESS | EXT2_INODE_JOURNAL_DATA \
667 	| EXT2_INODE_NO_MERGE_TAIL | EXT2_INODE_DIR_SYNCH)
668 
669 #define EXT2_NAME_LENGTH	255
670 
671 struct ext2_dir_entry {
672 	uint32	inode_id;
673 	uint16	length;
674 	uint8	name_length;
675 	uint8	file_type;
676 	char	name[EXT2_NAME_LENGTH];
677 
678 	uint32	InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
679 	uint16	Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
680 	uint8	NameLength() const { return name_length; }
681 	uint8	FileType() const { return file_type; }
682 
683 	void	SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
684 
685 	void	SetLength(uint16 newLength/*uint8 nameLength*/)
686 	{
687 		length = B_HOST_TO_LENDIAN_INT16(newLength);
688 		/*name_length = nameLength;
689 
690 		if (nameLength % 4 == 0) {
691 			length = B_HOST_TO_LENDIAN_INT16(
692 				(short)(nameLength + MinimumSize()));
693 		} else {
694 			length = B_HOST_TO_LENDIAN_INT16(
695 				(short)(nameLength % 4 + 1 + MinimumSize()));
696 		}*/
697 	}
698 
699 	bool IsValid() const
700 	{
701 		return Length() > MinimumSize();
702 			// There is no maximum size, as the last entry spans until the
703 			// end of the block
704 	}
705 
706 	static size_t MinimumSize()
707 	{
708 		return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH;
709 	}
710 } _PACKED;
711 
712 // file types
713 #define EXT2_TYPE_UNKNOWN		0
714 #define EXT2_TYPE_FILE			1
715 #define EXT2_TYPE_DIRECTORY		2
716 #define EXT2_TYPE_CHAR_DEVICE	3
717 #define EXT2_TYPE_BLOCK_DEVICE	4
718 #define EXT2_TYPE_FIFO			5
719 #define EXT2_TYPE_SOCKET		6
720 #define EXT2_TYPE_SYMLINK		7
721 
722 #define EXT2_XATTR_MAGIC		0xea020000
723 #define EXT2_XATTR_ROUND		((1 << 2) - 1)
724 #define EXT2_XATTR_NAME_LENGTH	255
725 
726 #define EXT2_XATTR_INDEX_USER	1
727 
728 struct ext2_xattr_header {
729 	uint32	magic;
730 	uint32	refcount;
731 	uint32	blocks;		// must be 1 for ext2
732 	uint32	hash;
733 	uint32	reserved[4];	// zero
734 
735 	bool IsValid() const
736 	{
737 		return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC
738 			&& B_LENDIAN_TO_HOST_INT32(blocks) == 1
739 			&& refcount <= 1024;
740 	}
741 
742 	void Dump() const {
743 		for (unsigned int i = 0; i < Length(); i++)
744 			dprintf("%02x ", ((uint8 *)this)[i]);
745 		dprintf("\n");
746 	}
747 
748 	static size_t Length()
749 	{
750 		return sizeof(ext2_xattr_header);
751 	}
752 };
753 
754 struct ext2_xattr_entry {
755 	uint8	name_length;
756 	uint8	name_index;
757 	uint16	value_offset;
758 	uint32	value_block;	// must be zero for ext2
759 	uint32	value_size;
760 	uint32	hash;
761 	char	name[EXT2_XATTR_NAME_LENGTH];
762 
763 	uint8 NameLength() const { return name_length; }
764 	uint8 NameIndex() const { return name_index; }
765 	uint16 ValueOffset() const { return
766 			B_LENDIAN_TO_HOST_INT16(value_offset); }
767 	uint32 ValueSize() const { return
768 			B_LENDIAN_TO_HOST_INT32(value_size); }
769 
770 	// padded sizes
771 	uint32 Length() const { return (MinimumSize() + NameLength()
772 		+ EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; }
773 
774 	bool IsValid() const
775 	{
776 		return NameLength() > 0 && value_block == 0;
777 			// There is no maximum size, as the last entry spans until the
778 			// end of the block
779 	}
780 
781 	void Dump(bool full=false) const {
782 		for (unsigned int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++)
783 			dprintf("%02x ", ((uint8 *)this)[i]);
784 		dprintf("\n");
785 	}
786 
787 	static size_t MinimumSize()
788 	{
789 		return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH;
790 	}
791 } _PACKED;
792 
793 
794 struct file_cookie {
795 	bigtime_t	last_notification;
796 	off_t		last_size;
797 	int			open_mode;
798 };
799 
800 
801 #define EXT2_OPEN_MODE_USER_MASK		0x7fffffff
802 
803 #define INODE_NOTIFICATION_INTERVAL		10000000LL
804 
805 
806 extern fs_volume_ops gExt2VolumeOps;
807 extern fs_vnode_ops gExt2VnodeOps;
808 
809 #endif	// EXT2_H
810