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