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