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