xref: /libuv/src/win/util.c (revision 46c0e176)
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) {
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   int parent_pid = -1;
320   HANDLE handle;
321   PROCESSENTRY32 pe;
322   DWORD current_pid = GetCurrentProcessId();
323 
324   pe.dwSize = sizeof(PROCESSENTRY32);
325   handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
326 
327   if (Process32First(handle, &pe)) {
328     do {
329       if (pe.th32ProcessID == current_pid) {
330         parent_pid = pe.th32ParentProcessID;
331         break;
332       }
333     } while( Process32Next(handle, &pe));
334   }
335 
336   CloseHandle(handle);
337   return parent_pid;
338 }
339 
340 
uv_setup_args(int argc,char ** argv)341 char** uv_setup_args(int argc, char** argv) {
342   return argv;
343 }
344 
345 
uv__process_title_cleanup(void)346 void uv__process_title_cleanup(void) {
347 }
348 
349 
uv_set_process_title(const char * title)350 int uv_set_process_title(const char* title) {
351   int err;
352   int length;
353   WCHAR* title_w = NULL;
354 
355   uv__once_init();
356 
357   err = uv__convert_utf8_to_utf16(title, &title_w);
358   if (err)
359     return err;
360 
361   /* If the title must be truncated insert a \0 terminator there */
362   length = wcslen(title_w);
363   if (length >= MAX_TITLE_LENGTH)
364     title_w[MAX_TITLE_LENGTH - 1] = L'\0';
365 
366   if (!SetConsoleTitleW(title_w)) {
367     err = GetLastError();
368     goto done;
369   }
370 
371   EnterCriticalSection(&process_title_lock);
372   uv__free(process_title);
373   process_title = uv__strdup(title);
374   LeaveCriticalSection(&process_title_lock);
375 
376   err = 0;
377 
378 done:
379   uv__free(title_w);
380   return uv_translate_sys_error(err);
381 }
382 
383 
uv__get_process_title(void)384 static int uv__get_process_title(void) {
385   WCHAR title_w[MAX_TITLE_LENGTH];
386   DWORD wlen;
387 
388   wlen = GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR));
389   if (wlen == 0)
390     return uv_translate_sys_error(GetLastError());
391 
392   return uv__convert_utf16_to_utf8(title_w, wlen, &process_title);
393 }
394 
395 
uv_get_process_title(char * buffer,size_t size)396 int uv_get_process_title(char* buffer, size_t size) {
397   size_t len;
398   int r;
399 
400   if (buffer == NULL || size == 0)
401     return UV_EINVAL;
402 
403   uv__once_init();
404 
405   EnterCriticalSection(&process_title_lock);
406   /*
407    * If the process_title was never read before nor explicitly set,
408    * we must query it with getConsoleTitleW
409    */
410   if (process_title == NULL) {
411     r = uv__get_process_title();
412     if (r) {
413       LeaveCriticalSection(&process_title_lock);
414       return r;
415     }
416   }
417 
418   assert(process_title);
419   len = strlen(process_title) + 1;
420 
421   if (size < len) {
422     LeaveCriticalSection(&process_title_lock);
423     return UV_ENOBUFS;
424   }
425 
426   memcpy(buffer, process_title, len);
427   LeaveCriticalSection(&process_title_lock);
428 
429   return 0;
430 }
431 
432 
433 /* https://github.com/libuv/libuv/issues/1674 */
uv_clock_gettime(uv_clock_id clock_id,uv_timespec64_t * ts)434 int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) {
435   FILETIME ft;
436   int64_t t;
437 
438   if (ts == NULL)
439     return UV_EFAULT;
440 
441   switch (clock_id) {
442     case UV_CLOCK_MONOTONIC:
443       uv__once_init();
444       t = uv__hrtime(UV__NANOSEC);
445       ts->tv_sec = t / 1000000000;
446       ts->tv_nsec = t % 1000000000;
447       return 0;
448     case UV_CLOCK_REALTIME:
449       GetSystemTimePreciseAsFileTime(&ft);
450       /* In 100-nanosecond increments from 1601-01-01 UTC because why not? */
451       t = (int64_t) ft.dwHighDateTime << 32 | ft.dwLowDateTime;
452       /* Convert to UNIX epoch, 1970-01-01. Still in 100 ns increments. */
453       t -= 116444736000000000ll;
454       /* Now convert to seconds and nanoseconds. */
455       ts->tv_sec = t / 10000000;
456       ts->tv_nsec = t % 10000000 * 100;
457       return 0;
458   }
459 
460   return UV_EINVAL;
461 }
462 
463 
uv_hrtime(void)464 uint64_t uv_hrtime(void) {
465   uv__once_init();
466   return uv__hrtime(UV__NANOSEC);
467 }
468 
469 
uv__hrtime(unsigned int scale)470 uint64_t uv__hrtime(unsigned int scale) {
471   LARGE_INTEGER counter;
472   double scaled_freq;
473   double result;
474 
475   assert(hrtime_frequency_ != 0);
476   assert(scale != 0);
477   if (!QueryPerformanceCounter(&counter)) {
478     uv_fatal_error(GetLastError(), "QueryPerformanceCounter");
479   }
480   assert(counter.QuadPart != 0);
481 
482   /* Because we have no guarantee about the order of magnitude of the
483    * performance counter interval, integer math could cause this computation
484    * to overflow. Therefore we resort to floating point math.
485    */
486   scaled_freq = (double) hrtime_frequency_ / scale;
487   result = (double) counter.QuadPart / scaled_freq;
488   return (uint64_t) result;
489 }
490 
491 
uv_resident_set_memory(size_t * rss)492 int uv_resident_set_memory(size_t* rss) {
493   HANDLE current_process;
494   PROCESS_MEMORY_COUNTERS pmc;
495 
496   current_process = GetCurrentProcess();
497 
498   if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
499     return uv_translate_sys_error(GetLastError());
500   }
501 
502   *rss = pmc.WorkingSetSize;
503 
504   return 0;
505 }
506 
507 
uv_uptime(double * uptime)508 int uv_uptime(double* uptime) {
509   *uptime = GetTickCount64() / 1000.0;
510   return 0;
511 }
512 
513 
uv_available_parallelism(void)514 unsigned int uv_available_parallelism(void) {
515   SYSTEM_INFO info;
516   unsigned rc;
517 
518   /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
519    * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
520    */
521   GetSystemInfo(&info);
522 
523   rc = info.dwNumberOfProcessors;
524   if (rc < 1)
525     rc = 1;
526 
527   return rc;
528 }
529 
530 
uv_cpu_info(uv_cpu_info_t ** cpu_infos_ptr,int * cpu_count_ptr)531 int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
532   uv_cpu_info_t* cpu_infos;
533   SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
534   DWORD sppi_size;
535   SYSTEM_INFO system_info;
536   DWORD cpu_count, i;
537   NTSTATUS status;
538   ULONG result_size;
539   int err;
540   uv_cpu_info_t* cpu_info;
541 
542   cpu_infos = NULL;
543   cpu_count = 0;
544   sppi = NULL;
545 
546   uv__once_init();
547 
548   GetSystemInfo(&system_info);
549   cpu_count = system_info.dwNumberOfProcessors;
550 
551   cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
552   if (cpu_infos == NULL) {
553     err = ERROR_OUTOFMEMORY;
554     goto error;
555   }
556 
557   sppi_size = cpu_count * sizeof(*sppi);
558   sppi = uv__malloc(sppi_size);
559   if (sppi == NULL) {
560     err = ERROR_OUTOFMEMORY;
561     goto error;
562   }
563 
564   status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
565                                      sppi,
566                                      sppi_size,
567                                      &result_size);
568   if (!NT_SUCCESS(status)) {
569     err = pRtlNtStatusToDosError(status);
570     goto error;
571   }
572 
573   assert(result_size == sppi_size);
574 
575   for (i = 0; i < cpu_count; i++) {
576     WCHAR key_name[128];
577     HKEY processor_key;
578     DWORD cpu_speed;
579     DWORD cpu_speed_size = sizeof(cpu_speed);
580     WCHAR cpu_brand[256];
581     DWORD cpu_brand_size = sizeof(cpu_brand);
582     size_t len;
583 
584     len = _snwprintf(key_name,
585                      ARRAY_SIZE(key_name),
586                      L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
587                      i);
588 
589     assert(len > 0 && len < ARRAY_SIZE(key_name));
590 
591     err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
592                         key_name,
593                         0,
594                         KEY_QUERY_VALUE,
595                         &processor_key);
596     if (err != ERROR_SUCCESS) {
597       goto error;
598     }
599 
600     err = RegQueryValueExW(processor_key,
601                            L"~MHz",
602                            NULL,
603                            NULL,
604                            (BYTE*)&cpu_speed,
605                            &cpu_speed_size);
606     if (err != ERROR_SUCCESS) {
607       RegCloseKey(processor_key);
608       goto error;
609     }
610 
611     err = RegQueryValueExW(processor_key,
612                            L"ProcessorNameString",
613                            NULL,
614                            NULL,
615                            (BYTE*)&cpu_brand,
616                            &cpu_brand_size);
617     RegCloseKey(processor_key);
618     if (err != ERROR_SUCCESS)
619       goto error;
620 
621     cpu_info = &cpu_infos[i];
622     cpu_info->speed = cpu_speed;
623     cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
624     cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
625         sppi[i].IdleTime.QuadPart) / 10000;
626     cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
627     cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
628     cpu_info->cpu_times.nice = 0;
629 
630     uv__convert_utf16_to_utf8(cpu_brand,
631                               cpu_brand_size / sizeof(WCHAR),
632                               &(cpu_info->model));
633   }
634 
635   uv__free(sppi);
636 
637   *cpu_count_ptr = cpu_count;
638   *cpu_infos_ptr = cpu_infos;
639 
640   return 0;
641 
642  error:
643   if (cpu_infos != NULL) {
644     /* This is safe because the cpu_infos array is zeroed on allocation. */
645     for (i = 0; i < cpu_count; i++)
646       uv__free(cpu_infos[i].model);
647   }
648 
649   uv__free(cpu_infos);
650   uv__free(sppi);
651 
652   return uv_translate_sys_error(err);
653 }
654 
655 
uv_interface_addresses(uv_interface_address_t ** addresses_ptr,int * count_ptr)656 int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
657     int* count_ptr) {
658   IP_ADAPTER_ADDRESSES* win_address_buf;
659   ULONG win_address_buf_size;
660   IP_ADAPTER_ADDRESSES* adapter;
661 
662   uv_interface_address_t* uv_address_buf;
663   char* name_buf;
664   size_t uv_address_buf_size;
665   uv_interface_address_t* uv_address;
666 
667   int count;
668   ULONG flags;
669 
670   *addresses_ptr = NULL;
671   *count_ptr = 0;
672 
673   flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
674     GAA_FLAG_SKIP_DNS_SERVER;
675 
676   /* Fetch the size of the adapters reported by windows, and then get the list
677    * itself. */
678   win_address_buf_size = 0;
679   win_address_buf = NULL;
680 
681   for (;;) {
682     ULONG r;
683 
684     /* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
685      * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
686      * win_address_buf_size. */
687     r = GetAdaptersAddresses(AF_UNSPEC,
688                              flags,
689                              NULL,
690                              win_address_buf,
691                              &win_address_buf_size);
692 
693     if (r == ERROR_SUCCESS)
694       break;
695 
696     uv__free(win_address_buf);
697 
698     switch (r) {
699       case ERROR_BUFFER_OVERFLOW:
700         /* This happens when win_address_buf is NULL or too small to hold all
701          * adapters. */
702         win_address_buf = uv__malloc(win_address_buf_size);
703         if (win_address_buf == NULL)
704           return UV_ENOMEM;
705 
706         continue;
707 
708       case ERROR_NO_DATA: {
709         /* No adapters were found. */
710         uv_address_buf = uv__malloc(1);
711         if (uv_address_buf == NULL)
712           return UV_ENOMEM;
713 
714         *count_ptr = 0;
715         *addresses_ptr = uv_address_buf;
716 
717         return 0;
718       }
719 
720       case ERROR_ADDRESS_NOT_ASSOCIATED:
721         return UV_EAGAIN;
722 
723       case ERROR_INVALID_PARAMETER:
724         /* MSDN says:
725          *   "This error is returned for any of the following conditions: the
726          *   SizePointer parameter is NULL, the Address parameter is not
727          *   AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
728          *   the parameters requested is greater than ULONG_MAX."
729          * Since the first two conditions are not met, it must be that the
730          * adapter data is too big.
731          */
732         return UV_ENOBUFS;
733 
734       default:
735         /* Other (unspecified) errors can happen, but we don't have any special
736          * meaning for them. */
737         assert(r != ERROR_SUCCESS);
738         return uv_translate_sys_error(r);
739     }
740   }
741 
742   /* Count the number of enabled interfaces and compute how much space is
743    * needed to store their info. */
744   count = 0;
745   uv_address_buf_size = 0;
746 
747   for (adapter = win_address_buf;
748        adapter != NULL;
749        adapter = adapter->Next) {
750     IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
751     int name_size;
752 
753     /* Interfaces that are not 'up' should not be reported. Also skip
754      * interfaces that have no associated unicast address, as to avoid
755      * allocating space for the name for this interface. */
756     if (adapter->OperStatus != IfOperStatusUp ||
757         adapter->FirstUnicastAddress == NULL)
758       continue;
759 
760     /* Compute the size of the interface name. */
761     name_size = uv_utf16_length_as_wtf8(adapter->FriendlyName, -1);
762     uv_address_buf_size += name_size + 1;
763 
764     /* Count the number of addresses associated with this interface, and
765      * compute the size. */
766     for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
767                            adapter->FirstUnicastAddress;
768          unicast_address != NULL;
769          unicast_address = unicast_address->Next) {
770       count++;
771       uv_address_buf_size += sizeof(uv_interface_address_t);
772     }
773   }
774 
775   /* Allocate space to store interface data plus adapter names. */
776   uv_address_buf = uv__malloc(uv_address_buf_size);
777   if (uv_address_buf == NULL) {
778     uv__free(win_address_buf);
779     return UV_ENOMEM;
780   }
781 
782   /* Compute the start of the uv_interface_address_t array, and the place in
783    * the buffer where the interface names will be stored. */
784   uv_address = uv_address_buf;
785   name_buf = (char*) (uv_address_buf + count);
786 
787   /* Fill out the output buffer. */
788   for (adapter = win_address_buf;
789        adapter != NULL;
790        adapter = adapter->Next) {
791     IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
792     size_t name_size;
793     int r;
794 
795     if (adapter->OperStatus != IfOperStatusUp ||
796         adapter->FirstUnicastAddress == NULL)
797       continue;
798 
799     /* Convert the interface name to UTF8. */
800     name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
801     r = uv__copy_utf16_to_utf8(adapter->FriendlyName,
802                                -1,
803                                name_buf,
804                                &name_size);
805     if (r) {
806       uv__free(win_address_buf);
807       uv__free(uv_address_buf);
808       return r;
809     }
810     name_size += 1; /* Add NUL byte. */
811 
812     /* Add an uv_interface_address_t element for every unicast address. */
813     for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
814                            adapter->FirstUnicastAddress;
815          unicast_address != NULL;
816          unicast_address = unicast_address->Next) {
817       struct sockaddr* sa;
818       ULONG prefix_len;
819 
820       sa = unicast_address->Address.lpSockaddr;
821 
822       prefix_len =
823         ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
824 
825       memset(uv_address, 0, sizeof *uv_address);
826 
827       uv_address->name = name_buf;
828 
829       if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
830         memcpy(uv_address->phys_addr,
831                adapter->PhysicalAddress,
832                sizeof(uv_address->phys_addr));
833       }
834 
835       uv_address->is_internal =
836           (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
837 
838       if (sa->sa_family == AF_INET6) {
839         uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
840 
841         uv_address->netmask.netmask6.sin6_family = AF_INET6;
842         memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
843         /* This check ensures that we don't write past the size of the data. */
844         if (prefix_len % 8) {
845           uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
846               0xff << (8 - prefix_len % 8);
847         }
848 
849       } else {
850         uv_address->address.address4 = *((struct sockaddr_in *) sa);
851 
852         uv_address->netmask.netmask4.sin_family = AF_INET;
853         uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
854             htonl(0xffffffff << (32 - prefix_len)) : 0;
855       }
856 
857       uv_address++;
858     }
859 
860     name_buf += name_size;
861   }
862 
863   uv__free(win_address_buf);
864 
865   *addresses_ptr = uv_address_buf;
866   *count_ptr = count;
867 
868   return 0;
869 }
870 
871 
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)872 void uv_free_interface_addresses(uv_interface_address_t* addresses,
873     int count) {
874   uv__free(addresses);
875 }
876 
877 
uv_getrusage(uv_rusage_t * uv_rusage)878 int uv_getrusage(uv_rusage_t *uv_rusage) {
879   FILETIME createTime, exitTime, kernelTime, userTime;
880   SYSTEMTIME kernelSystemTime, userSystemTime;
881   PROCESS_MEMORY_COUNTERS memCounters;
882   IO_COUNTERS ioCounters;
883   int ret;
884 
885   ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
886   if (ret == 0) {
887     return uv_translate_sys_error(GetLastError());
888   }
889 
890   ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
891   if (ret == 0) {
892     return uv_translate_sys_error(GetLastError());
893   }
894 
895   ret = FileTimeToSystemTime(&userTime, &userSystemTime);
896   if (ret == 0) {
897     return uv_translate_sys_error(GetLastError());
898   }
899 
900   ret = GetProcessMemoryInfo(GetCurrentProcess(),
901                              &memCounters,
902                              sizeof(memCounters));
903   if (ret == 0) {
904     return uv_translate_sys_error(GetLastError());
905   }
906 
907   ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
908   if (ret == 0) {
909     return uv_translate_sys_error(GetLastError());
910   }
911 
912   memset(uv_rusage, 0, sizeof(*uv_rusage));
913 
914   uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
915                                userSystemTime.wMinute * 60 +
916                                userSystemTime.wSecond;
917   uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
918 
919   uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
920                                kernelSystemTime.wMinute * 60 +
921                                kernelSystemTime.wSecond;
922   uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
923 
924   uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
925   uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
926 
927   uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
928   uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
929 
930   return 0;
931 }
932 
933 
uv_os_homedir(char * buffer,size_t * size)934 int uv_os_homedir(char* buffer, size_t* size) {
935   uv_passwd_t pwd;
936   size_t len;
937   int r;
938 
939   /* Check if the USERPROFILE environment variable is set first. The task of
940      performing input validation on buffer and size is taken care of by
941      uv_os_getenv(). */
942   r = uv_os_getenv("USERPROFILE", buffer, size);
943 
944   /* Don't return an error if USERPROFILE was not found. */
945   if (r != UV_ENOENT)
946     return r;
947 
948   /* USERPROFILE is not set, so call uv_os_get_passwd() */
949   r = uv_os_get_passwd(&pwd);
950 
951   if (r != 0) {
952     return r;
953   }
954 
955   len = strlen(pwd.homedir);
956 
957   if (len >= *size) {
958     *size = len + 1;
959     uv_os_free_passwd(&pwd);
960     return UV_ENOBUFS;
961   }
962 
963   memcpy(buffer, pwd.homedir, len + 1);
964   *size = len;
965   uv_os_free_passwd(&pwd);
966 
967   return 0;
968 }
969 
970 
uv_os_tmpdir(char * buffer,size_t * size)971 int uv_os_tmpdir(char* buffer, size_t* size) {
972   wchar_t *path;
973   size_t len;
974 
975   if (buffer == NULL || size == NULL || *size == 0)
976     return UV_EINVAL;
977 
978   len = 0;
979   len = GetTempPathW(0, NULL);
980   if (len == 0) {
981     return uv_translate_sys_error(GetLastError());
982   }
983   /* Include space for terminating null char. */
984   len += 1;
985   path = uv__malloc(len * sizeof(wchar_t));
986   if (path == NULL) {
987     return UV_ENOMEM;
988   }
989   len = GetTempPathW(len, path);
990 
991   if (len == 0) {
992     uv__free(path);
993     return uv_translate_sys_error(GetLastError());
994   }
995 
996   /* The returned directory should not have a trailing slash, unless it points
997    * at a drive root, like c:\. Remove it if needed. */
998   if (path[len - 1] == L'\\' &&
999       !(len == 3 && path[1] == L':')) {
1000     len--;
1001     path[len] = L'\0';
1002   }
1003 
1004   return uv__copy_utf16_to_utf8(path, len, buffer, size);
1005 }
1006 
1007 
1008 /*
1009  * Converts a UTF-16 string into a UTF-8 one. The resulting string is
1010  * null-terminated.
1011  *
1012  * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
1013  * be specified.
1014  */
uv__convert_utf16_to_utf8(const WCHAR * utf16,size_t utf16len,char ** utf8)1015 int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8) {
1016   size_t utf8_len = 0;
1017 
1018   if (utf16 == NULL)
1019     return UV_EINVAL;
1020 
1021    *utf8 = NULL;
1022    return uv_utf16_to_wtf8(utf16, utf16len, utf8, &utf8_len);
1023 }
1024 
1025 
1026 /*
1027  * Converts a UTF-8 string into a UTF-16 one. The resulting string is
1028  * null-terminated.
1029  */
uv__convert_utf8_to_utf16(const char * utf8,WCHAR ** utf16)1030 int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16) {
1031   int bufsize;
1032 
1033   if (utf8 == NULL)
1034     return UV_EINVAL;
1035 
1036   /* Check how much space we need (including NUL). */
1037   bufsize = uv_wtf8_length_as_utf16(utf8);
1038   if (bufsize < 0)
1039     return UV__EINVAL;
1040 
1041   /* Allocate the destination buffer. */
1042   *utf16 = uv__malloc(sizeof(WCHAR) * bufsize);
1043 
1044   if (*utf16 == NULL)
1045     return UV_ENOMEM;
1046 
1047   /* Convert to UTF-16 */
1048   uv_wtf8_to_utf16(utf8, *utf16, bufsize);
1049 
1050   return 0;
1051 }
1052 
1053 
1054 /*
1055  * Converts a UTF-16 string into a UTF-8 one in an existing buffer. The
1056  * resulting string is null-terminated.
1057  *
1058  * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
1059  * be specified.
1060  */
uv__copy_utf16_to_utf8(const WCHAR * utf16buffer,size_t utf16len,char * utf8,size_t * size)1061 int uv__copy_utf16_to_utf8(const WCHAR* utf16buffer, size_t utf16len, char* utf8, size_t *size) {
1062   int r;
1063 
1064   if (utf8 == NULL || size == NULL)
1065     return UV_EINVAL;
1066 
1067   if (*size == 0) {
1068     *size = uv_utf16_length_as_wtf8(utf16buffer, utf16len);
1069     r = UV_ENOBUFS;
1070   } else {
1071     *size -= 1; /* Reserve space for NUL. */
1072     r = uv_utf16_to_wtf8(utf16buffer, utf16len, &utf8, size);
1073   }
1074   if (r == UV_ENOBUFS)
1075     *size += 1; /* Add space for NUL. */
1076   return r;
1077 }
1078 
1079 
uv__getpwuid_r(uv_passwd_t * pwd)1080 static int uv__getpwuid_r(uv_passwd_t* pwd) {
1081   HANDLE token;
1082   wchar_t username[UNLEN + 1];
1083   wchar_t *path;
1084   DWORD bufsize;
1085   int r;
1086 
1087   if (pwd == NULL)
1088     return UV_EINVAL;
1089 
1090   /* Get the home directory using GetUserProfileDirectoryW() */
1091   if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
1092     return uv_translate_sys_error(GetLastError());
1093 
1094   bufsize = 0;
1095   GetUserProfileDirectoryW(token, NULL, &bufsize);
1096   if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1097     r = GetLastError();
1098     CloseHandle(token);
1099     return uv_translate_sys_error(r);
1100   }
1101 
1102   path = uv__malloc(bufsize * sizeof(wchar_t));
1103   if (path == NULL) {
1104     CloseHandle(token);
1105     return UV_ENOMEM;
1106   }
1107 
1108   if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
1109     r = GetLastError();
1110     CloseHandle(token);
1111     uv__free(path);
1112     return uv_translate_sys_error(r);
1113   }
1114 
1115   CloseHandle(token);
1116 
1117   /* Get the username using GetUserNameW() */
1118   bufsize = ARRAY_SIZE(username);
1119   if (!GetUserNameW(username, &bufsize)) {
1120     r = GetLastError();
1121     uv__free(path);
1122 
1123     /* This should not be possible */
1124     if (r == ERROR_INSUFFICIENT_BUFFER)
1125       return UV_ENOMEM;
1126 
1127     return uv_translate_sys_error(r);
1128   }
1129 
1130   pwd->homedir = NULL;
1131   r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
1132   uv__free(path);
1133 
1134   if (r != 0)
1135     return r;
1136 
1137   pwd->username = NULL;
1138   r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
1139 
1140   if (r != 0) {
1141     uv__free(pwd->homedir);
1142     return r;
1143   }
1144 
1145   pwd->shell = NULL;
1146   pwd->uid = -1;
1147   pwd->gid = -1;
1148 
1149   return 0;
1150 }
1151 
1152 
uv_os_get_passwd(uv_passwd_t * pwd)1153 int uv_os_get_passwd(uv_passwd_t* pwd) {
1154   return uv__getpwuid_r(pwd);
1155 }
1156 
1157 
uv_os_get_passwd2(uv_passwd_t * pwd,uv_uid_t uid)1158 int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
1159   return UV_ENOTSUP;
1160 }
1161 
1162 
uv_os_get_group(uv_group_t * grp,uv_uid_t gid)1163 int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
1164   return UV_ENOTSUP;
1165 }
1166 
1167 
uv_os_environ(uv_env_item_t ** envitems,int * count)1168 int uv_os_environ(uv_env_item_t** envitems, int* count) {
1169   wchar_t* env;
1170   wchar_t* penv;
1171   int i, cnt;
1172   uv_env_item_t* envitem;
1173 
1174   *envitems = NULL;
1175   *count = 0;
1176 
1177   env = GetEnvironmentStringsW();
1178   if (env == NULL)
1179     return 0;
1180 
1181   for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
1182 
1183   *envitems = uv__calloc(i, sizeof(**envitems));
1184   if (*envitems == NULL) {
1185     FreeEnvironmentStringsW(env);
1186     return UV_ENOMEM;
1187   }
1188 
1189   penv = env;
1190   cnt = 0;
1191 
1192   while (*penv != L'\0' && cnt < i) {
1193     char* buf;
1194     char* ptr;
1195 
1196     if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
1197       goto fail;
1198 
1199     /* Using buf + 1 here because we know that `buf` has length at least 1,
1200      * and some special environment variables on Windows start with a = sign. */
1201     ptr = strchr(buf + 1, '=');
1202     if (ptr == NULL) {
1203       uv__free(buf);
1204       goto do_continue;
1205     }
1206 
1207     *ptr = '\0';
1208 
1209     envitem = &(*envitems)[cnt];
1210     envitem->name = buf;
1211     envitem->value = ptr + 1;
1212 
1213     cnt++;
1214 
1215   do_continue:
1216     penv += wcslen(penv) + 1;
1217   }
1218 
1219   FreeEnvironmentStringsW(env);
1220 
1221   *count = cnt;
1222   return 0;
1223 
1224 fail:
1225   FreeEnvironmentStringsW(env);
1226 
1227   for (i = 0; i < cnt; i++) {
1228     envitem = &(*envitems)[cnt];
1229     uv__free(envitem->name);
1230   }
1231   uv__free(*envitems);
1232 
1233   *envitems = NULL;
1234   *count = 0;
1235   return UV_ENOMEM;
1236 }
1237 
1238 
uv_os_getenv(const char * name,char * buffer,size_t * size)1239 int uv_os_getenv(const char* name, char* buffer, size_t* size) {
1240   wchar_t fastvar[512];
1241   wchar_t* var;
1242   DWORD varlen;
1243   wchar_t* name_w;
1244   size_t len;
1245   int r;
1246 
1247   if (name == NULL || buffer == NULL || size == NULL || *size == 0)
1248     return UV_EINVAL;
1249 
1250   r = uv__convert_utf8_to_utf16(name, &name_w);
1251 
1252   if (r != 0)
1253     return r;
1254 
1255   var = fastvar;
1256   varlen = ARRAY_SIZE(fastvar);
1257 
1258   for (;;) {
1259     SetLastError(ERROR_SUCCESS);
1260     len = GetEnvironmentVariableW(name_w, var, varlen);
1261 
1262     if (len == 0)
1263       r = uv_translate_sys_error(GetLastError());
1264 
1265     if (len < varlen)
1266       break;
1267 
1268     /* Try repeatedly because we might have been preempted by another thread
1269      * modifying the environment variable just as we're trying to read it.
1270      */
1271     if (var != fastvar)
1272       uv__free(var);
1273 
1274     varlen = 1 + len;
1275     var = uv__malloc(varlen * sizeof(*var));
1276 
1277     if (var == NULL) {
1278       r = UV_ENOMEM;
1279       goto fail;
1280     }
1281   }
1282 
1283   uv__free(name_w);
1284   name_w = NULL;
1285 
1286   if (r == 0)
1287     r = uv__copy_utf16_to_utf8(var, len, buffer, size);
1288 
1289 fail:
1290 
1291   if (name_w != NULL)
1292     uv__free(name_w);
1293 
1294   if (var != fastvar)
1295     uv__free(var);
1296 
1297   return r;
1298 }
1299 
1300 
uv_os_setenv(const char * name,const char * value)1301 int uv_os_setenv(const char* name, const char* value) {
1302   wchar_t* name_w;
1303   wchar_t* value_w;
1304   int r;
1305 
1306   if (name == NULL || value == NULL)
1307     return UV_EINVAL;
1308 
1309   r = uv__convert_utf8_to_utf16(name, &name_w);
1310 
1311   if (r != 0)
1312     return r;
1313 
1314   r = uv__convert_utf8_to_utf16(value, &value_w);
1315 
1316   if (r != 0) {
1317     uv__free(name_w);
1318     return r;
1319   }
1320 
1321   r = SetEnvironmentVariableW(name_w, value_w);
1322   uv__free(name_w);
1323   uv__free(value_w);
1324 
1325   if (r == 0)
1326     return uv_translate_sys_error(GetLastError());
1327 
1328   return 0;
1329 }
1330 
1331 
uv_os_unsetenv(const char * name)1332 int uv_os_unsetenv(const char* name) {
1333   wchar_t* name_w;
1334   int r;
1335 
1336   if (name == NULL)
1337     return UV_EINVAL;
1338 
1339   r = uv__convert_utf8_to_utf16(name, &name_w);
1340 
1341   if (r != 0)
1342     return r;
1343 
1344   r = SetEnvironmentVariableW(name_w, NULL);
1345   uv__free(name_w);
1346 
1347   if (r == 0)
1348     return uv_translate_sys_error(GetLastError());
1349 
1350   return 0;
1351 }
1352 
1353 
uv_os_gethostname(char * buffer,size_t * size)1354 int uv_os_gethostname(char* buffer, size_t* size) {
1355   WCHAR buf[UV_MAXHOSTNAMESIZE];
1356 
1357   if (buffer == NULL || size == NULL || *size == 0)
1358     return UV_EINVAL;
1359 
1360   uv__once_init(); /* Initialize winsock */
1361 
1362   if (pGetHostNameW == NULL)
1363     return UV_ENOSYS;
1364 
1365   if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
1366     return uv_translate_sys_error(WSAGetLastError());
1367 
1368   return uv__copy_utf16_to_utf8(buf, -1, buffer, size);
1369 }
1370 
1371 
uv__get_handle(uv_pid_t pid,int access,HANDLE * handle)1372 static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
1373   int r;
1374 
1375   if (pid == 0)
1376     *handle = GetCurrentProcess();
1377   else
1378     *handle = OpenProcess(access, FALSE, pid);
1379 
1380   if (*handle == NULL) {
1381     r = GetLastError();
1382 
1383     if (r == ERROR_INVALID_PARAMETER)
1384       return UV_ESRCH;
1385     else
1386       return uv_translate_sys_error(r);
1387   }
1388 
1389   return 0;
1390 }
1391 
1392 
uv_os_getpriority(uv_pid_t pid,int * priority)1393 int uv_os_getpriority(uv_pid_t pid, int* priority) {
1394   HANDLE handle;
1395   int r;
1396 
1397   if (priority == NULL)
1398     return UV_EINVAL;
1399 
1400   r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
1401 
1402   if (r != 0)
1403     return r;
1404 
1405   r = GetPriorityClass(handle);
1406 
1407   if (r == 0) {
1408     r = uv_translate_sys_error(GetLastError());
1409   } else {
1410     /* Map Windows priority classes to Unix nice values. */
1411     if (r == REALTIME_PRIORITY_CLASS)
1412       *priority = UV_PRIORITY_HIGHEST;
1413     else if (r == HIGH_PRIORITY_CLASS)
1414       *priority = UV_PRIORITY_HIGH;
1415     else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
1416       *priority = UV_PRIORITY_ABOVE_NORMAL;
1417     else if (r == NORMAL_PRIORITY_CLASS)
1418       *priority = UV_PRIORITY_NORMAL;
1419     else if (r == BELOW_NORMAL_PRIORITY_CLASS)
1420       *priority = UV_PRIORITY_BELOW_NORMAL;
1421     else  /* IDLE_PRIORITY_CLASS */
1422       *priority = UV_PRIORITY_LOW;
1423 
1424     r = 0;
1425   }
1426 
1427   CloseHandle(handle);
1428   return r;
1429 }
1430 
1431 
uv_os_setpriority(uv_pid_t pid,int priority)1432 int uv_os_setpriority(uv_pid_t pid, int priority) {
1433   HANDLE handle;
1434   int priority_class;
1435   int r;
1436 
1437   /* Map Unix nice values to Windows priority classes. */
1438   if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
1439     return UV_EINVAL;
1440   else if (priority < UV_PRIORITY_HIGH)
1441     priority_class = REALTIME_PRIORITY_CLASS;
1442   else if (priority < UV_PRIORITY_ABOVE_NORMAL)
1443     priority_class = HIGH_PRIORITY_CLASS;
1444   else if (priority < UV_PRIORITY_NORMAL)
1445     priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
1446   else if (priority < UV_PRIORITY_BELOW_NORMAL)
1447     priority_class = NORMAL_PRIORITY_CLASS;
1448   else if (priority < UV_PRIORITY_LOW)
1449     priority_class = BELOW_NORMAL_PRIORITY_CLASS;
1450   else
1451     priority_class = IDLE_PRIORITY_CLASS;
1452 
1453   r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
1454 
1455   if (r != 0)
1456     return r;
1457 
1458   if (SetPriorityClass(handle, priority_class) == 0)
1459     r = uv_translate_sys_error(GetLastError());
1460 
1461   CloseHandle(handle);
1462   return r;
1463 }
1464 
uv_thread_getpriority(uv_thread_t tid,int * priority)1465 int uv_thread_getpriority(uv_thread_t tid, int* priority) {
1466   int r;
1467 
1468   if (priority == NULL)
1469     return UV_EINVAL;
1470 
1471   r = GetThreadPriority(tid);
1472   if (r == THREAD_PRIORITY_ERROR_RETURN)
1473     return uv_translate_sys_error(GetLastError());
1474 
1475   *priority = r;
1476   return 0;
1477 }
1478 
uv_thread_setpriority(uv_thread_t tid,int priority)1479 int uv_thread_setpriority(uv_thread_t tid, int priority) {
1480   int r;
1481 
1482   switch (priority) {
1483     case UV_THREAD_PRIORITY_HIGHEST:
1484       r = SetThreadPriority(tid, THREAD_PRIORITY_HIGHEST);
1485       break;
1486     case UV_THREAD_PRIORITY_ABOVE_NORMAL:
1487       r = SetThreadPriority(tid, THREAD_PRIORITY_ABOVE_NORMAL);
1488       break;
1489     case UV_THREAD_PRIORITY_NORMAL:
1490       r = SetThreadPriority(tid, THREAD_PRIORITY_NORMAL);
1491       break;
1492     case UV_THREAD_PRIORITY_BELOW_NORMAL:
1493       r = SetThreadPriority(tid, THREAD_PRIORITY_BELOW_NORMAL);
1494       break;
1495     case UV_THREAD_PRIORITY_LOWEST:
1496       r = SetThreadPriority(tid, THREAD_PRIORITY_LOWEST);
1497       break;
1498     default:
1499       return 0;
1500   }
1501 
1502   if (r == 0)
1503     return uv_translate_sys_error(GetLastError());
1504 
1505   return 0;
1506 }
1507 
uv_os_uname(uv_utsname_t * buffer)1508 int uv_os_uname(uv_utsname_t* buffer) {
1509   /* Implementation loosely based on
1510      https://github.com/gagern/gnulib/blob/master/lib/uname.c */
1511   OSVERSIONINFOW os_info;
1512   SYSTEM_INFO system_info;
1513   HKEY registry_key;
1514   WCHAR product_name_w[256];
1515   DWORD product_name_w_size;
1516   size_t version_size;
1517   int processor_level;
1518   int r;
1519 
1520   if (buffer == NULL)
1521     return UV_EINVAL;
1522 
1523   uv__once_init();
1524   os_info.dwOSVersionInfoSize = sizeof(os_info);
1525   os_info.szCSDVersion[0] = L'\0';
1526 
1527   /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
1528      if RtlGetVersion() is not available. */
1529   if (pRtlGetVersion) {
1530     pRtlGetVersion(&os_info);
1531   } else {
1532     /* Silence GetVersionEx() deprecation warning. */
1533     #ifdef _MSC_VER
1534     #pragma warning(suppress : 4996)
1535     #endif
1536     if (GetVersionExW(&os_info) == 0) {
1537       r = uv_translate_sys_error(GetLastError());
1538       goto error;
1539     }
1540   }
1541 
1542   /* Populate the version field. */
1543   version_size = 0;
1544   r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1545                     L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
1546                     0,
1547                     KEY_QUERY_VALUE | KEY_WOW64_64KEY,
1548                     &registry_key);
1549 
1550   if (r == ERROR_SUCCESS) {
1551     product_name_w_size = sizeof(product_name_w);
1552     r = RegGetValueW(registry_key,
1553                      NULL,
1554                      L"ProductName",
1555                      RRF_RT_REG_SZ,
1556                      NULL,
1557                      (PVOID) product_name_w,
1558                      &product_name_w_size);
1559     RegCloseKey(registry_key);
1560 
1561     if (r == ERROR_SUCCESS) {
1562       /* Windows 11 shares dwMajorVersion with Windows 10
1563        * this workaround tries to disambiguate that by checking
1564        * if the dwBuildNumber is from Windows 11 releases (>= 22000).
1565        *
1566        * This workaround replaces the ProductName key value
1567        * from "Windows 10 *" to "Windows 11 *" */
1568       if (os_info.dwMajorVersion == 10 &&
1569           os_info.dwBuildNumber >= 22000 &&
1570           product_name_w_size >= ARRAY_SIZE(L"Windows 10")) {
1571         /* If ProductName starts with "Windows 10" */
1572         if (wcsncmp(product_name_w, L"Windows 10", ARRAY_SIZE(L"Windows 10") - 1) == 0) {
1573           /* Bump 10 to 11 */
1574           product_name_w[9] = '1';
1575         }
1576       }
1577 
1578       version_size = sizeof(buffer->version);
1579       r = uv__copy_utf16_to_utf8(product_name_w,
1580                                  -1,
1581                                  buffer->version,
1582                                  &version_size);
1583       if (r)
1584         goto error;
1585     }
1586   }
1587 
1588   /* Append service pack information to the version if present. */
1589   if (os_info.szCSDVersion[0] != L'\0') {
1590     if (version_size > 0)
1591       buffer->version[version_size++] = ' ';
1592 
1593     version_size = sizeof(buffer->version) - version_size;
1594     r = uv__copy_utf16_to_utf8(os_info.szCSDVersion,
1595                                -1,
1596                                buffer->version +
1597                                  sizeof(buffer->version) - version_size,
1598                                &version_size);
1599     if (r)
1600       goto error;
1601   }
1602 
1603   /* Populate the sysname field. */
1604 #ifdef __MINGW32__
1605   r = snprintf(buffer->sysname,
1606                sizeof(buffer->sysname),
1607                "MINGW32_NT-%u.%u",
1608                (unsigned int) os_info.dwMajorVersion,
1609                (unsigned int) os_info.dwMinorVersion);
1610   assert((size_t)r < sizeof(buffer->sysname));
1611 #else
1612   uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
1613 #endif
1614 
1615   /* Populate the release field. */
1616   r = snprintf(buffer->release,
1617                sizeof(buffer->release),
1618                "%d.%d.%d",
1619                (unsigned int) os_info.dwMajorVersion,
1620                (unsigned int) os_info.dwMinorVersion,
1621                (unsigned int) os_info.dwBuildNumber);
1622   assert((size_t)r < sizeof(buffer->release));
1623 
1624   /* Populate the machine field. */
1625   GetSystemInfo(&system_info);
1626 
1627   switch (system_info.wProcessorArchitecture) {
1628     case PROCESSOR_ARCHITECTURE_AMD64:
1629       uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
1630       break;
1631     case PROCESSOR_ARCHITECTURE_IA64:
1632       uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
1633       break;
1634     case PROCESSOR_ARCHITECTURE_INTEL:
1635       uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
1636 
1637       if (system_info.wProcessorLevel > 3) {
1638         processor_level = system_info.wProcessorLevel < 6 ?
1639                           system_info.wProcessorLevel : 6;
1640         buffer->machine[1] = '0' + processor_level;
1641       }
1642 
1643       break;
1644     case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1645       uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
1646       break;
1647     case PROCESSOR_ARCHITECTURE_MIPS:
1648       uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
1649       break;
1650     case PROCESSOR_ARCHITECTURE_ALPHA:
1651     case PROCESSOR_ARCHITECTURE_ALPHA64:
1652       uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
1653       break;
1654     case PROCESSOR_ARCHITECTURE_PPC:
1655       uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
1656       break;
1657     case PROCESSOR_ARCHITECTURE_SHX:
1658       uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
1659       break;
1660     case PROCESSOR_ARCHITECTURE_ARM:
1661       uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
1662       break;
1663     default:
1664       uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
1665       break;
1666   }
1667 
1668   return 0;
1669 
1670 error:
1671   buffer->sysname[0] = '\0';
1672   buffer->release[0] = '\0';
1673   buffer->version[0] = '\0';
1674   buffer->machine[0] = '\0';
1675   return r;
1676 }
1677 
uv_gettimeofday(uv_timeval64_t * tv)1678 int uv_gettimeofday(uv_timeval64_t* tv) {
1679   /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
1680   const uint64_t epoch = (uint64_t) 116444736000000000ULL;
1681   FILETIME file_time;
1682   ULARGE_INTEGER ularge;
1683 
1684   if (tv == NULL)
1685     return UV_EINVAL;
1686 
1687   GetSystemTimeAsFileTime(&file_time);
1688   ularge.LowPart = file_time.dwLowDateTime;
1689   ularge.HighPart = file_time.dwHighDateTime;
1690   tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
1691   tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
1692   return 0;
1693 }
1694 
uv__random_rtlgenrandom(void * buf,size_t buflen)1695 int uv__random_rtlgenrandom(void* buf, size_t buflen) {
1696   if (buflen == 0)
1697     return 0;
1698 
1699   if (SystemFunction036(buf, buflen) == FALSE)
1700     return UV_EIO;
1701 
1702   return 0;
1703 }
1704 
uv_sleep(unsigned int msec)1705 void uv_sleep(unsigned int msec) {
1706   Sleep(msec);
1707 }
1708