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