-
-
Notifications
You must be signed in to change notification settings - Fork 187
/
ext4.hexpat
543 lines (469 loc) · 28.1 KB
/
ext4.hexpat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
#pragma author endes
#pragma description ext4 volume layout parser (until inodes)
// Decodes the ext4 superblock, group descriptors and inodes.
// Does not decode the directory entries, inode data, jornal or superblock backups.
// Heavily based on the linux kernel documentation:
// https://www.kernel.org/doc/html/latest/filesystems/ext4/
#pragma endian little
#pragma magic [53 EF] @ 0x438
#pragma pattern_limit 0x90000
import type.time;
import type.size;
import type.magic;
import std.core;
import std.mem;
import std.math;
enum ext4_super_state : u16 {
Cleanlyumounted = 0x01,
Errorsdetected = 0x02,
Orphansbeingrecovered = 0x03
};
enum ext4_super_errors : u16 {
Continue = 0x01,
RemountReadOnly = 0x02,
Panic = 0x03
};
enum ext4_super_creator : u32 {
Linux = 0x00,
Hurd = 0x01,
Masix = 0x02,
FreeBSD = 0x03,
Lites = 0x04
};
enum ext4_super_revision : u32 {
ORIGINAL = 0x00,
V2_DYNAMIC_REV = 0x01
};
bitfield ext4_super_compat {
COMPAT_DIR_PREALLOC : 1 [[comment("Directory preallocation.")]];
COMPAT_IMAGIC_INODES : 1 [[comment("“imagic inodes”. Not clear from the code what this does.")]];
COMPAT_HAS_JOURNAL : 1 [[comment("Has a journal.")]];
COMPAT_EXT_ATTR : 1 [[comment("Supports extended attributes.")]];
COMPAT_RESIZE_INODE : 1 [[comment("Has reserved GDT blocks for filesystem expansion.")]];
COMPAT_DIR_INDEX : 1 [[comment("Has directory indices.")]];
COMPAT_LAZY_BG : 1 [[comment("“Lazy BG”. Not in Linux kernel, seems to have been for uninitialized block groups?.")]];
COMPAT_EXCLUDE_INODE : 1 [[comment("“Exclude inode”. Not used.")]];
COMPAT_EXCLUDE_BITMAP : 1 [[comment("“Exclude bitmap”. Seems to be used to indicate the presence of snapshot-related exclude bitmaps? Not defined in linux kernel or used in e2fsprogs.")]];
COMPAT_SPARSE_SUPER2 : 1 [[comment("Sparse Super Block, v2. If this flag is set, the SB field s_backup_bgs points to the two block groups that contain backup superblocks.")]];
COMPAT_FAST_COMMIT : 1 [[comment("Journal fast commits supported.")]];
padding : 1;
RO_COMPAT_ORPHAN_PRESENT : 1 [[comment("Orphan file allocated. This is the special file for more efficient tracking of unlinked but still open inodes.")]];
};
bitfield ext4_super_incompat {
INCOMPAT_COMPRESSION : 1;
INCOMPAT_FILETYPE : 1 [[comment("Directory entries record the file type.")]];
INCOMPAT_RECOVER : 1 [[comment("Filesystem needs recovery.")]];
INCOMPAT_JOURNAL_DEV : 1 [[comment("Filesystem has a separate journal device.")]];
INCOMPAT_META_BG : 1 [[comment("Meta block groups.")]];
padding : 1;
INCOMPAT_EXTENTS : 1 [[comment("Files in this filesystem use extents.")]];
INCOMPAT_64BIT : 1 [[comment("Enable a filesystem size of 2^64 blocks.")]];
INCOMPAT_MMP : 1 [[comment("Multiple mount protection.")]];
INCOMPAT_FLEX_BG : 1 [[comment("Flexible block groups.")]];
INCOMPAT_EA_INODE : 1 [[comment("Inodes can be used to store large extended attribute values.")]];
padding : 1 [[comment("Data in directory entry.")]];
INCOMPAT_DIRDATA : 1;
INCOMPAT_CSUM_SEED : 1 [[comment("Metadata checksum seed is stored in the superblock.")]];
INCOMPAT_LARGEDIR : 1 [[comment("Large directory >2GB or 3-level htree.")]];
INCOMPAT_INLINE_DATA : 1 [[comment("Data in inode.")]];
INCOMPAT_ENCRYPT : 1 [[comment("Encrypted inodes are present on the filesystem.")]];
};
bitfield ext4_super_compat_ro {
RO_COMPAT_SPARSE_SUPER : 1 [[comment("Sparse superblocks.")]];
RO_COMPAT_LARGE_FILE : 1 [[comment("This filesystem has been used to store a file greater than 2GiB.")]];
RO_COMPAT_BTREE_DIR : 1 [[comment("Not used in linux kernel or e2fsprogs.")]];
RO_COMPAT_HUGE_FILE : 1 [[comment("This filesystem has files whose sizes are represented in units of logical blocks, not 512-byte sectors. This implies a very large file indeed!.")]];
RO_COMPAT_GDT_CSUM : 1 [[comment("Group descriptors have checksums.")]];
RO_COMPAT_DIR_NLINK : 1 [[comment("Indicates that the old ext3 32,000 subdirectory limit no longer applies.")]];
RO_COMPAT_EXTRA_ISIZE : 1 [[comment("Indicates that large inodes exist on this filesystem.")]];
RO_COMPAT_HAS_SNAPSHOT : 1 [[comment("This filesystem has a snapshot.")]];
RO_COMPAT_QUOTA : 1;
RO_COMPAT_BIGALLOC : 1 [[comment("This filesystem supports “bigalloc”, which means that file extents are tracked in units of clusters (of blocks) instead of blocks.")]];
RO_COMPAT_METADATA_CSUM : 1 [[comment("This filesystem supports metadata checksumming.")]];
RO_COMPAT_REPLICA : 1 [[comment("Filesystem supports replicas. This feature is neither in the kernel nor e2fsprogs.")]];
RO_COMPAT_READONLY : 1 [[comment("Read-only filesystem image.")]];
RO_COMPAT_PROJECT : 1 [[comment("Filesystem tracks project quotas.")]];
padding : 1;
RO_COMPAT_VERITY : 1 [[comment("Verity inodes may be present on the filesystem.")]];
RO_COMPAT_ORPHAN_PRESENT : 1 [[comment("Indicates orphan file may have valid orphan entries and thus we need to clean them up when mounting the filesystem.")]];
};
enum ext4_super_def_hash : u8 {
LEGACY = 0x00,
HALF_MD4 = 0x01,
TEA = 0x02,
LEGACY_UNSIGNED = 0x03,
HALF_MD4_UNSIGNED = 0x04,
TEA_UNSIGNED = 0x05
};
bitfield ext4_super_mountopts {
EXT4_DEFM_DEBUG : 1 [[comment("Print debugging info upon (re)mount.")]];
EXT4_DEFM_BSDGROUPS : 1 [[comment("New files take the gid of the containing directory (instead of the fsgid of the current process).")]];
EXT4_DEFM_XATTR_USER : 1 [[comment("Support userspace-provided extended attributes.")]];
EXT4_DEFM_ACL : 1 [[comment("Support POSIX access control lists (ACLs).")]];
EXT4_DEFM_UID16 : 1 [[comment("Do not support 32-bit UIDs.")]];
EXT4_DEFM_JMODE_DATA : 1 [[comment("All data and metadata are committed to the journal.")]];
EXT4_DEFM_JMODE_ORDER : 1 [[comment("All data are flushed to the disk before metadata are committed to the journal.")]];
padding : 1;
EXT4_DEFM_NOBARRIER : 1 [[comment("Disable write flushes.")]];
EXT4_DEFM_BLOCK_VALIDITY : 1 [[comment("Track which blocks in a filesystem are metadata and therefore should not be used as data blocks.")]];
EXT4_DEFM_DISCARD : 1 [[comment("Enable DISCARD support, where the storage device is told about blocks becoming unused.")]];
EXT4_DEFM_NODELALLOC : 1 [[comment("Disable delayed allocation.")]];
};
bitfield ext4_super_flags {
SIGNED_HASH_DIRECTORY : 1;
UNSIGNED_HASH_DIRECTORY : 1;
TEST_DEV_CODE : 1;
};
enum ext4_super_encrypt_algos : u8 {
ENCRYPTION_MODE_INVALID = 0x00,
ENCRYPTION_MODE_AES_256_XTS = 0x01,
ENCRYPTION_MODE_AES_256_GCM = 0x02,
ENCRYPTION_MODE_AES_256_CBC = 0x03,
};
struct ext4_super_block {
u32 s_inodes_count [[comment("Total inode count.")]];
u32 s_blocks_count_lo [[comment("Total block count.")]];
u32 s_r_blocks_count_lo [[comment("This number of blocks can only be allocated by the super-user.")]];
u32 s_free_blocks_count_lo [[comment("Free block count.")]];
u32 s_free_inodes_count [[comment("Free inode count.")]];
u32 s_first_data_block [[comment("First data block. This must be at least 1 for 1k-block filesystems and is typically 0 for all other block sizes.")]];
u32 s_log_block_size;
u32 s_log_cluster_size;
u64 block_size = std::math::pow(2, 10+s_log_block_size);
u64 cluster_size = std::math::pow(2, 10+s_log_cluster_size);
u32 s_blocks_per_group [[comment("Blocks per group.")]];
u32 s_clusters_per_group [[comment("Clusters per group, if bigalloc is enabled. Otherwise s_clusters_per_group must equal s_blocks_per_group.")]];
u32 s_inodes_per_group [[comment("Inodes per group.")]];
type::time32_t s_mtime [[comment("Last mount time, in seconds since the epoch.")]];
type::time32_t s_wtime [[comment("Last write time, in seconds since the epoch.")]];
u16 s_mnt_count [[comment("Number of mounts since the last fsck.")]];
u16 s_max_mnt_count [[comment("Number of mounts beyond which a fsck is needed.")]];
type::Magic<"\x53\xEF"> s_magic;
ext4_super_state s_state [[comment("File system state.")]];
ext4_super_errors s_errors [[comment("Behaviour when detecting errors.")]];
u16 s_minor_rev_level [[comment("Minor revision level.")]];
type::time32_t s_lastcheck [[comment("Time of last check, in seconds since the epoch.")]];
u32 s_checkinterval [[comment("Maximum time between checks, in seconds.")]];
ext4_super_creator s_creator_os [[comment("Creator OS.")]];
ext4_super_revision s_rev_level [[comment("Revision level.")]];
u16 s_def_resuid [[comment("Default uid for reserved blocks.")]];
u16 s_def_resgid [[comment("Default gid for reserved blocks.")]];
// EXT2_DYNAMIC_REV superblock
if (s_rev_level >= ext4_super_revision::V2_DYNAMIC_REV) {
u32 s_first_ino [[comment("First non-reserved inode.")]];
u16 s_inode_size [[comment("Size of inode structure, in bytes.")]];
u16 s_block_group_nr [[comment("Block group number of this superblock.")]];
ext4_super_compat s_feature_compat [[comment("Compatible feature set flags. Kernel can still read/write this fs even if it doesn’t understand a flag; fsck should not do that.")]];
padding[2];
ext4_super_incompat s_feature_incompat [[comment("Incompatible feature set. If the kernel or fsck doesn’t understand one of these bits, it should stop.")]];
padding[1];
ext4_super_compat_ro s_feature_ro_compat [[comment("Readonly-compatible feature set. If the kernel doesn’t understand one of these bits, it can still mount read-only.")]];
padding[1];
u8 s_uuid[16] [[comment("128-bit UUID for volume.")]];
char s_volume_name[16] [[comment("Volume label.")]];
char s_last_mounted[64] [[comment("Directory where filesystem was last mounted.")]];
if (s_feature_incompat.INCOMPAT_COMPRESSION) {
u32 s_algorithm_usage_bitmap;
} else {
padding[4];
}
// Performance hints
if (s_feature_compat.COMPAT_DIR_PREALLOC) {
u8 s_prealloc_blocks [[comment("Number of blocks to try to preallocate for ... files? (Not used in e2fsprogs/Linux).")]];
u8 s_prealloc_dir_blocks [[comment("Number of blocks to preallocate for directories. (Not used in e2fsprogs/Linux).")]];
} else {
padding[2];
}
u16 s_reserved_gdt_blocks [[comment("Number of reserved GDT entries for future filesystem expansion.")]];
// Journaling support
if (s_feature_compat.COMPAT_HAS_JOURNAL) {
u8 s_journal_uuid[16] [[comment("UUID of journal superblock.")]];
u32 s_journal_inum [[comment("Inode number of journal file.")]];
if (s_feature_incompat.INCOMPAT_JOURNAL_DEV) {
u32 s_journal_dev [[comment("Device number of journal file.")]];
} else {
padding[4];
}
} else {
padding[24];
}
u32 s_last_orphan [[comment("Inode start of list of orphaned inodes to delete.")]];
u32 s_hash_seed[4] [[comment("HTREE hash seed.")]];
ext4_super_def_hash s_def_hash_version [[comment("Default hash algorithm to use for directory hashes.")]];
u8 s_jnl_backup_type [[comment("If this value is 0 or EXT3_JNL_BACKUP_BLOCKS (1), then the s_jnl_blocks field contains a duplicate copy of the inode’s i_block[] array and i_size.")]];
if (s_feature_incompat.INCOMPAT_64BIT) {
u16 s_desc_size [[comment("Size of group descriptors, in bytes, if the 64bit incompat feature flag is set.")]];
} else {
padding[2];
}
ext4_super_mountopts s_default_mount_opts [[comment("Default mount options.")]];
padding[2];
if (s_feature_incompat.INCOMPAT_META_BG) {
u32 s_first_meta_bg [[comment("First metablock block group, if the meta_bg feature is enabled.")]];
} else {
padding[4];
}
type::time32_t s_mkfs_time [[comment("When the filesystem was created, in seconds since the epoch.")]];
u32 s_jnl_blocks[17] [[comment("Backup copy of the journal inode’s i_block[] array in the first 15 elements and i_size_high and i_size in the 16th and 17th elements, respectively.")]];
if (s_feature_incompat.INCOMPAT_64BIT) {
u32 s_blocks_count_hi [[comment("High 32-bits of the block count.")]];
u32 s_r_blocks_count_hi [[comment("High 32-bits of the reserved block count.")]];
u32 s_free_blocks_count_hi [[comment("High 32-bits of the free block count.")]];
u64 s_blocks_count = (u64(s_blocks_count_hi) << 32) + s_blocks_count_lo;
u64 s_r_blocks_count = (u64(s_r_blocks_count_hi) << 32) + s_r_blocks_count_lo;
u64 s_free_blocks_count = (u64(s_free_blocks_count_hi) << 32) + s_free_blocks_count_lo;
u64 groups_count = std::math::ceil(s_blocks_count/float(s_blocks_per_group));
} else {
padding[12];
u64 s_blocks_count = s_blocks_count_lo;
u64 s_r_blocks_count = s_r_blocks_count_lo;
u64 s_free_blocks_count = s_free_blocks_count_lo;
u64 groups_count = std::math::ceil(s_blocks_count/float(s_blocks_per_group));
}
if (s_feature_ro_compat.RO_COMPAT_EXTRA_ISIZE) {
u16 s_min_extra_isize [[comment("All inodes have at least # bytes.")]];
u16 s_want_extra_isize [[comment("New inodes should reserve # bytes.")]];
} else {
padding[4];
}
ext4_super_flags s_flags [[comment("Miscellaneous flags.")]];
padding[3];
u16 s_raid_stride [[comment("RAID stride. This is the number of logical blocks read from or written to the disk before moving to the next disk. This affects the placement of filesystem metadata.")]];
if (s_feature_incompat.INCOMPAT_MMP) {
u16 s_mmp_interval [[comment("Number of seconds to wait in multi-mount prevention (MMP) checking.")]];
u64 s_mmp_block [[comment("Block number for multi-mount protection data.")]];
} else {
padding[10];
}
u32 s_raid_stripe_width [[comment("RAID stripe width. This is the number of logical blocks read from or written to the disk before coming back to the current disk.")]];
if (s_feature_incompat.INCOMPAT_FLEX_BG) {
u8 s_log_groups_per_flex;
u64 groups_per_flex = std::math::pow(2, s_log_groups_per_flex);
} else {
padding[1];
}
if (s_feature_ro_compat.RO_COMPAT_METADATA_CSUM) {
u8 s_checksum_type [[comment("Metadata checksum algorithm type.")]];
} else {
padding[1];
}
padding[2];
u64 s_kbytes_written [[comment("Number of KiB written to this filesystem over its lifetime.")]];
if (s_feature_ro_compat.RO_COMPAT_HAS_SNAPSHOT) {
u32 s_snapshot_inum [[comment("inode number of active snapshot. (Not used in e2fsprogs/Linux.)")]];
u32 s_snapshot_id [[comment("Sequential ID of active snapshot. (Not used in e2fsprogs/Linux.)")]];
u64 s_snapshot_r_blocks_count [[comment("Number of blocks reserved for active snapshot’s future use. (Not used in e2fsprogs/Linux.)")]];
u32 s_snapshot_list [[comment("inode number of the head of the on-disk snapshot list. (Not used in e2fsprogs/Linux.)")]];
} else {
padding[20];
}
u32 s_error_count [[comment("Number of errors seen.")]];
if (s_error_count > 0) {
type::time32_t s_first_error_time [[comment("First time an error happened.")]];
u32 s_first_error_ino [[comment("inode involved in first error.")]];
u64 s_first_error_block [[comment("Number of block involved of first error.")]];
char s_first_error_func[32] [[comment("Name of function where the error happened.")]];
u32 s_first_error_line [[comment("Line number where error happened.")]];
type::time32_t s_last_error_time [[comment("Last time an error happened.")]];
u32 s_last_error_ino [[comment("inode involved in most recent error.")]];
u32 s_last_error_line [[comment("Line number where most recent error happened.")]];
u64 s_last_error_block [[comment("Number of block involved in most recent error.")]];
char s_last_error_func[32] [[comment("Name of function where the most recent error happened.")]];
} else {
padding[104];
}
char s_mount_opts[64] [[comment("ASCIIZ string of mount options.")]];
if (s_feature_ro_compat.RO_COMPAT_QUOTA) {
u32 s_usr_quota_inum [[comment("Inode number of user quota file.")]];
u32 s_grp_quota_inum [[comment("Inode number of group quota file.")]];
} else {
padding[8];
}
u32 s_overhead_blocks [[comment("Overhead blocks/clusters in fs. (Huh? This field is always zero, which means that the linux kernel calculates it dynamically.)")]];
if (s_feature_compat.COMPAT_SPARSE_SUPER2) {
u32 s_backup_bgs[2] [[comment("Block groups containing superblock backups.")]];
} else {
padding[8];
}
if (s_feature_incompat.INCOMPAT_ENCRYPT) {
ext4_super_encrypt_algos s_encrypt_algos[4] [[comment("Encryption algorithms in use. There can be up to four algorithms in use at any time.")]];
u8 s_encrypt_pw_salt[16] [[comment("Salt for the string2key algorithm for encryption.")]];
} else {
padding[20];
}
u32 s_lpf_ino [[comment("Inode number of lost+found.")]];
if (s_feature_ro_compat.RO_COMPAT_PROJECT) {
u32 s_prj_quota_inum [[comment("Inode that tracks project quotas.")]];
} else {
padding[4];
}
if (s_feature_ro_compat.RO_COMPAT_METADATA_CSUM) {
u32 s_checksum_seed [[comment("Checksum seed used for metadata_csum calculations. This value is crc32c(~0, $orig_fs_uuid).")]];
} else {
padding[4];
}
u8 s_wtime_hi [[comment("Upper 8 bits of the s_wtime field.")]];
u8 s_mtime_hi [[comment("Upper 8 bits of the s_mtime field.")]];
u8 s_mkfs_time_hi [[comment("Upper 8 bits of the s_mkfs_time field.")]];
u8 s_lastcheck_hi [[comment("Upper 8 bits of the s_lastcheck field.")]];
u8 s_first_error_time_hi [[comment("Upper 8 bits of the s_first_error_time field.")]];
u8 s_last_error_time_hi [[comment("Upper 8 bits of the s_last_error_time field.")]];
padding[2];
u16 s_encoding [[comment("Filename charset encoding.")]];
u16 s_encoding_flags [[comment("Filename charset encoding flags.")]];
if (s_feature_compat.RO_COMPAT_ORPHAN_PRESENT) {
u32 s_orphan_file_inum [[comment("Orphan file inode number.")]];
} else {
padding[4];
}
padding[376];
if (s_feature_ro_compat.RO_COMPAT_METADATA_CSUM) {
u32 s_checksum [[comment("Superblock checksum.")]];
} else {
padding[4];
}
}
};
ext4_super_block super_block @ 0x400;
fn block_to_address(u32 block) {
return super_block.block_size * block;
};
fn block_pointer_to_address(u32 block) {
return block_to_address(block) - block;
};
struct ext4_bitmap {
u8 data[super_block.block_size];
};
bitfield ext4_i_mode {
S_IXOTH : 1 [[comment("Others may execute.")]];
S_IWOTH : 1 [[comment("Others may write.")]];
S_IROTH : 1 [[comment("Others may read.")]];
S_IXGRP : 1 [[comment("Group members may execute.")]];
S_IWGRP : 1 [[comment("Group members may write.")]];
S_IRGRP : 1 [[comment("Group members may read.")]];
S_IXUSR : 1 [[comment("Owner may execute.")]];
S_IWUSR : 1 [[comment("Owner may write.")]];
S_IRUSR : 1 [[comment("Owner may read.")]];
S_ISVTX : 1 [[comment("Sticky bit.")]];
S_ISGID : 1 [[comment("Set GID.")]];
S_ISUID : 1 [[comment("Set UID.")]];
S_IFIFO : 1 [[comment("FIFO.")]];
S_IFCHR : 1 [[comment("Character device.")]];
S_IFDIR : 1 [[comment("Directory.")]];
S_IFREG : 1 [[comment("Regular file.")]];
};
bitfield ext4_i_flags {
EXT4_SECRM_FL : 1 [[comment("This file requires secure deletion.")]];
EXT4_UNRM_FL : 1 [[comment("This file should be preserved, should undeletion be desired.")]];
EXT4_COMPR_FL : 1 [[comment("File is compressed.")]];
EXT4_SYNC_FL : 1 [[comment("All writes to the file must be synchronous.")]];
EXT4_IMMUTABLE_FL : 1 [[comment("File is immutable.")]];
EXT4_APPEND_FL : 1 [[comment("File can only be appended.")]];
EXT4_NODUMP_FL : 1 [[comment("The dump utility should not dump this file.")]];
EXT4_NOATIME_FL : 1 [[comment("Do not update access time.")]];
EXT4_DIRTY_FL : 1 [[comment("Dirty compressed file.")]];
EXT4_COMPRBLK_FL : 1 [[comment("File has one or more compressed clusters.")]];
EXT4_NOCOMPR_FL : 1 [[comment("Do not compress file.")]];
EXT4_ENCRYPT_FL : 1 [[comment("Encrypted inode.")]];
EXT4_INDEX_FL : 1 [[comment("Directory has hashed indexes.")]];
EXT4_IMAGIC_FL : 1 [[comment("AFS magic directory.")]];
EXT4_JOURNAL_DATA_FL : 1 [[comment("File data must always be written through the journal.")]];
EXT4_NOTAIL_FL : 1 [[comment("File tail should not be merged.")]];
EXT4_DIRSYNC_FL : 1 [[comment("All directory entry data should be written synchronously.")]];
EXT4_TOPDIR_FL : 1 [[comment("Top of directory hierarchy.")]];
EXT4_HUGE_FILE_FL : 1 [[comment("This is a huge file.")]];
EXT4_EXTENTS_FL : 1 [[comment("Inode uses extents.")]];
EXT4_VERITY_FL : 1 [[comment("Verity protected file.")]];
EXT4_EA_INODE_FL : 1 [[comment("Inode stores a large extended attribute value in its data blocks.")]];
EXT4_EOFBLOCKS_FL : 1 [[comment("This file has blocks allocated past EOF.")]];
padding : 1;
EXT4_SNAPFILE_FL : 1 [[comment("Inode is a snapshot.")]];
padding : 1;
EXT4_SNAPFILE_DELETED_FL : 1 [[comment("Snapshot is being deleted.")]];
EXT4_SNAPFILE_SHRUNK_FL : 1 [[comment("Snapshot shrink has completed.")]];
EXT4_INLINE_DATA_FL : 1 [[comment("Inode has inline data.")]];
EXT4_PROJINHERIT_FL : 1 [[comment("Create children with the same project ID.")]];
padding : 1;
EXT4_RESERVED_FL : 1 [[comment("Reserved for ext4 library.")]];
};
struct ext4_inode {
ext4_i_mode i_mode [[comment("File mode.")]];
u16 i_uid [[comment("Lower 16-bits of Owner UID.")]];
u32 i_size [[comment("Lower 32-bits of size in bytes.")]];
type::time32_t i_atime [[comment("Last access time.")]];
type::time32_t i_ctime [[comment("Last inode change time.")]];
type::time32_t i_mtime [[comment("Last data modification time.")]];
type::time32_t i_dtime [[comment("Deletion Time.")]];
u16 i_gid [[comment("Lower 16-bits of GID.")]];
u16 i_links_count [[comment("Hard link count.")]];
u32 i_blocks_lo [[comment("Lower 32-bits of “block” count.")]];
ext4_i_flags i_flags [[comment("Inode flags.")]];
u32 i_osd1 [[comment("Depends of the OS.")]];
u32 i_block[15] [[comment("Block map or extent tree.")]];
u32 i_generation [[comment("File version (for NFS).")]];
u32 i_file_acl [[comment("Lower 32-bits of extended attribute block.")]];
u32 i_dir_acl [[comment("Upper 32-bits of file/directory size.")]];
u32 i_faddr [[comment("Fragment address.")]];
u8 i_osd2[12] [[comment("Depends of the OS.")]];
if (super_block.s_rev_level >= ext4_super_revision::V2_DYNAMIC_REV && super_block.s_inode_size > 0x80) {
u16 i_extra_isize [[comment("Size of this inode - 128.")]];
u16 i_checksum_hi [[comment("Upper 16-bits of the inode checksum.")]];
if (super_block.s_inode_size > 0x84) {
u32 i_ctime_extra [[comment("Extra change time bits.")]];
u32 i_mtime_extra [[comment("Extra modification time bits.")]];
u32 i_atime_extra [[comment("Extra access time bits.")]];
u32 i_crtime [[comment("File creation time.")]];
u32 i_crtime_extra [[comment("Extra file creation time bits.")]];
if (super_block.s_inode_size > 0x98) {
u32 i_version_hi [[comment("Upper 32-bits for version number.")]];
if (super_block.s_inode_size > 0x9C) {
u32 i_projid [[comment("Project ID.")]];
if (super_block.s_inode_size > 0xA0) {
padding[super_block.s_inode_size - 0xA0];
}
}
}
}
}
};
bitfield ext4_bg_flags {
EXT4_BG_INODE_UNINIT : 1 [[comment("Inode table and bitmap are not initialized.")]];
EXT4_BG_BLOCK_UNINIT : 1 [[comment("Block bitmap is not initialized.")]];
EXT4_BG_INODE_ZEROED : 1 [[comment("Inode table is zeroed.")]];
};
struct ext4_group_desc {
ext4_bitmap *bg_block_bitmap : u32 [[pointer_base("block_pointer_to_address"), comment("Lower 32-bits of location of block bitmap.")]];
ext4_bitmap *bg_inode_bitmap : u32 [[pointer_base("block_pointer_to_address"), comment("Lower 32-bits of location of inode bitmap.")]];
ext4_inode *bg_inode_table[super_block.s_inodes_per_group] : u32 [[pointer_base("block_pointer_to_address"), comment("Lower 32-bits of location of inode table.")]];
u16 bg_free_blocks_count [[comment("Lower 16-bits of free block count.")]];
u16 bg_free_inodes_count [[comment("Lower 16-bits of free inode count.")]];
u16 bg_used_dirs_count [[comment("Lower 16-bits of directory count.")]];
ext4_bg_flags bg_flags [[comment("Block group flags.")]];
padding[1];
u32 bg_exclude_bitmap_lo [[comment("Lower 32-bits of location of snapshot exclusion bitmap.")]];
u16 bg_block_bitmap_csum_lo [[comment("Lower 16-bits of the block bitmap checksum.")]];
u16 bg_inode_bitmap_csum_lo [[comment("Lower 16-bits of the inode bitmap checksum.")]];
u16 bg_itable_unused_lo [[comment("Lower 16-bits of unused inode count.")]];
u16 bg_checksum [[comment("Group descriptor checksum.")]];
};
struct ext4_group_desc_64_bit : ext4_group_desc {
u32 bg_block_bitmap_hi [[comment("Upper 32-bits of location of block bitmap.")]];
u32 bg_inode_bitmap_hi [[comment("Upper 32-bits of location of inodes bitmap.")]];
u32 bg_inode_table_hi [[comment("Upper 32-bits of location of inodes table.")]];
u16 bg_free_blocks_count_hi [[comment("Upper 16-bits of free block count.")]];
u16 bg_free_inodes_count_hi [[comment("Upper 16-bits of free inode count.")]];
u16 bg_used_dirs_count_hi [[comment("Upper 16-bits of directory count.")]];
u16 bg_itable_unused_hi [[comment("Upper 16-bits of unused inode count.")]];
u32 bg_exclude_bitmap_hi [[comment("Upper 32-bits of location of snapshot exclusion bitmap.")]];
u16 bg_block_bitmap_csum_hi [[comment("Upper 16-bits of the block bitmap checksum.")]];
u16 bg_inode_bitmap_csum_hi [[comment("Upper 16-bits of the inode bitmap checksum.")]];
padding[4];
};
struct ext4_group_descriptors {
if (super_block.s_rev_level >= ext4_super_revision::V2_DYNAMIC_REV && super_block.s_feature_incompat.INCOMPAT_64BIT) {
ext4_group_desc_64_bit group_desc[super_block.groups_count];
} else {
ext4_group_desc group_desc[super_block.groups_count];
}
};
ext4_group_descriptors group_descs @ block_to_address(2);