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