1 /* 2 * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 #ifndef EXT2_H 6 #define EXT2_H 7 8 9 #include <sys/stat.h> 10 11 #include <ByteOrder.h> 12 #include <fs_interface.h> 13 #include <KernelExport.h> 14 15 16 typedef uint64 fileblock_t; // file block number 17 typedef uint64 fsblock_t; // filesystem block number 18 19 20 #define EXT2_SUPER_BLOCK_OFFSET 1024 21 22 struct ext2_super_block { 23 uint32 num_inodes; 24 uint32 num_blocks; 25 uint32 reserved_blocks; 26 uint32 free_blocks; 27 uint32 free_inodes; 28 uint32 first_data_block; 29 uint32 block_shift; 30 uint32 fragment_shift; 31 uint32 blocks_per_group; 32 uint32 fragments_per_group; 33 uint32 inodes_per_group; 34 uint32 mount_time; 35 uint32 write_time; 36 uint16 mount_count; 37 uint16 max_mount_count; 38 uint16 magic; 39 uint16 state; 40 uint16 error_handling; 41 uint16 minor_revision_level; 42 uint32 last_check_time; 43 uint32 check_interval; 44 uint32 creator_os; 45 uint32 revision_level; 46 uint16 reserved_blocks_uid; 47 uint16 reserved_blocks_gid; 48 uint32 first_inode; 49 uint16 inode_size; 50 uint16 block_group; 51 uint32 compatible_features; 52 uint32 incompatible_features; 53 uint32 read_only_features; 54 uint8 uuid[16]; 55 char name[16]; 56 char last_mount_point[64]; 57 uint32 algorithm_usage_bitmap; 58 uint8 preallocated_blocks; 59 uint8 preallocated_directory_blocks; 60 uint16 reserved_gdt_blocks; 61 62 // journaling ext3 support 63 uint8 journal_uuid[16]; 64 uint32 journal_inode; 65 uint32 journal_device; 66 uint32 last_orphan; 67 uint32 hash_seed[4]; 68 uint8 default_hash_version; 69 uint8 _reserved1; 70 uint16 group_descriptor_size; 71 uint32 default_mount_options; 72 uint32 first_meta_block_group; 73 uint32 fs_creation_time; 74 uint32 journal_inode_backup[17]; 75 76 // ext4 support 77 uint32 num_blocks_high; 78 uint32 reserved_blocks_high; 79 uint32 free_blocks_high; 80 uint16 min_inode_size; 81 uint16 want_inode_size; 82 uint32 flags; 83 uint16 raid_stride; 84 uint16 mmp_interval; 85 uint64 mmp_block; 86 uint32 raid_stripe_width; 87 uint8 groups_per_flex_shift; 88 uint8 _reserved3; 89 uint16 _reserved4; 90 uint32 _reserved5[162]; 91 92 uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); } 93 uint16 State() const { return B_LENDIAN_TO_HOST_INT16(state); } 94 uint32 RevisionLevel() const { return B_LENDIAN_TO_HOST_INT16(revision_level); } 95 uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; } 96 uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); } 97 uint64 NumBlocks(bool has64bits) const 98 { 99 uint64 blocks = B_LENDIAN_TO_HOST_INT32(num_blocks); 100 if (has64bits) 101 blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); 102 return blocks; 103 } 104 uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); } 105 uint64 FreeBlocks(bool has64bits) const 106 { 107 uint64 blocks = B_LENDIAN_TO_HOST_INT32(free_blocks); 108 if (has64bits) 109 blocks |= ((uint64)B_LENDIAN_TO_HOST_INT32(free_blocks_high) << 32); 110 return blocks; 111 } 112 uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); } 113 uint32 FirstDataBlock() const 114 { return B_LENDIAN_TO_HOST_INT32(first_data_block); } 115 uint32 BlocksPerGroup() const 116 { return B_LENDIAN_TO_HOST_INT32(blocks_per_group); } 117 uint32 InodesPerGroup() const 118 { return B_LENDIAN_TO_HOST_INT32(inodes_per_group); } 119 uint32 FirstMetaBlockGroup() const 120 { return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); } 121 uint32 CompatibleFeatures() const 122 { return B_LENDIAN_TO_HOST_INT32(compatible_features); } 123 uint32 ReadOnlyFeatures() const 124 { return B_LENDIAN_TO_HOST_INT32(read_only_features); } 125 uint32 IncompatibleFeatures() const 126 { return B_LENDIAN_TO_HOST_INT32(incompatible_features); } 127 uint16 ReservedGDTBlocks() const 128 { return B_LENDIAN_TO_HOST_INT16(reserved_gdt_blocks); } 129 ino_t JournalInode() const 130 { return B_LENDIAN_TO_HOST_INT32(journal_inode); } 131 ino_t LastOrphan() const 132 { return (ino_t)B_LENDIAN_TO_HOST_INT32(last_orphan); } 133 uint32 HashSeed(uint8 i) const 134 { return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); } 135 uint16 GroupDescriptorSize() const 136 { return B_LENDIAN_TO_HOST_INT16(group_descriptor_size); } 137 138 void SetFreeInodes(uint32 freeInodes) 139 { free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); } 140 void SetFreeBlocks(uint64 freeBlocks, bool has64bits) 141 { 142 free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks & 0xffffffff); 143 if (has64bits) 144 free_blocks_high = B_HOST_TO_LENDIAN_INT32(freeBlocks >> 32); 145 } 146 void SetLastOrphan(ino_t id) 147 { last_orphan = B_HOST_TO_LENDIAN_INT32((uint32)id); } 148 void SetReadOnlyFeatures(uint32 readOnlyFeatures) const 149 { readOnlyFeatures = B_HOST_TO_LENDIAN_INT32(readOnlyFeatures); } 150 151 bool IsValid(); 152 // implemented in Volume.cpp 153 } _PACKED; 154 155 #define EXT2_OLD_REVISION 0 156 #define EXT2_DYNAMIC_REVISION 1 157 158 #define EXT2_MAX_REVISION EXT2_DYNAMIC_REVISION 159 160 #define EXT2_FS_STATE_VALID 1 // File system was cleanly unmounted 161 #define EXT2_FS_STATE_ERROR 2 // File system has errors 162 #define EXT2_FS_STATE_ORPHAN 3 // Orphans are being recovered 163 164 // compatible features 165 #define EXT2_FEATURE_DIRECTORY_PREALLOCATION 0x0001 166 #define EXT2_FEATURE_IMAGIC_INODES 0x0002 167 #define EXT2_FEATURE_HAS_JOURNAL 0x0004 168 #define EXT2_FEATURE_EXT_ATTR 0x0008 169 #define EXT2_FEATURE_RESIZE_INODE 0x0010 170 #define EXT2_FEATURE_DIRECTORY_INDEX 0x0020 171 172 // read-only compatible features 173 #define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER 0x0001 174 #define EXT2_READ_ONLY_FEATURE_LARGE_FILE 0x0002 175 #define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY 0x0004 176 #define EXT2_READ_ONLY_FEATURE_HUGE_FILE 0x0008 177 #define EXT2_READ_ONLY_FEATURE_GDT_CSUM 0x0010 178 #define EXT2_READ_ONLY_FEATURE_DIR_NLINK 0x0020 179 #define EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE 0x0040 180 181 // incompatible features 182 #define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION 0x0001 183 #define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE 0x0002 184 #define EXT2_INCOMPATIBLE_FEATURE_RECOVER 0x0004 185 #define EXT2_INCOMPATIBLE_FEATURE_JOURNAL 0x0008 186 #define EXT2_INCOMPATIBLE_FEATURE_META_GROUP 0x0010 187 #define EXT2_INCOMPATIBLE_FEATURE_EXTENTS 0x0040 188 #define EXT2_INCOMPATIBLE_FEATURE_64BIT 0x0080 189 #define EXT2_INCOMPATIBLE_FEATURE_MMP 0x0100 190 #define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP 0x0200 191 192 // states 193 #define EXT2_STATE_VALID 0x01 194 #define EXT2_STATE_INVALID 0x02 195 196 #define EXT2_BLOCK_GROUP_NORMAL_SIZE 32 197 #define EXT2_BLOCK_GROUP_64BIT_SIZE 64 198 199 // block group flags 200 #define EXT2_BLOCK_GROUP_INODE_UNINIT 0x1 201 #define EXT2_BLOCK_GROUP_BLOCK_UNINIT 0x2 202 203 204 struct ext2_block_group { 205 uint32 block_bitmap; 206 uint32 inode_bitmap; 207 uint32 inode_table; 208 uint16 free_blocks; 209 uint16 free_inodes; 210 uint16 used_directories; 211 uint16 flags; 212 uint32 _reserved[2]; 213 uint16 unused_inodes; 214 uint16 checksum; 215 216 // ext4 217 uint32 block_bitmap_high; 218 uint32 inode_bitmap_high; 219 uint32 inode_table_high; 220 uint16 free_blocks_high; 221 uint16 free_inodes_high; 222 uint16 used_directories_high; 223 uint16 unused_inodes_high; 224 uint32 _reserved2[3]; 225 226 fsblock_t BlockBitmap(bool has64bits) const 227 { 228 uint64 block = B_LENDIAN_TO_HOST_INT32(block_bitmap); 229 if (has64bits) 230 block |= 231 ((uint64)B_LENDIAN_TO_HOST_INT32(block_bitmap_high) << 32); 232 return block; 233 } 234 fsblock_t InodeBitmap(bool has64bits) const 235 { 236 uint64 bitmap = B_LENDIAN_TO_HOST_INT32(inode_bitmap); 237 if (has64bits) 238 bitmap |= 239 ((uint64)B_LENDIAN_TO_HOST_INT32(inode_bitmap_high) << 32); 240 return bitmap; 241 } 242 uint64 InodeTable(bool has64bits) const 243 { 244 uint64 table = B_LENDIAN_TO_HOST_INT32(inode_table); 245 if (has64bits) 246 table |= ((uint64)B_LENDIAN_TO_HOST_INT32(inode_table_high) << 32); 247 return table; 248 } 249 uint32 FreeBlocks(bool has64bits) const 250 { 251 uint32 blocks = B_LENDIAN_TO_HOST_INT16(free_blocks); 252 if (has64bits) 253 blocks |= 254 ((uint32)B_LENDIAN_TO_HOST_INT16(free_blocks_high) << 16); 255 return blocks; 256 } 257 uint32 FreeInodes(bool has64bits) const 258 { 259 uint32 inodes = B_LENDIAN_TO_HOST_INT16(free_inodes); 260 if (has64bits) 261 inodes |= 262 ((uint32)B_LENDIAN_TO_HOST_INT16(free_inodes_high) << 16); 263 return inodes; 264 } 265 uint32 UsedDirectories(bool has64bits) const 266 { 267 uint32 dirs = B_LENDIAN_TO_HOST_INT16(used_directories); 268 if (has64bits) 269 dirs |= 270 ((uint32)B_LENDIAN_TO_HOST_INT16(used_directories_high) << 16); 271 return dirs; 272 } 273 uint16 Flags() const { return B_LENDIAN_TO_HOST_INT16(flags); } 274 uint32 UnusedInodes(bool has64bits) const 275 { 276 uint32 inodes = B_LENDIAN_TO_HOST_INT16(unused_inodes); 277 if (has64bits) 278 inodes |= 279 ((uint32)B_LENDIAN_TO_HOST_INT16(unused_inodes_high) << 16); 280 return inodes; 281 } 282 283 284 void SetFreeBlocks(uint32 freeBlocks, bool has64bits) 285 { 286 free_blocks = B_HOST_TO_LENDIAN_INT16(freeBlocks) & 0xffff; 287 if (has64bits) 288 free_blocks_high = B_HOST_TO_LENDIAN_INT16(freeBlocks >> 16); 289 } 290 291 void SetFreeInodes(uint32 freeInodes, bool has64bits) 292 { 293 free_inodes = B_HOST_TO_LENDIAN_INT16(freeInodes) & 0xffff; 294 if (has64bits) 295 free_inodes_high = B_HOST_TO_LENDIAN_INT16(freeInodes >> 16); 296 } 297 298 void SetUsedDirectories(uint16 usedDirectories, bool has64bits) 299 { 300 used_directories = B_HOST_TO_LENDIAN_INT16(usedDirectories& 0xffff); 301 if (has64bits) 302 used_directories_high = 303 B_HOST_TO_LENDIAN_INT16(usedDirectories >> 16); 304 } 305 306 void SetFlags(uint16 newFlags) 307 { 308 flags = B_HOST_TO_LENDIAN_INT16(newFlags); 309 } 310 311 void SetUnusedInodes(uint32 unusedInodes, bool has64bits) 312 { 313 unused_inodes = B_HOST_TO_LENDIAN_INT16(unusedInodes) & 0xffff; 314 if (has64bits) 315 unused_inodes_high = B_HOST_TO_LENDIAN_INT16(unusedInodes >> 16); 316 } 317 } _PACKED; 318 319 #define EXT2_DIRECT_BLOCKS 12 320 #define EXT2_ROOT_NODE 2 321 #define EXT2_SHORT_SYMLINK_LENGTH 60 322 323 struct ext2_data_stream { 324 uint32 direct[EXT2_DIRECT_BLOCKS]; 325 uint32 indirect; 326 uint32 double_indirect; 327 uint32 triple_indirect; 328 } _PACKED; 329 330 #define EXT2_EXTENT_MAGIC 0xf30a 331 #define EXT2_EXTENT_MAX_LENGTH 0x8000 332 333 struct ext2_extent_header { 334 uint16 magic; 335 uint16 num_entries; 336 uint16 max_entries; 337 uint16 depth; 338 uint32 generation; 339 bool IsValid() const 340 { 341 return B_LENDIAN_TO_HOST_INT16(magic) == EXT2_EXTENT_MAGIC; 342 } 343 uint16 NumEntries() const { return B_LENDIAN_TO_HOST_INT16(num_entries); } 344 uint16 MaxEntries() const { return B_LENDIAN_TO_HOST_INT16(max_entries); } 345 uint16 Depth() const { return B_LENDIAN_TO_HOST_INT16(depth); } 346 uint32 Generation() const { return B_LENDIAN_TO_HOST_INT32(generation); } 347 void SetNumEntries(uint16 num) 348 { num_entries = B_HOST_TO_LENDIAN_INT16(num); } 349 void SetMaxEntries(uint16 max) 350 { max_entries = B_HOST_TO_LENDIAN_INT16(max); } 351 void SetDepth(uint16 _depth) 352 { depth = B_HOST_TO_LENDIAN_INT16(_depth); } 353 void SetGeneration(uint32 _generation) 354 { generation = B_HOST_TO_LENDIAN_INT32(_generation); } 355 } _PACKED; 356 357 struct ext2_extent_index { 358 uint32 logical_block; 359 uint32 physical_block; 360 uint16 physical_block_high; 361 uint16 _reserved; 362 uint32 LogicalBlock() const 363 { return B_LENDIAN_TO_HOST_INT32(logical_block); } 364 uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block) 365 | ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); } 366 void SetLogicalBlock(uint32 block) { 367 logical_block = B_HOST_TO_LENDIAN_INT32(block); } 368 void SetPhysicalBlock(uint64 block) { 369 physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff); 370 physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); } 371 } _PACKED; 372 373 struct ext2_extent_entry { 374 uint32 logical_block; 375 uint16 length; 376 uint16 physical_block_high; 377 uint32 physical_block; 378 uint32 LogicalBlock() const 379 { return B_LENDIAN_TO_HOST_INT32(logical_block); } 380 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length) == 0x8000 381 ? 0x8000 : B_LENDIAN_TO_HOST_INT16(length) & 0x7fff; } 382 uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block) 383 | ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); } 384 void SetLogicalBlock(uint32 block) { 385 logical_block = B_HOST_TO_LENDIAN_INT32(block); } 386 void SetLength(uint16 _length) { 387 length = B_HOST_TO_LENDIAN_INT16(_length) & 0x7fff; } 388 void SetPhysicalBlock(uint64 block) { 389 physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff); 390 physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); } 391 } _PACKED; 392 393 struct ext2_extent_stream { 394 ext2_extent_header extent_header; 395 union { 396 ext2_extent_entry extent_entries[4]; 397 ext2_extent_index extent_index[4]; 398 }; 399 } _PACKED; 400 401 #define EXT2_INODE_NORMAL_SIZE 128 402 #define EXT2_INODE_MAX_LINKS 65000 403 404 struct ext2_inode { 405 uint16 mode; 406 uint16 uid; 407 uint32 size; 408 uint32 access_time; 409 uint32 change_time; 410 uint32 modification_time; 411 uint32 deletion_time; 412 uint16 gid; 413 uint16 num_links; 414 uint32 num_blocks; 415 uint32 flags; 416 uint32 version; 417 union { 418 ext2_data_stream stream; 419 char symlink[EXT2_SHORT_SYMLINK_LENGTH]; 420 ext2_extent_stream extent_stream; 421 }; 422 uint32 generation; 423 uint32 file_access_control; 424 union { 425 // for directories vs. files 426 uint32 directory_access_control; 427 uint32 size_high; 428 }; 429 uint32 fragment; 430 union { 431 struct { 432 uint8 fragment_number; 433 uint8 fragment_size; 434 }; 435 uint16 num_blocks_high; 436 }; 437 uint16 _padding; 438 uint16 uid_high; 439 uint16 gid_high; 440 uint32 _reserved2; 441 442 // extra attributes 443 uint16 extra_inode_size; 444 uint16 _padding2; 445 uint32 change_time_extra; 446 uint32 modification_time_extra; 447 uint32 access_time_extra; 448 uint32 creation_time; 449 uint32 creation_time_extra; 450 uint32 version_high; 451 452 uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } 453 uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); } 454 uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); } 455 uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); } 456 uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks) 457 | ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); } 458 459 static void _DecodeTime(struct timespec *timespec, uint32 time, 460 uint32 time_extra, bool extra) 461 { 462 timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time); 463 if (extra && sizeof(timespec->tv_sec) > 4) 464 timespec->tv_sec |= 465 (uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32; 466 if (extra) 467 timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2; 468 else 469 timespec->tv_nsec = 0; 470 } 471 472 void GetModificationTime(struct timespec *timespec, bool extra) const 473 { _DecodeTime(timespec, modification_time, modification_time_extra, 474 extra); } 475 void GetAccessTime(struct timespec *timespec, bool extra) const 476 { _DecodeTime(timespec, access_time, access_time_extra, extra); } 477 void GetChangeTime(struct timespec *timespec, bool extra) const 478 { _DecodeTime(timespec, change_time, change_time_extra, extra); } 479 void GetCreationTime(struct timespec *timespec, bool extra) const 480 { 481 if (extra) 482 _DecodeTime(timespec, creation_time, creation_time_extra, extra); 483 else { 484 timespec->tv_sec = 0; 485 timespec->tv_nsec = 0; 486 } 487 } 488 time_t DeletionTime() const 489 { return B_LENDIAN_TO_HOST_INT32(deletion_time); } 490 491 static uint32 _EncodeTime(const struct timespec *timespec) 492 { 493 uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc; 494 if (sizeof(timespec->tv_sec) > 4) 495 time |= (uint64)timespec->tv_sec >> 32; 496 return B_HOST_TO_LENDIAN_INT32(time); 497 } 498 499 void SetModificationTime(const struct timespec *timespec, bool extra) 500 { 501 modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 502 if (extra) 503 modification_time_extra = _EncodeTime(timespec); 504 } 505 void SetAccessTime(const struct timespec *timespec, bool extra) 506 { 507 access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 508 if (extra) 509 access_time_extra = _EncodeTime(timespec); 510 } 511 void SetChangeTime(const struct timespec *timespec, bool extra) 512 { 513 change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 514 if (extra) 515 change_time_extra = _EncodeTime(timespec); 516 } 517 void SetCreationTime(const struct timespec *timespec, bool extra) 518 { 519 if (extra) { 520 creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 521 creation_time_extra = 522 B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec); 523 } 524 } 525 void SetDeletionTime(time_t deletionTime) 526 { 527 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime); 528 } 529 530 ino_t NextOrphan() const { return (ino_t)DeletionTime(); } 531 532 off_t Size() const 533 { 534 if (S_ISREG(Mode())) { 535 return B_LENDIAN_TO_HOST_INT32(size) 536 | ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32); 537 } 538 539 return B_LENDIAN_TO_HOST_INT32(size); 540 } 541 542 uint32 ExtendedAttributesBlock() const 543 { return B_LENDIAN_TO_HOST_INT32(file_access_control);} 544 545 uint16 ExtraInodeSize() const 546 { return B_LENDIAN_TO_HOST_INT16(extra_inode_size); } 547 548 uint32 UserID() const 549 { 550 return B_LENDIAN_TO_HOST_INT16(uid) 551 | (B_LENDIAN_TO_HOST_INT16(uid_high) << 16); 552 } 553 554 uint32 GroupID() const 555 { 556 return B_LENDIAN_TO_HOST_INT16(gid) 557 | (B_LENDIAN_TO_HOST_INT16(gid_high) << 16); 558 } 559 560 void SetMode(uint16 newMode) 561 { 562 mode = B_LENDIAN_TO_HOST_INT16(newMode); 563 } 564 565 void UpdateMode(uint16 newMode, uint16 mask) 566 { 567 SetMode((Mode() & ~mask) | (newMode & mask)); 568 } 569 570 void ClearFlag(uint32 mask) 571 { 572 flags &= ~B_HOST_TO_LENDIAN_INT32(mask); 573 } 574 575 void SetFlag(uint32 mask) 576 { 577 flags |= B_HOST_TO_LENDIAN_INT32(mask); 578 } 579 580 void SetFlags(uint32 newFlags) 581 { 582 flags = B_HOST_TO_LENDIAN_INT32(newFlags); 583 } 584 585 void SetNumLinks(uint16 numLinks) 586 { 587 num_links = B_HOST_TO_LENDIAN_INT16(numLinks); 588 } 589 590 void SetNumBlocks(uint32 numBlocks) 591 { 592 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks); 593 } 594 595 void SetNumBlocks64(uint64 numBlocks) 596 { 597 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff); 598 num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32); 599 } 600 601 void SetNextOrphan(ino_t id) 602 { 603 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id); 604 } 605 606 void SetSize(off_t newSize) 607 { 608 size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF); 609 if (S_ISREG(Mode())) 610 size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32); 611 } 612 613 void SetUserID(uint32 newUID) 614 { 615 uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF); 616 uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16); 617 } 618 619 void SetGroupID(uint32 newGID) 620 { 621 gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF); 622 gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16); 623 } 624 625 void SetExtendedAttributesBlock(uint32 block) 626 { 627 file_access_control = B_HOST_TO_LENDIAN_INT32(block); 628 } 629 630 void SetExtraInodeSize(uint16 newSize) 631 { 632 extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize); 633 } 634 } _PACKED; 635 636 #define EXT2_SUPER_BLOCK_MAGIC 0xef53 637 638 // flags 639 #define EXT2_INODE_SECURE_DELETION 0x00000001 640 #define EXT2_INODE_UNDELETE 0x00000002 641 #define EXT2_INODE_COMPRESSED 0x00000004 642 #define EXT2_INODE_SYNCHRONOUS 0x00000008 643 #define EXT2_INODE_IMMUTABLE 0x00000010 644 #define EXT2_INODE_APPEND_ONLY 0x00000020 645 #define EXT2_INODE_NO_DUMP 0x00000040 646 #define EXT2_INODE_NO_ACCESS_TIME 0x00000080 647 #define EXT2_INODE_DIRTY 0x00000100 648 #define EXT2_INODE_COMPRESSED_BLOCKS 0x00000200 649 #define EXT2_INODE_DO_NOT_COMPRESS 0x00000400 650 #define EXT2_INODE_COMPRESSION_ERROR 0x00000800 651 #define EXT2_INODE_BTREE 0x00001000 652 #define EXT2_INODE_INDEXED 0x00001000 653 #define EXT2_INODE_JOURNAL_DATA 0x00004000 654 #define EXT2_INODE_NO_MERGE_TAIL 0x00008000 655 #define EXT2_INODE_DIR_SYNCH 0x00010000 656 #define EXT2_INODE_HUGE_FILE 0x00040000 657 #define EXT2_INODE_EXTENTS 0x00080000 658 #define EXT2_INODE_LARGE_EA 0x00200000 659 #define EXT2_INODE_EOF_BLOCKS 0x00400000 660 #define EXT2_INODE_INLINE_DATA 0x10000000 661 #define EXT2_INODE_RESERVED 0x80000000 662 663 #define EXT2_INODE_INHERITED (EXT2_INODE_SECURE_DELETION | EXT2_INODE_UNDELETE \ 664 | EXT2_INODE_COMPRESSED | EXT2_INODE_SYNCHRONOUS | EXT2_INODE_IMMUTABLE \ 665 | EXT2_INODE_APPEND_ONLY | EXT2_INODE_NO_DUMP | EXT2_INODE_NO_ACCESS_TIME \ 666 | EXT2_INODE_DO_NOT_COMPRESS | EXT2_INODE_JOURNAL_DATA \ 667 | EXT2_INODE_NO_MERGE_TAIL | EXT2_INODE_DIR_SYNCH) 668 669 #define EXT2_NAME_LENGTH 255 670 671 struct ext2_dir_entry { 672 uint32 inode_id; 673 uint16 length; 674 uint8 name_length; 675 uint8 file_type; 676 char name[EXT2_NAME_LENGTH]; 677 678 uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); } 679 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); } 680 uint8 NameLength() const { return name_length; } 681 uint8 FileType() const { return file_type; } 682 683 void SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); } 684 685 void SetLength(uint16 newLength/*uint8 nameLength*/) 686 { 687 length = B_HOST_TO_LENDIAN_INT16(newLength); 688 /*name_length = nameLength; 689 690 if (nameLength % 4 == 0) { 691 length = B_HOST_TO_LENDIAN_INT16( 692 (short)(nameLength + MinimumSize())); 693 } else { 694 length = B_HOST_TO_LENDIAN_INT16( 695 (short)(nameLength % 4 + 1 + MinimumSize())); 696 }*/ 697 } 698 699 bool IsValid() const 700 { 701 return Length() > MinimumSize(); 702 // There is no maximum size, as the last entry spans until the 703 // end of the block 704 } 705 706 static size_t MinimumSize() 707 { 708 return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH; 709 } 710 } _PACKED; 711 712 // file types 713 #define EXT2_TYPE_UNKNOWN 0 714 #define EXT2_TYPE_FILE 1 715 #define EXT2_TYPE_DIRECTORY 2 716 #define EXT2_TYPE_CHAR_DEVICE 3 717 #define EXT2_TYPE_BLOCK_DEVICE 4 718 #define EXT2_TYPE_FIFO 5 719 #define EXT2_TYPE_SOCKET 6 720 #define EXT2_TYPE_SYMLINK 7 721 722 #define EXT2_XATTR_MAGIC 0xea020000 723 #define EXT2_XATTR_ROUND ((1 << 2) - 1) 724 #define EXT2_XATTR_NAME_LENGTH 255 725 726 #define EXT2_XATTR_INDEX_USER 1 727 728 struct ext2_xattr_header { 729 uint32 magic; 730 uint32 refcount; 731 uint32 blocks; // must be 1 for ext2 732 uint32 hash; 733 uint32 reserved[4]; // zero 734 735 bool IsValid() const 736 { 737 return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC 738 && B_LENDIAN_TO_HOST_INT32(blocks) == 1 739 && refcount <= 1024; 740 } 741 742 void Dump() const { 743 for (unsigned int i = 0; i < Length(); i++) 744 dprintf("%02x ", ((uint8 *)this)[i]); 745 dprintf("\n"); 746 } 747 748 static size_t Length() 749 { 750 return sizeof(ext2_xattr_header); 751 } 752 }; 753 754 struct ext2_xattr_entry { 755 uint8 name_length; 756 uint8 name_index; 757 uint16 value_offset; 758 uint32 value_block; // must be zero for ext2 759 uint32 value_size; 760 uint32 hash; 761 char name[EXT2_XATTR_NAME_LENGTH]; 762 763 uint8 NameLength() const { return name_length; } 764 uint8 NameIndex() const { return name_index; } 765 uint16 ValueOffset() const { return 766 B_LENDIAN_TO_HOST_INT16(value_offset); } 767 uint32 ValueSize() const { return 768 B_LENDIAN_TO_HOST_INT32(value_size); } 769 770 // padded sizes 771 uint32 Length() const { return (MinimumSize() + NameLength() 772 + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; } 773 774 bool IsValid() const 775 { 776 return NameLength() > 0 && value_block == 0; 777 // There is no maximum size, as the last entry spans until the 778 // end of the block 779 } 780 781 void Dump(bool full=false) const { 782 for (unsigned int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++) 783 dprintf("%02x ", ((uint8 *)this)[i]); 784 dprintf("\n"); 785 } 786 787 static size_t MinimumSize() 788 { 789 return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH; 790 } 791 } _PACKED; 792 793 794 struct file_cookie { 795 bigtime_t last_notification; 796 off_t last_size; 797 int open_mode; 798 }; 799 800 801 #define EXT2_OPEN_MODE_USER_MASK 0x7fffffff 802 803 #define INODE_NOTIFICATION_INTERVAL 10000000LL 804 805 806 extern fs_volume_ops gExt2VolumeOps; 807 extern fs_vnode_ops gExt2VnodeOps; 808 809 #endif // EXT2_H 810