xref: /libuv/src/win/util.c (revision c6d43bea)
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  */
uv__util_init(void)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 
uv_exepath(char * buffer,size_t * size_ptr)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 
uv__cwd(WCHAR ** buf,DWORD * len)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 
uv_cwd(char * buffer,size_t * size)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 
uv_chdir(const char * dir)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 
uv_loadavg(double avg[3])273 void uv_loadavg(double avg[3]) {
274   /* Can't be implemented */
275   avg[0] = avg[1] = avg[2] = 0;
276 }
277 
278 
uv_get_free_memory(void)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 
uv_get_total_memory(void)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 
uv_get_constrained_memory(void)303 uint64_t uv_get_constrained_memory(void) {
304   return 0;  /* Memory constraints are unknown. */
305 }
306 
307 
uv_get_available_memory(void)308 uint64_t uv_get_available_memory(void) {
309   return uv_get_free_memory();
310 }
311 
312 
uv_os_getpid(void)313 uv_pid_t uv_os_getpid(void) {
314   return GetCurrentProcessId();
315 }
316 
317 
uv_os_getppid(void)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 
uv_setup_args(int argc,char ** argv)335 char** uv_setup_args(int argc, char** argv) {
336   return argv;
337 }
338 
339 
uv__process_title_cleanup(void)340 void uv__process_title_cleanup(void) {
341 }
342 
343 
uv_set_process_title(const char * title)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 
uv__get_process_title(void)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 
uv_get_process_title(char * buffer,size_t size)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 */
uv_clock_gettime(uv_clock_id clock_id,uv_timespec64_t * ts)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 
uv_hrtime(void)458 uint64_t uv_hrtime(void) {
459   uv__once_init();
460   return uv__hrtime(UV__NANOSEC);
461 }
462 
463 
uv__hrtime(unsigned int scale)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 
uv_resident_set_memory(size_t * rss)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 
uv_uptime(double * uptime)502 int uv_uptime(double* uptime) {
503   *uptime = GetTickCount64() / 1000.0;
504   return 0;
505 }
506 
507 
uv_available_parallelism(void)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 
uv_cpu_info(uv_cpu_info_t ** cpu_infos_ptr,int * cpu_count_ptr)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 
uv_interface_addresses(uv_interface_address_t ** addresses_ptr,int * count_ptr)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 
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)870 void uv_free_interface_addresses(uv_interface_address_t* addresses,
871     int count) {
872   uv__free(addresses);
873 }
874 
875 
uv_getrusage(uv_rusage_t * uv_rusage)876 int uv_getrusage(uv_rusage_t *uv_rusage) {
877   FILETIME createTime, exitTime, kernelTime, userTime;
878   SYSTEMTIME kernelSystemTime, userSystemTime;
879   PROCESS_MEMORY_COUNTERS memCounters;
880   IO_COUNTERS ioCounters;
881   int ret;
882 
883   ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
884   if (ret == 0) {
885     return uv_translate_sys_error(GetLastError());
886   }
887 
888   ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
889   if (ret == 0) {
890     return uv_translate_sys_error(GetLastError());
891   }
892 
893   ret = FileTimeToSystemTime(&userTime, &userSystemTime);
894   if (ret == 0) {
895     return uv_translate_sys_error(GetLastError());
896   }
897 
898   ret = GetProcessMemoryInfo(GetCurrentProcess(),
899                              &memCounters,
900                              sizeof(memCounters));
901   if (ret == 0) {
902     return uv_translate_sys_error(GetLastError());
903   }
904 
905   ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
906   if (ret == 0) {
907     return uv_translate_sys_error(GetLastError());
908   }
909 
910   memset(uv_rusage, 0, sizeof(*uv_rusage));
911 
912   uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
913                                userSystemTime.wMinute * 60 +
914                                userSystemTime.wSecond;
915   uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
916 
917   uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
918                                kernelSystemTime.wMinute * 60 +
919                                kernelSystemTime.wSecond;
920   uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
921 
922   uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
923   uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
924 
925   uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
926   uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
927 
928   return 0;
929 }
930 
931 
uv_os_homedir(char * buffer,size_t * size)932 int uv_os_homedir(char* buffer, size_t* size) {
933   uv_passwd_t pwd;
934   size_t len;
935   int r;
936 
937   /* Check if the USERPROFILE environment variable is set first. The task of
938      performing input validation on buffer and size is taken care of by
939      uv_os_getenv(). */
940   r = uv_os_getenv("USERPROFILE", buffer, size);
941 
942   /* Don't return an error if USERPROFILE was not found. */
943   if (r != UV_ENOENT) {
944     /* USERPROFILE is empty or invalid */
945     if (r == 0 && *size < 3) {
946       return UV_ENOENT;
947     }
948     return r;
949   }
950 
951   /* USERPROFILE is not set, so call uv_os_get_passwd() */
952   r = uv_os_get_passwd(&pwd);
953 
954   if (r != 0) {
955     return r;
956   }
957 
958   len = strlen(pwd.homedir);
959 
960   if (len >= *size) {
961     *size = len + 1;
962     uv_os_free_passwd(&pwd);
963     return UV_ENOBUFS;
964   }
965 
966   memcpy(buffer, pwd.homedir, len + 1);
967   *size = len;
968   uv_os_free_passwd(&pwd);
969 
970   return 0;
971 }
972 
973 
uv_os_tmpdir(char * buffer,size_t * size)974 int uv_os_tmpdir(char* buffer, size_t* size) {
975   wchar_t *path;
976   size_t len;
977 
978   if (buffer == NULL || size == NULL || *size == 0)
979     return UV_EINVAL;
980 
981   len = 0;
982   len = GetTempPathW(0, NULL);
983   if (len == 0) {
984     return uv_translate_sys_error(GetLastError());
985   }
986 
987   /* tmp path is empty or invalid */
988   if (len < 3) {
989     return UV_ENOENT;
990   }
991 
992   /* Include space for terminating null char. */
993   len += 1;
994   path = uv__malloc(len * sizeof(wchar_t));
995   if (path == NULL) {
996     return UV_ENOMEM;
997   }
998   len = GetTempPathW(len, path);
999 
1000   if (len == 0) {
1001     uv__free(path);
1002     return uv_translate_sys_error(GetLastError());
1003   }
1004 
1005   /* The returned directory should not have a trailing slash, unless it points
1006    * at a drive root, like c:\. Remove it if needed. */
1007   if (path[len - 1] == L'\\' &&
1008       !(len == 3 && path[1] == L':')) {
1009     len--;
1010     path[len] = L'\0';
1011   }
1012 
1013   return uv__copy_utf16_to_utf8(path, len, buffer, size);
1014 }
1015 
1016 
1017 /*
1018  * Converts a UTF-16 string into a UTF-8 one. The resulting string is
1019  * null-terminated.
1020  *
1021  * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
1022  * be specified.
1023  */
uv__convert_utf16_to_utf8(const WCHAR * utf16,size_t utf16len,char ** utf8)1024 int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8) {
1025   size_t utf8_len = 0;
1026 
1027   if (utf16 == NULL)
1028     return UV_EINVAL;
1029 
1030    *utf8 = NULL;
1031    return uv_utf16_to_wtf8(utf16, utf16len, utf8, &utf8_len);
1032 }
1033 
1034 
1035 /*
1036  * Converts a UTF-8 string into a UTF-16 one. The resulting string is
1037  * null-terminated.
1038  */
uv__convert_utf8_to_utf16(const char * utf8,WCHAR ** utf16)1039 int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16) {
1040   int bufsize;
1041 
1042   if (utf8 == NULL)
1043     return UV_EINVAL;
1044 
1045   /* Check how much space we need (including NUL). */
1046   bufsize = uv_wtf8_length_as_utf16(utf8);
1047   if (bufsize < 0)
1048     return UV__EINVAL;
1049 
1050   /* Allocate the destination buffer. */
1051   *utf16 = uv__malloc(sizeof(WCHAR) * bufsize);
1052 
1053   if (*utf16 == NULL)
1054     return UV_ENOMEM;
1055 
1056   /* Convert to UTF-16 */
1057   uv_wtf8_to_utf16(utf8, *utf16, bufsize);
1058 
1059   return 0;
1060 }
1061 
1062 
1063 /*
1064  * Converts a UTF-16 string into a UTF-8 one in an existing buffer. The
1065  * resulting string is null-terminated.
1066  *
1067  * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
1068  * be specified.
1069  */
uv__copy_utf16_to_utf8(const WCHAR * utf16buffer,size_t utf16len,char * utf8,size_t * size)1070 int uv__copy_utf16_to_utf8(const WCHAR* utf16buffer, size_t utf16len, char* utf8, size_t *size) {
1071   int r;
1072 
1073   if (utf8 == NULL || size == NULL)
1074     return UV_EINVAL;
1075 
1076   if (*size == 0) {
1077     *size = uv_utf16_length_as_wtf8(utf16buffer, utf16len);
1078     r = UV_ENOBUFS;
1079   } else {
1080     *size -= 1; /* Reserve space for NUL. */
1081     r = uv_utf16_to_wtf8(utf16buffer, utf16len, &utf8, size);
1082   }
1083   if (r == UV_ENOBUFS)
1084     *size += 1; /* Add space for NUL. */
1085   return r;
1086 }
1087 
1088 
uv__getpwuid_r(uv_passwd_t * pwd)1089 static int uv__getpwuid_r(uv_passwd_t* pwd) {
1090   HANDLE token;
1091   wchar_t username[UNLEN + 1];
1092   wchar_t *path;
1093   DWORD bufsize;
1094   int r;
1095 
1096   if (pwd == NULL)
1097     return UV_EINVAL;
1098 
1099   /* Get the home directory using GetUserProfileDirectoryW() */
1100   if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
1101     return uv_translate_sys_error(GetLastError());
1102 
1103   bufsize = 0;
1104   GetUserProfileDirectoryW(token, NULL, &bufsize);
1105   if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1106     r = GetLastError();
1107     CloseHandle(token);
1108     return uv_translate_sys_error(r);
1109   }
1110 
1111   path = uv__malloc(bufsize * sizeof(wchar_t));
1112   if (path == NULL) {
1113     CloseHandle(token);
1114     return UV_ENOMEM;
1115   }
1116 
1117   if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
1118     r = GetLastError();
1119     CloseHandle(token);
1120     uv__free(path);
1121     return uv_translate_sys_error(r);
1122   }
1123 
1124   CloseHandle(token);
1125 
1126   /* Get the username using GetUserNameW() */
1127   bufsize = ARRAY_SIZE(username);
1128   if (!GetUserNameW(username, &bufsize)) {
1129     r = GetLastError();
1130     uv__free(path);
1131 
1132     /* This should not be possible */
1133     if (r == ERROR_INSUFFICIENT_BUFFER)
1134       return UV_ENOMEM;
1135 
1136     return uv_translate_sys_error(r);
1137   }
1138 
1139   pwd->homedir = NULL;
1140   r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
1141   uv__free(path);
1142 
1143   if (r != 0)
1144     return r;
1145 
1146   pwd->username = NULL;
1147   r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
1148 
1149   if (r != 0) {
1150     uv__free(pwd->homedir);
1151     return r;
1152   }
1153 
1154   pwd->shell = NULL;
1155   pwd->uid = -1;
1156   pwd->gid = -1;
1157 
1158   return 0;
1159 }
1160 
1161 
uv_os_get_passwd(uv_passwd_t * pwd)1162 int uv_os_get_passwd(uv_passwd_t* pwd) {
1163   return uv__getpwuid_r(pwd);
1164 }
1165 
1166 
uv_os_get_passwd2(uv_passwd_t * pwd,uv_uid_t uid)1167 int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
1168   return UV_ENOTSUP;
1169 }
1170 
1171 
uv_os_get_group(uv_group_t * grp,uv_uid_t gid)1172 int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
1173   return UV_ENOTSUP;
1174 }
1175 
1176 
uv_os_environ(uv_env_item_t ** envitems,int * count)1177 int uv_os_environ(uv_env_item_t** envitems, int* count) {
1178   wchar_t* env;
1179   wchar_t* penv;
1180   int i, cnt;
1181   uv_env_item_t* envitem;
1182 
1183   *envitems = NULL;
1184   *count = 0;
1185 
1186   env = GetEnvironmentStringsW();
1187   if (env == NULL)
1188     return 0;
1189 
1190   for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
1191 
1192   *envitems = uv__calloc(i, sizeof(**envitems));
1193   if (*envitems == NULL) {
1194     FreeEnvironmentStringsW(env);
1195     return UV_ENOMEM;
1196   }
1197 
1198   penv = env;
1199   cnt = 0;
1200 
1201   while (*penv != L'\0' && cnt < i) {
1202     char* buf;
1203     char* ptr;
1204 
1205     if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
1206       goto fail;
1207 
1208     /* Using buf + 1 here because we know that `buf` has length at least 1,
1209      * and some special environment variables on Windows start with a = sign. */
1210     ptr = strchr(buf + 1, '=');
1211     if (ptr == NULL) {
1212       uv__free(buf);
1213       goto do_continue;
1214     }
1215 
1216     *ptr = '\0';
1217 
1218     envitem = &(*envitems)[cnt];
1219     envitem->name = buf;
1220     envitem->value = ptr + 1;
1221 
1222     cnt++;
1223 
1224   do_continue:
1225     penv += wcslen(penv) + 1;
1226   }
1227 
1228   FreeEnvironmentStringsW(env);
1229 
1230   *count = cnt;
1231   return 0;
1232 
1233 fail:
1234   FreeEnvironmentStringsW(env);
1235 
1236   for (i = 0; i < cnt; i++) {
1237     envitem = &(*envitems)[cnt];
1238     uv__free(envitem->name);
1239   }
1240   uv__free(*envitems);
1241 
1242   *envitems = NULL;
1243   *count = 0;
1244   return UV_ENOMEM;
1245 }
1246 
1247 
uv_os_getenv(const char * name,char * buffer,size_t * size)1248 int uv_os_getenv(const char* name, char* buffer, size_t* size) {
1249   wchar_t fastvar[512];
1250   wchar_t* var;
1251   DWORD varlen;
1252   wchar_t* name_w;
1253   size_t len;
1254   int r;
1255 
1256   if (name == NULL || buffer == NULL || size == NULL || *size == 0)
1257     return UV_EINVAL;
1258 
1259   r = uv__convert_utf8_to_utf16(name, &name_w);
1260 
1261   if (r != 0)
1262     return r;
1263 
1264   var = fastvar;
1265   varlen = ARRAY_SIZE(fastvar);
1266 
1267   for (;;) {
1268     SetLastError(ERROR_SUCCESS);
1269     len = GetEnvironmentVariableW(name_w, var, varlen);
1270 
1271     if (len == 0)
1272       r = uv_translate_sys_error(GetLastError());
1273 
1274     if (len < varlen)
1275       break;
1276 
1277     /* Try repeatedly because we might have been preempted by another thread
1278      * modifying the environment variable just as we're trying to read it.
1279      */
1280     if (var != fastvar)
1281       uv__free(var);
1282 
1283     varlen = 1 + len;
1284     var = uv__malloc(varlen * sizeof(*var));
1285 
1286     if (var == NULL) {
1287       r = UV_ENOMEM;
1288       goto fail;
1289     }
1290   }
1291 
1292   uv__free(name_w);
1293   name_w = NULL;
1294 
1295   if (r == 0)
1296     r = uv__copy_utf16_to_utf8(var, len, buffer, size);
1297 
1298 fail:
1299 
1300   if (name_w != NULL)
1301     uv__free(name_w);
1302 
1303   if (var != fastvar)
1304     uv__free(var);
1305 
1306   return r;
1307 }
1308 
1309 
uv_os_setenv(const char * name,const char * value)1310 int uv_os_setenv(const char* name, const char* value) {
1311   wchar_t* name_w;
1312   wchar_t* value_w;
1313   int r;
1314 
1315   if (name == NULL || value == NULL)
1316     return UV_EINVAL;
1317 
1318   r = uv__convert_utf8_to_utf16(name, &name_w);
1319 
1320   if (r != 0)
1321     return r;
1322 
1323   r = uv__convert_utf8_to_utf16(value, &value_w);
1324 
1325   if (r != 0) {
1326     uv__free(name_w);
1327     return r;
1328   }
1329 
1330   r = SetEnvironmentVariableW(name_w, value_w);
1331   uv__free(name_w);
1332   uv__free(value_w);
1333 
1334   if (r == 0)
1335     return uv_translate_sys_error(GetLastError());
1336 
1337   return 0;
1338 }
1339 
1340 
uv_os_unsetenv(const char * name)1341 int uv_os_unsetenv(const char* name) {
1342   wchar_t* name_w;
1343   int r;
1344 
1345   if (name == NULL)
1346     return UV_EINVAL;
1347 
1348   r = uv__convert_utf8_to_utf16(name, &name_w);
1349 
1350   if (r != 0)
1351     return r;
1352 
1353   r = SetEnvironmentVariableW(name_w, NULL);
1354   uv__free(name_w);
1355 
1356   if (r == 0)
1357     return uv_translate_sys_error(GetLastError());
1358 
1359   return 0;
1360 }
1361 
1362 
uv_os_gethostname(char * buffer,size_t * size)1363 int uv_os_gethostname(char* buffer, size_t* size) {
1364   WCHAR buf[UV_MAXHOSTNAMESIZE];
1365 
1366   if (buffer == NULL || size == NULL || *size == 0)
1367     return UV_EINVAL;
1368 
1369   uv__once_init(); /* Initialize winsock */
1370 
1371   if (pGetHostNameW == NULL)
1372     return UV_ENOSYS;
1373 
1374   if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
1375     return uv_translate_sys_error(WSAGetLastError());
1376 
1377   return uv__copy_utf16_to_utf8(buf, -1, buffer, size);
1378 }
1379 
1380 
uv__get_handle(uv_pid_t pid,int access,HANDLE * handle)1381 static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
1382   int r;
1383 
1384   if (pid == 0)
1385     *handle = GetCurrentProcess();
1386   else
1387     *handle = OpenProcess(access, FALSE, pid);
1388 
1389   if (*handle == NULL) {
1390     r = GetLastError();
1391 
1392     if (r == ERROR_INVALID_PARAMETER)
1393       return UV_ESRCH;
1394     else
1395       return uv_translate_sys_error(r);
1396   }
1397 
1398   return 0;
1399 }
1400 
1401 
uv_os_getpriority(uv_pid_t pid,int * priority)1402 int uv_os_getpriority(uv_pid_t pid, int* priority) {
1403   HANDLE handle;
1404   int r;
1405 
1406   if (priority == NULL)
1407     return UV_EINVAL;
1408 
1409   r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
1410 
1411   if (r != 0)
1412     return r;
1413 
1414   r = GetPriorityClass(handle);
1415 
1416   if (r == 0) {
1417     r = uv_translate_sys_error(GetLastError());
1418   } else {
1419     /* Map Windows priority classes to Unix nice values. */
1420     if (r == REALTIME_PRIORITY_CLASS)
1421       *priority = UV_PRIORITY_HIGHEST;
1422     else if (r == HIGH_PRIORITY_CLASS)
1423       *priority = UV_PRIORITY_HIGH;
1424     else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
1425       *priority = UV_PRIORITY_ABOVE_NORMAL;
1426     else if (r == NORMAL_PRIORITY_CLASS)
1427       *priority = UV_PRIORITY_NORMAL;
1428     else if (r == BELOW_NORMAL_PRIORITY_CLASS)
1429       *priority = UV_PRIORITY_BELOW_NORMAL;
1430     else  /* IDLE_PRIORITY_CLASS */
1431       *priority = UV_PRIORITY_LOW;
1432 
1433     r = 0;
1434   }
1435 
1436   CloseHandle(handle);
1437   return r;
1438 }
1439 
1440 
uv_os_setpriority(uv_pid_t pid,int priority)1441 int uv_os_setpriority(uv_pid_t pid, int priority) {
1442   HANDLE handle;
1443   int priority_class;
1444   int r;
1445 
1446   /* Map Unix nice values to Windows priority classes. */
1447   if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
1448     return UV_EINVAL;
1449   else if (priority < UV_PRIORITY_HIGH)
1450     priority_class = REALTIME_PRIORITY_CLASS;
1451   else if (priority < UV_PRIORITY_ABOVE_NORMAL)
1452     priority_class = HIGH_PRIORITY_CLASS;
1453   else if (priority < UV_PRIORITY_NORMAL)
1454     priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
1455   else if (priority < UV_PRIORITY_BELOW_NORMAL)
1456     priority_class = NORMAL_PRIORITY_CLASS;
1457   else if (priority < UV_PRIORITY_LOW)
1458     priority_class = BELOW_NORMAL_PRIORITY_CLASS;
1459   else
1460     priority_class = IDLE_PRIORITY_CLASS;
1461 
1462   r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
1463 
1464   if (r != 0)
1465     return r;
1466 
1467   if (SetPriorityClass(handle, priority_class) == 0)
1468     r = uv_translate_sys_error(GetLastError());
1469 
1470   CloseHandle(handle);
1471   return r;
1472 }
1473 
uv_thread_getpriority(uv_thread_t tid,int * priority)1474 int uv_thread_getpriority(uv_thread_t tid, int* priority) {
1475   int r;
1476 
1477   if (priority == NULL)
1478     return UV_EINVAL;
1479 
1480   r = GetThreadPriority(tid);
1481   if (r == THREAD_PRIORITY_ERROR_RETURN)
1482     return uv_translate_sys_error(GetLastError());
1483 
1484   *priority = r;
1485   return 0;
1486 }
1487 
uv_thread_setpriority(uv_thread_t tid,int priority)1488 int uv_thread_setpriority(uv_thread_t tid, int priority) {
1489   int r;
1490 
1491   switch (priority) {
1492     case UV_THREAD_PRIORITY_HIGHEST:
1493       r = SetThreadPriority(tid, THREAD_PRIORITY_HIGHEST);
1494       break;
1495     case UV_THREAD_PRIORITY_ABOVE_NORMAL:
1496       r = SetThreadPriority(tid, THREAD_PRIORITY_ABOVE_NORMAL);
1497       break;
1498     case UV_THREAD_PRIORITY_NORMAL:
1499       r = SetThreadPriority(tid, THREAD_PRIORITY_NORMAL);
1500       break;
1501     case UV_THREAD_PRIORITY_BELOW_NORMAL:
1502       r = SetThreadPriority(tid, THREAD_PRIORITY_BELOW_NORMAL);
1503       break;
1504     case UV_THREAD_PRIORITY_LOWEST:
1505       r = SetThreadPriority(tid, THREAD_PRIORITY_LOWEST);
1506       break;
1507     default:
1508       return 0;
1509   }
1510 
1511   if (r == 0)
1512     return uv_translate_sys_error(GetLastError());
1513 
1514   return 0;
1515 }
1516 
uv_os_uname(uv_utsname_t * buffer)1517 int uv_os_uname(uv_utsname_t* buffer) {
1518   /* Implementation loosely based on
1519      https://github.com/gagern/gnulib/blob/master/lib/uname.c */
1520   OSVERSIONINFOW os_info;
1521   SYSTEM_INFO system_info;
1522   HKEY registry_key;
1523   WCHAR product_name_w[256];
1524   DWORD product_name_w_size;
1525   size_t version_size;
1526   int processor_level;
1527   int r;
1528 
1529   if (buffer == NULL)
1530     return UV_EINVAL;
1531 
1532   uv__once_init();
1533   os_info.dwOSVersionInfoSize = sizeof(os_info);
1534   os_info.szCSDVersion[0] = L'\0';
1535 
1536   pRtlGetVersion(&os_info);
1537 
1538   /* Populate the version field. */
1539   version_size = 0;
1540   r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1541                     L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
1542                     0,
1543                     KEY_QUERY_VALUE | KEY_WOW64_64KEY,
1544                     &registry_key);
1545 
1546   if (r == ERROR_SUCCESS) {
1547     product_name_w_size = sizeof(product_name_w);
1548     r = RegGetValueW(registry_key,
1549                      NULL,
1550                      L"ProductName",
1551                      RRF_RT_REG_SZ,
1552                      NULL,
1553                      (PVOID) product_name_w,
1554                      &product_name_w_size);
1555     RegCloseKey(registry_key);
1556 
1557     if (r == ERROR_SUCCESS) {
1558       /* Windows 11 shares dwMajorVersion with Windows 10
1559        * this workaround tries to disambiguate that by checking
1560        * if the dwBuildNumber is from Windows 11 releases (>= 22000).
1561        *
1562        * This workaround replaces the ProductName key value
1563        * from "Windows 10 *" to "Windows 11 *" */
1564       if (os_info.dwMajorVersion == 10 &&
1565           os_info.dwBuildNumber >= 22000 &&
1566           product_name_w_size >= ARRAY_SIZE(L"Windows 10")) {
1567         /* If ProductName starts with "Windows 10" */
1568         if (wcsncmp(product_name_w, L"Windows 10", ARRAY_SIZE(L"Windows 10") - 1) == 0) {
1569           /* Bump 10 to 11 */
1570           product_name_w[9] = '1';
1571         }
1572       }
1573 
1574       version_size = sizeof(buffer->version);
1575       r = uv__copy_utf16_to_utf8(product_name_w,
1576                                  -1,
1577                                  buffer->version,
1578                                  &version_size);
1579       if (r)
1580         goto error;
1581     }
1582   }
1583 
1584   /* Append service pack information to the version if present. */
1585   if (os_info.szCSDVersion[0] != L'\0') {
1586     if (version_size > 0)
1587       buffer->version[version_size++] = ' ';
1588 
1589     version_size = sizeof(buffer->version) - version_size;
1590     r = uv__copy_utf16_to_utf8(os_info.szCSDVersion,
1591                                -1,
1592                                buffer->version +
1593                                  sizeof(buffer->version) - version_size,
1594                                &version_size);
1595     if (r)
1596       goto error;
1597   }
1598 
1599   /* Populate the sysname field. */
1600 #ifdef __MINGW32__
1601   r = snprintf(buffer->sysname,
1602                sizeof(buffer->sysname),
1603                "MINGW32_NT-%u.%u",
1604                (unsigned int) os_info.dwMajorVersion,
1605                (unsigned int) os_info.dwMinorVersion);
1606   assert((size_t)r < sizeof(buffer->sysname));
1607 #else
1608   uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
1609 #endif
1610 
1611   /* Populate the release field. */
1612   r = snprintf(buffer->release,
1613                sizeof(buffer->release),
1614                "%d.%d.%d",
1615                (unsigned int) os_info.dwMajorVersion,
1616                (unsigned int) os_info.dwMinorVersion,
1617                (unsigned int) os_info.dwBuildNumber);
1618   assert((size_t)r < sizeof(buffer->release));
1619 
1620   /* Populate the machine field. */
1621   GetSystemInfo(&system_info);
1622 
1623   switch (system_info.wProcessorArchitecture) {
1624     case PROCESSOR_ARCHITECTURE_AMD64:
1625       uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
1626       break;
1627     case PROCESSOR_ARCHITECTURE_IA64:
1628       uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
1629       break;
1630     case PROCESSOR_ARCHITECTURE_INTEL:
1631       uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
1632 
1633       if (system_info.wProcessorLevel > 3) {
1634         processor_level = system_info.wProcessorLevel < 6 ?
1635                           system_info.wProcessorLevel : 6;
1636         buffer->machine[1] = '0' + processor_level;
1637       }
1638 
1639       break;
1640     case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1641       uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
1642       break;
1643     case PROCESSOR_ARCHITECTURE_MIPS:
1644       uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
1645       break;
1646     case PROCESSOR_ARCHITECTURE_ALPHA:
1647     case PROCESSOR_ARCHITECTURE_ALPHA64:
1648       uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
1649       break;
1650     case PROCESSOR_ARCHITECTURE_PPC:
1651       uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
1652       break;
1653     case PROCESSOR_ARCHITECTURE_SHX:
1654       uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
1655       break;
1656     case PROCESSOR_ARCHITECTURE_ARM:
1657       uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
1658       break;
1659     default:
1660       uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
1661       break;
1662   }
1663 
1664   return 0;
1665 
1666 error:
1667   buffer->sysname[0] = '\0';
1668   buffer->release[0] = '\0';
1669   buffer->version[0] = '\0';
1670   buffer->machine[0] = '\0';
1671   return r;
1672 }
1673 
uv_gettimeofday(uv_timeval64_t * tv)1674 int uv_gettimeofday(uv_timeval64_t* tv) {
1675   /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
1676   const uint64_t epoch = (uint64_t) 116444736000000000ULL;
1677   FILETIME file_time;
1678   ULARGE_INTEGER ularge;
1679 
1680   if (tv == NULL)
1681     return UV_EINVAL;
1682 
1683   GetSystemTimeAsFileTime(&file_time);
1684   ularge.LowPart = file_time.dwLowDateTime;
1685   ularge.HighPart = file_time.dwHighDateTime;
1686   tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
1687   tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
1688   return 0;
1689 }
1690 
uv__random_rtlgenrandom(void * buf,size_t buflen)1691 int uv__random_rtlgenrandom(void* buf, size_t buflen) {
1692   if (buflen == 0)
1693     return 0;
1694 
1695   if (SystemFunction036(buf, buflen) == FALSE)
1696     return UV_EIO;
1697 
1698   return 0;
1699 }
1700 
uv_sleep(unsigned int msec)1701 void uv_sleep(unsigned int msec) {
1702   Sleep(msec);
1703 }
1704