LONG IsoClose(ULONG FileId) { PISO_FILE_INFO FileHandle = FsGetDeviceSpecific(FileId); MmHeapFree(FileHandle); return ESUCCESS; }
static VOID DetectPciIrqRoutingTable(PCONFIGURATION_COMPONENT_DATA BusKey) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; PPCI_IRQ_ROUTING_TABLE Table; PCONFIGURATION_COMPONENT_DATA TableKey; ULONG Size; Table = GetPciIrqRoutingTable(); if (Table != NULL) { TRACE("Table size: %u\n", Table->TableSize); /* Set 'Configuration Data' value */ Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) + 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + Table->TableSize; PartialResourceList = MmHeapAlloc(Size); if (PartialResourceList == NULL) { ERR("Failed to allocate resource descriptor\n"); return; } /* Initialize resource descriptor */ memset(PartialResourceList, 0, Size); PartialResourceList->Version = 1; PartialResourceList->Revision = 1; PartialResourceList->Count = 2; PartialDescriptor = &PartialResourceList->PartialDescriptors[0]; PartialDescriptor->Type = CmResourceTypeBusNumber; PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; PartialDescriptor->u.BusNumber.Start = 0; PartialDescriptor->u.BusNumber.Length = 1; PartialDescriptor = &PartialResourceList->PartialDescriptors[1]; PartialDescriptor->Type = CmResourceTypeDeviceSpecific; PartialDescriptor->ShareDisposition = CmResourceShareUndetermined; PartialDescriptor->u.DeviceSpecificData.DataSize = Table->TableSize; memcpy(&PartialResourceList->PartialDescriptors[2], Table, Table->TableSize); FldrCreateComponentKey(BusKey, PeripheralClass, RealModeIrqRoutingTable, 0x0, 0x0, 0xFFFFFFFF, "PCI Real-mode IRQ Routing Table", PartialResourceList, Size, &TableKey); MmHeapFree(PartialResourceList); } }
/* * IsoBufferDirectory() * This function allocates a buffer, reads the specified directory * and returns a pointer to that buffer into pDirectoryBuffer. The * function returns an ARC error code. The directory is specified * by its starting sector and length. */ static LONG IsoBufferDirectory(ULONG DeviceId, ULONG DirectoryStartSector, ULONG DirectoryLength, PVOID* pDirectoryBuffer) { PVOID DirectoryBuffer; ULONG SectorCount; LARGE_INTEGER Position; ULONG Count; ULONG ret; TRACE("IsoBufferDirectory() DirectoryStartSector = %d DirectoryLength = %d\n", DirectoryStartSector, DirectoryLength); SectorCount = ROUND_UP(DirectoryLength, SECTORSIZE) / SECTORSIZE; TRACE("Trying to read (DirectoryCount) %d sectors.\n", SectorCount); // // Attempt to allocate memory for directory buffer // TRACE("Trying to allocate (DirectoryLength) %d bytes.\n", DirectoryLength); DirectoryBuffer = MmHeapAlloc(DirectoryLength); if (!DirectoryBuffer) return ENOMEM; // // Now read directory contents into DirectoryBuffer // Position.HighPart = 0; Position.LowPart = DirectoryStartSector * SECTORSIZE; ret = ArcSeek(DeviceId, &Position, SeekAbsolute); if (ret != ESUCCESS) { MmHeapFree(DirectoryBuffer); return ret; } ret = ArcRead(DeviceId, DirectoryBuffer, SectorCount * SECTORSIZE, &Count); if (ret != ESUCCESS || Count != SectorCount * SECTORSIZE) { MmHeapFree(DirectoryBuffer); return EIO; } *pDirectoryBuffer = DirectoryBuffer; return ESUCCESS; }
BOOLEAN IniAddSettingValueToSection(ULONG_PTR SectionId, PCSTR SettingName, PCSTR SettingValue) { PINI_SECTION Section = (PINI_SECTION)SectionId; PINI_SECTION_ITEM SectionItem; // Allocate a new item structure SectionItem = MmHeapAlloc(sizeof(INI_SECTION_ITEM)); if (!SectionItem) { return FALSE; } RtlZeroMemory(SectionItem, sizeof(INI_SECTION_ITEM)); // Allocate the setting name buffer SectionItem->ItemName = MmHeapAlloc(strlen(SettingName) + 1); if (!SectionItem->ItemName) { MmHeapFree(SectionItem); return FALSE; } // Allocate the setting value buffer SectionItem->ItemValue = MmHeapAlloc(strlen(SettingValue) + 1); if (!SectionItem->ItemValue) { MmHeapFree(SectionItem->ItemName); MmHeapFree(SectionItem); return FALSE; } strcpy(SectionItem->ItemName, SettingName); strcpy(SectionItem->ItemValue, SettingValue); // Add it to the current section Section->SectionItemCount++; InsertTailList(&Section->SectionItemList, &SectionItem->ListEntry); return TRUE; }
VOID UiShowMessageBoxesInSection(PCSTR SectionName) { ULONG Idx; CHAR SettingName[80]; CHAR SettingValue[80]; PCHAR MessageBoxText; ULONG MessageBoxTextSize; ULONG_PTR SectionId; if (!IniOpenSection(SectionName, &SectionId)) { return; } // // Find all the message box settings and run them // for (Idx=0; Idx<IniGetNumSectionItems(SectionId); Idx++) { IniReadSettingByNumber(SectionId, Idx, SettingName, sizeof(SettingName), SettingValue, sizeof(SettingValue)); if (_stricmp(SettingName, "MessageBox") == 0) { // Get the real length of the MessageBox text MessageBoxTextSize = IniGetSectionSettingValueSize(SectionId, Idx); //if (MessageBoxTextSize > 0) { // Allocate enough memory to hold the text MessageBoxText = MmHeapAlloc(MessageBoxTextSize); if (MessageBoxText) { // Get the MessageBox text IniReadSettingByNumber(SectionId, Idx, SettingName, sizeof(SettingName), MessageBoxText, MessageBoxTextSize); // Fix it up UiEscapeString(MessageBoxText); // Display it UiMessageBox(MessageBoxText); // Free the memory MmHeapFree(MessageBoxText); } } } } }
VOID TuiMessageBox(PCSTR MessageText) { PVOID ScreenBuffer; // Save the screen contents ScreenBuffer = MmHeapAlloc(UiScreenWidth * UiScreenHeight * 2); TuiSaveScreen(ScreenBuffer); // Display the message box TuiMessageBoxCritical(MessageText); // Restore the screen contents TuiRestoreScreen(ScreenBuffer); MmHeapFree(ScreenBuffer); }
static VOID DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCONFIGURATION_COMPONENT_DATA BusKey; ULONG Size; /* Set 'Configuration Data' value */ Size = sizeof(CM_PARTIAL_RESOURCE_LIST) - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); PartialResourceList = MmHeapAlloc(Size); if (PartialResourceList == NULL) { TRACE( "Failed to allocate resource descriptor\n"); return; } /* Initialize resource descriptor */ memset(PartialResourceList, 0, Size); PartialResourceList->Version = 1; PartialResourceList->Revision = 1; PartialResourceList->Count = 0; /* Create new bus key */ FldrCreateComponentKey(SystemKey, AdapterClass, MultiFunctionAdapter, 0x0, 0x0, 0xFFFFFFFF, "ISA", PartialResourceList, Size, &BusKey); /* Increment bus number */ (*BusNumber)++; MmHeapFree(PartialResourceList); /* Detect ISA/BIOS devices */ DetectBiosDisks(SystemKey, BusKey); /* FIXME: Detect more ISA devices */ }
VOID InfCloseFile(HINF InfHandle) { PINFCACHE Cache; Cache = (PINFCACHE)InfHandle; if (Cache == NULL) { return; } while (Cache->FirstSection != NULL) { Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection); } Cache->LastSection = NULL; MmHeapFree(Cache); }
VOID TuiFadeInBackdrop(VOID) { PPALETTE_ENTRY TuiFadePalette = NULL; if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed()) { TuiFadePalette = (PPALETTE_ENTRY)MmHeapAlloc(sizeof(PALETTE_ENTRY) * 64); if (TuiFadePalette != NULL) { VideoSavePaletteState(TuiFadePalette, 64); VideoSetAllColorsToBlack(64); } } // Draw the backdrop and title box TuiDrawBackdrop(); if (UiUseSpecialEffects && ! MachVideoIsPaletteFixed() && TuiFadePalette != NULL) { VideoFadeIn(TuiFadePalette, 64); MmHeapFree(TuiFadePalette); } }
static PINFCACHESECTION InfpCacheFreeSection( PINFCACHESECTION Section) { PINFCACHESECTION Next; if (Section == NULL) { return NULL; } /* Release all keys */ Next = Section->Next; while (Section->FirstLine != NULL) { Section->FirstLine = InfpCacheFreeLine(Section->FirstLine); } Section->LastLine = NULL; MmHeapFree(Section); return Next; }
BOOLEAN InfOpenFile( PHINF InfHandle, PCSTR FileName, PULONG ErrorLine) { FILEINFORMATION Information; ULONG FileId; PCHAR FileBuffer; ULONG FileSize, Count; PINFCACHE Cache; BOOLEAN Success; LONG ret; *InfHandle = NULL; *ErrorLine = (ULONG) - 1; // // Open the .inf file // FileId = FsOpenFile(FileName); if (!FileId) { return FALSE; } // // Query file size // ret = ArcGetFileInformation(FileId, &Information); if ((ret != ESUCCESS) || (Information.EndingAddress.HighPart != 0)) { ArcClose(FileId); return FALSE; } FileSize = Information.EndingAddress.LowPart; // // Allocate buffer to cache the file // FileBuffer = MmHeapAlloc(FileSize + 1); if (!FileBuffer) { ArcClose(FileId); return FALSE; } // // Read file into memory // ret = ArcRead(FileId, FileBuffer, FileSize, &Count); if ((ret != ESUCCESS) || (Count != FileSize)) { ArcClose(FileId); MmHeapFree(FileBuffer); return FALSE; } // // We don't need the file anymore. Close it // ArcClose(FileId); // // Append string terminator // FileBuffer[FileSize] = 0; // // Allocate infcache header // Cache = (PINFCACHE)MmHeapAlloc(sizeof(INFCACHE)); if (!Cache) { MmHeapFree(FileBuffer); return FALSE; } // // Initialize inicache header // RtlZeroMemory(Cache, sizeof(INFCACHE)); // // Parse the inf buffer // Success = InfpParseBuffer(Cache, FileBuffer, FileBuffer + FileSize, ErrorLine); if (!Success) { MmHeapFree(Cache); Cache = NULL; } // // Free file buffer, as it has been parsed // MmHeapFree(FileBuffer); // // Return .inf parsed contents // *InfHandle = (HINF)Cache; return Success; }
BOOLEAN TuiEditBox(PCSTR MessageText, PCHAR EditTextBuffer, ULONG Length) { int width = 8; unsigned int height = 1; int curline = 0; int k; size_t i , j; int x1, x2, y1, y2; char temp[260]; char key; int EditBoxLine; ULONG EditBoxStartX, EditBoxEndX; int EditBoxCursorX; unsigned int EditBoxTextCount; int EditBoxTextDisplayIndex; BOOLEAN ReturnCode; PVOID ScreenBuffer; // Save the screen contents ScreenBuffer = MmHeapAlloc(UiScreenWidth * UiScreenHeight * 2); TuiSaveScreen(ScreenBuffer); // Find the height for (i=0; i<strlen(MessageText); i++) { if (MessageText[i] == '\n') height++; } // Find the width for (i=0,j=0,k=0; i<height; i++) { while ((MessageText[j] != '\n') && (MessageText[j] != 0)) { j++; k++; } if (k > width) width = k; k = 0; j++; } // Calculate box area x1 = (UiScreenWidth - (width+2))/2; x2 = x1 + width + 3; y1 = ((UiScreenHeight - height - 2)/2) + 1; y2 = y1 + height + 4; // Draw the box TuiDrawBox(x1, y1, x2, y2, D_VERT, D_HORZ, TRUE, TRUE, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor)); // Draw the text for (i=0,j=0; i<strlen(MessageText)+1; i++) { if ((MessageText[i] == '\n') || (MessageText[i] == 0)) { temp[j] = 0; j = 0; UiDrawText(x1+2, y1+1+curline, temp, ATTR(UiMessageBoxFgColor, UiMessageBoxBgColor)); curline++; } else temp[j++] = MessageText[i]; } EditBoxTextCount = 0; EditBoxLine = y2 - 2; EditBoxStartX = x1 + 3; EditBoxEndX = x2 - 3; UiFillArea(EditBoxStartX, EditBoxLine, EditBoxEndX, EditBoxLine, ' ', ATTR(UiEditBoxTextColor, UiEditBoxBgColor)); // Show the cursor EditBoxCursorX = EditBoxStartX; MachVideoSetTextCursorPosition(EditBoxCursorX, EditBoxLine); MachVideoHideShowTextCursor(TRUE); // Draw status text UiDrawStatusText("Press ENTER to continue, or ESC to cancel"); VideoCopyOffScreenBufferToVRAM(); for (;;) { if (MachConsKbHit()) { key = MachConsGetCh(); if(key == KEY_EXTENDED) { key = MachConsGetCh(); } if(key == KEY_ENTER) { ReturnCode = TRUE; break; } else if(key == KEY_ESC) { ReturnCode = FALSE; break; } else if (key == KEY_BACKSPACE) // Remove a character { if (EditBoxTextCount) { EditBoxTextCount--; EditTextBuffer[EditBoxTextCount] = 0; } else { MachBeep(); } } else // Add this key to the buffer { if (EditBoxTextCount < Length - 1) { EditTextBuffer[EditBoxTextCount] = key; EditBoxTextCount++; EditTextBuffer[EditBoxTextCount] = 0; } else { MachBeep(); } } } // Draw the edit box background UiFillArea(EditBoxStartX, EditBoxLine, EditBoxEndX, EditBoxLine, ' ', ATTR(UiEditBoxTextColor, UiEditBoxBgColor)); // Fill the text in if (EditBoxTextCount > (EditBoxEndX - EditBoxStartX)) { EditBoxTextDisplayIndex = EditBoxTextCount - (EditBoxEndX - EditBoxStartX); EditBoxCursorX = EditBoxEndX; } else { EditBoxTextDisplayIndex = 0; EditBoxCursorX = EditBoxStartX + EditBoxTextCount; } UiDrawText(EditBoxStartX, EditBoxLine, &EditTextBuffer[EditBoxTextDisplayIndex], ATTR(UiEditBoxTextColor, UiEditBoxBgColor)); // Move the cursor MachVideoSetTextCursorPosition(EditBoxCursorX, EditBoxLine); TuiUpdateDateTime(); VideoCopyOffScreenBufferToVRAM(); } // Hide the cursor again MachVideoHideShowTextCursor(FALSE); // Restore the screen contents TuiRestoreScreen(ScreenBuffer); MmHeapFree(ScreenBuffer); return ReturnCode; }
/* * IsoLookupFile() * This function searches the file system for the * specified filename and fills in an ISO_FILE_INFO structure * with info describing the file, etc. returns ARC error code */ static LONG IsoLookupFile(PCSTR FileName, ULONG DeviceId, PISO_FILE_INFO IsoFileInfoPointer) { UCHAR Buffer[SECTORSIZE]; PPVD Pvd = (PPVD)Buffer; UINT32 i; ULONG NumberOfPathParts; CHAR PathPart[261]; PVOID DirectoryBuffer; ULONG DirectorySector; ULONG DirectoryLength; ISO_FILE_INFO IsoFileInfo; LARGE_INTEGER Position; ULONG Count; LONG ret; TRACE("IsoLookupFile() FileName = %s\n", FileName); RtlZeroMemory(IsoFileInfoPointer, sizeof(ISO_FILE_INFO)); RtlZeroMemory(&IsoFileInfo, sizeof(ISO_FILE_INFO)); // // Read The Primary Volume Descriptor // Position.HighPart = 0; Position.LowPart = 16 * SECTORSIZE; ret = ArcSeek(DeviceId, &Position, SeekAbsolute); if (ret != ESUCCESS) return ret; ret = ArcRead(DeviceId, Pvd, SECTORSIZE, &Count); if (ret != ESUCCESS || Count < sizeof(PVD)) return EIO; DirectorySector = Pvd->RootDirRecord.ExtentLocationL; DirectoryLength = Pvd->RootDirRecord.DataLengthL; // // Figure out how many sub-directories we are nested in // NumberOfPathParts = FsGetNumPathParts(FileName); // // Loop once for each part // for (i=0; i<NumberOfPathParts; i++) { // // Get first path part // FsGetFirstNameFromPath(PathPart, FileName); // // Advance to the next part of the path // for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++) { } FileName++; // // Buffer the directory contents // ret = IsoBufferDirectory(DeviceId, DirectorySector, DirectoryLength, &DirectoryBuffer); if (ret != ESUCCESS) return ret; // // Search for file name in directory // if (!IsoSearchDirectoryBufferForFile(DirectoryBuffer, DirectoryLength, PathPart, &IsoFileInfo)) { MmHeapFree(DirectoryBuffer); return ENOENT; } MmHeapFree(DirectoryBuffer); // // If we have another sub-directory to go then // grab the start sector and file size // if ((i+1) < NumberOfPathParts) { DirectorySector = IsoFileInfo.FileStart; DirectoryLength = IsoFileInfo.FileSize; } } RtlCopyMemory(IsoFileInfoPointer, &IsoFileInfo, sizeof(ISO_FILE_INFO)); return ESUCCESS; }
BOOLEAN WinLdrAddDriverToList(LIST_ENTRY *BootDriverListHead, LPWSTR RegistryPath, LPWSTR ImagePath, LPWSTR ServiceName) { PBOOT_DRIVER_LIST_ENTRY BootDriverEntry; NTSTATUS Status; USHORT PathLength; BootDriverEntry = MmHeapAlloc(sizeof(BOOT_DRIVER_LIST_ENTRY)); if (!BootDriverEntry) return FALSE; // DTE will be filled during actual load of the driver BootDriverEntry->LdrEntry = NULL; // Check - if we have a valid ImagePath, if not - we need to build it // like "System32\\Drivers\\blah.sys" if (ImagePath && (wcslen(ImagePath) > 0)) { // Just copy ImagePath to the corresponding field in the structure PathLength = wcslen(ImagePath) * sizeof(WCHAR) + sizeof(UNICODE_NULL); BootDriverEntry->FilePath.Length = 0; BootDriverEntry->FilePath.MaximumLength = PathLength; BootDriverEntry->FilePath.Buffer = MmHeapAlloc(PathLength); if (!BootDriverEntry->FilePath.Buffer) { MmHeapFree(BootDriverEntry); return FALSE; } Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, ImagePath); if (!NT_SUCCESS(Status)) { MmHeapFree(BootDriverEntry->FilePath.Buffer); MmHeapFree(BootDriverEntry); return FALSE; } } else { // we have to construct ImagePath ourselves PathLength = wcslen(ServiceName)*sizeof(WCHAR) + sizeof(L"system32\\drivers\\.sys"); BootDriverEntry->FilePath.Length = 0; BootDriverEntry->FilePath.MaximumLength = PathLength; BootDriverEntry->FilePath.Buffer = MmHeapAlloc(PathLength); if (!BootDriverEntry->FilePath.Buffer) { MmHeapFree(BootDriverEntry); return FALSE; } Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, L"system32\\drivers\\"); if (!NT_SUCCESS(Status)) { MmHeapFree(BootDriverEntry->FilePath.Buffer); MmHeapFree(BootDriverEntry); return FALSE; } Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, ServiceName); if (!NT_SUCCESS(Status)) { MmHeapFree(BootDriverEntry->FilePath.Buffer); MmHeapFree(BootDriverEntry); return FALSE; } Status = RtlAppendUnicodeToString(&BootDriverEntry->FilePath, L".sys"); if (!NT_SUCCESS(Status)) { MmHeapFree(BootDriverEntry->FilePath.Buffer); MmHeapFree(BootDriverEntry); return FALSE; } } // Add registry path PathLength = (wcslen(RegistryPath) + wcslen(ServiceName))*sizeof(WCHAR) + sizeof(UNICODE_NULL); BootDriverEntry->RegistryPath.Length = 0; BootDriverEntry->RegistryPath.MaximumLength = PathLength; BootDriverEntry->RegistryPath.Buffer = MmHeapAlloc(PathLength); if (!BootDriverEntry->RegistryPath.Buffer) return FALSE; Status = RtlAppendUnicodeToString(&BootDriverEntry->RegistryPath, RegistryPath); if (!NT_SUCCESS(Status)) return FALSE; Status = RtlAppendUnicodeToString(&BootDriverEntry->RegistryPath, ServiceName); if (!NT_SUCCESS(Status)) return FALSE; // Insert entry at top of the list InsertTailList(BootDriverListHead, &BootDriverEntry->Link); return TRUE; }
VOID WinLdrScanRegistry(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, IN LPCSTR DirectoryPath) { LONG rc = 0; FRLDRHKEY hGroupKey, hOrderKey, hServiceKey, hDriverKey; LPWSTR GroupNameBuffer; WCHAR ServiceName[256]; ULONG OrderList[128]; ULONG BufferSize; ULONG Index; ULONG TagIndex; LPWSTR GroupName; ULONG ValueSize; ULONG ValueType; ULONG StartValue; ULONG TagValue; WCHAR DriverGroup[256]; ULONG DriverGroupSize; CHAR ImagePath[256]; WCHAR TempImagePath[256]; BOOLEAN Status; /* get 'service group order' key */ rc = RegOpenKey(NULL, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder", &hGroupKey); if (rc != ERROR_SUCCESS) { TRACE_CH(ODYSSEY, "Failed to open the 'ServiceGroupOrder' key (rc %d)\n", (int)rc); return; } /* get 'group order list' key */ rc = RegOpenKey(NULL, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\GroupOrderList", &hOrderKey); if (rc != ERROR_SUCCESS) { TRACE_CH(ODYSSEY, "Failed to open the 'GroupOrderList' key (rc %d)\n", (int)rc); return; } /* enumerate drivers */ rc = RegOpenKey(NULL, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services", &hServiceKey); if (rc != ERROR_SUCCESS) { TRACE_CH(ODYSSEY, "Failed to open the 'Services' key (rc %d)\n", (int)rc); return; } /* Get the Name Group */ BufferSize = 4096; GroupNameBuffer = MmHeapAlloc(BufferSize); rc = RegQueryValue(hGroupKey, L"List", NULL, (PUCHAR)GroupNameBuffer, &BufferSize); TRACE_CH(ODYSSEY, "RegQueryValue(): rc %d\n", (int)rc); if (rc != ERROR_SUCCESS) return; TRACE_CH(ODYSSEY, "BufferSize: %d \n", (int)BufferSize); TRACE_CH(ODYSSEY, "GroupNameBuffer: '%S' \n", GroupNameBuffer); /* Loop through each group */ GroupName = GroupNameBuffer; while (*GroupName) { TRACE("Driver group: '%S'\n", GroupName); /* Query the Order */ BufferSize = sizeof(OrderList); rc = RegQueryValue(hOrderKey, GroupName, NULL, (PUCHAR)OrderList, &BufferSize); if (rc != ERROR_SUCCESS) OrderList[0] = 0; /* enumerate all drivers */ for (TagIndex = 1; TagIndex <= OrderList[0]; TagIndex++) { Index = 0; while (TRUE) { /* Get the Driver's Name */ ValueSize = sizeof(ServiceName); rc = RegEnumKey(hServiceKey, Index, ServiceName, &ValueSize); //TRACE_CH(ODYSSEY, "RegEnumKey(): rc %d\n", (int)rc); /* Makre sure it's valid, and check if we're done */ if (rc == ERROR_NO_MORE_ITEMS) break; if (rc != ERROR_SUCCESS) { MmHeapFree(GroupNameBuffer); return; } //TRACE_CH(ODYSSEY, "Service %d: '%S'\n", (int)Index, ServiceName); /* open driver Key */ rc = RegOpenKey(hServiceKey, ServiceName, &hDriverKey); if (rc == ERROR_SUCCESS) { /* Read the Start Value */ ValueSize = sizeof(ULONG); rc = RegQueryValue(hDriverKey, L"Start", &ValueType, (PUCHAR)&StartValue, &ValueSize); if (rc != ERROR_SUCCESS) StartValue = (ULONG)-1; //TRACE_CH(ODYSSEY, " Start: %x \n", (int)StartValue); /* Read the Tag */ ValueSize = sizeof(ULONG); rc = RegQueryValue(hDriverKey, L"Tag", &ValueType, (PUCHAR)&TagValue, &ValueSize); if (rc != ERROR_SUCCESS) TagValue = (ULONG)-1; //TRACE_CH(ODYSSEY, " Tag: %x \n", (int)TagValue); /* Read the driver's group */ DriverGroupSize = sizeof(DriverGroup); rc = RegQueryValue(hDriverKey, L"Group", NULL, (PUCHAR)DriverGroup, &DriverGroupSize); //TRACE_CH(ODYSSEY, " Group: '%S' \n", DriverGroup); /* Make sure it should be started */ if ((StartValue == 0) && (TagValue == OrderList[TagIndex]) && (_wcsicmp(DriverGroup, GroupName) == 0)) { /* Get the Driver's Location */ ValueSize = sizeof(TempImagePath); rc = RegQueryValue(hDriverKey, L"ImagePath", NULL, (PUCHAR)TempImagePath, &ValueSize); /* Write the whole path if it suceeded, else prepare to fail */ if (rc != ERROR_SUCCESS) { TRACE_CH(ODYSSEY, "ImagePath: not found\n"); TempImagePath[0] = 0; sprintf(ImagePath, "%s\\system32\\drivers\\%S.sys", DirectoryPath, ServiceName); } else if (TempImagePath[0] != L'\\') { sprintf(ImagePath, "%s%S", DirectoryPath, TempImagePath); } else { sprintf(ImagePath, "%S", TempImagePath); TRACE_CH(ODYSSEY, "ImagePath: '%s'\n", ImagePath); } TRACE("Adding boot driver: '%s'\n", ImagePath); Status = WinLdrAddDriverToList(&LoaderBlock->BootDriverListHead, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", TempImagePath, ServiceName); if (!Status) ERR("Failed to add boot driver\n"); } else { //TRACE(" Skipping driver '%S' with Start %d, Tag %d and Group '%S' (Current Tag %d, current group '%S')\n", // ServiceName, StartValue, TagValue, DriverGroup, OrderList[TagIndex], GroupName); } } Index++; } } Index = 0; while (TRUE) { /* Get the Driver's Name */ ValueSize = sizeof(ServiceName); rc = RegEnumKey(hServiceKey, Index, ServiceName, &ValueSize); //TRACE_CH(ODYSSEY, "RegEnumKey(): rc %d\n", (int)rc); if (rc == ERROR_NO_MORE_ITEMS) break; if (rc != ERROR_SUCCESS) { MmHeapFree(GroupNameBuffer); return; } //TRACE_CH(ODYSSEY, "Service %d: '%S'\n", (int)Index, ServiceName); /* open driver Key */ rc = RegOpenKey(hServiceKey, ServiceName, &hDriverKey); if (rc == ERROR_SUCCESS) { /* Read the Start Value */ ValueSize = sizeof(ULONG); rc = RegQueryValue(hDriverKey, L"Start", &ValueType, (PUCHAR)&StartValue, &ValueSize); if (rc != ERROR_SUCCESS) StartValue = (ULONG)-1; //TRACE_CH(ODYSSEY, " Start: %x \n", (int)StartValue); /* Read the Tag */ ValueSize = sizeof(ULONG); rc = RegQueryValue(hDriverKey, L"Tag", &ValueType, (PUCHAR)&TagValue, &ValueSize); if (rc != ERROR_SUCCESS) TagValue = (ULONG)-1; //TRACE_CH(ODYSSEY, " Tag: %x \n", (int)TagValue); /* Read the driver's group */ DriverGroupSize = sizeof(DriverGroup); rc = RegQueryValue(hDriverKey, L"Group", NULL, (PUCHAR)DriverGroup, &DriverGroupSize); //TRACE_CH(ODYSSEY, " Group: '%S' \n", DriverGroup); for (TagIndex = 1; TagIndex <= OrderList[0]; TagIndex++) { if (TagValue == OrderList[TagIndex]) break; } if ((StartValue == 0) && (TagIndex > OrderList[0]) && (_wcsicmp(DriverGroup, GroupName) == 0)) { ValueSize = sizeof(TempImagePath); rc = RegQueryValue(hDriverKey, L"ImagePath", NULL, (PUCHAR)TempImagePath, &ValueSize); if (rc != ERROR_SUCCESS) { TRACE_CH(ODYSSEY, "ImagePath: not found\n"); TempImagePath[0] = 0; sprintf(ImagePath, "%ssystem32\\drivers\\%S.sys", DirectoryPath, ServiceName); } else if (TempImagePath[0] != L'\\') { sprintf(ImagePath, "%s%S", DirectoryPath, TempImagePath); } else { sprintf(ImagePath, "%S", TempImagePath); TRACE_CH(ODYSSEY, "ImagePath: '%s'\n", ImagePath); } TRACE(" Adding boot driver: '%s'\n", ImagePath); Status = WinLdrAddDriverToList(&LoaderBlock->BootDriverListHead, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", TempImagePath, ServiceName); if (!Status) ERR(" Failed to add boot driver\n"); } else { //TRACE(" Skipping driver '%S' with Start %d, Tag %d and Group '%S' (Current group '%S')\n", // ServiceName, StartValue, TagValue, DriverGroup, GroupName); } } Index++; } /* Move to the next group name */ GroupName = GroupName + wcslen(GroupName) + 1; } /* Free allocated memory */ MmHeapFree(GroupNameBuffer); }
VOID DetectPciBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; PCI_REGISTRY_INFO BusData; PCONFIGURATION_COMPONENT_DATA BiosKey; ULONG Size; PCONFIGURATION_COMPONENT_DATA BusKey; ULONG i; /* Report the PCI BIOS */ if (FindPciBios(&BusData)) { /* Set 'Configuration Data' value */ Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors); PartialResourceList = MmHeapAlloc(Size); if (PartialResourceList == NULL) { ERR("Failed to allocate resource descriptor\n"); return; } /* Initialize resource descriptor */ memset(PartialResourceList, 0, Size); /* Create new bus key */ FldrCreateComponentKey(SystemKey, AdapterClass, MultiFunctionAdapter, 0x0, 0x0, 0xFFFFFFFF, "PCI BIOS", PartialResourceList, Size, &BiosKey); /* Increment bus number */ (*BusNumber)++; MmHeapFree(PartialResourceList); DetectPciIrqRoutingTable(BiosKey); /* Report PCI buses */ for (i = 0; i < (ULONG)BusData.NoBuses; i++) { /* Check if this is the first bus */ if (i == 0) { /* Set 'Configuration Data' value */ Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + sizeof(PCI_REGISTRY_INFO); PartialResourceList = MmHeapAlloc(Size); if (!PartialResourceList) { ERR("Failed to allocate resource descriptor\n"); return; } /* Initialize resource descriptor */ memset(PartialResourceList, 0, Size); PartialResourceList->Version = 1; PartialResourceList->Revision = 1; PartialResourceList->Count = 1; PartialDescriptor = &PartialResourceList->PartialDescriptors[0]; PartialDescriptor->Type = CmResourceTypeDeviceSpecific; PartialDescriptor->ShareDisposition = CmResourceShareUndetermined; PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(PCI_REGISTRY_INFO); memcpy(&PartialResourceList->PartialDescriptors[1], &BusData, sizeof(PCI_REGISTRY_INFO)); } else { /* Set 'Configuration Data' value */ Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors); PartialResourceList = MmHeapAlloc(Size); if (!PartialResourceList) { ERR("Failed to allocate resource descriptor\n"); return; } /* Initialize resource descriptor */ memset(PartialResourceList, 0, Size); } /* Create the bus key */ FldrCreateComponentKey(SystemKey, AdapterClass, MultiFunctionAdapter, 0x0, 0x0, 0xFFFFFFFF, "PCI", PartialResourceList, Size, &BusKey); MmHeapFree(PartialResourceList); /* Increment bus number */ (*BusNumber)++; } } }
static PCM_PARTIAL_RESOURCE_LIST GetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry; //EXTENDED_GEOMETRY ExtGeometry; GEOMETRY Geometry; ULONG Size; // // Initialize returned size // *pSize = 0; /* Set 'Configuration Data' value */ Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + sizeof(CM_DISK_GEOMETRY_DEVICE_DATA); PartialResourceList = MmHeapAlloc(Size); if (PartialResourceList == NULL) { ERR("Failed to allocate a full resource descriptor\n"); return NULL; } memset(PartialResourceList, 0, Size); PartialResourceList->Version = 1; PartialResourceList->Revision = 1; PartialResourceList->Count = 1; PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific; // PartialResourceList->PartialDescriptors[0].ShareDisposition = // PartialResourceList->PartialDescriptors[0].Flags = PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize = sizeof(CM_DISK_GEOMETRY_DEVICE_DATA); /* Get pointer to geometry data */ DiskGeometry = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST)); /* Get the disk geometry */ //ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY); if(MachDiskGetDriveGeometry(DriveNumber, &Geometry)) { DiskGeometry->BytesPerSector = Geometry.BytesPerSector; DiskGeometry->NumberOfCylinders = Geometry.Cylinders; DiskGeometry->SectorsPerTrack = Geometry.Sectors; DiskGeometry->NumberOfHeads = Geometry.Heads; } else { ERR("Reading disk geometry failed\n"); MmHeapFree(PartialResourceList); return NULL; } TRACE("Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n", DriveNumber, DiskGeometry->NumberOfCylinders, DiskGeometry->NumberOfHeads, DiskGeometry->SectorsPerTrack, DiskGeometry->BytesPerSector); // // Return configuration data // *pSize = Size; return PartialResourceList; }
static VOID DetectBiosDisks(PCONFIGURATION_COMPONENT_DATA SystemKey, PCONFIGURATION_COMPONENT_DATA BusKey) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCM_INT13_DRIVE_PARAMETER Int13Drives; GEOMETRY Geometry; PCONFIGURATION_COMPONENT_DATA DiskKey, ControllerKey; UCHAR DiskCount, i; ULONG Size; BOOLEAN Changed; /* Count the number of visible drives */ DiskReportError(FALSE); DiskCount = 0; /* There are some really broken BIOSes out there. There are even BIOSes * that happily report success when you ask them to read from non-existent * harddisks. So, we set the buffer to known contents first, then try to * read. If the BIOS reports success but the buffer contents haven't * changed then we fail anyway */ memset((PVOID) DISKREADBUFFER, 0xcd, 512); while (MachDiskReadLogicalSectors(0x80 + DiskCount, 0ULL, 1, (PVOID)DISKREADBUFFER)) { Changed = FALSE; for (i = 0; ! Changed && i < 512; i++) { Changed = ((PUCHAR)DISKREADBUFFER)[i] != 0xcd; } if (! Changed) { TRACE("BIOS reports success for disk %d but data didn't change\n", (int)DiskCount); break; } DiskCount++; memset((PVOID) DISKREADBUFFER, 0xcd, 512); } DiskReportError(TRUE); TRACE("BIOS reports %d harddisk%s\n", (int)DiskCount, (DiskCount == 1) ? "": "s"); //DetectBiosFloppyController(BusKey); /* Allocate resource descriptor */ Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount; PartialResourceList = MmHeapAlloc(Size); if (PartialResourceList == NULL) { ERR("Failed to allocate resource descriptor\n"); return; } /* Initialize resource descriptor */ memset(PartialResourceList, 0, Size); PartialResourceList->Version = 1; PartialResourceList->Revision = 1; PartialResourceList->Count = 1; PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific; PartialResourceList->PartialDescriptors[0].ShareDisposition = 0; PartialResourceList->PartialDescriptors[0].Flags = 0; PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize = sizeof(CM_INT13_DRIVE_PARAMETER) * DiskCount; /* Get harddisk Int13 geometry data */ Int13Drives = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST)); for (i = 0; i < DiskCount; i++) { if (MachDiskGetDriveGeometry(0x80 + i, &Geometry)) { Int13Drives[i].DriveSelect = 0x80 + i; Int13Drives[i].MaxCylinders = Geometry.Cylinders - 1; Int13Drives[i].SectorsPerTrack = (USHORT)Geometry.Sectors; Int13Drives[i].MaxHeads = (USHORT)Geometry.Heads - 1; Int13Drives[i].NumberDrives = DiskCount; TRACE( "Disk %x: %u Cylinders %u Heads %u Sectors %u Bytes\n", 0x80 + i, Geometry.Cylinders - 1, Geometry.Heads -1, Geometry.Sectors, Geometry.BytesPerSector); } } FldrCreateComponentKey(BusKey, ControllerClass, DiskController, Output | Input, 0, 0xFFFFFFFF, NULL, PartialResourceList, Size, &ControllerKey); TRACE("Created key: DiskController\\0\n"); MmHeapFree(PartialResourceList); /* Create and fill subkey for each harddisk */ for (i = 0; i < DiskCount; i++) { PCM_PARTIAL_RESOURCE_LIST PartialResourceList; ULONG Size; CHAR Identifier[20]; /* Get disk values */ PartialResourceList = GetHarddiskConfigurationData(0x80 + i, &Size); GetHarddiskIdentifier(Identifier, 0x80 + i); /* Create disk key */ FldrCreateComponentKey(ControllerKey, PeripheralClass, DiskPeripheral, Output | Input, 0, 0xFFFFFFFF, Identifier, PartialResourceList, Size, &DiskKey); if (PartialResourceList) MmHeapFree(PartialResourceList); } }
LONG RegSetValue(FRLDRHKEY Key, PCWSTR ValueName, ULONG Type, PCSTR Data, ULONG DataSize) { PLIST_ENTRY Ptr; PVALUE Value = NULL; TRACE("Key 0x%p, ValueName '%S', Type %ld, Data 0x%p, DataSize %ld\n", Key, ValueName, Type, Data, DataSize); if ((ValueName == NULL) || (*ValueName == 0)) { /* set default value */ if ((Key->Data != NULL) && (Key->DataSize > sizeof(PUCHAR))) { MmHeapFree(Key->Data); } if (DataSize <= sizeof(PUCHAR)) { Key->DataSize = DataSize; Key->DataType = Type; memcpy(&Key->Data, Data, DataSize); } else { Key->Data = MmHeapAlloc(DataSize); Key->DataSize = DataSize; Key->DataType = Type; memcpy(Key->Data, Data, DataSize); } } else { /* set non-default value */ Ptr = Key->ValueList.Flink; while (Ptr != &Key->ValueList) { Value = CONTAINING_RECORD(Ptr, VALUE, ValueList); TRACE("Value->Name '%S'\n", Value->Name); if (_wcsicmp(Value->Name, ValueName) == 0) break; Ptr = Ptr->Flink; } if (Ptr == &Key->ValueList) { /* add new value */ TRACE("No value found - adding new value\n"); Value = (PVALUE)MmHeapAlloc(sizeof(VALUE)); if (Value == NULL) return ERROR_OUTOFMEMORY; InsertTailList(&Key->ValueList, &Value->ValueList); Key->ValueCount++; Value->NameSize = (wcslen(ValueName)+1) * sizeof(WCHAR); Value->Name = MmHeapAlloc(Value->NameSize); if (Value->Name == NULL) return ERROR_OUTOFMEMORY; wcscpy(Value->Name, ValueName); Value->DataType = REG_NONE; Value->DataSize = 0; Value->Data = NULL; } /* set new value */ if ((Value->Data != NULL) && (Value->DataSize > sizeof(PUCHAR))) { MmHeapFree(Value->Data); } if (DataSize <= sizeof(PUCHAR)) { Value->DataSize = DataSize; Value->DataType = Type; memcpy(&Value->Data, Data, DataSize); } else { Value->Data = MmHeapAlloc(DataSize); if (Value->Data == NULL) return ERROR_OUTOFMEMORY; Value->DataType = Type; Value->DataSize = DataSize; memcpy(Value->Data, Data, DataSize); } } return(ERROR_SUCCESS); }
BOOLEAN IniFileInitialize(VOID) { FILEINFORMATION FileInformation; ULONG FileId; // File handle for freeldr.ini PCHAR FreeLoaderIniFileData; ULONG FreeLoaderIniFileSize, Count; LONG ret; BOOLEAN Success; TRACE("IniFileInitialize()\n"); // // Open freeldr.ini // ret = IniOpenIniFile(&FileId); if (ret != ESUCCESS) { UiMessageBoxCritical("Error opening freeldr.ini or file not found.\nYou need to re-install FreeLoader."); return FALSE; } // // Get the file size // ret = ArcGetFileInformation(FileId, &FileInformation); if (ret != ESUCCESS || FileInformation.EndingAddress.HighPart != 0) { UiMessageBoxCritical("Error while getting informations about freeldr.ini.\nYou need to re-install FreeLoader."); return FALSE; } FreeLoaderIniFileSize = FileInformation.EndingAddress.LowPart; // // Allocate memory to cache the whole freeldr.ini // FreeLoaderIniFileData = MmHeapAlloc(FreeLoaderIniFileSize); if (!FreeLoaderIniFileData) { UiMessageBoxCritical("Out of memory while loading freeldr.ini."); ArcClose(FileId); return FALSE; } // // Read freeldr.ini off the disk // ret = ArcRead(FileId, FreeLoaderIniFileData, FreeLoaderIniFileSize, &Count); if (ret != ESUCCESS || Count != FreeLoaderIniFileSize) { UiMessageBoxCritical("Error while reading freeldr.ini."); ArcClose(FileId); MmHeapFree(FreeLoaderIniFileData); return FALSE; } // // Parse the .ini file data // Success = IniParseFile(FreeLoaderIniFileData, FreeLoaderIniFileSize); // // Do some cleanup, and return // ArcClose(FileId); MmHeapFree(FreeLoaderIniFileData); return Success; }
static BOOLEAN RegImportValue ( PHHIVE Hive, PCM_KEY_VALUE ValueCell, FRLDRHKEY Key) { PVOID DataCell; PWCHAR wName; LONG Error; ULONG DataLength; ULONG i; if (ValueCell->Signature != CM_KEY_VALUE_SIGNATURE) { ERR("Invalid key cell!\n"); return FALSE; } if (ValueCell->Flags & VALUE_COMP_NAME) { wName = MmHeapAlloc ((ValueCell->NameLength + 1) * sizeof(WCHAR)); for (i = 0; i < ValueCell->NameLength; i++) { wName[i] = ((PCHAR)ValueCell->Name)[i]; } wName[ValueCell->NameLength] = 0; } else { wName = MmHeapAlloc(ValueCell->NameLength + sizeof(WCHAR)); memcpy(wName, ValueCell->Name, ValueCell->NameLength); wName[ValueCell->NameLength / sizeof(WCHAR)] = 0; } DataLength = ValueCell->DataLength & REG_DATA_SIZE_MASK; TRACE("ValueName: '%S'\n", wName); TRACE("DataLength: %u\n", DataLength); if (DataLength <= sizeof(HCELL_INDEX) && (ValueCell->DataLength & REG_DATA_IN_OFFSET)) { Error = RegSetValue(Key, wName, ValueCell->Type, (PCHAR)&ValueCell->Data, DataLength); if (Error != ERROR_SUCCESS) { ERR("RegSetValue() failed!\n"); MmHeapFree(wName); return FALSE; } } else { DataCell = (PVOID)HvGetCell(Hive, ValueCell->Data); TRACE("DataCell: %x\n", DataCell); Error = RegSetValue(Key, wName, ValueCell->Type, DataCell, DataLength); if (Error != ERROR_SUCCESS) { ERR("RegSetValue() failed!\n"); MmHeapFree(wName); return FALSE; } } MmHeapFree(wName); return TRUE; }
static BOOLEAN RegImportSubKey( PHHIVE Hive, PCM_KEY_NODE KeyCell, FRLDRHKEY ParentKey) { PCM_KEY_INDEX IndexCell; PVALUE_LIST_CELL ValueListCell; PCM_KEY_VALUE ValueCell = NULL; PWCHAR wName; FRLDRHKEY SubKey; LONG Error; ULONG i; TRACE("KeyCell: %x\n", KeyCell); TRACE("KeyCell->Signature: %x\n", KeyCell->Signature); if (KeyCell->Signature != CM_KEY_NODE_SIGNATURE) { ERR("Invalid key cell Signature!\n"); return FALSE; } if (KeyCell->Flags & KEY_COMP_NAME) { wName = MmHeapAlloc((KeyCell->NameLength + 1) * sizeof(WCHAR)); for (i = 0; i < KeyCell->NameLength; i++) { wName[i] = ((PCHAR)KeyCell->Name)[i]; } wName[KeyCell->NameLength] = 0; } else { wName = MmHeapAlloc(KeyCell->NameLength + sizeof(WCHAR)); memcpy(wName, KeyCell->Name, KeyCell->NameLength); wName[KeyCell->NameLength / sizeof(WCHAR)] = 0; } TRACE("KeyName: '%S'\n", wName); /* Create new sub key */ Error = RegCreateKey(ParentKey, wName, &SubKey); MmHeapFree(wName); if (Error != ERROR_SUCCESS) { ERR("RegCreateKey() failed!\n"); return FALSE; } TRACE("Subkeys: %u\n", KeyCell->SubKeyCounts); TRACE("Values: %u\n", KeyCell->ValueList.Count); /* Enumerate and add values */ if (KeyCell->ValueList.Count > 0) { ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyCell->ValueList.List); TRACE("ValueListCell: %x\n", ValueListCell); for (i = 0; i < KeyCell->ValueList.Count; i++) { TRACE("ValueOffset[%d]: %x\n", i, ValueListCell->ValueOffset[i]); ValueCell = (PCM_KEY_VALUE) HvGetCell (Hive, ValueListCell->ValueOffset[i]); TRACE("ValueCell[%d]: %x\n", i, ValueCell); if (!RegImportValue(Hive, ValueCell, SubKey)) return FALSE; } } /* Enumerate and add subkeys */ if (KeyCell->SubKeyCounts[Stable] > 0) { IndexCell = HvGetCell (Hive, KeyCell->SubKeyLists[Stable]); if (!RegImportIndexSubKey(Hive, IndexCell, SubKey)) return FALSE; } return TRUE; }