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