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 EXT2_SUPER_BLOCK_OFFSET 1024 17 18 struct ext2_super_block { 19 uint32 num_inodes; 20 uint32 num_blocks; 21 uint32 reserved_blocks; 22 uint32 free_blocks; 23 uint32 free_inodes; 24 uint32 first_data_block; 25 uint32 block_shift; 26 uint32 fragment_shift; 27 uint32 blocks_per_group; 28 uint32 fragments_per_group; 29 uint32 inodes_per_group; 30 uint32 mount_time; 31 uint32 write_time; 32 uint16 mount_count; 33 uint16 max_mount_count; 34 uint16 magic; 35 uint16 state; 36 uint16 error_handling; 37 uint16 minor_revision_level; 38 uint32 last_check_time; 39 uint32 check_interval; 40 uint32 creator_os; 41 uint32 revision_level; 42 uint16 reserved_blocks_uid; 43 uint16 reserved_blocks_gid; 44 uint32 first_inode; 45 uint16 inode_size; 46 uint16 block_group; 47 uint32 compatible_features; 48 uint32 incompatible_features; 49 uint32 read_only_features; 50 uint8 uuid[16]; 51 char name[16]; 52 char last_mount_point[64]; 53 uint32 algorithm_usage_bitmap; 54 uint8 preallocated_blocks; 55 uint8 preallocated_directory_blocks; 56 uint16 _padding; 57 58 // journaling ext3 support 59 uint8 journal_uuid[16]; 60 uint32 journal_inode; 61 uint32 journal_device; 62 uint32 last_orphan; 63 uint32 hash_seed[4]; 64 uint8 default_hash_version; 65 uint8 _reserved1; 66 uint16 _reserved2; 67 uint32 default_mount_options; 68 uint32 first_meta_block_group; 69 uint32 fs_creation_time; 70 uint32 journal_inode_backup[17]; 71 72 // ext4 support 73 uint32 num_blocks_hi; 74 uint32 reserved_blocks_hi; 75 uint32 free_blocks_hi; 76 uint16 min_inode_size; 77 uint16 want_inode_size; 78 uint32 flags; 79 uint16 raid_stride; 80 uint16 mmp_interval; 81 uint64 mmp_block; 82 uint32 raid_stripe_width; 83 uint8 groups_per_flex_shift; 84 uint8 _reserved3; 85 uint16 _reserved4; 86 uint32 _reserved5[162]; 87 88 uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); } 89 uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; } 90 uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); } 91 uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); } 92 uint32 FreeInodes() const { return B_LENDIAN_TO_HOST_INT32(free_inodes); } 93 uint32 FreeBlocks() const { return B_LENDIAN_TO_HOST_INT32(free_blocks); } 94 uint16 InodeSize() const { return B_LENDIAN_TO_HOST_INT16(inode_size); } 95 uint32 FirstDataBlock() const 96 { return B_LENDIAN_TO_HOST_INT32(first_data_block); } 97 uint32 BlocksPerGroup() const 98 { return B_LENDIAN_TO_HOST_INT32(blocks_per_group); } 99 uint32 InodesPerGroup() const 100 { return B_LENDIAN_TO_HOST_INT32(inodes_per_group); } 101 uint32 FirstMetaBlockGroup() const 102 { return B_LENDIAN_TO_HOST_INT32(first_meta_block_group); } 103 uint32 CompatibleFeatures() const 104 { return B_LENDIAN_TO_HOST_INT32(compatible_features); } 105 uint32 ReadOnlyFeatures() const 106 { return B_LENDIAN_TO_HOST_INT32(read_only_features); } 107 uint32 IncompatibleFeatures() const 108 { return B_LENDIAN_TO_HOST_INT32(incompatible_features); } 109 110 bool IsValid(); 111 // implemented in Volume.cpp 112 } _PACKED; 113 114 #define EXT2_OLD_REVISION 0 115 #define EXT2_DYNAMIC_REVISION 1 116 117 // compatible features 118 #define EXT2_FEATURE_DIRECTORY_PREALLOCATION 0x0001 119 #define EXT2_FEATURE_IMAGIC_INODES 0x0002 120 #define EXT2_FEATURE_HAS_JOURNAL 0x0004 121 #define EXT2_FEATURE_EXT_ATTR 0x0008 122 #define EXT2_FEATURE_RESIZE_INODE 0x0010 123 #define EXT2_FEATURE_DIRECTORY_INDEX 0x0020 124 125 // read-only compatible features 126 #define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER 0x0001 127 #define EXT2_READ_ONLY_FEATURE_LARGE_FILE 0x0002 128 #define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY 0x0004 129 130 // incompatible features 131 #define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION 0x0001 132 #define EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE 0x0002 133 #define EXT2_INCOMPATIBLE_FEATURE_RECOVER 0x0004 134 #define EXT2_INCOMPATIBLE_FEATURE_JOURNAL 0x0008 135 #define EXT2_INCOMPATIBLE_FEATURE_META_GROUP 0x0010 136 #define EXT2_INCOMPATIBLE_FEATURE_EXTENTS 0x0040 137 #define EXT2_INCOMPATIBLE_FEATURE_64BIT 0x0080 138 #define EXT2_INCOMPATIBLE_FEATURE_MMP 0x0100 139 #define EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP 0x0200 140 141 // states 142 #define EXT2_STATE_VALID 0x01 143 #define EXT2_STATE_INVALID 0x02 144 145 struct ext2_block_group { 146 uint32 block_bitmap; 147 uint32 inode_bitmap; 148 uint32 inode_table; 149 uint16 free_blocks; 150 uint16 free_inodes; 151 uint16 used_directories; 152 uint16 _padding; 153 uint32 _reserved[3]; 154 155 uint32 InodeTable() const 156 { return B_LENDIAN_TO_HOST_INT32(inode_table); } 157 } _PACKED; 158 159 #define EXT2_DIRECT_BLOCKS 12 160 #define EXT2_ROOT_NODE 2 161 #define EXT2_SHORT_SYMLINK_LENGTH 60 162 163 struct ext2_data_stream { 164 uint32 direct[EXT2_DIRECT_BLOCKS]; 165 uint32 indirect; 166 uint32 double_indirect; 167 uint32 triple_indirect; 168 } _PACKED; 169 170 struct ext2_inode { 171 uint16 mode; 172 uint16 uid; 173 uint32 size; 174 uint32 access_time; 175 uint32 creation_time; 176 uint32 modification_time; 177 uint32 deletion_time; 178 uint16 gid; 179 uint16 num_links; 180 uint32 num_blocks; 181 uint32 flags; 182 uint32 _reserved1; 183 union { 184 ext2_data_stream stream; 185 char symlink[EXT2_SHORT_SYMLINK_LENGTH]; 186 }; 187 uint32 generation; 188 uint32 file_access_control; 189 union { 190 // for directories vs. files 191 uint32 directory_access_control; 192 uint32 size_high; 193 }; 194 uint32 fragment; 195 uint8 fragment_number; 196 uint8 fragment_size; 197 uint16 _padding; 198 uint16 uid_high; 199 uint16 gid_high; 200 uint32 _reserved2; 201 uint16 extra_inode_size; 202 uint16 _padding2; 203 204 uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } 205 uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); } 206 uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); } 207 208 time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); } 209 time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); } 210 time_t ModificationTime() const { return B_LENDIAN_TO_HOST_INT32(modification_time); } 211 time_t DeletionTime() const { return B_LENDIAN_TO_HOST_INT32(deletion_time); } 212 213 off_t Size() const 214 { 215 if (S_ISREG(Mode())) { 216 return B_LENDIAN_TO_HOST_INT32(size) 217 | ((off_t)B_LENDIAN_TO_HOST_INT32(size_high) << 32); 218 } 219 220 return B_LENDIAN_TO_HOST_INT32(size); 221 } 222 223 uint32 UserID() const 224 { 225 return B_LENDIAN_TO_HOST_INT16(uid) 226 | (B_LENDIAN_TO_HOST_INT16(uid_high) << 16); 227 } 228 229 uint32 GroupID() const 230 { 231 return B_LENDIAN_TO_HOST_INT16(gid) 232 | (B_LENDIAN_TO_HOST_INT16(gid_high) << 16); 233 } 234 } _PACKED; 235 236 #define EXT2_SUPER_BLOCK_MAGIC 0xef53 237 238 // flags 239 #define EXT2_INODE_SECURE_DELETION 0x00000001 240 #define EXT2_INODE_UNDELETE 0x00000002 241 #define EXT2_INODE_COMPRESSED 0x00000004 242 #define EXT2_INODE_SYNCHRONOUS 0x00000008 243 #define EXT2_INODE_IMMUTABLE 0x00000010 244 #define EXT2_INODE_APPEND_ONLY 0x00000020 245 #define EXT2_INODE_NO_DUMP 0x00000040 246 #define EXT2_INODE_NO_ACCESS_TIME 0x00000080 247 #define EXT2_INODE_DIRTY 0x00000100 248 #define EXT2_INODE_COMPRESSED_BLOCKS 0x00000200 249 #define EXT2_INODE_DO_NOT_COMPRESS 0x00000400 250 #define EXT2_INODE_COMPRESSION_ERROR 0x00000800 251 #define EXT2_INODE_BTREE 0x00001000 252 253 #define EXT2_NAME_LENGTH 255 254 255 struct ext2_dir_entry { 256 uint32 inode_id; 257 uint16 length; 258 uint8 name_length; 259 uint8 file_type; 260 char name[EXT2_NAME_LENGTH]; 261 262 uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); } 263 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); } 264 uint8 NameLength() const { return name_length; } 265 uint8 FileType() const { return file_type; } 266 267 bool IsValid() const 268 { 269 return Length() > MinimumSize(); 270 // There is no maximum size, as the last entry spans until the 271 // end of the block 272 } 273 274 static size_t MinimumSize() 275 { 276 return sizeof(ext2_dir_entry) - EXT2_NAME_LENGTH; 277 } 278 } _PACKED; 279 280 // file types 281 #define EXT2_TYPE_UNKOWN 0 282 #define EXT2_TYPE_FILE 1 283 #define EXT2_TYPE_DIRECTORY 2 284 #define EXT2_TYPE_CHAR_DEVICE 3 285 #define EXT2_TYPE_BLOCK_DEVICE 4 286 #define EXT2_TYPE_FIFO 5 287 #define EXT2_TYPE_SOCKET 6 288 #define EXT2_TYPE_SYMLINK 7 289 290 #define EXT2_XATTR_MAGIC 0xea020000 291 #define EXT2_XATTR_ROUND ((1 << 2) - 1) 292 #define EXT2_XATTR_NAME_LENGTH 255 293 294 #define EXT2_XATTR_INDEX_USER 1 295 296 struct ext2_xattr_header { 297 uint32 magic; 298 uint32 refcount; 299 uint32 blocks; // must be 1 for ext2 300 uint32 hash; 301 uint32 reserved[4]; // zero 302 303 bool IsValid() const 304 { 305 return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC 306 && B_LENDIAN_TO_HOST_INT32(blocks) == 1 307 && refcount <= 1024; 308 } 309 310 void Dump() const { 311 for (int i = 0; i < Length(); i++) 312 dprintf("%02x ", ((uint8 *)this)[i]); 313 dprintf("\n"); 314 } 315 316 static size_t Length() 317 { 318 return sizeof(ext2_xattr_header); 319 } 320 }; 321 322 struct ext2_xattr_entry { 323 uint8 name_length; 324 uint8 name_index; 325 uint16 value_offset; 326 uint32 value_block; // must be zero for ext2 327 uint32 value_size; 328 uint32 hash; 329 char name[EXT2_XATTR_NAME_LENGTH]; 330 331 uint8 NameLength() const { return name_length; } 332 uint8 NameIndex() const { return name_index; } 333 uint16 ValueOffset() const { return 334 B_LENDIAN_TO_HOST_INT16(value_offset); } 335 uint32 ValueSize() const { return 336 B_LENDIAN_TO_HOST_INT32(value_size); } 337 338 // padded sizes 339 uint32 Length() const { return (MinimumSize() + NameLength() 340 + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; } 341 342 bool IsValid() const 343 { 344 return NameLength() > 0 && value_block == 0; 345 // There is no maximum size, as the last entry spans until the 346 // end of the block 347 } 348 349 void Dump(bool full=false) const { 350 for (int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++) 351 dprintf("%02x ", ((uint8 *)this)[i]); 352 dprintf("\n"); 353 } 354 355 static size_t MinimumSize() 356 { 357 return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH; 358 } 359 } _PACKED; 360 361 362 extern fs_volume_ops gExt2VolumeOps; 363 extern fs_vnode_ops gExt2VnodeOps; 364 365 #endif // EXT2_H 366