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
16typedef uint64 fileblock_t;		// file block number
17typedef uint64 fsblock_t;		// filesystem block number
18
19
20#define EXT2_SUPER_BLOCK_OFFSET	1024
21
22struct 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
96	uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); }
97	uint16 State() const { return B_LENDIAN_TO_HOST_INT16(state); }
98	uint32 RevisionLevel() const { return B_LENDIAN_TO_HOST_INT16(revision_level); }
99	uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; }
100	uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); }
101	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	}
108	uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); }
109	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	}
116	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	}
123	uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); }
124	uint32 FirstDataBlock() const
125		{ return B_LENDIAN_TO_HOST_INT32(first_data_block); }
126	uint32 BlocksPerGroup() const
127		{ return B_LENDIAN_TO_HOST_INT32(blocks_per_group); }
128	uint32 FragmentsPerGroup() const
129		{ return B_LENDIAN_TO_HOST_INT32(fragments_per_group); }
130	uint32 InodesPerGroup() const
131		{ return B_LENDIAN_TO_HOST_INT32(inodes_per_group); }
132	uint32 FirstMetaBlockGroup() const
133		{ return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); }
134	uint32 CompatibleFeatures() const
135		{ return B_LENDIAN_TO_HOST_INT32(compatible_features); }
136	uint32 ReadOnlyFeatures() const
137		{ return B_LENDIAN_TO_HOST_INT32(read_only_features); }
138	uint32 IncompatibleFeatures() const
139		{ return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
140	uint16 ReservedGDTBlocks() const
141		{ return B_LENDIAN_TO_HOST_INT16(reserved_gdt_blocks); }
142	ino_t  JournalInode() const
143		{ return B_LENDIAN_TO_HOST_INT32(journal_inode); }
144	ino_t  LastOrphan() const
145		{ return (ino_t)B_LENDIAN_TO_HOST_INT32(last_orphan); }
146	uint32 HashSeed(uint8 i) const
147		{ return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
148	uint16 GroupDescriptorSize() const
149		{ return B_LENDIAN_TO_HOST_INT16(group_descriptor_size); }
150
151	void SetFreeInodes(uint32 freeInodes)
152		{ free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); }
153	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	}
159	void SetLastOrphan(ino_t id)
160		{ last_orphan = B_HOST_TO_LENDIAN_INT32((uint32)id); }
161	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		1	// File system was cleanly unmounted
175#define EXT2_FS_STATE_ERROR		2	// File system has errors
176#define EXT2_FS_STATE_ORPHAN	3	// 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
229struct 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
256	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	}
264	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	}
272	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	}
279	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	}
287	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	}
295	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	}
303	uint16 Flags() const { return B_LENDIAN_TO_HOST_INT16(flags); }
304	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
314	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
321	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
328	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
336	void SetFlags(uint16 newFlags)
337	{
338		flags = B_HOST_TO_LENDIAN_INT16(newFlags);
339	}
340
341	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
353struct 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
363struct ext2_extent_header {
364	uint16 magic;
365	uint16 num_entries;
366	uint16 max_entries;
367	uint16 depth;
368	uint32 generation;
369	bool IsValid() const
370	{
371		return B_LENDIAN_TO_HOST_INT16(magic) == EXT2_EXTENT_MAGIC;
372	}
373	uint16 NumEntries() const { return B_LENDIAN_TO_HOST_INT16(num_entries); }
374	uint16 MaxEntries() const { return B_LENDIAN_TO_HOST_INT16(max_entries); }
375	uint16 Depth() const { return B_LENDIAN_TO_HOST_INT16(depth); }
376	uint32 Generation() const { return B_LENDIAN_TO_HOST_INT32(generation); }
377	void SetNumEntries(uint16 num)
378		{ num_entries = B_HOST_TO_LENDIAN_INT16(num); }
379	void SetMaxEntries(uint16 max)
380		{ max_entries = B_HOST_TO_LENDIAN_INT16(max); }
381	void SetDepth(uint16 _depth)
382		{ depth = B_HOST_TO_LENDIAN_INT16(_depth); }
383	void SetGeneration(uint32 _generation)
384		{ generation = B_HOST_TO_LENDIAN_INT32(_generation); }
385} _PACKED;
386
387struct ext2_extent_tail {
388	uint32 checksum;
389} _PACKED;
390
391struct ext2_extent_index {
392	uint32 logical_block;
393	uint32 physical_block;
394	uint16 physical_block_high;
395	uint16 _reserved;
396	uint32 LogicalBlock() const
397		{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
398	uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
399		| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
400	void SetLogicalBlock(uint32 block) {
401		logical_block = B_HOST_TO_LENDIAN_INT32(block); }
402	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
407struct ext2_extent_entry {
408	uint32 logical_block;
409	uint16 length;
410	uint16 physical_block_high;
411	uint32 physical_block;
412	uint32 LogicalBlock() const
413		{ return B_LENDIAN_TO_HOST_INT32(logical_block); }
414	uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length) == 0x8000
415		? 0x8000 : B_LENDIAN_TO_HOST_INT16(length) & 0x7fff; }
416	uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block)
417		| ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); }
418	void SetLogicalBlock(uint32 block) {
419		logical_block = B_HOST_TO_LENDIAN_INT32(block); }
420	void SetLength(uint16 _length) {
421		length = B_HOST_TO_LENDIAN_INT16(_length) & 0x7fff; }
422	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
427struct 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
438struct 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
487	uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
488	uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
489	uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
490	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
491	uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
492		| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
493
494	static void _DecodeTime(struct timespec *timespec, uint32 time,
495		uint32 time_extra, bool extra)
496	{
497		timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time);
498		if (extra && sizeof(timespec->tv_sec) > 4)
499			timespec->tv_sec |=
500				(uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32;
501		if (extra)
502			timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2;
503		else
504			timespec->tv_nsec = 0;
505	}
506
507	void GetModificationTime(struct timespec *timespec, bool extra) const
508		{ _DecodeTime(timespec, modification_time, modification_time_extra,
509			extra); }
510	void GetAccessTime(struct timespec *timespec, bool extra) const
511		{ _DecodeTime(timespec, access_time, access_time_extra, extra); }
512	void GetChangeTime(struct timespec *timespec, bool extra) const
513		{ _DecodeTime(timespec, change_time, change_time_extra, extra); }
514	void GetCreationTime(struct timespec *timespec, bool extra) const
515	{
516		if (extra)
517			_DecodeTime(timespec, creation_time, creation_time_extra, extra);
518		else {
519			timespec->tv_sec = 0;
520			timespec->tv_nsec = 0;
521		}
522	}
523	time_t DeletionTime() const
524		{ return B_LENDIAN_TO_HOST_INT32(deletion_time); }
525
526	static uint32 _EncodeTime(const struct timespec *timespec)
527	{
528		uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc;
529		if (sizeof(timespec->tv_sec) > 4)
530			time |= (uint64)timespec->tv_sec >> 32;
531		return B_HOST_TO_LENDIAN_INT32(time);
532	}
533
534	void SetModificationTime(const struct timespec *timespec, bool extra)
535	{
536		modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
537		if (extra)
538			modification_time_extra = _EncodeTime(timespec);
539	}
540	void SetAccessTime(const struct timespec *timespec, bool extra)
541	{
542		access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
543		if (extra)
544			access_time_extra = _EncodeTime(timespec);
545	}
546	void SetChangeTime(const struct timespec *timespec, bool extra)
547	{
548		change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
549		if (extra)
550			change_time_extra = _EncodeTime(timespec);
551	}
552	void SetCreationTime(const struct timespec *timespec, bool extra)
553	{
554		if (extra) {
555			creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
556			creation_time_extra =
557				B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec);
558		}
559	}
560	void SetDeletionTime(time_t deletionTime)
561	{
562		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
563	}
564
565	ino_t  NextOrphan() const { return (ino_t)DeletionTime(); }
566
567	off_t Size() const
568	{
569		if (S_ISREG(Mode())) {
570			return B_LENDIAN_TO_HOST_INT32(size)
571				| ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32);
572		}
573
574		return B_LENDIAN_TO_HOST_INT32(size);
575	}
576
577	uint32 ExtendedAttributesBlock() const
578	{	return B_LENDIAN_TO_HOST_INT32(file_access_control);}
579
580	uint16 ExtraInodeSize() const
581		{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
582
583	uint32 UserID() const
584	{
585		return B_LENDIAN_TO_HOST_INT16(uid)
586			| (B_LENDIAN_TO_HOST_INT16(uid_high) << 16);
587	}
588
589	uint32 GroupID() const
590	{
591		return B_LENDIAN_TO_HOST_INT16(gid)
592			| (B_LENDIAN_TO_HOST_INT16(gid_high) << 16);
593	}
594
595	void SetMode(uint16 newMode)
596	{
597		mode = B_LENDIAN_TO_HOST_INT16(newMode);
598	}
599
600	void UpdateMode(uint16 newMode, uint16 mask)
601	{
602		SetMode((Mode() & ~mask) | (newMode & mask));
603	}
604
605	void ClearFlag(uint32 mask)
606	{
607		flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
608	}
609
610	void SetFlag(uint32 mask)
611	{
612		flags |= B_HOST_TO_LENDIAN_INT32(mask);
613	}
614
615	void SetFlags(uint32 newFlags)
616	{
617		flags = B_HOST_TO_LENDIAN_INT32(newFlags);
618	}
619
620	void SetNumLinks(uint16 numLinks)
621	{
622		num_links = B_HOST_TO_LENDIAN_INT16(numLinks);
623	}
624
625	void SetNumBlocks(uint32 numBlocks)
626	{
627		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
628	}
629
630	void SetNumBlocks64(uint64 numBlocks)
631	{
632		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff);
633		num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32);
634	}
635
636	void SetNextOrphan(ino_t id)
637	{
638		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id);
639	}
640
641	void SetSize(off_t newSize)
642	{
643		size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF);
644		if (S_ISREG(Mode()))
645			size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32);
646	}
647
648	void SetUserID(uint32 newUID)
649	{
650		uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF);
651		uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16);
652	}
653
654	void SetGroupID(uint32 newGID)
655	{
656		gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF);
657		gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16);
658	}
659
660	void SetExtendedAttributesBlock(uint32 block)
661	{
662		file_access_control = B_HOST_TO_LENDIAN_INT32(block);
663	}
664
665	void SetExtraInodeSize(uint16 newSize)
666	{
667		extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize);
668	}
669} _PACKED;
670
671#define EXT2_SUPER_BLOCK_MAGIC			0xef53
672
673// flags
674#define EXT2_INODE_SECURE_DELETION		0x00000001
675#define EXT2_INODE_UNDELETE				0x00000002
676#define EXT2_INODE_COMPRESSED			0x00000004
677#define EXT2_INODE_SYNCHRONOUS			0x00000008
678#define EXT2_INODE_IMMUTABLE			0x00000010
679#define EXT2_INODE_APPEND_ONLY			0x00000020
680#define EXT2_INODE_NO_DUMP				0x00000040
681#define EXT2_INODE_NO_ACCESS_TIME		0x00000080
682#define EXT2_INODE_DIRTY				0x00000100
683#define EXT2_INODE_COMPRESSED_BLOCKS	0x00000200
684#define EXT2_INODE_DO_NOT_COMPRESS		0x00000400
685#define EXT2_INODE_COMPRESSION_ERROR	0x00000800
686#define EXT2_INODE_BTREE				0x00001000
687#define EXT2_INODE_INDEXED				0x00001000
688#define EXT2_INODE_JOURNAL_DATA			0x00004000
689#define EXT2_INODE_NO_MERGE_TAIL		0x00008000
690#define EXT2_INODE_DIR_SYNCH			0x00010000
691#define EXT2_INODE_HUGE_FILE			0x00040000
692#define EXT2_INODE_EXTENTS				0x00080000
693#define EXT2_INODE_LARGE_EA				0x00200000
694#define EXT2_INODE_EOF_BLOCKS			0x00400000
695#define EXT2_INODE_INLINE_DATA			0x10000000
696#define EXT2_INODE_RESERVED				0x80000000
697
698#define EXT2_INODE_INHERITED (EXT2_INODE_SECURE_DELETION | EXT2_INODE_UNDELETE \
699	| EXT2_INODE_COMPRESSED | EXT2_INODE_SYNCHRONOUS | EXT2_INODE_IMMUTABLE \
700	| EXT2_INODE_APPEND_ONLY | EXT2_INODE_NO_DUMP | EXT2_INODE_NO_ACCESS_TIME \
701	| EXT2_INODE_DO_NOT_COMPRESS | EXT2_INODE_JOURNAL_DATA \
702	| EXT2_INODE_NO_MERGE_TAIL | EXT2_INODE_DIR_SYNCH)
703
704#define EXT2_NAME_LENGTH	255
705
706#define EXT2_DIR_PAD		4
707#define EXT2_DIR_ROUND		(EXT2_DIR_PAD - 1)
708#define EXT2_DIR_REC_LEN(namelen)	(((namelen) + 8 + EXT2_DIR_ROUND) \
709										& ~EXT2_DIR_ROUND)
710
711struct ext2_dir_entry {
712	uint32	inode_id;
713	uint16	length;
714	uint8	name_length;
715	uint8	file_type;
716	char	name[EXT2_NAME_LENGTH];
717
718	uint32	InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
719	uint16	Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
720	uint8	NameLength() const { return name_length; }
721	uint8	FileType() const { return file_type; }
722
723	void	SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
724
725	void	SetLength(uint16 newLength/*uint8 nameLength*/)
726	{
727		length = B_HOST_TO_LENDIAN_INT16(newLength);
728		/*name_length = nameLength;
729
730		if (nameLength % 4 == 0) {
731			length = B_HOST_TO_LENDIAN_INT16(
732				(short)(nameLength + MinimumSize()));
733		} else {
734			length = B_HOST_TO_LENDIAN_INT16(
735				(short)(nameLength % 4 + 1 + MinimumSize()));
736		}*/
737	}
738
739	bool IsValid() const
740	{
741		return Length() > MinimumSize();
742			// There is no maximum size, as the last entry spans until the
743			// end of the block
744	}
745
746	static size_t MinimumSize()
747	{
748		return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH;
749	}
750} _PACKED;
751
752struct ext2_dir_entry_tail {
753	uint32	zero1;
754	uint16	twelve;
755	uint8	zero2;
756	uint8	hexade;
757	uint32	checksum;
758} _PACKED;
759
760struct ext2_htree_tail {
761	uint32	reserved;
762	uint32	checksum;
763} _PACKED;
764
765// file types
766#define EXT2_TYPE_UNKNOWN		0
767#define EXT2_TYPE_FILE			1
768#define EXT2_TYPE_DIRECTORY		2
769#define EXT2_TYPE_CHAR_DEVICE	3
770#define EXT2_TYPE_BLOCK_DEVICE	4
771#define EXT2_TYPE_FIFO			5
772#define EXT2_TYPE_SOCKET		6
773#define EXT2_TYPE_SYMLINK		7
774
775#define EXT2_XATTR_MAGIC		0xea020000
776#define EXT2_XATTR_ROUND		((1 << 2) - 1)
777#define EXT2_XATTR_NAME_LENGTH	255
778
779#define EXT2_XATTR_INDEX_USER	1
780
781struct ext2_xattr_header {
782	uint32	magic;
783	uint32	refcount;
784	uint32	blocks;		// must be 1 for ext2
785	uint32	hash;
786	uint32	checksum;
787	uint32	reserved[3];	// zero
788
789	bool IsValid() const
790	{
791		return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC
792			&& B_LENDIAN_TO_HOST_INT32(blocks) == 1
793			&& refcount <= 1024;
794	}
795
796	void Dump() const {
797		for (unsigned int i = 0; i < Length(); i++)
798			dprintf("%02x ", ((uint8 *)this)[i]);
799		dprintf("\n");
800	}
801
802	static size_t Length()
803	{
804		return sizeof(ext2_xattr_header);
805	}
806};
807
808struct ext2_xattr_entry {
809	uint8	name_length;
810	uint8	name_index;
811	uint16	value_offset;
812	uint32	value_block;	// must be zero for ext2
813	uint32	value_size;
814	uint32	hash;
815	char	name[EXT2_XATTR_NAME_LENGTH];
816
817	uint8 NameLength() const { return name_length; }
818	uint8 NameIndex() const { return name_index; }
819	uint16 ValueOffset() const { return
820			B_LENDIAN_TO_HOST_INT16(value_offset); }
821	uint32 ValueSize() const { return
822			B_LENDIAN_TO_HOST_INT32(value_size); }
823
824	// padded sizes
825	uint32 Length() const { return (MinimumSize() + NameLength()
826		+ EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; }
827
828	bool IsValid() const
829	{
830		return NameLength() > 0 && value_block == 0;
831			// There is no maximum size, as the last entry spans until the
832			// end of the block
833	}
834
835	void Dump(bool full=false) const {
836		for (unsigned int i = 0; i < (full ? sizeof(*this) : MinimumSize()); i++)
837			dprintf("%02x ", ((uint8 *)this)[i]);
838		dprintf("\n");
839	}
840
841	static size_t MinimumSize()
842	{
843		return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH;
844	}
845} _PACKED;
846
847
848struct file_cookie {
849	bigtime_t	last_notification;
850	off_t		last_size;
851	int			open_mode;
852};
853
854
855#define EXT2_OPEN_MODE_USER_MASK		0x7fffffff
856
857#define INODE_NOTIFICATION_INTERVAL		10000000LL
858
859
860extern fs_volume_ops gExt2VolumeOps;
861extern fs_vnode_ops gExt2VnodeOps;
862
863#endif	// EXT2_H
864