Files
nt-lite/code/kernel/ke_settings.c
T

146 lines
4.6 KiB
C

// Kernel settings reader. This file performs a direct lookup in the simple system settings file.
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <kernel/ke_settings.h>
#include <kernel/io_file.h>
#include <kernel/ke_system_root.h>
#include <kernel/mm_virt.h>
#define KE_SETTINGS_MAX_FILE_BYTES (64u * 1024u)
// Returns whether one settings.ini character is horizontal whitespace.
static bool KeSettingSpace(char c) {
return c == ' ' || c == '\t' || c == '\r';
}
// Trims horizontal whitespace from one immutable settings.ini span.
static void KeSettingTrim(const char** begin, const char** end) {
while (*begin < *end && KeSettingSpace(**begin))
++*begin;
while (*end > *begin && KeSettingSpace((*end)[-1]))
--*end;
}
// Returns whether one immutable span exactly matches a NUL-terminated string.
static bool KeSettingSpanEquals(const char* begin, const char* end, const char* text) {
while (begin < end && *text) {
if (*begin++ != *text++)
return false;
}
return begin == end && *text == '\0';
}
// Looks up one [section] key=value entry in a read-only settings buffer.
static KSTATUS KeFindSetting(const char* text, size_t length,
const char* wantedSection, const char* wantedKey,
char* buffer, size_t bufferSize) {
char section[64] = {0};
size_t offset = 0;
while (offset < length) {
size_t lineStart = offset;
while (offset < length && text[offset] != '\n')
++offset;
size_t lineEnd = offset;
if (offset < length)
++offset;
const char* begin = text + lineStart;
const char* end = text + lineEnd;
KeSettingTrim(&begin, &end);
if (begin == end || *begin == ';' || *begin == '#')
continue;
if (*begin == '[') {
if (end[-1] != ']')
return NTLSTATUS_INVALID_PARAMETER;
const char* sectionBegin = begin + 1;
const char* sectionEnd = end - 1;
KeSettingTrim(&sectionBegin, &sectionEnd);
size_t sectionLength = (size_t)(sectionEnd - sectionBegin);
if (sectionLength >= sizeof(section))
return NTLSTATUS_INVALID_PARAMETER;
memcpy(section, sectionBegin, sectionLength);
section[sectionLength] = '\0';
continue;
}
const char* equals = NULL;
for (const char* p = begin; p < end; ++p) {
if (*p == '=') {
equals = p;
break;
}
}
if (!equals)
continue;
const char* keyBegin = begin;
const char* keyEnd = equals;
const char* valueBegin = equals + 1;
const char* valueEnd = end;
KeSettingTrim(&keyBegin, &keyEnd);
KeSettingTrim(&valueBegin, &valueEnd);
if (strcmp(section, wantedSection) != 0 ||
!KeSettingSpanEquals(keyBegin, keyEnd, wantedKey)) {
continue;
}
size_t valueLength = (size_t)(valueEnd - valueBegin);
if (valueLength + 1u > bufferSize)
return NTLSTATUS_BUFFER_TOO_SMALL;
memcpy(buffer, valueBegin, valueLength);
buffer[valueLength] = '\0';
return NTLSTATUS_SUCCESS;
}
return NTLSTATUS_NOT_FOUND;
}
// Reads one string setting from the system settings file.
__declspec(dllexport) KSTATUS KeGetSettingString(const char* section,
const char* key,
char* buffer,
size_t bufferSize) {
if (!section || !*section || !key || !*key || !buffer || bufferSize == 0)
return NTLSTATUS_INVALID_PARAMETER;
buffer[0] = '\0';
FILE_OBJECT* file = NULL;
KSTATUS status = KeOpenSystemRootFile(KE_SETTINGS_PATH, &file);
if (!KSUCCESS(status))
return status;
uint64_t fileSize64 = IoGetFileSize(file);
if (fileSize64 >= KE_SETTINGS_MAX_FILE_BYTES) {
IoCloseFile(file);
return NTLSTATUS_BUFFER_TOO_SMALL;
}
size_t fileSize = (size_t)fileSize64;
char* text = (char*)MmAllocatePool(fileSize + 1u);
if (!text) {
IoCloseFile(file);
return NTLSTATUS_NO_MEMORY;
}
size_t got = 0;
status = IoReadFile(file, text, fileSize, &got);
IoCloseFile(file);
if (!KSUCCESS(status) || got != fileSize) {
MmFreePool(text);
return KSUCCESS(status) ? NTLSTATUS_FAILURE : status;
}
text[got] = '\0';
status = KeFindSetting(text, got, section, key, buffer, bufferSize);
MmFreePool(text);
return status;
}