[SETUPLIB] Add support for removing sections and key values, and remove some hacks (#6815)

- Use LIST_ENTRY instead of custom list pointers;
- Fix key/section unlinking before freeing.
This commit is contained in:
Hermès Bélusca-Maïto 2024-04-24 12:58:09 +02:00
parent b9ca9b0061
commit e151ef9ae1
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
3 changed files with 201 additions and 199 deletions

View file

@ -1006,9 +1006,8 @@ QueryBootStoreOptions(
IN OUT PBOOT_STORE_OPTIONS BootOptions IN OUT PBOOT_STORE_OPTIONS BootOptions
/* , IN PULONG BootOptionsLength */ ) /* , IN PULONG BootOptionsLength */ )
{ {
NTSTATUS Status = STATUS_SUCCESS;
PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle; PBOOT_STORE_CONTEXT BootStore = (PBOOT_STORE_CONTEXT)Handle;
PWCHAR TimeoutStr; PCWSTR TimeoutStr;
if (!BootStore || !BootOptions) if (!BootStore || !BootOptions)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
@ -1036,36 +1035,34 @@ QueryBootStoreOptions(
{ {
BootOptions->Version = FreeLdr; BootOptions->Version = FreeLdr;
Status = IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection, BootOptions->CurrentBootEntryKey = 0;
L"DefaultOS", (PWCHAR*)&BootOptions->CurrentBootEntryKey); IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
if (!NT_SUCCESS(Status)) L"DefaultOS", (PCWSTR*)&BootOptions->CurrentBootEntryKey);
BootOptions->CurrentBootEntryKey = 0;
Status = IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection, BootOptions->Timeout = 0;
L"TimeOut", &TimeoutStr); if (IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
if (NT_SUCCESS(Status) && TimeoutStr) L"TimeOut", &TimeoutStr) && TimeoutStr)
{
BootOptions->Timeout = _wtoi(TimeoutStr); BootOptions->Timeout = _wtoi(TimeoutStr);
else }
BootOptions->Timeout = 0;
} }
else if (BootStore->Type == NtLdr) else if (BootStore->Type == NtLdr)
{ {
BootOptions->Version = NtLdr; BootOptions->Version = NtLdr;
Status = IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection, BootOptions->CurrentBootEntryKey = 0;
L"default", (PWCHAR*)&BootOptions->CurrentBootEntryKey); IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
if (!NT_SUCCESS(Status)) L"default", (PCWSTR*)&BootOptions->CurrentBootEntryKey);
BootOptions->CurrentBootEntryKey = 0;
Status = IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection, BootOptions->Timeout = 0;
L"timeout", &TimeoutStr); if (IniGetKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
if (NT_SUCCESS(Status) && TimeoutStr) L"timeout", &TimeoutStr) && TimeoutStr)
{
BootOptions->Timeout = _wtoi(TimeoutStr); BootOptions->Timeout = _wtoi(TimeoutStr);
else }
BootOptions->Timeout = 0;
} }
return STATUS_SUCCESS; // FIXME: use Status; instead? return STATUS_SUCCESS;
} }
NTSTATUS NTSTATUS
@ -1110,9 +1107,8 @@ SetBootStoreOptions(
L"DefaultOS", (PCWSTR)BootOptions->CurrentBootEntryKey); L"DefaultOS", (PCWSTR)BootOptions->CurrentBootEntryKey);
RtlStringCchPrintfW(TimeoutStr, ARRAYSIZE(TimeoutStr), L"%d", BootOptions->Timeout); RtlStringCchPrintfW(TimeoutStr, ARRAYSIZE(TimeoutStr), L"%d", BootOptions->Timeout);
IniInsertKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection, IniAddKey(((PBOOT_STORE_INI_CONTEXT)BootStore)->OptionsIniSection,
NULL, INSERT_FIRST, // INSERT_LAST, // FIXME!! There is a bug in the INI parser where a given key can be inserted twice in the same section... L"TimeOut", TimeoutStr);
L"TimeOut", TimeoutStr);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1129,7 +1125,7 @@ FreeLdrEnumerateBootEntries(
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
PINICACHEITERATOR Iterator; PINICACHEITERATOR Iterator;
PINI_SECTION OsIniSection; PINI_SECTION OsIniSection;
PWCHAR SectionName, KeyData; PCWSTR SectionName, KeyData;
UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) +
max(sizeof(NTOS_OPTIONS), sizeof(BOOT_SECTOR_OPTIONS))]; max(sizeof(NTOS_OPTIONS), sizeof(BOOT_SECTOR_OPTIONS))];
PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
@ -1140,7 +1136,7 @@ FreeLdrEnumerateBootEntries(
if (!Iterator) return STATUS_SUCCESS; if (!Iterator) return STATUS_SUCCESS;
do do
{ {
PWCHAR InstallName; PCWSTR InstallName;
ULONG InstallNameLength; ULONG InstallNameLength;
/* Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni) */ /* Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni) */
@ -1195,9 +1191,8 @@ FreeLdrEnumerateBootEntries(
if (!OsIniSection) if (!OsIniSection)
goto DoEnum; goto DoEnum;
/* Check for supported boot type "Windows2003" */ /* Check for supported boot type */
Status = IniGetKey(OsIniSection, L"BootType", &KeyData); if (!IniGetKey(OsIniSection, L"BootType", &KeyData) || !KeyData)
if (!NT_SUCCESS(Status) || !KeyData)
{ {
/* Certainly not a ReactOS installation */ /* Certainly not a ReactOS installation */
DPRINT1("No BootType value present!\n"); DPRINT1("No BootType value present!\n");
@ -1222,15 +1217,13 @@ FreeLdrEnumerateBootEntries(
/* Check its SystemPath */ /* Check its SystemPath */
Options->OsLoadPath = NULL; Options->OsLoadPath = NULL;
Status = IniGetKey(OsIniSection, L"SystemPath", &KeyData); if (IniGetKey(OsIniSection, L"SystemPath", &KeyData))
if (NT_SUCCESS(Status))
Options->OsLoadPath = KeyData; Options->OsLoadPath = KeyData;
// KeyData == SystemRoot; // KeyData == SystemRoot;
/* Check the optional Options */ /* Check the optional Options */
Options->OsLoadOptions = NULL; Options->OsLoadOptions = NULL;
Status = IniGetKey(OsIniSection, L"Options", &KeyData); if (IniGetKey(OsIniSection, L"Options", &KeyData))
if (NT_SUCCESS(Status))
Options->OsLoadOptions = KeyData; Options->OsLoadOptions = KeyData;
} }
else else
@ -1251,20 +1244,17 @@ FreeLdrEnumerateBootEntries(
/* Check its BootDrive */ /* Check its BootDrive */
Options->Drive = NULL; Options->Drive = NULL;
Status = IniGetKey(OsIniSection, L"BootDrive", &KeyData); if (IniGetKey(OsIniSection, L"BootDrive", &KeyData))
if (NT_SUCCESS(Status))
Options->Drive = KeyData; Options->Drive = KeyData;
/* Check its BootPartition */ /* Check its BootPartition */
Options->Partition = NULL; Options->Partition = NULL;
Status = IniGetKey(OsIniSection, L"BootPartition", &KeyData); if (IniGetKey(OsIniSection, L"BootPartition", &KeyData))
if (NT_SUCCESS(Status))
Options->Partition = KeyData; Options->Partition = KeyData;
/* Check its BootSector */ /* Check its BootSector */
Options->BootSectorFileName = NULL; Options->BootSectorFileName = NULL;
Status = IniGetKey(OsIniSection, L"BootSectorFile", &KeyData); if (IniGetKey(OsIniSection, L"BootSectorFile", &KeyData))
if (NT_SUCCESS(Status))
Options->BootSectorFileName = KeyData; Options->BootSectorFileName = KeyData;
} }
else else
@ -1300,7 +1290,7 @@ NtLdrEnumerateBootEntries(
{ {
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
PINICACHEITERATOR Iterator; PINICACHEITERATOR Iterator;
PWCHAR SectionName, KeyData; PCWSTR SectionName, KeyData;
UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)]; UCHAR xxBootEntry[FIELD_OFFSET(BOOT_STORE_ENTRY, OsOptions) + sizeof(NTOS_OPTIONS)];
PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry; PBOOT_STORE_ENTRY BootEntry = (PBOOT_STORE_ENTRY)&xxBootEntry;
PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions; PNTOS_OPTIONS Options = (PNTOS_OPTIONS)&BootEntry->OsOptions;
@ -1312,7 +1302,7 @@ NtLdrEnumerateBootEntries(
if (!Iterator) return STATUS_SUCCESS; if (!Iterator) return STATUS_SUCCESS;
do do
{ {
PWCHAR InstallName, OsOptions; PCWSTR InstallName, OsOptions;
ULONG InstallNameLength, OsOptionsLength; ULONG InstallNameLength, OsOptionsLength;
/* Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni) */ /* Poor-man quotes removal (improvement over bootsup.c:UpdateFreeLoaderIni) */

View file

@ -16,60 +16,38 @@
/* PRIVATE FUNCTIONS ********************************************************/ /* PRIVATE FUNCTIONS ********************************************************/
static static VOID
PINI_KEYWORD
IniCacheFreeKey( IniCacheFreeKey(
PINI_KEYWORD Key) _In_ PINI_KEYWORD Key)
{ {
PINI_KEYWORD Next; /* Unlink the key */
RemoveEntryList(&Key->ListEntry);
if (Key == NULL) /* Free its data */
return NULL; if (Key->Name)
Next = Key->Next;
if (Key->Name != NULL)
{
RtlFreeHeap(ProcessHeap, 0, Key->Name); RtlFreeHeap(ProcessHeap, 0, Key->Name);
Key->Name = NULL; if (Key->Data)
}
if (Key->Data != NULL)
{
RtlFreeHeap(ProcessHeap, 0, Key->Data); RtlFreeHeap(ProcessHeap, 0, Key->Data);
Key->Data = NULL;
}
RtlFreeHeap(ProcessHeap, 0, Key); RtlFreeHeap(ProcessHeap, 0, Key);
return Next;
} }
static static VOID
PINI_SECTION
IniCacheFreeSection( IniCacheFreeSection(
PINI_SECTION Section) _In_ PINI_SECTION Section)
{ {
PINI_SECTION Next; /* Unlink the section */
RemoveEntryList(&Section->ListEntry);
if (Section == NULL) /* Free its data */
return NULL; while (!IsListEmpty(&Section->KeyList))
Next = Section->Next;
while (Section->FirstKey != NULL)
{ {
Section->FirstKey = IniCacheFreeKey(Section->FirstKey); PLIST_ENTRY Entry = RemoveHeadList(&Section->KeyList);
PINI_KEYWORD Key = CONTAINING_RECORD(Entry, INI_KEYWORD, ListEntry);
IniCacheFreeKey(Key);
} }
Section->LastKey = NULL; if (Section->Name)
if (Section->Name != NULL)
{
RtlFreeHeap(ProcessHeap, 0, Section->Name); RtlFreeHeap(ProcessHeap, 0, Section->Name);
Section->Name = NULL;
}
RtlFreeHeap(ProcessHeap, 0, Section); RtlFreeHeap(ProcessHeap, 0, Section);
return Next;
} }
static static
@ -78,10 +56,13 @@ IniCacheFindSection(
_In_ PINICACHE Cache, _In_ PINICACHE Cache,
_In_ PCWSTR Name) _In_ PCWSTR Name)
{ {
PINI_SECTION Section; PLIST_ENTRY Entry;
for (Section = Cache->FirstSection; Section; Section = Section->Next) for (Entry = Cache->SectionList.Flink;
Entry != &Cache->SectionList;
Entry = Entry->Flink)
{ {
PINI_SECTION Section = CONTAINING_RECORD(Entry, INI_SECTION, ListEntry);
if (_wcsicmp(Section->Name, Name) == 0) if (_wcsicmp(Section->Name, Name) == 0)
return Section; return Section;
} }
@ -94,10 +75,13 @@ IniCacheFindKey(
_In_ PINI_SECTION Section, _In_ PINI_SECTION Section,
_In_ PCWSTR Name) _In_ PCWSTR Name)
{ {
PINI_KEYWORD Key; PLIST_ENTRY Entry;
for (Key = Section->FirstKey; Key; Key = Key->Next) for (Entry = Section->KeyList.Flink;
Entry != &Section->KeyList;
Entry = Entry->Flink)
{ {
PINI_KEYWORD Key = CONTAINING_RECORD(Entry, INI_KEYWORD, ListEntry);
if (_wcsicmp(Key->Name, Name) == 0) if (_wcsicmp(Key->Name, Name) == 0)
return Key; return Key;
} }
@ -208,43 +192,33 @@ IniCacheAddKeyAorW(
Key->Data = DataU; Key->Data = DataU;
/* Insert the key into section */ /* Insert the key into section */
if (Section->FirstKey == NULL) if (IsListEmpty(&Section->KeyList))
{ {
Section->FirstKey = Key; InsertHeadList(&Section->KeyList, &Key->ListEntry);
Section->LastKey = Key;
} }
else if ((InsertionType == INSERT_FIRST) || else if ((InsertionType == INSERT_FIRST) ||
((InsertionType == INSERT_BEFORE) && ((InsertionType == INSERT_BEFORE) &&
((AnchorKey == NULL) || (AnchorKey == Section->FirstKey)))) (!AnchorKey || (&AnchorKey->ListEntry == Section->KeyList.Flink))))
{ {
/* Insert at the head of the list */ /* Insert at the head of the list */
Section->FirstKey->Prev = Key; InsertHeadList(&Section->KeyList, &Key->ListEntry);
Key->Next = Section->FirstKey;
Section->FirstKey = Key;
} }
else if ((InsertionType == INSERT_BEFORE) && (AnchorKey != NULL)) else if ((InsertionType == INSERT_BEFORE) && AnchorKey)
{ {
/* Insert before the anchor key */ /* Insert before the anchor key */
Key->Next = AnchorKey; InsertTailList(&AnchorKey->ListEntry, &Key->ListEntry);
Key->Prev = AnchorKey->Prev;
AnchorKey->Prev->Next = Key;
AnchorKey->Prev = Key;
} }
else if ((InsertionType == INSERT_LAST) || else if ((InsertionType == INSERT_LAST) ||
((InsertionType == INSERT_AFTER) && ((InsertionType == INSERT_AFTER) &&
((AnchorKey == NULL) || (AnchorKey == Section->LastKey)))) (!AnchorKey || (&AnchorKey->ListEntry == Section->KeyList.Blink))))
{ {
Section->LastKey->Next = Key; /* Insert at the tail of the list */
Key->Prev = Section->LastKey; InsertTailList(&Section->KeyList, &Key->ListEntry);
Section->LastKey = Key;
} }
else if ((InsertionType == INSERT_AFTER) && (AnchorKey != NULL)) else if ((InsertionType == INSERT_AFTER) && AnchorKey)
{ {
/* Insert after the anchor key */ /* Insert after the anchor key */
Key->Next = AnchorKey->Next; InsertHeadList(&AnchorKey->ListEntry, &Key->ListEntry);
Key->Prev = AnchorKey;
AnchorKey->Next->Prev = Key;
AnchorKey->Next = Key;
} }
return Key; return Key;
@ -305,19 +279,10 @@ IniCacheAddSectionAorW(
return NULL; return NULL;
} }
Section->Name = NameU; Section->Name = NameU;
InitializeListHead(&Section->KeyList);
/* Append the section */ /* Append the section */
if (Cache->FirstSection == NULL) InsertTailList(&Cache->SectionList, &Section->ListEntry);
{
Cache->FirstSection = Section;
Cache->LastSection = Section;
}
else
{
Cache->LastSection->Next = Section;
Section->Prev = Cache->LastSection;
Cache->LastSection = Section;
}
return Section; return Section;
} }
@ -540,14 +505,9 @@ IniCacheLoadFromMemory(
ULONG KeyValueSize; ULONG KeyValueSize;
/* Allocate inicache header */ /* Allocate inicache header */
*Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap, *Cache = IniCacheCreate();
HEAP_ZERO_MEMORY, if (!*Cache)
sizeof(INICACHE));
if (*Cache == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
}
/* Parse ini file */ /* Parse ini file */
Section = NULL; Section = NULL;
@ -737,16 +697,17 @@ IniCacheLoad(
VOID VOID
IniCacheDestroy( IniCacheDestroy(
PINICACHE Cache) _In_ PINICACHE Cache)
{ {
if (Cache == NULL) if (!Cache)
return; return;
while (Cache->FirstSection != NULL) while (!IsListEmpty(&Cache->SectionList))
{ {
Cache->FirstSection = IniCacheFreeSection(Cache->FirstSection); PLIST_ENTRY Entry = RemoveHeadList(&Cache->SectionList);
PINI_SECTION Section = CONTAINING_RECORD(Entry, INI_SECTION, ListEntry);
IniCacheFreeSection(Section);
} }
Cache->LastSection = NULL;
RtlFreeHeap(ProcessHeap, 0, Cache); RtlFreeHeap(ProcessHeap, 0, Cache);
} }
@ -765,110 +726,110 @@ IniGetSection(
return IniCacheFindSection(Cache, Name); return IniCacheFindSection(Cache, Name);
} }
NTSTATUS PINI_KEYWORD
IniGetKey( IniGetKey(
PINI_SECTION Section, _In_ PINI_SECTION Section,
PWCHAR KeyName, _In_ PCWSTR KeyName,
PWCHAR *KeyData) _Out_ PCWSTR* KeyData)
{ {
PINI_KEYWORD Key; PINI_KEYWORD Key;
if (Section == NULL || KeyName == NULL || KeyData == NULL) if (!Section || !KeyName || !KeyData)
{ {
DPRINT("Invalid parameter\n"); DPRINT("Invalid parameter\n");
return STATUS_INVALID_PARAMETER; return NULL;
} }
*KeyData = NULL; *KeyData = NULL;
Key = IniCacheFindKey(Section, KeyName); Key = IniCacheFindKey(Section, KeyName);
if (Key == NULL) if (!Key)
{ return NULL;
return STATUS_INVALID_PARAMETER;
}
*KeyData = Key->Data; *KeyData = Key->Data;
return STATUS_SUCCESS; return Key;
} }
PINICACHEITERATOR PINICACHEITERATOR
IniFindFirstValue( IniFindFirstValue(
PINI_SECTION Section, _In_ PINI_SECTION Section,
PWCHAR *KeyName, _Out_ PCWSTR* KeyName,
PWCHAR *KeyData) _Out_ PCWSTR* KeyData)
{ {
PINICACHEITERATOR Iterator; PINICACHEITERATOR Iterator;
PLIST_ENTRY Entry;
PINI_KEYWORD Key; PINI_KEYWORD Key;
if (Section == NULL || KeyName == NULL || KeyData == NULL) if (!Section || !KeyName || !KeyData)
{ {
DPRINT("Invalid parameter\n"); DPRINT("Invalid parameter\n");
return NULL; return NULL;
} }
Key = Section->FirstKey; Entry = Section->KeyList.Flink;
if (Key == NULL) if (Entry == &Section->KeyList)
{ {
DPRINT("Invalid parameter\n"); DPRINT("Invalid parameter\n");
return NULL; return NULL;
} }
Key = CONTAINING_RECORD(Entry, INI_KEYWORD, ListEntry);
*KeyName = Key->Name;
*KeyData = Key->Data;
Iterator = (PINICACHEITERATOR)RtlAllocateHeap(ProcessHeap, Iterator = (PINICACHEITERATOR)RtlAllocateHeap(ProcessHeap,
0, 0,
sizeof(INICACHEITERATOR)); sizeof(INICACHEITERATOR));
if (Iterator == NULL) if (!Iterator)
{ {
DPRINT("RtlAllocateHeap() failed\n"); DPRINT("RtlAllocateHeap() failed\n");
return NULL; return NULL;
} }
Iterator->Section = Section; Iterator->Section = Section;
Iterator->Key = Key; Iterator->Key = Key;
*KeyName = Key->Name;
*KeyData = Key->Data;
return Iterator; return Iterator;
} }
BOOLEAN BOOLEAN
IniFindNextValue( IniFindNextValue(
PINICACHEITERATOR Iterator, _In_ PINICACHEITERATOR Iterator,
PWCHAR *KeyName, _Out_ PCWSTR* KeyName,
PWCHAR *KeyData) _Out_ PCWSTR* KeyData)
{ {
PLIST_ENTRY Entry;
PINI_KEYWORD Key; PINI_KEYWORD Key;
if (Iterator == NULL || KeyName == NULL || KeyData == NULL) if (!Iterator || !KeyName || !KeyData)
{ {
DPRINT("Invalid parameter\n"); DPRINT("Invalid parameter\n");
return FALSE; return FALSE;
} }
Key = Iterator->Key->Next; Entry = Iterator->Key->ListEntry.Flink;
if (Key == NULL) if (Entry == &Iterator->Section->KeyList)
{ {
DPRINT("No more entries\n"); DPRINT("No more entries\n");
return FALSE; return FALSE;
} }
Key = CONTAINING_RECORD(Entry, INI_KEYWORD, ListEntry);
Iterator->Key = Key;
*KeyName = Key->Name; *KeyName = Key->Name;
*KeyData = Key->Data; *KeyData = Key->Data;
Iterator->Key = Key;
return TRUE; return TRUE;
} }
VOID VOID
IniFindClose( IniFindClose(
PINICACHEITERATOR Iterator) _In_ PINICACHEITERATOR Iterator)
{ {
if (Iterator == NULL) if (!Iterator)
return; return;
RtlFreeHeap(ProcessHeap, 0, Iterator); RtlFreeHeap(ProcessHeap, 0, Iterator);
} }
@ -886,6 +847,18 @@ IniAddSection(
return IniCacheAddSectionAorW(Cache, Name, wcslen(Name), TRUE); return IniCacheAddSectionAorW(Cache, Name, wcslen(Name), TRUE);
} }
VOID
IniRemoveSection(
_In_ PINI_SECTION Section)
{
if (!Section)
{
DPRINT("Invalid parameter\n");
return;
}
IniCacheFreeSection(Section);
}
PINI_KEYWORD PINI_KEYWORD
IniInsertKey( IniInsertKey(
_In_ PINI_SECTION Section, _In_ PINI_SECTION Section,
@ -915,6 +888,32 @@ IniAddKey(
return IniInsertKey(Section, NULL, INSERT_LAST, Name, Data); return IniInsertKey(Section, NULL, INSERT_LAST, Name, Data);
} }
VOID
IniRemoveKeyByName(
_In_ PINI_SECTION Section,
_In_ PCWSTR KeyName)
{
PINI_KEYWORD Key;
UNREFERENCED_PARAMETER(Section);
Key = IniCacheFindKey(Section, KeyName);
if (Key)
IniCacheFreeKey(Key);
}
VOID
IniRemoveKey(
_In_ PINI_SECTION Section,
_In_ PINI_KEYWORD Key)
{
UNREFERENCED_PARAMETER(Section);
if (!Key)
{
DPRINT("Invalid parameter\n");
return;
}
IniCacheFreeKey(Key);
}
PINICACHE PINICACHE
IniCacheCreate(VOID) IniCacheCreate(VOID)
@ -925,11 +924,12 @@ IniCacheCreate(VOID)
Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap, Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY, HEAP_ZERO_MEMORY,
sizeof(INICACHE)); sizeof(INICACHE));
if (Cache == NULL) if (!Cache)
{ {
DPRINT("RtlAllocateHeap() failed\n"); DPRINT("RtlAllocateHeap() failed\n");
return NULL; return NULL;
} }
InitializeListHead(&Cache->SectionList);
return Cache; return Cache;
} }
@ -940,6 +940,7 @@ IniCacheSaveByHandle(
HANDLE FileHandle) HANDLE FileHandle)
{ {
NTSTATUS Status; NTSTATUS Status;
PLIST_ENTRY Entry1, Entry2;
PINI_SECTION Section; PINI_SECTION Section;
PINI_KEYWORD Key; PINI_KEYWORD Key;
ULONG BufferSize; ULONG BufferSize;
@ -951,23 +952,25 @@ IniCacheSaveByHandle(
/* Calculate required buffer size */ /* Calculate required buffer size */
BufferSize = 0; BufferSize = 0;
Section = Cache->FirstSection; Entry1 = Cache->SectionList.Flink;
while (Section != NULL) while (Entry1 != &Cache->SectionList)
{ {
Section = CONTAINING_RECORD(Entry1, INI_SECTION, ListEntry);
BufferSize += (Section->Name ? wcslen(Section->Name) : 0) BufferSize += (Section->Name ? wcslen(Section->Name) : 0)
+ 4; /* "[]\r\n" */ + 4; /* "[]\r\n" */
Key = Section->FirstKey; Entry2 = Section->KeyList.Flink;
while (Key != NULL) while (Entry2 != &Section->KeyList)
{ {
Key = CONTAINING_RECORD(Entry2, INI_KEYWORD, ListEntry);
BufferSize += wcslen(Key->Name) BufferSize += wcslen(Key->Name)
+ (Key->Data ? wcslen(Key->Data) : 0) + (Key->Data ? wcslen(Key->Data) : 0)
+ 3; /* "=\r\n" */ + 3; /* "=\r\n" */
Key = Key->Next; Entry2 = Entry2->Flink;
} }
Section = Section->Next; Entry1 = Entry1->Flink;
if (Section != NULL) if (Entry1 != &Cache->SectionList)
BufferSize += 2; /* Extra "\r\n" at end of each section */ BufferSize += 2; /* Extra "\r\n" at end of each section */
} }
@ -985,22 +988,24 @@ IniCacheSaveByHandle(
/* Fill file buffer */ /* Fill file buffer */
Ptr = Buffer; Ptr = Buffer;
Section = Cache->FirstSection; Entry1 = Cache->SectionList.Flink;
while (Section != NULL) while (Entry1 != &Cache->SectionList)
{ {
Section = CONTAINING_RECORD(Entry1, INI_SECTION, ListEntry);
Len = sprintf(Ptr, "[%S]\r\n", Section->Name); Len = sprintf(Ptr, "[%S]\r\n", Section->Name);
Ptr += Len; Ptr += Len;
Key = Section->FirstKey; Entry2 = Section->KeyList.Flink;
while (Key != NULL) while (Entry2 != &Section->KeyList)
{ {
Key = CONTAINING_RECORD(Entry2, INI_KEYWORD, ListEntry);
Len = sprintf(Ptr, "%S=%S\r\n", Key->Name, Key->Data); Len = sprintf(Ptr, "%S=%S\r\n", Key->Name, Key->Data);
Ptr += Len; Ptr += Len;
Key = Key->Next; Entry2 = Entry2->Flink;
} }
Section = Section->Next; Entry1 = Entry1->Flink;
if (Section != NULL) if (Entry1 != &Cache->SectionList)
{ {
Len = sprintf(Ptr, "\r\n"); Len = sprintf(Ptr, "\r\n");
Ptr += Len; Ptr += Len;

View file

@ -11,26 +11,19 @@ typedef struct _INI_KEYWORD
{ {
PWSTR Name; PWSTR Name;
PWSTR Data; PWSTR Data;
LIST_ENTRY ListEntry;
struct _INI_KEYWORD *Next;
struct _INI_KEYWORD *Prev;
} INI_KEYWORD, *PINI_KEYWORD; } INI_KEYWORD, *PINI_KEYWORD;
typedef struct _INI_SECTION typedef struct _INI_SECTION
{ {
PWSTR Name; PWSTR Name;
LIST_ENTRY KeyList;
PINI_KEYWORD FirstKey; LIST_ENTRY ListEntry;
PINI_KEYWORD LastKey;
struct _INI_SECTION *Next;
struct _INI_SECTION *Prev;
} INI_SECTION, *PINI_SECTION; } INI_SECTION, *PINI_SECTION;
typedef struct _INICACHE typedef struct _INICACHE
{ {
PINI_SECTION FirstSection; LIST_ENTRY SectionList;
PINI_SECTION LastSection;
} INICACHE, *PINICACHE; } INICACHE, *PINICACHE;
typedef struct _PINICACHEITERATOR typedef struct _PINICACHEITERATOR
@ -70,40 +63,44 @@ IniCacheLoad(
VOID VOID
IniCacheDestroy( IniCacheDestroy(
PINICACHE Cache); _In_ PINICACHE Cache);
PINI_SECTION PINI_SECTION
IniGetSection( IniGetSection(
_In_ PINICACHE Cache, _In_ PINICACHE Cache,
_In_ PCWSTR Name); _In_ PCWSTR Name);
NTSTATUS PINI_KEYWORD
IniGetKey( IniGetKey(
PINI_SECTION Section, _In_ PINI_SECTION Section,
PWCHAR KeyName, _In_ PCWSTR KeyName,
PWCHAR *KeyData); _Out_ PCWSTR* KeyData);
PINICACHEITERATOR PINICACHEITERATOR
IniFindFirstValue( IniFindFirstValue(
PINI_SECTION Section, _In_ PINI_SECTION Section,
PWCHAR *KeyName, _Out_ PCWSTR* KeyName,
PWCHAR *KeyData); _Out_ PCWSTR* KeyData);
BOOLEAN BOOLEAN
IniFindNextValue( IniFindNextValue(
PINICACHEITERATOR Iterator, _In_ PINICACHEITERATOR Iterator,
PWCHAR *KeyName, _Out_ PCWSTR* KeyName,
PWCHAR *KeyData); _Out_ PCWSTR* KeyData);
VOID VOID
IniFindClose( IniFindClose(
PINICACHEITERATOR Iterator); _In_ PINICACHEITERATOR Iterator);
PINI_SECTION PINI_SECTION
IniAddSection( IniAddSection(
_In_ PINICACHE Cache, _In_ PINICACHE Cache,
_In_ PCWSTR Name); _In_ PCWSTR Name);
VOID
IniRemoveSection(
_In_ PINI_SECTION Section);
PINI_KEYWORD PINI_KEYWORD
IniInsertKey( IniInsertKey(
_In_ PINI_SECTION Section, _In_ PINI_SECTION Section,
@ -118,6 +115,16 @@ IniAddKey(
_In_ PCWSTR Name, _In_ PCWSTR Name,
_In_ PCWSTR Data); _In_ PCWSTR Data);
VOID
IniRemoveKeyByName(
_In_ PINI_SECTION Section,
_In_ PCWSTR KeyName);
VOID
IniRemoveKey(
_In_ PINI_SECTION Section,
_In_ PINI_KEYWORD Key);
PINICACHE PINICACHE
IniCacheCreate(VOID); IniCacheCreate(VOID);