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
19typedef uint64 fileblock_t;		// file block number
20typedef uint64 fsblock_t;		// filesystem block number
21
22
23#define EXT2_SUPER_BLOCK_OFFSET	1024
24
25struct 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
206struct 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
325struct 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
335struct 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
359struct 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
375struct 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
395struct 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
406struct 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
669struct 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
726struct 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
752struct 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
792struct 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
804extern fs_volume_ops gExt2VolumeOps;
805extern fs_vnode_ops gExt2VnodeOps;
806
807#endif	// EXT2_H
808