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 487 uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } 488 uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); } 489 uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); } 490 uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); } 491 uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks) 492 | ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); } 493 494 static void _DecodeTime(struct timespec *timespec, uint32 time, 495 uint32 time_extra, bool extra) 496 { 497 timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time); 498 if (extra && sizeof(timespec->tv_sec) > 4) 499 timespec->tv_sec |= 500 (uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32; 501 if (extra) 502 timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2; 503 else 504 timespec->tv_nsec = 0; 505 } 506 507 void GetModificationTime(struct timespec *timespec, bool extra) const 508 { _DecodeTime(timespec, modification_time, modification_time_extra, 509 extra); } 510 void GetAccessTime(struct timespec *timespec, bool extra) const 511 { _DecodeTime(timespec, access_time, access_time_extra, extra); } 512 void GetChangeTime(struct timespec *timespec, bool extra) const 513 { _DecodeTime(timespec, change_time, change_time_extra, extra); } 514 void GetCreationTime(struct timespec *timespec, bool extra) const 515 { 516 if (extra) 517 _DecodeTime(timespec, creation_time, creation_time_extra, extra); 518 else { 519 timespec->tv_sec = 0; 520 timespec->tv_nsec = 0; 521 } 522 } 523 time_t DeletionTime() const 524 { return B_LENDIAN_TO_HOST_INT32(deletion_time); } 525 526 static uint32 _EncodeTime(const struct timespec *timespec) 527 { 528 uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc; 529 if (sizeof(timespec->tv_sec) > 4) 530 time |= (uint64)timespec->tv_sec >> 32; 531 return B_HOST_TO_LENDIAN_INT32(time); 532 } 533 534 void SetModificationTime(const struct timespec *timespec, bool extra) 535 { 536 modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 537 if (extra) 538 modification_time_extra = _EncodeTime(timespec); 539 } 540 void SetAccessTime(const struct timespec *timespec, bool extra) 541 { 542 access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 543 if (extra) 544 access_time_extra = _EncodeTime(timespec); 545 } 546 void SetChangeTime(const struct timespec *timespec, bool extra) 547 { 548 change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 549 if (extra) 550 change_time_extra = _EncodeTime(timespec); 551 } 552 void SetCreationTime(const struct timespec *timespec, bool extra) 553 { 554 if (extra) { 555 creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 556 creation_time_extra = 557 B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec); 558 } 559 } 560 void SetDeletionTime(time_t deletionTime) 561 { 562 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime); 563 } 564 565 ino_t NextOrphan() const { return (ino_t)DeletionTime(); } 566 567 off_t Size() const 568 { 569 if (S_ISREG(Mode())) { 570 return B_LENDIAN_TO_HOST_INT32(size) 571 | ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32); 572 } 573 574 return B_LENDIAN_TO_HOST_INT32(size); 575 } 576 577 uint32 ExtendedAttributesBlock() const 578 { return B_LENDIAN_TO_HOST_INT32(file_access_control);} 579 580 uint16 ExtraInodeSize() const 581 { return B_LENDIAN_TO_HOST_INT16(extra_inode_size); } 582 583 uint32 UserID() const 584 { 585 return B_LENDIAN_TO_HOST_INT16(uid) 586 | (B_LENDIAN_TO_HOST_INT16(uid_high) << 16); 587 } 588 589 uint32 GroupID() const 590 { 591 return B_LENDIAN_TO_HOST_INT16(gid) 592 | (B_LENDIAN_TO_HOST_INT16(gid_high) << 16); 593 } 594 595 void SetMode(uint16 newMode) 596 { 597 mode = B_LENDIAN_TO_HOST_INT16(newMode); 598 } 599 600 void UpdateMode(uint16 newMode, uint16 mask) 601 { 602 SetMode((Mode() & ~mask) | (newMode & mask)); 603 } 604 605 void ClearFlag(uint32 mask) 606 { 607 flags &= ~B_HOST_TO_LENDIAN_INT32(mask); 608 } 609 610 void SetFlag(uint32 mask) 611 { 612 flags |= B_HOST_TO_LENDIAN_INT32(mask); 613 } 614 615 void SetFlags(uint32 newFlags) 616 { 617 flags = B_HOST_TO_LENDIAN_INT32(newFlags); 618 } 619 620 void SetNumLinks(uint16 numLinks) 621 { 622 num_links = B_HOST_TO_LENDIAN_INT16(numLinks); 623 } 624 625 void SetNumBlocks(uint32 numBlocks) 626 { 627 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks); 628 } 629 630 void SetNumBlocks64(uint64 numBlocks) 631 { 632 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff); 633 num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32); 634 } 635 636 void SetNextOrphan(ino_t id) 637 { 638 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id); 639 } 640 641 void SetSize(off_t newSize) 642 { 643 size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF); 644 if (S_ISREG(Mode())) 645 size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32); 646 } 647 648 void SetUserID(uint32 newUID) 649 { 650 uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF); 651 uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16); 652 } 653 654 void SetGroupID(uint32 newGID) 655 { 656 gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF); 657 gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16); 658 } 659 660 void SetExtendedAttributesBlock(uint32 block) 661 { 662 file_access_control = B_HOST_TO_LENDIAN_INT32(block); 663 } 664 665 void SetExtraInodeSize(uint16 newSize) 666 { 667 extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize); 668 } 669 } _PACKED; 670 671 #define EXT2_SUPER_BLOCK_MAGIC 0xef53 672 673 // flags 674 #define EXT2_INODE_SECURE_DELETION 0x00000001 675 #define EXT2_INODE_UNDELETE 0x00000002 676 #define EXT2_INODE_COMPRESSED 0x00000004 677 #define EXT2_INODE_SYNCHRONOUS 0x00000008 678 #define EXT2_INODE_IMMUTABLE 0x00000010 679 #define EXT2_INODE_APPEND_ONLY 0x00000020 680 #define EXT2_INODE_NO_DUMP 0x00000040 681 #define EXT2_INODE_NO_ACCESS_TIME 0x00000080 682 #define EXT2_INODE_DIRTY 0x00000100 683 #define EXT2_INODE_COMPRESSED_BLOCKS 0x00000200 684 #define EXT2_INODE_DO_NOT_COMPRESS 0x00000400 685 #define EXT2_INODE_COMPRESSION_ERROR 0x00000800 686 #define EXT2_INODE_BTREE 0x00001000 687 #define EXT2_INODE_INDEXED 0x00001000 688 #define EXT2_INODE_JOURNAL_DATA 0x00004000 689 #define EXT2_INODE_NO_MERGE_TAIL 0x00008000 690 #define EXT2_INODE_DIR_SYNCH 0x00010000 691 #define EXT2_INODE_HUGE_FILE 0x00040000 692 #define EXT2_INODE_EXTENTS 0x00080000 693 #define EXT2_INODE_LARGE_EA 0x00200000 694 #define EXT2_INODE_EOF_BLOCKS 0x00400000 695 #define EXT2_INODE_INLINE_DATA 0x10000000 696 #define EXT2_INODE_RESERVED 0x80000000 697 698 #define EXT2_INODE_INHERITED (EXT2_INODE_SECURE_DELETION | EXT2_INODE_UNDELETE \ 699 | EXT2_INODE_COMPRESSED | EXT2_INODE_SYNCHRONOUS | EXT2_INODE_IMMUTABLE \ 700 | EXT2_INODE_APPEND_ONLY | EXT2_INODE_NO_DUMP | EXT2_INODE_NO_ACCESS_TIME \ 701 | EXT2_INODE_DO_NOT_COMPRESS | EXT2_INODE_JOURNAL_DATA \ 702 | EXT2_INODE_NO_MERGE_TAIL | EXT2_INODE_DIR_SYNCH) 703 704 #define EXT2_NAME_LENGTH 255 705 706 #define EXT2_DIR_PAD 4 707 #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) 708 #define EXT2_DIR_REC_LEN(namelen) (((namelen) + 8 + EXT2_DIR_ROUND) \ 709 & ~EXT2_DIR_ROUND) 710 711 struct ext2_dir_entry { 712 uint32 inode_id; 713 uint16 length; 714 uint8 name_length; 715 uint8 file_type; 716 char name[EXT2_NAME_LENGTH]; 717 718 uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); } 719 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); } 720 uint8 NameLength() const { return name_length; } 721 uint8 FileType() const { return file_type; } 722 723 void SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); } 724 725 void SetLength(uint16 newLength/*uint8 nameLength*/) 726 { 727 length = B_HOST_TO_LENDIAN_INT16(newLength); 728 /*name_length = nameLength; 729 730 if (nameLength % 4 == 0) { 731 length = B_HOST_TO_LENDIAN_INT16( 732 (short)(nameLength + MinimumSize())); 733 } else { 734 length = B_HOST_TO_LENDIAN_INT16( 735 (short)(nameLength % 4 + 1 + MinimumSize())); 736 }*/ 737 } 738 739 bool IsValid() const 740 { 741 return Length() > MinimumSize(); 742 // There is no maximum size, as the last entry spans until the 743 // end of the block 744 } 745 746 static size_t MinimumSize() 747 { 748 return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH; 749 } 750 } _PACKED; 751 752 struct ext2_dir_entry_tail { 753 uint32 zero1; 754 uint16 twelve; 755 uint8 zero2; 756 uint8 hexade; 757 uint32 checksum; 758 } _PACKED; 759 760 struct ext2_htree_tail { 761 uint32 reserved; 762 uint32 checksum; 763 } _PACKED; 764 765 // file types 766 #define EXT2_TYPE_UNKNOWN 0 767 #define EXT2_TYPE_FILE 1 768 #define EXT2_TYPE_DIRECTORY 2 769 #define EXT2_TYPE_CHAR_DEVICE 3 770 #define EXT2_TYPE_BLOCK_DEVICE 4 771 #define EXT2_TYPE_FIFO 5 772 #define EXT2_TYPE_SOCKET 6 773 #define EXT2_TYPE_SYMLINK 7 774 775 #define EXT2_XATTR_MAGIC 0xea020000 776 #define EXT2_XATTR_ROUND ((1 << 2) - 1) 777 #define EXT2_XATTR_NAME_LENGTH 255 778 779 #define EXT2_XATTR_INDEX_USER 1 780 781 struct ext2_xattr_header { 782 uint32 magic; 783 uint32 refcount; 784 uint32 blocks; // must be 1 for ext2 785 uint32 hash; 786 uint32 checksum; 787 uint32 reserved[3]; // zero 788 789 bool IsValid() const 790 { 791 return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC 792 && B_LENDIAN_TO_HOST_INT32(blocks) == 1 793 && refcount <= 1024; 794 } 795 796 void Dump() const { 797 for (unsigned int i = 0; i < Length(); i++) 798 dprintf("%02x ", ((uint8 *)this)[i]); 799 dprintf("\n"); 800 } 801 802 static size_t Length() 803 { 804 return sizeof(ext2_xattr_header); 805 } 806 }; 807 808 struct ext2_xattr_entry { 809 uint8 name_length; 810 uint8 name_index; 811 uint16 value_offset; 812 uint32 value_block; // must be zero for ext2 813 uint32 value_size; 814 uint32 hash; 815 char name[EXT2_XATTR_NAME_LENGTH]; 816 817 uint8 NameLength() const { return name_length; } 818 uint8 NameIndex() const { return name_index; } 819 uint16 ValueOffset() const { return 820 B_LENDIAN_TO_HOST_INT16(value_offset); } 821 uint32 ValueSize() const { return 822 B_LENDIAN_TO_HOST_INT32(value_size); } 823 824 // padded sizes 825 uint32 Length() const { return (MinimumSize() + NameLength() 826 + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; } 827 828 bool IsValid() const 829 { 830 return NameLength() > 0 && value_block == 0; 831 // There is no maximum size, as the last entry spans until the 832 // end of the block 833 } 834 835 void Dump(bool full=false) const { 836 for (unsigned int i = 0; i < (full ? sizeof(*this) : MinimumSize()); i++) 837 dprintf("%02x ", ((uint8 *)this)[i]); 838 dprintf("\n"); 839 } 840 841 static size_t MinimumSize() 842 { 843 return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH; 844 } 845 } _PACKED; 846 847 848 struct file_cookie { 849 bigtime_t last_notification; 850 off_t last_size; 851 int open_mode; 852 }; 853 854 855 #define EXT2_OPEN_MODE_USER_MASK 0x7fffffff 856 857 #define INODE_NOTIFICATION_INTERVAL 10000000LL 858 859 860 extern fs_volume_ops gExt2VolumeOps; 861 extern fs_vnode_ops gExt2VnodeOps; 862 863 #endif // EXT2_H 864