• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   *uptime = GetTickCount64() / 1000.0;
535   return 0;
536 }
537 
538 
uv_available_parallelism(void)539 unsigned int uv_available_parallelism(void) {
540   SYSTEM_INFO info;
541   unsigned rc;
542 
543   /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
544    * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
545    */
546   GetSystemInfo(&info);
547 
548   rc = info.dwNumberOfProcessors;
549   if (rc < 1)
550     rc = 1;
551 
552   return rc;
553 }
554 
555 
uv_cpu_info(uv_cpu_info_t ** cpu_infos_ptr,int * cpu_count_ptr)556 int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
557   uv_cpu_info_t* cpu_infos;
558   SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
559   DWORD sppi_size;
560   SYSTEM_INFO system_info;
561   DWORD cpu_count, i;
562   NTSTATUS status;
563   ULONG result_size;
564   int err;
565   uv_cpu_info_t* cpu_info;
566 
567   cpu_infos = NULL;
568   cpu_count = 0;
569   sppi = NULL;
570 
571   uv__once_init();
572 
573   GetSystemInfo(&system_info);
574   cpu_count = system_info.dwNumberOfProcessors;
575 
576   cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
577   if (cpu_infos == NULL) {
578     err = ERROR_OUTOFMEMORY;
579     goto error;
580   }
581 
582   sppi_size = cpu_count * sizeof(*sppi);
583   sppi = uv__malloc(sppi_size);
584   if (sppi == NULL) {
585     err = ERROR_OUTOFMEMORY;
586     goto error;
587   }
588 
589   status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
590                                      sppi,
591                                      sppi_size,
592                                      &result_size);
593   if (!NT_SUCCESS(status)) {
594     err = pRtlNtStatusToDosError(status);
595     goto error;
596   }
597 
598   assert(result_size == sppi_size);
599 
600   for (i = 0; i < cpu_count; i++) {
601     WCHAR key_name[128];
602     HKEY processor_key;
603     DWORD cpu_speed;
604     DWORD cpu_speed_size = sizeof(cpu_speed);
605     WCHAR cpu_brand[256];
606     DWORD cpu_brand_size = sizeof(cpu_brand);
607     size_t len;
608 
609     len = _snwprintf(key_name,
610                      ARRAY_SIZE(key_name),
611                      L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
612                      i);
613 
614     assert(len > 0 && len < ARRAY_SIZE(key_name));
615 
616     err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
617                         key_name,
618                         0,
619                         KEY_QUERY_VALUE,
620                         &processor_key);
621     if (err != ERROR_SUCCESS) {
622       goto error;
623     }
624 
625     err = RegQueryValueExW(processor_key,
626                            L"~MHz",
627                            NULL,
628                            NULL,
629                            (BYTE*)&cpu_speed,
630                            &cpu_speed_size);
631     if (err != ERROR_SUCCESS) {
632       RegCloseKey(processor_key);
633       goto error;
634     }
635 
636     err = RegQueryValueExW(processor_key,
637                            L"ProcessorNameString",
638                            NULL,
639                            NULL,
640                            (BYTE*)&cpu_brand,
641                            &cpu_brand_size);
642     RegCloseKey(processor_key);
643     if (err != ERROR_SUCCESS)
644       goto error;
645 
646     cpu_info = &cpu_infos[i];
647     cpu_info->speed = cpu_speed;
648     cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
649     cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
650         sppi[i].IdleTime.QuadPart) / 10000;
651     cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
652     cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
653     cpu_info->cpu_times.nice = 0;
654 
655     uv__convert_utf16_to_utf8(cpu_brand,
656                               cpu_brand_size / sizeof(WCHAR),
657                               &(cpu_info->model));
658   }
659 
660   uv__free(sppi);
661 
662   *cpu_count_ptr = cpu_count;
663   *cpu_infos_ptr = cpu_infos;
664 
665   return 0;
666 
667  error:
668   if (cpu_infos != NULL) {
669     /* This is safe because the cpu_infos array is zeroed on allocation. */
670     for (i = 0; i < cpu_count; i++)
671       uv__free(cpu_infos[i].model);
672   }
673 
674   uv__free(cpu_infos);
675   uv__free(sppi);
676 
677   return uv_translate_sys_error(err);
678 }
679 
680 
is_windows_version_or_greater(DWORD os_major,DWORD os_minor,WORD service_pack_major,WORD service_pack_minor)681 static int is_windows_version_or_greater(DWORD os_major,
682                                          DWORD os_minor,
683                                          WORD service_pack_major,
684                                          WORD service_pack_minor) {
685   OSVERSIONINFOEX osvi;
686   DWORDLONG condition_mask = 0;
687   int op = VER_GREATER_EQUAL;
688 
689   /* Initialize the OSVERSIONINFOEX structure. */
690   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
691   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
692   osvi.dwMajorVersion = os_major;
693   osvi.dwMinorVersion = os_minor;
694   osvi.wServicePackMajor = service_pack_major;
695   osvi.wServicePackMinor = service_pack_minor;
696 
697   /* Initialize the condition mask. */
698   VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
699   VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
700   VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
701   VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
702 
703   /* Perform the test. */
704   return (int) VerifyVersionInfo(
705     &osvi,
706     VER_MAJORVERSION | VER_MINORVERSION |
707     VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
708     condition_mask);
709 }
710 
711 
address_prefix_match(int family,struct sockaddr * address,struct sockaddr * prefix_address,int prefix_len)712 static int address_prefix_match(int family,
713                                 struct sockaddr* address,
714                                 struct sockaddr* prefix_address,
715                                 int prefix_len) {
716   uint8_t* address_data;
717   uint8_t* prefix_address_data;
718   int i;
719 
720   assert(address->sa_family == family);
721   assert(prefix_address->sa_family == family);
722 
723   if (family == AF_INET6) {
724     address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
725     prefix_address_data =
726       (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
727   } else {
728     address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
729     prefix_address_data =
730       (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
731   }
732 
733   for (i = 0; i < prefix_len >> 3; i++) {
734     if (address_data[i] != prefix_address_data[i])
735       return 0;
736   }
737 
738   if (prefix_len % 8)
739     return prefix_address_data[i] ==
740       (address_data[i] & (0xff << (8 - prefix_len % 8)));
741 
742   return 1;
743 }
744 
745 
uv_interface_addresses(uv_interface_address_t ** addresses_ptr,int * count_ptr)746 int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
747     int* count_ptr) {
748   IP_ADAPTER_ADDRESSES* win_address_buf;
749   ULONG win_address_buf_size;
750   IP_ADAPTER_ADDRESSES* adapter;
751 
752   uv_interface_address_t* uv_address_buf;
753   char* name_buf;
754   size_t uv_address_buf_size;
755   uv_interface_address_t* uv_address;
756 
757   int count;
758 
759   int is_vista_or_greater;
760   ULONG flags;
761 
762   *addresses_ptr = NULL;
763   *count_ptr = 0;
764 
765   is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
766   if (is_vista_or_greater) {
767     flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
768       GAA_FLAG_SKIP_DNS_SERVER;
769   } else {
770     /* We need at least XP SP1. */
771     if (!is_windows_version_or_greater(5, 1, 1, 0))
772       return UV_ENOTSUP;
773 
774     flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
775       GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
776   }
777 
778 
779   /* Fetch the size of the adapters reported by windows, and then get the list
780    * itself. */
781   win_address_buf_size = 0;
782   win_address_buf = NULL;
783 
784   for (;;) {
785     ULONG r;
786 
787     /* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
788      * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
789      * win_address_buf_size. */
790     r = GetAdaptersAddresses(AF_UNSPEC,
791                              flags,
792                              NULL,
793                              win_address_buf,
794                              &win_address_buf_size);
795 
796     if (r == ERROR_SUCCESS)
797       break;
798 
799     uv__free(win_address_buf);
800 
801     switch (r) {
802       case ERROR_BUFFER_OVERFLOW:
803         /* This happens when win_address_buf is NULL or too small to hold all
804          * adapters. */
805         win_address_buf = uv__malloc(win_address_buf_size);
806         if (win_address_buf == NULL)
807           return UV_ENOMEM;
808 
809         continue;
810 
811       case ERROR_NO_DATA: {
812         /* No adapters were found. */
813         uv_address_buf = uv__malloc(1);
814         if (uv_address_buf == NULL)
815           return UV_ENOMEM;
816 
817         *count_ptr = 0;
818         *addresses_ptr = uv_address_buf;
819 
820         return 0;
821       }
822 
823       case ERROR_ADDRESS_NOT_ASSOCIATED:
824         return UV_EAGAIN;
825 
826       case ERROR_INVALID_PARAMETER:
827         /* MSDN says:
828          *   "This error is returned for any of the following conditions: the
829          *   SizePointer parameter is NULL, the Address parameter is not
830          *   AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
831          *   the parameters requested is greater than ULONG_MAX."
832          * Since the first two conditions are not met, it must be that the
833          * adapter data is too big.
834          */
835         return UV_ENOBUFS;
836 
837       default:
838         /* Other (unspecified) errors can happen, but we don't have any special
839          * meaning for them. */
840         assert(r != ERROR_SUCCESS);
841         return uv_translate_sys_error(r);
842     }
843   }
844 
845   /* Count the number of enabled interfaces and compute how much space is
846    * needed to store their info. */
847   count = 0;
848   uv_address_buf_size = 0;
849 
850   for (adapter = win_address_buf;
851        adapter != NULL;
852        adapter = adapter->Next) {
853     IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
854     int name_size;
855 
856     /* Interfaces that are not 'up' should not be reported. Also skip
857      * interfaces that have no associated unicast address, as to avoid
858      * allocating space for the name for this interface. */
859     if (adapter->OperStatus != IfOperStatusUp ||
860         adapter->FirstUnicastAddress == NULL)
861       continue;
862 
863     /* Compute the size of the interface name. */
864     name_size = WideCharToMultiByte(CP_UTF8,
865                                     0,
866                                     adapter->FriendlyName,
867                                     -1,
868                                     NULL,
869                                     0,
870                                     NULL,
871                                     FALSE);
872     if (name_size <= 0) {
873       uv__free(win_address_buf);
874       return uv_translate_sys_error(GetLastError());
875     }
876     uv_address_buf_size += name_size;
877 
878     /* Count the number of addresses associated with this interface, and
879      * compute the size. */
880     for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
881                            adapter->FirstUnicastAddress;
882          unicast_address != NULL;
883          unicast_address = unicast_address->Next) {
884       count++;
885       uv_address_buf_size += sizeof(uv_interface_address_t);
886     }
887   }
888 
889   /* Allocate space to store interface data plus adapter names. */
890   uv_address_buf = uv__malloc(uv_address_buf_size);
891   if (uv_address_buf == NULL) {
892     uv__free(win_address_buf);
893     return UV_ENOMEM;
894   }
895 
896   /* Compute the start of the uv_interface_address_t array, and the place in
897    * the buffer where the interface names will be stored. */
898   uv_address = uv_address_buf;
899   name_buf = (char*) (uv_address_buf + count);
900 
901   /* Fill out the output buffer. */
902   for (adapter = win_address_buf;
903        adapter != NULL;
904        adapter = adapter->Next) {
905     IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
906     int name_size;
907     size_t max_name_size;
908 
909     if (adapter->OperStatus != IfOperStatusUp ||
910         adapter->FirstUnicastAddress == NULL)
911       continue;
912 
913     /* Convert the interface name to UTF8. */
914     max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
915     if (max_name_size > (size_t) INT_MAX)
916       max_name_size = INT_MAX;
917     name_size = WideCharToMultiByte(CP_UTF8,
918                                     0,
919                                     adapter->FriendlyName,
920                                     -1,
921                                     name_buf,
922                                     (int) max_name_size,
923                                     NULL,
924                                     FALSE);
925     if (name_size <= 0) {
926       uv__free(win_address_buf);
927       uv__free(uv_address_buf);
928       return uv_translate_sys_error(GetLastError());
929     }
930 
931     /* Add an uv_interface_address_t element for every unicast address. */
932     for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
933                            adapter->FirstUnicastAddress;
934          unicast_address != NULL;
935          unicast_address = unicast_address->Next) {
936       struct sockaddr* sa;
937       ULONG prefix_len;
938 
939       sa = unicast_address->Address.lpSockaddr;
940 
941       /* XP has no OnLinkPrefixLength field. */
942       if (is_vista_or_greater) {
943         prefix_len =
944           ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
945       } else {
946         /* Prior to Windows Vista the FirstPrefix pointed to the list with
947          * single prefix for each IP address assigned to the adapter.
948          * Order of FirstPrefix does not match order of FirstUnicastAddress,
949          * so we need to find corresponding prefix.
950          */
951         IP_ADAPTER_PREFIX* prefix;
952         prefix_len = 0;
953 
954         for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
955           /* We want the longest matching prefix. */
956           if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
957               prefix->PrefixLength <= prefix_len)
958             continue;
959 
960           if (address_prefix_match(sa->sa_family, sa,
961               prefix->Address.lpSockaddr, prefix->PrefixLength)) {
962             prefix_len = prefix->PrefixLength;
963           }
964         }
965 
966         /* If there is no matching prefix information, return a single-host
967          * subnet mask (e.g. 255.255.255.255 for IPv4).
968          */
969         if (!prefix_len)
970           prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
971       }
972 
973       memset(uv_address, 0, sizeof *uv_address);
974 
975       uv_address->name = name_buf;
976 
977       if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
978         memcpy(uv_address->phys_addr,
979                adapter->PhysicalAddress,
980                sizeof(uv_address->phys_addr));
981       }
982 
983       uv_address->is_internal =
984           (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
985 
986       if (sa->sa_family == AF_INET6) {
987         uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
988 
989         uv_address->netmask.netmask6.sin6_family = AF_INET6;
990         memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
991         /* This check ensures that we don't write past the size of the data. */
992         if (prefix_len % 8) {
993           uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
994               0xff << (8 - prefix_len % 8);
995         }
996 
997       } else {
998         uv_address->address.address4 = *((struct sockaddr_in *) sa);
999 
1000         uv_address->netmask.netmask4.sin_family = AF_INET;
1001         uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
1002             htonl(0xffffffff << (32 - prefix_len)) : 0;
1003       }
1004 
1005       uv_address++;
1006     }
1007 
1008     name_buf += name_size;
1009   }
1010 
1011   uv__free(win_address_buf);
1012 
1013   *addresses_ptr = uv_address_buf;
1014   *count_ptr = count;
1015 
1016   return 0;
1017 }
1018 
1019 
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)1020 void uv_free_interface_addresses(uv_interface_address_t* addresses,
1021     int count) {
1022   uv__free(addresses);
1023 }
1024 
1025 
uv_getrusage(uv_rusage_t * uv_rusage)1026 int uv_getrusage(uv_rusage_t *uv_rusage) {
1027   FILETIME createTime, exitTime, kernelTime, userTime;
1028   SYSTEMTIME kernelSystemTime, userSystemTime;
1029   PROCESS_MEMORY_COUNTERS memCounters;
1030   IO_COUNTERS ioCounters;
1031   int ret;
1032 
1033   ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
1034   if (ret == 0) {
1035     return uv_translate_sys_error(GetLastError());
1036   }
1037 
1038   ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
1039   if (ret == 0) {
1040     return uv_translate_sys_error(GetLastError());
1041   }
1042 
1043   ret = FileTimeToSystemTime(&userTime, &userSystemTime);
1044   if (ret == 0) {
1045     return uv_translate_sys_error(GetLastError());
1046   }
1047 
1048   ret = GetProcessMemoryInfo(GetCurrentProcess(),
1049                              &memCounters,
1050                              sizeof(memCounters));
1051   if (ret == 0) {
1052     return uv_translate_sys_error(GetLastError());
1053   }
1054 
1055   ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
1056   if (ret == 0) {
1057     return uv_translate_sys_error(GetLastError());
1058   }
1059 
1060   memset(uv_rusage, 0, sizeof(*uv_rusage));
1061 
1062   uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
1063                                userSystemTime.wMinute * 60 +
1064                                userSystemTime.wSecond;
1065   uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
1066 
1067   uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
1068                                kernelSystemTime.wMinute * 60 +
1069                                kernelSystemTime.wSecond;
1070   uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
1071 
1072   uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
1073   uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
1074 
1075   uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
1076   uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
1077 
1078   return 0;
1079 }
1080 
1081 
uv_os_homedir(char * buffer,size_t * size)1082 int uv_os_homedir(char* buffer, size_t* size) {
1083   uv_passwd_t pwd;
1084   size_t len;
1085   int r;
1086 
1087   /* Check if the USERPROFILE environment variable is set first. The task of
1088      performing input validation on buffer and size is taken care of by
1089      uv_os_getenv(). */
1090   r = uv_os_getenv("USERPROFILE", buffer, size);
1091 
1092   /* Don't return an error if USERPROFILE was not found. */
1093   if (r != UV_ENOENT)
1094     return r;
1095 
1096   /* USERPROFILE is not set, so call uv__getpwuid_r() */
1097   r = uv__getpwuid_r(&pwd);
1098 
1099   if (r != 0) {
1100     return r;
1101   }
1102 
1103   len = strlen(pwd.homedir);
1104 
1105   if (len >= *size) {
1106     *size = len + 1;
1107     uv_os_free_passwd(&pwd);
1108     return UV_ENOBUFS;
1109   }
1110 
1111   memcpy(buffer, pwd.homedir, len + 1);
1112   *size = len;
1113   uv_os_free_passwd(&pwd);
1114 
1115   return 0;
1116 }
1117 
1118 
uv_os_tmpdir(char * buffer,size_t * size)1119 int uv_os_tmpdir(char* buffer, size_t* size) {
1120   wchar_t *path;
1121   DWORD bufsize;
1122   size_t len;
1123 
1124   if (buffer == NULL || size == NULL || *size == 0)
1125     return UV_EINVAL;
1126 
1127   len = 0;
1128   len = GetTempPathW(0, NULL);
1129   if (len == 0) {
1130     return uv_translate_sys_error(GetLastError());
1131   }
1132   /* Include space for terminating null char. */
1133   len += 1;
1134   path = uv__malloc(len * sizeof(wchar_t));
1135   if (path == NULL) {
1136     return UV_ENOMEM;
1137   }
1138   len  = GetTempPathW(len, path);
1139 
1140   if (len == 0) {
1141     uv__free(path);
1142     return uv_translate_sys_error(GetLastError());
1143   }
1144 
1145   /* The returned directory should not have a trailing slash, unless it points
1146    * at a drive root, like c:\. Remove it if needed. */
1147   if (path[len - 1] == L'\\' &&
1148       !(len == 3 && path[1] == L':')) {
1149     len--;
1150     path[len] = L'\0';
1151   }
1152 
1153   /* Check how much space we need */
1154   bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
1155 
1156   if (bufsize == 0) {
1157     uv__free(path);
1158     return uv_translate_sys_error(GetLastError());
1159   } else if (bufsize > *size) {
1160     uv__free(path);
1161     *size = bufsize;
1162     return UV_ENOBUFS;
1163   }
1164 
1165   /* Convert to UTF-8 */
1166   bufsize = WideCharToMultiByte(CP_UTF8,
1167                                 0,
1168                                 path,
1169                                 -1,
1170                                 buffer,
1171                                 *size,
1172                                 NULL,
1173                                 NULL);
1174   uv__free(path);
1175 
1176   if (bufsize == 0)
1177     return uv_translate_sys_error(GetLastError());
1178 
1179   *size = bufsize - 1;
1180   return 0;
1181 }
1182 
1183 
uv_os_free_passwd(uv_passwd_t * pwd)1184 void uv_os_free_passwd(uv_passwd_t* pwd) {
1185   if (pwd == NULL)
1186     return;
1187 
1188   uv__free(pwd->username);
1189   uv__free(pwd->homedir);
1190   pwd->username = NULL;
1191   pwd->homedir = NULL;
1192 }
1193 
1194 
1195 /*
1196  * Converts a UTF-16 string into a UTF-8 one. The resulting string is
1197  * null-terminated.
1198  *
1199  * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
1200  * be specified.
1201  */
uv__convert_utf16_to_utf8(const WCHAR * utf16,int utf16len,char ** utf8)1202 int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
1203   DWORD bufsize;
1204 
1205   if (utf16 == NULL)
1206     return UV_EINVAL;
1207 
1208   /* Check how much space we need */
1209   bufsize = WideCharToMultiByte(CP_UTF8,
1210                                 0,
1211                                 utf16,
1212                                 utf16len,
1213                                 NULL,
1214                                 0,
1215                                 NULL,
1216                                 NULL);
1217 
1218   if (bufsize == 0)
1219     return uv_translate_sys_error(GetLastError());
1220 
1221   /* Allocate the destination buffer adding an extra byte for the terminating
1222    * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
1223    * we do it ourselves always, just in case. */
1224   *utf8 = uv__malloc(bufsize + 1);
1225 
1226   if (*utf8 == NULL)
1227     return UV_ENOMEM;
1228 
1229   /* Convert to UTF-8 */
1230   bufsize = WideCharToMultiByte(CP_UTF8,
1231                                 0,
1232                                 utf16,
1233                                 utf16len,
1234                                 *utf8,
1235                                 bufsize,
1236                                 NULL,
1237                                 NULL);
1238 
1239   if (bufsize == 0) {
1240     uv__free(*utf8);
1241     *utf8 = NULL;
1242     return uv_translate_sys_error(GetLastError());
1243   }
1244 
1245   (*utf8)[bufsize] = '\0';
1246   return 0;
1247 }
1248 
1249 
1250 /*
1251  * Converts a UTF-8 string into a UTF-16 one. The resulting string is
1252  * null-terminated.
1253  *
1254  * If utf8 is null terminated, utf8len can be set to -1, otherwise it must
1255  * be specified.
1256  */
uv__convert_utf8_to_utf16(const char * utf8,int utf8len,WCHAR ** utf16)1257 int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
1258   int bufsize;
1259 
1260   if (utf8 == NULL)
1261     return UV_EINVAL;
1262 
1263   /* Check how much space we need */
1264   bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
1265 
1266   if (bufsize == 0)
1267     return uv_translate_sys_error(GetLastError());
1268 
1269   /* Allocate the destination buffer adding an extra byte for the terminating
1270    * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
1271    * we do it ourselves always, just in case. */
1272   *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1));
1273 
1274   if (*utf16 == NULL)
1275     return UV_ENOMEM;
1276 
1277   /* Convert to UTF-16 */
1278   bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
1279 
1280   if (bufsize == 0) {
1281     uv__free(*utf16);
1282     *utf16 = NULL;
1283     return uv_translate_sys_error(GetLastError());
1284   }
1285 
1286   (*utf16)[bufsize] = L'\0';
1287   return 0;
1288 }
1289 
1290 
uv__getpwuid_r(uv_passwd_t * pwd)1291 int uv__getpwuid_r(uv_passwd_t* pwd) {
1292   HANDLE token;
1293   wchar_t username[UNLEN + 1];
1294   wchar_t *path;
1295   DWORD bufsize;
1296   int r;
1297 
1298   if (pwd == NULL)
1299     return UV_EINVAL;
1300 
1301   /* Get the home directory using GetUserProfileDirectoryW() */
1302   if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
1303     return uv_translate_sys_error(GetLastError());
1304 
1305   bufsize = 0;
1306   GetUserProfileDirectoryW(token, NULL, &bufsize);
1307   if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1308     r = GetLastError();
1309     CloseHandle(token);
1310     return uv_translate_sys_error(r);
1311   }
1312 
1313   path = uv__malloc(bufsize * sizeof(wchar_t));
1314   if (path == NULL) {
1315     CloseHandle(token);
1316     return UV_ENOMEM;
1317   }
1318 
1319   if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
1320     r = GetLastError();
1321     CloseHandle(token);
1322     uv__free(path);
1323     return uv_translate_sys_error(r);
1324   }
1325 
1326   CloseHandle(token);
1327 
1328   /* Get the username using GetUserNameW() */
1329   bufsize = ARRAY_SIZE(username);
1330   if (!GetUserNameW(username, &bufsize)) {
1331     r = GetLastError();
1332     uv__free(path);
1333 
1334     /* This should not be possible */
1335     if (r == ERROR_INSUFFICIENT_BUFFER)
1336       return UV_ENOMEM;
1337 
1338     return uv_translate_sys_error(r);
1339   }
1340 
1341   pwd->homedir = NULL;
1342   r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
1343   uv__free(path);
1344 
1345   if (r != 0)
1346     return r;
1347 
1348   pwd->username = NULL;
1349   r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
1350 
1351   if (r != 0) {
1352     uv__free(pwd->homedir);
1353     return r;
1354   }
1355 
1356   pwd->shell = NULL;
1357   pwd->uid = -1;
1358   pwd->gid = -1;
1359 
1360   return 0;
1361 }
1362 
1363 
uv_os_get_passwd(uv_passwd_t * pwd)1364 int uv_os_get_passwd(uv_passwd_t* pwd) {
1365   return uv__getpwuid_r(pwd);
1366 }
1367 
1368 
uv_os_environ(uv_env_item_t ** envitems,int * count)1369 int uv_os_environ(uv_env_item_t** envitems, int* count) {
1370   wchar_t* env;
1371   wchar_t* penv;
1372   int i, cnt;
1373   uv_env_item_t* envitem;
1374 
1375   *envitems = NULL;
1376   *count = 0;
1377 
1378   env = GetEnvironmentStringsW();
1379   if (env == NULL)
1380     return 0;
1381 
1382   for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
1383 
1384   *envitems = uv__calloc(i, sizeof(**envitems));
1385   if (*envitems == NULL) {
1386     FreeEnvironmentStringsW(env);
1387     return UV_ENOMEM;
1388   }
1389 
1390   penv = env;
1391   cnt = 0;
1392 
1393   while (*penv != L'\0' && cnt < i) {
1394     char* buf;
1395     char* ptr;
1396 
1397     if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
1398       goto fail;
1399 
1400     /* Using buf + 1 here because we know that `buf` has length at least 1,
1401      * and some special environment variables on Windows start with a = sign. */
1402     ptr = strchr(buf + 1, '=');
1403     if (ptr == NULL) {
1404       uv__free(buf);
1405       goto do_continue;
1406     }
1407 
1408     *ptr = '\0';
1409 
1410     envitem = &(*envitems)[cnt];
1411     envitem->name = buf;
1412     envitem->value = ptr + 1;
1413 
1414     cnt++;
1415 
1416   do_continue:
1417     penv += wcslen(penv) + 1;
1418   }
1419 
1420   FreeEnvironmentStringsW(env);
1421 
1422   *count = cnt;
1423   return 0;
1424 
1425 fail:
1426   FreeEnvironmentStringsW(env);
1427 
1428   for (i = 0; i < cnt; i++) {
1429     envitem = &(*envitems)[cnt];
1430     uv__free(envitem->name);
1431   }
1432   uv__free(*envitems);
1433 
1434   *envitems = NULL;
1435   *count = 0;
1436   return UV_ENOMEM;
1437 }
1438 
1439 
uv_os_getenv(const char * name,char * buffer,size_t * size)1440 int uv_os_getenv(const char* name, char* buffer, size_t* size) {
1441   wchar_t fastvar[512];
1442   wchar_t* var;
1443   DWORD varlen;
1444   wchar_t* name_w;
1445   DWORD bufsize;
1446   size_t len;
1447   int r;
1448 
1449   if (name == NULL || buffer == NULL || size == NULL || *size == 0)
1450     return UV_EINVAL;
1451 
1452   r = uv__convert_utf8_to_utf16(name, -1, &name_w);
1453 
1454   if (r != 0)
1455     return r;
1456 
1457   var = fastvar;
1458   varlen = ARRAY_SIZE(fastvar);
1459 
1460   for (;;) {
1461     SetLastError(ERROR_SUCCESS);
1462     len = GetEnvironmentVariableW(name_w, var, varlen);
1463 
1464     if (len < varlen)
1465       break;
1466 
1467     /* Try repeatedly because we might have been preempted by another thread
1468      * modifying the environment variable just as we're trying to read it.
1469      */
1470     if (var != fastvar)
1471       uv__free(var);
1472 
1473     varlen = 1 + len;
1474     var = uv__malloc(varlen * sizeof(*var));
1475 
1476     if (var == NULL) {
1477       r = UV_ENOMEM;
1478       goto fail;
1479     }
1480   }
1481 
1482   uv__free(name_w);
1483   name_w = NULL;
1484 
1485   if (len == 0) {
1486     r = GetLastError();
1487     if (r != ERROR_SUCCESS) {
1488       r = uv_translate_sys_error(r);
1489       goto fail;
1490     }
1491   }
1492 
1493   /* Check how much space we need */
1494   bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
1495 
1496   if (bufsize == 0) {
1497     r = uv_translate_sys_error(GetLastError());
1498     goto fail;
1499   } else if (bufsize > *size) {
1500     *size = bufsize;
1501     r = UV_ENOBUFS;
1502     goto fail;
1503   }
1504 
1505   /* Convert to UTF-8 */
1506   bufsize = WideCharToMultiByte(CP_UTF8,
1507                                 0,
1508                                 var,
1509                                 -1,
1510                                 buffer,
1511                                 *size,
1512                                 NULL,
1513                                 NULL);
1514 
1515   if (bufsize == 0) {
1516     r = uv_translate_sys_error(GetLastError());
1517     goto fail;
1518   }
1519 
1520   *size = bufsize - 1;
1521   r = 0;
1522 
1523 fail:
1524 
1525   if (name_w != NULL)
1526     uv__free(name_w);
1527 
1528   if (var != fastvar)
1529     uv__free(var);
1530 
1531   return r;
1532 }
1533 
1534 
uv_os_setenv(const char * name,const char * value)1535 int uv_os_setenv(const char* name, const char* value) {
1536   wchar_t* name_w;
1537   wchar_t* value_w;
1538   int r;
1539 
1540   if (name == NULL || value == NULL)
1541     return UV_EINVAL;
1542 
1543   r = uv__convert_utf8_to_utf16(name, -1, &name_w);
1544 
1545   if (r != 0)
1546     return r;
1547 
1548   r = uv__convert_utf8_to_utf16(value, -1, &value_w);
1549 
1550   if (r != 0) {
1551     uv__free(name_w);
1552     return r;
1553   }
1554 
1555   r = SetEnvironmentVariableW(name_w, value_w);
1556   uv__free(name_w);
1557   uv__free(value_w);
1558 
1559   if (r == 0)
1560     return uv_translate_sys_error(GetLastError());
1561 
1562   return 0;
1563 }
1564 
1565 
uv_os_unsetenv(const char * name)1566 int uv_os_unsetenv(const char* name) {
1567   wchar_t* name_w;
1568   int r;
1569 
1570   if (name == NULL)
1571     return UV_EINVAL;
1572 
1573   r = uv__convert_utf8_to_utf16(name, -1, &name_w);
1574 
1575   if (r != 0)
1576     return r;
1577 
1578   r = SetEnvironmentVariableW(name_w, NULL);
1579   uv__free(name_w);
1580 
1581   if (r == 0)
1582     return uv_translate_sys_error(GetLastError());
1583 
1584   return 0;
1585 }
1586 
1587 
uv_os_gethostname(char * buffer,size_t * size)1588 int uv_os_gethostname(char* buffer, size_t* size) {
1589   WCHAR buf[UV_MAXHOSTNAMESIZE];
1590   size_t len;
1591   char* utf8_str;
1592   int convert_result;
1593 
1594   if (buffer == NULL || size == NULL || *size == 0)
1595     return UV_EINVAL;
1596 
1597   uv__once_init(); /* Initialize winsock */
1598 
1599   if (pGetHostNameW == NULL)
1600     return UV_ENOSYS;
1601 
1602   if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
1603     return uv_translate_sys_error(WSAGetLastError());
1604 
1605   convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
1606 
1607   if (convert_result != 0)
1608     return convert_result;
1609 
1610   len = strlen(utf8_str);
1611   if (len >= *size) {
1612     *size = len + 1;
1613     uv__free(utf8_str);
1614     return UV_ENOBUFS;
1615   }
1616 
1617   memcpy(buffer, utf8_str, len + 1);
1618   uv__free(utf8_str);
1619   *size = len;
1620   return 0;
1621 }
1622 
1623 
uv__get_handle(uv_pid_t pid,int access,HANDLE * handle)1624 static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
1625   int r;
1626 
1627   if (pid == 0)
1628     *handle = GetCurrentProcess();
1629   else
1630     *handle = OpenProcess(access, FALSE, pid);
1631 
1632   if (*handle == NULL) {
1633     r = GetLastError();
1634 
1635     if (r == ERROR_INVALID_PARAMETER)
1636       return UV_ESRCH;
1637     else
1638       return uv_translate_sys_error(r);
1639   }
1640 
1641   return 0;
1642 }
1643 
1644 
uv_os_getpriority(uv_pid_t pid,int * priority)1645 int uv_os_getpriority(uv_pid_t pid, int* priority) {
1646   HANDLE handle;
1647   int r;
1648 
1649   if (priority == NULL)
1650     return UV_EINVAL;
1651 
1652   r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
1653 
1654   if (r != 0)
1655     return r;
1656 
1657   r = GetPriorityClass(handle);
1658 
1659   if (r == 0) {
1660     r = uv_translate_sys_error(GetLastError());
1661   } else {
1662     /* Map Windows priority classes to Unix nice values. */
1663     if (r == REALTIME_PRIORITY_CLASS)
1664       *priority = UV_PRIORITY_HIGHEST;
1665     else if (r == HIGH_PRIORITY_CLASS)
1666       *priority = UV_PRIORITY_HIGH;
1667     else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
1668       *priority = UV_PRIORITY_ABOVE_NORMAL;
1669     else if (r == NORMAL_PRIORITY_CLASS)
1670       *priority = UV_PRIORITY_NORMAL;
1671     else if (r == BELOW_NORMAL_PRIORITY_CLASS)
1672       *priority = UV_PRIORITY_BELOW_NORMAL;
1673     else  /* IDLE_PRIORITY_CLASS */
1674       *priority = UV_PRIORITY_LOW;
1675 
1676     r = 0;
1677   }
1678 
1679   CloseHandle(handle);
1680   return r;
1681 }
1682 
1683 
uv_os_setpriority(uv_pid_t pid,int priority)1684 int uv_os_setpriority(uv_pid_t pid, int priority) {
1685   HANDLE handle;
1686   int priority_class;
1687   int r;
1688 
1689   /* Map Unix nice values to Windows priority classes. */
1690   if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
1691     return UV_EINVAL;
1692   else if (priority < UV_PRIORITY_HIGH)
1693     priority_class = REALTIME_PRIORITY_CLASS;
1694   else if (priority < UV_PRIORITY_ABOVE_NORMAL)
1695     priority_class = HIGH_PRIORITY_CLASS;
1696   else if (priority < UV_PRIORITY_NORMAL)
1697     priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
1698   else if (priority < UV_PRIORITY_BELOW_NORMAL)
1699     priority_class = NORMAL_PRIORITY_CLASS;
1700   else if (priority < UV_PRIORITY_LOW)
1701     priority_class = BELOW_NORMAL_PRIORITY_CLASS;
1702   else
1703     priority_class = IDLE_PRIORITY_CLASS;
1704 
1705   r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
1706 
1707   if (r != 0)
1708     return r;
1709 
1710   if (SetPriorityClass(handle, priority_class) == 0)
1711     r = uv_translate_sys_error(GetLastError());
1712 
1713   CloseHandle(handle);
1714   return r;
1715 }
1716 
1717 
uv_os_uname(uv_utsname_t * buffer)1718 int uv_os_uname(uv_utsname_t* buffer) {
1719   /* Implementation loosely based on
1720      https://github.com/gagern/gnulib/blob/master/lib/uname.c */
1721   OSVERSIONINFOW os_info;
1722   SYSTEM_INFO system_info;
1723   HKEY registry_key;
1724   WCHAR product_name_w[256];
1725   DWORD product_name_w_size;
1726   int version_size;
1727   int processor_level;
1728   int r;
1729 
1730   if (buffer == NULL)
1731     return UV_EINVAL;
1732 
1733   uv__once_init();
1734   os_info.dwOSVersionInfoSize = sizeof(os_info);
1735   os_info.szCSDVersion[0] = L'\0';
1736 
1737   /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
1738      if RtlGetVersion() is not available. */
1739   if (pRtlGetVersion) {
1740     pRtlGetVersion(&os_info);
1741   } else {
1742     /* Silence GetVersionEx() deprecation warning. */
1743     #ifdef _MSC_VER
1744     #pragma warning(suppress : 4996)
1745     #endif
1746     if (GetVersionExW(&os_info) == 0) {
1747       r = uv_translate_sys_error(GetLastError());
1748       goto error;
1749     }
1750   }
1751 
1752   /* Populate the version field. */
1753   version_size = 0;
1754   r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1755                     L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
1756                     0,
1757                     KEY_QUERY_VALUE,
1758                     &registry_key);
1759 
1760   if (r == ERROR_SUCCESS) {
1761     product_name_w_size = sizeof(product_name_w);
1762     r = RegGetValueW(registry_key,
1763                      NULL,
1764                      L"ProductName",
1765                      RRF_RT_REG_SZ,
1766                      NULL,
1767                      (PVOID) product_name_w,
1768                      &product_name_w_size);
1769     RegCloseKey(registry_key);
1770 
1771     if (r == ERROR_SUCCESS) {
1772       version_size = WideCharToMultiByte(CP_UTF8,
1773                                          0,
1774                                          product_name_w,
1775                                          -1,
1776                                          buffer->version,
1777                                          sizeof(buffer->version),
1778                                          NULL,
1779                                          NULL);
1780       if (version_size == 0) {
1781         r = uv_translate_sys_error(GetLastError());
1782         goto error;
1783       }
1784     }
1785   }
1786 
1787   /* Append service pack information to the version if present. */
1788   if (os_info.szCSDVersion[0] != L'\0') {
1789     if (version_size > 0)
1790       buffer->version[version_size - 1] = ' ';
1791 
1792     if (WideCharToMultiByte(CP_UTF8,
1793                             0,
1794                             os_info.szCSDVersion,
1795                             -1,
1796                             buffer->version + version_size,
1797                             sizeof(buffer->version) - version_size,
1798                             NULL,
1799                             NULL) == 0) {
1800       r = uv_translate_sys_error(GetLastError());
1801       goto error;
1802     }
1803   }
1804 
1805   /* Populate the sysname field. */
1806 #ifdef __MINGW32__
1807   r = snprintf(buffer->sysname,
1808                sizeof(buffer->sysname),
1809                "MINGW32_NT-%u.%u",
1810                (unsigned int) os_info.dwMajorVersion,
1811                (unsigned int) os_info.dwMinorVersion);
1812   assert((size_t)r < sizeof(buffer->sysname));
1813 #else
1814   uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
1815 #endif
1816 
1817   /* Populate the release field. */
1818   r = snprintf(buffer->release,
1819                sizeof(buffer->release),
1820                "%d.%d.%d",
1821                (unsigned int) os_info.dwMajorVersion,
1822                (unsigned int) os_info.dwMinorVersion,
1823                (unsigned int) os_info.dwBuildNumber);
1824   assert((size_t)r < sizeof(buffer->release));
1825 
1826   /* Populate the machine field. */
1827   GetSystemInfo(&system_info);
1828 
1829   switch (system_info.wProcessorArchitecture) {
1830     case PROCESSOR_ARCHITECTURE_AMD64:
1831       uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
1832       break;
1833     case PROCESSOR_ARCHITECTURE_IA64:
1834       uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
1835       break;
1836     case PROCESSOR_ARCHITECTURE_INTEL:
1837       uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
1838 
1839       if (system_info.wProcessorLevel > 3) {
1840         processor_level = system_info.wProcessorLevel < 6 ?
1841                           system_info.wProcessorLevel : 6;
1842         buffer->machine[1] = '0' + processor_level;
1843       }
1844 
1845       break;
1846     case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1847       uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
1848       break;
1849     case PROCESSOR_ARCHITECTURE_MIPS:
1850       uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
1851       break;
1852     case PROCESSOR_ARCHITECTURE_ALPHA:
1853     case PROCESSOR_ARCHITECTURE_ALPHA64:
1854       uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
1855       break;
1856     case PROCESSOR_ARCHITECTURE_PPC:
1857       uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
1858       break;
1859     case PROCESSOR_ARCHITECTURE_SHX:
1860       uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
1861       break;
1862     case PROCESSOR_ARCHITECTURE_ARM:
1863       uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
1864       break;
1865     default:
1866       uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
1867       break;
1868   }
1869 
1870   return 0;
1871 
1872 error:
1873   buffer->sysname[0] = '\0';
1874   buffer->release[0] = '\0';
1875   buffer->version[0] = '\0';
1876   buffer->machine[0] = '\0';
1877   return r;
1878 }
1879 
uv_gettimeofday(uv_timeval64_t * tv)1880 int uv_gettimeofday(uv_timeval64_t* tv) {
1881   /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
1882   const uint64_t epoch = (uint64_t) 116444736000000000ULL;
1883   FILETIME file_time;
1884   ULARGE_INTEGER ularge;
1885 
1886   if (tv == NULL)
1887     return UV_EINVAL;
1888 
1889   GetSystemTimeAsFileTime(&file_time);
1890   ularge.LowPart = file_time.dwLowDateTime;
1891   ularge.HighPart = file_time.dwHighDateTime;
1892   tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
1893   tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
1894   return 0;
1895 }
1896 
uv__random_rtlgenrandom(void * buf,size_t buflen)1897 int uv__random_rtlgenrandom(void* buf, size_t buflen) {
1898   if (buflen == 0)
1899     return 0;
1900 
1901   if (SystemFunction036(buf, buflen) == FALSE)
1902     return UV_EIO;
1903 
1904   return 0;
1905 }
1906 
uv_sleep(unsigned int msec)1907 void uv_sleep(unsigned int msec) {
1908   Sleep(msec);
1909 }
1910