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		0x1	// File system was cleanly unmounted
175#define EXT2_FS_STATE_ERROR		0x2	// File system has errors
176#define EXT2_FS_STATE_ORPHAN	0x4	// Orphans are being recovered
177
178// compatible features
179#define EXT2_FEATURE_DIRECTORY_PREALLOCATION	0x0001
180#define EXT2_FEATURE_IMAGIC_INODES				0x0002
181#define EXT2_FEATURE_HAS_JOURNAL				0x0004
182#define EXT2_FEATURE_EXT_ATTR					0x0008
183#define EXT2_FEATURE_RESIZE_INODE				0x0010
184#define EXT2_FEATURE_DIRECTORY_INDEX			0x0020
185#define EXT2_FEATURE_SPARSESUPER2				0x0200
186
187// read-only compatible features
188#define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER		0x0001
189#define EXT2_READ_ONLY_FEATURE_LARGE_FILE		0x0002
190#define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY	0x0004
191#define EXT2_READ_ONLY_FEATURE_HUGE_FILE		0x0008
192#define EXT2_READ_ONLY_FEATURE_GDT_CSUM			0x0010
193#define EXT2_READ_ONLY_FEATURE_DIR_NLINK		0x0020
194#define EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE		0x0040
195#define EXT2_READ_ONLY_FEATURE_QUOTA			0x0100
196#define EXT2_READ_ONLY_FEATURE_BIGALLOC			0x0200
197#define EXT4_READ_ONLY_FEATURE_METADATA_CSUM	0x0400
198#define EXT4_READ_ONLY_FEATURE_READONLY			0x1000
199#define EXT4_READ_ONLY_FEATURE_PROJECT			0x2000
200
201// incompatible features
202#define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION	0x0001
203#define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE		0x0002
204#define EXT2_INCOMPATIBLE_FEATURE_RECOVER		0x0004
205#define EXT2_INCOMPATIBLE_FEATURE_JOURNAL		0x0008
206#define EXT2_INCOMPATIBLE_FEATURE_META_GROUP	0x0010
207#define EXT2_INCOMPATIBLE_FEATURE_EXTENTS		0x0040
208#define EXT2_INCOMPATIBLE_FEATURE_64BIT			0x0080
209#define EXT2_INCOMPATIBLE_FEATURE_MMP			0x0100
210#define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP	0x0200
211#define EXT2_INCOMPATIBLE_FEATURE_EA_INODE		0x0400
212#define EXT2_INCOMPATIBLE_FEATURE_DIR_DATA		0x1000
213#define EXT2_INCOMPATIBLE_FEATURE_CSUM_SEED		0x2000
214#define EXT2_INCOMPATIBLE_FEATURE_LARGEDIR		0x4000
215#define EXT2_INCOMPATIBLE_FEATURE_INLINE_DATA	0x8000
216#define EXT2_INCOMPATIBLE_FEATURE_ENCRYPT		0x10000
217
218// states
219#define EXT2_STATE_VALID						0x01
220#define	EXT2_STATE_INVALID						0x02
221
222#define EXT2_BLOCK_GROUP_NORMAL_SIZE			32
223
224// block group flags
225#define EXT2_BLOCK_GROUP_INODE_UNINIT	0x1
226#define EXT2_BLOCK_GROUP_BLOCK_UNINIT	0x2
227
228
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	uint32	project_id;
487
488	uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
489	uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
490	uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
491	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
492	uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
493		| ((uint64)B_LENDIAN_TO_HOST_INT16(num_blocks_high) << 32); }
494
495	static void _DecodeTime(struct timespec *timespec, uint32 time,
496		uint32 time_extra, bool extra)
497	{
498		timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time);
499		if (extra && sizeof(timespec->tv_sec) > 4)
500			timespec->tv_sec |=
501				(uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32;
502		if (extra)
503			timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2;
504		else
505			timespec->tv_nsec = 0;
506	}
507
508	void GetModificationTime(struct timespec *timespec, bool extra) const
509		{ _DecodeTime(timespec, modification_time, modification_time_extra,
510			extra); }
511	void GetAccessTime(struct timespec *timespec, bool extra) const
512		{ _DecodeTime(timespec, access_time, access_time_extra, extra); }
513	void GetChangeTime(struct timespec *timespec, bool extra) const
514		{ _DecodeTime(timespec, change_time, change_time_extra, extra); }
515	void GetCreationTime(struct timespec *timespec, bool extra) const
516	{
517		if (extra)
518			_DecodeTime(timespec, creation_time, creation_time_extra, extra);
519		else {
520			timespec->tv_sec = 0;
521			timespec->tv_nsec = 0;
522		}
523	}
524	time_t DeletionTime() const
525		{ return B_LENDIAN_TO_HOST_INT32(deletion_time); }
526
527	static uint32 _EncodeTime(const struct timespec *timespec)
528	{
529		uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc;
530		if (sizeof(timespec->tv_sec) > 4)
531			time |= (uint64)timespec->tv_sec >> 32;
532		return B_HOST_TO_LENDIAN_INT32(time);
533	}
534
535	void SetModificationTime(const struct timespec *timespec, bool extra)
536	{
537		modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
538		if (extra)
539			modification_time_extra = _EncodeTime(timespec);
540	}
541	void SetAccessTime(const struct timespec *timespec, bool extra)
542	{
543		access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
544		if (extra)
545			access_time_extra = _EncodeTime(timespec);
546	}
547	void SetChangeTime(const struct timespec *timespec, bool extra)
548	{
549		change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
550		if (extra)
551			change_time_extra = _EncodeTime(timespec);
552	}
553	void SetCreationTime(const struct timespec *timespec, bool extra)
554	{
555		if (extra) {
556			creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
557			creation_time_extra =
558				B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec);
559		}
560	}
561	void SetDeletionTime(time_t deletionTime)
562	{
563		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
564	}
565
566	ino_t  NextOrphan() const { return (ino_t)DeletionTime(); }
567
568	off_t Size() const
569	{
570		if (S_ISREG(Mode())) {
571			return B_LENDIAN_TO_HOST_INT32(size)
572				| ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32);
573		}
574
575		return B_LENDIAN_TO_HOST_INT32(size);
576	}
577
578	uint32 ExtendedAttributesBlock() const
579	{	return B_LENDIAN_TO_HOST_INT32(file_access_control);}
580
581	uint16 ExtraInodeSize() const
582		{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
583
584	uint32 UserID() const
585	{
586		return B_LENDIAN_TO_HOST_INT16(uid)
587			| (B_LENDIAN_TO_HOST_INT16(uid_high) << 16);
588	}
589
590	uint32 GroupID() const
591	{
592		return B_LENDIAN_TO_HOST_INT16(gid)
593			| (B_LENDIAN_TO_HOST_INT16(gid_high) << 16);
594	}
595
596	void SetMode(uint16 newMode)
597	{
598		mode = B_LENDIAN_TO_HOST_INT16(newMode);
599	}
600
601	void UpdateMode(uint16 newMode, uint16 mask)
602	{
603		SetMode((Mode() & ~mask) | (newMode & mask));
604	}
605
606	void ClearFlag(uint32 mask)
607	{
608		flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
609	}
610
611	void SetFlag(uint32 mask)
612	{
613		flags |= B_HOST_TO_LENDIAN_INT32(mask);
614	}
615
616	void SetFlags(uint32 newFlags)
617	{
618		flags = B_HOST_TO_LENDIAN_INT32(newFlags);
619	}
620
621	void SetNumLinks(uint16 numLinks)
622	{
623		num_links = B_HOST_TO_LENDIAN_INT16(numLinks);
624	}
625
626	void SetNumBlocks(uint32 numBlocks)
627	{
628		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
629	}
630
631	void SetNumBlocks64(uint64 numBlocks)
632	{
633		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff);
634		num_blocks_high = B_HOST_TO_LENDIAN_INT16(numBlocks >> 32);
635	}
636
637	void SetNextOrphan(ino_t id)
638	{
639		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id);
640	}
641
642	void SetSize(off_t newSize)
643	{
644		size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF);
645		if (S_ISREG(Mode()))
646			size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32);
647	}
648
649	void SetUserID(uint32 newUID)
650	{
651		uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF);
652		uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16);
653	}
654
655	void SetGroupID(uint32 newGID)
656	{
657		gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF);
658		gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16);
659	}
660
661	void SetExtendedAttributesBlock(uint32 block)
662	{
663		file_access_control = B_HOST_TO_LENDIAN_INT32(block);
664	}
665
666	void SetExtraInodeSize(uint16 newSize)
667	{
668		extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize);
669	}
670} _PACKED;
671
672#define EXT2_SUPER_BLOCK_MAGIC			0xef53
673
674// flags
675#define EXT2_INODE_SECURE_DELETION		0x00000001
676#define EXT2_INODE_UNDELETE				0x00000002
677#define EXT2_INODE_COMPRESSED			0x00000004
678#define EXT2_INODE_SYNCHRONOUS			0x00000008
679#define EXT2_INODE_IMMUTABLE			0x00000010
680#define EXT2_INODE_APPEND_ONLY			0x00000020
681#define EXT2_INODE_NO_DUMP				0x00000040
682#define EXT2_INODE_NO_ACCESS_TIME		0x00000080
683#define EXT2_INODE_DIRTY				0x00000100
684#define EXT2_INODE_COMPRESSED_BLOCKS	0x00000200
685#define EXT2_INODE_DO_NOT_COMPRESS		0x00000400
686#define EXT2_INODE_COMPRESSION_ERROR	0x00000800
687#define EXT2_INODE_BTREE				0x00001000
688#define EXT2_INODE_INDEXED				0x00001000
689#define EXT2_INODE_JOURNAL_DATA			0x00004000
690#define EXT2_INODE_NO_MERGE_TAIL		0x00008000
691#define EXT2_INODE_DIR_SYNCH			0x00010000
692#define EXT2_INODE_HUGE_FILE			0x00040000
693#define EXT2_INODE_EXTENTS				0x00080000
694#define EXT2_INODE_LARGE_EA				0x00200000
695#define EXT2_INODE_EOF_BLOCKS			0x00400000
696#define EXT2_INODE_INLINE_DATA			0x10000000
697#define EXT2_INODE_RESERVED				0x80000000
698
699#define EXT2_INODE_INHERITED (EXT2_INODE_SECURE_DELETION | EXT2_INODE_UNDELETE \
700	| EXT2_INODE_COMPRESSED | EXT2_INODE_SYNCHRONOUS | EXT2_INODE_IMMUTABLE \
701	| EXT2_INODE_APPEND_ONLY | EXT2_INODE_NO_DUMP | EXT2_INODE_NO_ACCESS_TIME \
702	| EXT2_INODE_DO_NOT_COMPRESS | EXT2_INODE_JOURNAL_DATA \
703	| EXT2_INODE_NO_MERGE_TAIL | EXT2_INODE_DIR_SYNCH)
704
705#define EXT2_NAME_LENGTH	255
706
707#define EXT2_DIR_PAD		4
708#define EXT2_DIR_ROUND		(EXT2_DIR_PAD - 1)
709#define EXT2_DIR_REC_LEN(namelen)	(((namelen) + 8 + EXT2_DIR_ROUND) \
710										& ~EXT2_DIR_ROUND)
711
712struct ext2_dir_entry {
713	uint32	inode_id;
714	uint16	length;
715	uint8	name_length;
716	uint8	file_type;
717	char	name[EXT2_NAME_LENGTH];
718
719	uint32	InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
720	uint16	Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
721	uint8	NameLength() const { return name_length; }
722	uint8	FileType() const { return file_type; }
723
724	void	SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
725
726	void	SetLength(uint16 newLength/*uint8 nameLength*/)
727	{
728		length = B_HOST_TO_LENDIAN_INT16(newLength);
729		/*name_length = nameLength;
730
731		if (nameLength % 4 == 0) {
732			length = B_HOST_TO_LENDIAN_INT16(
733				(short)(nameLength + MinimumSize()));
734		} else {
735			length = B_HOST_TO_LENDIAN_INT16(
736				(short)(nameLength % 4 + 1 + MinimumSize()));
737		}*/
738	}
739
740	bool IsValid() const
741	{
742		return Length() > MinimumSize();
743			// There is no maximum size, as the last entry spans until the
744			// end of the block
745	}
746
747	static size_t MinimumSize()
748	{
749		return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH;
750	}
751} _PACKED;
752
753struct ext2_dir_entry_tail {
754	uint32	zero1;
755	uint16	twelve;
756	uint8	zero2;
757	uint8	hexade;
758	uint32	checksum;
759} _PACKED;
760
761struct ext2_htree_tail {
762	uint32	reserved;
763	uint32	checksum;
764} _PACKED;
765
766// file types
767#define EXT2_TYPE_UNKNOWN		0
768#define EXT2_TYPE_FILE			1
769#define EXT2_TYPE_DIRECTORY		2
770#define EXT2_TYPE_CHAR_DEVICE	3
771#define EXT2_TYPE_BLOCK_DEVICE	4
772#define EXT2_TYPE_FIFO			5
773#define EXT2_TYPE_SOCKET		6
774#define EXT2_TYPE_SYMLINK		7
775
776#define EXT2_XATTR_MAGIC		0xea020000
777#define EXT2_XATTR_ROUND		((1 << 2) - 1)
778#define EXT2_XATTR_NAME_LENGTH	255
779
780#define EXT2_XATTR_INDEX_USER	1
781
782struct ext2_xattr_header {
783	uint32	magic;
784	uint32	refcount;
785	uint32	blocks;		// must be 1 for ext2
786	uint32	hash;
787	uint32	checksum;
788	uint32	reserved[3];	// zero
789
790	bool IsValid() const
791	{
792		return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC
793			&& B_LENDIAN_TO_HOST_INT32(blocks) == 1
794			&& refcount <= 1024;
795	}
796
797	void Dump() const {
798		for (unsigned int i = 0; i < Length(); i++)
799			dprintf("%02x ", ((uint8 *)this)[i]);
800		dprintf("\n");
801	}
802
803	static size_t Length()
804	{
805		return sizeof(ext2_xattr_header);
806	}
807};
808
809struct ext2_xattr_entry {
810	uint8	name_length;
811	uint8	name_index;
812	uint16	value_offset;
813	uint32	value_block;	// must be zero for ext2
814	uint32	value_size;
815	uint32	hash;
816	char	name[EXT2_XATTR_NAME_LENGTH];
817
818	uint8 NameLength() const { return name_length; }
819	uint8 NameIndex() const { return name_index; }
820	uint16 ValueOffset() const { return
821			B_LENDIAN_TO_HOST_INT16(value_offset); }
822	uint32 ValueSize() const { return
823			B_LENDIAN_TO_HOST_INT32(value_size); }
824
825	// padded sizes
826	uint32 Length() const { return (MinimumSize() + NameLength()
827		+ EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; }
828
829	bool IsValid() const
830	{
831		return NameLength() > 0 && value_block == 0;
832			// There is no maximum size, as the last entry spans until the
833			// end of the block
834	}
835
836	void Dump(bool full=false) const {
837		for (unsigned int i = 0; i < (full ? sizeof(*this) : MinimumSize()); i++)
838			dprintf("%02x ", ((uint8 *)this)[i]);
839		dprintf("\n");
840	}
841
842	static size_t MinimumSize()
843	{
844		return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH;
845	}
846} _PACKED;
847
848
849struct file_cookie {
850	bigtime_t	last_notification;
851	off_t		last_size;
852	int			open_mode;
853};
854
855
856#define EXT2_OPEN_MODE_USER_MASK		0x7fffffff
857
858#define INODE_NOTIFICATION_INTERVAL		10000000LL
859
860
861extern fs_volume_ops gExt2VolumeOps;
862extern fs_vnode_ops gExt2VnodeOps;
863
864#endif	// EXT2_H
865