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