// Dynamic partition discovery. This file owns MBR/GPT parsing and keeps structural identity out of filesystem providers. #include #include #include #include #include #include #include #include #include #include #define IOP_SECTOR_SIZE 512u #define IOP_GPT_SIGNATURE "EFI PART" #define IOP_GPT_REVISION_1_0 0x00010000u #define IOP_GPT_MIN_ENTRY_SIZE 128u #pragma pack(push, 1) typedef struct IOP_MBR_PARTITION_ENTRY { uint8_t BootIndicator; uint8_t StartingChs[3]; uint8_t Type; uint8_t EndingChs[3]; uint32_t StartingLba; uint32_t SectorCount; } IOP_MBR_PARTITION_ENTRY; typedef struct IOP_GPT_HEADER { char Signature[8]; uint32_t Revision; uint32_t HeaderSize; uint32_t HeaderCrc32; uint32_t Reserved; uint64_t MyLba; uint64_t AlternateLba; uint64_t FirstUsableLba; uint64_t LastUsableLba; BOOT_VOLUME_GUID DiskGuid; uint64_t PartitionEntryLba; uint32_t NumberOfPartitionEntries; uint32_t SizeOfPartitionEntry; uint32_t PartitionEntryArrayCrc32; } IOP_GPT_HEADER; typedef struct IOP_GPT_ENTRY_PREFIX { BOOT_VOLUME_GUID PartitionTypeGuid; BOOT_VOLUME_GUID UniquePartitionGuid; uint64_t StartingLba; uint64_t EndingLba; uint64_t Attributes; } IOP_GPT_ENTRY_PREFIX; #pragma pack(pop) _Static_assert(sizeof(IOP_MBR_PARTITION_ENTRY) == 16u, "MBR partition entry layout must match disk format"); _Static_assert(sizeof(IOP_GPT_HEADER) == 92u, "GPT header prefix layout must match disk format"); _Static_assert(sizeof(IOP_GPT_ENTRY_PREFIX) == 56u, "GPT entry prefix layout must match disk format"); typedef struct IOP_PARTITION_RECORD { struct IOP_PARTITION_RECORD* Next; IO_PARTITION_INFO Info; BOOT_VOLUME_SELECTOR Identity; } IOP_PARTITION_RECORD; typedef struct IOP_PARTITION_CALLBACK_ENTRY { struct IOP_PARTITION_CALLBACK_ENTRY* Next; IO_PARTITION_CHANGE_CALLBACK Callback; void* Context; } IOP_PARTITION_CALLBACK_ENTRY; typedef struct IOP_GPT_VALIDATED_HEADER { IOP_GPT_HEADER Header; uint64_t EntryBytes; uint64_t EntrySectors; } IOP_GPT_VALIDATED_HEADER; static MUTEX* gPartitionMutex; static IOP_PARTITION_RECORD* gPartitions; static IOP_PARTITION_CALLBACK_ENTRY* gPartitionCallbacks; static BOOT_VOLUME_SELECTOR gSystemVolumeSelector; static bool gPartitionManagerInitialized; // Returns whether two shared GUID values are identical. static bool IopGuidEquals(const BOOT_VOLUME_GUID* left, const BOOT_VOLUME_GUID* right) { return left && right && memcmp(left, right, sizeof(*left)) == 0; } // Returns whether one shared GUID value is all zeroes. static bool IopGuidIsZero(const BOOT_VOLUME_GUID* guid) { static const BOOT_VOLUME_GUID zero = {0}; return guid && IopGuidEquals(guid, &zero); } // Returns whether one internal partition identity equals another. static bool IopIdentityEquals(const BOOT_VOLUME_SELECTOR* left, const BOOT_VOLUME_SELECTOR* right) { if (!left || !right || left->Kind != right->Kind) return false; if (left->Kind == BootVolumeSelectorMbr) { return left->Identity.Mbr.DiskSignature == right->Identity.Mbr.DiskSignature && left->Identity.Mbr.PartitionNumber == right->Identity.Mbr.PartitionNumber; } if (left->Kind == BootVolumeSelectorGpt) { return IopGuidEquals(&left->Identity.Gpt.PartitionGuid, &right->Identity.Gpt.PartitionGuid); } return false; } // Acquires the partition-manager mutex for registry and callback serialization. static bool IopAcquirePartitionMutex(void) { if (!gPartitionMutex) return false; return KE_MUTEX_ACQUIRE_SUCCEEDED(KeAcquireMutex(gPartitionMutex, KE_WAIT_INFINITE)); } // Frees one dynamically discovered partition list. static void IopFreePartitionList(IOP_PARTITION_RECORD* head) { while (head) { IOP_PARTITION_RECORD* next = head->Next; MmFreePool(head); head = next; } } // Updates one CRC32 accumulator using the GPT/IEEE polynomial. static uint32_t IopCrc32Update(uint32_t crc, const uint8_t* data, size_t length) { for (size_t i = 0; i < length; ++i) { crc ^= data[i]; for (uint32_t bit = 0; bit < 8; ++bit) crc = (crc >> 1) ^ (0xedb88320u & (uint32_t)-(int32_t)(crc & 1u)); } return crc; } // Computes a complete GPT CRC32 value. static uint32_t IopCrc32(const void* data, size_t length) { uint32_t crc = IopCrc32Update(0xffffffffu, (const uint8_t*)data, length); return crc ^ 0xffffffffu; } // Reads an arbitrary byte span through the kernel's 512-byte block-device API. static KSTATUS IopReadDiskBytes(uint8_t diskIndex, uint64_t diskSectors, uint64_t byteOffset, void* buffer, size_t length) { if (!buffer || length == 0) return NTLSTATUS_INVALID_PARAMETER; if (diskSectors > UINT64_MAX / IOP_SECTOR_SIZE) return NTLSTATUS_INVALID_PARAMETER; uint64_t diskBytes = diskSectors * IOP_SECTOR_SIZE; if (byteOffset > diskBytes || (uint64_t)length > diskBytes - byteOffset) return NTLSTATUS_INVALID_PARAMETER; uint8_t sector[IOP_SECTOR_SIZE]; uint8_t* out = (uint8_t*)buffer; size_t remaining = length; while (remaining) { uint64_t lba = byteOffset / IOP_SECTOR_SIZE; uint32_t inSector = (uint32_t)(byteOffset % IOP_SECTOR_SIZE); size_t chunk = IOP_SECTOR_SIZE - inSector; if (chunk > remaining) chunk = remaining; KSTATUS status = IoReadDiskSectors(diskIndex, lba, 1, sector); if (!KSUCCESS(status)) return status; memcpy(out, sector + inSector, chunk); out += chunk; byteOffset += chunk; remaining -= chunk; } return NTLSTATUS_SUCCESS; } // Returns whether one MBR type is an extended-partition container we intentionally do not enumerate. static bool IopMbrTypeIsExtended(uint8_t type) { return type == 0x05u || type == 0x0fu || type == 0x85u; } // Allocates one immutable partition record. static IOP_PARTITION_RECORD* IopAllocatePartition(uint8_t diskIndex, uint64_t startLba, uint64_t sectorCount, const BOOT_VOLUME_SELECTOR* identity) { if (!sectorCount || !identity) return NULL; IOP_PARTITION_RECORD* record = MmAllocatePool(sizeof(*record)); if (!record) return NULL; memset(record, 0, sizeof(*record)); record->Info.DiskIndex = diskIndex; record->Info.StartLba = startLba; record->Info.SectorCount = sectorCount; record->Identity = *identity; return record; } // Inserts one discovered partition in ascending LBA order and rejects overlap or duplicate identity. static KSTATUS IopInsertDiscoveredPartition(IOP_PARTITION_RECORD** head, IOP_PARTITION_RECORD* record) { if (!head || !record || record->Info.SectorCount == 0) return NTLSTATUS_INVALID_PARAMETER; if (record->Info.StartLba > UINT64_MAX - record->Info.SectorCount) return NTLSTATUS_INVALID_PARAMETER; uint64_t recordEnd = record->Info.StartLba + record->Info.SectorCount; IOP_PARTITION_RECORD* previous = NULL; IOP_PARTITION_RECORD* current = *head; while (current && current->Info.StartLba < record->Info.StartLba) { if (IopIdentityEquals(¤t->Identity, &record->Identity)) return NTLSTATUS_OBJECT_NAME_COLLISION; previous = current; current = current->Next; } for (IOP_PARTITION_RECORD* scan = current; scan; scan = scan->Next) { if (IopIdentityEquals(&scan->Identity, &record->Identity)) return NTLSTATUS_OBJECT_NAME_COLLISION; } if (previous) { uint64_t previousEnd = previous->Info.StartLba + previous->Info.SectorCount; if (previousEnd > record->Info.StartLba) return NTLSTATUS_INVALID_PARAMETER; } if (current && recordEnd > current->Info.StartLba) return NTLSTATUS_INVALID_PARAMETER; record->Next = current; if (previous) previous->Next = record; else *head = record; return NTLSTATUS_SUCCESS; } // Validates the exact CRC32 of one GPT partition-entry array without imposing an entry-count cap. static KSTATUS IopValidateGptEntryArrayCrc(uint8_t diskIndex, const IOP_GPT_VALIDATED_HEADER* validated) { uint8_t sector[IOP_SECTOR_SIZE]; uint64_t remaining = validated->EntryBytes; uint64_t lba = validated->Header.PartitionEntryLba; uint32_t crc = 0xffffffffu; while (remaining) { KSTATUS status = IoReadDiskSectors(diskIndex, lba++, 1, sector); if (!KSUCCESS(status)) return status; size_t chunk = remaining < IOP_SECTOR_SIZE ? (size_t)remaining : IOP_SECTOR_SIZE; crc = IopCrc32Update(crc, sector, chunk); remaining -= chunk; } crc ^= 0xffffffffu; return crc == validated->Header.PartitionEntryArrayCrc32 ? NTLSTATUS_SUCCESS : NTLSTATUS_CHECKSUM_MISMATCH; } // Validates one primary or backup GPT header and its partition-entry-array CRC. static KSTATUS IopValidateGptHeader(uint8_t diskIndex, uint64_t diskSectors, uint64_t headerLba, uint64_t expectedAlternateLba, IOP_GPT_VALIDATED_HEADER* validatedOut) { if (!validatedOut || diskSectors < 3 || headerLba >= diskSectors || expectedAlternateLba >= diskSectors || headerLba == expectedAlternateLba) { return NTLSTATUS_INVALID_PARAMETER; } uint8_t sector[IOP_SECTOR_SIZE]; KSTATUS status = IoReadDiskSectors(diskIndex, headerLba, 1, sector); if (!KSUCCESS(status)) return status; IOP_GPT_HEADER header; memcpy(&header, sector, sizeof(header)); if (memcmp(header.Signature, IOP_GPT_SIGNATURE, 8) != 0 || header.Revision < IOP_GPT_REVISION_1_0 || header.HeaderSize < sizeof(IOP_GPT_HEADER) || header.HeaderSize > IOP_SECTOR_SIZE || header.Reserved != 0 || header.MyLba != headerLba || header.AlternateLba != expectedAlternateLba || header.FirstUsableLba > header.LastUsableLba || header.LastUsableLba >= diskSectors || IopGuidIsZero(&header.DiskGuid) || header.NumberOfPartitionEntries == 0 || header.SizeOfPartitionEntry < IOP_GPT_MIN_ENTRY_SIZE || (header.SizeOfPartitionEntry & 7u) != 0) { return NTLSTATUS_INVALID_PARAMETER; } uint32_t expectedHeaderCrc = header.HeaderCrc32; memset(sector + offsetof(IOP_GPT_HEADER, HeaderCrc32), 0, sizeof(header.HeaderCrc32)); if (IopCrc32(sector, header.HeaderSize) != expectedHeaderCrc) return NTLSTATUS_CHECKSUM_MISMATCH; if ((uint64_t)header.NumberOfPartitionEntries > UINT64_MAX / header.SizeOfPartitionEntry) return NTLSTATUS_INVALID_PARAMETER; uint64_t entryBytes = (uint64_t)header.NumberOfPartitionEntries * header.SizeOfPartitionEntry; if (entryBytes > UINT64_MAX - (IOP_SECTOR_SIZE - 1u)) return NTLSTATUS_INVALID_PARAMETER; uint64_t entrySectors = (entryBytes + IOP_SECTOR_SIZE - 1u) / IOP_SECTOR_SIZE; if (entrySectors == 0 || header.PartitionEntryLba >= diskSectors || entrySectors > diskSectors - header.PartitionEntryLba) { return NTLSTATUS_INVALID_PARAMETER; } uint64_t entryLastLba = header.PartitionEntryLba + entrySectors - 1u; if (headerLba == 1u) { if (header.PartitionEntryLba <= headerLba || entryLastLba >= header.FirstUsableLba) return NTLSTATUS_INVALID_PARAMETER; } else { if (header.PartitionEntryLba <= header.LastUsableLba || entryLastLba >= headerLba) return NTLSTATUS_INVALID_PARAMETER; } IOP_GPT_VALIDATED_HEADER validated = {0}; validated.Header = header; validated.EntryBytes = entryBytes; validated.EntrySectors = entrySectors; status = IopValidateGptEntryArrayCrc(diskIndex, &validated); if (!KSUCCESS(status)) return status; *validatedOut = validated; return NTLSTATUS_SUCCESS; } // Returns whether independently valid primary and backup GPT headers describe the same table. static bool IopGptHeadersAgree(const IOP_GPT_VALIDATED_HEADER* primary, const IOP_GPT_VALIDATED_HEADER* backup) { if (!primary || !backup) return false; return IopGuidEquals(&primary->Header.DiskGuid, &backup->Header.DiskGuid) && primary->Header.FirstUsableLba == backup->Header.FirstUsableLba && primary->Header.LastUsableLba == backup->Header.LastUsableLba && primary->Header.NumberOfPartitionEntries == backup->Header.NumberOfPartitionEntries && primary->Header.SizeOfPartitionEntry == backup->Header.SizeOfPartitionEntry && primary->Header.PartitionEntryArrayCrc32 == backup->Header.PartitionEntryArrayCrc32; } // Parses all populated GPT entries from one already validated table. static KSTATUS IopParseGptEntries(uint8_t diskIndex, uint64_t diskSectors, const IOP_GPT_VALIDATED_HEADER* validated, IOP_PARTITION_RECORD** partitionsOut) { if (!validated || !partitionsOut) return NTLSTATUS_INVALID_PARAMETER; IOP_PARTITION_RECORD* partitions = NULL; if (validated->Header.PartitionEntryLba > UINT64_MAX / IOP_SECTOR_SIZE) return NTLSTATUS_INVALID_PARAMETER; uint64_t arrayByteBase = validated->Header.PartitionEntryLba * IOP_SECTOR_SIZE; for (uint32_t index = 0; index < validated->Header.NumberOfPartitionEntries; ++index) { uint64_t entryOffset = (uint64_t)index * validated->Header.SizeOfPartitionEntry; if (arrayByteBase > UINT64_MAX - entryOffset) { IopFreePartitionList(partitions); return NTLSTATUS_INVALID_PARAMETER; } IOP_GPT_ENTRY_PREFIX entry; KSTATUS status = IopReadDiskBytes(diskIndex, diskSectors, arrayByteBase + entryOffset, &entry, sizeof(entry)); if (!KSUCCESS(status)) { IopFreePartitionList(partitions); return status; } if (IopGuidIsZero(&entry.PartitionTypeGuid)) continue; if (IopGuidIsZero(&entry.UniquePartitionGuid) || entry.EndingLba < entry.StartingLba || entry.StartingLba < validated->Header.FirstUsableLba || entry.EndingLba > validated->Header.LastUsableLba) { IopFreePartitionList(partitions); return NTLSTATUS_INVALID_PARAMETER; } uint64_t sectorCount = entry.EndingLba - entry.StartingLba + 1u; BOOT_VOLUME_SELECTOR identity = {0}; identity.Kind = BootVolumeSelectorGpt; identity.Identity.Gpt.PartitionGuid = entry.UniquePartitionGuid; IOP_PARTITION_RECORD* record = IopAllocatePartition(diskIndex, entry.StartingLba, sectorCount, &identity); if (!record) { IopFreePartitionList(partitions); return NTLSTATUS_NO_MEMORY; } status = IopInsertDiscoveredPartition(&partitions, record); if (!KSUCCESS(status)) { MmFreePool(record); IopFreePartitionList(partitions); return status; } } *partitionsOut = partitions; return NTLSTATUS_SUCCESS; } // Discovers one GPT disk from primary/backup metadata and rejects inconsistent valid copies. static KSTATUS IopDiscoverGptDisk(uint8_t diskIndex, uint64_t diskSectors, IOP_PARTITION_RECORD** partitionsOut) { IOP_GPT_VALIDATED_HEADER primary = {0}; IOP_GPT_VALIDATED_HEADER backup = {0}; KSTATUS primaryStatus = IopValidateGptHeader(diskIndex, diskSectors, 1u, diskSectors - 1u, &primary); KSTATUS backupStatus = IopValidateGptHeader(diskIndex, diskSectors, diskSectors - 1u, 1u, &backup); bool primaryValid = KSUCCESS(primaryStatus); bool backupValid = KSUCCESS(backupStatus); if (!primaryValid && !backupValid) { DbgPrint("partition: disk %u GPT primary=0x%x backup=0x%x\n", diskIndex, primaryStatus, backupStatus); return primaryStatus == NTLSTATUS_CHECKSUM_MISMATCH || backupStatus == NTLSTATUS_CHECKSUM_MISMATCH ? NTLSTATUS_CHECKSUM_MISMATCH : NTLSTATUS_INVALID_PARAMETER; } if (primaryValid && backupValid && !IopGptHeadersAgree(&primary, &backup)) { DbgPrint("partition: disk %u GPT primary/backup metadata disagree\n", diskIndex); return NTLSTATUS_INVALID_PARAMETER; } const IOP_GPT_VALIDATED_HEADER* selected = primaryValid ? &primary : &backup; if (!primaryValid) DbgPrint("partition: disk %u using valid backup GPT\n", diskIndex); return IopParseGptEntries(diskIndex, diskSectors, selected, partitionsOut); } // Discovers either an MBR primary-partition map or a protective-MBR GPT map. static KSTATUS IopDiscoverDiskPartitions(uint8_t diskIndex, DEVICE_OBJECT* device, IOP_PARTITION_RECORD** partitionsOut) { if (!device || !partitionsOut) return NTLSTATUS_INVALID_PARAMETER; *partitionsOut = NULL; if (device->u.Disk.SectorSize != IOP_SECTOR_SIZE || device->u.Disk.SectorCount == 0) { DbgPrint("partition: disk %u unsupported sector geometry size=%u sectors=%llu\n", diskIndex, device->u.Disk.SectorSize, (unsigned long long)device->u.Disk.SectorCount); return NTLSTATUS_NOT_SUPPORTED; } uint64_t diskSectors = device->u.Disk.SectorCount; uint8_t sector[IOP_SECTOR_SIZE]; KSTATUS status = IoReadDiskSectors(diskIndex, 0, 1, sector); if (!KSUCCESS(status)) return status; if (sector[510] != 0x55u || sector[511] != 0xaau) return NTLSTATUS_NOT_FOUND; uint32_t diskSignature = 0; memcpy(&diskSignature, sector + 440u, sizeof(diskSignature)); IOP_MBR_PARTITION_ENTRY entries[4]; memcpy(entries, sector + 446u, sizeof(entries)); bool protective = false; for (uint32_t i = 0; i < 4; ++i) { if (entries[i].Type == 0xeeu && entries[i].SectorCount != 0) protective = true; } if (protective) return IopDiscoverGptDisk(diskIndex, diskSectors, partitionsOut); // Validate the complete primary table before emitting supported partitions. Extended containers remain // unsupported, but malformed container extents must not make a partially trusted MBR map acceptable. for (uint32_t i = 0; i < 4; ++i) { const IOP_MBR_PARTITION_ENTRY* entry = &entries[i]; if (entry->BootIndicator != 0x00u && entry->BootIndicator != 0x80u) return NTLSTATUS_INVALID_PARAMETER; if (entry->Type == 0 && entry->SectorCount == 0) continue; if (entry->Type == 0 || entry->SectorCount == 0 || entry->StartingLba == 0 || entry->StartingLba >= diskSectors || (uint64_t)entry->SectorCount > diskSectors - entry->StartingLba) { return NTLSTATUS_INVALID_PARAMETER; } uint64_t entryEnd = (uint64_t)entry->StartingLba + entry->SectorCount; for (uint32_t previous = 0; previous < i; ++previous) { const IOP_MBR_PARTITION_ENTRY* prior = &entries[previous]; if (prior->Type == 0 && prior->SectorCount == 0) continue; uint64_t priorEnd = (uint64_t)prior->StartingLba + prior->SectorCount; if ((uint64_t)entry->StartingLba < priorEnd && (uint64_t)prior->StartingLba < entryEnd) { return NTLSTATUS_INVALID_PARAMETER; } } } IOP_PARTITION_RECORD* partitions = NULL; for (uint32_t i = 0; i < 4; ++i) { const IOP_MBR_PARTITION_ENTRY* entry = &entries[i]; if (entry->Type == 0 || IopMbrTypeIsExtended(entry->Type)) continue; BOOT_VOLUME_SELECTOR identity = {0}; identity.Kind = BootVolumeSelectorMbr; identity.Identity.Mbr.DiskSignature = diskSignature; identity.Identity.Mbr.PartitionNumber = i + 1u; IOP_PARTITION_RECORD* record = IopAllocatePartition(diskIndex, entry->StartingLba, entry->SectorCount, &identity); if (!record) { IopFreePartitionList(partitions); return NTLSTATUS_NO_MEMORY; } status = IopInsertDiscoveredPartition(&partitions, record); if (!KSUCCESS(status)) { MmFreePool(record); IopFreePartitionList(partitions); return status; } } *partitionsOut = partitions; return NTLSTATUS_SUCCESS; } // Returns whether the registry already contains at least one partition for this disk index. static bool IopDiskAlreadyDiscovered(uint8_t diskIndex) { bool found = false; if (!IopAcquirePartitionMutex()) return false; for (IOP_PARTITION_RECORD* record = gPartitions; record; record = record->Next) { if (record->Info.DiskIndex == diskIndex) { found = true; break; } } KeReleaseMutex(gPartitionMutex); return found; } // Appends one discovered list to the live registry and synchronously notifies every subscriber. static KSTATUS IopPublishPartitions(uint8_t diskIndex, IOP_PARTITION_RECORD* discovered) { if (!IopAcquirePartitionMutex()) { IopFreePartitionList(discovered); return NTLSTATUS_FAILURE; } for (IOP_PARTITION_RECORD* record = gPartitions; record; record = record->Next) { if (record->Info.DiskIndex == diskIndex) { KeReleaseMutex(gPartitionMutex); IopFreePartitionList(discovered); return NTLSTATUS_SUCCESS; } } IOP_PARTITION_RECORD** tail = &gPartitions; while (*tail) tail = &(*tail)->Next; *tail = discovered; for (IOP_PARTITION_RECORD* record = discovered; record; record = record->Next) { if (record->Identity.Kind == BootVolumeSelectorMbr) { DbgPrint("partition: disk=%u mbr/%08X/%u start=%llu sectors=%llu\n", record->Info.DiskIndex, record->Identity.Identity.Mbr.DiskSignature, record->Identity.Identity.Mbr.PartitionNumber, (unsigned long long)record->Info.StartLba, (unsigned long long)record->Info.SectorCount); } else { const BOOT_VOLUME_GUID* guid = &record->Identity.Identity.Gpt.PartitionGuid; DbgPrint("partition: disk=%u gpt/%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X start=%llu sectors=%llu\n", record->Info.DiskIndex, guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7], (unsigned long long)record->Info.StartLba, (unsigned long long)record->Info.SectorCount); } if (IopIdentityEquals(&record->Identity, &gSystemVolumeSelector)) { DbgPrint("partition: configured system_volume matches disk=%u start=%llu sectors=%llu\n", record->Info.DiskIndex, (unsigned long long)record->Info.StartLba, (unsigned long long)record->Info.SectorCount); } for (IOP_PARTITION_CALLBACK_ENTRY* entry = gPartitionCallbacks; entry; entry = entry->Next) entry->Callback(&record->Info, IoPartitionArrived, entry->Context); } KeReleaseMutex(gPartitionMutex); return NTLSTATUS_SUCCESS; } // Discovers and publishes all partitions for one newly registered disk. static void IopDiskArrived(uint8_t diskIndex, DEVICE_OBJECT* device) { if (!device || IopDiskAlreadyDiscovered(diskIndex)) return; IOP_PARTITION_RECORD* discovered = NULL; KSTATUS status = IopDiscoverDiskPartitions(diskIndex, device, &discovered); if (!KSUCCESS(status)) { if (status != NTLSTATUS_NOT_FOUND) { DbgPrint("partition: disk %u discovery failed status=0x%x\n", diskIndex, status); } else { DbgPrint("partition: disk %u has no partition table\n", diskIndex); } return; } if (!discovered) { DbgPrint("partition: disk %u contains no supported partitions\n", diskIndex); return; } status = IopPublishPartitions(diskIndex, discovered); if (!KSUCCESS(status)) DbgPrint("partition: disk %u publish failed status=0x%x\n", diskIndex, status); } // Removes all partitions belonging to one disk and notifies consumers before freeing their snapshots. static void IopDiskRemoved(uint8_t diskIndex, IO_PARTITION_CHANGE change) { if (!IopAcquirePartitionMutex()) return; IOP_PARTITION_RECORD** link = &gPartitions; while (*link) { IOP_PARTITION_RECORD* record = *link; if (record->Info.DiskIndex != diskIndex) { link = &record->Next; continue; } *link = record->Next; for (IOP_PARTITION_CALLBACK_ENTRY* entry = gPartitionCallbacks; entry; entry = entry->Next) entry->Callback(&record->Info, change, entry->Context); MmFreePool(record); } KeReleaseMutex(gPartitionMutex); } // Receives the underlying disk namespace and translates it into partition changes. static void IopDiskChange(uint8_t diskIndex, DEVICE_OBJECT* device, IO_DEVICE_CHANGE change, void* context) { (void)context; switch (change) { case IoDeviceArrived: IopDiskArrived(diskIndex, device); break; case IoDeviceSurpriseRemoved: case IoDeviceRemoved: IopDiskRemoved(diskIndex, change == IoDeviceSurpriseRemoved ? IoPartitionSurpriseRemoved : IoPartitionRemoved); break; case IoDeviceQueryRemove: default: break; } } // Replays one disk that predates partition-manager initialization. static void IopReplayDisk(uint8_t diskIndex, DEVICE_OBJECT* device, void* context) { (void)context; IopDiskArrived(diskIndex, device); } // Initializes dynamic partition discovery and the mandatory structural system-volume selector. KSTATUS IoInitializePartitionManager(const char* systemVolumeSelector) { if (!systemVolumeSelector || !*systemVolumeSelector) return NTLSTATUS_INVALID_PARAMETER; if (gPartitionManagerInitialized) return NTLSTATUS_ALREADY_EXISTS; BOOT_VOLUME_SELECTOR selector = {0}; if (!BootVolumeSelectorParse(systemVolumeSelector, strlen(systemVolumeSelector), &selector)) return NTLSTATUS_INVALID_PARAMETER; MUTEX* mutex = NULL; KSTATUS status = KeMutexCreate(&mutex); if (!KSUCCESS(status)) return status; gPartitionMutex = mutex; gSystemVolumeSelector = selector; status = IoRegisterDiskChangeCallback(IopDiskChange, NULL); if (!KSUCCESS(status)) { gPartitionMutex = NULL; memset(&gSystemVolumeSelector, 0, sizeof(gSystemVolumeSelector)); ObDereferenceObject(&mutex->Header); return status; } // The disk-change subscription is permanent, so the manager becomes live before replaying existing disks. gPartitionManagerInitialized = true; status = IoEnumerateDiskDevices(IopReplayDisk, NULL); if (!KSUCCESS(status)) return status; DbgPrint("partition: dynamic discovery initialized for system_volume=%s\n", systemVolumeSelector); return NTLSTATUS_SUCCESS; } // Registers one partition-change consumer and replays every currently discovered partition before returning. __declspec(dllexport) KSTATUS IoRegisterPartitionChangeCallback(IO_PARTITION_CHANGE_CALLBACK callback, void* context) { if (!callback || !gPartitionManagerInitialized) return NTLSTATUS_INVALID_PARAMETER; IOP_PARTITION_CALLBACK_ENTRY* entry = MmAllocatePool(sizeof(*entry)); if (!entry) return NTLSTATUS_NO_MEMORY; entry->Next = NULL; entry->Callback = callback; entry->Context = context; if (!IopAcquirePartitionMutex()) { MmFreePool(entry); return NTLSTATUS_FAILURE; } IOP_PARTITION_CALLBACK_ENTRY** tail = &gPartitionCallbacks; while (*tail) tail = &(*tail)->Next; *tail = entry; for (IOP_PARTITION_RECORD* record = gPartitions; record; record = record->Next) callback(&record->Info, IoPartitionArrived, context); KeReleaseMutex(gPartitionMutex); return NTLSTATUS_SUCCESS; } // Returns the uniquely selected system partition, or NOT_FOUND/COLLISION while discovery is incomplete or ambiguous. KSTATUS IoQuerySystemPartition(IO_PARTITION_INFO* partitionOut) { if (!partitionOut || !gPartitionManagerInitialized) return NTLSTATUS_INVALID_PARAMETER; if (!IopAcquirePartitionMutex()) return NTLSTATUS_FAILURE; const IOP_PARTITION_RECORD* match = NULL; uint32_t matchCount = 0; for (IOP_PARTITION_RECORD* record = gPartitions; record; record = record->Next) { if (!IopIdentityEquals(&record->Identity, &gSystemVolumeSelector)) continue; match = record; matchCount++; } KSTATUS status; if (matchCount == 0) { status = NTLSTATUS_NOT_FOUND; } else if (matchCount != 1) { status = NTLSTATUS_OBJECT_NAME_COLLISION; } else { *partitionOut = match->Info; status = NTLSTATUS_SUCCESS; } KeReleaseMutex(gPartitionMutex); return status; }