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