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 #define EXT2_SUPER_BLOCK_OFFSET 1024 19 20 struct ext2_super_block { 21 uint32 num_inodes; 22 uint32 num_blocks; 23 uint32 reserved_blocks; 24 uint32 free_blocks; 25 uint32 free_inodes; 26 uint32 first_data_block; 27 uint32 block_shift; 28 uint32 fragment_shift; 29 uint32 blocks_per_group; 30 uint32 fragments_per_group; 31 uint32 inodes_per_group; 32 uint32 mount_time; 33 uint32 write_time; 34 uint16 mount_count; 35 uint16 max_mount_count; 36 uint16 magic; 37 uint16 state; 38 uint16 error_handling; 39 uint16 minor_revision_level; 40 uint32 last_check_time; 41 uint32 check_interval; 42 uint32 creator_os; 43 uint32 revision_level; 44 uint16 reserved_blocks_uid; 45 uint16 reserved_blocks_gid; 46 uint32 first_inode; 47 uint16 inode_size; 48 uint16 block_group; 49 uint32 compatible_features; 50 uint32 incompatible_features; 51 uint32 read_only_features; 52 uint8 uuid[16]; 53 char name[16]; 54 char last_mount_point[64]; 55 uint32 algorithm_usage_bitmap; 56 uint8 preallocated_blocks; 57 uint8 preallocated_directory_blocks; 58 uint16 _padding; 59 60 // journaling ext3 support 61 uint8 journal_uuid[16]; 62 uint32 journal_inode; 63 uint32 journal_device; 64 uint32 last_orphan; 65 uint32 hash_seed[4]; 66 uint8 default_hash_version; 67 uint8 _reserved1; 68 uint16 _reserved2; 69 uint32 default_mount_options; 70 uint32 first_meta_block_group; 71 uint32 fs_creation_time; 72 uint32 journal_inode_backup[17]; 73 74 // ext4 support 75 uint32 num_blocks_hi; 76 uint32 reserved_blocks_hi; 77 uint32 free_blocks_hi; 78 uint16 min_inode_size; 79 uint16 want_inode_size; 80 uint32 flags; 81 uint16 raid_stride; 82 uint16 mmp_interval; 83 uint64 mmp_block; 84 uint32 raid_stripe_width; 85 uint8 groups_per_flex_shift; 86 uint8 _reserved3; 87 uint16 _reserved4; 88 uint32 _reserved5[162]; 89 90 uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); } 91 uint16 State() const { return B_LENDIAN_TO_HOST_INT16(state); } 92 uint32 RevisionLevel() const { return B_LENDIAN_TO_HOST_INT16(revision_level); } 93 uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; } 94 uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); } 95 uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); } 96 uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); } 97 uint32 FreeBlocks() const { return B_LENDIAN_TO_HOST_INT32(free_blocks); } 98 uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); } 99 uint32 FirstDataBlock() const 100 { return B_LENDIAN_TO_HOST_INT32(first_data_block); } 101 uint32 BlocksPerGroup() const 102 { return B_LENDIAN_TO_HOST_INT32(blocks_per_group); } 103 uint32 InodesPerGroup() const 104 { return B_LENDIAN_TO_HOST_INT32(inodes_per_group); } 105 uint32 FirstMetaBlockGroup() const 106 { return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); } 107 uint32 CompatibleFeatures() const 108 { return B_LENDIAN_TO_HOST_INT32(compatible_features); } 109 uint32 ReadOnlyFeatures() const 110 { return B_LENDIAN_TO_HOST_INT32(read_only_features); } 111 uint32 IncompatibleFeatures() const 112 { return B_LENDIAN_TO_HOST_INT32(incompatible_features); } 113 ino_t JournalInode() const 114 { return B_LENDIAN_TO_HOST_INT32(journal_inode); } 115 ino_t LastOrphan() const 116 { return (ino_t)B_LENDIAN_TO_HOST_INT32(last_orphan); } 117 uint32 HashSeed(uint8 i) const 118 { return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); } 119 120 void SetFreeInodes(uint32 freeInodes) 121 { free_inodes = B_HOST_TO_LENDIAN_INT32(freeInodes); } 122 void SetFreeBlocks(uint32 freeBlocks) 123 { free_blocks = B_HOST_TO_LENDIAN_INT32(freeBlocks); } 124 void SetLastOrphan(ino_t id) 125 { last_orphan = B_HOST_TO_LENDIAN_INT32((uint32)id); } 126 127 bool IsValid(); 128 // implemented in Volume.cpp 129 } _PACKED; 130 131 #define EXT2_OLD_REVISION 0 132 #define EXT2_DYNAMIC_REVISION 1 133 134 #define EXT2_MAX_REVISION EXT2_DYNAMIC_REVISION 135 136 #define EXT2_FS_STATE_VALID 1 // File system was cleanly unmounted 137 #define EXT2_FS_STATE_ERROR 2 // File system has errors 138 #define EXT2_FS_STATE_ORPHAN 3 // Orphans are being recovered 139 140 // compatible features 141 #define EXT2_FEATURE_DIRECTORY_PREALLOCATION 0x0001 142 #define EXT2_FEATURE_IMAGIC_INODES 0x0002 143 #define EXT2_FEATURE_HAS_JOURNAL 0x0004 144 #define EXT2_FEATURE_EXT_ATTR 0x0008 145 #define EXT2_FEATURE_RESIZE_INODE 0x0010 146 #define EXT2_FEATURE_DIRECTORY_INDEX 0x0020 147 148 // read-only compatible features 149 #define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER 0x0001 150 #define EXT2_READ_ONLY_FEATURE_LARGE_FILE 0x0002 151 #define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY 0x0004 152 #define EXT2_READ_ONLY_FEATURE_HUGE_FILE 0x0008 153 154 // incompatible features 155 #define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION 0x0001 156 #define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE 0x0002 157 #define EXT2_INCOMPATIBLE_FEATURE_RECOVER 0x0004 158 #define EXT2_INCOMPATIBLE_FEATURE_JOURNAL 0x0008 159 #define EXT2_INCOMPATIBLE_FEATURE_META_GROUP 0x0010 160 #define EXT2_INCOMPATIBLE_FEATURE_EXTENTS 0x0040 161 #define EXT2_INCOMPATIBLE_FEATURE_64BIT 0x0080 162 #define EXT2_INCOMPATIBLE_FEATURE_MMP 0x0100 163 #define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP 0x0200 164 165 // states 166 #define EXT2_STATE_VALID 0x01 167 #define EXT2_STATE_INVALID 0x02 168 169 struct ext2_block_group { 170 uint32 block_bitmap; 171 uint32 inode_bitmap; 172 uint32 inode_table; 173 uint16 free_blocks; 174 uint16 free_inodes; 175 uint16 used_directories; 176 uint16 _padding; 177 uint32 _reserved[3]; 178 179 uint32 BlockBitmap() const 180 { return B_LENDIAN_TO_HOST_INT32(block_bitmap); } 181 uint32 InodeBitmap() const 182 { return B_LENDIAN_TO_HOST_INT32(inode_bitmap); } 183 uint32 InodeTable() const 184 { return B_LENDIAN_TO_HOST_INT32(inode_table); } 185 uint16 FreeBlocks() const 186 { return B_LENDIAN_TO_HOST_INT16(free_blocks); } 187 uint16 FreeInodes() const 188 { return B_LENDIAN_TO_HOST_INT16(free_inodes); } 189 uint16 UsedDirectories() const 190 { return B_LENDIAN_TO_HOST_INT16(used_directories); } 191 192 void SetFreeBlocks(uint16 freeBlocks) 193 { free_blocks = B_HOST_TO_LENDIAN_INT16(freeBlocks); } 194 195 void SetFreeInodes(uint16 freeInodes) 196 { free_inodes = B_HOST_TO_LENDIAN_INT16(freeInodes); } 197 198 void SetUsedDirectories(uint16 usedDirectories) 199 { used_directories = B_HOST_TO_LENDIAN_INT16(usedDirectories); } 200 } _PACKED; 201 202 #define EXT2_DIRECT_BLOCKS 12 203 #define EXT2_ROOT_NODE 2 204 #define EXT2_SHORT_SYMLINK_LENGTH 60 205 206 struct ext2_data_stream { 207 uint32 direct[EXT2_DIRECT_BLOCKS]; 208 uint32 indirect; 209 uint32 double_indirect; 210 uint32 triple_indirect; 211 } _PACKED; 212 213 #define EXT2_INODE_NORMAL_SIZE 128 214 215 struct ext2_inode { 216 uint16 mode; 217 uint16 uid; 218 uint32 size; 219 uint32 access_time; 220 uint32 change_time; 221 uint32 modification_time; 222 uint32 deletion_time; 223 uint16 gid; 224 uint16 num_links; 225 uint32 num_blocks; 226 uint32 flags; 227 uint32 version; 228 union { 229 ext2_data_stream stream; 230 char symlink[EXT2_SHORT_SYMLINK_LENGTH]; 231 }; 232 uint32 generation; 233 uint32 file_access_control; 234 union { 235 // for directories vs. files 236 uint32 directory_access_control; 237 uint32 size_high; 238 }; 239 uint32 fragment; 240 union { 241 struct { 242 uint8 fragment_number; 243 uint8 fragment_size; 244 }; 245 uint16 num_blocks_high; 246 }; 247 uint16 _padding; 248 uint16 uid_high; 249 uint16 gid_high; 250 uint32 _reserved2; 251 252 // extra attributes 253 uint16 extra_inode_size; 254 uint16 _padding2; 255 uint32 change_time_extra; 256 uint32 modification_time_extra; 257 uint32 access_time_extra; 258 uint32 creation_time; 259 uint32 creation_time_extra; 260 uint32 version_high; 261 262 uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } 263 uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); } 264 uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); } 265 uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); } 266 uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks) 267 | ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); } 268 269 static void _DecodeTime(struct timespec *timespec, uint32 time, 270 uint32 time_extra, bool extra) 271 { 272 timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time); 273 if (extra && sizeof(timespec->tv_sec) > 4) 274 timespec->tv_sec |= 275 (uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32; 276 if (extra) 277 timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2; 278 else 279 timespec->tv_nsec = 0; 280 } 281 282 void GetModificationTime(struct timespec *timespec, bool extra) const 283 { _DecodeTime(timespec, modification_time, modification_time_extra, 284 extra); } 285 void GetAccessTime(struct timespec *timespec, bool extra) const 286 { _DecodeTime(timespec, access_time, access_time_extra, extra); } 287 void GetChangeTime(struct timespec *timespec, bool extra) const 288 { _DecodeTime(timespec, change_time, change_time_extra, extra); } 289 void GetCreationTime(struct timespec *timespec, bool extra) const 290 { 291 if (extra) 292 _DecodeTime(timespec, creation_time, creation_time_extra, extra); 293 else { 294 timespec->tv_sec = 0; 295 timespec->tv_nsec = 0; 296 } 297 } 298 time_t DeletionTime() const 299 { return B_LENDIAN_TO_HOST_INT32(deletion_time); } 300 301 static uint32 _EncodeTime(const struct timespec *timespec) 302 { 303 uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc; 304 if (sizeof(timespec->tv_sec) > 4) 305 time |= (uint64)timespec->tv_sec >> 32; 306 return B_HOST_TO_LENDIAN_INT32(time); 307 } 308 309 void SetModificationTime(const struct timespec *timespec, bool extra) 310 { 311 modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 312 if (extra) 313 modification_time_extra = _EncodeTime(timespec); 314 } 315 void SetAccessTime(const struct timespec *timespec, bool extra) 316 { 317 access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 318 if (extra) 319 access_time_extra = _EncodeTime(timespec); 320 } 321 void SetChangeTime(const struct timespec *timespec, bool extra) 322 { 323 change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 324 if (extra) 325 change_time_extra = _EncodeTime(timespec); 326 } 327 void SetCreationTime(const struct timespec *timespec, bool extra) 328 { 329 if (extra) { 330 creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec); 331 creation_time_extra = 332 B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec); 333 } 334 } 335 void SetDeletionTime(time_t deletionTime) 336 { 337 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime); 338 } 339 340 ino_t NextOrphan() const { return (ino_t)DeletionTime(); } 341 342 off_t Size() const 343 { 344 if (S_ISREG(Mode())) { 345 return B_LENDIAN_TO_HOST_INT32(size) 346 | ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32); 347 } 348 349 return B_LENDIAN_TO_HOST_INT32(size); 350 } 351 352 uint16 ExtraInodeSize() const 353 { return B_LENDIAN_TO_HOST_INT16(extra_inode_size); } 354 355 uint32 UserID() const 356 { 357 return B_LENDIAN_TO_HOST_INT16(uid) 358 | (B_LENDIAN_TO_HOST_INT16(uid_high) << 16); 359 } 360 361 uint32 GroupID() const 362 { 363 return B_LENDIAN_TO_HOST_INT16(gid) 364 | (B_LENDIAN_TO_HOST_INT16(gid_high) << 16); 365 } 366 367 void SetMode(uint16 newMode) 368 { 369 mode = B_LENDIAN_TO_HOST_INT16(newMode); 370 } 371 372 void UpdateMode(uint16 newMode, uint16 mask) 373 { 374 SetMode((Mode() & ~mask) | (newMode & mask)); 375 } 376 377 void ClearFlag(uint32 mask) 378 { 379 flags &= ~B_HOST_TO_LENDIAN_INT32(mask); 380 } 381 382 void SetFlag(uint32 mask) 383 { 384 flags |= B_HOST_TO_LENDIAN_INT32(mask); 385 } 386 387 void SetFlags(uint32 newFlags) 388 { 389 flags = B_HOST_TO_LENDIAN_INT32(newFlags); 390 } 391 392 void SetNumLinks(uint16 numLinks) 393 { 394 num_links = B_HOST_TO_LENDIAN_INT16(numLinks); 395 } 396 397 void SetNumBlocks(uint32 numBlocks) 398 { 399 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks); 400 } 401 402 void SetNumBlocks64(uint64 numBlocks) 403 { 404 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff); 405 num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32); 406 } 407 408 void SetNextOrphan(ino_t id) 409 { 410 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id); 411 } 412 413 void SetSize(off_t newSize) 414 { 415 size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF); 416 if (S_ISREG(Mode())) 417 size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32); 418 } 419 420 void SetUserID(uint32 newUID) 421 { 422 uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF); 423 uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16); 424 } 425 426 void SetGroupID(uint32 newGID) 427 { 428 gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF); 429 gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16); 430 } 431 432 void SetExtendedAttributesBlock(uint32 block) 433 { 434 file_access_control = B_HOST_TO_LENDIAN_INT32(block); 435 } 436 437 void SetExtraInodeSize(uint16 newSize) 438 { 439 extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize); 440 } 441 } _PACKED; 442 443 #define EXT2_SUPER_BLOCK_MAGIC 0xef53 444 445 // flags 446 #define EXT2_INODE_SECURE_DELETION 0x00000001 447 #define EXT2_INODE_UNDELETE 0x00000002 448 #define EXT2_INODE_COMPRESSED 0x00000004 449 #define EXT2_INODE_SYNCHRONOUS 0x00000008 450 #define EXT2_INODE_IMMUTABLE 0x00000010 451 #define EXT2_INODE_APPEND_ONLY 0x00000020 452 #define EXT2_INODE_NO_DUMP 0x00000040 453 #define EXT2_INODE_NO_ACCESS_TIME 0x00000080 454 #define EXT2_INODE_DIRTY 0x00000100 455 #define EXT2_INODE_COMPRESSED_BLOCKS 0x00000200 456 #define EXT2_INODE_DO_NOT_COMPRESS 0x00000400 457 #define EXT2_INODE_COMPRESSION_ERROR 0x00000800 458 #define EXT2_INODE_BTREE 0x00001000 459 #define EXT2_INODE_INDEXED 0x00001000 460 #define EXT2_INODE_HUGE_FILE 0x00040000 461 462 #define EXT2_NAME_LENGTH 255 463 464 struct ext2_dir_entry { 465 uint32 inode_id; 466 uint16 length; 467 uint8 name_length; 468 uint8 file_type; 469 char name[EXT2_NAME_LENGTH]; 470 471 uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); } 472 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); } 473 uint8 NameLength() const { return name_length; } 474 uint8 FileType() const { return file_type; } 475 476 void SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); } 477 478 void SetLength(uint16 newLength/*uint8 nameLength*/) 479 { 480 length = B_HOST_TO_LENDIAN_INT16(newLength); 481 /*name_length = nameLength; 482 483 if (nameLength % 4 == 0) { 484 length = B_HOST_TO_LENDIAN_INT16( 485 (short)(nameLength + MinimumSize())); 486 } else { 487 length = B_HOST_TO_LENDIAN_INT16( 488 (short)(nameLength % 4 + 1 + MinimumSize())); 489 }*/ 490 } 491 492 bool IsValid() const 493 { 494 return Length() > MinimumSize(); 495 // There is no maximum size, as the last entry spans until the 496 // end of the block 497 } 498 499 static size_t MinimumSize() 500 { 501 return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH; 502 } 503 } _PACKED; 504 505 // file types 506 #define EXT2_TYPE_UNKOWN 0 507 #define EXT2_TYPE_FILE 1 508 #define EXT2_TYPE_DIRECTORY 2 509 #define EXT2_TYPE_CHAR_DEVICE 3 510 #define EXT2_TYPE_BLOCK_DEVICE 4 511 #define EXT2_TYPE_FIFO 5 512 #define EXT2_TYPE_SOCKET 6 513 #define EXT2_TYPE_SYMLINK 7 514 515 #define EXT2_XATTR_MAGIC 0xea020000 516 #define EXT2_XATTR_ROUND ((1 << 2) - 1) 517 #define EXT2_XATTR_NAME_LENGTH 255 518 519 #define EXT2_XATTR_INDEX_USER 1 520 521 struct ext2_xattr_header { 522 uint32 magic; 523 uint32 refcount; 524 uint32 blocks; // must be 1 for ext2 525 uint32 hash; 526 uint32 reserved[4]; // zero 527 528 bool IsValid() const 529 { 530 return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC 531 && B_LENDIAN_TO_HOST_INT32(blocks) == 1 532 && refcount <= 1024; 533 } 534 535 void Dump() const { 536 for (unsigned int i = 0; i < Length(); i++) 537 dprintf("%02x ", ((uint8 *)this)[i]); 538 dprintf("\n"); 539 } 540 541 static size_t Length() 542 { 543 return sizeof(ext2_xattr_header); 544 } 545 }; 546 547 struct ext2_xattr_entry { 548 uint8 name_length; 549 uint8 name_index; 550 uint16 value_offset; 551 uint32 value_block; // must be zero for ext2 552 uint32 value_size; 553 uint32 hash; 554 char name[EXT2_XATTR_NAME_LENGTH]; 555 556 uint8 NameLength() const { return name_length; } 557 uint8 NameIndex() const { return name_index; } 558 uint16 ValueOffset() const { return 559 B_LENDIAN_TO_HOST_INT16(value_offset); } 560 uint32 ValueSize() const { return 561 B_LENDIAN_TO_HOST_INT32(value_size); } 562 563 // padded sizes 564 uint32 Length() const { return (MinimumSize() + NameLength() 565 + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; } 566 567 bool IsValid() const 568 { 569 return NameLength() > 0 && value_block == 0; 570 // There is no maximum size, as the last entry spans until the 571 // end of the block 572 } 573 574 void Dump(bool full=false) const { 575 for (unsigned int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++) 576 dprintf("%02x ", ((uint8 *)this)[i]); 577 dprintf("\n"); 578 } 579 580 static size_t MinimumSize() 581 { 582 return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH; 583 } 584 } _PACKED; 585 586 587 struct file_cookie { 588 bigtime_t last_notification; 589 off_t last_size; 590 int open_mode; 591 }; 592 593 #define EXT2_OPEN_MODE_USER_MASK 0x7fffffff 594 595 #define INODE_NOTIFICATION_INTERVAL 10000000LL 596 597 598 extern fs_volume_ops gExt2VolumeOps; 599 extern fs_vnode_ops gExt2VnodeOps; 600 601 #endif // EXT2_H 602