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