From b9ca9b0061da651caad60d733945f44c9453aff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Tue, 23 Apr 2024 22:40:31 +0200 Subject: [PATCH] [SETUPLIB] Don't create new INI sections or key-values if they already exist (#6815) - If a section already exists, return the existing one. This allows avoiding different section entries with the same name in the cache. If an INI file has separate sections with the same name, their contents (key-values) get merged into a unique section. - If a key-value already exists, update its data value and return the existing one. (Note that this may be subject to behaviour change in the future.) --- base/setup/lib/utils/bldrsup.c | 12 +- base/setup/lib/utils/inicache.c | 230 ++++++++++++++++++-------------- base/setup/lib/utils/inicache.h | 10 +- 3 files changed, 141 insertions(+), 111 deletions(-) diff --git a/base/setup/lib/utils/bldrsup.c b/base/setup/lib/utils/bldrsup.c index 655575b700a..e5017eaf210 100644 --- a/base/setup/lib/utils/bldrsup.c +++ b/base/setup/lib/utils/bldrsup.c @@ -214,10 +214,8 @@ CreateCommonFreeLdrSections( * Cache the "FREELOADER" section for our future usage. */ - /* Get or create the "FREELOADER" section */ - IniSection = IniGetSection(BootStore->IniCache, L"FREELOADER"); - if (!IniSection) - IniSection = IniAddSection(BootStore->IniCache, L"FREELOADER"); + /* Create the "FREELOADER" section */ + IniSection = IniAddSection(BootStore->IniCache, L"FREELOADER"); if (!IniSection) DPRINT1("CreateCommonFreeLdrSections: Failed to create 'FREELOADER' section!\n"); @@ -237,10 +235,8 @@ CreateCommonFreeLdrSections( * Cache the "Operating Systems" section for our future usage. */ - /* Get or create the "Operating Systems" section */ - IniSection = IniGetSection(BootStore->IniCache, L"Operating Systems"); - if (!IniSection) - IniSection = IniAddSection(BootStore->IniCache, L"Operating Systems"); + /* Create the "Operating Systems" section */ + IniSection = IniAddSection(BootStore->IniCache, L"Operating Systems"); if (!IniSection) DPRINT1("CreateCommonFreeLdrSections: Failed to create 'Operating Systems' section!\n"); diff --git a/base/setup/lib/utils/inicache.c b/base/setup/lib/utils/inicache.c index 2c74a4160e3..87917a1c175 100644 --- a/base/setup/lib/utils/inicache.c +++ b/base/setup/lib/utils/inicache.c @@ -72,28 +72,36 @@ IniCacheFreeSection( return Next; } +static +PINI_SECTION +IniCacheFindSection( + _In_ PINICACHE Cache, + _In_ PCWSTR Name) +{ + PINI_SECTION Section; + + for (Section = Cache->FirstSection; Section; Section = Section->Next) + { + if (_wcsicmp(Section->Name, Name) == 0) + return Section; + } + return NULL; +} + static PINI_KEYWORD IniCacheFindKey( - PINI_SECTION Section, - PWCHAR Name, - ULONG NameLength) + _In_ PINI_SECTION Section, + _In_ PCWSTR Name) { PINI_KEYWORD Key; - Key = Section->FirstKey; - while (Key != NULL) + for (Key = Section->FirstKey; Key; Key = Key->Next) { - if (NameLength == wcslen(Key->Name)) - { - if (_wcsnicmp(Key->Name, Name, NameLength) == 0) - break; - } - - Key = Key->Next; + if (_wcsicmp(Key->Name, Name) == 0) + return Key; } - - return Key; + return NULL; } static @@ -108,66 +116,98 @@ IniCacheAddKeyAorW( _In_ ULONG DataLength, _In_ BOOLEAN IsUnicode) { - PINI_KEYWORD Key = NULL; + PINI_KEYWORD Key; + PWSTR NameU, DataU; - if (Section == NULL || - Name == NULL || - NameLength == 0 || - Data == NULL || - DataLength == 0) + if (!Section || !Name || NameLength == 0 || !Data || DataLength == 0) { DPRINT("Invalid parameter\n"); return NULL; } - /* Allocate key buffer */ + /* Allocate the UNICODE key name */ + NameU = (PWSTR)RtlAllocateHeap(ProcessHeap, + 0, + (NameLength + 1) * sizeof(WCHAR)); + if (!NameU) + { + DPRINT("RtlAllocateHeap() failed\n"); + return NULL; + } + /* Copy the value name (ANSI or UNICODE) */ + if (IsUnicode) + wcsncpy(NameU, (PCWCH)Name, NameLength); + else + _snwprintf(NameU, NameLength, L"%.*S", NameLength, (PCCH)Name); + NameU[NameLength] = UNICODE_NULL; + + /* + * Find whether a key with the given name already exists in the section. + * If so, modify the data and return it; otherwise create a new one. + */ + Key = IniCacheFindKey(Section, NameU); + if (Key) + { + RtlFreeHeap(ProcessHeap, 0, NameU); + + /* Modify the existing data */ + + /* Allocate the UNICODE data buffer */ + DataU = (PWSTR)RtlAllocateHeap(ProcessHeap, + 0, + (DataLength + 1) * sizeof(WCHAR)); + if (!DataU) + { + DPRINT("RtlAllocateHeap() failed\n"); + return NULL; // We failed, don't modify the original key. + } + /* Copy the data (ANSI or UNICODE) */ + if (IsUnicode) + wcsncpy(DataU, (PCWCH)Data, DataLength); + else + _snwprintf(DataU, DataLength, L"%.*S", DataLength, (PCCH)Data); + DataU[DataLength] = UNICODE_NULL; + + /* Swap the old key data with the new one */ + RtlFreeHeap(ProcessHeap, 0, Key->Data); + Key->Data = DataU; + + /* Return the modified key */ + return Key; + } + + /* Allocate the key buffer and name */ Key = (PINI_KEYWORD)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(INI_KEYWORD)); - if (Key == NULL) + if (!Key) { DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, 0, NameU); return NULL; } + Key->Name = NameU; - /* Allocate name buffer */ - Key->Name = (PWCHAR)RtlAllocateHeap(ProcessHeap, - 0, - (NameLength + 1) * sizeof(WCHAR)); - if (Key->Name == NULL) + /* Allocate the UNICODE data buffer */ + DataU = (PWSTR)RtlAllocateHeap(ProcessHeap, + 0, + (DataLength + 1) * sizeof(WCHAR)); + if (!DataU) { DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, 0, NameU); RtlFreeHeap(ProcessHeap, 0, Key); return NULL; } - - /* Copy value name (ANSI or UNICODE) */ + /* Copy the data (ANSI or UNICODE) */ if (IsUnicode) - wcsncpy(Key->Name, (PCWCH)Name, NameLength); + wcsncpy(DataU, (PCWCH)Data, DataLength); else - _snwprintf(Key->Name, NameLength, L"%.*S", NameLength, (PCCH)Name); - Key->Name[NameLength] = UNICODE_NULL; + _snwprintf(DataU, DataLength, L"%.*S", DataLength, (PCCH)Data); + DataU[DataLength] = UNICODE_NULL; + Key->Data = DataU; - /* Allocate data buffer */ - Key->Data = (PWCHAR)RtlAllocateHeap(ProcessHeap, - 0, - (DataLength + 1) * sizeof(WCHAR)); - if (Key->Data == NULL) - { - DPRINT("RtlAllocateHeap() failed\n"); - RtlFreeHeap(ProcessHeap, 0, Key->Name); - RtlFreeHeap(ProcessHeap, 0, Key); - return NULL; - } - - /* Copy value data (ANSI or UNICODE) */ - if (IsUnicode) - wcsncpy(Key->Data, (PCWCH)Data, DataLength); - else - _snwprintf(Key->Data, DataLength, L"%.*S", DataLength, (PCCH)Data); - Key->Data[DataLength] = UNICODE_NULL; - - /* Insert key into section */ + /* Insert the key into section */ if (Section->FirstKey == NULL) { Section->FirstKey = Key; @@ -218,42 +258,55 @@ IniCacheAddSectionAorW( _In_ ULONG NameLength, _In_ BOOLEAN IsUnicode) { - PINI_SECTION Section = NULL; + PINI_SECTION Section; + PWSTR NameU; - if (Cache == NULL || Name == NULL || NameLength == 0) + if (!Cache || !Name || NameLength == 0) { DPRINT("Invalid parameter\n"); return NULL; } + /* Allocate the UNICODE section name */ + NameU = (PWSTR)RtlAllocateHeap(ProcessHeap, + 0, + (NameLength + 1) * sizeof(WCHAR)); + if (!NameU) + { + DPRINT("RtlAllocateHeap() failed\n"); + return NULL; + } + /* Copy the section name (ANSI or UNICODE) */ + if (IsUnicode) + wcsncpy(NameU, (PCWCH)Name, NameLength); + else + _snwprintf(NameU, NameLength, L"%.*S", NameLength, (PCCH)Name); + NameU[NameLength] = UNICODE_NULL; + + /* + * Find whether a section with the given name already exists. + * If so, just return it; otherwise create a new one. + */ + Section = IniCacheFindSection(Cache, NameU); + if (Section) + { + RtlFreeHeap(ProcessHeap, 0, NameU); + return Section; + } + + /* Allocate the section buffer and name */ Section = (PINI_SECTION)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(INI_SECTION)); - if (Section == NULL) + if (!Section) { DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, 0, NameU); return NULL; } + Section->Name = NameU; - /* Allocate and initialize section name */ - Section->Name = (PWCHAR)RtlAllocateHeap(ProcessHeap, - 0, - (NameLength + 1) * sizeof(WCHAR)); - if (Section->Name == NULL) - { - DPRINT("RtlAllocateHeap() failed\n"); - RtlFreeHeap(ProcessHeap, 0, Section); - return NULL; - } - - /* Copy section name (ANSI or UNICODE) */ - if (IsUnicode) - wcsncpy(Section->Name, (PCWCH)Name, NameLength); - else - _snwprintf(Section->Name, NameLength, L"%.*S", NameLength, (PCCH)Name); - Section->Name[NameLength] = UNICODE_NULL; - - /* Append section */ + /* Append the section */ if (Cache->FirstSection == NULL) { Cache->FirstSection = Section; @@ -701,34 +754,15 @@ IniCacheDestroy( PINI_SECTION IniGetSection( - PINICACHE Cache, - PWCHAR Name) + _In_ PINICACHE Cache, + _In_ PCWSTR Name) { - PINI_SECTION Section = NULL; - - if (Cache == NULL || Name == NULL) + if (!Cache || !Name) { DPRINT("Invalid parameter\n"); return NULL; } - - /* Iterate through list of sections */ - Section = Cache->FirstSection; - while (Section != NULL) - { - DPRINT("Comparing '%S' and '%S'\n", Section->Name, Name); - - /* Are the section names the same? */ - if (_wcsicmp(Section->Name, Name) == 0) - return Section; - - /* Get the next section */ - Section = Section->Next; - } - - DPRINT("Section not found\n"); - - return NULL; + return IniCacheFindSection(Cache, Name); } NTSTATUS @@ -747,7 +781,7 @@ IniGetKey( *KeyData = NULL; - Key = IniCacheFindKey(Section, KeyName, wcslen(KeyName)); + Key = IniCacheFindKey(Section, KeyName); if (Key == NULL) { return STATUS_INVALID_PARAMETER; diff --git a/base/setup/lib/utils/inicache.h b/base/setup/lib/utils/inicache.h index 60f83e4d378..f33780b8c78 100644 --- a/base/setup/lib/utils/inicache.h +++ b/base/setup/lib/utils/inicache.h @@ -9,8 +9,8 @@ typedef struct _INI_KEYWORD { - PWCHAR Name; - PWCHAR Data; + PWSTR Name; + PWSTR Data; struct _INI_KEYWORD *Next; struct _INI_KEYWORD *Prev; @@ -18,7 +18,7 @@ typedef struct _INI_KEYWORD typedef struct _INI_SECTION { - PWCHAR Name; + PWSTR Name; PINI_KEYWORD FirstKey; PINI_KEYWORD LastKey; @@ -74,8 +74,8 @@ IniCacheDestroy( PINI_SECTION IniGetSection( - PINICACHE Cache, - PWCHAR Name); + _In_ PINICACHE Cache, + _In_ PCWSTR Name); NTSTATUS IniGetKey(