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