patterns/fs: Refactor all partition types into a FS module

This commit is contained in:
Nik
2025-05-25 19:51:32 +02:00
committed by GitHub
parent d96bfbb942
commit db4d62aa20
9 changed files with 366 additions and 99 deletions

108
patterns/fs/fat32.hexpat Normal file
View File

@@ -0,0 +1,108 @@
import std.core;
u64 bytesPerCluster;
struct FSInfo {
u32 leadSignature;
padding[480];
u32 structSignature;
u32 freeClusterCount;
u32 nextFreeCluster;
padding[12];
u32 trailSignature;
};
bitfield SequenceNumber {
padding : 1;
lastLogical : 1;
padding : 1;
number : 5;
} [[bitfield_order(std::core::BitfieldOrder::MostToLeastSignificant, 8)]];
enum EntryStatus : u8 {
Regular = 0x00,
DotEntry = 0x2E,
DeletedEntry = 0xE5
};
union EntryStatusOrSequenceNumber {
EntryStatus entryStatus;
SequenceNumber sequenceNumber;
};
bitfield Attributes {
readOnly : 1;
hidden : 1;
systemFile : 1;
volumeLabel : 1;
subdirectory : 1;
archive : 1;
padding : 2;
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
struct DirEntry {
char fileName[8];
char extension[3];
Attributes attributes;
u8 reserved[10];
u16 time, date;
u16 startingCluster;
u32 fileSize;
u8 data[fileSize] @ startingCluster * bytesPerCluster;
};
struct VFATDirEntry {
EntryStatusOrSequenceNumber entryStatusOrSequenceNumber;
char16 name1[5];
Attributes attributes;
u8 type;
u8 nameChecksum;
char16 name2[6];
u16 startingCluster;
char16 name3[2];
if (entryStatusOrSequenceNumber.sequenceNumber.number > 1)
VFATDirEntry nextLogicalEntry;
else
DirEntry physicalEntry;
};
struct FAT32 {
u8 jmpCode[3];
char oemName[8];
u16 bytesPerSector;
u8 sectorsPerCluster;
u16 reservedAreaSize;
u8 numFats;
u16 rootEntryCount;
u16 numSectors;
u8 mediaType;
u16 fatSize;
u16 sectorsPerTrack;
u16 numHeads;
u32 numHiddenSectors;
u32 numFsSectors;
u32 numFatSectors;
u16 extFlags;
u16 fsVersion;
u32 rootCluster;
u16 fsInfoSector;
u16 backupBootSector;
padding[12];
u8 driveNumber;
padding[1];
u8 bootSignature;
u32 volumeID;
char volumeLabel[11];
char fsType[8];
u8 bootstrapCode[420];
u16 signature;
bytesPerCluster = (sectorsPerCluster * 1024) * bytesPerSector;
FSInfo fsInfo @ addressof(this) + fsInfoSector * bytesPerSector;
VFATDirEntry rootDirEntry @ addressof(this) + rootCluster * bytesPerCluster;
};
FAT32 fat32 @ 0x00;

View File

@@ -25,7 +25,7 @@ struct GUID {
u16 Data2;
u16 Data3;
u8 Data4[8];
};
} [[static]];
bitfield RUNLIST_HEADER {
unsigned offset : 4;
@@ -36,6 +36,9 @@ struct RUNLIST {
RUNLIST_HEADER header;
u8 count[header.length];
u8 lcn[header.offset];
if (header.length == 0)
break;
};
struct BIOS_PARAMETER_BLOCK {
@@ -101,13 +104,13 @@ enum ATTR_TYPES : u32 {
};
enum ATTR_DEF_FLAGS : u32 {
ATTR_DEF_INDEXABLE = 0x02,
ATTR_DEF_MULTIPLE = 0x04,
ATTR_DEF_NOT_ZERO = 0x08,
ATTR_DEF_INDEXED_UNIQUE = 0x10,
ATTR_DEF_NAMED_UNIQUE = 0x20,
ATTR_DEF_RESIDENT = 0x40,
ATTR_DEF_ALWAYS_LOG = 0x80,
ATTR_DEF_INDEXABLE = 0x02,
ATTR_DEF_MULTIPLE = 0x04,
ATTR_DEF_NOT_ZERO = 0x08,
ATTR_DEF_INDEXED_UNIQUE = 0x10,
ATTR_DEF_NAMED_UNIQUE = 0x20,
ATTR_DEF_RESIDENT = 0x40,
ATTR_DEF_ALWAYS_LOG = 0x80,
};
enum COLLATION_RULES : u32 {
@@ -176,12 +179,12 @@ struct STANDARD_INFORMATION_HEADER {
u64 last_mft_change_time;
u64 last_access_time;
FILE_ATTR_FLAGS file_attributes;
};
} [[static]];
struct STANDARD_INFORMATION_OLD {
STANDARD_INFORMATION_HEADER header [[inline]];
u8 reserved12[12];
};
} [[static]];
struct STANDARD_INFORMATION {
STANDARD_INFORMATION_HEADER header [[inline]];
@@ -192,17 +195,17 @@ struct STANDARD_INFORMATION {
u32 security_id;
u64 quota_charged;
u64 usn;
};
} [[static]];
struct FILE_NAME_ATTR_PACKED {
u16 packed_ea_size;
u16 reserved;
};
} [[static]];
union FILE_NAME_ATTR_FORM {
FILE_NAME_ATTR_PACKED packed [[inline]];
u32 reparse_point_tag;
};
} [[static]];
struct FILE_NAME_ATTR {
leMFT_REF parent_directory;
@@ -252,7 +255,7 @@ struct VOLUME_INFORMATION {
u8 major_ver;
u8 minor_ver;
VOLUME_FLAGS flags;
};
} [[static]];
enum SECURITY_DESCRIPTOR_CONTROL : u16 {
SE_OWNER_DEFAULTED = 0x0001,
@@ -671,8 +674,8 @@ struct RESTART_PAGE_HEADER {
};
enum RESTART_AREA_FLAGS : u16 {
RESTART_VOLUME_IS_CLEAN = 0x0002,
RESTART_SPACE_FILLER = 0xffff,
RESTART_VOLUME_IS_CLEAN = 0x0002,
RESTART_SPACE_FILLER = 0xffff,
};
struct RESTART_AREA {
@@ -768,7 +771,7 @@ struct ATTR_RECORD {
}
}
RUNLIST runlist[];
RUNLIST runlist[while(true)];
} else {
u32 value_offset_delta = 0;
if (value_offset > (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes)) {
@@ -988,7 +991,7 @@ MFT_RECORD mft_sec @ nbs.mft_lcn * cluster_size + 9 * mft_rec_size [[name("$Secu
// ============= $UpCase =============
MFT_RECORD mft_uc @ nbs.mft_lcn * cluster_size + 10 * mft_rec_size [[name("$UpCase")]];
u8 uc_tbl[1] @ mft_get_dat_attr_lcn(mft_uc) * cluster_size [[name("$UpCase, tabl")]];
u8 uc_tbl[1] @ mft_get_dat_attr_lcn(mft_uc) * cluster_size [[name("$UpCase, tabl")]];
// ============= $Extend =============
MFT_RECORD mft_ext @ nbs.mft_lcn * cluster_size + 11 * mft_rec_size [[name("$Extend")]];

231
patterns/fs/pattern.hexpat Normal file
View File

@@ -0,0 +1,231 @@
#pragma author WerWolv
#pragma description Drive File System
#pragma MIME application/x-ima
import std.io;
import std.core;
import type.magic;
import type.guid;
import type.base;
import * from fs.fat32 as FAT32Partition;
import * from fs.exfat as ExFATPartition;
import * from fs.ntfs as NTFSPartition;
const u32 SectorSize = 512;
struct DiskTimeStamp {
u8 seconds, minutes, hours;
};
enum DiskProtection : u16 {
None = 0x0000,
CopyProtected = 0x5A5A
};
bitfield CHS {
h : 8;
s : 6;
c : 10;
} [[format("chs_formatter")]];
fn chs_formatter(CHS chs) {
return std::format("({:X}, {:X}, {:X}) | 0x{:X}", chs.c, chs.h, chs.s, (chs.c * 16 + chs.h) * 63 + (chs.s - 1));
};
enum PartitionStatus : u8 {
None = 0x00,
Active = 0x80
};
enum MBRPartitionType : u8 {
Empty = 0x00,
FAT12 = 0x01,
XENIXRoot = 0x02,
XENIXUsr = 0x03,
FAT16_16_32MB = 0x04,
ExtendedCHS = 0x05,
FAT16_32MBPlus = 0x06,
NTFS = 0x07,
AIX = 0x08,
AIXBootable = 0x09,
OS2BootManager = 0x0A,
FAT32_CHS = 0x0B,
FAT32_LBA = 0x0C,
FAT16_LBA = 0x0E,
ExtendedLBA = 0x0F,
OPUS = 0x10,
HiddenFAT12 = 0x11,
CompaqDiagnostics = 0x12,
HiddenFAT16_16_32MB = 0x14,
HiddenFAT16_32MBPlus = 0x16,
HiddenNTFS = 0x17,
ASTSmartSleep = 0x18,
HiddenFAT32_CHS = 0x1B,
HiddenFAT32_LBA = 0x1C,
HiddenFAT16_LBA = 0x1E,
NEC_DOS = 0x24,
WindowsRecovery = 0x27,
Plan9 = 0x39,
PowerQuest = 0x3C,
Venix286 = 0x40,
PPC_PReP_Boot = 0x41,
SFS = 0x42,
QNX4_x = 0x4D,
QNX4_x_2ndPart = 0x4E,
QNX4_x_3rdPart = 0x4F,
OnTrackDM = 0x50,
OnTrackDM6Aux1 = 0x51,
CP_M = 0x52,
OnTrackDM6Aux3 = 0x53,
OnTrackDM6 = 0x54,
EZDrive = 0x55,
GoldenBow = 0x56,
PriamEDisk = 0x5C,
SpeedStor = 0x61,
GNU_HURD = 0x63,
NovellNetware286 = 0x64,
NovellNetware386 = 0x65,
DiskSecureMultiBoot = 0x70,
PC_IX = 0x75,
XOSL = 0x78,
OldMinix = 0x80,
LinuxMinix = 0x81,
LinuxSwap = 0x82,
Linux = 0x83,
OS2HiddenCDrive = 0x84,
LinuxExtended = 0x85,
NTFSVolumeSet = 0x86,
NTFSVolumeSet2 = 0x87,
LinuxLVM = 0x8E,
Amoeba = 0x93,
AmoebaBBT = 0x94,
BSD_OS = 0x9F,
IBMThinkpadHibernation = 0xA0,
FreeBSD = 0xA5,
OpenBSD = 0xA6,
NeXTSTEP = 0xA7,
MacOSX = 0xA8,
NetBSD = 0xA9,
BSDIFS = 0xB7,
BSDISwap = 0xB8,
BootWizardHidden = 0xBB,
DRDOSFAT12 = 0xC1,
DRDOSFAT16 = 0xC4,
DRDOSFAT16B = 0xC6,
Syrinx = 0xC7,
NonFSData = 0xDA,
CP_M_CTOS = 0xDB,
DellUtility = 0xDE,
BootIt = 0xDF,
DOSAccess = 0xE1,
DOSRO = 0xE3,
SpeedStor2 = 0xE4,
BeOS = 0xEB,
GPTProtective = 0xEE,
EFI_System = 0xEF,
LinuxPA_RISC = 0xF0,
SpeedStor3 = 0xF1,
DOSSecondary = 0xF2,
LinuxRAID = 0xFD,
LANstep = 0xFE,
Unknown = 0xFF
};
enum GPTPartitionType : u128 {
UnusedEntry = u128("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
MicrosoftReservedPartition = u128("\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE"),
PartitionBasicData = u128("\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7")
};
bitfield GPTAttributes {
bool platform_required : 1;
padding : 59;
bool read_only : 1;
bool shadow_copy : 1;
bool hidden : 1;
bool no_drive_letter : 1;
};
struct GPTEntry {
GPTPartitionType partitionType [[no_unique_address]];
type::GUID partitionTypeGuid;
type::GUID partitionGuid;
u64 firstLba;
u64 lastLba;
GPTAttributes attribute;
char16 partitionName[36];
padding[parent.entrySize - 128];
u64 partitionOffset = firstLba * SectorSize [[export]];
match (partitionType) {
(GPTPartitionType::UnusedEntry): {}
(GPTPartitionType::MicrosoftReservedPartition):
std::mem::Bytes<(lastLba - firstLba + 1) * SectorSize> microsoftReservedPartition @ partitionOffset;
(GPTPartitionType::PartitionBasicData): {}
(_): std::error(std::format("Unknown GPT Partition Type {}", partitionType));
}
};
struct GUIDPartitionTable {
type::Magic<"EFI PART"> signature;
u16 versionMinor;
u16 versionMajor;
u32 headerSize;
type::Hex<u32> headerCrc32;
u32 reserved;
u64 currentLba;
u64 backupLba;
u64 firstUsableLba;
u64 lastUsableLba;
type::GUID diskGuid;
u64 entryLba;
u32 entryCount;
u32 entrySize;
type::Hex<u32> entryCrc32;
GPTEntry entries[entryCount] @ addressof(this) + (entryLba - currentLba) * SectorSize;
};
struct PartitionEntry {
PartitionStatus status;
CHS chsFirstSectorAddress;
MBRPartitionType type;
CHS chsLastSectorAddress;
u32 lbaFirstSectorAddress;
u32 numSectors;
u64 partitionOffset = lbaFirstSectorAddress * SectorSize [[export]];
match (type) {
(MBRPartitionType::Empty): continue;
(MBRPartitionType::FAT32_LBA | MBRPartitionType::FAT32_CHS):
FAT32Partition fat32Partition @ partitionOffset;
(MBRPartitionType::NTFS): {
char magic[8] @ partitionOffset + 3;
if (magic == "NTFS ")
NTFSPartition ntfsPartition @ partitionOffset;
else if (magic == "EXFAT ")
ExFATPartition exfatPartiton @ partitionOffset;
else
std::error("Unknown MBR partition with NTFS Type ID");
}
(MBRPartitionType::GPTProtective):
GUIDPartitionTable gpt @ partitionOffset;
(_): std::error(std::format("Unknown MBR Partition Type {}", type));
}
};
struct MasterBootRecord {
u8 bootstrapCodeArea1[218];
padding[2];
u8 originalPhysicalDrive;
DiskTimeStamp diskTimeStamp;
u8 bootstrapCodeArea2[216];
u32 diskSignature;
DiskProtection diskProtection;
PartitionEntry partitionEntries[4];
u16 bootSignature;
};
MasterBootRecord mbr @ 0x00;

View File

@@ -1,75 +0,0 @@
#pragma author RadxaYuntian
#pragma description Master Boot Record & GUID Partition Table
#pragma endian little
import type.base;
import type.guid;
#ifndef SECTOR_SIZE
#define SECTOR_SIZE 512
#endif
bitfield CHSAddress {
u8 head;
sector : 6;
cylinder: 10;
};
struct MBREntry {
u8 status;
CHSAddress first_chs;
u8 type;
CHSAddress last_chs;
u32 first_lba;
u32 sector_count;
};
struct MasterBootRecord {
padding[446];
MBREntry entries[4];
type::Hex<u16> boot_signature;
padding[SECTOR_SIZE - 512];
};
bitfield GPTAttributes {
bool platform_required : 1;
padding : 59;
bool read_only : 1;
bool shadow_copy : 1;
bool hidden : 1;
bool no_drive_letter : 1;
};
struct GPTEntry {
type::GUID partition_type;
type::GUID partition_guid;
u64 first_lba;
u64 last_lba;
GPTAttributes attribute;
char16 partition_name[36];
padding[parent.entry_size - 128];
};
struct GUIDPartitionTable {
char signature[8]; // "EFI PART"
u16 version_minor;
u16 version_major;
u32 header_size;
type::Hex<u32> header_crc32; // from 0x0 to 0x5b
u32 reserved; // must be 0
u64 current_lba;
u64 backup_lba;
u64 first_usable_lba;
u64 last_usable_lba;
type::GUID disk_guid;
u64 entry_lba;
u32 entry_count;
u32 entry_size;
type::Hex<u32> entry_crc32;
padding[SECTOR_SIZE - 92]; // end of first LBA
padding[SECTOR_SIZE * (entry_lba - current_lba - 1)]; // non-GPT data
GPTEntry entries[entry_count];
};
MasterBootRecord mbr @ 0 * SECTOR_SIZE;
GUIDPartitionTable gpt @ 1 * SECTOR_SIZE;