diff --git a/README.md b/README.md index e3ab393..c82a338 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed | VDF | | `patterns/vdf.hexpat` | Binary Value Data Format (.vdf) files | | IP | | `patterns/ip.hexpat` | Ethernet II Frames (IP Packets) | | UF2 | | `patterns/uf2.hexpat` | [USB Flashing Format](https://github.com/microsoft/uf2) | +| File System | | `patterns/fs.hexpat` | Drive File System | ### Scripts diff --git a/patterns/fs.hexpat b/patterns/fs.hexpat new file mode 100644 index 0000000..c29e452 --- /dev/null +++ b/patterns/fs.hexpat @@ -0,0 +1,168 @@ +#include + +struct DiskTimeStamp { + u8 seconds, minutes, hours; +}; + +enum DiskProtection : u16 { + None = 0x0000, + CopyProtected = 0x5A5A +}; + +bitfield CHS { + h : 8; + s : 6; + c : 10; +} [[right_to_left, 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 PartitionType : u8 { + EmptyPartitionEntry = 0x00, + FAT32_CHS = 0x0B, + FAT32_LBA = 0x0C +}; + +namespace fat32 { + + 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; + } [[left_to_right]]; + + 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; + } [[right_to_left]]; + + 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 Partition { + 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; + }; + +} + +struct PartitionEntry { + PartitionStatus status; + CHS chsFirstSectorAddress; + PartitionType type; + CHS chsLastSectorAddress; + u32 lbaFirstSectorAddress; + u32 numSectors; + + if (type == PartitionType::EmptyPartitionEntry) + continue; + else if (type == PartitionType::FAT32_CHS || type == PartitionType::FAT32_LBA) + fat32::Partition partition @ lbaFirstSectorAddress * 512; +}; + +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; \ No newline at end of file