Blame src/win/util.c

Packit b5b901
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit b5b901
 *
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include <assert.h>
Packit b5b901
#include <direct.h>
Packit b5b901
#include <limits.h>
Packit b5b901
#include <stdio.h>
Packit b5b901
#include <string.h>
Packit b5b901
#include <time.h>
Packit b5b901
#include <wchar.h>
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "internal.h"
Packit b5b901
Packit b5b901
#include <winsock2.h>
Packit b5b901
#include <winperf.h>
Packit b5b901
#include <iphlpapi.h>
Packit b5b901
#include <psapi.h>
Packit b5b901
#include <tlhelp32.h>
Packit b5b901
#include <windows.h>
Packit b5b901
#include <userenv.h>
Packit b5b901
#include <math.h>
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * Max title length; the only thing MSDN tells us about the maximum length
Packit b5b901
 * of the console title is that it is smaller than 64K. However in practice
Packit b5b901
 * it is much smaller, and there is no way to figure out what the exact length
Packit b5b901
 * of the title is or can be, at least not on XP. To make it even more
Packit b5b901
 * annoying, GetConsoleTitle fails when the buffer to be read into is bigger
Packit b5b901
 * than the actual maximum length. So we make a conservative guess here;
Packit b5b901
 * just don't put the novel you're writing in the title, unless the plot
Packit b5b901
 * survives truncation.
Packit b5b901
 */
Packit b5b901
#define MAX_TITLE_LENGTH 8192
Packit b5b901
Packit b5b901
/* The number of nanoseconds in one second. */
Packit b5b901
#define UV__NANOSEC 1000000000
Packit b5b901
Packit b5b901
/* Max user name length, from iphlpapi.h */
Packit b5b901
#ifndef UNLEN
Packit b5b901
# define UNLEN 256
Packit b5b901
#endif
Packit b5b901
Packit b5b901
Packit Service e08953
/* A RtlGenRandom() by any other name... */
Packit Service e08953
extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
Packit b5b901
Packit b5b901
/* Cached copy of the process title, plus a mutex guarding it. */
Packit b5b901
static char *process_title;
Packit b5b901
static CRITICAL_SECTION process_title_lock;
Packit b5b901
Packit b5b901
/* Interval (in seconds) of the high-resolution clock. */
Packit b5b901
static double hrtime_interval_ = 0;
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * One-time initialization code for functionality defined in util.c.
Packit b5b901
 */
Packit b5b901
void uv__util_init(void) {
Packit b5b901
  LARGE_INTEGER perf_frequency;
Packit b5b901
Packit b5b901
  /* Initialize process title access mutex. */
Packit b5b901
  InitializeCriticalSection(&process_title_lock);
Packit b5b901
Packit b5b901
  /* Retrieve high-resolution timer frequency
Packit b5b901
   * and precompute its reciprocal.
Packit b5b901
   */
Packit b5b901
  if (QueryPerformanceFrequency(&perf_frequency)) {
Packit b5b901
    hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
Packit b5b901
  } else {
Packit b5b901
    hrtime_interval_= 0;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_exepath(char* buffer, size_t* size_ptr) {
Packit b5b901
  int utf8_len, utf16_buffer_len, utf16_len;
Packit b5b901
  WCHAR* utf16_buffer;
Packit b5b901
  int err;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (*size_ptr > 32768) {
Packit b5b901
    /* Windows paths can never be longer than this. */
Packit b5b901
    utf16_buffer_len = 32768;
Packit b5b901
  } else {
Packit b5b901
    utf16_buffer_len = (int) *size_ptr;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
Packit b5b901
  if (!utf16_buffer) {
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Get the path as UTF-16. */
Packit b5b901
  utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
Packit b5b901
  if (utf16_len <= 0) {
Packit b5b901
    err = GetLastError();
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* utf16_len contains the length, *not* including the terminating null. */
Packit b5b901
  utf16_buffer[utf16_len] = L'\0';
Packit b5b901
Packit b5b901
  /* Convert to UTF-8 */
Packit b5b901
  utf8_len = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                 0,
Packit b5b901
                                 utf16_buffer,
Packit b5b901
                                 -1,
Packit b5b901
                                 buffer,
Packit b5b901
                                 (int) *size_ptr,
Packit b5b901
                                 NULL,
Packit b5b901
                                 NULL);
Packit b5b901
  if (utf8_len == 0) {
Packit b5b901
    err = GetLastError();
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__free(utf16_buffer);
Packit b5b901
Packit b5b901
  /* utf8_len *does* include the terminating null at this point, but the
Packit b5b901
   * returned size shouldn't. */
Packit b5b901
  *size_ptr = utf8_len - 1;
Packit b5b901
  return 0;
Packit b5b901
Packit b5b901
 error:
Packit b5b901
  uv__free(utf16_buffer);
Packit b5b901
  return uv_translate_sys_error(err);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_cwd(char* buffer, size_t* size) {
Packit b5b901
  DWORD utf16_len;
Packit Service e08953
  WCHAR *utf16_buffer;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == NULL) {
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  utf16_len = GetCurrentDirectoryW(0, NULL);
Packit b5b901
  if (utf16_len == 0) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit Service e08953
  }
Packit Service e08953
  utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
Packit Service e08953
  if (utf16_buffer == NULL) {
Packit Service e08953
    return UV_ENOMEM;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
Packit Service e08953
  if (utf16_len == 0) {
Packit Service e08953
    uv__free(utf16_buffer);
Packit Service e08953
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* utf16_len contains the length, *not* including the terminating null. */
Packit b5b901
  utf16_buffer[utf16_len] = L'\0';
Packit b5b901
Packit b5b901
  /* The returned directory should not have a trailing slash, unless it points
Packit b5b901
   * at a drive root, like c:\. Remove it if needed. */
Packit b5b901
  if (utf16_buffer[utf16_len - 1] == L'\\' &&
Packit b5b901
      !(utf16_len == 3 && utf16_buffer[1] == L':')) {
Packit b5b901
    utf16_len--;
Packit b5b901
    utf16_buffer[utf16_len] = L'\0';
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Check how much space we need */
Packit b5b901
  r = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                          0,
Packit b5b901
                          utf16_buffer,
Packit b5b901
                          -1,
Packit b5b901
                          NULL,
Packit b5b901
                          0,
Packit b5b901
                          NULL,
Packit b5b901
                          NULL);
Packit b5b901
  if (r == 0) {
Packit Service e08953
    uv__free(utf16_buffer);
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  } else if (r > (int) *size) {
Packit Service e08953
    uv__free(utf16_buffer);
Packit b5b901
    *size = r;
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Convert to UTF-8 */
Packit b5b901
  r = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                          0,
Packit b5b901
                          utf16_buffer,
Packit b5b901
                          -1,
Packit b5b901
                          buffer,
Packit b5b901
                          *size > INT_MAX ? INT_MAX : (int) *size,
Packit b5b901
                          NULL,
Packit b5b901
                          NULL);
Packit Service e08953
  uv__free(utf16_buffer);
Packit Service e08953
Packit b5b901
  if (r == 0) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  *size = r - 1;
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_chdir(const char* dir) {
Packit Service e08953
  WCHAR *utf16_buffer;
Packit Service e08953
  size_t utf16_len, new_utf16_len;
Packit b5b901
  WCHAR drive_letter, env_var[4];
Packit b5b901
Packit b5b901
  if (dir == NULL) {
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  utf16_len = MultiByteToWideChar(CP_UTF8,
Packit Service e08953
                                  0,
Packit Service e08953
                                  dir,
Packit Service e08953
                                  -1,
Packit Service e08953
                                  NULL,
Packit Service e08953
                                  0);
Packit Service e08953
  if (utf16_len == 0) {
Packit Service e08953
    return uv_translate_sys_error(GetLastError());
Packit Service e08953
  }
Packit Service e08953
  utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
Packit Service e08953
  if (utf16_buffer == NULL) {
Packit Service e08953
    return UV_ENOMEM;
Packit Service e08953
  }
Packit Service e08953
Packit b5b901
  if (MultiByteToWideChar(CP_UTF8,
Packit b5b901
                          0,
Packit b5b901
                          dir,
Packit b5b901
                          -1,
Packit b5b901
                          utf16_buffer,
Packit Service e08953
                          utf16_len) == 0) {
Packit Service e08953
    uv__free(utf16_buffer);
Packit Service e08953
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!SetCurrentDirectoryW(utf16_buffer)) {
Packit Service e08953
    uv__free(utf16_buffer);
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Windows stores the drive-local path in an "hidden" environment variable,
Packit b5b901
   * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
Packit b5b901
   * this, so we'll have to do it. */
Packit Service e08953
  new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
Packit Service e08953
  if (new_utf16_len > utf16_len ) {
Packit Service e08953
    uv__free(utf16_buffer);
Packit Service e08953
    utf16_buffer = uv__malloc(new_utf16_len * sizeof(WCHAR));
Packit Service e08953
    if (utf16_buffer == NULL) {
Packit Service e08953
      /* When updating the environment variable fails, return UV_OK anyway.
Packit Service e08953
       * We did successfully change current working directory, only updating
Packit Service e08953
       * hidden env variable failed. */
Packit Service e08953
      return 0;
Packit Service e08953
    }
Packit Service e08953
    new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer);
Packit Service e08953
  }
Packit b5b901
  if (utf16_len == 0) {
Packit Service e08953
    uv__free(utf16_buffer);
Packit Service e08953
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* The returned directory should not have a trailing slash, unless it points
Packit b5b901
   * at a drive root, like c:\. Remove it if needed. */
Packit b5b901
  if (utf16_buffer[utf16_len - 1] == L'\\' &&
Packit b5b901
      !(utf16_len == 3 && utf16_buffer[1] == L':')) {
Packit b5b901
    utf16_len--;
Packit b5b901
    utf16_buffer[utf16_len] = L'\0';
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (utf16_len < 2 || utf16_buffer[1] != L':') {
Packit b5b901
    /* Doesn't look like a drive letter could be there - probably an UNC path.
Packit b5b901
     * TODO: Need to handle win32 namespaces like \\?\C:\ ? */
Packit b5b901
    drive_letter = 0;
Packit b5b901
  } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
Packit b5b901
    drive_letter = utf16_buffer[0];
Packit b5b901
  } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
Packit b5b901
    /* Convert to uppercase. */
Packit b5b901
    drive_letter = utf16_buffer[0] - L'a' + L'A';
Packit b5b901
  } else {
Packit b5b901
    /* Not valid. */
Packit b5b901
    drive_letter = 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (drive_letter != 0) {
Packit b5b901
    /* Construct the environment variable name and set it. */
Packit b5b901
    env_var[0] = L'=';
Packit b5b901
    env_var[1] = drive_letter;
Packit b5b901
    env_var[2] = L':';
Packit b5b901
    env_var[3] = L'\0';
Packit b5b901
Packit Service e08953
    SetEnvironmentVariableW(env_var, utf16_buffer);
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  uv__free(utf16_buffer);
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_loadavg(double avg[3]) {
Packit b5b901
  /* Can't be implemented */
Packit b5b901
  avg[0] = avg[1] = avg[2] = 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uint64_t uv_get_free_memory(void) {
Packit b5b901
  MEMORYSTATUSEX memory_status;
Packit b5b901
  memory_status.dwLength = sizeof(memory_status);
Packit b5b901
Packit b5b901
  if (!GlobalMemoryStatusEx(&memory_status)) {
Packit b5b901
     return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return (uint64_t)memory_status.ullAvailPhys;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uint64_t uv_get_total_memory(void) {
Packit b5b901
  MEMORYSTATUSEX memory_status;
Packit b5b901
  memory_status.dwLength = sizeof(memory_status);
Packit b5b901
Packit b5b901
  if (!GlobalMemoryStatusEx(&memory_status)) {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return (uint64_t)memory_status.ullTotalPhys;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit Service e08953
uint64_t uv_get_constrained_memory(void) {
Packit Service e08953
  return 0;  /* Memory constraints are unknown. */
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
Packit b5b901
uv_pid_t uv_os_getpid(void) {
Packit b5b901
  return GetCurrentProcessId();
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uv_pid_t uv_os_getppid(void) {
Packit b5b901
  int parent_pid = -1;
Packit b5b901
  HANDLE handle;
Packit b5b901
  PROCESSENTRY32 pe;
Packit b5b901
  DWORD current_pid = GetCurrentProcessId();
Packit b5b901
Packit b5b901
  pe.dwSize = sizeof(PROCESSENTRY32);
Packit b5b901
  handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
Packit b5b901
Packit b5b901
  if (Process32First(handle, &pe)) {
Packit b5b901
    do {
Packit b5b901
      if (pe.th32ProcessID == current_pid) {
Packit b5b901
        parent_pid = pe.th32ParentProcessID;
Packit b5b901
        break;
Packit b5b901
      }
Packit b5b901
    } while( Process32Next(handle, &pe);;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  CloseHandle(handle);
Packit b5b901
  return parent_pid;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
char** uv_setup_args(int argc, char** argv) {
Packit b5b901
  return argv;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit Service e08953
void uv__process_title_cleanup(void) {
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
Packit b5b901
int uv_set_process_title(const char* title) {
Packit b5b901
  int err;
Packit b5b901
  int length;
Packit b5b901
  WCHAR* title_w = NULL;
Packit b5b901
Packit b5b901
  uv__once_init();
Packit b5b901
Packit b5b901
  /* Find out how big the buffer for the wide-char title must be */
Packit b5b901
  length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
Packit b5b901
  if (!length) {
Packit b5b901
    err = GetLastError();
Packit b5b901
    goto done;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Convert to wide-char string */
Packit b5b901
  title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
Packit b5b901
  if (!title_w) {
Packit b5b901
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
  }
Packit b5b901
Packit b5b901
  length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length);
Packit b5b901
  if (!length) {
Packit b5b901
    err = GetLastError();
Packit b5b901
    goto done;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* If the title must be truncated insert a \0 terminator there */
Packit b5b901
  if (length > MAX_TITLE_LENGTH) {
Packit b5b901
    title_w[MAX_TITLE_LENGTH - 1] = L'\0';
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!SetConsoleTitleW(title_w)) {
Packit b5b901
    err = GetLastError();
Packit b5b901
    goto done;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  EnterCriticalSection(&process_title_lock);
Packit b5b901
  uv__free(process_title);
Packit b5b901
  process_title = uv__strdup(title);
Packit b5b901
  LeaveCriticalSection(&process_title_lock);
Packit b5b901
Packit b5b901
  err = 0;
Packit b5b901
Packit b5b901
done:
Packit b5b901
  uv__free(title_w);
Packit b5b901
  return uv_translate_sys_error(err);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv__get_process_title(void) {
Packit b5b901
  WCHAR title_w[MAX_TITLE_LENGTH];
Packit b5b901
Packit b5b901
  if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0)
Packit b5b901
    return -1;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_get_process_title(char* buffer, size_t size) {
Packit b5b901
  size_t len;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  uv__once_init();
Packit b5b901
Packit b5b901
  EnterCriticalSection(&process_title_lock);
Packit b5b901
  /*
Packit b5b901
   * If the process_title was never read before nor explicitly set,
Packit b5b901
   * we must query it with getConsoleTitleW
Packit b5b901
   */
Packit b5b901
  if (!process_title && uv__get_process_title() == -1) {
Packit b5b901
    LeaveCriticalSection(&process_title_lock);
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  assert(process_title);
Packit b5b901
  len = strlen(process_title) + 1;
Packit b5b901
Packit b5b901
  if (size < len) {
Packit b5b901
    LeaveCriticalSection(&process_title_lock);
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memcpy(buffer, process_title, len);
Packit b5b901
  LeaveCriticalSection(&process_title_lock);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uint64_t uv_hrtime(void) {
Packit b5b901
  uv__once_init();
Packit b5b901
  return uv__hrtime(UV__NANOSEC);
Packit b5b901
}
Packit b5b901
Packit b5b901
uint64_t uv__hrtime(double scale) {
Packit b5b901
  LARGE_INTEGER counter;
Packit b5b901
Packit b5b901
  /* If the performance interval is zero, there's no support. */
Packit b5b901
  if (hrtime_interval_ == 0) {
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!QueryPerformanceCounter(&counter)) {
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Because we have no guarantee about the order of magnitude of the
Packit b5b901
   * performance counter interval, integer math could cause this computation
Packit b5b901
   * to overflow. Therefore we resort to floating point math.
Packit b5b901
   */
Packit b5b901
  return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_resident_set_memory(size_t* rss) {
Packit b5b901
  HANDLE current_process;
Packit b5b901
  PROCESS_MEMORY_COUNTERS pmc;
Packit b5b901
Packit b5b901
  current_process = GetCurrentProcess();
Packit b5b901
Packit b5b901
  if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  *rss = pmc.WorkingSetSize;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_uptime(double* uptime) {
Packit b5b901
  BYTE stack_buffer[4096];
Packit b5b901
  BYTE* malloced_buffer = NULL;
Packit b5b901
  BYTE* buffer = (BYTE*) stack_buffer;
Packit b5b901
  size_t buffer_size = sizeof(stack_buffer);
Packit b5b901
  DWORD data_size;
Packit b5b901
Packit b5b901
  PERF_DATA_BLOCK* data_block;
Packit b5b901
  PERF_OBJECT_TYPE* object_type;
Packit b5b901
  PERF_COUNTER_DEFINITION* counter_definition;
Packit b5b901
Packit b5b901
  DWORD i;
Packit b5b901
Packit b5b901
  for (;;) {
Packit b5b901
    LONG result;
Packit b5b901
Packit b5b901
    data_size = (DWORD) buffer_size;
Packit b5b901
    result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
Packit b5b901
                              L"2",
Packit b5b901
                              NULL,
Packit b5b901
                              NULL,
Packit b5b901
                              buffer,
Packit b5b901
                              &data_size);
Packit b5b901
    if (result == ERROR_SUCCESS) {
Packit b5b901
      break;
Packit b5b901
    } else if (result != ERROR_MORE_DATA) {
Packit b5b901
      *uptime = 0;
Packit b5b901
      return uv_translate_sys_error(result);
Packit b5b901
    }
Packit b5b901
Packit b5b901
    buffer_size *= 2;
Packit b5b901
    /* Don't let the buffer grow infinitely. */
Packit b5b901
    if (buffer_size > 1 << 20) {
Packit b5b901
      goto internalError;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    uv__free(malloced_buffer);
Packit b5b901
Packit b5b901
    buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
Packit b5b901
    if (malloced_buffer == NULL) {
Packit b5b901
      *uptime = 0;
Packit b5b901
      return UV_ENOMEM;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (data_size < sizeof(*data_block))
Packit b5b901
    goto internalError;
Packit b5b901
Packit b5b901
  data_block = (PERF_DATA_BLOCK*) buffer;
Packit b5b901
Packit b5b901
  if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
Packit b5b901
    goto internalError;
Packit b5b901
Packit b5b901
  if (data_size < data_block->HeaderLength + sizeof(*object_type))
Packit b5b901
    goto internalError;
Packit b5b901
Packit b5b901
  object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
Packit b5b901
Packit b5b901
  if (object_type->NumInstances != PERF_NO_INSTANCES)
Packit b5b901
    goto internalError;
Packit b5b901
Packit b5b901
  counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
Packit b5b901
      data_block->HeaderLength + object_type->HeaderLength);
Packit b5b901
  for (i = 0; i < object_type->NumCounters; i++) {
Packit b5b901
    if ((BYTE*) counter_definition + sizeof(*counter_definition) >
Packit b5b901
        buffer + data_size) {
Packit b5b901
      break;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (counter_definition->CounterNameTitleIndex == 674 &&
Packit b5b901
        counter_definition->CounterSize == sizeof(uint64_t)) {
Packit b5b901
      if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
Packit b5b901
          !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
Packit b5b901
        goto internalError;
Packit b5b901
      } else {
Packit b5b901
        BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
Packit b5b901
                        counter_definition->CounterOffset;
Packit b5b901
        uint64_t value = *((uint64_t*) address);
Packit b5b901
        *uptime = floor((double) (object_type->PerfTime.QuadPart - value) /
Packit b5b901
                        (double) object_type->PerfFreq.QuadPart);
Packit b5b901
        uv__free(malloced_buffer);
Packit b5b901
        return 0;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    counter_definition = (PERF_COUNTER_DEFINITION*)
Packit b5b901
        ((BYTE*) counter_definition + counter_definition->ByteLength);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* If we get here, the uptime value was not found. */
Packit b5b901
  uv__free(malloced_buffer);
Packit b5b901
  *uptime = 0;
Packit b5b901
  return UV_ENOSYS;
Packit b5b901
Packit b5b901
 internalError:
Packit b5b901
  uv__free(malloced_buffer);
Packit b5b901
  *uptime = 0;
Packit b5b901
  return UV_EIO;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
Packit b5b901
  uv_cpu_info_t* cpu_infos;
Packit b5b901
  SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
Packit b5b901
  DWORD sppi_size;
Packit b5b901
  SYSTEM_INFO system_info;
Packit b5b901
  DWORD cpu_count, i;
Packit b5b901
  NTSTATUS status;
Packit b5b901
  ULONG result_size;
Packit b5b901
  int err;
Packit b5b901
  uv_cpu_info_t* cpu_info;
Packit b5b901
Packit b5b901
  cpu_infos = NULL;
Packit b5b901
  cpu_count = 0;
Packit b5b901
  sppi = NULL;
Packit b5b901
Packit b5b901
  uv__once_init();
Packit b5b901
Packit b5b901
  GetSystemInfo(&system_info);
Packit b5b901
  cpu_count = system_info.dwNumberOfProcessors;
Packit b5b901
Packit b5b901
  cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
Packit b5b901
  if (cpu_infos == NULL) {
Packit b5b901
    err = ERROR_OUTOFMEMORY;
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  sppi_size = cpu_count * sizeof(*sppi);
Packit b5b901
  sppi = uv__malloc(sppi_size);
Packit b5b901
  if (sppi == NULL) {
Packit b5b901
    err = ERROR_OUTOFMEMORY;
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
Packit b5b901
                                     sppi,
Packit b5b901
                                     sppi_size,
Packit b5b901
                                     &result_size);
Packit b5b901
  if (!NT_SUCCESS(status)) {
Packit b5b901
    err = pRtlNtStatusToDosError(status);
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  assert(result_size == sppi_size);
Packit b5b901
Packit b5b901
  for (i = 0; i < cpu_count; i++) {
Packit b5b901
    WCHAR key_name[128];
Packit b5b901
    HKEY processor_key;
Packit b5b901
    DWORD cpu_speed;
Packit b5b901
    DWORD cpu_speed_size = sizeof(cpu_speed);
Packit b5b901
    WCHAR cpu_brand[256];
Packit b5b901
    DWORD cpu_brand_size = sizeof(cpu_brand);
Packit b5b901
    size_t len;
Packit b5b901
Packit b5b901
    len = _snwprintf(key_name,
Packit b5b901
                     ARRAY_SIZE(key_name),
Packit b5b901
                     L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
Packit b5b901
                     i);
Packit b5b901
Packit b5b901
    assert(len > 0 && len < ARRAY_SIZE(key_name));
Packit b5b901
Packit b5b901
    err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
Packit b5b901
                        key_name,
Packit b5b901
                        0,
Packit b5b901
                        KEY_QUERY_VALUE,
Packit b5b901
                        &processor_key);
Packit b5b901
    if (err != ERROR_SUCCESS) {
Packit b5b901
      goto error;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    err = RegQueryValueExW(processor_key,
Packit b5b901
                           L"~MHz",
Packit b5b901
                           NULL,
Packit b5b901
                           NULL,
Packit b5b901
                           (BYTE*)&cpu_speed,
Packit b5b901
                           &cpu_speed_size);
Packit b5b901
    if (err != ERROR_SUCCESS) {
Packit b5b901
      RegCloseKey(processor_key);
Packit b5b901
      goto error;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    err = RegQueryValueExW(processor_key,
Packit b5b901
                           L"ProcessorNameString",
Packit b5b901
                           NULL,
Packit b5b901
                           NULL,
Packit b5b901
                           (BYTE*)&cpu_brand,
Packit b5b901
                           &cpu_brand_size);
Packit b5b901
    RegCloseKey(processor_key);
Packit Service e08953
    if (err != ERROR_SUCCESS)
Packit Service e08953
      goto error;
Packit b5b901
Packit b5b901
    cpu_info = &cpu_infos[i];
Packit b5b901
    cpu_info->speed = cpu_speed;
Packit b5b901
    cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
Packit b5b901
    cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
Packit b5b901
        sppi[i].IdleTime.QuadPart) / 10000;
Packit b5b901
    cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
Packit b5b901
    cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
Packit b5b901
    cpu_info->cpu_times.nice = 0;
Packit b5b901
Packit b5b901
    uv__convert_utf16_to_utf8(cpu_brand,
Packit b5b901
                              cpu_brand_size / sizeof(WCHAR),
Packit b5b901
                              &(cpu_info->model));
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__free(sppi);
Packit b5b901
Packit b5b901
  *cpu_count_ptr = cpu_count;
Packit b5b901
  *cpu_infos_ptr = cpu_infos;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
Packit b5b901
 error:
Packit Service e08953
  if (cpu_infos != NULL) {
Packit Service e08953
    /* This is safe because the cpu_infos array is zeroed on allocation. */
Packit Service e08953
    for (i = 0; i < cpu_count; i++)
Packit Service e08953
      uv__free(cpu_infos[i].model);
Packit Service e08953
  }
Packit b5b901
Packit b5b901
  uv__free(cpu_infos);
Packit b5b901
  uv__free(sppi);
Packit b5b901
Packit b5b901
  return uv_translate_sys_error(err);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int is_windows_version_or_greater(DWORD os_major,
Packit b5b901
                                         DWORD os_minor,
Packit b5b901
                                         WORD service_pack_major,
Packit b5b901
                                         WORD service_pack_minor) {
Packit b5b901
  OSVERSIONINFOEX osvi;
Packit b5b901
  DWORDLONG condition_mask = 0;
Packit b5b901
  int op = VER_GREATER_EQUAL;
Packit b5b901
Packit b5b901
  /* Initialize the OSVERSIONINFOEX structure. */
Packit b5b901
  ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
Packit b5b901
  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
Packit b5b901
  osvi.dwMajorVersion = os_major;
Packit b5b901
  osvi.dwMinorVersion = os_minor;
Packit b5b901
  osvi.wServicePackMajor = service_pack_major;
Packit b5b901
  osvi.wServicePackMinor = service_pack_minor;
Packit b5b901
Packit b5b901
  /* Initialize the condition mask. */
Packit b5b901
  VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
Packit b5b901
  VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
Packit b5b901
  VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
Packit b5b901
  VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
Packit b5b901
Packit b5b901
  /* Perform the test. */
Packit b5b901
  return (int) VerifyVersionInfo(
Packit b5b901
    &osvi,
Packit b5b901
    VER_MAJORVERSION | VER_MINORVERSION |
Packit b5b901
    VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
Packit b5b901
    condition_mask);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int address_prefix_match(int family,
Packit b5b901
                                struct sockaddr* address,
Packit b5b901
                                struct sockaddr* prefix_address,
Packit b5b901
                                int prefix_len) {
Packit b5b901
  uint8_t* address_data;
Packit b5b901
  uint8_t* prefix_address_data;
Packit b5b901
  int i;
Packit b5b901
Packit b5b901
  assert(address->sa_family == family);
Packit b5b901
  assert(prefix_address->sa_family == family);
Packit b5b901
Packit b5b901
  if (family == AF_INET6) {
Packit b5b901
    address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
Packit b5b901
    prefix_address_data =
Packit b5b901
      (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
Packit b5b901
  } else {
Packit b5b901
    address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
Packit b5b901
    prefix_address_data =
Packit b5b901
      (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  for (i = 0; i < prefix_len >> 3; i++) {
Packit b5b901
    if (address_data[i] != prefix_address_data[i])
Packit b5b901
      return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (prefix_len % 8)
Packit b5b901
    return prefix_address_data[i] ==
Packit b5b901
      (address_data[i] & (0xff << (8 - prefix_len % 8)));
Packit b5b901
Packit b5b901
  return 1;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
Packit b5b901
    int* count_ptr) {
Packit b5b901
  IP_ADAPTER_ADDRESSES* win_address_buf;
Packit b5b901
  ULONG win_address_buf_size;
Packit b5b901
  IP_ADAPTER_ADDRESSES* adapter;
Packit b5b901
Packit b5b901
  uv_interface_address_t* uv_address_buf;
Packit b5b901
  char* name_buf;
Packit b5b901
  size_t uv_address_buf_size;
Packit b5b901
  uv_interface_address_t* uv_address;
Packit b5b901
Packit b5b901
  int count;
Packit b5b901
Packit b5b901
  int is_vista_or_greater;
Packit b5b901
  ULONG flags;
Packit b5b901
Packit Service e08953
  *addresses_ptr = NULL;
Packit Service e08953
  *count_ptr = 0;
Packit Service e08953
Packit b5b901
  is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
Packit b5b901
  if (is_vista_or_greater) {
Packit b5b901
    flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
Packit b5b901
      GAA_FLAG_SKIP_DNS_SERVER;
Packit b5b901
  } else {
Packit b5b901
    /* We need at least XP SP1. */
Packit b5b901
    if (!is_windows_version_or_greater(5, 1, 1, 0))
Packit b5b901
      return UV_ENOTSUP;
Packit b5b901
Packit b5b901
    flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
Packit b5b901
      GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
Packit b5b901
  }
Packit b5b901
Packit b5b901
Packit b5b901
  /* Fetch the size of the adapters reported by windows, and then get the list
Packit b5b901
   * itself. */
Packit b5b901
  win_address_buf_size = 0;
Packit b5b901
  win_address_buf = NULL;
Packit b5b901
Packit b5b901
  for (;;) {
Packit b5b901
    ULONG r;
Packit b5b901
Packit b5b901
    /* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
Packit b5b901
     * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
Packit b5b901
     * win_address_buf_size. */
Packit b5b901
    r = GetAdaptersAddresses(AF_UNSPEC,
Packit b5b901
                             flags,
Packit b5b901
                             NULL,
Packit b5b901
                             win_address_buf,
Packit b5b901
                             &win_address_buf_size);
Packit b5b901
Packit b5b901
    if (r == ERROR_SUCCESS)
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    uv__free(win_address_buf);
Packit b5b901
Packit b5b901
    switch (r) {
Packit b5b901
      case ERROR_BUFFER_OVERFLOW:
Packit b5b901
        /* This happens when win_address_buf is NULL or too small to hold all
Packit b5b901
         * adapters. */
Packit b5b901
        win_address_buf = uv__malloc(win_address_buf_size);
Packit b5b901
        if (win_address_buf == NULL)
Packit b5b901
          return UV_ENOMEM;
Packit b5b901
Packit b5b901
        continue;
Packit b5b901
Packit b5b901
      case ERROR_NO_DATA: {
Packit b5b901
        /* No adapters were found. */
Packit b5b901
        uv_address_buf = uv__malloc(1);
Packit b5b901
        if (uv_address_buf == NULL)
Packit b5b901
          return UV_ENOMEM;
Packit b5b901
Packit b5b901
        *count_ptr = 0;
Packit b5b901
        *addresses_ptr = uv_address_buf;
Packit b5b901
Packit b5b901
        return 0;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      case ERROR_ADDRESS_NOT_ASSOCIATED:
Packit b5b901
        return UV_EAGAIN;
Packit b5b901
Packit b5b901
      case ERROR_INVALID_PARAMETER:
Packit b5b901
        /* MSDN says:
Packit b5b901
         *   "This error is returned for any of the following conditions: the
Packit b5b901
         *   SizePointer parameter is NULL, the Address parameter is not
Packit b5b901
         *   AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
Packit b5b901
         *   the parameters requested is greater than ULONG_MAX."
Packit b5b901
         * Since the first two conditions are not met, it must be that the
Packit b5b901
         * adapter data is too big.
Packit b5b901
         */
Packit b5b901
        return UV_ENOBUFS;
Packit b5b901
Packit b5b901
      default:
Packit b5b901
        /* Other (unspecified) errors can happen, but we don't have any special
Packit b5b901
         * meaning for them. */
Packit b5b901
        assert(r != ERROR_SUCCESS);
Packit b5b901
        return uv_translate_sys_error(r);
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Count the number of enabled interfaces and compute how much space is
Packit b5b901
   * needed to store their info. */
Packit b5b901
  count = 0;
Packit b5b901
  uv_address_buf_size = 0;
Packit b5b901
Packit b5b901
  for (adapter = win_address_buf;
Packit b5b901
       adapter != NULL;
Packit b5b901
       adapter = adapter->Next) {
Packit b5b901
    IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
Packit b5b901
    int name_size;
Packit b5b901
Packit b5b901
    /* Interfaces that are not 'up' should not be reported. Also skip
Packit b5b901
     * interfaces that have no associated unicast address, as to avoid
Packit b5b901
     * allocating space for the name for this interface. */
Packit b5b901
    if (adapter->OperStatus != IfOperStatusUp ||
Packit b5b901
        adapter->FirstUnicastAddress == NULL)
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    /* Compute the size of the interface name. */
Packit b5b901
    name_size = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                    0,
Packit b5b901
                                    adapter->FriendlyName,
Packit b5b901
                                    -1,
Packit b5b901
                                    NULL,
Packit b5b901
                                    0,
Packit b5b901
                                    NULL,
Packit b5b901
                                    FALSE);
Packit b5b901
    if (name_size <= 0) {
Packit b5b901
      uv__free(win_address_buf);
Packit b5b901
      return uv_translate_sys_error(GetLastError());
Packit b5b901
    }
Packit b5b901
    uv_address_buf_size += name_size;
Packit b5b901
Packit b5b901
    /* Count the number of addresses associated with this interface, and
Packit b5b901
     * compute the size. */
Packit b5b901
    for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
Packit b5b901
                           adapter->FirstUnicastAddress;
Packit b5b901
         unicast_address != NULL;
Packit b5b901
         unicast_address = unicast_address->Next) {
Packit b5b901
      count++;
Packit b5b901
      uv_address_buf_size += sizeof(uv_interface_address_t);
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Allocate space to store interface data plus adapter names. */
Packit b5b901
  uv_address_buf = uv__malloc(uv_address_buf_size);
Packit b5b901
  if (uv_address_buf == NULL) {
Packit b5b901
    uv__free(win_address_buf);
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Compute the start of the uv_interface_address_t array, and the place in
Packit b5b901
   * the buffer where the interface names will be stored. */
Packit b5b901
  uv_address = uv_address_buf;
Packit b5b901
  name_buf = (char*) (uv_address_buf + count);
Packit b5b901
Packit b5b901
  /* Fill out the output buffer. */
Packit b5b901
  for (adapter = win_address_buf;
Packit b5b901
       adapter != NULL;
Packit b5b901
       adapter = adapter->Next) {
Packit b5b901
    IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
Packit b5b901
    int name_size;
Packit b5b901
    size_t max_name_size;
Packit b5b901
Packit b5b901
    if (adapter->OperStatus != IfOperStatusUp ||
Packit b5b901
        adapter->FirstUnicastAddress == NULL)
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    /* Convert the interface name to UTF8. */
Packit b5b901
    max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
Packit b5b901
    if (max_name_size > (size_t) INT_MAX)
Packit b5b901
      max_name_size = INT_MAX;
Packit b5b901
    name_size = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                    0,
Packit b5b901
                                    adapter->FriendlyName,
Packit b5b901
                                    -1,
Packit b5b901
                                    name_buf,
Packit b5b901
                                    (int) max_name_size,
Packit b5b901
                                    NULL,
Packit b5b901
                                    FALSE);
Packit b5b901
    if (name_size <= 0) {
Packit b5b901
      uv__free(win_address_buf);
Packit b5b901
      uv__free(uv_address_buf);
Packit b5b901
      return uv_translate_sys_error(GetLastError());
Packit b5b901
    }
Packit b5b901
Packit b5b901
    /* Add an uv_interface_address_t element for every unicast address. */
Packit b5b901
    for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
Packit b5b901
                           adapter->FirstUnicastAddress;
Packit b5b901
         unicast_address != NULL;
Packit b5b901
         unicast_address = unicast_address->Next) {
Packit b5b901
      struct sockaddr* sa;
Packit b5b901
      ULONG prefix_len;
Packit b5b901
Packit b5b901
      sa = unicast_address->Address.lpSockaddr;
Packit b5b901
Packit b5b901
      /* XP has no OnLinkPrefixLength field. */
Packit b5b901
      if (is_vista_or_greater) {
Packit b5b901
        prefix_len =
Packit b5b901
          ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
Packit b5b901
      } else {
Packit b5b901
        /* Prior to Windows Vista the FirstPrefix pointed to the list with
Packit b5b901
         * single prefix for each IP address assigned to the adapter.
Packit b5b901
         * Order of FirstPrefix does not match order of FirstUnicastAddress,
Packit b5b901
         * so we need to find corresponding prefix.
Packit b5b901
         */
Packit b5b901
        IP_ADAPTER_PREFIX* prefix;
Packit b5b901
        prefix_len = 0;
Packit b5b901
Packit b5b901
        for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
Packit b5b901
          /* We want the longest matching prefix. */
Packit b5b901
          if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
Packit b5b901
              prefix->PrefixLength <= prefix_len)
Packit b5b901
            continue;
Packit b5b901
Packit b5b901
          if (address_prefix_match(sa->sa_family, sa,
Packit b5b901
              prefix->Address.lpSockaddr, prefix->PrefixLength)) {
Packit b5b901
            prefix_len = prefix->PrefixLength;
Packit b5b901
          }
Packit b5b901
        }
Packit b5b901
Packit b5b901
        /* If there is no matching prefix information, return a single-host
Packit b5b901
         * subnet mask (e.g. 255.255.255.255 for IPv4).
Packit b5b901
         */
Packit b5b901
        if (!prefix_len)
Packit b5b901
          prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      memset(uv_address, 0, sizeof *uv_address);
Packit b5b901
Packit b5b901
      uv_address->name = name_buf;
Packit b5b901
Packit b5b901
      if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
Packit b5b901
        memcpy(uv_address->phys_addr,
Packit b5b901
               adapter->PhysicalAddress,
Packit b5b901
               sizeof(uv_address->phys_addr));
Packit b5b901
      }
Packit b5b901
Packit b5b901
      uv_address->is_internal =
Packit b5b901
          (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
Packit b5b901
Packit b5b901
      if (sa->sa_family == AF_INET6) {
Packit b5b901
        uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
Packit b5b901
Packit b5b901
        uv_address->netmask.netmask6.sin6_family = AF_INET6;
Packit b5b901
        memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
Packit b5b901
        /* This check ensures that we don't write past the size of the data. */
Packit b5b901
        if (prefix_len % 8) {
Packit b5b901
          uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
Packit b5b901
              0xff << (8 - prefix_len % 8);
Packit b5b901
        }
Packit b5b901
Packit b5b901
      } else {
Packit b5b901
        uv_address->address.address4 = *((struct sockaddr_in *) sa);
Packit b5b901
Packit b5b901
        uv_address->netmask.netmask4.sin_family = AF_INET;
Packit b5b901
        uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
Packit b5b901
            htonl(0xffffffff << (32 - prefix_len)) : 0;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      uv_address++;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    name_buf += name_size;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__free(win_address_buf);
Packit b5b901
Packit b5b901
  *addresses_ptr = uv_address_buf;
Packit b5b901
  *count_ptr = count;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_free_interface_addresses(uv_interface_address_t* addresses,
Packit b5b901
    int count) {
Packit b5b901
  uv__free(addresses);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_getrusage(uv_rusage_t *uv_rusage) {
Packit b5b901
  FILETIME createTime, exitTime, kernelTime, userTime;
Packit b5b901
  SYSTEMTIME kernelSystemTime, userSystemTime;
Packit b5b901
  PROCESS_MEMORY_COUNTERS memCounters;
Packit b5b901
  IO_COUNTERS ioCounters;
Packit b5b901
  int ret;
Packit b5b901
Packit b5b901
  ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
Packit b5b901
  if (ret == 0) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
Packit b5b901
  if (ret == 0) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  ret = FileTimeToSystemTime(&userTime, &userSystemTime);
Packit b5b901
  if (ret == 0) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  ret = GetProcessMemoryInfo(GetCurrentProcess(),
Packit b5b901
                             &memCounters,
Packit b5b901
                             sizeof(memCounters));
Packit b5b901
  if (ret == 0) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
Packit b5b901
  if (ret == 0) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memset(uv_rusage, 0, sizeof(*uv_rusage));
Packit b5b901
Packit b5b901
  uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
Packit b5b901
                               userSystemTime.wMinute * 60 +
Packit b5b901
                               userSystemTime.wSecond;
Packit b5b901
  uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
Packit b5b901
Packit b5b901
  uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
Packit b5b901
                               kernelSystemTime.wMinute * 60 +
Packit b5b901
                               kernelSystemTime.wSecond;
Packit b5b901
  uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
Packit b5b901
Packit b5b901
  uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
Packit b5b901
  uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
Packit b5b901
Packit b5b901
  uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
Packit b5b901
  uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_homedir(char* buffer, size_t* size) {
Packit b5b901
  uv_passwd_t pwd;
Packit b5b901
  size_t len;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  /* Check if the USERPROFILE environment variable is set first. The task of
Packit b5b901
     performing input validation on buffer and size is taken care of by
Packit b5b901
     uv_os_getenv(). */
Packit b5b901
  r = uv_os_getenv("USERPROFILE", buffer, size);
Packit b5b901
Packit b5b901
  /* Don't return an error if USERPROFILE was not found. */
Packit b5b901
  if (r != UV_ENOENT)
Packit b5b901
    return r;
Packit b5b901
Packit b5b901
  /* USERPROFILE is not set, so call uv__getpwuid_r() */
Packit b5b901
  r = uv__getpwuid_r(&pwd);
Packit b5b901
Packit b5b901
  if (r != 0) {
Packit b5b901
    return r;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  len = strlen(pwd.homedir);
Packit b5b901
Packit b5b901
  if (len >= *size) {
Packit b5b901
    *size = len + 1;
Packit b5b901
    uv_os_free_passwd(&pwd);
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memcpy(buffer, pwd.homedir, len + 1);
Packit b5b901
  *size = len;
Packit b5b901
  uv_os_free_passwd(&pwd);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_tmpdir(char* buffer, size_t* size) {
Packit Service e08953
  wchar_t *path;
Packit b5b901
  DWORD bufsize;
Packit b5b901
  size_t len;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit Service e08953
  len = 0;
Packit Service e08953
  len = GetTempPathW(0, NULL);
Packit Service e08953
  if (len == 0) {
Packit Service e08953
    return uv_translate_sys_error(GetLastError());
Packit Service e08953
  }
Packit Service e08953
  /* Include space for terminating null char. */
Packit Service e08953
  len += 1;
Packit Service e08953
  path = uv__malloc(len * sizeof(wchar_t));
Packit Service e08953
  if (path == NULL) {
Packit Service e08953
    return UV_ENOMEM;
Packit Service e08953
  }
Packit Service e08953
  len  = GetTempPathW(len, path);
Packit b5b901
Packit b5b901
  if (len == 0) {
Packit Service e08953
    uv__free(path);
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* The returned directory should not have a trailing slash, unless it points
Packit b5b901
   * at a drive root, like c:\. Remove it if needed. */
Packit b5b901
  if (path[len - 1] == L'\\' &&
Packit b5b901
      !(len == 3 && path[1] == L':')) {
Packit b5b901
    len--;
Packit b5b901
    path[len] = L'\0';
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Check how much space we need */
Packit b5b901
  bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
Packit b5b901
Packit b5b901
  if (bufsize == 0) {
Packit Service e08953
    uv__free(path);
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  } else if (bufsize > *size) {
Packit Service e08953
    uv__free(path);
Packit b5b901
    *size = bufsize;
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Convert to UTF-8 */
Packit b5b901
  bufsize = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                0,
Packit b5b901
                                path,
Packit b5b901
                                -1,
Packit b5b901
                                buffer,
Packit b5b901
                                *size,
Packit b5b901
                                NULL,
Packit b5b901
                                NULL);
Packit Service e08953
  uv__free(path);
Packit b5b901
Packit b5b901
  if (bufsize == 0)
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
Packit b5b901
  *size = bufsize - 1;
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_os_free_passwd(uv_passwd_t* pwd) {
Packit b5b901
  if (pwd == NULL)
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  uv__free(pwd->username);
Packit b5b901
  uv__free(pwd->homedir);
Packit b5b901
  pwd->username = NULL;
Packit b5b901
  pwd->homedir = NULL;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * Converts a UTF-16 string into a UTF-8 one. The resulting string is
Packit b5b901
 * null-terminated.
Packit b5b901
 *
Packit b5b901
 * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
Packit b5b901
 * be specified.
Packit b5b901
 */
Packit b5b901
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
Packit b5b901
  DWORD bufsize;
Packit b5b901
Packit b5b901
  if (utf16 == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  /* Check how much space we need */
Packit b5b901
  bufsize = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                0,
Packit b5b901
                                utf16,
Packit b5b901
                                utf16len,
Packit b5b901
                                NULL,
Packit b5b901
                                0,
Packit b5b901
                                NULL,
Packit b5b901
                                NULL);
Packit b5b901
Packit b5b901
  if (bufsize == 0)
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
Packit b5b901
  /* Allocate the destination buffer adding an extra byte for the terminating
Packit b5b901
   * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
Packit b5b901
   * we do it ourselves always, just in case. */
Packit b5b901
  *utf8 = uv__malloc(bufsize + 1);
Packit b5b901
Packit b5b901
  if (*utf8 == NULL)
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
Packit b5b901
  /* Convert to UTF-8 */
Packit b5b901
  bufsize = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                0,
Packit b5b901
                                utf16,
Packit b5b901
                                utf16len,
Packit b5b901
                                *utf8,
Packit b5b901
                                bufsize,
Packit b5b901
                                NULL,
Packit b5b901
                                NULL);
Packit b5b901
Packit b5b901
  if (bufsize == 0) {
Packit b5b901
    uv__free(*utf8);
Packit b5b901
    *utf8 = NULL;
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  (*utf8)[bufsize] = '\0';
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * Converts a UTF-8 string into a UTF-16 one. The resulting string is
Packit b5b901
 * null-terminated.
Packit b5b901
 *
Packit b5b901
 * If utf8 is null terminated, utf8len can be set to -1, otherwise it must
Packit b5b901
 * be specified.
Packit b5b901
 */
Packit b5b901
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
Packit b5b901
  int bufsize;
Packit b5b901
Packit b5b901
  if (utf8 == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  /* Check how much space we need */
Packit b5b901
  bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
Packit b5b901
Packit b5b901
  if (bufsize == 0)
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
Packit b5b901
  /* Allocate the destination buffer adding an extra byte for the terminating
Packit b5b901
   * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
Packit b5b901
   * we do it ourselves always, just in case. */
Packit b5b901
  *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1));
Packit b5b901
Packit b5b901
  if (*utf16 == NULL)
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
Packit b5b901
  /* Convert to UTF-16 */
Packit b5b901
  bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
Packit b5b901
Packit b5b901
  if (bufsize == 0) {
Packit b5b901
    uv__free(*utf16);
Packit b5b901
    *utf16 = NULL;
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  (*utf16)[bufsize] = L'\0';
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__getpwuid_r(uv_passwd_t* pwd) {
Packit b5b901
  HANDLE token;
Packit b5b901
  wchar_t username[UNLEN + 1];
Packit Service e08953
  wchar_t *path;
Packit b5b901
  DWORD bufsize;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (pwd == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  /* Get the home directory using GetUserProfileDirectoryW() */
Packit b5b901
  if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
Packit Service e08953
  bufsize = 0;
Packit Service e08953
  GetUserProfileDirectoryW(token, NULL, &bufsize);
Packit Service e08953
  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
Packit b5b901
    r = GetLastError();
Packit b5b901
    CloseHandle(token);
Packit Service e08953
    return uv_translate_sys_error(r);
Packit Service e08953
  }
Packit b5b901
Packit Service e08953
  path = uv__malloc(bufsize * sizeof(wchar_t));
Packit Service e08953
  if (path == NULL) {
Packit Service e08953
    CloseHandle(token);
Packit Service e08953
    return UV_ENOMEM;
Packit Service e08953
  }
Packit b5b901
Packit Service e08953
  if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
Packit Service e08953
    r = GetLastError();
Packit Service e08953
    CloseHandle(token);
Packit Service e08953
    uv__free(path);
Packit b5b901
    return uv_translate_sys_error(r);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  CloseHandle(token);
Packit b5b901
Packit b5b901
  /* Get the username using GetUserNameW() */
Packit b5b901
  bufsize = ARRAY_SIZE(username);
Packit b5b901
  if (!GetUserNameW(username, &bufsize)) {
Packit b5b901
    r = GetLastError();
Packit Service e08953
    uv__free(path);
Packit b5b901
Packit b5b901
    /* This should not be possible */
Packit b5b901
    if (r == ERROR_INSUFFICIENT_BUFFER)
Packit b5b901
      return UV_ENOMEM;
Packit b5b901
Packit b5b901
    return uv_translate_sys_error(r);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  pwd->homedir = NULL;
Packit b5b901
  r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
Packit Service e08953
  uv__free(path);
Packit b5b901
Packit b5b901
  if (r != 0)
Packit b5b901
    return r;
Packit b5b901
Packit b5b901
  pwd->username = NULL;
Packit b5b901
  r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
Packit b5b901
Packit b5b901
  if (r != 0) {
Packit b5b901
    uv__free(pwd->homedir);
Packit b5b901
    return r;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  pwd->shell = NULL;
Packit b5b901
  pwd->uid = -1;
Packit b5b901
  pwd->gid = -1;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_get_passwd(uv_passwd_t* pwd) {
Packit b5b901
  return uv__getpwuid_r(pwd);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit Service e08953
int uv_os_environ(uv_env_item_t** envitems, int* count) {
Packit Service e08953
  wchar_t* env;
Packit Service e08953
  wchar_t* penv;
Packit Service e08953
  int i, cnt;
Packit Service e08953
  uv_env_item_t* envitem;
Packit Service e08953
Packit Service e08953
  *envitems = NULL;
Packit Service e08953
  *count = 0;
Packit Service e08953
Packit Service e08953
  env = GetEnvironmentStringsW();
Packit Service e08953
  if (env == NULL)
Packit Service e08953
    return 0;
Packit Service e08953
Packit Service e08953
  for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
Packit Service e08953
Packit Service e08953
  *envitems = uv__calloc(i, sizeof(**envitems));
Packit Service e08953
  if (*envitems == NULL) {
Packit Service e08953
    FreeEnvironmentStringsW(env);
Packit Service e08953
    return UV_ENOMEM;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  penv = env;
Packit Service e08953
  cnt = 0;
Packit Service e08953
Packit Service e08953
  while (*penv != L'\0' && cnt < i) {
Packit Service e08953
    char* buf;
Packit Service e08953
    char* ptr;
Packit Service e08953
Packit Service e08953
    if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
Packit Service e08953
      goto fail;
Packit Service e08953
Packit Service e08953
    /* Using buf + 1 here because we know that `buf` has length at least 1,
Packit Service e08953
     * and some special environment variables on Windows start with a = sign. */
Packit Service e08953
    ptr = strchr(buf + 1, '=');
Packit Service e08953
    if (ptr == NULL) {
Packit Service e08953
      uv__free(buf);
Packit Service e08953
      goto do_continue;
Packit Service e08953
    }
Packit Service e08953
Packit Service e08953
    *ptr = '\0';
Packit Service e08953
Packit Service e08953
    envitem = &(*envitems)[cnt];
Packit Service e08953
    envitem->name = buf;
Packit Service e08953
    envitem->value = ptr + 1;
Packit Service e08953
Packit Service e08953
    cnt++;
Packit Service e08953
Packit Service e08953
  do_continue:
Packit Service e08953
    penv += wcslen(penv) + 1;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  FreeEnvironmentStringsW(env);
Packit Service e08953
Packit Service e08953
  *count = cnt;
Packit Service e08953
  return 0;
Packit Service e08953
Packit Service e08953
fail:
Packit Service e08953
  FreeEnvironmentStringsW(env);
Packit Service e08953
Packit Service e08953
  for (i = 0; i < cnt; i++) {
Packit Service e08953
    envitem = &(*envitems)[cnt];
Packit Service e08953
    uv__free(envitem->name);
Packit Service e08953
  }
Packit Service e08953
  uv__free(*envitems);
Packit Service e08953
Packit Service e08953
  *envitems = NULL;
Packit Service e08953
  *count = 0;
Packit Service e08953
  return UV_ENOMEM;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
Packit b5b901
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
Packit Service e08953
  wchar_t fastvar[512];
Packit Service e08953
  wchar_t* var;
Packit Service e08953
  DWORD varlen;
Packit b5b901
  wchar_t* name_w;
Packit b5b901
  DWORD bufsize;
Packit b5b901
  size_t len;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (name == NULL || buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  r = uv__convert_utf8_to_utf16(name, -1, &name_w);
Packit b5b901
Packit b5b901
  if (r != 0)
Packit b5b901
    return r;
Packit b5b901
Packit Service e08953
  var = fastvar;
Packit Service e08953
  varlen = ARRAY_SIZE(fastvar);
Packit Service e08953
Packit Service e08953
  for (;;) {
Packit Service e08953
    SetLastError(ERROR_SUCCESS);
Packit Service e08953
    len = GetEnvironmentVariableW(name_w, var, varlen);
Packit Service e08953
Packit Service e08953
    if (len < varlen)
Packit Service e08953
      break;
Packit Service e08953
Packit Service e08953
    /* Try repeatedly because we might have been preempted by another thread
Packit Service e08953
     * modifying the environment variable just as we're trying to read it.
Packit Service e08953
     */
Packit Service e08953
    if (var != fastvar)
Packit Service e08953
      uv__free(var);
Packit Service e08953
Packit Service e08953
    varlen = 1 + len;
Packit Service e08953
    var = uv__malloc(varlen * sizeof(*var));
Packit Service e08953
Packit Service e08953
    if (var == NULL) {
Packit Service e08953
      r = UV_ENOMEM;
Packit Service e08953
      goto fail;
Packit Service e08953
    }
Packit Service e08953
  }
Packit Service e08953
Packit b5b901
  uv__free(name_w);
Packit Service e08953
  name_w = NULL;
Packit b5b901
Packit b5b901
  if (len == 0) {
Packit b5b901
    r = GetLastError();
Packit Service e08953
    if (r != ERROR_SUCCESS) {
Packit Service e08953
      r = uv_translate_sys_error(r);
Packit Service e08953
      goto fail;
Packit Service e08953
    }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Check how much space we need */
Packit b5b901
  bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
Packit b5b901
Packit b5b901
  if (bufsize == 0) {
Packit Service e08953
    r = uv_translate_sys_error(GetLastError());
Packit Service e08953
    goto fail;
Packit b5b901
  } else if (bufsize > *size) {
Packit b5b901
    *size = bufsize;
Packit Service e08953
    r = UV_ENOBUFS;
Packit Service e08953
    goto fail;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Convert to UTF-8 */
Packit b5b901
  bufsize = WideCharToMultiByte(CP_UTF8,
Packit b5b901
                                0,
Packit b5b901
                                var,
Packit b5b901
                                -1,
Packit b5b901
                                buffer,
Packit b5b901
                                *size,
Packit b5b901
                                NULL,
Packit b5b901
                                NULL);
Packit b5b901
Packit Service e08953
  if (bufsize == 0) {
Packit Service e08953
    r = uv_translate_sys_error(GetLastError());
Packit Service e08953
    goto fail;
Packit Service e08953
  }
Packit b5b901
Packit b5b901
  *size = bufsize - 1;
Packit Service e08953
  r = 0;
Packit Service e08953
Packit Service e08953
fail:
Packit Service e08953
Packit Service e08953
  if (name_w != NULL)
Packit Service e08953
    uv__free(name_w);
Packit Service e08953
Packit Service e08953
  if (var != fastvar)
Packit Service e08953
    uv__free(var);
Packit Service e08953
Packit Service e08953
  return r;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_setenv(const char* name, const char* value) {
Packit b5b901
  wchar_t* name_w;
Packit b5b901
  wchar_t* value_w;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (name == NULL || value == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  r = uv__convert_utf8_to_utf16(name, -1, &name_w);
Packit b5b901
Packit b5b901
  if (r != 0)
Packit b5b901
    return r;
Packit b5b901
Packit b5b901
  r = uv__convert_utf8_to_utf16(value, -1, &value_w);
Packit b5b901
Packit b5b901
  if (r != 0) {
Packit b5b901
    uv__free(name_w);
Packit b5b901
    return r;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  r = SetEnvironmentVariableW(name_w, value_w);
Packit b5b901
  uv__free(name_w);
Packit b5b901
  uv__free(value_w);
Packit b5b901
Packit b5b901
  if (r == 0)
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_unsetenv(const char* name) {
Packit b5b901
  wchar_t* name_w;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (name == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  r = uv__convert_utf8_to_utf16(name, -1, &name_w);
Packit b5b901
Packit b5b901
  if (r != 0)
Packit b5b901
    return r;
Packit b5b901
Packit b5b901
  r = SetEnvironmentVariableW(name_w, NULL);
Packit b5b901
  uv__free(name_w);
Packit b5b901
Packit b5b901
  if (r == 0)
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_gethostname(char* buffer, size_t* size) {
Packit Service e08953
  char buf[UV_MAXHOSTNAMESIZE];
Packit b5b901
  size_t len;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  uv__once_init(); /* Initialize winsock */
Packit b5b901
Packit b5b901
  if (gethostname(buf, sizeof(buf)) != 0)
Packit b5b901
    return uv_translate_sys_error(WSAGetLastError());
Packit b5b901
Packit b5b901
  buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
Packit b5b901
  len = strlen(buf);
Packit b5b901
Packit b5b901
  if (len >= *size) {
Packit b5b901
    *size = len + 1;
Packit b5b901
    return UV_ENOBUFS;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memcpy(buffer, buf, len + 1);
Packit b5b901
  *size = len;
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (pid == 0)
Packit b5b901
    *handle = GetCurrentProcess();
Packit b5b901
  else
Packit b5b901
    *handle = OpenProcess(access, FALSE, pid);
Packit b5b901
Packit b5b901
  if (*handle == NULL) {
Packit b5b901
    r = GetLastError();
Packit b5b901
Packit b5b901
    if (r == ERROR_INVALID_PARAMETER)
Packit b5b901
      return UV_ESRCH;
Packit b5b901
    else
Packit b5b901
      return uv_translate_sys_error(r);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_getpriority(uv_pid_t pid, int* priority) {
Packit b5b901
  HANDLE handle;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  if (priority == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
Packit b5b901
Packit b5b901
  if (r != 0)
Packit b5b901
    return r;
Packit b5b901
Packit b5b901
  r = GetPriorityClass(handle);
Packit b5b901
Packit b5b901
  if (r == 0) {
Packit b5b901
    r = uv_translate_sys_error(GetLastError());
Packit b5b901
  } else {
Packit b5b901
    /* Map Windows priority classes to Unix nice values. */
Packit b5b901
    if (r == REALTIME_PRIORITY_CLASS)
Packit b5b901
      *priority = UV_PRIORITY_HIGHEST;
Packit b5b901
    else if (r == HIGH_PRIORITY_CLASS)
Packit b5b901
      *priority = UV_PRIORITY_HIGH;
Packit b5b901
    else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
Packit b5b901
      *priority = UV_PRIORITY_ABOVE_NORMAL;
Packit b5b901
    else if (r == NORMAL_PRIORITY_CLASS)
Packit b5b901
      *priority = UV_PRIORITY_NORMAL;
Packit b5b901
    else if (r == BELOW_NORMAL_PRIORITY_CLASS)
Packit b5b901
      *priority = UV_PRIORITY_BELOW_NORMAL;
Packit b5b901
    else  /* IDLE_PRIORITY_CLASS */
Packit b5b901
      *priority = UV_PRIORITY_LOW;
Packit b5b901
Packit b5b901
    r = 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  CloseHandle(handle);
Packit b5b901
  return r;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_os_setpriority(uv_pid_t pid, int priority) {
Packit b5b901
  HANDLE handle;
Packit b5b901
  int priority_class;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  /* Map Unix nice values to Windows priority classes. */
Packit b5b901
  if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  else if (priority < UV_PRIORITY_HIGH)
Packit b5b901
    priority_class = REALTIME_PRIORITY_CLASS;
Packit b5b901
  else if (priority < UV_PRIORITY_ABOVE_NORMAL)
Packit b5b901
    priority_class = HIGH_PRIORITY_CLASS;
Packit b5b901
  else if (priority < UV_PRIORITY_NORMAL)
Packit b5b901
    priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
Packit b5b901
  else if (priority < UV_PRIORITY_BELOW_NORMAL)
Packit b5b901
    priority_class = NORMAL_PRIORITY_CLASS;
Packit b5b901
  else if (priority < UV_PRIORITY_LOW)
Packit b5b901
    priority_class = BELOW_NORMAL_PRIORITY_CLASS;
Packit b5b901
  else
Packit b5b901
    priority_class = IDLE_PRIORITY_CLASS;
Packit b5b901
Packit b5b901
  r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
Packit b5b901
Packit b5b901
  if (r != 0)
Packit b5b901
    return r;
Packit b5b901
Packit b5b901
  if (SetPriorityClass(handle, priority_class) == 0)
Packit b5b901
    r = uv_translate_sys_error(GetLastError());
Packit b5b901
Packit b5b901
  CloseHandle(handle);
Packit b5b901
  return r;
Packit b5b901
}
Packit Service e08953
Packit Service e08953
Packit Service e08953
int uv_os_uname(uv_utsname_t* buffer) {
Packit Service e08953
  /* Implementation loosely based on
Packit Service e08953
     https://github.com/gagern/gnulib/blob/master/lib/uname.c */
Packit Service e08953
  OSVERSIONINFOW os_info;
Packit Service e08953
  SYSTEM_INFO system_info;
Packit Service e08953
  HKEY registry_key;
Packit Service e08953
  WCHAR product_name_w[256];
Packit Service e08953
  DWORD product_name_w_size;
Packit Service e08953
  int version_size;
Packit Service e08953
  int processor_level;
Packit Service e08953
  int r;
Packit Service e08953
Packit Service e08953
  if (buffer == NULL)
Packit Service e08953
    return UV_EINVAL;
Packit Service e08953
Packit Service e08953
  uv__once_init();
Packit Service e08953
  os_info.dwOSVersionInfoSize = sizeof(os_info);
Packit Service e08953
  os_info.szCSDVersion[0] = L'\0';
Packit Service e08953
Packit Service e08953
  /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
Packit Service e08953
     if RtlGetVersion() is not available. */
Packit Service e08953
  if (pRtlGetVersion) {
Packit Service e08953
    pRtlGetVersion(&os_info);
Packit Service e08953
  } else {
Packit Service e08953
    /* Silence GetVersionEx() deprecation warning. */
Packit Service e08953
    #pragma warning(suppress : 4996)
Packit Service e08953
    if (GetVersionExW(&os_info) == 0) {
Packit Service e08953
      r = uv_translate_sys_error(GetLastError());
Packit Service e08953
      goto error;
Packit Service e08953
    }
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  /* Populate the version field. */
Packit Service e08953
  version_size = 0;
Packit Service e08953
  r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
Packit Service e08953
                    L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
Packit Service e08953
                    0,
Packit Service e08953
                    KEY_QUERY_VALUE,
Packit Service e08953
                    &registry_key);
Packit Service e08953
Packit Service e08953
  if (r == ERROR_SUCCESS) {
Packit Service e08953
    product_name_w_size = sizeof(product_name_w);
Packit Service e08953
    r = RegGetValueW(registry_key,
Packit Service e08953
                     NULL,
Packit Service e08953
                     L"ProductName",
Packit Service e08953
                     RRF_RT_REG_SZ,
Packit Service e08953
                     NULL,
Packit Service e08953
                     (PVOID) product_name_w,
Packit Service e08953
                     &product_name_w_size);
Packit Service e08953
    RegCloseKey(registry_key);
Packit Service e08953
Packit Service e08953
    if (r == ERROR_SUCCESS) {
Packit Service e08953
      version_size = WideCharToMultiByte(CP_UTF8,
Packit Service e08953
                                         0,
Packit Service e08953
                                         product_name_w,
Packit Service e08953
                                         -1,
Packit Service e08953
                                         buffer->version,
Packit Service e08953
                                         sizeof(buffer->version),
Packit Service e08953
                                         NULL,
Packit Service e08953
                                         NULL);
Packit Service e08953
      if (version_size == 0) {
Packit Service e08953
        r = uv_translate_sys_error(GetLastError());
Packit Service e08953
        goto error;
Packit Service e08953
      }
Packit Service e08953
    }
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  /* Append service pack information to the version if present. */
Packit Service e08953
  if (os_info.szCSDVersion[0] != L'\0') {
Packit Service e08953
    if (version_size > 0)
Packit Service e08953
      buffer->version[version_size - 1] = ' ';
Packit Service e08953
Packit Service e08953
    if (WideCharToMultiByte(CP_UTF8,
Packit Service e08953
                            0,
Packit Service e08953
                            os_info.szCSDVersion,
Packit Service e08953
                            -1,
Packit Service e08953
                            buffer->version + version_size,
Packit Service e08953
                            sizeof(buffer->version) - version_size,
Packit Service e08953
                            NULL,
Packit Service e08953
                            NULL) == 0) {
Packit Service e08953
      r = uv_translate_sys_error(GetLastError());
Packit Service e08953
      goto error;
Packit Service e08953
    }
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  /* Populate the sysname field. */
Packit Service e08953
#ifdef __MINGW32__
Packit Service e08953
  r = snprintf(buffer->sysname,
Packit Service e08953
               sizeof(buffer->sysname),
Packit Service e08953
               "MINGW32_NT-%u.%u",
Packit Service e08953
               (unsigned int) os_info.dwMajorVersion,
Packit Service e08953
               (unsigned int) os_info.dwMinorVersion);
Packit Service e08953
  assert(r < sizeof(buffer->sysname));
Packit Service e08953
#else
Packit Service e08953
  uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
Packit Service e08953
#endif
Packit Service e08953
Packit Service e08953
  /* Populate the release field. */
Packit Service e08953
  r = snprintf(buffer->release,
Packit Service e08953
               sizeof(buffer->release),
Packit Service e08953
               "%d.%d.%d",
Packit Service e08953
               (unsigned int) os_info.dwMajorVersion,
Packit Service e08953
               (unsigned int) os_info.dwMinorVersion,
Packit Service e08953
               (unsigned int) os_info.dwBuildNumber);
Packit Service e08953
  assert(r < sizeof(buffer->release));
Packit Service e08953
Packit Service e08953
  /* Populate the machine field. */
Packit Service e08953
  GetSystemInfo(&system_info);
Packit Service e08953
Packit Service e08953
  switch (system_info.wProcessorArchitecture) {
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_AMD64:
Packit Service e08953
      uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_IA64:
Packit Service e08953
      uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_INTEL:
Packit Service e08953
      uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
Packit Service e08953
Packit Service e08953
      if (system_info.wProcessorLevel > 3) {
Packit Service e08953
        processor_level = system_info.wProcessorLevel < 6 ?
Packit Service e08953
                          system_info.wProcessorLevel : 6;
Packit Service e08953
        buffer->machine[1] = '0' + processor_level;
Packit Service e08953
      }
Packit Service e08953
Packit Service e08953
      break;
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
Packit Service e08953
      uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_MIPS:
Packit Service e08953
      uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_ALPHA:
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_ALPHA64:
Packit Service e08953
      uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_PPC:
Packit Service e08953
      uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_SHX:
Packit Service e08953
      uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
    case PROCESSOR_ARCHITECTURE_ARM:
Packit Service e08953
      uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
    default:
Packit Service e08953
      uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
Packit Service e08953
      break;
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  return 0;
Packit Service e08953
Packit Service e08953
error:
Packit Service e08953
  buffer->sysname[0] = '\0';
Packit Service e08953
  buffer->release[0] = '\0';
Packit Service e08953
  buffer->version[0] = '\0';
Packit Service e08953
  buffer->machine[0] = '\0';
Packit Service e08953
  return r;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
int uv_gettimeofday(uv_timeval64_t* tv) {
Packit Service e08953
  /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
Packit Service e08953
  const uint64_t epoch = (uint64_t) 116444736000000000ULL;
Packit Service e08953
  FILETIME file_time;
Packit Service e08953
  ULARGE_INTEGER ularge;
Packit Service e08953
Packit Service e08953
  if (tv == NULL)
Packit Service e08953
    return UV_EINVAL;
Packit Service e08953
Packit Service e08953
  GetSystemTimeAsFileTime(&file_time);
Packit Service e08953
  ularge.LowPart = file_time.dwLowDateTime;
Packit Service e08953
  ularge.HighPart = file_time.dwHighDateTime;
Packit Service e08953
  tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
Packit Service e08953
  tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
Packit Service e08953
  return 0;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
int uv__random_rtlgenrandom(void* buf, size_t buflen) {
Packit Service e08953
  if (buflen == 0)
Packit Service e08953
    return 0;
Packit Service e08953
Packit Service e08953
  if (SystemFunction036(buf, buflen) == FALSE)
Packit Service e08953
    return UV_EIO;
Packit Service e08953
Packit Service e08953
  return 0;
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
void uv_sleep(unsigned int msec) {
Packit Service e08953
  Sleep(msec);
Packit Service e08953
}