Alien-uv
view release on metacpan or search on metacpan
libuv/src/win/util.c view on Meta::CPAN
#include <iphlpapi.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <windows.h>
#include <userenv.h>
#include <math.h>
/*
* Max title length; the only thing MSDN tells us about the maximum length
* of the console title is that it is smaller than 64K. However in practice
* it is much smaller, and there is no way to figure out what the exact length
* of the title is or can be, at least not on XP. To make it even more
* annoying, GetConsoleTitle fails when the buffer to be read into is bigger
* than the actual maximum length. So we make a conservative guess here;
* just don't put the novel you're writing in the title, unless the plot
* survives truncation.
*/
#define MAX_TITLE_LENGTH 8192
/* The number of nanoseconds in one second. */
#define UV__NANOSEC 1000000000
/* Max user name length, from iphlpapi.h */
#ifndef UNLEN
# define UNLEN 256
#endif
/* Maximum environment variable size, including the terminating null */
#define MAX_ENV_VAR_LENGTH 32767
/* Cached copy of the process title, plus a mutex guarding it. */
static char *process_title;
static CRITICAL_SECTION process_title_lock;
/* Interval (in seconds) of the high-resolution clock. */
static double hrtime_interval_ = 0;
/*
* One-time initialization code for functionality defined in util.c.
*/
void uv__util_init(void) {
LARGE_INTEGER perf_frequency;
/* Initialize process title access mutex. */
InitializeCriticalSection(&process_title_lock);
/* Retrieve high-resolution timer frequency
* and precompute its reciprocal.
*/
if (QueryPerformanceFrequency(&perf_frequency)) {
hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
} else {
hrtime_interval_= 0;
}
}
int uv_exepath(char* buffer, size_t* size_ptr) {
int utf8_len, utf16_buffer_len, utf16_len;
WCHAR* utf16_buffer;
int err;
if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
return UV_EINVAL;
}
if (*size_ptr > 32768) {
/* Windows paths can never be longer than this. */
utf16_buffer_len = 32768;
} else {
utf16_buffer_len = (int) *size_ptr;
}
utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
if (!utf16_buffer) {
return UV_ENOMEM;
}
/* Get the path as UTF-16. */
utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
if (utf16_len <= 0) {
err = GetLastError();
goto error;
}
/* utf16_len contains the length, *not* including the terminating null. */
utf16_buffer[utf16_len] = L'\0';
/* Convert to UTF-8 */
utf8_len = WideCharToMultiByte(CP_UTF8,
0,
utf16_buffer,
-1,
buffer,
(int) *size_ptr,
NULL,
NULL);
if (utf8_len == 0) {
err = GetLastError();
goto error;
}
uv__free(utf16_buffer);
/* utf8_len *does* include the terminating null at this point, but the
* returned size shouldn't. */
*size_ptr = utf8_len - 1;
return 0;
error:
uv__free(utf16_buffer);
return uv_translate_sys_error(err);
}
int uv_cwd(char* buffer, size_t* size) {
DWORD utf16_len;
WCHAR utf16_buffer[MAX_PATH];
int r;
if (buffer == NULL || size == NULL) {
return UV_EINVAL;
}
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
if (utf16_len == 0) {
return uv_translate_sys_error(GetLastError());
} else if (utf16_len > MAX_PATH) {
/* This should be impossible; however the CRT has a code path to deal with
* this scenario, so I added a check anyway. */
return UV_EIO;
}
/* utf16_len contains the length, *not* including the terminating null. */
utf16_buffer[utf16_len] = L'\0';
/* The returned directory should not have a trailing slash, unless it points
* at a drive root, like c:\. Remove it if needed. */
if (utf16_buffer[utf16_len - 1] == L'\\' &&
!(utf16_len == 3 && utf16_buffer[1] == L':')) {
utf16_len--;
utf16_buffer[utf16_len] = L'\0';
}
/* Check how much space we need */
r = WideCharToMultiByte(CP_UTF8,
0,
utf16_buffer,
-1,
NULL,
0,
NULL,
NULL);
if (r == 0) {
return uv_translate_sys_error(GetLastError());
} else if (r > (int) *size) {
*size = r;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
r = WideCharToMultiByte(CP_UTF8,
0,
utf16_buffer,
-1,
buffer,
*size > INT_MAX ? INT_MAX : (int) *size,
libuv/src/win/util.c view on Meta::CPAN
return argv;
}
int uv_set_process_title(const char* title) {
int err;
int length;
WCHAR* title_w = NULL;
uv__once_init();
/* Find out how big the buffer for the wide-char title must be */
length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
if (!length) {
err = GetLastError();
goto done;
}
/* Convert to wide-char string */
title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
if (!title_w) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length);
if (!length) {
err = GetLastError();
goto done;
}
/* If the title must be truncated insert a \0 terminator there */
if (length > MAX_TITLE_LENGTH) {
title_w[MAX_TITLE_LENGTH - 1] = L'\0';
}
if (!SetConsoleTitleW(title_w)) {
err = GetLastError();
goto done;
}
EnterCriticalSection(&process_title_lock);
uv__free(process_title);
process_title = uv__strdup(title);
LeaveCriticalSection(&process_title_lock);
err = 0;
done:
uv__free(title_w);
return uv_translate_sys_error(err);
}
static int uv__get_process_title(void) {
WCHAR title_w[MAX_TITLE_LENGTH];
if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
return -1;
}
if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0)
return -1;
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
if (buffer == NULL || size == 0)
return UV_EINVAL;
uv__once_init();
EnterCriticalSection(&process_title_lock);
/*
* If the process_title was never read before nor explicitly set,
* we must query it with getConsoleTitleW
*/
if (!process_title && uv__get_process_title() == -1) {
LeaveCriticalSection(&process_title_lock);
return uv_translate_sys_error(GetLastError());
}
assert(process_title);
len = strlen(process_title) + 1;
if (size < len) {
LeaveCriticalSection(&process_title_lock);
return UV_ENOBUFS;
}
memcpy(buffer, process_title, len);
LeaveCriticalSection(&process_title_lock);
return 0;
}
uint64_t uv_hrtime(void) {
uv__once_init();
return uv__hrtime(UV__NANOSEC);
}
uint64_t uv__hrtime(double scale) {
LARGE_INTEGER counter;
/* If the performance interval is zero, there's no support. */
if (hrtime_interval_ == 0) {
return 0;
}
if (!QueryPerformanceCounter(&counter)) {
return 0;
}
/* Because we have no guarantee about the order of magnitude of the
* performance counter interval, integer math could cause this computation
* to overflow. Therefore we resort to floating point math.
*/
libuv/src/win/util.c view on Meta::CPAN
goto error;
}
assert(result_size == sppi_size);
for (i = 0; i < cpu_count; i++) {
WCHAR key_name[128];
HKEY processor_key;
DWORD cpu_speed;
DWORD cpu_speed_size = sizeof(cpu_speed);
WCHAR cpu_brand[256];
DWORD cpu_brand_size = sizeof(cpu_brand);
size_t len;
len = _snwprintf(key_name,
ARRAY_SIZE(key_name),
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
i);
assert(len > 0 && len < ARRAY_SIZE(key_name));
err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
key_name,
0,
KEY_QUERY_VALUE,
&processor_key);
if (err != ERROR_SUCCESS) {
goto error;
}
err = RegQueryValueExW(processor_key,
L"~MHz",
NULL,
NULL,
(BYTE*)&cpu_speed,
&cpu_speed_size);
if (err != ERROR_SUCCESS) {
RegCloseKey(processor_key);
goto error;
}
err = RegQueryValueExW(processor_key,
L"ProcessorNameString",
NULL,
NULL,
(BYTE*)&cpu_brand,
&cpu_brand_size);
RegCloseKey(processor_key);
if (err != ERROR_SUCCESS)
goto error;
cpu_info = &cpu_infos[i];
cpu_info->speed = cpu_speed;
cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
sppi[i].IdleTime.QuadPart) / 10000;
cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
cpu_info->cpu_times.nice = 0;
uv__convert_utf16_to_utf8(cpu_brand,
cpu_brand_size / sizeof(WCHAR),
&(cpu_info->model));
}
uv__free(sppi);
*cpu_count_ptr = cpu_count;
*cpu_infos_ptr = cpu_infos;
return 0;
error:
/* This is safe because the cpu_infos array is zeroed on allocation. */
for (i = 0; i < cpu_count; i++)
uv__free(cpu_infos[i].model);
uv__free(cpu_infos);
uv__free(sppi);
return uv_translate_sys_error(err);
}
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(cpu_infos[i].model);
}
uv__free(cpu_infos);
}
static int is_windows_version_or_greater(DWORD os_major,
DWORD os_minor,
WORD service_pack_major,
WORD service_pack_minor) {
OSVERSIONINFOEX osvi;
DWORDLONG condition_mask = 0;
int op = VER_GREATER_EQUAL;
/* Initialize the OSVERSIONINFOEX structure. */
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvi.dwMajorVersion = os_major;
osvi.dwMinorVersion = os_minor;
osvi.wServicePackMajor = service_pack_major;
osvi.wServicePackMinor = service_pack_minor;
/* Initialize the condition mask. */
VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
/* Perform the test. */
return (int) VerifyVersionInfo(
&osvi,
VER_MAJORVERSION | VER_MINORVERSION |
libuv/src/win/util.c view on Meta::CPAN
return uv_translate_sys_error(GetLastError());
} else if (len > MAX_PATH + 1) {
/* This should not be possible */
return UV_EIO;
}
/* The returned directory should not have a trailing slash, unless it points
* at a drive root, like c:\. Remove it if needed. */
if (path[len - 1] == L'\\' &&
!(len == 3 && path[1] == L':')) {
len--;
path[len] = L'\0';
}
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
path,
-1,
buffer,
*size,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
*size = bufsize - 1;
return 0;
}
void uv_os_free_passwd(uv_passwd_t* pwd) {
if (pwd == NULL)
return;
uv__free(pwd->username);
uv__free(pwd->homedir);
pwd->username = NULL;
pwd->homedir = NULL;
}
/*
* Converts a UTF-16 string into a UTF-8 one. The resulting string is
* null-terminated.
*
* If utf16 is null terminated, utf16len can be set to -1, otherwise it must
* be specified.
*/
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
DWORD bufsize;
if (utf16 == NULL)
return UV_EINVAL;
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
utf16,
utf16len,
NULL,
0,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
/* Allocate the destination buffer adding an extra byte for the terminating
* NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
* we do it ourselves always, just in case. */
*utf8 = uv__malloc(bufsize + 1);
if (*utf8 == NULL)
return UV_ENOMEM;
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
utf16,
utf16len,
*utf8,
bufsize,
NULL,
NULL);
if (bufsize == 0) {
uv__free(*utf8);
*utf8 = NULL;
return uv_translate_sys_error(GetLastError());
}
(*utf8)[bufsize] = '\0';
return 0;
}
/*
* Converts a UTF-8 string into a UTF-16 one. The resulting string is
* null-terminated.
*
* If utf8 is null terminated, utf8len can be set to -1, otherwise it must
* be specified.
*/
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
int bufsize;
if (utf8 == NULL)
return UV_EINVAL;
/* Check how much space we need */
bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
/* Allocate the destination buffer adding an extra byte for the terminating
* NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
* we do it ourselves always, just in case. */
*utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1));
if (*utf16 == NULL)
return UV_ENOMEM;
/* Convert to UTF-16 */
bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
if (bufsize == 0) {
uv__free(*utf16);
*utf16 = NULL;
return uv_translate_sys_error(GetLastError());
}
(*utf16)[bufsize] = '\0';
return 0;
}
int uv__getpwuid_r(uv_passwd_t* pwd) {
HANDLE token;
wchar_t username[UNLEN + 1];
wchar_t path[MAX_PATH];
DWORD bufsize;
int r;
if (pwd == NULL)
return UV_EINVAL;
/* Get the home directory using GetUserProfileDirectoryW() */
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
return uv_translate_sys_error(GetLastError());
bufsize = ARRAY_SIZE(path);
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
r = GetLastError();
CloseHandle(token);
/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
return UV_ENOMEM;
return uv_translate_sys_error(r);
}
CloseHandle(token);
/* Get the username using GetUserNameW() */
bufsize = ARRAY_SIZE(username);
if (!GetUserNameW(username, &bufsize)) {
r = GetLastError();
/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
return UV_ENOMEM;
return uv_translate_sys_error(r);
}
pwd->homedir = NULL;
r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
if (r != 0)
return r;
pwd->username = NULL;
r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
if (r != 0) {
uv__free(pwd->homedir);
return r;
}
pwd->shell = NULL;
pwd->uid = -1;
pwd->gid = -1;
return 0;
}
int uv_os_get_passwd(uv_passwd_t* pwd) {
return uv__getpwuid_r(pwd);
}
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
wchar_t var[MAX_ENV_VAR_LENGTH];
wchar_t* name_w;
DWORD bufsize;
size_t len;
int r;
if (name == NULL || buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
r = uv__convert_utf8_to_utf16(name, -1, &name_w);
if (r != 0)
return r;
len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
uv__free(name_w);
assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
if (len == 0) {
r = GetLastError();
if (r == ERROR_ENVVAR_NOT_FOUND)
return UV_ENOENT;
return uv_translate_sys_error(r);
}
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
var,
-1,
buffer,
*size,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
*size = bufsize - 1;
return 0;
}
int uv_os_setenv(const char* name, const char* value) {
wchar_t* name_w;
wchar_t* value_w;
int r;
if (name == NULL || value == NULL)
return UV_EINVAL;
r = uv__convert_utf8_to_utf16(name, -1, &name_w);
if (r != 0)
return r;
r = uv__convert_utf8_to_utf16(value, -1, &value_w);
if (r != 0) {
uv__free(name_w);
return r;
}
r = SetEnvironmentVariableW(name_w, value_w);
uv__free(name_w);
uv__free(value_w);
if (r == 0)
return uv_translate_sys_error(GetLastError());
return 0;
}
int uv_os_unsetenv(const char* name) {
wchar_t* name_w;
int r;
if (name == NULL)
return UV_EINVAL;
r = uv__convert_utf8_to_utf16(name, -1, &name_w);
if (r != 0)
return r;
r = SetEnvironmentVariableW(name_w, NULL);
uv__free(name_w);
if (r == 0)
return uv_translate_sys_error(GetLastError());
return 0;
}
int uv_os_gethostname(char* buffer, size_t* size) {
char buf[UV_MAXHOSTNAMESIZE];
size_t len;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
uv__once_init(); /* Initialize winsock */
if (gethostname(buf, sizeof(buf)) != 0)
return uv_translate_sys_error(WSAGetLastError());
buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
len = strlen(buf);
if (len >= *size) {
*size = len + 1;
return UV_ENOBUFS;
}
memcpy(buffer, buf, len + 1);
*size = len;
return 0;
}
static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
int r;
if (pid == 0)
*handle = GetCurrentProcess();
else
*handle = OpenProcess(access, FALSE, pid);
if (*handle == NULL) {
r = GetLastError();
if (r == ERROR_INVALID_PARAMETER)
return UV_ESRCH;
else
return uv_translate_sys_error(r);
}
return 0;
}
( run in 1.476 second using v1.01-cache-2.11-cpan-acebb50784d )