146 lines
4.6 KiB
C
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(§ionBegin, §ionEnd);
|
|
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;
|
|
}
|