xref: /haiku/src/add-ons/kernel/file_systems/ext2/ext2.h (revision a7dde370f552f5376edbf25046ec9cf2ba8bbd1a)
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 #define EXT2_SUPER_BLOCK_OFFSET	1024
19 
20 struct ext2_super_block {
21 	uint32	num_inodes;
22 	uint32	num_blocks;
23 	uint32	reserved_blocks;
24 	uint32	free_blocks;
25 	uint32	free_inodes;
26 	uint32	first_data_block;
27 	uint32	block_shift;
28 	uint32	fragment_shift;
29 	uint32	blocks_per_group;
30 	uint32	fragments_per_group;
31 	uint32	inodes_per_group;
32 	uint32	mount_time;
33 	uint32	write_time;
34 	uint16	mount_count;
35 	uint16	max_mount_count;
36 	uint16	magic;
37 	uint16	state;
38 	uint16	error_handling;
39 	uint16	minor_revision_level;
40 	uint32	last_check_time;
41 	uint32	check_interval;
42 	uint32	creator_os;
43 	uint32	revision_level;
44 	uint16	reserved_blocks_uid;
45 	uint16	reserved_blocks_gid;
46 	uint32	first_inode;
47 	uint16	inode_size;
48 	uint16	block_group;
49 	uint32	compatible_features;
50 	uint32	incompatible_features;
51 	uint32	read_only_features;
52 	uint8	uuid[16];
53 	char	name[16];
54 	char	last_mount_point[64];
55 	uint32	algorithm_usage_bitmap;
56 	uint8	preallocated_blocks;
57 	uint8	preallocated_directory_blocks;
58 	uint16	_padding;
59 
60 	// journaling ext3 support
61 	uint8	journal_uuid[16];
62 	uint32	journal_inode;
63 	uint32	journal_device;
64 	uint32	last_orphan;
65 	uint32	hash_seed[4];
66 	uint8	default_hash_version;
67 	uint8	_reserved1;
68 	uint16	group_descriptor_size;
69 	uint32	default_mount_options;
70 	uint32	first_meta_block_group;
71 	uint32	fs_creation_time;
72 	uint32	journal_inode_backup[17];
73 
74 	// ext4 support
75 	uint32	num_blocks_hi;
76 	uint32	reserved_blocks_hi;
77 	uint32	free_blocks_hi;
78 	uint16	min_inode_size;
79 	uint16	want_inode_size;
80 	uint32	flags;
81 	uint16	raid_stride;
82 	uint16	mmp_interval;
83 	uint64	mmp_block;
84 	uint32	raid_stripe_width;
85 	uint8	groups_per_flex_shift;
86 	uint8	_reserved3;
87 	uint16	_reserved4;
88 	uint32	_reserved5[162];
89 
90 	uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); }
91 	uint16 State() const { return B_LENDIAN_TO_HOST_INT16(state); }
92 	uint32 RevisionLevel() const { return B_LENDIAN_TO_HOST_INT16(revision_level); }
93 	uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; }
94 	uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); }
95 	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
96 	uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); }
97 	uint32 FreeBlocks() const { return B_LENDIAN_TO_HOST_INT32(free_blocks); }
98 	uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); }
99 	uint32 FirstDataBlock() const
100 		{ return B_LENDIAN_TO_HOST_INT32(first_data_block); }
101 	uint32 BlocksPerGroup() const
102 		{ return B_LENDIAN_TO_HOST_INT32(blocks_per_group); }
103 	uint32 InodesPerGroup() const
104 		{ return B_LENDIAN_TO_HOST_INT32(inodes_per_group); }
105 	uint32 FirstMetaBlockGroup() const
106 		{ return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); }
107 	uint32 CompatibleFeatures() const
108 		{ return B_LENDIAN_TO_HOST_INT32(compatible_features); }
109 	uint32 ReadOnlyFeatures() const
110 		{ return B_LENDIAN_TO_HOST_INT32(read_only_features); }
111 	uint32 IncompatibleFeatures() const
112 		{ return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
113 	ino_t  JournalInode() const
114 		{ return B_LENDIAN_TO_HOST_INT32(journal_inode); }
115 	ino_t  LastOrphan() const
116 		{ return (ino_t)B_LENDIAN_TO_HOST_INT32(last_orphan); }
117 	uint32 HashSeed(uint8 i) const
118 		{ return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
119 	uint16 GroupDescriptorSize() const
120 		{ return B_LENDIAN_TO_HOST_INT16(group_descriptor_size); }
121 
122 	void SetFreeInodes(uint32 freeInodes)
123 		{ free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); }
124 	void SetFreeBlocks(uint32 freeBlocks)
125 		{ free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks); }
126 	void SetLastOrphan(ino_t id)
127 		{ last_orphan = B_HOST_TO_LENDIAN_INT32((uint32)id); }
128 	void SetReadOnlyFeatures(uint32 readOnlyFeatures) const
129 		{ readOnlyFeatures = B_HOST_TO_LENDIAN_INT32(readOnlyFeatures); }
130 
131 	bool IsValid();
132 		// implemented in Volume.cpp
133 } _PACKED;
134 
135 #define EXT2_OLD_REVISION		0
136 #define EXT2_DYNAMIC_REVISION	1
137 
138 #define EXT2_MAX_REVISION		EXT2_DYNAMIC_REVISION
139 
140 #define EXT2_FS_STATE_VALID		1	// File system was cleanly unmounted
141 #define EXT2_FS_STATE_ERROR		2	// File system has errors
142 #define EXT2_FS_STATE_ORPHAN	3	// Orphans are being recovered
143 
144 // compatible features
145 #define EXT2_FEATURE_DIRECTORY_PREALLOCATION	0x0001
146 #define EXT2_FEATURE_IMAGIC_INODES				0x0002
147 #define EXT2_FEATURE_HAS_JOURNAL				0x0004
148 #define EXT2_FEATURE_EXT_ATTR					0x0008
149 #define EXT2_FEATURE_RESIZE_INODE				0x0010
150 #define EXT2_FEATURE_DIRECTORY_INDEX			0x0020
151 
152 // read-only compatible features
153 #define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER		0x0001
154 #define EXT2_READ_ONLY_FEATURE_LARGE_FILE		0x0002
155 #define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY	0x0004
156 #define EXT2_READ_ONLY_FEATURE_HUGE_FILE		0x0008
157 #define EXT2_READ_ONLY_FEATURE_GDT_CSUM			0x0010
158 #define EXT2_READ_ONLY_FEATURE_DIR_NLINK		0x0020
159 #define EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE		0x0040
160 
161 // incompatible features
162 #define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION	0x0001
163 #define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE		0x0002
164 #define EXT2_INCOMPATIBLE_FEATURE_RECOVER		0x0004
165 #define EXT2_INCOMPATIBLE_FEATURE_JOURNAL		0x0008
166 #define EXT2_INCOMPATIBLE_FEATURE_META_GROUP	0x0010
167 #define EXT2_INCOMPATIBLE_FEATURE_EXTENTS		0x0040
168 #define EXT2_INCOMPATIBLE_FEATURE_64BIT			0x0080
169 #define EXT2_INCOMPATIBLE_FEATURE_MMP			0x0100
170 #define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP	0x0200
171 
172 // states
173 #define EXT2_STATE_VALID						0x01
174 #define	EXT2_STATE_INVALID						0x02
175 
176 struct ext2_block_group {
177 	uint32	block_bitmap;
178 	uint32	inode_bitmap;
179 	uint32	inode_table;
180 	uint16	free_blocks;
181 	uint16	free_inodes;
182 	uint16	used_directories;
183 	uint16	_padding;
184 	uint32	_reserved[3];
185 
186 	uint32	BlockBitmap() const
187 		{ return B_LENDIAN_TO_HOST_INT32(block_bitmap); }
188 	uint32	InodeBitmap() const
189 		{ return B_LENDIAN_TO_HOST_INT32(inode_bitmap); }
190 	uint32	InodeTable() const
191 		{ return B_LENDIAN_TO_HOST_INT32(inode_table); }
192 	uint16	FreeBlocks() const
193 		{ return B_LENDIAN_TO_HOST_INT16(free_blocks); }
194 	uint16	FreeInodes() const
195 		{ return B_LENDIAN_TO_HOST_INT16(free_inodes); }
196 	uint16	UsedDirectories() const
197 		{ return B_LENDIAN_TO_HOST_INT16(used_directories); }
198 
199 	void	SetFreeBlocks(uint16 freeBlocks)
200 		{ free_blocks = B_HOST_TO_LENDIAN_INT16(freeBlocks); }
201 
202 	void	SetFreeInodes(uint16 freeInodes)
203 		{ free_inodes = B_HOST_TO_LENDIAN_INT16(freeInodes); }
204 
205 	void	SetUsedDirectories(uint16 usedDirectories)
206 		{ used_directories = B_HOST_TO_LENDIAN_INT16(usedDirectories); }
207 } _PACKED;
208 
209 #define EXT2_DIRECT_BLOCKS			12
210 #define EXT2_ROOT_NODE				2
211 #define EXT2_SHORT_SYMLINK_LENGTH	60
212 
213 struct ext2_data_stream {
214 	uint32 direct[EXT2_DIRECT_BLOCKS];
215 	uint32 indirect;
216 	uint32 double_indirect;
217 	uint32 triple_indirect;
218 } _PACKED;
219 
220 #define EXT2_INODE_NORMAL_SIZE		128
221 
222 struct ext2_inode {
223 	uint16	mode;
224 	uint16	uid;
225 	uint32	size;
226 	uint32	access_time;
227 	uint32	change_time;
228 	uint32	modification_time;
229 	uint32	deletion_time;
230 	uint16	gid;
231 	uint16	num_links;
232 	uint32	num_blocks;
233 	uint32	flags;
234 	uint32	version;
235 	union {
236 		ext2_data_stream stream;
237 		char symlink[EXT2_SHORT_SYMLINK_LENGTH];
238 	};
239 	uint32	generation;
240 	uint32	file_access_control;
241 	union {
242 		// for directories vs. files
243 		uint32	directory_access_control;
244 		uint32	size_high;
245 	};
246 	uint32	fragment;
247 	union {
248 		struct {
249 			uint8	fragment_number;
250 			uint8	fragment_size;
251 		};
252 		uint16 num_blocks_high;
253 	};
254 	uint16	_padding;
255 	uint16	uid_high;
256 	uint16	gid_high;
257 	uint32	_reserved2;
258 
259 	// extra attributes
260 	uint16	extra_inode_size;
261 	uint16	_padding2;
262 	uint32	change_time_extra;
263 	uint32	modification_time_extra;
264 	uint32	access_time_extra;
265 	uint32	creation_time;
266 	uint32	creation_time_extra;
267 	uint32	version_high;
268 
269 	uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
270 	uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
271 	uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
272 	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
273 	uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
274 		| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
275 
276 	static void _DecodeTime(struct timespec *timespec, uint32 time,
277 		uint32 time_extra, bool extra)
278 	{
279 		timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time);
280 		if (extra && sizeof(timespec->tv_sec) > 4)
281 			timespec->tv_sec |=
282 				(uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32;
283 		if (extra)
284 			timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2;
285 		else
286 			timespec->tv_nsec = 0;
287 	}
288 
289 	void GetModificationTime(struct timespec *timespec, bool extra) const
290 		{ _DecodeTime(timespec, modification_time, modification_time_extra,
291 			extra); }
292 	void GetAccessTime(struct timespec *timespec, bool extra) const
293 		{ _DecodeTime(timespec, access_time, access_time_extra, extra); }
294 	void GetChangeTime(struct timespec *timespec, bool extra) const
295 		{ _DecodeTime(timespec, change_time, change_time_extra, extra); }
296 	void GetCreationTime(struct timespec *timespec, bool extra) const
297 	{
298 		if (extra)
299 			_DecodeTime(timespec, creation_time, creation_time_extra, extra);
300 		else {
301 			timespec->tv_sec = 0;
302 			timespec->tv_nsec = 0;
303 		}
304 	}
305 	time_t DeletionTime() const
306 		{ return B_LENDIAN_TO_HOST_INT32(deletion_time); }
307 
308 	static uint32 _EncodeTime(const struct timespec *timespec)
309 	{
310 		uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc;
311 		if (sizeof(timespec->tv_sec) > 4)
312 			time |= (uint64)timespec->tv_sec >> 32;
313 		return B_HOST_TO_LENDIAN_INT32(time);
314 	}
315 
316 	void SetModificationTime(const struct timespec *timespec, bool extra)
317 	{
318 		modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
319 		if (extra)
320 			modification_time_extra = _EncodeTime(timespec);
321 	}
322 	void SetAccessTime(const struct timespec *timespec, bool extra)
323 	{
324 		access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
325 		if (extra)
326 			access_time_extra = _EncodeTime(timespec);
327 	}
328 	void SetChangeTime(const struct timespec *timespec, bool extra)
329 	{
330 		change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
331 		if (extra)
332 			change_time_extra = _EncodeTime(timespec);
333 	}
334 	void SetCreationTime(const struct timespec *timespec, bool extra)
335 	{
336 		if (extra) {
337 			creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
338 			creation_time_extra =
339 				B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec);
340 		}
341 	}
342 	void SetDeletionTime(time_t deletionTime)
343 	{
344 		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
345 	}
346 
347 	ino_t  NextOrphan() const { return (ino_t)DeletionTime(); }
348 
349 	off_t Size() const
350 	{
351 		if (S_ISREG(Mode())) {
352 			return B_LENDIAN_TO_HOST_INT32(size)
353 				| ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32);
354 		}
355 
356 		return B_LENDIAN_TO_HOST_INT32(size);
357 	}
358 
359 	uint32 ExtendedAttributesBlock() const
360 	{	return B_LENDIAN_TO_HOST_INT32(file_access_control);}
361 
362 	uint16 ExtraInodeSize() const
363 		{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
364 
365 	uint32 UserID() const
366 	{
367 		return B_LENDIAN_TO_HOST_INT16(uid)
368 			| (B_LENDIAN_TO_HOST_INT16(uid_high) << 16);
369 	}
370 
371 	uint32 GroupID() const
372 	{
373 		return B_LENDIAN_TO_HOST_INT16(gid)
374 			| (B_LENDIAN_TO_HOST_INT16(gid_high) << 16);
375 	}
376 
377 	void SetMode(uint16 newMode)
378 	{
379 		mode = B_LENDIAN_TO_HOST_INT16(newMode);
380 	}
381 
382 	void UpdateMode(uint16 newMode, uint16 mask)
383 	{
384 		SetMode((Mode() & ~mask) | (newMode & mask));
385 	}
386 
387 	void ClearFlag(uint32 mask)
388 	{
389 		flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
390 	}
391 
392 	void SetFlag(uint32 mask)
393 	{
394 		flags |= B_HOST_TO_LENDIAN_INT32(mask);
395 	}
396 
397 	void SetFlags(uint32 newFlags)
398 	{
399 		flags = B_HOST_TO_LENDIAN_INT32(newFlags);
400 	}
401 
402 	void SetNumLinks(uint16 numLinks)
403 	{
404 		num_links = B_HOST_TO_LENDIAN_INT16(numLinks);
405 	}
406 
407 	void SetNumBlocks(uint32 numBlocks)
408 	{
409 		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
410 	}
411 
412 	void SetNumBlocks64(uint64 numBlocks)
413 	{
414 		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff);
415 		num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32);
416 	}
417 
418 	void SetNextOrphan(ino_t id)
419 	{
420 		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id);
421 	}
422 
423 	void SetSize(off_t newSize)
424 	{
425 		size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF);
426 		if (S_ISREG(Mode()))
427 			size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32);
428 	}
429 
430 	void SetUserID(uint32 newUID)
431 	{
432 		uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF);
433 		uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16);
434 	}
435 
436 	void SetGroupID(uint32 newGID)
437 	{
438 		gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF);
439 		gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16);
440 	}
441 
442 	void SetExtendedAttributesBlock(uint32 block)
443 	{
444 		file_access_control = B_HOST_TO_LENDIAN_INT32(block);
445 	}
446 
447 	void SetExtraInodeSize(uint16 newSize)
448 	{
449 		extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize);
450 	}
451 } _PACKED;
452 
453 #define EXT2_SUPER_BLOCK_MAGIC			0xef53
454 
455 // flags
456 #define EXT2_INODE_SECURE_DELETION		0x00000001
457 #define EXT2_INODE_UNDELETE				0x00000002
458 #define EXT2_INODE_COMPRESSED			0x00000004
459 #define EXT2_INODE_SYNCHRONOUS			0x00000008
460 #define EXT2_INODE_IMMUTABLE			0x00000010
461 #define EXT2_INODE_APPEND_ONLY			0x00000020
462 #define EXT2_INODE_NO_DUMP				0x00000040
463 #define EXT2_INODE_NO_ACCESS_TIME		0x00000080
464 #define EXT2_INODE_DIRTY				0x00000100
465 #define EXT2_INODE_COMPRESSED_BLOCKS	0x00000200
466 #define EXT2_INODE_DO_NOT_COMPRESS		0x00000400
467 #define EXT2_INODE_COMPRESSION_ERROR	0x00000800
468 #define EXT2_INODE_BTREE				0x00001000
469 #define EXT2_INODE_INDEXED				0x00001000
470 #define EXT2_INODE_HUGE_FILE			0x00040000
471 
472 #define EXT2_NAME_LENGTH	255
473 
474 struct ext2_dir_entry {
475 	uint32	inode_id;
476 	uint16	length;
477 	uint8	name_length;
478 	uint8	file_type;
479 	char	name[EXT2_NAME_LENGTH];
480 
481 	uint32	InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
482 	uint16	Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
483 	uint8	NameLength() const { return name_length; }
484 	uint8	FileType() const { return file_type; }
485 
486 	void	SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
487 
488 	void	SetLength(uint16 newLength/*uint8 nameLength*/)
489 	{
490 		length = B_HOST_TO_LENDIAN_INT16(newLength);
491 		/*name_length = nameLength;
492 
493 		if (nameLength % 4 == 0) {
494 			length = B_HOST_TO_LENDIAN_INT16(
495 				(short)(nameLength + MinimumSize()));
496 		} else {
497 			length = B_HOST_TO_LENDIAN_INT16(
498 				(short)(nameLength % 4 + 1 + MinimumSize()));
499 		}*/
500 	}
501 
502 	bool IsValid() const
503 	{
504 		return Length() > MinimumSize();
505 			// There is no maximum size, as the last entry spans until the
506 			// end of the block
507 	}
508 
509 	static size_t MinimumSize()
510 	{
511 		return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH;
512 	}
513 } _PACKED;
514 
515 // file types
516 #define EXT2_TYPE_UNKNOWN		0
517 #define EXT2_TYPE_FILE			1
518 #define EXT2_TYPE_DIRECTORY		2
519 #define EXT2_TYPE_CHAR_DEVICE	3
520 #define EXT2_TYPE_BLOCK_DEVICE	4
521 #define EXT2_TYPE_FIFO			5
522 #define EXT2_TYPE_SOCKET		6
523 #define EXT2_TYPE_SYMLINK		7
524 
525 #define EXT2_XATTR_MAGIC		0xea020000
526 #define EXT2_XATTR_ROUND		((1 << 2) - 1)
527 #define EXT2_XATTR_NAME_LENGTH	255
528 
529 #define EXT2_XATTR_INDEX_USER	1
530 
531 struct ext2_xattr_header {
532 	uint32	magic;
533 	uint32	refcount;
534 	uint32	blocks;		// must be 1 for ext2
535 	uint32	hash;
536 	uint32	reserved[4];	// zero
537 
538 	bool IsValid() const
539 	{
540 		return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC
541 			&& B_LENDIAN_TO_HOST_INT32(blocks) == 1
542 			&& refcount <= 1024;
543 	}
544 
545 	void Dump() const {
546 		for (unsigned int i = 0; i < Length(); i++)
547 			dprintf("%02x ", ((uint8 *)this)[i]);
548 		dprintf("\n");
549 	}
550 
551 	static size_t Length()
552 	{
553 		return sizeof(ext2_xattr_header);
554 	}
555 };
556 
557 struct ext2_xattr_entry {
558 	uint8	name_length;
559 	uint8	name_index;
560 	uint16	value_offset;
561 	uint32	value_block;	// must be zero for ext2
562 	uint32	value_size;
563 	uint32	hash;
564 	char	name[EXT2_XATTR_NAME_LENGTH];
565 
566 	uint8 NameLength() const { return name_length; }
567 	uint8 NameIndex() const { return name_index; }
568 	uint16 ValueOffset() const { return
569 			B_LENDIAN_TO_HOST_INT16(value_offset); }
570 	uint32 ValueSize() const { return
571 			B_LENDIAN_TO_HOST_INT32(value_size); }
572 
573 	// padded sizes
574 	uint32 Length() const { return (MinimumSize() + NameLength()
575 		+ EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; }
576 
577 	bool IsValid() const
578 	{
579 		return NameLength() > 0 && value_block == 0;
580 			// There is no maximum size, as the last entry spans until the
581 			// end of the block
582 	}
583 
584 	void Dump(bool full=false) const {
585 		for (unsigned int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++)
586 			dprintf("%02x ", ((uint8 *)this)[i]);
587 		dprintf("\n");
588 	}
589 
590 	static size_t MinimumSize()
591 	{
592 		return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH;
593 	}
594 } _PACKED;
595 
596 
597 struct file_cookie {
598 	bigtime_t	last_notification;
599 	off_t		last_size;
600 	int			open_mode;
601 };
602 
603 #define EXT2_OPEN_MODE_USER_MASK		0x7fffffff
604 
605 #define INODE_NOTIFICATION_INTERVAL		10000000LL
606 
607 
608 extern fs_volume_ops gExt2VolumeOps;
609 extern fs_vnode_ops gExt2VnodeOps;
610 
611 #endif	// EXT2_H
612