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