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