Home | History | Annotate | Line # | Download | only in win
      1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
      2  *
      3  * Permission is hereby granted, free of charge, to any person obtaining a copy
      4  * of this software and associated documentation files (the "Software"), to
      5  * deal in the Software without restriction, including without limitation the
      6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      7  * sell copies of the Software, and to permit persons to whom the Software is
      8  * furnished to do so, subject to the following conditions:
      9  *
     10  * The above copyright notice and this permission notice shall be included in
     11  * all copies or substantial portions of the Software.
     12  *
     13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     19  * IN THE SOFTWARE.
     20  */
     21 
     22 #include <assert.h>
     23 #include <direct.h>
     24 #include <limits.h>
     25 #include <stdio.h>
     26 #include <string.h>
     27 #include <time.h>
     28 #include <wchar.h>
     29 
     30 #include "uv.h"
     31 #include "internal.h"
     32 
     33 /* clang-format off */
     34 #include <sysinfoapi.h>
     35 #include <winsock2.h>
     36 #include <winperf.h>
     37 #include <iphlpapi.h>
     38 #include <psapi.h>
     39 #include <tlhelp32.h>
     40 #include <windows.h>
     41 /* clang-format on */
     42 #include <userenv.h>
     43 #include <math.h>
     44 
     45 /*
     46  * Max title length; the only thing MSDN tells us about the maximum length
     47  * of the console title is that it is smaller than 64K. However in practice
     48  * it is much smaller, and there is no way to figure out what the exact length
     49  * of the title is or can be, at least not on XP. To make it even more
     50  * annoying, GetConsoleTitle fails when the buffer to be read into is bigger
     51  * than the actual maximum length. So we make a conservative guess here;
     52  * just don't put the novel you're writing in the title, unless the plot
     53  * survives truncation.
     54  */
     55 #define MAX_TITLE_LENGTH 8192
     56 
     57 /* The number of nanoseconds in one second. */
     58 #define UV__NANOSEC 1000000000
     59 
     60 /* Max user name length, from iphlpapi.h */
     61 #ifndef UNLEN
     62 # define UNLEN 256
     63 #endif
     64 
     65 
     66 /* A RtlGenRandom() by any other name... */
     67 extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
     68 
     69 /* Cached copy of the process title, plus a mutex guarding it. */
     70 static char *process_title;
     71 static CRITICAL_SECTION process_title_lock;
     72 
     73 /* Frequency of the high-resolution clock. */
     74 static uint64_t hrtime_frequency_ = 0;
     75 
     76 
     77 /*
     78  * One-time initialization code for functionality defined in util.c.
     79  */
     80 void uv__util_init(void) {
     81   LARGE_INTEGER perf_frequency;
     82 
     83   /* Initialize process title access mutex. */
     84   InitializeCriticalSection(&process_title_lock);
     85 
     86   /* Retrieve high-resolution timer frequency
     87    * and precompute its reciprocal.
     88    */
     89   if (QueryPerformanceFrequency(&perf_frequency)) {
     90     hrtime_frequency_ = perf_frequency.QuadPart;
     91   } else {
     92     uv_fatal_error(GetLastError(), "QueryPerformanceFrequency");
     93   }
     94 }
     95 
     96 
     97 int uv_exepath(char* buffer, size_t* size_ptr) {
     98   size_t utf8_len, utf16_buffer_len, utf16_len;
     99   WCHAR* utf16_buffer;
    100   int err;
    101 
    102   if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
    103     return UV_EINVAL;
    104   }
    105 
    106   if (*size_ptr > 32768) {
    107     /* Windows paths can never be longer than this. */
    108     utf16_buffer_len = 32768;
    109   } else {
    110     utf16_buffer_len = (int) *size_ptr;
    111   }
    112 
    113   utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
    114   if (!utf16_buffer) {
    115     return UV_ENOMEM;
    116   }
    117 
    118   /* Get the path as UTF-16. */
    119   utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
    120   if (utf16_len <= 0) {
    121     err = GetLastError();
    122     goto error;
    123   }
    124 
    125   /* Convert to UTF-8 */
    126   utf8_len = *size_ptr - 1; /* Reserve space for NUL */
    127   err = uv_utf16_to_wtf8(utf16_buffer, utf16_len, &buffer, &utf8_len);
    128   if (err == UV_ENOBUFS) {
    129     utf8_len = *size_ptr - 1;
    130     err = 0;
    131   }
    132   *size_ptr = utf8_len;
    133 
    134   uv__free(utf16_buffer);
    135 
    136   return err;
    137 
    138  error:
    139   uv__free(utf16_buffer);
    140   return uv_translate_sys_error(err);
    141 }
    142 
    143 
    144 static int uv__cwd(WCHAR** buf, DWORD *len) {
    145   WCHAR* p;
    146   DWORD n;
    147   DWORD t;
    148 
    149   t = GetCurrentDirectoryW(0, NULL);
    150   for (;;) {
    151     if (t == 0)
    152       return uv_translate_sys_error(GetLastError());
    153 
    154     /* |t| is the size of the buffer _including_ nul. */
    155     p = uv__malloc(t * sizeof(*p));
    156     if (p == NULL)
    157       return UV_ENOMEM;
    158 
    159     /* |n| is the size of the buffer _excluding_ nul but _only on success_.
    160      * If |t| was too small because another thread changed the working
    161      * directory, |n| is the size the buffer should be _including_ nul.
    162      * It therefore follows we must resize when n >= t and fail when n == 0.
    163      */
    164     n = GetCurrentDirectoryW(t, p);
    165     if (n > 0)
    166       if (n < t)
    167         break;
    168 
    169     uv__free(p);
    170     t = n;
    171   }
    172 
    173   /* The returned directory should not have a trailing slash, unless it points
    174    * at a drive root, like c:\. Remove it if needed.
    175    */
    176   t = n - 1;
    177   if (p[t] == L'\\' && !(n == 3 && p[1] == L':')) {
    178     p[t] = L'\0';
    179     n = t;
    180   }
    181 
    182   *buf = p;
    183   *len = n;
    184 
    185   return 0;
    186 }
    187 
    188 
    189 int uv_cwd(char* buffer, size_t* size) {
    190   DWORD utf16_len;
    191   WCHAR *utf16_buffer;
    192   int r;
    193 
    194   if (buffer == NULL || size == NULL || *size == 0) {
    195     return UV_EINVAL;
    196   }
    197 
    198   r = uv__cwd(&utf16_buffer, &utf16_len);
    199   if (r < 0)
    200     return r;
    201 
    202   r = uv__copy_utf16_to_utf8(utf16_buffer, utf16_len, buffer, size);
    203 
    204   uv__free(utf16_buffer);
    205 
    206   return r;
    207 }
    208 
    209 
    210 int uv_chdir(const char* dir) {
    211   WCHAR *utf16_buffer;
    212   DWORD utf16_len;
    213   WCHAR drive_letter, env_var[4];
    214   int r;
    215 
    216   /* Convert to UTF-16 */
    217   r = uv__convert_utf8_to_utf16(dir, &utf16_buffer);
    218   if (r)
    219     return r;
    220 
    221   if (!SetCurrentDirectoryW(utf16_buffer)) {
    222     uv__free(utf16_buffer);
    223     return uv_translate_sys_error(GetLastError());
    224   }
    225 
    226   /* uv__cwd() will return a new buffer. */
    227   uv__free(utf16_buffer);
    228   utf16_buffer = NULL;
    229 
    230   /* Windows stores the drive-local path in an "hidden" environment variable,
    231    * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
    232    * this, so we'll have to do it. */
    233   r = uv__cwd(&utf16_buffer, &utf16_len);
    234   if (r == UV_ENOMEM) {
    235     /* When updating the environment variable fails, return UV_OK anyway.
    236      * We did successfully change current working directory, only updating
    237      * hidden env variable failed. */
    238     return 0;
    239   }
    240   if (r < 0) {
    241     return r;
    242   }
    243 
    244   if (utf16_len < 2 || utf16_buffer[1] != L':') {
    245     /* Doesn't look like a drive letter could be there - probably an UNC path.
    246      * TODO: Need to handle win32 namespaces like \\?\C:\ ? */
    247     drive_letter = 0;
    248   } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
    249     drive_letter = utf16_buffer[0];
    250   } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
    251     /* Convert to uppercase. */
    252     drive_letter = utf16_buffer[0] - L'a' + L'A';
    253   } else {
    254     /* Not valid. */
    255     drive_letter = 0;
    256   }
    257 
    258   if (drive_letter != 0) {
    259     /* Construct the environment variable name and set it. */
    260     env_var[0] = L'=';
    261     env_var[1] = drive_letter;
    262     env_var[2] = L':';
    263     env_var[3] = L'\0';
    264 
    265     SetEnvironmentVariableW(env_var, utf16_buffer);
    266   }
    267 
    268   uv__free(utf16_buffer);
    269   return 0;
    270 }
    271 
    272 
    273 void uv_loadavg(double avg[3]) {
    274   /* Can't be implemented */
    275   avg[0] = avg[1] = avg[2] = 0;
    276 }
    277 
    278 
    279 uint64_t uv_get_free_memory(void) {
    280   MEMORYSTATUSEX memory_status;
    281   memory_status.dwLength = sizeof(memory_status);
    282 
    283   if (!GlobalMemoryStatusEx(&memory_status)) {
    284      return 0;
    285   }
    286 
    287   return (uint64_t)memory_status.ullAvailPhys;
    288 }
    289 
    290 
    291 uint64_t uv_get_total_memory(void) {
    292   MEMORYSTATUSEX memory_status;
    293   memory_status.dwLength = sizeof(memory_status);
    294 
    295   if (!GlobalMemoryStatusEx(&memory_status)) {
    296     return 0;
    297   }
    298 
    299   return (uint64_t)memory_status.ullTotalPhys;
    300 }
    301 
    302 
    303 uint64_t uv_get_constrained_memory(void) {
    304   return 0;  /* Memory constraints are unknown. */
    305 }
    306 
    307 
    308 uint64_t uv_get_available_memory(void) {
    309   return uv_get_free_memory();
    310 }
    311 
    312 
    313 uv_pid_t uv_os_getpid(void) {
    314   return GetCurrentProcessId();
    315 }
    316 
    317 
    318 uv_pid_t uv_os_getppid(void) {
    319   NTSTATUS nt_status;
    320   PROCESS_BASIC_INFORMATION basic_info;
    321 
    322   nt_status = pNtQueryInformationProcess(GetCurrentProcess(),
    323     ProcessBasicInformation,
    324     &basic_info,
    325     sizeof(basic_info),
    326     NULL);
    327   if (NT_SUCCESS(nt_status)) {
    328     return basic_info.InheritedFromUniqueProcessId;
    329   } else {
    330     return -1;
    331   }
    332 }
    333 
    334 
    335 char** uv_setup_args(int argc, char** argv) {
    336   return argv;
    337 }
    338 
    339 
    340 void uv__process_title_cleanup(void) {
    341 }
    342 
    343 
    344 int uv_set_process_title(const char* title) {
    345   int err;
    346   int length;
    347   WCHAR* title_w = NULL;
    348 
    349   uv__once_init();
    350 
    351   err = uv__convert_utf8_to_utf16(title, &title_w);
    352   if (err)
    353     return err;
    354 
    355   /* If the title must be truncated insert a \0 terminator there */
    356   length = wcslen(title_w);
    357   if (length >= MAX_TITLE_LENGTH)
    358     title_w[MAX_TITLE_LENGTH - 1] = L'\0';
    359 
    360   if (!SetConsoleTitleW(title_w)) {
    361     err = GetLastError();
    362     goto done;
    363   }
    364 
    365   EnterCriticalSection(&process_title_lock);
    366   uv__free(process_title);
    367   process_title = uv__strdup(title);
    368   LeaveCriticalSection(&process_title_lock);
    369 
    370   err = 0;
    371 
    372 done:
    373   uv__free(title_w);
    374   return uv_translate_sys_error(err);
    375 }
    376 
    377 
    378 static int uv__get_process_title(void) {
    379   WCHAR title_w[MAX_TITLE_LENGTH];
    380   DWORD wlen;
    381 
    382   wlen = GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR));
    383   if (wlen == 0)
    384     return uv_translate_sys_error(GetLastError());
    385 
    386   return uv__convert_utf16_to_utf8(title_w, wlen, &process_title);
    387 }
    388 
    389 
    390 int uv_get_process_title(char* buffer, size_t size) {
    391   size_t len;
    392   int r;
    393 
    394   if (buffer == NULL || size == 0)
    395     return UV_EINVAL;
    396 
    397   uv__once_init();
    398 
    399   EnterCriticalSection(&process_title_lock);
    400   /*
    401    * If the process_title was never read before nor explicitly set,
    402    * we must query it with getConsoleTitleW
    403    */
    404   if (process_title == NULL) {
    405     r = uv__get_process_title();
    406     if (r) {
    407       LeaveCriticalSection(&process_title_lock);
    408       return r;
    409     }
    410   }
    411 
    412   assert(process_title);
    413   len = strlen(process_title) + 1;
    414 
    415   if (size < len) {
    416     LeaveCriticalSection(&process_title_lock);
    417     return UV_ENOBUFS;
    418   }
    419 
    420   memcpy(buffer, process_title, len);
    421   LeaveCriticalSection(&process_title_lock);
    422 
    423   return 0;
    424 }
    425 
    426 
    427 /* https://github.com/libuv/libuv/issues/1674 */
    428 int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) {
    429   FILETIME ft;
    430   int64_t t;
    431 
    432   if (ts == NULL)
    433     return UV_EFAULT;
    434 
    435   switch (clock_id) {
    436     case UV_CLOCK_MONOTONIC:
    437       uv__once_init();
    438       t = uv__hrtime(UV__NANOSEC);
    439       ts->tv_sec = t / 1000000000;
    440       ts->tv_nsec = t % 1000000000;
    441       return 0;
    442     case UV_CLOCK_REALTIME:
    443       GetSystemTimePreciseAsFileTime(&ft);
    444       /* In 100-nanosecond increments from 1601-01-01 UTC because why not? */
    445       t = (int64_t) ft.dwHighDateTime << 32 | ft.dwLowDateTime;
    446       /* Convert to UNIX epoch, 1970-01-01. Still in 100 ns increments. */
    447       t -= 116444736000000000ll;
    448       /* Now convert to seconds and nanoseconds. */
    449       ts->tv_sec = t / 10000000;
    450       ts->tv_nsec = t % 10000000 * 100;
    451       return 0;
    452   }
    453 
    454   return UV_EINVAL;
    455 }
    456 
    457 
    458 uint64_t uv_hrtime(void) {
    459   uv__once_init();
    460   return uv__hrtime(UV__NANOSEC);
    461 }
    462 
    463 
    464 uint64_t uv__hrtime(unsigned int scale) {
    465   LARGE_INTEGER counter;
    466   double scaled_freq;
    467   double result;
    468 
    469   assert(hrtime_frequency_ != 0);
    470   assert(scale != 0);
    471   if (!QueryPerformanceCounter(&counter)) {
    472     uv_fatal_error(GetLastError(), "QueryPerformanceCounter");
    473   }
    474   assert(counter.QuadPart != 0);
    475 
    476   /* Because we have no guarantee about the order of magnitude of the
    477    * performance counter interval, integer math could cause this computation
    478    * to overflow. Therefore we resort to floating point math.
    479    */
    480   scaled_freq = (double) hrtime_frequency_ / scale;
    481   result = (double) counter.QuadPart / scaled_freq;
    482   return (uint64_t) result;
    483 }
    484 
    485 
    486 int uv_resident_set_memory(size_t* rss) {
    487   HANDLE current_process;
    488   PROCESS_MEMORY_COUNTERS pmc;
    489 
    490   current_process = GetCurrentProcess();
    491 
    492   if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
    493     return uv_translate_sys_error(GetLastError());
    494   }
    495 
    496   *rss = pmc.WorkingSetSize;
    497 
    498   return 0;
    499 }
    500 
    501 
    502 int uv_uptime(double* uptime) {
    503   *uptime = GetTickCount64() / 1000.0;
    504   return 0;
    505 }
    506 
    507 
    508 unsigned int uv_available_parallelism(void) {
    509   DWORD_PTR procmask;
    510   DWORD_PTR sysmask;
    511   int count;
    512   int i;
    513 
    514   /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
    515    * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
    516    */
    517   count = 0;
    518   if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask))
    519     for (i = 0; i < 8 * sizeof(procmask); i++)
    520       count += 1 & (procmask >> i);
    521 
    522   if (count > 0)
    523     return count;
    524 
    525   return 1;
    526 }
    527 
    528 
    529 int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
    530   uv_cpu_info_t* cpu_infos;
    531   SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
    532   DWORD sppi_size;
    533   SYSTEM_INFO system_info;
    534   DWORD cpu_count, i;
    535   NTSTATUS status;
    536   ULONG result_size;
    537   int err;
    538   uv_cpu_info_t* cpu_info;
    539 
    540   cpu_infos = NULL;
    541   cpu_count = 0;
    542   sppi = NULL;
    543 
    544   uv__once_init();
    545 
    546   GetSystemInfo(&system_info);
    547   cpu_count = system_info.dwNumberOfProcessors;
    548 
    549   cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
    550   if (cpu_infos == NULL) {
    551     err = ERROR_OUTOFMEMORY;
    552     goto error;
    553   }
    554 
    555   sppi_size = cpu_count * sizeof(*sppi);
    556   sppi = uv__malloc(sppi_size);
    557   if (sppi == NULL) {
    558     err = ERROR_OUTOFMEMORY;
    559     goto error;
    560   }
    561 
    562   status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
    563                                      sppi,
    564                                      sppi_size,
    565                                      &result_size);
    566   if (!NT_SUCCESS(status)) {
    567     err = pRtlNtStatusToDosError(status);
    568     goto error;
    569   }
    570 
    571   assert(result_size == sppi_size);
    572 
    573   for (i = 0; i < cpu_count; i++) {
    574     WCHAR key_name[128];
    575     HKEY processor_key;
    576     DWORD cpu_speed;
    577     DWORD cpu_speed_size = sizeof(cpu_speed);
    578     WCHAR cpu_brand[256];
    579     DWORD cpu_brand_size = sizeof(cpu_brand);
    580     size_t len;
    581 
    582     len = _snwprintf(key_name,
    583                      ARRAY_SIZE(key_name),
    584                      L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
    585                      i);
    586 
    587     assert(len > 0 && len < ARRAY_SIZE(key_name));
    588 
    589     err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
    590                         key_name,
    591                         0,
    592                         KEY_QUERY_VALUE,
    593                         &processor_key);
    594     if (err != ERROR_SUCCESS) {
    595       goto error;
    596     }
    597 
    598     err = RegQueryValueExW(processor_key,
    599                            L"~MHz",
    600                            NULL,
    601                            NULL,
    602                            (BYTE*)&cpu_speed,
    603                            &cpu_speed_size);
    604     if (err != ERROR_SUCCESS) {
    605       RegCloseKey(processor_key);
    606       goto error;
    607     }
    608 
    609     err = RegQueryValueExW(processor_key,
    610                            L"ProcessorNameString",
    611                            NULL,
    612                            NULL,
    613                            (BYTE*)&cpu_brand,
    614                            &cpu_brand_size);
    615     RegCloseKey(processor_key);
    616     if (err != ERROR_SUCCESS)
    617       goto error;
    618 
    619     cpu_info = &cpu_infos[i];
    620     cpu_info->speed = cpu_speed;
    621     cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
    622     cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
    623         sppi[i].IdleTime.QuadPart) / 10000;
    624     cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
    625     cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
    626     cpu_info->cpu_times.nice = 0;
    627 
    628     uv__convert_utf16_to_utf8(cpu_brand,
    629                               cpu_brand_size / sizeof(WCHAR),
    630                               &(cpu_info->model));
    631   }
    632 
    633   uv__free(sppi);
    634 
    635   *cpu_count_ptr = cpu_count;
    636   *cpu_infos_ptr = cpu_infos;
    637 
    638   return 0;
    639 
    640  error:
    641   if (cpu_infos != NULL) {
    642     /* This is safe because the cpu_infos array is zeroed on allocation. */
    643     for (i = 0; i < cpu_count; i++)
    644       uv__free(cpu_infos[i].model);
    645   }
    646 
    647   uv__free(cpu_infos);
    648   uv__free(sppi);
    649 
    650   return uv_translate_sys_error(err);
    651 }
    652 
    653 
    654 int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
    655     int* count_ptr) {
    656   IP_ADAPTER_ADDRESSES* win_address_buf;
    657   ULONG win_address_buf_size;
    658   IP_ADAPTER_ADDRESSES* adapter;
    659 
    660   uv_interface_address_t* uv_address_buf;
    661   char* name_buf;
    662   size_t uv_address_buf_size;
    663   uv_interface_address_t* uv_address;
    664 
    665   int count;
    666   ULONG flags;
    667 
    668   *addresses_ptr = NULL;
    669   *count_ptr = 0;
    670 
    671   flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
    672     GAA_FLAG_SKIP_DNS_SERVER;
    673 
    674   /* Fetch the size of the adapters reported by windows, and then get the list
    675    * itself. */
    676   win_address_buf_size = 0;
    677   win_address_buf = NULL;
    678 
    679   for (;;) {
    680     ULONG r;
    681 
    682     /* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
    683      * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
    684      * win_address_buf_size. */
    685     r = GetAdaptersAddresses(AF_UNSPEC,
    686                              flags,
    687                              NULL,
    688                              win_address_buf,
    689                              &win_address_buf_size);
    690 
    691     if (r == ERROR_SUCCESS)
    692       break;
    693 
    694     uv__free(win_address_buf);
    695 
    696     switch (r) {
    697       case ERROR_BUFFER_OVERFLOW:
    698         /* This happens when win_address_buf is NULL or too small to hold all
    699          * adapters. */
    700         win_address_buf = uv__malloc(win_address_buf_size);
    701         if (win_address_buf == NULL)
    702           return UV_ENOMEM;
    703 
    704         continue;
    705 
    706       case ERROR_NO_DATA: {
    707         /* No adapters were found. */
    708         uv_address_buf = uv__malloc(1);
    709         if (uv_address_buf == NULL)
    710           return UV_ENOMEM;
    711 
    712         *count_ptr = 0;
    713         *addresses_ptr = uv_address_buf;
    714 
    715         return 0;
    716       }
    717 
    718       case ERROR_ADDRESS_NOT_ASSOCIATED:
    719         return UV_EAGAIN;
    720 
    721       case ERROR_INVALID_PARAMETER:
    722         /* MSDN says:
    723          *   "This error is returned for any of the following conditions: the
    724          *   SizePointer parameter is NULL, the Address parameter is not
    725          *   AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
    726          *   the parameters requested is greater than ULONG_MAX."
    727          * Since the first two conditions are not met, it must be that the
    728          * adapter data is too big.
    729          */
    730         return UV_ENOBUFS;
    731 
    732       default:
    733         /* Other (unspecified) errors can happen, but we don't have any special
    734          * meaning for them. */
    735         assert(r != ERROR_SUCCESS);
    736         return uv_translate_sys_error(r);
    737     }
    738   }
    739 
    740   /* Count the number of enabled interfaces and compute how much space is
    741    * needed to store their info. */
    742   count = 0;
    743   uv_address_buf_size = 0;
    744 
    745   for (adapter = win_address_buf;
    746        adapter != NULL;
    747        adapter = adapter->Next) {
    748     IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
    749     int name_size;
    750 
    751     /* Interfaces that are not 'up' should not be reported. Also skip
    752      * interfaces that have no associated unicast address, as to avoid
    753      * allocating space for the name for this interface. */
    754     if (adapter->OperStatus != IfOperStatusUp ||
    755         adapter->FirstUnicastAddress == NULL)
    756       continue;
    757 
    758     /* Compute the size of the interface name. */
    759     name_size = uv_utf16_length_as_wtf8(adapter->FriendlyName, -1);
    760     uv_address_buf_size += name_size + 1;
    761 
    762     /* Count the number of addresses associated with this interface, and
    763      * compute the size. */
    764     for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
    765                            adapter->FirstUnicastAddress;
    766          unicast_address != NULL;
    767          unicast_address = unicast_address->Next) {
    768       count++;
    769       uv_address_buf_size += sizeof(uv_interface_address_t);
    770     }
    771   }
    772 
    773   /* Allocate space to store interface data plus adapter names. */
    774   uv_address_buf = uv__malloc(uv_address_buf_size);
    775   if (uv_address_buf == NULL) {
    776     uv__free(win_address_buf);
    777     return UV_ENOMEM;
    778   }
    779 
    780   /* Compute the start of the uv_interface_address_t array, and the place in
    781    * the buffer where the interface names will be stored. */
    782   uv_address = uv_address_buf;
    783   name_buf = (char*) (uv_address_buf + count);
    784 
    785   /* Fill out the output buffer. */
    786   for (adapter = win_address_buf;
    787        adapter != NULL;
    788        adapter = adapter->Next) {
    789     IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
    790     size_t name_size;
    791     int r;
    792 
    793     if (adapter->OperStatus != IfOperStatusUp ||
    794         adapter->FirstUnicastAddress == NULL)
    795       continue;
    796 
    797     /* Convert the interface name to UTF8. */
    798     name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
    799     r = uv__copy_utf16_to_utf8(adapter->FriendlyName,
    800                                -1,
    801                                name_buf,
    802                                &name_size);
    803     if (r) {
    804       uv__free(win_address_buf);
    805       uv__free(uv_address_buf);
    806       return r;
    807     }
    808     name_size += 1; /* Add NUL byte. */
    809 
    810     /* Add an uv_interface_address_t element for every unicast address. */
    811     for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
    812                            adapter->FirstUnicastAddress;
    813          unicast_address != NULL;
    814          unicast_address = unicast_address->Next) {
    815       struct sockaddr* sa;
    816       ULONG prefix_len;
    817 
    818       sa = unicast_address->Address.lpSockaddr;
    819 
    820       prefix_len =
    821         ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
    822 
    823       memset(uv_address, 0, sizeof *uv_address);
    824 
    825       uv_address->name = name_buf;
    826 
    827       if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
    828         memcpy(uv_address->phys_addr,
    829                adapter->PhysicalAddress,
    830                sizeof(uv_address->phys_addr));
    831       }
    832 
    833       uv_address->is_internal =
    834           (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
    835 
    836       if (sa->sa_family == AF_INET6) {
    837         uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
    838 
    839         uv_address->netmask.netmask6.sin6_family = AF_INET6;
    840         memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
    841         /* This check ensures that we don't write past the size of the data. */
    842         if (prefix_len % 8) {
    843           uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
    844               0xff << (8 - prefix_len % 8);
    845         }
    846 
    847       } else {
    848         uv_address->address.address4 = *((struct sockaddr_in *) sa);
    849 
    850         uv_address->netmask.netmask4.sin_family = AF_INET;
    851         uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
    852             htonl(0xffffffff << (32 - prefix_len)) : 0;
    853       }
    854 
    855       uv_address++;
    856     }
    857 
    858     name_buf += name_size;
    859   }
    860 
    861   uv__free(win_address_buf);
    862 
    863   *addresses_ptr = uv_address_buf;
    864   *count_ptr = count;
    865 
    866   return 0;
    867 }
    868 
    869 
    870 void uv_free_interface_addresses(uv_interface_address_t* addresses,
    871     int count) {
    872   uv__free(addresses);
    873 }
    874 
    875 
    876 int uv_getrusage(uv_rusage_t *uv_rusage) {
    877   FILETIME create_time, exit_time, kernel_time, user_time;
    878   SYSTEMTIME kernel_system_time, user_system_time;
    879   PROCESS_MEMORY_COUNTERS mem_counters;
    880   IO_COUNTERS io_counters;
    881   int ret;
    882 
    883   ret = GetProcessTimes(GetCurrentProcess(),
    884                         &create_time,
    885                         &exit_time,
    886                         &kernel_time,
    887                         &user_time);
    888   if (ret == 0) {
    889     return uv_translate_sys_error(GetLastError());
    890   }
    891 
    892   ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time);
    893   if (ret == 0) {
    894     return uv_translate_sys_error(GetLastError());
    895   }
    896 
    897   ret = FileTimeToSystemTime(&user_time, &user_system_time);
    898   if (ret == 0) {
    899     return uv_translate_sys_error(GetLastError());
    900   }
    901 
    902   ret = GetProcessMemoryInfo(GetCurrentProcess(),
    903                              &mem_counters,
    904                              sizeof(mem_counters));
    905   if (ret == 0) {
    906     return uv_translate_sys_error(GetLastError());
    907   }
    908 
    909   ret = GetProcessIoCounters(GetCurrentProcess(), &io_counters);
    910   if (ret == 0) {
    911     return uv_translate_sys_error(GetLastError());
    912   }
    913 
    914   memset(uv_rusage, 0, sizeof(*uv_rusage));
    915 
    916   uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 +
    917                                user_system_time.wMinute * 60 +
    918                                user_system_time.wSecond;
    919   uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000;
    920 
    921   uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 +
    922                                kernel_system_time.wMinute * 60 +
    923                                kernel_system_time.wSecond;
    924   uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000;
    925 
    926   uv_rusage->ru_majflt = (uint64_t) mem_counters.PageFaultCount;
    927   uv_rusage->ru_maxrss = (uint64_t) mem_counters.PeakWorkingSetSize / 1024;
    928 
    929   uv_rusage->ru_oublock = (uint64_t) io_counters.WriteOperationCount;
    930   uv_rusage->ru_inblock = (uint64_t) io_counters.ReadOperationCount;
    931 
    932   return 0;
    933 }
    934 
    935 
    936 int uv_getrusage_thread(uv_rusage_t* uv_rusage) {
    937   FILETIME create_time, exit_time, kernel_time, user_time;
    938   SYSTEMTIME kernel_system_time, user_system_time;
    939   int ret;
    940 
    941   ret = GetThreadTimes(GetCurrentThread(),
    942                        &create_time,
    943                        &exit_time,
    944                        &kernel_time,
    945                        &user_time);
    946   if (ret == 0) {
    947     return uv_translate_sys_error(GetLastError());
    948   }
    949 
    950   ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time);
    951   if (ret == 0) {
    952     return uv_translate_sys_error(GetLastError());
    953   }
    954 
    955   ret = FileTimeToSystemTime(&user_time, &user_system_time);
    956   if (ret == 0) {
    957     return uv_translate_sys_error(GetLastError());
    958   }
    959 
    960   memset(uv_rusage, 0, sizeof(*uv_rusage));
    961 
    962   uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 +
    963                                user_system_time.wMinute * 60 +
    964                                user_system_time.wSecond;
    965   uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000;
    966 
    967   uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 +
    968                                kernel_system_time.wMinute * 60 +
    969                                kernel_system_time.wSecond;
    970   uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000;
    971 
    972   return 0;
    973 }
    974 
    975 
    976 int uv_os_homedir(char* buffer, size_t* size) {
    977   uv_passwd_t pwd;
    978   size_t len;
    979   int r;
    980 
    981   /* Check if the USERPROFILE environment variable is set first. The task of
    982      performing input validation on buffer and size is taken care of by
    983      uv_os_getenv(). */
    984   r = uv_os_getenv("USERPROFILE", buffer, size);
    985 
    986   /* Don't return an error if USERPROFILE was not found. */
    987   if (r != UV_ENOENT) {
    988     /* USERPROFILE is empty or invalid */
    989     if (r == 0 && *size < 3) {
    990       return UV_ENOENT;
    991     }
    992     return r;
    993   }
    994 
    995   /* USERPROFILE is not set, so call uv_os_get_passwd() */
    996   r = uv_os_get_passwd(&pwd);
    997 
    998   if (r != 0) {
    999     return r;
   1000   }
   1001 
   1002   len = strlen(pwd.homedir);
   1003 
   1004   if (len >= *size) {
   1005     *size = len + 1;
   1006     uv_os_free_passwd(&pwd);
   1007     return UV_ENOBUFS;
   1008   }
   1009 
   1010   memcpy(buffer, pwd.homedir, len + 1);
   1011   *size = len;
   1012   uv_os_free_passwd(&pwd);
   1013 
   1014   return 0;
   1015 }
   1016 
   1017 
   1018 int uv_os_tmpdir(char* buffer, size_t* size) {
   1019   int r;
   1020   wchar_t *path;
   1021   size_t len;
   1022 
   1023   if (buffer == NULL || size == NULL || *size == 0)
   1024     return UV_EINVAL;
   1025 
   1026   len = 0;
   1027   len = GetTempPathW(0, NULL);
   1028   if (len == 0) {
   1029     return uv_translate_sys_error(GetLastError());
   1030   }
   1031 
   1032   /* tmp path is empty or invalid */
   1033   if (len < 3) {
   1034     return UV_ENOENT;
   1035   }
   1036 
   1037   /* Include space for terminating null char. */
   1038   len += 1;
   1039   path = uv__malloc(len * sizeof(wchar_t));
   1040   if (path == NULL) {
   1041     return UV_ENOMEM;
   1042   }
   1043   len = GetTempPathW(len, path);
   1044 
   1045   if (len == 0) {
   1046     uv__free(path);
   1047     return uv_translate_sys_error(GetLastError());
   1048   }
   1049 
   1050   /* The returned directory should not have a trailing slash, unless it points
   1051    * at a drive root, like c:\. Remove it if needed. */
   1052   if (path[len - 1] == L'\\' &&
   1053       !(len == 3 && path[1] == L':')) {
   1054     len--;
   1055     path[len] = L'\0';
   1056   }
   1057 
   1058   r = uv__copy_utf16_to_utf8(path, len, buffer, size);
   1059   uv__free(path);
   1060   return r;
   1061 }
   1062 
   1063 
   1064 /*
   1065  * Converts a UTF-16 string into a UTF-8 one. The resulting string is
   1066  * null-terminated.
   1067  *
   1068  * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
   1069  * be specified.
   1070  */
   1071 int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8) {
   1072   size_t utf8_len = 0;
   1073 
   1074   if (utf16 == NULL)
   1075     return UV_EINVAL;
   1076 
   1077    *utf8 = NULL;
   1078    return uv_utf16_to_wtf8(utf16, utf16len, utf8, &utf8_len);
   1079 }
   1080 
   1081 
   1082 /*
   1083  * Converts a UTF-8 string into a UTF-16 one. The resulting string is
   1084  * null-terminated.
   1085  */
   1086 int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16) {
   1087   int bufsize;
   1088 
   1089   if (utf8 == NULL)
   1090     return UV_EINVAL;
   1091 
   1092   /* Check how much space we need (including NUL). */
   1093   bufsize = uv_wtf8_length_as_utf16(utf8);
   1094   if (bufsize < 0)
   1095     return UV__EINVAL;
   1096 
   1097   /* Allocate the destination buffer. */
   1098   *utf16 = uv__malloc(sizeof(WCHAR) * bufsize);
   1099 
   1100   if (*utf16 == NULL)
   1101     return UV_ENOMEM;
   1102 
   1103   /* Convert to UTF-16 */
   1104   uv_wtf8_to_utf16(utf8, *utf16, bufsize);
   1105 
   1106   return 0;
   1107 }
   1108 
   1109 
   1110 /*
   1111  * Converts a UTF-16 string into a UTF-8 one in an existing buffer. The
   1112  * resulting string is null-terminated.
   1113  *
   1114  * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
   1115  * be specified.
   1116  */
   1117 int uv__copy_utf16_to_utf8(const WCHAR* utf16buffer, size_t utf16len, char* utf8, size_t *size) {
   1118   int r;
   1119 
   1120   if (utf8 == NULL || size == NULL)
   1121     return UV_EINVAL;
   1122 
   1123   if (*size == 0) {
   1124     *size = uv_utf16_length_as_wtf8(utf16buffer, utf16len);
   1125     r = UV_ENOBUFS;
   1126   } else {
   1127     *size -= 1; /* Reserve space for NUL. */
   1128     r = uv_utf16_to_wtf8(utf16buffer, utf16len, &utf8, size);
   1129   }
   1130   if (r == UV_ENOBUFS)
   1131     *size += 1; /* Add space for NUL. */
   1132   return r;
   1133 }
   1134 
   1135 
   1136 static int uv__getpwuid_r(uv_passwd_t* pwd) {
   1137   HANDLE token;
   1138   wchar_t username[UNLEN + 1];
   1139   wchar_t *path;
   1140   DWORD bufsize;
   1141   int r;
   1142 
   1143   if (pwd == NULL)
   1144     return UV_EINVAL;
   1145 
   1146   /* Get the home directory using GetUserProfileDirectoryW() */
   1147   if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
   1148     return uv_translate_sys_error(GetLastError());
   1149 
   1150   bufsize = 0;
   1151   GetUserProfileDirectoryW(token, NULL, &bufsize);
   1152   if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
   1153     r = GetLastError();
   1154     CloseHandle(token);
   1155     return uv_translate_sys_error(r);
   1156   }
   1157 
   1158   path = uv__malloc(bufsize * sizeof(wchar_t));
   1159   if (path == NULL) {
   1160     CloseHandle(token);
   1161     return UV_ENOMEM;
   1162   }
   1163 
   1164   if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
   1165     r = GetLastError();
   1166     CloseHandle(token);
   1167     uv__free(path);
   1168     return uv_translate_sys_error(r);
   1169   }
   1170 
   1171   CloseHandle(token);
   1172 
   1173   /* Get the username using GetUserNameW() */
   1174   bufsize = ARRAY_SIZE(username);
   1175   if (!GetUserNameW(username, &bufsize)) {
   1176     r = GetLastError();
   1177     uv__free(path);
   1178 
   1179     /* This should not be possible */
   1180     if (r == ERROR_INSUFFICIENT_BUFFER)
   1181       return UV_ENOMEM;
   1182 
   1183     return uv_translate_sys_error(r);
   1184   }
   1185 
   1186   pwd->homedir = NULL;
   1187   r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
   1188   uv__free(path);
   1189 
   1190   if (r != 0)
   1191     return r;
   1192 
   1193   pwd->username = NULL;
   1194   r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
   1195 
   1196   if (r != 0) {
   1197     uv__free(pwd->homedir);
   1198     return r;
   1199   }
   1200 
   1201   pwd->shell = NULL;
   1202   pwd->uid = -1;
   1203   pwd->gid = -1;
   1204 
   1205   return 0;
   1206 }
   1207 
   1208 
   1209 int uv_os_get_passwd(uv_passwd_t* pwd) {
   1210   return uv__getpwuid_r(pwd);
   1211 }
   1212 
   1213 
   1214 int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
   1215   return UV_ENOTSUP;
   1216 }
   1217 
   1218 
   1219 int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
   1220   return UV_ENOTSUP;
   1221 }
   1222 
   1223 
   1224 int uv_os_environ(uv_env_item_t** envitems, int* count) {
   1225   wchar_t* env;
   1226   wchar_t* penv;
   1227   int i, cnt;
   1228   uv_env_item_t* envitem;
   1229 
   1230   *envitems = NULL;
   1231   *count = 0;
   1232 
   1233   env = GetEnvironmentStringsW();
   1234   if (env == NULL)
   1235     return 0;
   1236 
   1237   for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
   1238 
   1239   *envitems = uv__calloc(i, sizeof(**envitems));
   1240   if (*envitems == NULL) {
   1241     FreeEnvironmentStringsW(env);
   1242     return UV_ENOMEM;
   1243   }
   1244 
   1245   penv = env;
   1246   cnt = 0;
   1247 
   1248   while (*penv != L'\0' && cnt < i) {
   1249     char* buf;
   1250     char* ptr;
   1251 
   1252     if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
   1253       goto fail;
   1254 
   1255     /* Using buf + 1 here because we know that `buf` has length at least 1,
   1256      * and some special environment variables on Windows start with a = sign. */
   1257     ptr = strchr(buf + 1, '=');
   1258     if (ptr == NULL) {
   1259       uv__free(buf);
   1260       goto do_continue;
   1261     }
   1262 
   1263     *ptr = '\0';
   1264 
   1265     envitem = &(*envitems)[cnt];
   1266     envitem->name = buf;
   1267     envitem->value = ptr + 1;
   1268 
   1269     cnt++;
   1270 
   1271   do_continue:
   1272     penv += wcslen(penv) + 1;
   1273   }
   1274 
   1275   FreeEnvironmentStringsW(env);
   1276 
   1277   *count = cnt;
   1278   return 0;
   1279 
   1280 fail:
   1281   FreeEnvironmentStringsW(env);
   1282 
   1283   for (i = 0; i < cnt; i++) {
   1284     envitem = &(*envitems)[cnt];
   1285     uv__free(envitem->name);
   1286   }
   1287   uv__free(*envitems);
   1288 
   1289   *envitems = NULL;
   1290   *count = 0;
   1291   return UV_ENOMEM;
   1292 }
   1293 
   1294 
   1295 int uv_os_getenv(const char* name, char* buffer, size_t* size) {
   1296   wchar_t fastvar[512];
   1297   wchar_t* var;
   1298   DWORD varlen;
   1299   wchar_t* name_w;
   1300   size_t len;
   1301   int r;
   1302 
   1303   if (name == NULL || buffer == NULL || size == NULL || *size == 0)
   1304     return UV_EINVAL;
   1305 
   1306   r = uv__convert_utf8_to_utf16(name, &name_w);
   1307 
   1308   if (r != 0)
   1309     return r;
   1310 
   1311   var = fastvar;
   1312   varlen = ARRAY_SIZE(fastvar);
   1313 
   1314   for (;;) {
   1315     SetLastError(ERROR_SUCCESS);
   1316     len = GetEnvironmentVariableW(name_w, var, varlen);
   1317 
   1318     if (len == 0)
   1319       r = uv_translate_sys_error(GetLastError());
   1320 
   1321     if (len < varlen)
   1322       break;
   1323 
   1324     /* Try repeatedly because we might have been preempted by another thread
   1325      * modifying the environment variable just as we're trying to read it.
   1326      */
   1327     if (var != fastvar)
   1328       uv__free(var);
   1329 
   1330     varlen = 1 + len;
   1331     var = uv__malloc(varlen * sizeof(*var));
   1332 
   1333     if (var == NULL) {
   1334       r = UV_ENOMEM;
   1335       goto fail;
   1336     }
   1337   }
   1338 
   1339   uv__free(name_w);
   1340   name_w = NULL;
   1341 
   1342   if (r == 0)
   1343     r = uv__copy_utf16_to_utf8(var, len, buffer, size);
   1344 
   1345 fail:
   1346 
   1347   if (name_w != NULL)
   1348     uv__free(name_w);
   1349 
   1350   if (var != fastvar)
   1351     uv__free(var);
   1352 
   1353   return r;
   1354 }
   1355 
   1356 
   1357 int uv_os_setenv(const char* name, const char* value) {
   1358   wchar_t* name_w;
   1359   wchar_t* value_w;
   1360   int r;
   1361 
   1362   if (name == NULL || value == NULL)
   1363     return UV_EINVAL;
   1364 
   1365   r = uv__convert_utf8_to_utf16(name, &name_w);
   1366 
   1367   if (r != 0)
   1368     return r;
   1369 
   1370   r = uv__convert_utf8_to_utf16(value, &value_w);
   1371 
   1372   if (r != 0) {
   1373     uv__free(name_w);
   1374     return r;
   1375   }
   1376 
   1377   r = SetEnvironmentVariableW(name_w, value_w);
   1378   uv__free(name_w);
   1379   uv__free(value_w);
   1380 
   1381   if (r == 0)
   1382     return uv_translate_sys_error(GetLastError());
   1383 
   1384   return 0;
   1385 }
   1386 
   1387 
   1388 int uv_os_unsetenv(const char* name) {
   1389   wchar_t* name_w;
   1390   int r;
   1391 
   1392   if (name == NULL)
   1393     return UV_EINVAL;
   1394 
   1395   r = uv__convert_utf8_to_utf16(name, &name_w);
   1396 
   1397   if (r != 0)
   1398     return r;
   1399 
   1400   r = SetEnvironmentVariableW(name_w, NULL);
   1401   uv__free(name_w);
   1402 
   1403   if (r == 0)
   1404     return uv_translate_sys_error(GetLastError());
   1405 
   1406   return 0;
   1407 }
   1408 
   1409 
   1410 int uv_os_gethostname(char* buffer, size_t* size) {
   1411   WCHAR buf[UV_MAXHOSTNAMESIZE];
   1412 
   1413   if (buffer == NULL || size == NULL || *size == 0)
   1414     return UV_EINVAL;
   1415 
   1416   uv__once_init(); /* Initialize winsock */
   1417 
   1418   if (pGetHostNameW == NULL)
   1419     return UV_ENOSYS;
   1420 
   1421   if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
   1422     return uv_translate_sys_error(WSAGetLastError());
   1423 
   1424   return uv__copy_utf16_to_utf8(buf, -1, buffer, size);
   1425 }
   1426 
   1427 
   1428 static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
   1429   int r;
   1430 
   1431   if (pid == 0)
   1432     *handle = GetCurrentProcess();
   1433   else
   1434     *handle = OpenProcess(access, FALSE, pid);
   1435 
   1436   if (*handle == NULL) {
   1437     r = GetLastError();
   1438 
   1439     if (r == ERROR_INVALID_PARAMETER)
   1440       return UV_ESRCH;
   1441     else
   1442       return uv_translate_sys_error(r);
   1443   }
   1444 
   1445   return 0;
   1446 }
   1447 
   1448 
   1449 int uv_os_getpriority(uv_pid_t pid, int* priority) {
   1450   HANDLE handle;
   1451   int r;
   1452 
   1453   if (priority == NULL)
   1454     return UV_EINVAL;
   1455 
   1456   r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
   1457 
   1458   if (r != 0)
   1459     return r;
   1460 
   1461   r = GetPriorityClass(handle);
   1462 
   1463   if (r == 0) {
   1464     r = uv_translate_sys_error(GetLastError());
   1465   } else {
   1466     /* Map Windows priority classes to Unix nice values. */
   1467     if (r == REALTIME_PRIORITY_CLASS)
   1468       *priority = UV_PRIORITY_HIGHEST;
   1469     else if (r == HIGH_PRIORITY_CLASS)
   1470       *priority = UV_PRIORITY_HIGH;
   1471     else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
   1472       *priority = UV_PRIORITY_ABOVE_NORMAL;
   1473     else if (r == NORMAL_PRIORITY_CLASS)
   1474       *priority = UV_PRIORITY_NORMAL;
   1475     else if (r == BELOW_NORMAL_PRIORITY_CLASS)
   1476       *priority = UV_PRIORITY_BELOW_NORMAL;
   1477     else  /* IDLE_PRIORITY_CLASS */
   1478       *priority = UV_PRIORITY_LOW;
   1479 
   1480     r = 0;
   1481   }
   1482 
   1483   CloseHandle(handle);
   1484   return r;
   1485 }
   1486 
   1487 
   1488 int uv_os_setpriority(uv_pid_t pid, int priority) {
   1489   HANDLE handle;
   1490   int priority_class;
   1491   int r;
   1492 
   1493   /* Map Unix nice values to Windows priority classes. */
   1494   if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
   1495     return UV_EINVAL;
   1496   else if (priority < UV_PRIORITY_HIGH)
   1497     priority_class = REALTIME_PRIORITY_CLASS;
   1498   else if (priority < UV_PRIORITY_ABOVE_NORMAL)
   1499     priority_class = HIGH_PRIORITY_CLASS;
   1500   else if (priority < UV_PRIORITY_NORMAL)
   1501     priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
   1502   else if (priority < UV_PRIORITY_BELOW_NORMAL)
   1503     priority_class = NORMAL_PRIORITY_CLASS;
   1504   else if (priority < UV_PRIORITY_LOW)
   1505     priority_class = BELOW_NORMAL_PRIORITY_CLASS;
   1506   else
   1507     priority_class = IDLE_PRIORITY_CLASS;
   1508 
   1509   r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
   1510 
   1511   if (r != 0)
   1512     return r;
   1513 
   1514   if (SetPriorityClass(handle, priority_class) == 0)
   1515     r = uv_translate_sys_error(GetLastError());
   1516 
   1517   CloseHandle(handle);
   1518   return r;
   1519 }
   1520 
   1521 int uv_thread_getpriority(uv_thread_t tid, int* priority) {
   1522   int r;
   1523 
   1524   if (priority == NULL)
   1525     return UV_EINVAL;
   1526 
   1527   r = GetThreadPriority(tid);
   1528   if (r == THREAD_PRIORITY_ERROR_RETURN)
   1529     return uv_translate_sys_error(GetLastError());
   1530 
   1531   *priority = r;
   1532   return 0;
   1533 }
   1534 
   1535 int uv_thread_setpriority(uv_thread_t tid, int priority) {
   1536   int r;
   1537 
   1538   switch (priority) {
   1539     case UV_THREAD_PRIORITY_HIGHEST:
   1540       r = SetThreadPriority(tid, THREAD_PRIORITY_HIGHEST);
   1541       break;
   1542     case UV_THREAD_PRIORITY_ABOVE_NORMAL:
   1543       r = SetThreadPriority(tid, THREAD_PRIORITY_ABOVE_NORMAL);
   1544       break;
   1545     case UV_THREAD_PRIORITY_NORMAL:
   1546       r = SetThreadPriority(tid, THREAD_PRIORITY_NORMAL);
   1547       break;
   1548     case UV_THREAD_PRIORITY_BELOW_NORMAL:
   1549       r = SetThreadPriority(tid, THREAD_PRIORITY_BELOW_NORMAL);
   1550       break;
   1551     case UV_THREAD_PRIORITY_LOWEST:
   1552       r = SetThreadPriority(tid, THREAD_PRIORITY_LOWEST);
   1553       break;
   1554     default:
   1555       return 0;
   1556   }
   1557 
   1558   if (r == 0)
   1559     return uv_translate_sys_error(GetLastError());
   1560 
   1561   return 0;
   1562 }
   1563 
   1564 int uv_os_uname(uv_utsname_t* buffer) {
   1565   /* Implementation loosely based on
   1566      https://github.com/gagern/gnulib/blob/master/lib/uname.c */
   1567   OSVERSIONINFOW os_info;
   1568   SYSTEM_INFO system_info;
   1569   HKEY registry_key;
   1570   WCHAR product_name_w[256];
   1571   DWORD product_name_w_size;
   1572   size_t version_size;
   1573   int processor_level;
   1574   int r;
   1575 
   1576   if (buffer == NULL)
   1577     return UV_EINVAL;
   1578 
   1579   uv__once_init();
   1580   os_info.dwOSVersionInfoSize = sizeof(os_info);
   1581   os_info.szCSDVersion[0] = L'\0';
   1582 
   1583   pRtlGetVersion(&os_info);
   1584 
   1585   /* Populate the version field. */
   1586   version_size = 0;
   1587   r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
   1588                     L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
   1589                     0,
   1590                     KEY_QUERY_VALUE | KEY_WOW64_64KEY,
   1591                     &registry_key);
   1592 
   1593   if (r == ERROR_SUCCESS) {
   1594     product_name_w_size = sizeof(product_name_w);
   1595     r = RegGetValueW(registry_key,
   1596                      NULL,
   1597                      L"ProductName",
   1598                      RRF_RT_REG_SZ,
   1599                      NULL,
   1600                      (PVOID) product_name_w,
   1601                      &product_name_w_size);
   1602     RegCloseKey(registry_key);
   1603 
   1604     if (r == ERROR_SUCCESS) {
   1605       /* Windows 11 shares dwMajorVersion with Windows 10
   1606        * this workaround tries to disambiguate that by checking
   1607        * if the dwBuildNumber is from Windows 11 releases (>= 22000).
   1608        *
   1609        * This workaround replaces the ProductName key value
   1610        * from "Windows 10 *" to "Windows 11 *" */
   1611       if (os_info.dwMajorVersion == 10 &&
   1612           os_info.dwBuildNumber >= 22000 &&
   1613           product_name_w_size >= ARRAY_SIZE(L"Windows 10")) {
   1614         /* If ProductName starts with "Windows 10" */
   1615         if (wcsncmp(product_name_w, L"Windows 10", ARRAY_SIZE(L"Windows 10") - 1) == 0) {
   1616           /* Bump 10 to 11 */
   1617           product_name_w[9] = '1';
   1618         }
   1619       }
   1620 
   1621       version_size = sizeof(buffer->version);
   1622       r = uv__copy_utf16_to_utf8(product_name_w,
   1623                                  -1,
   1624                                  buffer->version,
   1625                                  &version_size);
   1626       if (r)
   1627         goto error;
   1628     }
   1629   }
   1630 
   1631   /* Append service pack information to the version if present. */
   1632   if (os_info.szCSDVersion[0] != L'\0') {
   1633     if (version_size > 0)
   1634       buffer->version[version_size++] = ' ';
   1635 
   1636     version_size = sizeof(buffer->version) - version_size;
   1637     r = uv__copy_utf16_to_utf8(os_info.szCSDVersion,
   1638                                -1,
   1639                                buffer->version +
   1640                                  sizeof(buffer->version) - version_size,
   1641                                &version_size);
   1642     if (r)
   1643       goto error;
   1644   }
   1645 
   1646   /* Populate the sysname field. */
   1647 #ifdef __MINGW32__
   1648   r = snprintf(buffer->sysname,
   1649                sizeof(buffer->sysname),
   1650                "MINGW32_NT-%u.%u",
   1651                (unsigned int) os_info.dwMajorVersion,
   1652                (unsigned int) os_info.dwMinorVersion);
   1653   assert((size_t)r < sizeof(buffer->sysname));
   1654 #else
   1655   uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
   1656 #endif
   1657 
   1658   /* Populate the release field. */
   1659   r = snprintf(buffer->release,
   1660                sizeof(buffer->release),
   1661                "%d.%d.%d",
   1662                (unsigned int) os_info.dwMajorVersion,
   1663                (unsigned int) os_info.dwMinorVersion,
   1664                (unsigned int) os_info.dwBuildNumber);
   1665   assert((size_t)r < sizeof(buffer->release));
   1666 
   1667   /* Populate the machine field. */
   1668   GetSystemInfo(&system_info);
   1669 
   1670   switch (system_info.wProcessorArchitecture) {
   1671     case PROCESSOR_ARCHITECTURE_AMD64:
   1672       uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
   1673       break;
   1674     case PROCESSOR_ARCHITECTURE_IA64:
   1675       uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
   1676       break;
   1677     case PROCESSOR_ARCHITECTURE_INTEL:
   1678       uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
   1679 
   1680       if (system_info.wProcessorLevel > 3) {
   1681         processor_level = system_info.wProcessorLevel < 6 ?
   1682                           system_info.wProcessorLevel : 6;
   1683         buffer->machine[1] = '0' + processor_level;
   1684       }
   1685 
   1686       break;
   1687     case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
   1688       uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
   1689       break;
   1690     case PROCESSOR_ARCHITECTURE_MIPS:
   1691       uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
   1692       break;
   1693     case PROCESSOR_ARCHITECTURE_ALPHA:
   1694     case PROCESSOR_ARCHITECTURE_ALPHA64:
   1695       uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
   1696       break;
   1697     case PROCESSOR_ARCHITECTURE_PPC:
   1698       uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
   1699       break;
   1700     case PROCESSOR_ARCHITECTURE_SHX:
   1701       uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
   1702       break;
   1703     case PROCESSOR_ARCHITECTURE_ARM:
   1704       uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
   1705       break;
   1706     default:
   1707       uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
   1708       break;
   1709   }
   1710 
   1711   return 0;
   1712 
   1713 error:
   1714   buffer->sysname[0] = '\0';
   1715   buffer->release[0] = '\0';
   1716   buffer->version[0] = '\0';
   1717   buffer->machine[0] = '\0';
   1718   return r;
   1719 }
   1720 
   1721 int uv_gettimeofday(uv_timeval64_t* tv) {
   1722   /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
   1723   const uint64_t epoch = (uint64_t) 116444736000000000ULL;
   1724   FILETIME file_time;
   1725   ULARGE_INTEGER ularge;
   1726 
   1727   if (tv == NULL)
   1728     return UV_EINVAL;
   1729 
   1730   GetSystemTimeAsFileTime(&file_time);
   1731   ularge.LowPart = file_time.dwLowDateTime;
   1732   ularge.HighPart = file_time.dwHighDateTime;
   1733   tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
   1734   tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
   1735   return 0;
   1736 }
   1737 
   1738 int uv__random_rtlgenrandom(void* buf, size_t buflen) {
   1739   if (buflen == 0)
   1740     return 0;
   1741 
   1742   if (SystemFunction036(buf, buflen) == FALSE)
   1743     return UV_EIO;
   1744 
   1745   return 0;
   1746 }
   1747 
   1748 void uv_sleep(unsigned int msec) {
   1749   Sleep(msec);
   1750 }
   1751