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