libuv-svace-build

Форк
0
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 8192
56

57
/* The number of nanoseconds in one second. */
58
#define UV__NANOSEC 1000000000
59

60
/* Max user name length, from iphlpapi.h */
61
#ifndef UNLEN
62
# define UNLEN 256
63
#endif
64

65

66
/* A RtlGenRandom() by any other name... */
67
extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
68

69
/* Cached copy of the process title, plus a mutex guarding it. */
70
static char *process_title;
71
static CRITICAL_SECTION process_title_lock;
72

73
/* Frequency of the high-resolution clock. */
74
static uint64_t hrtime_frequency_ = 0;
75

76

77
/*
78
 * One-time initialization code for functionality defined in util.c.
79
 */
80
void uv__util_init(void) {
81
  LARGE_INTEGER perf_frequency;
82

83
  /* Initialize process title access mutex. */
84
  InitializeCriticalSection(&process_title_lock);
85

86
  /* Retrieve high-resolution timer frequency
87
   * and precompute its reciprocal.
88
   */
89
  if (QueryPerformanceFrequency(&perf_frequency)) {
90
    hrtime_frequency_ = perf_frequency.QuadPart;
91
  } else {
92
    uv_fatal_error(GetLastError(), "QueryPerformanceFrequency");
93
  }
94
}
95

96

97
int uv_exepath(char* buffer, size_t* size_ptr) {
98
  size_t utf8_len, utf16_buffer_len, utf16_len;
99
  WCHAR* utf16_buffer;
100
  int err;
101

102
  if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
103
    return UV_EINVAL;
104
  }
105

106
  if (*size_ptr > 32768) {
107
    /* Windows paths can never be longer than this. */
108
    utf16_buffer_len = 32768;
109
  } else {
110
    utf16_buffer_len = (int) *size_ptr;
111
  }
112

113
  utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
114
  if (!utf16_buffer) {
115
    return UV_ENOMEM;
116
  }
117

118
  /* Get the path as UTF-16. */
119
  utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
120
  if (utf16_len <= 0) {
121
    err = GetLastError();
122
    goto error;
123
  }
124

125
  /* Convert to UTF-8 */
126
  utf8_len = *size_ptr - 1; /* Reserve space for NUL */
127
  err = uv_utf16_to_wtf8(utf16_buffer, utf16_len, &buffer, &utf8_len);
128
  if (err == UV_ENOBUFS) {
129
    utf8_len = *size_ptr - 1;
130
    err = 0;
131
  }
132
  *size_ptr = utf8_len;
133

134
  uv__free(utf16_buffer);
135

136
  return err;
137

138
 error:
139
  uv__free(utf16_buffer);
140
  return uv_translate_sys_error(err);
141
}
142

143

144
static int uv__cwd(WCHAR** buf, DWORD *len) {
145
  WCHAR* p;
146
  DWORD n;
147
  DWORD t;
148

149
  t = GetCurrentDirectoryW(0, NULL);
150
  for (;;) {
151
    if (t == 0)
152
      return uv_translate_sys_error(GetLastError());
153

154
    /* |t| is the size of the buffer _including_ nul. */
155
    p = uv__malloc(t * sizeof(*p));
156
    if (p == NULL)
157
      return UV_ENOMEM;
158

159
    /* |n| is the size of the buffer _excluding_ nul but _only on success_.
160
     * If |t| was too small because another thread changed the working
161
     * directory, |n| is the size the buffer should be _including_ nul.
162
     * It therefore follows we must resize when n >= t and fail when n == 0.
163
     */
164
    n = GetCurrentDirectoryW(t, p);
165
    if (n > 0)
166
      if (n < t)
167
        break;
168

169
    uv__free(p);
170
    t = n;
171
  }
172

173
  /* The returned directory should not have a trailing slash, unless it points
174
   * at a drive root, like c:\. Remove it if needed.
175
   */
176
  t = n - 1;
177
  if (p[t] == L'\\' && !(n == 3 && p[1] == L':')) {
178
    p[t] = L'\0';
179
    n = t;
180
  }
181

182
  *buf = p;
183
  *len = n;
184

185
  return 0;
186
}
187

188

189
int uv_cwd(char* buffer, size_t* size) {
190
  DWORD utf16_len;
191
  WCHAR *utf16_buffer;
192
  int r;
193

194
  if (buffer == NULL || size == NULL) {
195
    return UV_EINVAL;
196
  }
197

198
  r = uv__cwd(&utf16_buffer, &utf16_len);
199
  if (r < 0)
200
    return r;
201

202
  r = uv__copy_utf16_to_utf8(utf16_buffer, utf16_len, buffer, size);
203

204
  uv__free(utf16_buffer);
205

206
  return r;
207
}
208

209

210
int uv_chdir(const char* dir) {
211
  WCHAR *utf16_buffer;
212
  DWORD utf16_len;
213
  WCHAR drive_letter, env_var[4];
214
  int r;
215

216
  /* Convert to UTF-16 */
217
  r = uv__convert_utf8_to_utf16(dir, &utf16_buffer);
218
  if (r)
219
    return r;
220

221
  if (!SetCurrentDirectoryW(utf16_buffer)) {
222
    uv__free(utf16_buffer);
223
    return uv_translate_sys_error(GetLastError());
224
  }
225

226
  /* uv__cwd() will return a new buffer. */
227
  uv__free(utf16_buffer);
228
  utf16_buffer = NULL;
229

230
  /* Windows stores the drive-local path in an "hidden" environment variable,
231
   * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
232
   * this, so we'll have to do it. */
233
  r = uv__cwd(&utf16_buffer, &utf16_len);
234
  if (r == UV_ENOMEM) {
235
    /* When updating the environment variable fails, return UV_OK anyway.
236
     * We did successfully change current working directory, only updating
237
     * hidden env variable failed. */
238
    return 0;
239
  }
240
  if (r < 0) {
241
    return r;
242
  }
243

244
  if (utf16_len < 2 || utf16_buffer[1] != L':') {
245
    /* Doesn't look like a drive letter could be there - probably an UNC path.
246
     * TODO: Need to handle win32 namespaces like \\?\C:\ ? */
247
    drive_letter = 0;
248
  } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
249
    drive_letter = utf16_buffer[0];
250
  } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
251
    /* Convert to uppercase. */
252
    drive_letter = utf16_buffer[0] - L'a' + L'A';
253
  } else {
254
    /* Not valid. */
255
    drive_letter = 0;
256
  }
257

258
  if (drive_letter != 0) {
259
    /* Construct the environment variable name and set it. */
260
    env_var[0] = L'=';
261
    env_var[1] = drive_letter;
262
    env_var[2] = L':';
263
    env_var[3] = L'\0';
264

265
    SetEnvironmentVariableW(env_var, utf16_buffer);
266
  }
267

268
  uv__free(utf16_buffer);
269
  return 0;
270
}
271

272

273
void uv_loadavg(double avg[3]) {
274
  /* Can't be implemented */
275
  avg[0] = avg[1] = avg[2] = 0;
276
}
277

278

279
uint64_t uv_get_free_memory(void) {
280
  MEMORYSTATUSEX memory_status;
281
  memory_status.dwLength = sizeof(memory_status);
282

283
  if (!GlobalMemoryStatusEx(&memory_status)) {
284
     return 0;
285
  }
286

287
  return (uint64_t)memory_status.ullAvailPhys;
288
}
289

290

291
uint64_t uv_get_total_memory(void) {
292
  MEMORYSTATUSEX memory_status;
293
  memory_status.dwLength = sizeof(memory_status);
294

295
  if (!GlobalMemoryStatusEx(&memory_status)) {
296
    return 0;
297
  }
298

299
  return (uint64_t)memory_status.ullTotalPhys;
300
}
301

302

303
uint64_t uv_get_constrained_memory(void) {
304
  return 0;  /* Memory constraints are unknown. */
305
}
306

307

308
uint64_t uv_get_available_memory(void) {
309
  return uv_get_free_memory();
310
}
311

312

313
uv_pid_t uv_os_getpid(void) {
314
  return GetCurrentProcessId();
315
}
316

317

318
uv_pid_t uv_os_getppid(void) {
319
  int parent_pid = -1;
320
  HANDLE handle;
321
  PROCESSENTRY32 pe;
322
  DWORD current_pid = GetCurrentProcessId();
323

324
  pe.dwSize = sizeof(PROCESSENTRY32);
325
  handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
326

327
  if (Process32First(handle, &pe)) {
328
    do {
329
      if (pe.th32ProcessID == current_pid) {
330
        parent_pid = pe.th32ParentProcessID;
331
        break;
332
      }
333
    } while( Process32Next(handle, &pe));
334
  }
335

336
  CloseHandle(handle);
337
  return parent_pid;
338
}
339

340

341
char** uv_setup_args(int argc, char** argv) {
342
  return argv;
343
}
344

345

346
void uv__process_title_cleanup(void) {
347
}
348

349

350
int uv_set_process_title(const char* title) {
351
  int err;
352
  int length;
353
  WCHAR* title_w = NULL;
354

355
  uv__once_init();
356

357
  err = uv__convert_utf8_to_utf16(title, &title_w);
358
  if (err)
359
    return err;
360

361
  /* If the title must be truncated insert a \0 terminator there */
362
  length = wcslen(title_w);
363
  if (length >= MAX_TITLE_LENGTH)
364
    title_w[MAX_TITLE_LENGTH - 1] = L'\0';
365

366
  if (!SetConsoleTitleW(title_w)) {
367
    err = GetLastError();
368
    goto done;
369
  }
370

371
  EnterCriticalSection(&process_title_lock);
372
  uv__free(process_title);
373
  process_title = uv__strdup(title);
374
  LeaveCriticalSection(&process_title_lock);
375

376
  err = 0;
377

378
done:
379
  uv__free(title_w);
380
  return uv_translate_sys_error(err);
381
}
382

383

384
static int uv__get_process_title(void) {
385
  WCHAR title_w[MAX_TITLE_LENGTH];
386
  DWORD wlen;
387

388
  wlen = GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR));
389
  if (wlen == 0)
390
    return uv_translate_sys_error(GetLastError());
391

392
  return uv__convert_utf16_to_utf8(title_w, wlen, &process_title);
393
}
394

395

396
int uv_get_process_title(char* buffer, size_t size) {
397
  size_t len;
398
  int r;
399

400
  if (buffer == NULL || size == 0)
401
    return UV_EINVAL;
402

403
  uv__once_init();
404

405
  EnterCriticalSection(&process_title_lock);
406
  /*
407
   * If the process_title was never read before nor explicitly set,
408
   * we must query it with getConsoleTitleW
409
   */
410
  if (process_title == NULL) {
411
    r = uv__get_process_title();
412
    if (r) {
413
      LeaveCriticalSection(&process_title_lock);
414
      return r;
415
    }
416
  }
417

418
  assert(process_title);
419
  len = strlen(process_title) + 1;
420

421
  if (size < len) {
422
    LeaveCriticalSection(&process_title_lock);
423
    return UV_ENOBUFS;
424
  }
425

426
  memcpy(buffer, process_title, len);
427
  LeaveCriticalSection(&process_title_lock);
428

429
  return 0;
430
}
431

432

433
/* https://github.com/libuv/libuv/issues/1674 */
434
int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) {
435
  FILETIME ft;
436
  int64_t t;
437

438
  if (ts == NULL)
439
    return UV_EFAULT;
440

441
  switch (clock_id) {
442
    case UV_CLOCK_MONOTONIC:
443
      uv__once_init();
444
      t = uv__hrtime(UV__NANOSEC);
445
      ts->tv_sec = t / 1000000000;
446
      ts->tv_nsec = t % 1000000000;
447
      return 0;
448
    case UV_CLOCK_REALTIME:
449
      GetSystemTimePreciseAsFileTime(&ft);
450
      /* In 100-nanosecond increments from 1601-01-01 UTC because why not? */
451
      t = (int64_t) ft.dwHighDateTime << 32 | ft.dwLowDateTime;
452
      /* Convert to UNIX epoch, 1970-01-01. Still in 100 ns increments. */
453
      t -= 116444736000000000ll;
454
      /* Now convert to seconds and nanoseconds. */
455
      ts->tv_sec = t / 10000000;
456
      ts->tv_nsec = t % 10000000 * 100;
457
      return 0;
458
  }
459

460
  return UV_EINVAL;
461
}
462

463

464
uint64_t uv_hrtime(void) {
465
  uv__once_init();
466
  return uv__hrtime(UV__NANOSEC);
467
}
468

469

470
uint64_t uv__hrtime(unsigned int scale) {
471
  LARGE_INTEGER counter;
472
  double scaled_freq;
473
  double result;
474

475
  assert(hrtime_frequency_ != 0);
476
  assert(scale != 0);
477
  if (!QueryPerformanceCounter(&counter)) {
478
    uv_fatal_error(GetLastError(), "QueryPerformanceCounter");
479
  }
480
  assert(counter.QuadPart != 0);
481

482
  /* Because we have no guarantee about the order of magnitude of the
483
   * performance counter interval, integer math could cause this computation
484
   * to overflow. Therefore we resort to floating point math.
485
   */
486
  scaled_freq = (double) hrtime_frequency_ / scale;
487
  result = (double) counter.QuadPart / scaled_freq;
488
  return (uint64_t) result;
489
}
490

491

492
int uv_resident_set_memory(size_t* rss) {
493
  HANDLE current_process;
494
  PROCESS_MEMORY_COUNTERS pmc;
495

496
  current_process = GetCurrentProcess();
497

498
  if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
499
    return uv_translate_sys_error(GetLastError());
500
  }
501

502
  *rss = pmc.WorkingSetSize;
503

504
  return 0;
505
}
506

507

508
int uv_uptime(double* uptime) {
509
  *uptime = GetTickCount64() / 1000.0;
510
  return 0;
511
}
512

513

514
unsigned int uv_available_parallelism(void) {
515
  SYSTEM_INFO info;
516
  unsigned rc;
517

518
  /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
519
   * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
520
   */
521
  GetSystemInfo(&info);
522

523
  rc = info.dwNumberOfProcessors;
524
  if (rc < 1)
525
    rc = 1;
526

527
  return rc;
528
}
529

530

531
int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
532
  uv_cpu_info_t* cpu_infos;
533
  SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
534
  DWORD sppi_size;
535
  SYSTEM_INFO system_info;
536
  DWORD cpu_count, i;
537
  NTSTATUS status;
538
  ULONG result_size;
539
  int err;
540
  uv_cpu_info_t* cpu_info;
541

542
  cpu_infos = NULL;
543
  cpu_count = 0;
544
  sppi = NULL;
545

546
  uv__once_init();
547

548
  GetSystemInfo(&system_info);
549
  cpu_count = system_info.dwNumberOfProcessors;
550

551
  cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
552
  if (cpu_infos == NULL) {
553
    err = ERROR_OUTOFMEMORY;
554
    goto error;
555
  }
556

557
  sppi_size = cpu_count * sizeof(*sppi);
558
  sppi = uv__malloc(sppi_size);
559
  if (sppi == NULL) {
560
    err = ERROR_OUTOFMEMORY;
561
    goto error;
562
  }
563

564
  status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
565
                                     sppi,
566
                                     sppi_size,
567
                                     &result_size);
568
  if (!NT_SUCCESS(status)) {
569
    err = pRtlNtStatusToDosError(status);
570
    goto error;
571
  }
572

573
  assert(result_size == sppi_size);
574

575
  for (i = 0; i < cpu_count; i++) {
576
    WCHAR key_name[128];
577
    HKEY processor_key;
578
    DWORD cpu_speed;
579
    DWORD cpu_speed_size = sizeof(cpu_speed);
580
    WCHAR cpu_brand[256];
581
    DWORD cpu_brand_size = sizeof(cpu_brand);
582
    size_t len;
583

584
    len = _snwprintf(key_name,
585
                     ARRAY_SIZE(key_name),
586
                     L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
587
                     i);
588

589
    assert(len > 0 && len < ARRAY_SIZE(key_name));
590

591
    err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
592
                        key_name,
593
                        0,
594
                        KEY_QUERY_VALUE,
595
                        &processor_key);
596
    if (err != ERROR_SUCCESS) {
597
      goto error;
598
    }
599

600
    err = RegQueryValueExW(processor_key,
601
                           L"~MHz",
602
                           NULL,
603
                           NULL,
604
                           (BYTE*)&cpu_speed,
605
                           &cpu_speed_size);
606
    if (err != ERROR_SUCCESS) {
607
      RegCloseKey(processor_key);
608
      goto error;
609
    }
610

611
    err = RegQueryValueExW(processor_key,
612
                           L"ProcessorNameString",
613
                           NULL,
614
                           NULL,
615
                           (BYTE*)&cpu_brand,
616
                           &cpu_brand_size);
617
    RegCloseKey(processor_key);
618
    if (err != ERROR_SUCCESS)
619
      goto error;
620

621
    cpu_info = &cpu_infos[i];
622
    cpu_info->speed = cpu_speed;
623
    cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
624
    cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
625
        sppi[i].IdleTime.QuadPart) / 10000;
626
    cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
627
    cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
628
    cpu_info->cpu_times.nice = 0;
629

630
    uv__convert_utf16_to_utf8(cpu_brand,
631
                              cpu_brand_size / sizeof(WCHAR),
632
                              &(cpu_info->model));
633
  }
634

635
  uv__free(sppi);
636

637
  *cpu_count_ptr = cpu_count;
638
  *cpu_infos_ptr = cpu_infos;
639

640
  return 0;
641

642
 error:
643
  if (cpu_infos != NULL) {
644
    /* This is safe because the cpu_infos array is zeroed on allocation. */
645
    for (i = 0; i < cpu_count; i++)
646
      uv__free(cpu_infos[i].model);
647
  }
648

649
  uv__free(cpu_infos);
650
  uv__free(sppi);
651

652
  return uv_translate_sys_error(err);
653
}
654

655

656
int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
657
    int* count_ptr) {
658
  IP_ADAPTER_ADDRESSES* win_address_buf;
659
  ULONG win_address_buf_size;
660
  IP_ADAPTER_ADDRESSES* adapter;
661

662
  uv_interface_address_t* uv_address_buf;
663
  char* name_buf;
664
  size_t uv_address_buf_size;
665
  uv_interface_address_t* uv_address;
666

667
  int count;
668
  ULONG flags;
669

670
  *addresses_ptr = NULL;
671
  *count_ptr = 0;
672

673
  flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
674
    GAA_FLAG_SKIP_DNS_SERVER;
675

676
  /* Fetch the size of the adapters reported by windows, and then get the list
677
   * itself. */
678
  win_address_buf_size = 0;
679
  win_address_buf = NULL;
680

681
  for (;;) {
682
    ULONG 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. */
687
    r = GetAdaptersAddresses(AF_UNSPEC,
688
                             flags,
689
                             NULL,
690
                             win_address_buf,
691
                             &win_address_buf_size);
692

693
    if (r == ERROR_SUCCESS)
694
      break;
695

696
    uv__free(win_address_buf);
697

698
    switch (r) {
699
      case ERROR_BUFFER_OVERFLOW:
700
        /* This happens when win_address_buf is NULL or too small to hold all
701
         * adapters. */
702
        win_address_buf = uv__malloc(win_address_buf_size);
703
        if (win_address_buf == NULL)
704
          return UV_ENOMEM;
705

706
        continue;
707

708
      case ERROR_NO_DATA: {
709
        /* No adapters were found. */
710
        uv_address_buf = uv__malloc(1);
711
        if (uv_address_buf == NULL)
712
          return UV_ENOMEM;
713

714
        *count_ptr = 0;
715
        *addresses_ptr = uv_address_buf;
716

717
        return 0;
718
      }
719

720
      case ERROR_ADDRESS_NOT_ASSOCIATED:
721
        return UV_EAGAIN;
722

723
      case 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
         */
732
        return UV_ENOBUFS;
733

734
      default:
735
        /* Other (unspecified) errors can happen, but we don't have any special
736
         * meaning for them. */
737
        assert(r != ERROR_SUCCESS);
738
        return uv_translate_sys_error(r);
739
    }
740
  }
741

742
  /* Count the number of enabled interfaces and compute how much space is
743
   * needed to store their info. */
744
  count = 0;
745
  uv_address_buf_size = 0;
746

747
  for (adapter = win_address_buf;
748
       adapter != NULL;
749
       adapter = adapter->Next) {
750
    IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
751
    int name_size;
752

753
    /* Interfaces that are not 'up' should not be reported. Also skip
754
     * interfaces that have no associated unicast address, as to avoid
755
     * allocating space for the name for this interface. */
756
    if (adapter->OperStatus != IfOperStatusUp ||
757
        adapter->FirstUnicastAddress == NULL)
758
      continue;
759

760
    /* Compute the size of the interface name. */
761
    name_size = uv_utf16_length_as_wtf8(adapter->FriendlyName, -1);
762
    uv_address_buf_size += name_size + 1;
763

764
    /* Count the number of addresses associated with this interface, and
765
     * compute the size. */
766
    for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
767
                           adapter->FirstUnicastAddress;
768
         unicast_address != NULL;
769
         unicast_address = unicast_address->Next) {
770
      count++;
771
      uv_address_buf_size += sizeof(uv_interface_address_t);
772
    }
773
  }
774

775
  /* Allocate space to store interface data plus adapter names. */
776
  uv_address_buf = uv__malloc(uv_address_buf_size);
777
  if (uv_address_buf == NULL) {
778
    uv__free(win_address_buf);
779
    return UV_ENOMEM;
780
  }
781

782
  /* Compute the start of the uv_interface_address_t array, and the place in
783
   * the buffer where the interface names will be stored. */
784
  uv_address = uv_address_buf;
785
  name_buf = (char*) (uv_address_buf + count);
786

787
  /* Fill out the output buffer. */
788
  for (adapter = win_address_buf;
789
       adapter != NULL;
790
       adapter = adapter->Next) {
791
    IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
792
    size_t name_size;
793
    int r;
794

795
    if (adapter->OperStatus != IfOperStatusUp ||
796
        adapter->FirstUnicastAddress == NULL)
797
      continue;
798

799
    /* Convert the interface name to UTF8. */
800
    name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
801
    r = uv__copy_utf16_to_utf8(adapter->FriendlyName,
802
                               -1,
803
                               name_buf,
804
                               &name_size);
805
    if (r) {
806
      uv__free(win_address_buf);
807
      uv__free(uv_address_buf);
808
      return r;
809
    }
810
    name_size += 1; /* Add NUL byte. */
811

812
    /* Add an uv_interface_address_t element for every unicast address. */
813
    for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
814
                           adapter->FirstUnicastAddress;
815
         unicast_address != NULL;
816
         unicast_address = unicast_address->Next) {
817
      struct sockaddr* sa;
818
      ULONG prefix_len;
819

820
      sa = unicast_address->Address.lpSockaddr;
821

822
      prefix_len =
823
        ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
824

825
      memset(uv_address, 0, sizeof *uv_address);
826

827
      uv_address->name = name_buf;
828

829
      if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
830
        memcpy(uv_address->phys_addr,
831
               adapter->PhysicalAddress,
832
               sizeof(uv_address->phys_addr));
833
      }
834

835
      uv_address->is_internal =
836
          (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
837

838
      if (sa->sa_family == AF_INET6) {
839
        uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
840

841
        uv_address->netmask.netmask6.sin6_family = AF_INET6;
842
        memset(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. */
844
        if (prefix_len % 8) {
845
          uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
846
              0xff << (8 - prefix_len % 8);
847
        }
848

849
      } else {
850
        uv_address->address.address4 = *((struct sockaddr_in *) sa);
851

852
        uv_address->netmask.netmask4.sin_family = AF_INET;
853
        uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
854
            htonl(0xffffffff << (32 - prefix_len)) : 0;
855
      }
856

857
      uv_address++;
858
    }
859

860
    name_buf += name_size;
861
  }
862

863
  uv__free(win_address_buf);
864

865
  *addresses_ptr = uv_address_buf;
866
  *count_ptr = count;
867

868
  return 0;
869
}
870

871

872
void uv_free_interface_addresses(uv_interface_address_t* addresses,
873
    int count) {
874
  uv__free(addresses);
875
}
876

877

878
int uv_getrusage(uv_rusage_t *uv_rusage) {
879
  FILETIME createTime, exitTime, kernelTime, userTime;
880
  SYSTEMTIME kernelSystemTime, userSystemTime;
881
  PROCESS_MEMORY_COUNTERS memCounters;
882
  IO_COUNTERS ioCounters;
883
  int ret;
884

885
  ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
886
  if (ret == 0) {
887
    return uv_translate_sys_error(GetLastError());
888
  }
889

890
  ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
891
  if (ret == 0) {
892
    return uv_translate_sys_error(GetLastError());
893
  }
894

895
  ret = FileTimeToSystemTime(&userTime, &userSystemTime);
896
  if (ret == 0) {
897
    return uv_translate_sys_error(GetLastError());
898
  }
899

900
  ret = GetProcessMemoryInfo(GetCurrentProcess(),
901
                             &memCounters,
902
                             sizeof(memCounters));
903
  if (ret == 0) {
904
    return uv_translate_sys_error(GetLastError());
905
  }
906

907
  ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
908
  if (ret == 0) {
909
    return uv_translate_sys_error(GetLastError());
910
  }
911

912
  memset(uv_rusage, 0, sizeof(*uv_rusage));
913

914
  uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
915
                               userSystemTime.wMinute * 60 +
916
                               userSystemTime.wSecond;
917
  uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
918

919
  uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
920
                               kernelSystemTime.wMinute * 60 +
921
                               kernelSystemTime.wSecond;
922
  uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
923

924
  uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
925
  uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
926

927
  uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
928
  uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
929

930
  return 0;
931
}
932

933

934
int uv_os_homedir(char* buffer, size_t* size) {
935
  uv_passwd_t pwd;
936
  size_t len;
937
  int r;
938

939
  /* Check if the USERPROFILE environment variable is set first. The task of
940
     performing input validation on buffer and size is taken care of by
941
     uv_os_getenv(). */
942
  r = uv_os_getenv("USERPROFILE", buffer, size);
943

944
  /* Don't return an error if USERPROFILE was not found. */
945
  if (r != UV_ENOENT)
946
    return r;
947

948
  /* USERPROFILE is not set, so call uv_os_get_passwd() */
949
  r = uv_os_get_passwd(&pwd);
950

951
  if (r != 0) {
952
    return r;
953
  }
954

955
  len = strlen(pwd.homedir);
956

957
  if (len >= *size) {
958
    *size = len + 1;
959
    uv_os_free_passwd(&pwd);
960
    return UV_ENOBUFS;
961
  }
962

963
  memcpy(buffer, pwd.homedir, len + 1);
964
  *size = len;
965
  uv_os_free_passwd(&pwd);
966

967
  return 0;
968
}
969

970

971
int uv_os_tmpdir(char* buffer, size_t* size) {
972
  wchar_t *path;
973
  size_t len;
974

975
  if (buffer == NULL || size == NULL || *size == 0)
976
    return UV_EINVAL;
977

978
  len = 0;
979
  len = GetTempPathW(0, NULL);
980
  if (len == 0) {
981
    return uv_translate_sys_error(GetLastError());
982
  }
983
  /* Include space for terminating null char. */
984
  len += 1;
985
  path = uv__malloc(len * sizeof(wchar_t));
986
  if (path == NULL) {
987
    return UV_ENOMEM;
988
  }
989
  len = GetTempPathW(len, path);
990

991
  if (len == 0) {
992
    uv__free(path);
993
    return uv_translate_sys_error(GetLastError());
994
  }
995

996
  /* The returned directory should not have a trailing slash, unless it points
997
   * at a drive root, like c:\. Remove it if needed. */
998
  if (path[len - 1] == L'\\' &&
999
      !(len == 3 && path[1] == L':')) {
1000
    len--;
1001
    path[len] = L'\0';
1002
  }
1003

1004
  return 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
 */
1015
int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8) {
1016
  size_t utf8_len = 0;
1017

1018
  if (utf16 == NULL)
1019
    return UV_EINVAL;
1020

1021
   *utf8 = NULL;
1022
   return 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
 */
1030
int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16) {
1031
  int bufsize;
1032

1033
  if (utf8 == NULL)
1034
    return UV_EINVAL;
1035

1036
  /* Check how much space we need (including NUL). */
1037
  bufsize = uv_wtf8_length_as_utf16(utf8);
1038
  if (bufsize < 0)
1039
    return UV__EINVAL;
1040

1041
  /* Allocate the destination buffer. */
1042
  *utf16 = uv__malloc(sizeof(WCHAR) * bufsize);
1043

1044
  if (*utf16 == NULL)
1045
    return UV_ENOMEM;
1046

1047
  /* Convert to UTF-16 */
1048
  uv_wtf8_to_utf16(utf8, *utf16, bufsize);
1049

1050
  return 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
 */
1061
int uv__copy_utf16_to_utf8(const WCHAR* utf16buffer, size_t utf16len, char* utf8, size_t *size) {
1062
  int r;
1063

1064
  if (utf8 == NULL || size == NULL)
1065
    return UV_EINVAL;
1066

1067
  if (*size == 0) {
1068
    *size = uv_utf16_length_as_wtf8(utf16buffer, utf16len);
1069
    r = UV_ENOBUFS;
1070
  } else {
1071
    *size -= 1; /* Reserve space for NUL. */
1072
    r = uv_utf16_to_wtf8(utf16buffer, utf16len, &utf8, size);
1073
  }
1074
  if (r == UV_ENOBUFS)
1075
    *size += 1; /* Add space for NUL. */
1076
  return r;
1077
}
1078

1079

1080
static int uv__getpwuid_r(uv_passwd_t* pwd) {
1081
  HANDLE token;
1082
  wchar_t username[UNLEN + 1];
1083
  wchar_t *path;
1084
  DWORD bufsize;
1085
  int r;
1086

1087
  if (pwd == NULL)
1088
    return UV_EINVAL;
1089

1090
  /* Get the home directory using GetUserProfileDirectoryW() */
1091
  if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
1092
    return uv_translate_sys_error(GetLastError());
1093

1094
  bufsize = 0;
1095
  GetUserProfileDirectoryW(token, NULL, &bufsize);
1096
  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1097
    r = GetLastError();
1098
    CloseHandle(token);
1099
    return uv_translate_sys_error(r);
1100
  }
1101

1102
  path = uv__malloc(bufsize * sizeof(wchar_t));
1103
  if (path == NULL) {
1104
    CloseHandle(token);
1105
    return UV_ENOMEM;
1106
  }
1107

1108
  if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
1109
    r = GetLastError();
1110
    CloseHandle(token);
1111
    uv__free(path);
1112
    return uv_translate_sys_error(r);
1113
  }
1114

1115
  CloseHandle(token);
1116

1117
  /* Get the username using GetUserNameW() */
1118
  bufsize = ARRAY_SIZE(username);
1119
  if (!GetUserNameW(username, &bufsize)) {
1120
    r = GetLastError();
1121
    uv__free(path);
1122

1123
    /* This should not be possible */
1124
    if (r == ERROR_INSUFFICIENT_BUFFER)
1125
      return UV_ENOMEM;
1126

1127
    return uv_translate_sys_error(r);
1128
  }
1129

1130
  pwd->homedir = NULL;
1131
  r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
1132
  uv__free(path);
1133

1134
  if (r != 0)
1135
    return r;
1136

1137
  pwd->username = NULL;
1138
  r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
1139

1140
  if (r != 0) {
1141
    uv__free(pwd->homedir);
1142
    return r;
1143
  }
1144

1145
  pwd->shell = NULL;
1146
  pwd->uid = -1;
1147
  pwd->gid = -1;
1148

1149
  return 0;
1150
}
1151

1152

1153
int uv_os_get_passwd(uv_passwd_t* pwd) {
1154
  return uv__getpwuid_r(pwd);
1155
}
1156

1157

1158
int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
1159
  return UV_ENOTSUP;
1160
}
1161

1162

1163
int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
1164
  return UV_ENOTSUP;
1165
}
1166

1167

1168
int uv_os_environ(uv_env_item_t** envitems, int* count) {
1169
  wchar_t* env;
1170
  wchar_t* penv;
1171
  int i, cnt;
1172
  uv_env_item_t* envitem;
1173

1174
  *envitems = NULL;
1175
  *count = 0;
1176

1177
  env = GetEnvironmentStringsW();
1178
  if (env == NULL)
1179
    return 0;
1180

1181
  for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
1182

1183
  *envitems = uv__calloc(i, sizeof(**envitems));
1184
  if (*envitems == NULL) {
1185
    FreeEnvironmentStringsW(env);
1186
    return UV_ENOMEM;
1187
  }
1188

1189
  penv = env;
1190
  cnt = 0;
1191

1192
  while (*penv != L'\0' && cnt < i) {
1193
    char* buf;
1194
    char* ptr;
1195

1196
    if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
1197
      goto 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. */
1201
    ptr = strchr(buf + 1, '=');
1202
    if (ptr == NULL) {
1203
      uv__free(buf);
1204
      goto do_continue;
1205
    }
1206

1207
    *ptr = '\0';
1208

1209
    envitem = &(*envitems)[cnt];
1210
    envitem->name = buf;
1211
    envitem->value = ptr + 1;
1212

1213
    cnt++;
1214

1215
  do_continue:
1216
    penv += wcslen(penv) + 1;
1217
  }
1218

1219
  FreeEnvironmentStringsW(env);
1220

1221
  *count = cnt;
1222
  return 0;
1223

1224
fail:
1225
  FreeEnvironmentStringsW(env);
1226

1227
  for (i = 0; i < cnt; i++) {
1228
    envitem = &(*envitems)[cnt];
1229
    uv__free(envitem->name);
1230
  }
1231
  uv__free(*envitems);
1232

1233
  *envitems = NULL;
1234
  *count = 0;
1235
  return UV_ENOMEM;
1236
}
1237

1238

1239
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
1240
  wchar_t fastvar[512];
1241
  wchar_t* var;
1242
  DWORD varlen;
1243
  wchar_t* name_w;
1244
  size_t len;
1245
  int r;
1246

1247
  if (name == NULL || buffer == NULL || size == NULL || *size == 0)
1248
    return UV_EINVAL;
1249

1250
  r = uv__convert_utf8_to_utf16(name, &name_w);
1251

1252
  if (r != 0)
1253
    return r;
1254

1255
  var = fastvar;
1256
  varlen = ARRAY_SIZE(fastvar);
1257

1258
  for (;;) {
1259
    SetLastError(ERROR_SUCCESS);
1260
    len = GetEnvironmentVariableW(name_w, var, varlen);
1261

1262
    if (len == 0)
1263
      r = uv_translate_sys_error(GetLastError());
1264

1265
    if (len < varlen)
1266
      break;
1267

1268
    /* Try repeatedly because we might have been preempted by another thread
1269
     * modifying the environment variable just as we're trying to read it.
1270
     */
1271
    if (var != fastvar)
1272
      uv__free(var);
1273

1274
    varlen = 1 + len;
1275
    var = uv__malloc(varlen * sizeof(*var));
1276

1277
    if (var == NULL) {
1278
      r = UV_ENOMEM;
1279
      goto fail;
1280
    }
1281
  }
1282

1283
  uv__free(name_w);
1284
  name_w = NULL;
1285

1286
  if (r == 0)
1287
    r = uv__copy_utf16_to_utf8(var, len, buffer, size);
1288

1289
fail:
1290

1291
  if (name_w != NULL)
1292
    uv__free(name_w);
1293

1294
  if (var != fastvar)
1295
    uv__free(var);
1296

1297
  return r;
1298
}
1299

1300

1301
int uv_os_setenv(const char* name, const char* value) {
1302
  wchar_t* name_w;
1303
  wchar_t* value_w;
1304
  int r;
1305

1306
  if (name == NULL || value == NULL)
1307
    return UV_EINVAL;
1308

1309
  r = uv__convert_utf8_to_utf16(name, &name_w);
1310

1311
  if (r != 0)
1312
    return r;
1313

1314
  r = uv__convert_utf8_to_utf16(value, &value_w);
1315

1316
  if (r != 0) {
1317
    uv__free(name_w);
1318
    return r;
1319
  }
1320

1321
  r = SetEnvironmentVariableW(name_w, value_w);
1322
  uv__free(name_w);
1323
  uv__free(value_w);
1324

1325
  if (r == 0)
1326
    return uv_translate_sys_error(GetLastError());
1327

1328
  return 0;
1329
}
1330

1331

1332
int uv_os_unsetenv(const char* name) {
1333
  wchar_t* name_w;
1334
  int r;
1335

1336
  if (name == NULL)
1337
    return UV_EINVAL;
1338

1339
  r = uv__convert_utf8_to_utf16(name, &name_w);
1340

1341
  if (r != 0)
1342
    return r;
1343

1344
  r = SetEnvironmentVariableW(name_w, NULL);
1345
  uv__free(name_w);
1346

1347
  if (r == 0)
1348
    return uv_translate_sys_error(GetLastError());
1349

1350
  return 0;
1351
}
1352

1353

1354
int uv_os_gethostname(char* buffer, size_t* size) {
1355
  WCHAR buf[UV_MAXHOSTNAMESIZE];
1356

1357
  if (buffer == NULL || size == NULL || *size == 0)
1358
    return UV_EINVAL;
1359

1360
  uv__once_init(); /* Initialize winsock */
1361

1362
  if (pGetHostNameW == NULL)
1363
    return UV_ENOSYS;
1364

1365
  if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
1366
    return uv_translate_sys_error(WSAGetLastError());
1367

1368
  return uv__copy_utf16_to_utf8(buf, -1, buffer, size);
1369
}
1370

1371

1372
static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
1373
  int r;
1374

1375
  if (pid == 0)
1376
    *handle = GetCurrentProcess();
1377
  else
1378
    *handle = OpenProcess(access, FALSE, pid);
1379

1380
  if (*handle == NULL) {
1381
    r = GetLastError();
1382

1383
    if (r == ERROR_INVALID_PARAMETER)
1384
      return UV_ESRCH;
1385
    else
1386
      return uv_translate_sys_error(r);
1387
  }
1388

1389
  return 0;
1390
}
1391

1392

1393
int uv_os_getpriority(uv_pid_t pid, int* priority) {
1394
  HANDLE handle;
1395
  int r;
1396

1397
  if (priority == NULL)
1398
    return UV_EINVAL;
1399

1400
  r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
1401

1402
  if (r != 0)
1403
    return r;
1404

1405
  r = GetPriorityClass(handle);
1406

1407
  if (r == 0) {
1408
    r = uv_translate_sys_error(GetLastError());
1409
  } else {
1410
    /* Map Windows priority classes to Unix nice values. */
1411
    if (r == REALTIME_PRIORITY_CLASS)
1412
      *priority = UV_PRIORITY_HIGHEST;
1413
    else if (r == HIGH_PRIORITY_CLASS)
1414
      *priority = UV_PRIORITY_HIGH;
1415
    else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
1416
      *priority = UV_PRIORITY_ABOVE_NORMAL;
1417
    else if (r == NORMAL_PRIORITY_CLASS)
1418
      *priority = UV_PRIORITY_NORMAL;
1419
    else if (r == BELOW_NORMAL_PRIORITY_CLASS)
1420
      *priority = UV_PRIORITY_BELOW_NORMAL;
1421
    else  /* IDLE_PRIORITY_CLASS */
1422
      *priority = UV_PRIORITY_LOW;
1423

1424
    r = 0;
1425
  }
1426

1427
  CloseHandle(handle);
1428
  return r;
1429
}
1430

1431

1432
int uv_os_setpriority(uv_pid_t pid, int priority) {
1433
  HANDLE handle;
1434
  int priority_class;
1435
  int r;
1436

1437
  /* Map Unix nice values to Windows priority classes. */
1438
  if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
1439
    return UV_EINVAL;
1440
  else if (priority < UV_PRIORITY_HIGH)
1441
    priority_class = REALTIME_PRIORITY_CLASS;
1442
  else if (priority < UV_PRIORITY_ABOVE_NORMAL)
1443
    priority_class = HIGH_PRIORITY_CLASS;
1444
  else if (priority < UV_PRIORITY_NORMAL)
1445
    priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
1446
  else if (priority < UV_PRIORITY_BELOW_NORMAL)
1447
    priority_class = NORMAL_PRIORITY_CLASS;
1448
  else if (priority < UV_PRIORITY_LOW)
1449
    priority_class = BELOW_NORMAL_PRIORITY_CLASS;
1450
  else
1451
    priority_class = IDLE_PRIORITY_CLASS;
1452

1453
  r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
1454

1455
  if (r != 0)
1456
    return r;
1457

1458
  if (SetPriorityClass(handle, priority_class) == 0)
1459
    r = uv_translate_sys_error(GetLastError());
1460

1461
  CloseHandle(handle);
1462
  return r;
1463
}
1464

1465
int uv_thread_getpriority(uv_thread_t tid, int* priority) {
1466
  int r;
1467

1468
  if (priority == NULL)
1469
    return UV_EINVAL;
1470

1471
  r = GetThreadPriority(tid);
1472
  if (r == THREAD_PRIORITY_ERROR_RETURN)
1473
    return uv_translate_sys_error(GetLastError());
1474

1475
  *priority = r;
1476
  return 0;
1477
}
1478

1479
int uv_thread_setpriority(uv_thread_t tid, int priority) {
1480
  int r;
1481

1482
  switch (priority) {
1483
    case UV_THREAD_PRIORITY_HIGHEST:
1484
      r = SetThreadPriority(tid, THREAD_PRIORITY_HIGHEST);
1485
      break;
1486
    case UV_THREAD_PRIORITY_ABOVE_NORMAL:
1487
      r = SetThreadPriority(tid, THREAD_PRIORITY_ABOVE_NORMAL);
1488
      break;
1489
    case UV_THREAD_PRIORITY_NORMAL:
1490
      r = SetThreadPriority(tid, THREAD_PRIORITY_NORMAL);
1491
      break;
1492
    case UV_THREAD_PRIORITY_BELOW_NORMAL:
1493
      r = SetThreadPriority(tid, THREAD_PRIORITY_BELOW_NORMAL);
1494
      break;
1495
    case UV_THREAD_PRIORITY_LOWEST:
1496
      r = SetThreadPriority(tid, THREAD_PRIORITY_LOWEST);
1497
      break;
1498
    default:
1499
      return 0;
1500
  }
1501

1502
  if (r == 0)
1503
    return uv_translate_sys_error(GetLastError());
1504

1505
  return 0;
1506
}
1507

1508
int uv_os_uname(uv_utsname_t* buffer) {
1509
  /* Implementation loosely based on
1510
     https://github.com/gagern/gnulib/blob/master/lib/uname.c */
1511
  OSVERSIONINFOW os_info;
1512
  SYSTEM_INFO system_info;
1513
  HKEY registry_key;
1514
  WCHAR product_name_w[256];
1515
  DWORD product_name_w_size;
1516
  size_t version_size;
1517
  int processor_level;
1518
  int r;
1519

1520
  if (buffer == NULL)
1521
    return UV_EINVAL;
1522

1523
  uv__once_init();
1524
  os_info.dwOSVersionInfoSize = sizeof(os_info);
1525
  os_info.szCSDVersion[0] = L'\0';
1526

1527
  /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
1528
     if RtlGetVersion() is not available. */
1529
  if (pRtlGetVersion) {
1530
    pRtlGetVersion(&os_info);
1531
  } else {
1532
    /* Silence GetVersionEx() deprecation warning. */
1533
    #ifdef _MSC_VER
1534
    #pragma warning(suppress : 4996)
1535
    #endif
1536
    if (GetVersionExW(&os_info) == 0) {
1537
      r = uv_translate_sys_error(GetLastError());
1538
      goto error;
1539
    }
1540
  }
1541

1542
  /* Populate the version field. */
1543
  version_size = 0;
1544
  r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1545
                    L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
1546
                    0,
1547
                    KEY_QUERY_VALUE | KEY_WOW64_64KEY,
1548
                    &registry_key);
1549

1550
  if (r == ERROR_SUCCESS) {
1551
    product_name_w_size = sizeof(product_name_w);
1552
    r = RegGetValueW(registry_key,
1553
                     NULL,
1554
                     L"ProductName",
1555
                     RRF_RT_REG_SZ,
1556
                     NULL,
1557
                     (PVOID) product_name_w,
1558
                     &product_name_w_size);
1559
    RegCloseKey(registry_key);
1560

1561
    if (r == ERROR_SUCCESS) {
1562
      /* Windows 11 shares dwMajorVersion with Windows 10
1563
       * 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 *" */
1568
      if (os_info.dwMajorVersion == 10 &&
1569
          os_info.dwBuildNumber >= 22000 &&
1570
          product_name_w_size >= ARRAY_SIZE(L"Windows 10")) {
1571
        /* If ProductName starts with "Windows 10" */
1572
        if (wcsncmp(product_name_w, L"Windows 10", ARRAY_SIZE(L"Windows 10") - 1) == 0) {
1573
          /* Bump 10 to 11 */
1574
          product_name_w[9] = '1';
1575
        }
1576
      }
1577

1578
      version_size = sizeof(buffer->version);
1579
      r = uv__copy_utf16_to_utf8(product_name_w,
1580
                                 -1,
1581
                                 buffer->version,
1582
                                 &version_size);
1583
      if (r)
1584
        goto error;
1585
    }
1586
  }
1587

1588
  /* Append service pack information to the version if present. */
1589
  if (os_info.szCSDVersion[0] != L'\0') {
1590
    if (version_size > 0)
1591
      buffer->version[version_size++] = ' ';
1592

1593
    version_size = sizeof(buffer->version) - version_size;
1594
    r = uv__copy_utf16_to_utf8(os_info.szCSDVersion,
1595
                               -1,
1596
                               buffer->version + 
1597
                                 sizeof(buffer->version) - version_size,
1598
                               &version_size);
1599
    if (r)
1600
      goto error;
1601
  }
1602

1603
  /* Populate the sysname field. */
1604
#ifdef __MINGW32__
1605
  r = snprintf(buffer->sysname,
1606
               sizeof(buffer->sysname),
1607
               "MINGW32_NT-%u.%u",
1608
               (unsigned int) os_info.dwMajorVersion,
1609
               (unsigned int) os_info.dwMinorVersion);
1610
  assert((size_t)r < sizeof(buffer->sysname));
1611
#else
1612
  uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
1613
#endif
1614

1615
  /* Populate the release field. */
1616
  r = snprintf(buffer->release,
1617
               sizeof(buffer->release),
1618
               "%d.%d.%d",
1619
               (unsigned int) os_info.dwMajorVersion,
1620
               (unsigned int) os_info.dwMinorVersion,
1621
               (unsigned int) os_info.dwBuildNumber);
1622
  assert((size_t)r < sizeof(buffer->release));
1623

1624
  /* Populate the machine field. */
1625
  GetSystemInfo(&system_info);
1626

1627
  switch (system_info.wProcessorArchitecture) {
1628
    case PROCESSOR_ARCHITECTURE_AMD64:
1629
      uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
1630
      break;
1631
    case PROCESSOR_ARCHITECTURE_IA64:
1632
      uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
1633
      break;
1634
    case PROCESSOR_ARCHITECTURE_INTEL:
1635
      uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
1636

1637
      if (system_info.wProcessorLevel > 3) {
1638
        processor_level = system_info.wProcessorLevel < 6 ?
1639
                          system_info.wProcessorLevel : 6;
1640
        buffer->machine[1] = '0' + processor_level;
1641
      }
1642

1643
      break;
1644
    case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1645
      uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
1646
      break;
1647
    case PROCESSOR_ARCHITECTURE_MIPS:
1648
      uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
1649
      break;
1650
    case PROCESSOR_ARCHITECTURE_ALPHA:
1651
    case PROCESSOR_ARCHITECTURE_ALPHA64:
1652
      uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
1653
      break;
1654
    case PROCESSOR_ARCHITECTURE_PPC:
1655
      uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
1656
      break;
1657
    case PROCESSOR_ARCHITECTURE_SHX:
1658
      uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
1659
      break;
1660
    case PROCESSOR_ARCHITECTURE_ARM:
1661
      uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
1662
      break;
1663
    default:
1664
      uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
1665
      break;
1666
  }
1667

1668
  return 0;
1669

1670
error:
1671
  buffer->sysname[0] = '\0';
1672
  buffer->release[0] = '\0';
1673
  buffer->version[0] = '\0';
1674
  buffer->machine[0] = '\0';
1675
  return r;
1676
}
1677

1678
int uv_gettimeofday(uv_timeval64_t* tv) {
1679
  /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
1680
  const uint64_t epoch = (uint64_t) 116444736000000000ULL;
1681
  FILETIME file_time;
1682
  ULARGE_INTEGER ularge;
1683

1684
  if (tv == NULL)
1685
    return UV_EINVAL;
1686

1687
  GetSystemTimeAsFileTime(&file_time);
1688
  ularge.LowPart = file_time.dwLowDateTime;
1689
  ularge.HighPart = file_time.dwHighDateTime;
1690
  tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
1691
  tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
1692
  return 0;
1693
}
1694

1695
int uv__random_rtlgenrandom(void* buf, size_t buflen) {
1696
  if (buflen == 0)
1697
    return 0;
1698

1699
  if (SystemFunction036(buf, buflen) == FALSE)
1700
    return UV_EIO;
1701

1702
  return 0;
1703
}
1704

1705
void uv_sleep(unsigned int msec) {
1706
  Sleep(msec);
1707
}
1708

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.