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