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