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 struct ext2_inode { 214 uint16 mode; 215 uint16 uid; 216 uint32 size; 217 uint32 access_time; 218 uint32 creation_time; 219 uint32 modification_time; 220 uint32 deletion_time; 221 uint16 gid; 222 uint16 num_links; 223 uint32 num_blocks; 224 uint32 flags; 225 uint32 _reserved1; 226 union { 227 ext2_data_stream stream; 228 char symlink[EXT2_SHORT_SYMLINK_LENGTH]; 229 }; 230 uint32 generation; 231 uint32 file_access_control; 232 union { 233 // for directories vs. files 234 uint32 directory_access_control; 235 uint32 size_high; 236 }; 237 uint32 fragment; 238 union { 239 struct { 240 uint8 fragment_number; 241 uint8 fragment_size; 242 }; 243 uint16 num_blocks_high; 244 }; 245 uint16 _padding; 246 uint16 uid_high; 247 uint16 gid_high; 248 uint32 _reserved2; 249 uint16 extra_inode_size; 250 uint16 _padding2; 251 252 uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } 253 uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); } 254 uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); } 255 uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); } 256 uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks) 257 | ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); } 258 259 time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); } 260 time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); } 261 time_t ModificationTime() const { return B_LENDIAN_TO_HOST_INT32(modification_time); } 262 time_t DeletionTime() const { return B_LENDIAN_TO_HOST_INT32(deletion_time); } 263 ino_t NextOrphan() const { return (ino_t)DeletionTime(); } 264 265 off_t Size() const 266 { 267 if (S_ISREG(Mode())) { 268 return B_LENDIAN_TO_HOST_INT32(size) 269 | ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32); 270 } 271 272 return B_LENDIAN_TO_HOST_INT32(size); 273 } 274 275 uint32 UserID() const 276 { 277 return B_LENDIAN_TO_HOST_INT16(uid) 278 | (B_LENDIAN_TO_HOST_INT16(uid_high) << 16); 279 } 280 281 uint32 GroupID() const 282 { 283 return B_LENDIAN_TO_HOST_INT16(gid) 284 | (B_LENDIAN_TO_HOST_INT16(gid_high) << 16); 285 } 286 287 void SetMode(uint16 newMode) 288 { 289 mode = B_LENDIAN_TO_HOST_INT16(newMode); 290 } 291 292 void UpdateMode(uint16 newMode, uint16 mask) 293 { 294 SetMode((Mode() & ~mask) | (newMode & mask)); 295 } 296 297 void ClearFlag(uint32 mask) 298 { 299 flags &= ~B_HOST_TO_LENDIAN_INT32(mask); 300 } 301 302 void SetFlag(uint32 mask) 303 { 304 flags |= B_HOST_TO_LENDIAN_INT32(mask); 305 } 306 307 void SetFlags(uint32 newFlags) 308 { 309 flags = B_HOST_TO_LENDIAN_INT32(newFlags); 310 } 311 312 void SetNumLinks(uint16 numLinks) 313 { 314 num_links = B_HOST_TO_LENDIAN_INT16(numLinks); 315 } 316 317 void SetNumBlocks(uint32 numBlocks) 318 { 319 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks); 320 } 321 322 void SetNumBlocks64(uint64 numBlocks) 323 { 324 num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff); 325 num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32); 326 } 327 328 void SetAccessTime(time_t accessTime) 329 { 330 access_time = B_HOST_TO_LENDIAN_INT32((uint32)accessTime); 331 } 332 333 void SetCreationTime(time_t creationTime) 334 { 335 creation_time = B_HOST_TO_LENDIAN_INT32((uint32)creationTime); 336 } 337 338 void SetModificationTime(time_t modificationTime) 339 { 340 modification_time = B_HOST_TO_LENDIAN_INT32((uint32)modificationTime); 341 } 342 343 void SetDeletionTime(time_t deletionTime) 344 { 345 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime); 346 } 347 348 void SetNextOrphan(ino_t id) 349 { 350 deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id); 351 } 352 353 void SetSize(off_t newSize) 354 { 355 size = B_HOST_TO_LENDIAN_INT32(newSize & 0xFFFFFFFF); 356 if (S_ISREG(Mode())) 357 size_high = B_HOST_TO_LENDIAN_INT32(newSize >> 32); 358 } 359 360 void SetUserID(uint32 newUID) 361 { 362 uid = B_HOST_TO_LENDIAN_INT16(newUID & 0xFFFF); 363 uid_high = B_HOST_TO_LENDIAN_INT16(newUID >> 16); 364 } 365 366 void SetGroupID(uint32 newGID) 367 { 368 gid = B_HOST_TO_LENDIAN_INT16(newGID & 0xFFFF); 369 gid_high = B_HOST_TO_LENDIAN_INT16(newGID >> 16); 370 } 371 372 void SetExtendedAttributesBlock(uint32 block) 373 { 374 file_access_control = B_HOST_TO_LENDIAN_INT32(block); 375 } 376 } _PACKED; 377 378 #define EXT2_SUPER_BLOCK_MAGIC 0xef53 379 380 // flags 381 #define EXT2_INODE_SECURE_DELETION 0x00000001 382 #define EXT2_INODE_UNDELETE 0x00000002 383 #define EXT2_INODE_COMPRESSED 0x00000004 384 #define EXT2_INODE_SYNCHRONOUS 0x00000008 385 #define EXT2_INODE_IMMUTABLE 0x00000010 386 #define EXT2_INODE_APPEND_ONLY 0x00000020 387 #define EXT2_INODE_NO_DUMP 0x00000040 388 #define EXT2_INODE_NO_ACCESS_TIME 0x00000080 389 #define EXT2_INODE_DIRTY 0x00000100 390 #define EXT2_INODE_COMPRESSED_BLOCKS 0x00000200 391 #define EXT2_INODE_DO_NOT_COMPRESS 0x00000400 392 #define EXT2_INODE_COMPRESSION_ERROR 0x00000800 393 #define EXT2_INODE_BTREE 0x00001000 394 #define EXT2_INODE_INDEXED 0x00001000 395 #define EXT2_INODE_HUGE_FILE 0x00040000 396 397 #define EXT2_NAME_LENGTH 255 398 399 struct ext2_dir_entry { 400 uint32 inode_id; 401 uint16 length; 402 uint8 name_length; 403 uint8 file_type; 404 char name[EXT2_NAME_LENGTH]; 405 406 uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); } 407 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); } 408 uint8 NameLength() const { return name_length; } 409 uint8 FileType() const { return file_type; } 410 411 void SetInodeID(uint32 id) { inode_id = B_HOST_TO_LENDIAN_INT32(id); } 412 413 void SetLength(uint16 newLength/*uint8 nameLength*/) 414 { 415 length = B_HOST_TO_LENDIAN_INT16(newLength); 416 /*name_length = nameLength; 417 418 if (nameLength % 4 == 0) { 419 length = B_HOST_TO_LENDIAN_INT16( 420 (short)(nameLength + MinimumSize())); 421 } else { 422 length = B_HOST_TO_LENDIAN_INT16( 423 (short)(nameLength % 4 + 1 + MinimumSize())); 424 }*/ 425 } 426 427 bool IsValid() const 428 { 429 return Length() > MinimumSize(); 430 // There is no maximum size, as the last entry spans until the 431 // end of the block 432 } 433 434 static size_t MinimumSize() 435 { 436 return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH; 437 } 438 } _PACKED; 439 440 // file types 441 #define EXT2_TYPE_UNKOWN 0 442 #define EXT2_TYPE_FILE 1 443 #define EXT2_TYPE_DIRECTORY 2 444 #define EXT2_TYPE_CHAR_DEVICE 3 445 #define EXT2_TYPE_BLOCK_DEVICE 4 446 #define EXT2_TYPE_FIFO 5 447 #define EXT2_TYPE_SOCKET 6 448 #define EXT2_TYPE_SYMLINK 7 449 450 #define EXT2_XATTR_MAGIC 0xea020000 451 #define EXT2_XATTR_ROUND ((1 << 2) - 1) 452 #define EXT2_XATTR_NAME_LENGTH 255 453 454 #define EXT2_XATTR_INDEX_USER 1 455 456 struct ext2_xattr_header { 457 uint32 magic; 458 uint32 refcount; 459 uint32 blocks; // must be 1 for ext2 460 uint32 hash; 461 uint32 reserved[4]; // zero 462 463 bool IsValid() const 464 { 465 return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC 466 && B_LENDIAN_TO_HOST_INT32(blocks) == 1 467 && refcount <= 1024; 468 } 469 470 void Dump() const { 471 for (unsigned int i = 0; i < Length(); i++) 472 dprintf("%02x ", ((uint8 *)this)[i]); 473 dprintf("\n"); 474 } 475 476 static size_t Length() 477 { 478 return sizeof(ext2_xattr_header); 479 } 480 }; 481 482 struct ext2_xattr_entry { 483 uint8 name_length; 484 uint8 name_index; 485 uint16 value_offset; 486 uint32 value_block; // must be zero for ext2 487 uint32 value_size; 488 uint32 hash; 489 char name[EXT2_XATTR_NAME_LENGTH]; 490 491 uint8 NameLength() const { return name_length; } 492 uint8 NameIndex() const { return name_index; } 493 uint16 ValueOffset() const { return 494 B_LENDIAN_TO_HOST_INT16(value_offset); } 495 uint32 ValueSize() const { return 496 B_LENDIAN_TO_HOST_INT32(value_size); } 497 498 // padded sizes 499 uint32 Length() const { return (MinimumSize() + NameLength() 500 + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; } 501 502 bool IsValid() const 503 { 504 return NameLength() > 0 && value_block == 0; 505 // There is no maximum size, as the last entry spans until the 506 // end of the block 507 } 508 509 void Dump(bool full=false) const { 510 for (unsigned int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++) 511 dprintf("%02x ", ((uint8 *)this)[i]); 512 dprintf("\n"); 513 } 514 515 static size_t MinimumSize() 516 { 517 return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH; 518 } 519 } _PACKED; 520 521 522 struct file_cookie { 523 bigtime_t last_notification; 524 off_t last_size; 525 int open_mode; 526 }; 527 528 #define EXT2_OPEN_MODE_USER_MASK 0x7fffffff 529 530 #define INODE_NOTIFICATION_INTERVAL 10000000LL 531 532 533 extern fs_volume_ops gExt2VolumeOps; 534 extern fs_vnode_ops gExt2VnodeOps; 535 536 #endif // EXT2_H 537