aboutsummaryrefslogtreecommitdiffstats
path: root/api/logger.c
diff options
context:
space:
mode:
authorSimon Rozman <simon@rozman.si>2021-02-06 09:38:50 +0100
committerSimon Rozman <simon@rozman.si>2021-02-06 09:38:50 +0100
commit70b8903c503f400a6e11a0dd657ef99e634493cd (patch)
tree69416af10ab24ce695c0832ad823588616c9355c /api/logger.c
parentapi: upgrade logging (diff)
downloadwintun-sr/simons-wild-n-crazy-printf.tar.xz
wintun-sr/simons-wild-n-crazy-printf.zip
api: implement %r format type for logging registry pathsr/simons-wild-n-crazy-printf
Note: Once reviewed, merge with 728d6762cd95394f2541d4a3f3e7fdd17ecd8f2a Signed-off-by: Simon Rozman <simon@rozman.si>
Diffstat (limited to 'api/logger.c')
-rw-r--r--api/logger.c221
1 files changed, 182 insertions, 39 deletions
diff --git a/api/logger.c b/api/logger.c
index 7907437..0a8461b 100644
--- a/api/logger.c
+++ b/api/logger.c
@@ -9,6 +9,9 @@
#include <winternl.h>
#include <wchar.h>
+#define _PRECISION_MAX ((size_t)-1)
+#define _PRECISION_RUNTIME ((size_t)-2)
+
static BOOL CALLBACK
NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
{
@@ -51,16 +54,187 @@ LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ c
return LastError;
}
+VOID
+LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path)
+{
+ DWORD LastError = GetLastError();
+ if (Key == NULL)
+ {
+ wcscpy_s(Path, MAX_REG_PATH, L"<null>");
+ goto out;
+ }
+ if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1)
+ StrTruncate(Path, MAX_REG_PATH);
+ union
+ {
+ KEY_NAME_INFORMATION KeyNameInfo;
+ WCHAR Data[offsetof(KEY_NAME_INFORMATION, Name) + MAX_REG_PATH];
+ } Buffer;
+ DWORD Size;
+ if (!NT_SUCCESS(NtQueryKey(Key, 3, &Buffer, sizeof(Buffer), &Size)) ||
+ Size < offsetof(KEY_NAME_INFORMATION, Name) || Buffer.KeyNameInfo.NameLength >= MAX_REG_PATH * sizeof(WCHAR))
+ goto out;
+ Buffer.KeyNameInfo.NameLength /= sizeof(WCHAR);
+ wmemcpy_s(Path, MAX_REG_PATH, Buffer.KeyNameInfo.Name, Buffer.KeyNameInfo.NameLength);
+ Path[Buffer.KeyNameInfo.NameLength] = L'\0';
+out:
+ SetLastError(LastError);
+}
+
+_Success_(return >= 0)
+_Check_return_opt_ static ptrdiff_t
+PushTerminator(
+ _Out_writes_(BufferCount) _Always_(_Post_z_) wchar_t *Buffer,
+ _In_ size_t BufferCount,
+ _In_ size_t MaxCount,
+ _In_ size_t Count)
+{
+ if (Count < BufferCount)
+ {
+ Buffer[Count] = L'\0';
+ return Count;
+ }
+ if (MaxCount == _TRUNCATE)
+ {
+ Buffer[BufferCount - 1] = L'\0';
+ return -1;
+ }
+ _invalid_parameter_noinfo();
+ _set_errno(ERANGE);
+ Buffer[0] = L'\0';
+ return -1;
+}
+
+static ptrdiff_t
+PushChar(
+ _Out_writes_(BufferCount) wchar_t *Buffer,
+ _In_ size_t BufferCount,
+ _In_ size_t MaxCount,
+ _In_ size_t Count,
+ _In_ wchar_t Char)
+{
+ if (Count < BufferCount)
+ {
+ if (Count < MaxCount)
+ {
+ Buffer[Count] = Char;
+ return 1;
+ }
+ Buffer[MaxCount] = L'\0';
+ return -1;
+ }
+ if (MaxCount == _TRUNCATE)
+ {
+ Buffer[BufferCount - 1] = L'\0';
+ return -1;
+ }
+ _invalid_parameter_noinfo();
+ _set_errno(ERANGE);
+ Buffer[0] = L'\0';
+ return -1;
+}
+
+_Success_(return >= 0)
+_Check_return_opt_ static ptrdiff_t
+LoggerSPrintF(
+ _Out_writes_opt_(BufferCount) _Always_(_Post_z_) wchar_t *Buffer,
+ _In_ size_t BufferCount,
+ _In_ size_t MaxCount,
+ _In_z_ wchar_t const *Format,
+ va_list Args)
+{
+ if (!Buffer || !BufferCount || !Format)
+ {
+ _set_errno(EINVAL);
+ return -1;
+ }
+ for (size_t Count = 0;;)
+ {
+ ptrdiff_t Result;
+ if (*Format == L'\0')
+ return PushTerminator(Buffer, BufferCount, MaxCount, Count);
+ if (*Format != L'%')
+ {
+ Result = PushChar(Buffer, BufferCount, MaxCount, Count, *(Format++));
+ if (Result < 0)
+ return Result;
+ Count += Result;
+ continue;
+ }
+ const wchar_t *Flag = Format + 1, *FlagEnd = Flag + (wcschr(L"-+0 #", *Flag) ? 1 : 0);
+ const wchar_t *Width = FlagEnd, *WidthEnd = Width;
+#pragma warning(suppress : 6031)
+ wcstoul(Width, (wchar_t **)&WidthEnd, 10);
+ const wchar_t *Precision = WidthEnd, *PrecisionEnd = Precision;
+ size_t PrecisionVal = _PRECISION_MAX;
+ if (Precision[0] == L'.')
+ {
+ if (Precision[1] == L'*')
+ {
+ PrecisionVal = _PRECISION_RUNTIME;
+ PrecisionEnd = Precision + 2;
+ }
+ else
+ PrecisionVal = wcstoul(Precision + 1, (wchar_t **)&PrecisionEnd, 10);
+ }
+ size_t FieldPrecision;
+ const wchar_t *Size = PrecisionEnd, *SizeEnd = Size;
+ if (Size[0] == L'I' && (Size[1] == L'3' && Size[2] == L'2' || Size[1] == L'6' && Size[2] == L'4'))
+ SizeEnd = Size + 3;
+ else if (Size[0] == L'h' && Size[1] == L'h' || Size[0] == L'l' && Size[1] == L'l')
+ SizeEnd = Size + 2;
+ else if (
+ Size[0] == L'h' || Size[0] == L'I' || Size[0] == L'j' || Size[0] == L'l' || Size[0] == L'L' ||
+ Size[0] == L't' || Size[0] == L'w' || Size[0] == L'z')
+ SizeEnd = Size + 1;
+ const wchar_t *Type = SizeEnd, *TypeEnd = Type + 1;
+ if (*Type == L'r')
+ {
+ FieldPrecision = PrecisionVal == _PRECISION_RUNTIME ? va_arg(Args, unsigned long) : MAX_REG_PATH;
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(va_arg(Args, HKEY), RegPath);
+ for (size_t i = 0; i < FieldPrecision && RegPath[i];)
+ {
+ Result = PushChar(Buffer, BufferCount, MaxCount, Count, RegPath[i++]);
+ if (Result < 0)
+ return Result;
+ Count += Result;
+ }
+ Format = TypeEnd;
+ continue;
+ }
+ wchar_t FormatSub[100];
+ const size_t FormatSubCount = TypeEnd - Format;
+ if (FormatSubCount >= _countof(FormatSub))
+ {
+ _invalid_parameter(Format, _L(__FUNCTION__), _L(__FILE__), __LINE__, 0);
+ _set_errno(EINVAL);
+ Buffer[0] = L'\0';
+ return -1;
+ }
+ wmemcpy(FormatSub, Format, FormatSubCount);
+ FormatSub[FormatSubCount] = 0;
+ Result = _vsnwprintf_s(
+ Buffer + Count, BufferCount - Count, MaxCount != _TRUNCATE ? MaxCount - Count : _TRUNCATE, FormatSub, Args);
+ if (Result < 0)
+ return Result;
+ Count += Result;
+ Format = TypeEnd;
+#pragma warning(push)
+#pragma warning(disable : 6269)
+ if (PrecisionVal == _PRECISION_RUNTIME)
+ va_arg(Args, unsigned long);
+ va_arg(Args, int);
+#pragma warning(pop)
+ }
+}
+
_Post_equals_last_error_ DWORD
-LoggerLogV(
- _In_ WINTUN_LOGGER_LEVEL Level,
- _In_z_ const WCHAR *Function,
- _In_z_ _Printf_format_string_ const WCHAR *Format,
- _In_ va_list Args)
+LoggerLogV(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Format, _In_ va_list Args)
{
DWORD LastError = GetLastError();
WCHAR LogLine[0x400];
- if (_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1)
+ if (LoggerSPrintF(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1)
StrTruncate(LogLine, _countof(LogLine));
if (Function)
LoggerLog(Level, Function, LogLine);
@@ -99,41 +273,10 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *
}
_Post_equals_last_error_ DWORD
-LoggerErrorV(
- _In_ DWORD Error,
- _In_z_ const WCHAR *Function,
- _In_z_ _Printf_format_string_ const WCHAR *Format,
- _In_ va_list Args)
+LoggerErrorV(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Format, _In_ va_list Args)
{
WCHAR Prefix[0x400];
- if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1)
+ if (LoggerSPrintF(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1)
StrTruncate(Prefix, _countof(Prefix));
return LoggerError(Error, Function, Prefix);
}
-
-VOID
-LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path)
-{
- DWORD LastError = GetLastError();
- if (Key == NULL)
- {
- wcscpy_s(Path, MAX_REG_PATH, L"<null>");
- goto out;
- }
- if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1)
- StrTruncate(Path, MAX_REG_PATH);
- union
- {
- KEY_NAME_INFORMATION KeyNameInfo;
- WCHAR Data[offsetof(KEY_NAME_INFORMATION, Name) + MAX_REG_PATH];
- } Buffer;
- DWORD Size;
- if (!NT_SUCCESS(NtQueryKey(Key, 3, &Buffer, sizeof(Buffer), &Size)) ||
- Size < offsetof(KEY_NAME_INFORMATION, Name) || Buffer.KeyNameInfo.NameLength >= MAX_REG_PATH * sizeof(WCHAR))
- goto out;
- Buffer.KeyNameInfo.NameLength /= sizeof(WCHAR);
- wmemcpy_s(Path, MAX_REG_PATH, Buffer.KeyNameInfo.Name, Buffer.KeyNameInfo.NameLength);
- Path[Buffer.KeyNameInfo.NameLength] = L'\0';
-out:
- SetLastError(LastError);
-}