xref: /haiku/src/add-ons/kernel/file_systems/bfs/bfs.h (revision 24159a0c7d6d6dcba9f2a0c1a7c08d2c8167f21b)
1 /* bfs - BFS definitions and helper functions
2  *
3  * Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
4  * Parts of this code is based on work previously done by Marcus Overhagen.
5  *
6  * This file may be used under the terms of the MIT License.
7  */
8 #ifndef BFS_H
9 #define BFS_H
10 
11 
12 #include <SupportDefs.h>
13 
14 #include "bfs_endian.h"
15 
16 
17 #ifndef B_BEOS_VERSION_DANO
18 #	define B_BAD_DATA B_ERROR
19 #endif
20 
21 // ToDo: temporary fix! (missing but public ioctls)
22 #define IOCTL_FILE_UNCACHED_IO	10000
23 
24 struct block_run {
25 	int32		allocation_group;
26 	uint16		start;
27 	uint16		length;
28 
29 	int32 AllocationGroup() const { return BFS_ENDIAN_TO_HOST_INT32(allocation_group); }
30 	uint16 Start() const { return BFS_ENDIAN_TO_HOST_INT16(start); }
31 	uint16 Length() const { return BFS_ENDIAN_TO_HOST_INT16(length); }
32 
33 	inline bool operator==(const block_run &run) const;
34 	inline bool operator!=(const block_run &run) const;
35 	inline bool IsZero() const;
36 	inline bool MergeableWith(block_run run) const;
37 	inline void SetTo(int32 group, uint16 start, uint16 length = 1);
38 
39 	inline static block_run Run(int32 group, uint16 start, uint16 length = 1);
40 		// can't have a constructor because it's used in a union
41 } _PACKED;
42 
43 typedef block_run inode_addr;
44 
45 // Since the block_run::length field spans 16 bits, the largest number of
46 // blocks covered by a block_run is 65535 (as long as we don't want to
47 // break compatibility and take a zero length for 65536).
48 #define MAX_BLOCK_RUN_LENGTH	65535
49 
50 //**************************************
51 
52 
53 #define BFS_DISK_NAME_LENGTH	32
54 
55 struct disk_super_block {
56 	char		name[BFS_DISK_NAME_LENGTH];
57 	int32		magic1;
58 	int32		fs_byte_order;
59 	uint32		block_size;
60 	uint32		block_shift;
61 	off_t		num_blocks;
62 	off_t		used_blocks;
63 	int32		inode_size;
64 	int32		magic2;
65 	int32		blocks_per_ag;
66 	int32		ag_shift;
67 	int32		num_ags;
68 	int32		flags;
69 	block_run	log_blocks;
70 	off_t		log_start;
71 	off_t		log_end;
72 	int32		magic3;
73 	inode_addr	root_dir;
74 	inode_addr	indices;
75 	int32		pad[8];
76 
77 	int32 Magic1() const { return BFS_ENDIAN_TO_HOST_INT32(magic1); }
78 	int32 Magic2() const { return BFS_ENDIAN_TO_HOST_INT32(magic2); }
79 	int32 Magic3() const { return BFS_ENDIAN_TO_HOST_INT32(magic3); }
80 	int32 ByteOrder() const { return BFS_ENDIAN_TO_HOST_INT32(fs_byte_order); }
81 	uint32 BlockSize() const { return BFS_ENDIAN_TO_HOST_INT32(block_size); }
82 	uint32 BlockShift() const { return BFS_ENDIAN_TO_HOST_INT32(block_shift); }
83 	off_t NumBlocks() const { return BFS_ENDIAN_TO_HOST_INT64(num_blocks); }
84 	off_t UsedBlocks() const { return BFS_ENDIAN_TO_HOST_INT64(used_blocks); }
85 	int32 InodeSize() const { return BFS_ENDIAN_TO_HOST_INT32(inode_size); }
86 	int32 BlocksPerAllocationGroup() const { return BFS_ENDIAN_TO_HOST_INT32(blocks_per_ag); }
87 	int32 AllocationGroups() const { return BFS_ENDIAN_TO_HOST_INT32(num_ags); }
88 	int32 AllocationGroupShift() const { return BFS_ENDIAN_TO_HOST_INT32(ag_shift); }
89 	int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); }
90 	off_t LogStart() const { return BFS_ENDIAN_TO_HOST_INT64(log_start); }
91 	off_t LogEnd() const { return BFS_ENDIAN_TO_HOST_INT64(log_end); }
92 
93 	// implemented in Volume.cpp:
94 	bool IsValid();
95 	void Initialize(const char *name, off_t numBlocks, uint32 blockSize);
96 } _PACKED;
97 
98 #define SUPER_BLOCK_FS_LENDIAN		'BIGE'		/* BIGE */
99 
100 #define SUPER_BLOCK_MAGIC1			'BFS1'		/* BFS1 */
101 #define SUPER_BLOCK_MAGIC2			0xdd121031
102 #define SUPER_BLOCK_MAGIC3			0x15b6830e
103 
104 #define SUPER_BLOCK_DISK_CLEAN		'CLEN'		/* CLEN */
105 #define SUPER_BLOCK_DISK_DIRTY		'DIRT'		/* DIRT */
106 
107 //**************************************
108 
109 #define NUM_DIRECT_BLOCKS			12
110 
111 struct data_stream {
112 	block_run	direct[NUM_DIRECT_BLOCKS];
113 	off_t		max_direct_range;
114 	block_run	indirect;
115 	off_t		max_indirect_range;
116 	block_run	double_indirect;
117 	off_t		max_double_indirect_range;
118 	off_t		size;
119 
120 	off_t MaxDirectRange() const { return BFS_ENDIAN_TO_HOST_INT64(max_direct_range); }
121 	off_t MaxIndirectRange() const { return BFS_ENDIAN_TO_HOST_INT64(max_indirect_range); }
122 	off_t MaxDoubleIndirectRange() const { return BFS_ENDIAN_TO_HOST_INT64(max_double_indirect_range); }
123 	off_t Size() const { return BFS_ENDIAN_TO_HOST_INT64(size); }
124 } _PACKED;
125 
126 // This defines the size of the indirect and double indirect
127 // blocks. Note: the code may not work correctly at some places
128 // if this value is changed (it's not tested).
129 #define NUM_ARRAY_BLOCKS		4
130 #define ARRAY_BLOCKS_SHIFT		2
131 #define INDIRECT_BLOCKS_SHIFT	(ARRAY_BLOCKS_SHIFT + ARRAY_BLOCKS_SHIFT)
132 
133 //**************************************
134 
135 struct bfs_inode;
136 
137 struct small_data {
138 	uint32		type;
139 	uint16		name_size;
140 	uint16		data_size;
141 	char		name[0];	// name_size long, followed by data
142 
143 	uint32 Type() const { return BFS_ENDIAN_TO_HOST_INT32(type); }
144 	uint16 NameSize() const { return BFS_ENDIAN_TO_HOST_INT16(name_size); }
145 	uint16 DataSize() const { return BFS_ENDIAN_TO_HOST_INT16(data_size); }
146 
147 	inline char		*Name() const;
148 	inline uint8	*Data() const;
149 	inline uint32	Size() const;
150 	inline small_data *Next() const;
151 	inline bool		IsLast(const bfs_inode *inode) const;
152 } _PACKED;
153 
154 // the file name is part of the small_data structure
155 #define FILE_NAME_TYPE			'CSTR'
156 #define FILE_NAME_NAME			0x13
157 #define FILE_NAME_NAME_LENGTH	1
158 
159 
160 //**************************************
161 
162 class Volume;
163 
164 #define SHORT_SYMLINK_NAME_LENGTH	144 // length incl. terminating '\0'
165 
166 struct bfs_inode {
167 	int32		magic1;
168 	inode_addr	inode_num;
169 	int32		uid;
170 	int32		gid;
171 	int32		mode;				// see sys/stat.h
172 	int32		flags;
173 	bigtime_t	create_time;
174 	bigtime_t	last_modified_time;
175 	inode_addr	parent;
176 	inode_addr	attributes;
177 	uint32		type;				// attribute type
178 
179 	int32		inode_size;
180 	uint32		etc;				// a pointer to the Inode object during construction
181 
182 	union {
183 		data_stream		data;
184 		char 			short_symlink[SHORT_SYMLINK_NAME_LENGTH];
185 	};
186 	int32		pad[4];
187 
188 	small_data	small_data_start[0];
189 
190 	int32 Magic1() const { return BFS_ENDIAN_TO_HOST_INT32(magic1); }
191 	int32 UserID() const { return BFS_ENDIAN_TO_HOST_INT32(uid); }
192 	int32 GroupID() const { return BFS_ENDIAN_TO_HOST_INT32(gid); }
193 	int32 Mode() const { return BFS_ENDIAN_TO_HOST_INT32(mode); }
194 	int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); }
195 	int32 Type() const { return BFS_ENDIAN_TO_HOST_INT32(type); }
196 	int32 InodeSize() const { return BFS_ENDIAN_TO_HOST_INT32(inode_size); }
197 	bigtime_t LastModifiedTime() const { return BFS_ENDIAN_TO_HOST_INT64(last_modified_time); }
198 	bigtime_t CreateTime() const { return BFS_ENDIAN_TO_HOST_INT64(create_time); }
199 	small_data *SmallDataStart() { return small_data_start; }
200 
201 	status_t InitCheck(Volume *volume);
202 		// defined in Inode.cpp
203 } _PACKED;
204 
205 #define INODE_MAGIC1			0x3bbe0ad9
206 #define INODE_TIME_SHIFT		16
207 #define INODE_TIME_MASK			0xffff
208 #define INODE_FILE_NAME_LENGTH	256
209 
210 enum inode_flags {
211 	INODE_IN_USE			= 0x00000001,	// always set
212 	INODE_ATTR_INODE		= 0x00000004,
213 	INODE_LOGGED			= 0x00000008,	// log changes to the data stream
214 	INODE_DELETED			= 0x00000010,
215 	INODE_NOT_READY			= 0x00000020,	// used during Inode construction
216 	INODE_LONG_SYMLINK		= 0x00000040,	// symlink in data stream
217 
218 	INODE_PERMANENT_FLAGS	= 0x0000ffff,
219 
220 	INODE_WAS_WRITTEN		= 0x00020000,
221 	INODE_NO_TRANSACTION	= 0x00040000,
222 	INODE_DONT_FREE_SPACE	= 0x00080000,	// only used by the "chkbfs" functionality
223 	INODE_CHKBFS_RUNNING	= 0x00200000,
224 };
225 
226 //**************************************
227 
228 struct file_cookie {
229 	bigtime_t last_notification;
230 	off_t	last_size;
231 	int		open_mode;
232 };
233 
234 // notify every second if the file size has changed
235 #define INODE_NOTIFICATION_INTERVAL	1000000LL
236 
237 //**************************************
238 
239 
240 inline int32
241 divide_roundup(int32 num,int32 divisor)
242 {
243 	return (num + divisor - 1) / divisor;
244 }
245 
246 inline int64
247 divide_roundup(int64 num,int32 divisor)
248 {
249 	return (num + divisor - 1) / divisor;
250 }
251 
252 inline int
253 get_shift(uint64 i)
254 {
255 	int c;
256 	c = 0;
257 	while (i > 1) {
258 		i >>= 1;
259 		c++;
260 	}
261 	return c;
262 }
263 
264 inline int32
265 round_up(uint32 data)
266 {
267 	// rounds up to the next off_t boundary
268 	return (data + sizeof(off_t) - 1) & ~(sizeof(off_t) - 1);
269 }
270 
271 
272 /************************ block_run inline functions ************************/
273 //	#pragma mark -
274 
275 
276 inline bool
277 block_run::operator==(const block_run &run) const
278 {
279 	return allocation_group == run.allocation_group
280 		&& start == run.start
281 		&& length == run.length;
282 }
283 
284 
285 inline bool
286 block_run::operator!=(const block_run &run) const
287 {
288 	return allocation_group != run.allocation_group
289 		|| start != run.start
290 		|| length != run.length;
291 }
292 
293 
294 inline bool
295 block_run::IsZero() const
296 {
297 	return allocation_group == 0 && start == 0 && length == 0;
298 }
299 
300 
301 inline bool
302 block_run::MergeableWith(block_run run) const
303 {
304 	// 65535 is the maximum allowed run size for BFS
305 	return allocation_group == run.allocation_group
306 		&& Start() + Length() == run.Start()
307 		&& (uint32)Length() + run.Length() <= MAX_BLOCK_RUN_LENGTH;
308 }
309 
310 
311 inline void
312 block_run::SetTo(int32 _group,uint16 _start,uint16 _length)
313 {
314 	allocation_group = HOST_ENDIAN_TO_BFS_INT32(_group);
315 	start = HOST_ENDIAN_TO_BFS_INT16(_start);
316 	length = HOST_ENDIAN_TO_BFS_INT16(_length);
317 }
318 
319 
320 inline block_run
321 block_run::Run(int32 group, uint16 start, uint16 length)
322 {
323 	block_run run;
324 	run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(group);
325 	run.start = HOST_ENDIAN_TO_BFS_INT16(start);
326 	run.length = HOST_ENDIAN_TO_BFS_INT16(length);
327 	return run;
328 }
329 
330 
331 /************************ small_data inline functions ************************/
332 //	#pragma mark -
333 
334 
335 inline char *
336 small_data::Name() const
337 {
338 	return const_cast<char *>(name);
339 }
340 
341 
342 inline uint8 *
343 small_data::Data() const
344 {
345 	return (uint8 *)Name() + NameSize() + 3;
346 }
347 
348 
349 inline uint32
350 small_data::Size() const
351 {
352 	return sizeof(small_data) + NameSize() + 3 + DataSize() + 1;
353 }
354 
355 
356 inline small_data *
357 small_data::Next() const
358 {
359 	return (small_data *)((uint8 *)this + Size());
360 }
361 
362 
363 inline bool
364 small_data::IsLast(const bfs_inode *inode) const
365 {
366 	// we need to check the location first, because if name_size is already beyond
367 	// the block, we would touch invalid memory (although that can't cause wrong
368 	// results)
369 	return (uint32)this > (uint32)inode + inode->InodeSize() - sizeof(small_data) || name_size == 0;
370 }
371 
372 
373 #endif	/* BFS_H */
374