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 198 // block group flags 199 #define EXT2_BLOCK_GROUP_INODE_UNINIT 0x1 200 #define EXT2_BLOCK_GROUP_BLOCK_UNINIT 0x2 201 202 203 struct ext2_block_group { 204 uint32 block_bitmap; 205 uint32 inode_bitmap; 206 uint32 inode_table; 207 uint16 free_blocks; 208 uint16 free_inodes; 209 uint16 used_directories; 210 uint16 flags; 211 uint32 _reserved[2]; 212 uint16 unused_inodes; 213 uint16 checksum; 214 215 // ext4 216 uint32 block_bitmap_high; 217 uint32 inode_bitmap_high; 218 uint32 inode_table_high; 219 uint16 free_blocks_high; 220 uint16 free_inodes_high; 221 uint16 used_directories_high; 222 uint16 unused_inodes_high; 223 uint32 _reserved2[3]; 224 225 fsblock_t BlockBitmap(bool has64bits) const 226 { 227 uint64 block = B_LENDIAN_TO_HOST_INT32(block_bitmap); 228 if (has64bits) 229 block |= 230 ((uint64)B_LENDIAN_TO_HOST_INT32(block_bitmap_high) << 32); 231 return block; 232 } 233 fsblock_t InodeBitmap(bool has64bits) const 234 { 235 uint64 bitmap = B_LENDIAN_TO_HOST_INT32(inode_bitmap); 236 if (has64bits) 237 bitmap |= 238 ((uint64)B_LENDIAN_TO_HOST_INT32(inode_bitmap_high) << 32); 239 return bitmap; 240 } 241 uint64 InodeTable(bool has64bits) const 242 { 243 uint64 table = B_LENDIAN_TO_HOST_INT32(inode_table); 244 if (has64bits) 245 table |= ((uint64)B_LENDIAN_TO_HOST_INT32(inode_table_high) << 32); 246 return table; 247 } 248 uint32 FreeBlocks(bool has64bits) const 249 { 250 uint32 blocks = B_LENDIAN_TO_HOST_INT16(free_blocks); 251 if (has64bits) 252 blocks |= 253 ((uint32)B_LENDIAN_TO_HOST_INT16(free_blocks_high) << 16); 254 return blocks; 255 } 256 uint32 FreeInodes(bool has64bits) const 257 { 258 uint32 inodes = B_LENDIAN_TO_HOST_INT16(free_inodes); 259 if (has64bits) 260 inodes |= 261 ((uint32)B_LENDIAN_TO_HOST_INT16(free_inodes_high) << 16); 262 return inodes; 263 } 264 uint32 UsedDirectories(bool has64bits) const 265 { 266 uint32 dirs = B_LENDIAN_TO_HOST_INT16(used_directories); 267 if (has64bits) 268 dirs |= 269 ((uint32)B_LENDIAN_TO_HOST_INT16(used_directories_high) << 16); 270 return dirs; 271 } 272 uint16 Flags() const { return B_LENDIAN_TO_HOST_INT16(flags); } 273 uint32 UnusedInodes(bool has64bits) const 274 { 275 uint32 inodes = B_LENDIAN_TO_HOST_INT16(unused_inodes); 276 if (has64bits) 277 inodes |= 278 ((uint32)B_LENDIAN_TO_HOST_INT16(unused_inodes_high) << 16); 279 return inodes; 280 } 281 282 283 void SetFreeBlocks(uint32 freeBlocks, bool has64bits) 284 { 285 free_blocks = B_HOST_TO_LENDIAN_INT16(freeBlocks) & 0xffff; 286 if (has64bits) 287 free_blocks_high = B_HOST_TO_LENDIAN_INT16(freeBlocks >> 16); 288 } 289 290 void SetFreeInodes(uint32 freeInodes, bool has64bits) 291 { 292 free_inodes = B_HOST_TO_LENDIAN_INT16(freeInodes) & 0xffff; 293 if (has64bits) 294 free_inodes_high = B_HOST_TO_LENDIAN_INT16(freeInodes >> 16); 295 } 296 297 void SetUsedDirectories(uint16 usedDirectories, bool has64bits) 298 { 299 used_directories = B_HOST_TO_LENDIAN_INT16(usedDirectories& 0xffff); 300 if (has64bits) 301 used_directories_high = 302 B_HOST_TO_LENDIAN_INT16(usedDirectories >> 16); 303 } 304 305 void SetFlags(uint16 newFlags) 306 { 307 flags = B_HOST_TO_LENDIAN_INT16(newFlags); 308 } 309 310 void SetUnusedInodes(uint32 unusedInodes, bool has64bits) 311 { 312 unused_inodes = B_HOST_TO_LENDIAN_INT16(unusedInodes) & 0xffff; 313 if (has64bits) 314 unused_inodes_high = B_HOST_TO_LENDIAN_INT16(unusedInodes >> 16); 315 } 316 } _PACKED; 317 318 #define EXT2_DIRECT_BLOCKS 12 319 #define EXT2_ROOT_NODE 2 320 #define EXT2_SHORT_SYMLINK_LENGTH 60 321 322 struct ext2_data_stream { 323 uint32 direct[EXT2_DIRECT_BLOCKS]; 324 uint32 indirect; 325 uint32 double_indirect; 326 uint32 triple_indirect; 327 } _PACKED; 328 329 #define EXT2_EXTENT_MAGIC 0xf30a 330 #define EXT2_EXTENT_MAX_LENGTH 0x8000 331 332 struct ext2_extent_header { 333 uint16 magic; 334 uint16 num_entries; 335 uint16 max_entries; 336 uint16 depth; 337 uint32 generation; 338 bool IsValid() const 339 { 340 return B_LENDIAN_TO_HOST_INT16(magic) == EXT2_EXTENT_MAGIC; 341 } 342 uint16 NumEntries() const { return B_LENDIAN_TO_HOST_INT16(num_entries); } 343 uint16 MaxEntries() const { return B_LENDIAN_TO_HOST_INT16(max_entries); } 344 uint16 Depth() const { return B_LENDIAN_TO_HOST_INT16(depth); } 345 uint32 Generation() const { return B_LENDIAN_TO_HOST_INT32(generation); } 346 void SetNumEntries(uint16 num) 347 { num_entries = B_HOST_TO_LENDIAN_INT16(num); } 348 void SetMaxEntries(uint16 max) 349 { max_entries = B_HOST_TO_LENDIAN_INT16(max); } 350 void SetDepth(uint16 _depth) 351 { depth = B_HOST_TO_LENDIAN_INT16(_depth); } 352 void SetGeneration(uint32 _generation) 353 { generation = B_HOST_TO_LENDIAN_INT32(_generation); } 354 } _PACKED; 355 356 struct ext2_extent_index { 357 uint32 logical_block; 358 uint32 physical_block; 359 uint16 physical_block_high; 360 uint16 _reserved; 361 uint32 LogicalBlock() const 362 { return B_LENDIAN_TO_HOST_INT32(logical_block); } 363 uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block) 364 | ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); } 365 void SetLogicalBlock(uint32 block) { 366 logical_block = B_HOST_TO_LENDIAN_INT32(block); } 367 void SetPhysicalBlock(uint64 block) { 368 physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff); 369 physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); } 370 } _PACKED; 371 372 struct ext2_extent_entry { 373 uint32 logical_block; 374 uint16 length; 375 uint16 physical_block_high; 376 uint32 physical_block; 377 uint32 LogicalBlock() const 378 { return B_LENDIAN_TO_HOST_INT32(logical_block); } 379 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length) == 0x8000 380 ? 0x8000 : B_LENDIAN_TO_HOST_INT16(length) & 0x7fff; } 381 uint64 PhysicalBlock() const { return B_LENDIAN_TO_HOST_INT32(physical_block) 382 | ((uint64)B_LENDIAN_TO_HOST_INT16(physical_block_high) << 32); } 383 void SetLogicalBlock(uint32 block) { 384 logical_block = B_HOST_TO_LENDIAN_INT32(block); } 385 void SetLength(uint16 _length) { 386 length = B_HOST_TO_LENDIAN_INT16(_length) & 0x7fff; } 387 void SetPhysicalBlock(uint64 block) { 388 physical_block = B_HOST_TO_LENDIAN_INT32(block & 0xffffffff); 389 physical_block_high = B_HOST_TO_LENDIAN_INT16((block >> 32) & 0xffff); } 390 } _PACKED; 391 392 struct ext2_extent_stream { 393 ext2_extent_header extent_header; 394 union { 395 ext2_extent_entry extent_entries[4]; 396 ext2_extent_index extent_index[4]; 397 }; 398 } _PACKED; 399 400 #define EXT2_INODE_NORMAL_SIZE 128 401 #define EXT2_INODE_MAX_LINKS 65000 402 403 struct ext2_inode { 404 uint16 mode; 405 uint16 uid; 406 uint32 size; 407 uint32 access_time; 408 uint32 change_time; 409 uint32 modification_time; 410 uint32 deletion_time; 411 uint16 gid; 412 uint16 num_links; 413 uint32 num_blocks; 414 uint32 flags; 415 uint32 version; 416 union { 417 ext2_data_stream stream; 418 char symlink[EXT2_SHORT_SYMLINK_LENGTH]; 419 ext2_extent_stream extent_stream; 420 }; 421 uint32 generation; 422 uint32 file_access_control; 423 union { 424 // for directories vs. files 425 uint32 directory_access_control; 426 uint32 size_high; 427 }; 428 uint32 fragment; 429 union { 430 struct { 431 uint8 fragment_number; 432 uint8 fragment_size; 433 }; 434 uint16 num_blocks_high; 435 }; 436 uint16 _padding; 437 uint16 uid_high; 438 uint16 gid_high; 439 uint32 _reserved2; 440 441 // extra attributes 442 uint16 extra_inode_size; 443 uint16 _padding2; 444 uint32 change_time_extra; 445 uint32 modification_time_extra; 446 uint32 access_time_extra; 447 uint32 creation_time; 448 uint32 creation_time_extra; 449 uint32 version_high; 450 451 uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } 452 uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); } 453 uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); } 454 uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); } 455 uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks) 456 | ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); } 457 458 static void _DecodeTime(struct timespec *timespec, uint32 time, 459 uint32 time_extra, bool extra) 460 { 461 timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time); 462 if (extra && sizeof(timespec->tv_sec) > 4) 463 timespec->tv_sec |= 464 (uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32; 465 if (extra) 466 timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2; 467 else 468 timespec->tv_nsec = 0; 469 } 470 471 void GetModificationTime(struct timespec *timespec, bool extra) const 472 { _DecodeTime(timespec, modification_time, modification_time_extra, 473 extra); } 474 void GetAccessTime(struct timespec *timespec, bool extra) const 475 { _DecodeTime(timespec, access_time, access_time_extra, extra); } 476 void GetChangeTime(struct timespec *timespec, bool extra) const 477 { _DecodeTime(timespec, change_time, change_time_extra, extra); } 478 void GetCreationTime(struct timespec *timespec, bool extra) const 479 { 480 if (extra) 481 _DecodeTime(timespec, creation_time, creation_time_extra, extra); 482 else { 483 timespec->tv_sec = 0; 484 timespec->tv_nsec = 0; 485 } 486 } 487 time_t DeletionTime() const 488 { return B_LENDIAN_TO_HOST_INT32(deletion_time); } 489 490 static uint32 _EncodeTime(const struct timespec *timespec) 491 { 492 uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc; 493 if (sizeof(timespec->tv_sec) > 4) 494 time |= (uint64)timespec->tv_sec >> 32; 495 return B_HOST_TO_LENDIAN_INT32(time); 496 } 497 498 void SetModificationTime(const struct timespec *timespec, bool extra) 499 { 500 modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 501 if (extra) 502 modification_time_extra = _EncodeTime(timespec); 503 } 504 void SetAccessTime(const struct timespec *timespec, bool extra) 505 { 506 access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 507 if (extra) 508 access_time_extra = _EncodeTime(timespec); 509 } 510 void SetChangeTime(const struct timespec *timespec, bool extra) 511 { 512 change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 513 if (extra) 514 change_time_extra = _EncodeTime(timespec); 515 } 516 void SetCreationTime(const struct timespec *timespec, bool extra) 517 { 518 if (extra) { 519 creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 520 creation_time_extra = 521 B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec); 522 } 523 } 524 void SetDeletionTime(time_t deletionTime) 525 { 526 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime); 527 } 528 529 ino_t NextOrphan() const { return (ino_t)DeletionTime(); } 530 531 off_t Size() const 532 { 533 if (S_ISREG(Mode())) { 534 return B_LENDIAN_TO_HOST_INT32(size) 535 | ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32); 536 } 537 538 return B_LENDIAN_TO_HOST_INT32(size); 539 } 540 541 uint32 ExtendedAttributesBlock() const 542 { return B_LENDIAN_TO_HOST_INT32(file_access_control);} 543 544 uint16 ExtraInodeSize() const 545 { return B_LENDIAN_TO_HOST_INT16(extra_inode_size); } 546 547 uint32 UserID() const 548 { 549 return B_LENDIAN_TO_HOST_INT16(uid) 550 | (B_LENDIAN_TO_HOST_INT16(uid_high) << 16); 551 } 552 553 uint32 GroupID() const 554 { 555 return B_LENDIAN_TO_HOST_INT16(gid) 556 | (B_LENDIAN_TO_HOST_INT16(gid_high) << 16); 557 } 558 559 void SetMode(uint16 newMode) 560 { 561 mode = B_LENDIAN_TO_HOST_INT16(newMode); 562 } 563 564 void UpdateMode(uint16 newMode, uint16 mask) 565 { 566 SetMode((Mode() & ~mask) | (newMode & mask)); 567 } 568 569 void ClearFlag(uint32 mask) 570 { 571 flags &= ~B_HOST_TO_LENDIAN_INT32(mask); 572 } 573 574 void SetFlag(uint32 mask) 575 { 576 flags |= B_HOST_TO_LENDIAN_INT32(mask); 577 } 578 579 void SetFlags(uint32 newFlags) 580 { 581 flags = B_HOST_TO_LENDIAN_INT32(newFlags); 582 } 583 584 void SetNumLinks(uint16 numLinks) 585 { 586 num_links = B_HOST_TO_LENDIAN_INT16(numLinks); 587 } 588 589 void SetNumBlocks(uint32 numBlocks) 590 { 591 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks); 592 } 593 594 void SetNumBlocks64(uint64 numBlocks) 595 { 596 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff); 597 num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32); 598 } 599 600 void SetNextOrphan(ino_t id) 601 { 602 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id); 603 } 604 605 void SetSize(off_t newSize) 606 { 607 size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF); 608 if (S_ISREG(Mode())) 609 size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32); 610 } 611 612 void SetUserID(uint32 newUID) 613 { 614 uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF); 615 uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16); 616 } 617 618 void SetGroupID(uint32 newGID) 619 { 620 gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF); 621 gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16); 622 } 623 624 void SetExtendedAttributesBlock(uint32 block) 625 { 626 file_access_control = B_HOST_TO_LENDIAN_INT32(block); 627 } 628 629 void SetExtraInodeSize(uint16 newSize) 630 { 631 extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize); 632 } 633 } _PACKED; 634 635 #define EXT2_SUPER_BLOCK_MAGIC 0xef53 636 637 // flags 638 #define EXT2_INODE_SECURE_DELETION 0x00000001 639 #define EXT2_INODE_UNDELETE 0x00000002 640 #define EXT2_INODE_COMPRESSED 0x00000004 641 #define EXT2_INODE_SYNCHRONOUS 0x00000008 642 #define EXT2_INODE_IMMUTABLE 0x00000010 643 #define EXT2_INODE_APPEND_ONLY 0x00000020 644 #define EXT2_INODE_NO_DUMP 0x00000040 645 #define EXT2_INODE_NO_ACCESS_TIME 0x00000080 646 #define EXT2_INODE_DIRTY 0x00000100 647 #define EXT2_INODE_COMPRESSED_BLOCKS 0x00000200 648 #define EXT2_INODE_DO_NOT_COMPRESS 0x00000400 649 #define EXT2_INODE_COMPRESSION_ERROR 0x00000800 650 #define EXT2_INODE_BTREE 0x00001000 651 #define EXT2_INODE_INDEXED 0x00001000 652 #define EXT2_INODE_JOURNAL_DATA 0x00004000 653 #define EXT2_INODE_NO_MERGE_TAIL 0x00008000 654 #define EXT2_INODE_DIR_SYNCH 0x00010000 655 #define EXT2_INODE_HUGE_FILE 0x00040000 656 #define EXT2_INODE_EXTENTS 0x00080000 657 #define EXT2_INODE_LARGE_EA 0x00200000 658 #define EXT2_INODE_EOF_BLOCKS 0x00400000 659 #define EXT2_INODE_INLINE_DATA 0x10000000 660 #define EXT2_INODE_RESERVED 0x80000000 661 662 #define EXT2_INODE_INHERITED (EXT2_INODE_SECURE_DELETION | EXT2_INODE_UNDELETE \ 663 | EXT2_INODE_COMPRESSED | EXT2_INODE_SYNCHRONOUS | EXT2_INODE_IMMUTABLE \ 664 | EXT2_INODE_APPEND_ONLY | EXT2_INODE_NO_DUMP | EXT2_INODE_NO_ACCESS_TIME \ 665 | EXT2_INODE_DO_NOT_COMPRESS | EXT2_INODE_JOURNAL_DATA \ 666 | EXT2_INODE_NO_MERGE_TAIL | EXT2_INODE_DIR_SYNCH) 667 668 #define EXT2_NAME_LENGTH 255 669 670 struct ext2_dir_entry { 671 uint32 inode_id; 672 uint16 length; 673 uint8 name_length; 674 uint8 file_type; 675 char name[EXT2_NAME_LENGTH]; 676 677 uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); } 678 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); } 679 uint8 NameLength() const { return name_length; } 680 uint8 FileType() const { return file_type; } 681 682 void SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); } 683 684 void SetLength(uint16 newLength/*uint8 nameLength*/) 685 { 686 length = B_HOST_TO_LENDIAN_INT16(newLength); 687 /*name_length = nameLength; 688 689 if (nameLength % 4 == 0) { 690 length = B_HOST_TO_LENDIAN_INT16( 691 (short)(nameLength + MinimumSize())); 692 } else { 693 length = B_HOST_TO_LENDIAN_INT16( 694 (short)(nameLength % 4 + 1 + MinimumSize())); 695 }*/ 696 } 697 698 bool IsValid() const 699 { 700 return Length() > MinimumSize(); 701 // There is no maximum size, as the last entry spans until the 702 // end of the block 703 } 704 705 static size_t MinimumSize() 706 { 707 return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH; 708 } 709 } _PACKED; 710 711 // file types 712 #define EXT2_TYPE_UNKNOWN 0 713 #define EXT2_TYPE_FILE 1 714 #define EXT2_TYPE_DIRECTORY 2 715 #define EXT2_TYPE_CHAR_DEVICE 3 716 #define EXT2_TYPE_BLOCK_DEVICE 4 717 #define EXT2_TYPE_FIFO 5 718 #define EXT2_TYPE_SOCKET 6 719 #define EXT2_TYPE_SYMLINK 7 720 721 #define EXT2_XATTR_MAGIC 0xea020000 722 #define EXT2_XATTR_ROUND ((1 << 2) - 1) 723 #define EXT2_XATTR_NAME_LENGTH 255 724 725 #define EXT2_XATTR_INDEX_USER 1 726 727 struct ext2_xattr_header { 728 uint32 magic; 729 uint32 refcount; 730 uint32 blocks; // must be 1 for ext2 731 uint32 hash; 732 uint32 reserved[4]; // zero 733 734 bool IsValid() const 735 { 736 return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC 737 && B_LENDIAN_TO_HOST_INT32(blocks) == 1 738 && refcount <= 1024; 739 } 740 741 void Dump() const { 742 for (unsigned int i = 0; i < Length(); i++) 743 dprintf("%02x ", ((uint8 *)this)[i]); 744 dprintf("\n"); 745 } 746 747 static size_t Length() 748 { 749 return sizeof(ext2_xattr_header); 750 } 751 }; 752 753 struct ext2_xattr_entry { 754 uint8 name_length; 755 uint8 name_index; 756 uint16 value_offset; 757 uint32 value_block; // must be zero for ext2 758 uint32 value_size; 759 uint32 hash; 760 char name[EXT2_XATTR_NAME_LENGTH]; 761 762 uint8 NameLength() const { return name_length; } 763 uint8 NameIndex() const { return name_index; } 764 uint16 ValueOffset() const { return 765 B_LENDIAN_TO_HOST_INT16(value_offset); } 766 uint32 ValueSize() const { return 767 B_LENDIAN_TO_HOST_INT32(value_size); } 768 769 // padded sizes 770 uint32 Length() const { return (MinimumSize() + NameLength() 771 + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; } 772 773 bool IsValid() const 774 { 775 return NameLength() > 0 && value_block == 0; 776 // There is no maximum size, as the last entry spans until the 777 // end of the block 778 } 779 780 void Dump(bool full=false) const { 781 for (unsigned int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++) 782 dprintf("%02x ", ((uint8 *)this)[i]); 783 dprintf("\n"); 784 } 785 786 static size_t MinimumSize() 787 { 788 return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH; 789 } 790 } _PACKED; 791 792 793 struct file_cookie { 794 bigtime_t last_notification; 795 off_t last_size; 796 int open_mode; 797 }; 798 799 800 #define EXT2_OPEN_MODE_USER_MASK 0x7fffffff 801 802 #define INODE_NOTIFICATION_INTERVAL 10000000LL 803 804 805 extern fs_volume_ops gExt2VolumeOps; 806 extern fs_vnode_ops gExt2VnodeOps; 807 808 #endif // EXT2_H 809