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