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