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