xref: /haiku/src/add-ons/kernel/file_systems/ext2/ext2.h (revision c2f0a314a012bea8e4ebb35b8ce9e1a85c798727)
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 struct ext2_inode {
214 	uint16	mode;
215 	uint16	uid;
216 	uint32	size;
217 	uint32	access_time;
218 	uint32	creation_time;
219 	uint32	modification_time;
220 	uint32	deletion_time;
221 	uint16	gid;
222 	uint16	num_links;
223 	uint32	num_blocks;
224 	uint32	flags;
225 	uint32	_reserved1;
226 	union {
227 		ext2_data_stream stream;
228 		char symlink[EXT2_SHORT_SYMLINK_LENGTH];
229 	};
230 	uint32	generation;
231 	uint32	file_access_control;
232 	union {
233 		// for directories vs. files
234 		uint32	directory_access_control;
235 		uint32	size_high;
236 	};
237 	uint32	fragment;
238 	union {
239 		struct {
240 			uint8	fragment_number;
241 			uint8	fragment_size;
242 		};
243 		uint16 num_blocks_high;
244 	};
245 	uint16	_padding;
246 	uint16	uid_high;
247 	uint16	gid_high;
248 	uint32	_reserved2;
249 	uint16	extra_inode_size;
250 	uint16	_padding2;
251 
252 	uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
253 	uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
254 	uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
255 	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
256 	uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
257 		| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
258 
259 	time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
260 	time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
261 	time_t ModificationTime() const { return B_LENDIAN_TO_HOST_INT32(modification_time); }
262 	time_t DeletionTime() const { return B_LENDIAN_TO_HOST_INT32(deletion_time); }
263 	ino_t  NextOrphan() const { return (ino_t)DeletionTime(); }
264 
265 	off_t Size() const
266 	{
267 		if (S_ISREG(Mode())) {
268 			return B_LENDIAN_TO_HOST_INT32(size)
269 				| ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32);
270 		}
271 
272 		return B_LENDIAN_TO_HOST_INT32(size);
273 	}
274 
275 	uint32 UserID() const
276 	{
277 		return B_LENDIAN_TO_HOST_INT16(uid)
278 			| (B_LENDIAN_TO_HOST_INT16(uid_high) << 16);
279 	}
280 
281 	uint32 GroupID() const
282 	{
283 		return B_LENDIAN_TO_HOST_INT16(gid)
284 			| (B_LENDIAN_TO_HOST_INT16(gid_high) << 16);
285 	}
286 
287 	void SetMode(uint16 newMode)
288 	{
289 		mode = B_LENDIAN_TO_HOST_INT16(newMode);
290 	}
291 
292 	void UpdateMode(uint16 newMode, uint16 mask)
293 	{
294 		SetMode((Mode() & ~mask) | (newMode & mask));
295 	}
296 
297 	void ClearFlag(uint32 mask)
298 	{
299 		flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
300 	}
301 
302 	void SetFlag(uint32 mask)
303 	{
304 		flags |= B_HOST_TO_LENDIAN_INT32(mask);
305 	}
306 
307 	void SetFlags(uint32 newFlags)
308 	{
309 		flags = B_HOST_TO_LENDIAN_INT32(newFlags);
310 	}
311 
312 	void SetNumLinks(uint16 numLinks)
313 	{
314 		num_links = B_HOST_TO_LENDIAN_INT16(numLinks);
315 	}
316 
317 	void SetNumBlocks(uint32 numBlocks)
318 	{
319 		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
320 	}
321 
322 	void SetNumBlocks64(uint64 numBlocks)
323 	{
324 		num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff);
325 		num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32);
326 	}
327 
328 	void SetAccessTime(time_t accessTime)
329 	{
330 		access_time = B_HOST_TO_LENDIAN_INT32((uint32)accessTime);
331 	}
332 
333 	void SetCreationTime(time_t creationTime)
334 	{
335 		creation_time = B_HOST_TO_LENDIAN_INT32((uint32)creationTime);
336 	}
337 
338 	void SetModificationTime(time_t modificationTime)
339 	{
340 		modification_time = B_HOST_TO_LENDIAN_INT32((uint32)modificationTime);
341 	}
342 
343 	void SetDeletionTime(time_t deletionTime)
344 	{
345 		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
346 	}
347 
348 	void SetNextOrphan(ino_t id)
349 	{
350 		deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id);
351 	}
352 
353 	void SetSize(off_t newSize)
354 	{
355 		size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF);
356 		if (S_ISREG(Mode()))
357 			size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32);
358 	}
359 
360 	void SetUserID(uint32 newUID)
361 	{
362 		uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF);
363 		uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16);
364 	}
365 
366 	void SetGroupID(uint32 newGID)
367 	{
368 		gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF);
369 		gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16);
370 	}
371 
372 	void SetExtendedAttributesBlock(uint32 block)
373 	{
374 		file_access_control = B_HOST_TO_LENDIAN_INT32(block);
375 	}
376 } _PACKED;
377 
378 #define EXT2_SUPER_BLOCK_MAGIC			0xef53
379 
380 // flags
381 #define EXT2_INODE_SECURE_DELETION		0x00000001
382 #define EXT2_INODE_UNDELETE				0x00000002
383 #define EXT2_INODE_COMPRESSED			0x00000004
384 #define EXT2_INODE_SYNCHRONOUS			0x00000008
385 #define EXT2_INODE_IMMUTABLE			0x00000010
386 #define EXT2_INODE_APPEND_ONLY			0x00000020
387 #define EXT2_INODE_NO_DUMP				0x00000040
388 #define EXT2_INODE_NO_ACCESS_TIME		0x00000080
389 #define EXT2_INODE_DIRTY				0x00000100
390 #define EXT2_INODE_COMPRESSED_BLOCKS	0x00000200
391 #define EXT2_INODE_DO_NOT_COMPRESS		0x00000400
392 #define EXT2_INODE_COMPRESSION_ERROR	0x00000800
393 #define EXT2_INODE_BTREE				0x00001000
394 #define EXT2_INODE_INDEXED				0x00001000
395 #define EXT2_INODE_HUGE_FILE			0x00040000
396 
397 #define EXT2_NAME_LENGTH	255
398 
399 struct ext2_dir_entry {
400 	uint32	inode_id;
401 	uint16	length;
402 	uint8	name_length;
403 	uint8	file_type;
404 	char	name[EXT2_NAME_LENGTH];
405 
406 	uint32	InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
407 	uint16	Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
408 	uint8	NameLength() const { return name_length; }
409 	uint8	FileType() const { return file_type; }
410 
411 	void	SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); }
412 
413 	void	SetLength(uint16 newLength/*uint8 nameLength*/)
414 	{
415 		length = B_HOST_TO_LENDIAN_INT16(newLength);
416 		/*name_length = nameLength;
417 
418 		if (nameLength % 4 == 0) {
419 			length = B_HOST_TO_LENDIAN_INT16(
420 				(short)(nameLength + MinimumSize()));
421 		} else {
422 			length = B_HOST_TO_LENDIAN_INT16(
423 				(short)(nameLength % 4 + 1 + MinimumSize()));
424 		}*/
425 	}
426 
427 	bool IsValid() const
428 	{
429 		return Length() > MinimumSize();
430 			// There is no maximum size, as the last entry spans until the
431 			// end of the block
432 	}
433 
434 	static size_t MinimumSize()
435 	{
436 		return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH;
437 	}
438 } _PACKED;
439 
440 // file types
441 #define EXT2_TYPE_UNKOWN		0
442 #define EXT2_TYPE_FILE			1
443 #define EXT2_TYPE_DIRECTORY		2
444 #define EXT2_TYPE_CHAR_DEVICE	3
445 #define EXT2_TYPE_BLOCK_DEVICE	4
446 #define EXT2_TYPE_FIFO			5
447 #define EXT2_TYPE_SOCKET		6
448 #define EXT2_TYPE_SYMLINK		7
449 
450 #define EXT2_XATTR_MAGIC		0xea020000
451 #define EXT2_XATTR_ROUND		((1 << 2) - 1)
452 #define EXT2_XATTR_NAME_LENGTH	255
453 
454 #define EXT2_XATTR_INDEX_USER	1
455 
456 struct ext2_xattr_header {
457 	uint32	magic;
458 	uint32	refcount;
459 	uint32	blocks;		// must be 1 for ext2
460 	uint32	hash;
461 	uint32	reserved[4];	// zero
462 
463 	bool IsValid() const
464 	{
465 		return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC
466 			&& B_LENDIAN_TO_HOST_INT32(blocks) == 1
467 			&& refcount <= 1024;
468 	}
469 
470 	void Dump() const {
471 		for (unsigned int i = 0; i < Length(); i++)
472 			dprintf("%02x ", ((uint8 *)this)[i]);
473 		dprintf("\n");
474 	}
475 
476 	static size_t Length()
477 	{
478 		return sizeof(ext2_xattr_header);
479 	}
480 };
481 
482 struct ext2_xattr_entry {
483 	uint8	name_length;
484 	uint8	name_index;
485 	uint16	value_offset;
486 	uint32	value_block;	// must be zero for ext2
487 	uint32	value_size;
488 	uint32	hash;
489 	char	name[EXT2_XATTR_NAME_LENGTH];
490 
491 	uint8 NameLength() const { return name_length; }
492 	uint8 NameIndex() const { return name_index; }
493 	uint16 ValueOffset() const { return
494 			B_LENDIAN_TO_HOST_INT16(value_offset); }
495 	uint32 ValueSize() const { return
496 			B_LENDIAN_TO_HOST_INT32(value_size); }
497 
498 	// padded sizes
499 	uint32 Length() const { return (MinimumSize() + NameLength()
500 		+ EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; }
501 
502 	bool IsValid() const
503 	{
504 		return NameLength() > 0 && value_block == 0;
505 			// There is no maximum size, as the last entry spans until the
506 			// end of the block
507 	}
508 
509 	void Dump(bool full=false) const {
510 		for (unsigned int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++)
511 			dprintf("%02x ", ((uint8 *)this)[i]);
512 		dprintf("\n");
513 	}
514 
515 	static size_t MinimumSize()
516 	{
517 		return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH;
518 	}
519 } _PACKED;
520 
521 
522 struct file_cookie {
523 	bigtime_t	last_notification;
524 	off_t		last_size;
525 	int			open_mode;
526 };
527 
528 #define EXT2_OPEN_MODE_USER_MASK		0x7fffffff
529 
530 #define INODE_NOTIFICATION_INTERVAL		10000000LL
531 
532 
533 extern fs_volume_ops gExt2VolumeOps;
534 extern fs_vnode_ops gExt2VnodeOps;
535 
536 #endif	// EXT2_H
537