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