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