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