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