From: Grigory Vasilyev h0tc0d3@gmail.com
--- dlls/kernel32/firmware.c | 78 +++++++++++++++++++++++++++++++++++++ dlls/kernel32/kernel32.spec | 2 + dlls/kernel32/process.c | 57 ++++++++++++++++++++++++--- dlls/kernel32/unixlib.h | 11 ++++++ 4 files changed, 142 insertions(+), 6 deletions(-)
diff --git a/dlls/kernel32/firmware.c b/dlls/kernel32/firmware.c index b5064a624a4..aba4fb70382 100644 --- a/dlls/kernel32/firmware.c +++ b/dlls/kernel32/firmware.c @@ -22,7 +22,16 @@ #pragma makedep unix #endif
+#include <errno.h> #include <dirent.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -46,14 +55,83 @@ static NTSTATUS kernel32_unix_get_firmware_type(void *args) return STATUS_SUCCESS; }
+/* Get Firmware Variable */ +static NTSTATUS kernel32_unix_get_firmware_variable(void *args) +{ + int fd, rc; + size_t bytes, pos = 0; + ssize_t ssz; + char tguid[37]; + char filename[128]; + struct stat sb = {0}; + struct wine_get_firmware_variable_params *params = args; + + int gsize = strlen(params->guid); + + if (params->guid[0] == '{' && params->guid[(gsize - 1)] == '}') { + if (gsize - 2 < sizeof(tguid)) + bytes = gsize - 1; + else + bytes = sizeof(tguid); + memcpy(tguid, params->guid + 1, bytes); + tguid[bytes - 1] = '\0'; + snprintf(filename, sizeof(filename), "/sys/firmware/efi/efivars/%s-%s", params->name, tguid); + } else { + snprintf(filename, sizeof(filename), "/sys/firmware/efi/efivars/%s-%s", params->name, params->guid); + } + + fd = open(filename, O_RDONLY | O_NONBLOCK); + if (fd < 0) + goto done; + + rc = fstat(fd, &sb); + if (rc < 0 || sb.st_size == 0) + goto done; + + if (sb.st_size - 4 < params->size) + bytes = sb.st_size - 4; + else + bytes = params->size; + +try_read_attributes: + ssz = read(fd, params->attributes, 4); + if (ssz < 0) { + if (errno == EAGAIN || errno == EINTR) + goto try_read_attributes; + goto done; + } + + while (pos < bytes) { + ssz = read(fd, (char *) params->buffer + pos, bytes - pos); + if (ssz < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + goto done; + } + pos += ssz; + } + + close(fd); + params->status = ssz & 0xFFFFFFFF; + return STATUS_SUCCESS; + +done: + if (fd >= 0) + close(fd); + params->status = 0; + return STATUS_UNSUCCESSFUL; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { kernel32_unix_get_firmware_type, + kernel32_unix_get_firmware_variable, };
#ifdef _WIN64
const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { kernel32_unix_get_firmware_type, + kernel32_unix_get_firmware_variable, };
#endif /* _WIN64 */ diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 7ed8048f5d0..5d3556a2078 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -695,7 +695,9 @@ @ stdcall -import GetFileType(long) @ stdcall -import GetFinalPathNameByHandleA(long ptr long long) @ stdcall -import GetFinalPathNameByHandleW(long ptr long long) +@ stdcall GetFirmwareEnvironmentVariableExA(str str ptr long ptr) @ stdcall GetFirmwareEnvironmentVariableA(str str ptr long) +@ stdcall GetFirmwareEnvironmentVariableExW(wstr wstr ptr long ptr) @ stdcall GetFirmwareEnvironmentVariableW(wstr wstr ptr long) @ stdcall GetFirmwareType(ptr) @ stdcall -import GetFullPathNameA(str long ptr ptr) diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index f96a66b78fc..bccc5dbc5f2 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -719,14 +719,60 @@ WORD WINAPI GetMaximumProcessorGroupCount(void) return groups; }
+/*********************************************************************** + * GetFirmwareEnvironmentVariableExA (KERNEL32.@) + */ +DWORD WINAPI GetFirmwareEnvironmentVariableExA(LPCSTR name, LPCSTR guid, PVOID buffer, DWORD size, PDWORD attributes) +{ + struct wine_get_firmware_variable_params params = { 0 }; + params.name = name; + params.guid = guid; + params.buffer = buffer; + params.size = size; + params.attributes = attributes; + WINE_UNIX_CALL( kernel32_unix_func_get_firmware_variable, ¶ms ); + return params.status; +} + /*********************************************************************** * GetFirmwareEnvironmentVariableA (KERNEL32.@) */ DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR name, LPCSTR guid, PVOID buffer, DWORD size) { - FIXME("stub: %s %s %p %lu\n", debugstr_a(name), debugstr_a(guid), buffer, size); - SetLastError(ERROR_INVALID_FUNCTION); - return 0; + DWORD dwAttributes; + return GetFirmwareEnvironmentVariableExA( name, guid, buffer, size, &dwAttributes ); +} + +/*********************************************************************** + * GetFirmwareEnvironmentVariableExW (KERNEL32.@) + */ +DWORD WINAPI GetFirmwareEnvironmentVariableExW(LPCWSTR name, LPCWSTR guid, PVOID buffer, DWORD size, PDWORD attributes) +{ + DWORD ret; + INT len; + char *aname; + char *aguid; + + len = lstrlenW( name ) + 1; + ret = WideCharToMultiByte( GetOEMCP(), 0, name, len, NULL, 0, NULL, NULL ); + if ( !( aname = RtlAllocateHeap( GetProcessHeap(), 0, ret * sizeof(aname) ) ) ) + return 0; + WideCharToMultiByte( GetOEMCP(), 0, name, len, aname, ret, NULL, NULL ); + + len = lstrlenW( guid ) + 1; + ret = WideCharToMultiByte( GetOEMCP(), 0, guid, len, NULL, 0, NULL, NULL ); + if ( !( aguid = RtlAllocateHeap( GetProcessHeap(), 0, ret * sizeof(aguid) ) ) ) { + HeapFree( GetProcessHeap(), 0, aname ); + return 0; + } + WideCharToMultiByte( GetOEMCP(), 0, guid, len, aguid, ret, NULL, NULL ); + + ret = GetFirmwareEnvironmentVariableExA( aname, aguid, buffer, size, attributes ); + + HeapFree( GetProcessHeap(), 0, aname ); + HeapFree( GetProcessHeap(), 0, aguid ); + + return ret; }
/*********************************************************************** @@ -734,9 +780,8 @@ DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR name, LPCSTR guid, PVOID buf */ DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR name, LPCWSTR guid, PVOID buffer, DWORD size) { - FIXME("stub: %s %s %p %lu\n", debugstr_w(name), debugstr_w(guid), buffer, size); - SetLastError(ERROR_INVALID_FUNCTION); - return 0; + DWORD dwAttributes; + return GetFirmwareEnvironmentVariableExW( name, guid, buffer, size, &dwAttributes ); }
/*********************************************************************** diff --git a/dlls/kernel32/unixlib.h b/dlls/kernel32/unixlib.h index 102f5645dc5..321c62194a6 100644 --- a/dlls/kernel32/unixlib.h +++ b/dlls/kernel32/unixlib.h @@ -23,9 +23,20 @@
#include "wine/unixlib.h"
+struct wine_get_firmware_variable_params +{ + LPCSTR name; + LPCSTR guid; + PVOID buffer; + DWORD size; + PDWORD attributes; + DWORD status; +}; + enum kernel32_unix_func { kernel32_unix_func_get_firmware_type, + kernel32_unix_func_get_firmware_variable, };
extern unixlib_handle_t __wine_unixlib_handle;