xref: /haiku/src/add-ons/kernel/file_systems/ext2/ext2.h (revision 97901ec593ec4dd50ac115c1c35a6d72f6e489a5)
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 EXT2_SUPER_BLOCK_OFFSET	1024
17 
18 struct ext2_super_block {
19 	uint32	num_inodes;
20 	uint32	num_blocks;
21 	uint32	reserved_blocks;
22 	uint32	free_blocks;
23 	uint32	free_inodes;
24 	uint32	first_data_block;
25 	uint32	block_shift;
26 	uint32	fragment_shift;
27 	uint32	blocks_per_group;
28 	uint32	fragments_per_group;
29 	uint32	inodes_per_group;
30 	uint32	mount_time;
31 	uint32	write_time;
32 	uint16	mount_count;
33 	uint16	max_mount_count;
34 	uint16	magic;
35 	uint16	state;
36 	uint16	error_handling;
37 	uint16	minor_revision_level;
38 	uint32	last_check_time;
39 	uint32	check_interval;
40 	uint32	creator_os;
41 	uint32	revision_level;
42 	uint16	reserved_blocks_uid;
43 	uint16	reserved_blocks_gid;
44 	uint32	first_inode;
45 	uint16	inode_size;
46 	uint16	block_group;
47 	uint32	compatible_features;
48 	uint32	incompatible_features;
49 	uint32	read_only_features;
50 	uint8	uuid[16];
51 	char	name[16];
52 	char	last_mount_point[64];
53 	uint32	algorithm_usage_bitmap;
54 	uint8	preallocated_blocks;
55 	uint8	preallocated_directory_blocks;
56 	uint16	_padding;
57 
58 	// journaling ext3 support
59 	uint8	journal_uuid[16];
60 	uint32	journal_inode;
61 	uint32	journal_device;
62 	uint32	last_orphan;
63 	uint32	hash_seed[4];
64 	uint8	default_hash_version;
65 	uint8	_reserved1;
66 	uint16	_reserved2;
67 	uint32	default_mount_options;
68 	uint32	first_meta_block_group;
69 	uint32	fs_creation_time;
70 	uint32	journal_inode_backup[17];
71 
72 	// ext4 support
73 	uint32	num_blocks_hi;
74 	uint32	reserved_blocks_hi;
75 	uint32	free_blocks_hi;
76 	uint16	min_inode_size;
77 	uint16	want_inode_size;
78 	uint32	flags;
79 	uint16	raid_stride;
80 	uint16	mmp_interval;
81 	uint64	mmp_block;
82 	uint32	raid_stripe_width;
83 	uint8	groups_per_flex_shift;
84 	uint8	_reserved3;
85 	uint16	_reserved4;
86 	uint32	_reserved5[162];
87 
88 	uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); }
89 	uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; }
90 	uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); }
91 	uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
92 	uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); }
93 	uint32 FreeBlocks() const { return B_LENDIAN_TO_HOST_INT32(free_blocks); }
94 	uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); }
95 	uint32 FirstDataBlock() const
96 		{ return B_LENDIAN_TO_HOST_INT32(first_data_block); }
97 	uint32 BlocksPerGroup() const
98 		{ return B_LENDIAN_TO_HOST_INT32(blocks_per_group); }
99 	uint32 InodesPerGroup() const
100 		{ return B_LENDIAN_TO_HOST_INT32(inodes_per_group); }
101 	uint32 FirstMetaBlockGroup() const
102 		{ return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); }
103 	uint32 CompatibleFeatures() const
104 		{ return B_LENDIAN_TO_HOST_INT32(compatible_features); }
105 	uint32 ReadOnlyFeatures() const
106 		{ return B_LENDIAN_TO_HOST_INT32(read_only_features); }
107 	uint32 IncompatibleFeatures() const
108 		{ return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
109 
110 	bool IsValid();
111 		// implemented in Volume.cpp
112 } _PACKED;
113 
114 #define EXT2_OLD_REVISION		0
115 #define EXT2_DYNAMIC_REVISION	1
116 
117 // compatible features
118 #define EXT2_FEATURE_DIRECTORY_PREALLOCATION	0x0001
119 #define EXT2_FEATURE_IMAGIC_INODES				0x0002
120 #define EXT2_FEATURE_HAS_JOURNAL				0x0004
121 #define EXT2_FEATURE_EXT_ATTR					0x0008
122 #define EXT2_FEATURE_RESIZE_INODE				0x0010
123 #define EXT2_FEATURE_DIRECTORY_INDEX			0x0020
124 
125 // read-only compatible features
126 #define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER		0x0001
127 #define	EXT2_READ_ONLY_FEATURE_LARGE_FILE		0x0002
128 #define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY	0x0004
129 
130 // incompatible features
131 #define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION	0x0001
132 #define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE		0x0002
133 #define EXT2_INCOMPATIBLE_FEATURE_RECOVER		0x0004
134 #define EXT2_INCOMPATIBLE_FEATURE_JOURNAL		0x0008
135 #define EXT2_INCOMPATIBLE_FEATURE_META_GROUP	0x0010
136 #define EXT2_INCOMPATIBLE_FEATURE_EXTENTS		0x0040
137 #define EXT2_INCOMPATIBLE_FEATURE_64BIT			0x0080
138 #define EXT2_INCOMPATIBLE_FEATURE_MMP			0x0100
139 #define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP	0x0200
140 
141 // states
142 #define EXT2_STATE_VALID						0x01
143 #define	EXT2_STATE_INVALID						0x02
144 
145 struct ext2_block_group {
146 	uint32	block_bitmap;
147 	uint32	inode_bitmap;
148 	uint32	inode_table;
149 	uint16	free_blocks;
150 	uint16	free_inodes;
151 	uint16	used_directories;
152 	uint16	_padding;
153 	uint32	_reserved[3];
154 
155 	uint32 InodeTable() const
156 		{ return B_LENDIAN_TO_HOST_INT32(inode_table); }
157 } _PACKED;
158 
159 #define EXT2_DIRECT_BLOCKS			12
160 #define EXT2_ROOT_NODE				2
161 #define EXT2_SHORT_SYMLINK_LENGTH	60
162 
163 struct ext2_data_stream {
164 	uint32 direct[EXT2_DIRECT_BLOCKS];
165 	uint32 indirect;
166 	uint32 double_indirect;
167 	uint32 triple_indirect;
168 } _PACKED;
169 
170 struct ext2_inode {
171 	uint16	mode;
172 	uint16	uid;
173 	uint32	size;
174 	uint32	access_time;
175 	uint32	creation_time;
176 	uint32	modification_time;
177 	uint32	deletion_time;
178 	uint16	gid;
179 	uint16	num_links;
180 	uint32	num_blocks;
181 	uint32	flags;
182 	uint32	_reserved1;
183 	union {
184 		ext2_data_stream stream;
185 		char symlink[EXT2_SHORT_SYMLINK_LENGTH];
186 	};
187 	uint32	generation;
188 	uint32	file_access_control;
189 	union {
190 		// for directories vs. files
191 		uint32	directory_access_control;
192 		uint32	size_high;
193 	};
194 	uint32	fragment;
195 	uint8	fragment_number;
196 	uint8	fragment_size;
197 	uint16	_padding;
198 	uint16	uid_high;
199 	uint16	gid_high;
200 	uint32	_reserved2;
201 	uint16	extra_inode_size;
202 	uint16	_padding2;
203 
204 	uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
205 	uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
206 	uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
207 
208 	time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
209 	time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
210 	time_t ModificationTime() const { return B_LENDIAN_TO_HOST_INT32(modification_time); }
211 	time_t DeletionTime() const { return B_LENDIAN_TO_HOST_INT32(deletion_time); }
212 
213 	off_t Size() const
214 	{
215 		if (S_ISREG(Mode())) {
216 			return B_LENDIAN_TO_HOST_INT32(size)
217 				| ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32);
218 		}
219 
220 		return B_LENDIAN_TO_HOST_INT32(size);
221 	}
222 
223 	uint32 UserID() const
224 	{
225 		return B_LENDIAN_TO_HOST_INT16(uid)
226 			| (B_LENDIAN_TO_HOST_INT16(uid_high) << 16);
227 	}
228 
229 	uint32 GroupID() const
230 	{
231 		return B_LENDIAN_TO_HOST_INT16(gid)
232 			| (B_LENDIAN_TO_HOST_INT16(gid_high) << 16);
233 	}
234 } _PACKED;
235 
236 #define EXT2_SUPER_BLOCK_MAGIC			0xef53
237 
238 // flags
239 #define EXT2_INODE_SECURE_DELETION		0x00000001
240 #define EXT2_INODE_UNDELETE				0x00000002
241 #define EXT2_INODE_COMPRESSED			0x00000004
242 #define EXT2_INODE_SYNCHRONOUS			0x00000008
243 #define EXT2_INODE_IMMUTABLE			0x00000010
244 #define EXT2_INODE_APPEND_ONLY			0x00000020
245 #define EXT2_INODE_NO_DUMP				0x00000040
246 #define EXT2_INODE_NO_ACCESS_TIME		0x00000080
247 #define EXT2_INODE_DIRTY				0x00000100
248 #define EXT2_INODE_COMPRESSED_BLOCKS	0x00000200
249 #define EXT2_INODE_DO_NOT_COMPRESS		0x00000400
250 #define EXT2_INODE_COMPRESSION_ERROR	0x00000800
251 #define EXT2_INODE_BTREE				0x00001000
252 
253 #define EXT2_NAME_LENGTH	255
254 
255 struct ext2_dir_entry {
256 	uint32	inode_id;
257 	uint16	length;
258 	uint8	name_length;
259 	uint8	file_type;
260 	char	name[EXT2_NAME_LENGTH];
261 
262 	uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); }
263 	uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); }
264 	uint8 NameLength() const { return name_length; }
265 	uint8 FileType() const { return file_type; }
266 
267 	bool IsValid() const
268 	{
269 		return Length() > MinimumSize();
270 			// There is no maximum size, as the last entry spans until the
271 			// end of the block
272 	}
273 
274 	static size_t MinimumSize()
275 	{
276 		return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH;
277 	}
278 } _PACKED;
279 
280 // file types
281 #define EXT2_TYPE_UNKOWN		0
282 #define EXT2_TYPE_FILE			1
283 #define EXT2_TYPE_DIRECTORY		2
284 #define EXT2_TYPE_CHAR_DEVICE	3
285 #define EXT2_TYPE_BLOCK_DEVICE	4
286 #define EXT2_TYPE_FIFO			5
287 #define EXT2_TYPE_SOCKET		6
288 #define EXT2_TYPE_SYMLINK		7
289 
290 #define EXT2_XATTR_MAGIC		0xea020000
291 #define EXT2_XATTR_ROUND		((1 << 2) - 1)
292 #define EXT2_XATTR_NAME_LENGTH	255
293 
294 #define EXT2_XATTR_INDEX_USER	1
295 
296 struct ext2_xattr_header {
297 	uint32	magic;
298 	uint32	refcount;
299 	uint32	blocks;		// must be 1 for ext2
300 	uint32	hash;
301 	uint32	reserved[4];	// zero
302 
303 	bool IsValid() const
304 	{
305 		return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC
306 			&& B_LENDIAN_TO_HOST_INT32(blocks) == 1
307 			&& refcount <= 1024;
308 	}
309 
310 	void Dump() const {
311 		for (int i = 0; i < Length(); i++)
312 			dprintf("%02x ", ((uint8 *)this)[i]);
313 		dprintf("\n");
314 	}
315 
316 	static size_t Length()
317 	{
318 		return sizeof(ext2_xattr_header);
319 	}
320 };
321 
322 struct ext2_xattr_entry {
323 	uint8	name_length;
324 	uint8	name_index;
325 	uint16	value_offset;
326 	uint32	value_block;	// must be zero for ext2
327 	uint32	value_size;
328 	uint32	hash;
329 	char	name[EXT2_XATTR_NAME_LENGTH];
330 
331 	uint8 NameLength() const { return name_length; }
332 	uint8 NameIndex() const { return name_index; }
333 	uint16 ValueOffset() const { return
334 			B_LENDIAN_TO_HOST_INT16(value_offset); }
335 	uint32 ValueSize() const { return
336 			B_LENDIAN_TO_HOST_INT32(value_size); }
337 
338 	// padded sizes
339 	uint32 Length() const { return (MinimumSize() + NameLength()
340 		+ EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; }
341 
342 	bool IsValid() const
343 	{
344 		return NameLength() > 0 && value_block == 0;
345 			// There is no maximum size, as the last entry spans until the
346 			// end of the block
347 	}
348 
349 	void Dump(bool full=false) const {
350 		for (int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++)
351 			dprintf("%02x ", ((uint8 *)this)[i]);
352 		dprintf("\n");
353 	}
354 
355 	static size_t MinimumSize()
356 	{
357 		return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH;
358 	}
359 } _PACKED;
360 
361 
362 extern fs_volume_ops gExt2VolumeOps;
363 extern fs_vnode_ops gExt2VnodeOps;
364 
365 #endif	// EXT2_H
366