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