Upgrade libuv from 1.34.2 to 1.38.0 (#32)

This commit is contained in:
Dario Vladović 2020-06-06 22:05:48 +02:00 committed by GitHub
parent 3960042cc6
commit 46336f4b68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 1793 additions and 1288 deletions

View File

@ -265,6 +265,8 @@ typedef void* (*uv_realloc_func)(void* ptr, size_t size);
typedef void* (*uv_calloc_func)(size_t count, size_t size);
typedef void (*uv_free_func)(void* ptr);
UV_EXTERN void uv_library_shutdown(void);
UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func,
uv_realloc_func realloc_func,
uv_calloc_func calloc_func,
@ -605,7 +607,17 @@ enum uv_udp_flags {
* (provided they all set the flag) but only the last one to bind will receive
* any traffic, in effect "stealing" the port from the previous listener.
*/
UV_UDP_REUSEADDR = 4
UV_UDP_REUSEADDR = 4,
/*
* Indicates that the message was received by recvmmsg, so the buffer provided
* must not be freed by the recv_cb callback.
*/
UV_UDP_MMSG_CHUNK = 8,
/*
* Indicates that recvmmsg should be used, if available.
*/
UV_UDP_RECVMMSG = 256
};
typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
@ -1059,11 +1071,11 @@ UV_EXTERN int uv_cancel(uv_req_t* req);
struct uv_cpu_times_s {
uint64_t user;
uint64_t nice;
uint64_t sys;
uint64_t idle;
uint64_t irq;
uint64_t user; /* milliseconds */
uint64_t nice; /* milliseconds */
uint64_t sys; /* milliseconds */
uint64_t idle; /* milliseconds */
uint64_t irq; /* milliseconds */
};
struct uv_cpu_info_s {
@ -1177,12 +1189,22 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
UV_EXTERN uv_pid_t uv_os_getpid(void);
UV_EXTERN uv_pid_t uv_os_getppid(void);
#define UV_PRIORITY_LOW 19
#define UV_PRIORITY_BELOW_NORMAL 10
#define UV_PRIORITY_NORMAL 0
#define UV_PRIORITY_ABOVE_NORMAL -7
#define UV_PRIORITY_HIGH -14
#define UV_PRIORITY_HIGHEST -20
#if defined(__PASE__)
/* On IBM i PASE, the highest process priority is -10 */
# define UV_PRIORITY_LOW 39 // RUNPTY(99)
# define UV_PRIORITY_BELOW_NORMAL 15 // RUNPTY(50)
# define UV_PRIORITY_NORMAL 0 // RUNPTY(20)
# define UV_PRIORITY_ABOVE_NORMAL -4 // RUNTY(12)
# define UV_PRIORITY_HIGH -7 // RUNPTY(6)
# define UV_PRIORITY_HIGHEST -10 // RUNPTY(1)
#else
# define UV_PRIORITY_LOW 19
# define UV_PRIORITY_BELOW_NORMAL 10
# define UV_PRIORITY_NORMAL 0
# define UV_PRIORITY_ABOVE_NORMAL -7
# define UV_PRIORITY_HIGH -14
# define UV_PRIORITY_HIGHEST -20
#endif
UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
@ -1259,7 +1281,8 @@ typedef enum {
UV_FS_READDIR,
UV_FS_CLOSEDIR,
UV_FS_STATFS,
UV_FS_MKSTEMP
UV_FS_MKSTEMP,
UV_FS_LUTIME
} uv_fs_type;
struct uv_dir_s {
@ -1284,6 +1307,7 @@ struct uv_fs_s {
UV_EXTERN uv_fs_type uv_fs_get_type(const uv_fs_t*);
UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*);
UV_EXTERN int uv_fs_get_system_error(const uv_fs_t*);
UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*);
UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*);
UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*);
@ -1432,6 +1456,12 @@ UV_EXTERN int uv_fs_futime(uv_loop_t* loop,
double atime,
double mtime,
uv_fs_cb cb);
UV_EXTERN int uv_fs_lutime(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
double atime,
double mtime,
uv_fs_cb cb);
UV_EXTERN int uv_fs_lstat(uv_loop_t* loop,
uv_fs_t* req,
const char* path,

View File

@ -26,13 +26,13 @@
* Versions with the same major number are ABI stable. API is allowed to
* evolve between minor releases, but only in a backwards compatible way.
* Make sure you update the -soname directives in configure.ac
* and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
* whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
* not UV_VERSION_PATCH.)
*/
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 34
#define UV_VERSION_PATCH 2
#define UV_VERSION_MINOR 38
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""

View File

@ -517,7 +517,7 @@ typedef struct {
/* eol conversion state */ \
unsigned char previous_eol; \
/* ansi parser state */ \
unsigned char ansi_parser_state; \
unsigned short ansi_parser_state; \
unsigned char ansi_csi_argc; \
unsigned short ansi_csi_argv[4]; \
COORD saved_position; \

View File

@ -160,8 +160,8 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
}
void uv__threadpool_cleanup(void) {
#ifndef _WIN32
UV_DESTRUCTOR(static void cleanup(void)) {
unsigned int i;
if (nthreads == 0)
@ -181,8 +181,8 @@ UV_DESTRUCTOR(static void cleanup(void)) {
threads = NULL;
nthreads = 0;
}
#endif
}
static void init_threads(void) {

View File

@ -51,12 +51,7 @@ static int timer_less_than(const struct heap_node* ha,
/* Compare start_id when both have the same timeout. start_id is
* allocated with loop->timer_counter in uv_timer_start().
*/
if (a->start_id < b->start_id)
return 1;
if (b->start_id < a->start_id)
return 0;
return 0;
return a->start_id < b->start_id;
}
@ -87,7 +82,7 @@ int uv_timer_start(uv_timer_t* handle,
handle->timer_cb = cb;
handle->timeout = clamped_timeout;
handle->repeat = repeat;
/* start_id is the second index to be compared in uv__timer_cmp() */
/* start_id is the second index to be compared in timer_less_than() */
handle->start_id = handle->loop->timer_counter++;
heap_insert(timer_heap(handle->loop),

View File

@ -926,7 +926,7 @@ int uv_get_process_title(char* buffer, size_t size) {
}
UV_DESTRUCTOR(static void free_args_mem(void)) {
void uv__process_title_cleanup(void) {
uv__free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}

View File

@ -470,13 +470,14 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
{
case IFA_ADDRESS:
case IFA_LOCAL:
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
{
/* Make room for netmask */
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
l_addedNetmask = 1;
}
break;
break;
case IFA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
break;

View File

@ -32,10 +32,14 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h> /* sched_yield() */
#ifdef __linux__
#include <sys/eventfd.h>
#endif
static void uv__async_send(uv_loop_t* loop);
static int uv__async_start(uv_loop_t* loop);
static int uv__async_eventfd(void);
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
@ -78,20 +82,32 @@ int uv_async_send(uv_async_t* handle) {
/* Only call this from the event loop thread. */
static int uv__async_spin(uv_async_t* handle) {
int i;
int rc;
for (;;) {
/* rc=0 -- handle is not pending.
* rc=1 -- handle is pending, other thread is still working with it.
* rc=2 -- handle is pending, other thread is done.
/* 997 is not completely chosen at random. It's a prime number, acyclical
* by nature, and should therefore hopefully dampen sympathetic resonance.
*/
rc = cmpxchgi(&handle->pending, 2, 0);
for (i = 0; i < 997; i++) {
/* rc=0 -- handle is not pending.
* rc=1 -- handle is pending, other thread is still working with it.
* rc=2 -- handle is pending, other thread is done.
*/
rc = cmpxchgi(&handle->pending, 2, 0);
if (rc != 1)
return rc;
if (rc != 1)
return rc;
/* Other thread is busy with this handle, spin until it's done. */
cpu_relax();
/* Other thread is busy with this handle, spin until it's done. */
cpu_relax();
}
/* Yield the CPU. We may have preempted the other thread while it's
* inside the critical section and if it's running on the same CPU
* as us, we'll just burn CPU cycles until the end of our time slice.
*/
sched_yield();
}
}
@ -190,36 +206,18 @@ static int uv__async_start(uv_loop_t* loop) {
if (loop->async_io_watcher.fd != -1)
return 0;
err = uv__async_eventfd();
if (err >= 0) {
pipefd[0] = err;
pipefd[1] = -1;
}
else if (err == UV_ENOSYS) {
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
#if defined(__linux__)
/* Save a file descriptor by opening one of the pipe descriptors as
* read/write through the procfs. That file descriptor can then
* function as both ends of the pipe.
*/
if (err == 0) {
char buf[32];
int fd;
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
fd = uv__open_cloexec(buf, O_RDWR);
if (fd >= 0) {
uv__close(pipefd[0]);
uv__close(pipefd[1]);
pipefd[0] = fd;
pipefd[1] = fd;
}
}
#endif
}
#ifdef __linux__
err = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (err < 0)
return UV__ERR(errno);
pipefd[0] = err;
pipefd[1] = -1;
#else
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
if (err < 0)
return err;
#endif
uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]);
uv__io_start(loop, &loop->async_io_watcher, POLLIN);
@ -253,46 +251,3 @@ void uv__async_stop(uv_loop_t* loop) {
uv__close(loop->async_io_watcher.fd);
loop->async_io_watcher.fd = -1;
}
static int uv__async_eventfd(void) {
#if defined(__linux__)
static int no_eventfd2;
static int no_eventfd;
int fd;
if (no_eventfd2)
goto skip_eventfd2;
fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
if (fd != -1)
return fd;
if (errno != ENOSYS)
return UV__ERR(errno);
no_eventfd2 = 1;
skip_eventfd2:
if (no_eventfd)
goto skip_eventfd;
fd = uv__eventfd(0);
if (fd != -1) {
uv__cloexec(fd, 1);
uv__nonblock(fd, 1);
return fd;
}
if (errno != ENOSYS)
return UV__ERR(errno);
no_eventfd = 1;
skip_eventfd:
#endif
return UV_ENOSYS;
}

View File

@ -53,6 +53,8 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
UV_UNUSED(static void cpu_relax(void)) {
#if defined(__i386__) || defined(__x86_64__)
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
__asm__ volatile("yield");
#endif
}

View File

@ -37,6 +37,13 @@ static void init_process_title_mutex_once(void) {
}
void uv__process_title_cleanup(void) {
/* TODO(bnoordhuis) uv_mutex_destroy(&process_title_mutex)
* and reset process_title_mutex_once?
*/
}
char** uv_setup_args(int argc, char** argv) {
process_title = argc > 0 ? uv__strdup(argv[0]) : NULL;
return argv;

View File

@ -71,20 +71,12 @@ extern char** environ;
# include <sys/sysctl.h>
# include <sys/filio.h>
# include <sys/wait.h>
# if defined(__FreeBSD__) && __FreeBSD__ >= 10
# if defined(__FreeBSD__)
# define uv__accept4 accept4
# endif
# if defined(__NetBSD__)
# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
# endif
# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
defined(__NetBSD__) || defined(__OpenBSD__)
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
# endif
# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
# endif
#endif
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
@ -96,7 +88,8 @@ extern char** environ;
#endif
#if defined(__linux__)
#include <sys/syscall.h>
# include <sys/syscall.h>
# define uv__accept4 accept4
#endif
static int uv__run_pending(uv_loop_t* loop);
@ -179,9 +172,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
case UV_SIGNAL:
uv__signal_close((uv_signal_t*) handle);
/* Signal handles may not be closed immediately. The signal code will
* itself close uv__make_close_pending whenever appropriate. */
return;
break;
default:
assert(0);
@ -246,6 +237,8 @@ int uv__getiovmax(void) {
static void uv__finish_close(uv_handle_t* handle) {
uv_signal_t* sh;
/* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
* possible for it to be active in the sense that uv__is_active() returns
* true.
@ -268,7 +261,20 @@ static void uv__finish_close(uv_handle_t* handle) {
case UV_FS_EVENT:
case UV_FS_POLL:
case UV_POLL:
break;
case UV_SIGNAL:
/* If there are any caught signals "trapped" in the signal pipe,
* we can't call the close callback yet. Reinserting the handle
* into the closing queue makes the event loop spin but that's
* okay because we only need to deliver the pending events.
*/
sh = (uv_signal_t*) handle;
if (sh->caught_signals > sh->dispatched_signals) {
handle->flags ^= UV_HANDLE_CLOSED;
uv__make_close_pending(handle); /* Back into the queue. */
return;
}
break;
case UV_NAMED_PIPE:
@ -472,52 +478,32 @@ int uv__accept(int sockfd) {
int peerfd;
int err;
(void) &err;
assert(sockfd >= 0);
while (1) {
#if defined(__linux__) || \
(defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
defined(__NetBSD__)
static int no_accept4;
do
#ifdef uv__accept4
peerfd = uv__accept4(sockfd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
#else
peerfd = accept(sockfd, NULL, NULL);
#endif
while (peerfd == -1 && errno == EINTR);
if (no_accept4)
goto skip;
if (peerfd == -1)
return UV__ERR(errno);
peerfd = uv__accept4(sockfd,
NULL,
NULL,
UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
if (peerfd != -1)
return peerfd;
#ifndef uv__accept4
err = uv__cloexec(peerfd, 1);
if (err == 0)
err = uv__nonblock(peerfd, 1);
if (errno == EINTR)
continue;
if (errno != ENOSYS)
return UV__ERR(errno);
no_accept4 = 1;
skip:
if (err != 0) {
uv__close(peerfd);
return err;
}
#endif
peerfd = accept(sockfd, NULL, NULL);
if (peerfd == -1) {
if (errno == EINTR)
continue;
return UV__ERR(errno);
}
err = uv__cloexec(peerfd, 1);
if (err == 0)
err = uv__nonblock(peerfd, 1);
if (err) {
uv__close(peerfd);
return err;
}
return peerfd;
}
return peerfd;
}
@ -533,7 +519,7 @@ int uv__close_nocancel(int fd) {
#if defined(__APPLE__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
#if defined(__LP64__)
#if defined(__LP64__) || TARGET_OS_IPHONE
extern int close$NOCANCEL(int);
return close$NOCANCEL(fd);
#else
@ -849,8 +835,8 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
}
nwatchers = next_power_of_two(len + 2) - 2;
watchers = uv__realloc(loop->watchers,
(nwatchers + 2) * sizeof(loop->watchers[0]));
watchers = uv__reallocf(loop->watchers,
(nwatchers + 2) * sizeof(loop->watchers[0]));
if (watchers == NULL)
abort();
@ -1031,54 +1017,30 @@ int uv__open_cloexec(const char* path, int flags) {
int uv__dup2_cloexec(int oldfd, int newfd) {
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
int r;
#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
r = dup3(oldfd, newfd, O_CLOEXEC);
if (r == -1)
return UV__ERR(errno);
return r;
#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
if (r != -1)
return r;
if (errno != EINVAL)
return UV__ERR(errno);
/* Fall through. */
#elif defined(__linux__)
static int no_dup3;
if (!no_dup3) {
do
r = uv__dup3(oldfd, newfd, O_CLOEXEC);
while (r == -1 && errno == EBUSY);
if (r != -1)
return r;
if (errno != ENOSYS)
return UV__ERR(errno);
/* Fall through. */
no_dup3 = 1;
}
#endif
{
int err;
do
r = dup2(oldfd, newfd);
#if defined(__linux__)
while (r == -1 && errno == EBUSY);
#else
while (0); /* Never retry. */
#endif
int err;
int r;
if (r == -1)
return UV__ERR(errno);
r = dup2(oldfd, newfd); /* Never retry. */
if (r == -1)
return UV__ERR(errno);
err = uv__cloexec(newfd, 1);
if (err) {
uv__close(newfd);
return err;
}
return r;
err = uv__cloexec(newfd, 1);
if (err != 0) {
uv__close(newfd);
return err;
}
return r;
#endif
}
@ -1296,7 +1258,7 @@ int uv_os_environ(uv_env_item_t** envitems, int* count) {
*envitems = uv__calloc(i, sizeof(**envitems));
if (envitems == NULL)
if (*envitems == NULL)
return UV_ENOMEM;
for (j = 0, cnt = 0; j < i; j++) {

View File

@ -30,8 +30,7 @@
#include <TargetConditionals.h>
#if !TARGET_OS_IPHONE
# include <CoreFoundation/CoreFoundation.h>
# include <ApplicationServices/ApplicationServices.h>
#include "darwin-stub.h"
#endif

97
deps/libuv/src/unix/darwin-stub.h vendored Normal file
View File

@ -0,0 +1,97 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_DARWIN_STUB_H_
#define UV_DARWIN_STUB_H_
#include <stdint.h>
struct CFArrayCallBacks;
struct CFRunLoopSourceContext;
struct FSEventStreamContext;
typedef double CFAbsoluteTime;
typedef double CFTimeInterval;
typedef int FSEventStreamEventFlags;
typedef int OSStatus;
typedef long CFIndex;
typedef struct CFArrayCallBacks CFArrayCallBacks;
typedef struct CFRunLoopSourceContext CFRunLoopSourceContext;
typedef struct FSEventStreamContext FSEventStreamContext;
typedef uint32_t FSEventStreamCreateFlags;
typedef uint64_t FSEventStreamEventId;
typedef unsigned CFStringEncoding;
typedef void* CFAllocatorRef;
typedef void* CFArrayRef;
typedef void* CFBundleRef;
typedef void* CFDictionaryRef;
typedef void* CFRunLoopRef;
typedef void* CFRunLoopSourceRef;
typedef void* CFStringRef;
typedef void* CFTypeRef;
typedef void* FSEventStreamRef;
typedef void (*FSEventStreamCallback)(const FSEventStreamRef,
void*,
size_t,
void*,
const FSEventStreamEventFlags*,
const FSEventStreamEventId*);
struct CFRunLoopSourceContext {
CFIndex version;
void* info;
void* pad[7];
void (*perform)(void*);
};
struct FSEventStreamContext {
CFIndex version;
void* info;
void* pad[3];
};
static const CFStringEncoding kCFStringEncodingUTF8 = 0x8000100;
static const OSStatus noErr = 0;
static const FSEventStreamEventId kFSEventStreamEventIdSinceNow = -1;
static const int kFSEventStreamCreateFlagNoDefer = 2;
static const int kFSEventStreamCreateFlagFileEvents = 16;
static const int kFSEventStreamEventFlagEventIdsWrapped = 8;
static const int kFSEventStreamEventFlagHistoryDone = 16;
static const int kFSEventStreamEventFlagItemChangeOwner = 0x4000;
static const int kFSEventStreamEventFlagItemCreated = 0x100;
static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x2000;
static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x400;
static const int kFSEventStreamEventFlagItemIsDir = 0x20000;
static const int kFSEventStreamEventFlagItemModified = 0x1000;
static const int kFSEventStreamEventFlagItemRemoved = 0x200;
static const int kFSEventStreamEventFlagItemRenamed = 0x800;
static const int kFSEventStreamEventFlagItemXattrMod = 0x8000;
static const int kFSEventStreamEventFlagKernelDropped = 4;
static const int kFSEventStreamEventFlagMount = 64;
static const int kFSEventStreamEventFlagRootChanged = 32;
static const int kFSEventStreamEventFlagUnmount = 128;
static const int kFSEventStreamEventFlagUserDropped = 2;
#endif /* UV_DARWIN_STUB_H_ */

View File

@ -288,3 +288,28 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv__free(cp_times);
return 0;
}
int uv__sendmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags) {
#if __FreeBSD__ >= 11
return sendmmsg(fd, mmsg, vlen, flags);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__recvmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags,
struct timespec* timeout) {
#if __FreeBSD__ >= 11
return recvmmsg(fd, mmsg, vlen, flags, timeout);
#else
return errno = ENOSYS, -1;
#endif
}

View File

@ -205,6 +205,20 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
}
UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
struct timespec ts;
ts.tv_sec = time;
ts.tv_nsec = (uint64_t)(time * 1000000) % 1000000 * 1000;
return ts;
}
UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
struct timeval tv;
tv.tv_sec = time;
tv.tv_usec = (uint64_t)(time * 1000000) % 1000000;
return tv;
}
static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__) \
|| defined(_AIX71) \
@ -213,10 +227,8 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
* for the sake of consistency with other platforms.
*/
struct timespec ts[2];
ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
return utimensat(req->file, NULL, ts, 0);
#else
@ -230,10 +242,8 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
|| defined(__OpenBSD__) \
|| defined(__sun)
struct timeval tv[2];
tv[0].tv_sec = req->atime;
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
tv[0] = uv__fs_to_timeval(req->atime);
tv[1] = uv__fs_to_timeval(req->mtime);
# if defined(__sun)
return futimesat(req->file, NULL, tv);
# else
@ -666,7 +676,6 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
ssize_t maxlen;
ssize_t len;
char* buf;
char* newbuf;
#if defined(_POSIX_PATH_MAX) || defined(PATH_MAX)
maxlen = uv__fs_pathmax_size(req->path);
@ -710,14 +719,10 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
/* Uncommon case: resize to make room for the trailing nul byte. */
if (len == maxlen) {
newbuf = uv__realloc(buf, len + 1);
buf = uv__reallocf(buf, len + 1);
if (newbuf == NULL) {
uv__free(buf);
if (buf == NULL)
return -1;
}
buf = newbuf;
}
buf[len] = '\0';
@ -977,10 +982,8 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
* for the sake of consistency with other platforms.
*/
struct timespec ts[2];
ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);
return utimensat(AT_FDCWD, req->path, ts, 0);
#elif defined(__APPLE__) \
|| defined(__DragonFly__) \
@ -989,10 +992,8 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|| defined(__NetBSD__) \
|| defined(__OpenBSD__)
struct timeval tv[2];
tv[0].tv_sec = req->atime;
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
tv[0] = uv__fs_to_timeval(req->atime);
tv[1] = uv__fs_to_timeval(req->mtime);
return utimes(req->path, tv);
#elif defined(_AIX) \
&& !defined(_AIX71)
@ -1015,6 +1016,31 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
}
static ssize_t uv__fs_lutime(uv_fs_t* req) {
#if defined(__linux__) || \
defined(_AIX71) || \
defined(__sun) || \
defined(__HAIKU__)
struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);
return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW);
#elif defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__NetBSD__)
struct timeval tv[2];
tv[0] = uv__fs_to_timeval(req->atime);
tv[1] = uv__fs_to_timeval(req->mtime);
return lutimes(req->path, tv);
#else
errno = ENOSYS;
return -1;
#endif
}
static ssize_t uv__fs_write(uv_fs_t* req) {
#if defined(__linux__)
static int no_pwritev;
@ -1084,9 +1110,10 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
int dst_flags;
int result;
int err;
size_t bytes_to_send;
int64_t in_offset;
ssize_t bytes_written;
off_t bytes_to_send;
off_t in_offset;
off_t bytes_written;
size_t bytes_chunk;
dstfd = -1;
err = 0;
@ -1185,7 +1212,10 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
bytes_to_send = src_statsbuf.st_size;
in_offset = 0;
while (bytes_to_send != 0) {
uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, in_offset, bytes_to_send, NULL);
bytes_chunk = SSIZE_MAX;
if (bytes_to_send < (off_t) bytes_chunk)
bytes_chunk = bytes_to_send;
uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, in_offset, bytes_chunk, NULL);
bytes_written = fs_req.result;
uv_fs_req_cleanup(&fs_req);
@ -1528,6 +1558,7 @@ static void uv__fs_work(struct uv__work* w) {
X(FSYNC, uv__fs_fsync(req));
X(FTRUNCATE, ftruncate(req->file, req->off));
X(FUTIME, uv__fs_futime(req));
X(LUTIME, uv__fs_lutime(req));
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
X(LINK, link(req->path, req->new_path));
X(MKDIR, mkdir(req->path, req->mode));
@ -1714,6 +1745,19 @@ int uv_fs_futime(uv_loop_t* loop,
POST;
}
int uv_fs_lutime(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
double atime,
double mtime,
uv_fs_cb cb) {
INIT(LUTIME);
PATH;
req->atime = atime;
req->mtime = mtime;
POST;
}
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
INIT(LSTAT);
@ -2042,3 +2086,7 @@ int uv_fs_statfs(uv_loop_t* loop,
PATH;
POST;
}
int uv_fs_get_system_error(const uv_fs_t* req) {
return -req->result;
}

View File

@ -41,34 +41,33 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) {
#else /* TARGET_OS_IPHONE */
#include "darwin-stub.h"
#include <dlfcn.h>
#include <assert.h>
#include <stdlib.h>
#include <pthread.h>
#include <CoreFoundation/CFRunLoop.h>
#include <CoreServices/CoreServices.h>
static const int kFSEventsModified =
kFSEventStreamEventFlagItemChangeOwner |
kFSEventStreamEventFlagItemFinderInfoMod |
kFSEventStreamEventFlagItemInodeMetaMod |
kFSEventStreamEventFlagItemModified |
kFSEventStreamEventFlagItemXattrMod;
/* These are macros to avoid "initializer element is not constant" errors
* with old versions of gcc.
*/
#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
kFSEventStreamEventFlagItemModified | \
kFSEventStreamEventFlagItemInodeMetaMod | \
kFSEventStreamEventFlagItemChangeOwner | \
kFSEventStreamEventFlagItemXattrMod)
static const int kFSEventsRenamed =
kFSEventStreamEventFlagItemCreated |
kFSEventStreamEventFlagItemRemoved |
kFSEventStreamEventFlagItemRenamed;
#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
kFSEventStreamEventFlagItemRemoved | \
kFSEventStreamEventFlagItemRenamed)
#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
kFSEventStreamEventFlagKernelDropped | \
kFSEventStreamEventFlagEventIdsWrapped | \
kFSEventStreamEventFlagHistoryDone | \
kFSEventStreamEventFlagMount | \
kFSEventStreamEventFlagUnmount | \
kFSEventStreamEventFlagRootChanged)
static const int kFSEventsSystem =
kFSEventStreamEventFlagUserDropped |
kFSEventStreamEventFlagKernelDropped |
kFSEventStreamEventFlagEventIdsWrapped |
kFSEventStreamEventFlagHistoryDone |
kFSEventStreamEventFlagMount |
kFSEventStreamEventFlagUnmount |
kFSEventStreamEventFlagRootChanged;
typedef struct uv__fsevents_event_s uv__fsevents_event_t;
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
@ -148,7 +147,7 @@ static void (*pFSEventStreamRelease)(FSEventStreamRef);
static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
CFRunLoopRef,
CFStringRef);
static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
static int (*pFSEventStreamStart)(FSEventStreamRef);
static void (*pFSEventStreamStop)(FSEventStreamRef);
#define UV__FSEVENTS_PROCESS(handle, block) \
@ -215,7 +214,7 @@ static void uv__fsevents_push_event(uv_fs_event_t* handle,
/* Runs in CF thread, when there're events in FSEventStream */
static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
void* info,
size_t numEvents,
void* eventPaths,
@ -340,11 +339,8 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
FSEventStreamCreateFlags flags;
/* Initialize context */
ctx.version = 0;
memset(&ctx, 0, sizeof(ctx));
ctx.info = loop;
ctx.retain = NULL;
ctx.release = NULL;
ctx.copyDescription = NULL;
latency = 0.05;

View File

@ -225,22 +225,7 @@ uint64_t uv_get_free_memory(void) {
if (get_ibmi_system_status(&rcvr))
return 0;
/* The amount of main storage, in kilobytes, in the system. */
uint64_t main_storage_size = rcvr.main_storage_size;
/* The current amount of storage in use for temporary objects.
* in millions (M) of bytes.
*/
uint64_t current_unprotected_storage_used =
rcvr.current_unprotected_storage_used * 1024ULL;
/* Current unprotected storage includes the storage used for memory
* and disks so it is possible to exceed the amount of main storage.
*/
if (main_storage_size <= current_unprotected_storage_used)
return 0ULL;
return (main_storage_size - current_unprotected_storage_used) * 1024ULL;
return (uint64_t)rcvr.main_storage_size * 1024ULL;
}

View File

@ -28,9 +28,10 @@
#include <limits.h> /* _POSIX_PATH_MAX, PATH_MAX */
#include <stdlib.h> /* abort */
#include <string.h> /* strrchr */
#include <fcntl.h> /* O_CLOEXEC, may be */
#include <fcntl.h> /* O_CLOEXEC and O_NONBLOCK, if supported. */
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#if defined(__STRICT_ANSI__)
# define inline __inline
@ -105,10 +106,8 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
#if defined(__clang__) || \
defined(__GNUC__) || \
defined(__INTEL_COMPILER)
# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
#else
# define UV_DESTRUCTOR(declaration) declaration
# define UV_UNUSED(declaration) declaration
#endif
@ -284,13 +283,12 @@ int uv___stream_fd(const uv_stream_t* handle);
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
#endif /* defined(__APPLE__) */
#ifdef UV__O_NONBLOCK
# define UV__F_NONBLOCK UV__O_NONBLOCK
#ifdef O_NONBLOCK
# define UV__F_NONBLOCK O_NONBLOCK
#else
# define UV__F_NONBLOCK 1
#endif
int uv__make_socketpair(int fds[2], int flags);
int uv__make_pipe(int fds[2], int flags);
#if defined(__APPLE__)
@ -328,4 +326,27 @@ int uv__getsockpeername(const uv_handle_t* handle,
struct sockaddr* name,
int* namelen);
#if defined(__linux__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__)
#define HAVE_MMSG 1
struct uv__mmsghdr {
struct msghdr msg_hdr;
unsigned int msg_len;
};
int uv__recvmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags,
struct timespec* timeout);
int uv__sendmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags);
#else
#define HAVE_MMSG 0
#endif
#endif /* UV_UNIX_INTERNAL_H_ */

View File

@ -768,7 +768,8 @@ static int read_times(FILE* statfile_fp,
unsigned int numcpus,
uv_cpu_info_t* ci) {
struct uv_cpu_times_s ts;
uint64_t clock_ticks;
unsigned int ticks;
unsigned int multiplier;
uint64_t user;
uint64_t nice;
uint64_t sys;
@ -779,9 +780,10 @@ static int read_times(FILE* statfile_fp,
uint64_t len;
char buf[1024];
clock_ticks = sysconf(_SC_CLK_TCK);
assert(clock_ticks != (uint64_t) -1);
assert(clock_ticks != 0);
ticks = (unsigned int)sysconf(_SC_CLK_TCK);
multiplier = ((uint64_t)1000L / ticks);
assert(ticks != (unsigned int) -1);
assert(ticks != 0);
rewind(statfile_fp);
@ -823,11 +825,11 @@ static int read_times(FILE* statfile_fp,
&irq))
abort();
ts.user = clock_ticks * user;
ts.nice = clock_ticks * nice;
ts.sys = clock_ticks * sys;
ts.idle = clock_ticks * idle;
ts.irq = clock_ticks * irq;
ts.user = user * multiplier;
ts.nice = nice * multiplier;
ts.sys = sys * multiplier;
ts.idle = idle * multiplier;
ts.irq = irq * multiplier;
ci[num++].cpu_times = ts;
}
assert(num == numcpus);

View File

@ -29,6 +29,7 @@
#include <assert.h>
#include <errno.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <unistd.h>
@ -64,45 +65,17 @@ static void uv__inotify_read(uv_loop_t* loop,
static void maybe_free_watcher_list(struct watcher_list* w,
uv_loop_t* loop);
static int new_inotify_fd(void) {
int err;
int fd;
fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
if (fd != -1)
return fd;
if (errno != ENOSYS)
return UV__ERR(errno);
fd = uv__inotify_init();
if (fd == -1)
return UV__ERR(errno);
err = uv__cloexec(fd, 1);
if (err == 0)
err = uv__nonblock(fd, 1);
if (err) {
uv__close(fd);
return err;
}
return fd;
}
static int init_inotify(uv_loop_t* loop) {
int err;
int fd;
if (loop->inotify_fd != -1)
return 0;
err = new_inotify_fd();
if (err < 0)
return err;
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (fd < 0)
return UV__ERR(errno);
loop->inotify_fd = err;
loop->inotify_fd = fd;
uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
uv__io_start(loop, &loop->inotify_read_watcher, POLLIN);
@ -186,7 +159,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
/* No watchers left for this path. Clean up. */
RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
uv__inotify_rm_watch(loop->inotify_fd, w->wd);
inotify_rm_watch(loop->inotify_fd, w->wd);
uv__free(w);
}
}
@ -194,7 +167,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
static void uv__inotify_read(uv_loop_t* loop,
uv__io_t* dummy,
unsigned int events) {
const struct uv__inotify_event* e;
const struct inotify_event* e;
struct watcher_list* w;
uv_fs_event_t* h;
QUEUE queue;
@ -219,12 +192,12 @@ static void uv__inotify_read(uv_loop_t* loop,
/* Now we have one or more inotify_event structs. */
for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
e = (const struct uv__inotify_event*)p;
e = (const struct inotify_event*) p;
events = 0;
if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
if (e->mask & (IN_ATTRIB|IN_MODIFY))
events |= UV_CHANGE;
if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
if (e->mask & ~(IN_ATTRIB|IN_MODIFY))
events |= UV_RENAME;
w = find_watcher(loop, e->wd);
@ -290,16 +263,16 @@ int uv_fs_event_start(uv_fs_event_t* handle,
if (err)
return err;
events = UV__IN_ATTRIB
| UV__IN_CREATE
| UV__IN_MODIFY
| UV__IN_DELETE
| UV__IN_DELETE_SELF
| UV__IN_MOVE_SELF
| UV__IN_MOVED_FROM
| UV__IN_MOVED_TO;
events = IN_ATTRIB
| IN_CREATE
| IN_MODIFY
| IN_DELETE
| IN_DELETE_SELF
| IN_MOVE_SELF
| IN_MOVED_FROM
| IN_MOVED_TO;
wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
wd = inotify_add_watch(handle->loop->inotify_fd, path, events);
if (wd == -1)
return UV__ERR(errno);

View File

@ -26,19 +26,6 @@
#include <sys/types.h>
#include <errno.h>
#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
# define MSAN_ACTIVE 1
# include <sanitizer/msan_interface.h>
# endif
#endif
#if defined(__i386__)
# ifndef __NR_socketcall
# define __NR_socketcall 102
# endif
#endif
#if defined(__arm__)
# if defined(__thumb__) || defined(__ARM_EABI__)
# define UV_SYSCALL_BASE 0
@ -47,86 +34,6 @@
# endif
#endif /* __arm__ */
#ifndef __NR_accept4
# if defined(__x86_64__)
# define __NR_accept4 288
# elif defined(__i386__)
/* Nothing. Handled through socketcall(). */
# elif defined(__arm__)
# define __NR_accept4 (UV_SYSCALL_BASE + 366)
# endif
#endif /* __NR_accept4 */
#ifndef __NR_eventfd
# if defined(__x86_64__)
# define __NR_eventfd 284
# elif defined(__i386__)
# define __NR_eventfd 323
# elif defined(__arm__)
# define __NR_eventfd (UV_SYSCALL_BASE + 351)
# endif
#endif /* __NR_eventfd */
#ifndef __NR_eventfd2
# if defined(__x86_64__)
# define __NR_eventfd2 290
# elif defined(__i386__)
# define __NR_eventfd2 328
# elif defined(__arm__)
# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
# endif
#endif /* __NR_eventfd2 */
#ifndef __NR_inotify_init
# if defined(__x86_64__)
# define __NR_inotify_init 253
# elif defined(__i386__)
# define __NR_inotify_init 291
# elif defined(__arm__)
# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
# endif
#endif /* __NR_inotify_init */
#ifndef __NR_inotify_init1
# if defined(__x86_64__)
# define __NR_inotify_init1 294
# elif defined(__i386__)
# define __NR_inotify_init1 332
# elif defined(__arm__)
# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
# endif
#endif /* __NR_inotify_init1 */
#ifndef __NR_inotify_add_watch
# if defined(__x86_64__)
# define __NR_inotify_add_watch 254
# elif defined(__i386__)
# define __NR_inotify_add_watch 292
# elif defined(__arm__)
# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
# endif
#endif /* __NR_inotify_add_watch */
#ifndef __NR_inotify_rm_watch
# if defined(__x86_64__)
# define __NR_inotify_rm_watch 255
# elif defined(__i386__)
# define __NR_inotify_rm_watch 293
# elif defined(__arm__)
# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
# endif
#endif /* __NR_inotify_rm_watch */
#ifndef __NR_pipe2
# if defined(__x86_64__)
# define __NR_pipe2 293
# elif defined(__i386__)
# define __NR_pipe2 331
# elif defined(__arm__)
# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
# endif
#endif /* __NR_pipe2 */
#ifndef __NR_recvmmsg
# if defined(__x86_64__)
# define __NR_recvmmsg 299
@ -219,103 +126,7 @@
# endif
#endif /* __NR_getrandom */
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
#if defined(__i386__)
unsigned long args[4];
int r;
args[0] = (unsigned long) fd;
args[1] = (unsigned long) addr;
args[2] = (unsigned long) addrlen;
args[3] = (unsigned long) flags;
r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
/* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does
* a bad flags argument. Try to distinguish between the two cases.
*/
if (r == -1)
if (errno == EINVAL)
if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0)
errno = ENOSYS;
return r;
#elif defined(__NR_accept4)
return syscall(__NR_accept4, fd, addr, addrlen, flags);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__eventfd(unsigned int count) {
#if defined(__NR_eventfd)
return syscall(__NR_eventfd, count);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__eventfd2(unsigned int count, int flags) {
#if defined(__NR_eventfd2)
return syscall(__NR_eventfd2, count, flags);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__inotify_init(void) {
#if defined(__NR_inotify_init)
return syscall(__NR_inotify_init);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__inotify_init1(int flags) {
#if defined(__NR_inotify_init1)
return syscall(__NR_inotify_init1, flags);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) {
#if defined(__NR_inotify_add_watch)
return syscall(__NR_inotify_add_watch, fd, path, mask);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__inotify_rm_watch(int fd, int32_t wd) {
#if defined(__NR_inotify_rm_watch)
return syscall(__NR_inotify_rm_watch, fd, wd);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__pipe2(int pipefd[2], int flags) {
#if defined(__NR_pipe2)
int result;
result = syscall(__NR_pipe2, pipefd, flags);
#if MSAN_ACTIVE
if (!result)
__msan_unpoison(pipefd, sizeof(int[2]));
#endif
return result;
#else
return errno = ENOSYS, -1;
#endif
}
struct uv__mmsghdr;
int uv__sendmmsg(int fd,
struct uv__mmsghdr* mmsg,

View File

@ -31,55 +31,6 @@
#include <sys/time.h>
#include <sys/socket.h>
#if defined(__alpha__)
# define UV__O_CLOEXEC 0x200000
#elif defined(__hppa__)
# define UV__O_CLOEXEC 0x200000
#elif defined(__sparc__)
# define UV__O_CLOEXEC 0x400000
#else
# define UV__O_CLOEXEC 0x80000
#endif
#if defined(__alpha__)
# define UV__O_NONBLOCK 0x4
#elif defined(__hppa__)
# define UV__O_NONBLOCK O_NONBLOCK
#elif defined(__mips__)
# define UV__O_NONBLOCK 0x80
#elif defined(__sparc__)
# define UV__O_NONBLOCK 0x4000
#else
# define UV__O_NONBLOCK 0x800
#endif
#define UV__EFD_CLOEXEC UV__O_CLOEXEC
#define UV__EFD_NONBLOCK UV__O_NONBLOCK
#define UV__IN_CLOEXEC UV__O_CLOEXEC
#define UV__IN_NONBLOCK UV__O_NONBLOCK
#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
#if defined(SOCK_NONBLOCK)
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
#else
# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
#endif
/* inotify flags */
#define UV__IN_ACCESS 0x001
#define UV__IN_MODIFY 0x002
#define UV__IN_ATTRIB 0x004
#define UV__IN_CLOSE_WRITE 0x008
#define UV__IN_CLOSE_NOWRITE 0x010
#define UV__IN_OPEN 0x020
#define UV__IN_MOVED_FROM 0x040
#define UV__IN_MOVED_TO 0x080
#define UV__IN_CREATE 0x100
#define UV__IN_DELETE 0x200
#define UV__IN_DELETE_SELF 0x400
#define UV__IN_MOVE_SELF 0x800
struct uv__statx_timestamp {
int64_t tv_sec;
uint32_t tv_nsec;
@ -110,36 +61,6 @@ struct uv__statx {
uint64_t unused1[14];
};
struct uv__inotify_event {
int32_t wd;
uint32_t mask;
uint32_t cookie;
uint32_t len;
/* char name[0]; */
};
struct uv__mmsghdr {
struct msghdr msg_hdr;
unsigned int msg_len;
};
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
int uv__eventfd(unsigned int count);
int uv__eventfd2(unsigned int count, int flags);
int uv__inotify_init(void);
int uv__inotify_init1(int flags);
int uv__inotify_add_watch(int fd, const char* path, uint32_t mask);
int uv__inotify_rm_watch(int fd, int32_t wd);
int uv__pipe2(int pipefd[2], int flags);
int uv__recvmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags,
struct timespec* timeout);
int uv__sendmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags);
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
int uv__dup3(int oldfd, int newfd, int flags);

View File

@ -106,6 +106,8 @@ fail_rwlock_init:
fail_signal_init:
uv__platform_loop_delete(loop);
uv__free(loop->watchers);
loop->nwatchers = 0;
return err;
}

View File

@ -29,6 +29,9 @@ char** uv_setup_args(int argc, char** argv) {
return argv;
}
void uv__process_title_cleanup(void) {
}
int uv_set_process_title(const char* title) {
return 0;
}

View File

@ -61,7 +61,6 @@ void uv_loadavg(double avg[3]) {
int uv_exepath(char* buffer, size_t* size) {
int mib[4];
char **argsbuf = NULL;
char **argsbuf_tmp;
size_t argsbuf_size = 100U;
size_t exepath_size;
pid_t mypid;
@ -73,10 +72,9 @@ int uv_exepath(char* buffer, size_t* size) {
mypid = getpid();
for (;;) {
err = UV_ENOMEM;
argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size);
if (argsbuf_tmp == NULL)
argsbuf = uv__reallocf(argsbuf, argsbuf_size);
if (argsbuf == NULL)
goto out;
argsbuf = argsbuf_tmp;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = mypid;
@ -185,7 +183,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
char model[512];
int numcpus = 1;
int which[] = {CTL_HW,HW_MODEL};
int percpu[] = {CTL_HW,HW_CPUSPEED,0};
int percpu[] = {CTL_KERN,KERN_CPTIME2,0};
size_t size;
int i, j;
uv_cpu_info_t* cpu_info;
@ -206,17 +204,15 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
i = 0;
*count = numcpus;
which[1] = HW_CPUSPEED;
size = sizeof(cpuspeed);
if (sysctl(which, ARRAY_SIZE(percpu), &cpuspeed, &size, NULL, 0))
if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0))
goto error;
size = sizeof(info);
percpu[0] = CTL_KERN;
percpu[1] = KERN_CPTIME2;
for (i = 0; i < numcpus; i++) {
percpu[2] = i;
size = sizeof(info);
if (sysctl(which, ARRAY_SIZE(percpu), &info, &size, NULL, 0))
if (sysctl(percpu, ARRAY_SIZE(percpu), &info, &size, NULL, 0))
goto error;
cpu_info = &(*cpu_infos)[i];

View File

@ -43,6 +43,7 @@ int scandir(const char* maindir, struct dirent*** namelist,
int (*compar)(const struct dirent**,
const struct dirent **)) {
struct dirent** nl;
struct dirent** nl_copy;
struct dirent* dirent;
unsigned count;
size_t allocated;
@ -62,19 +63,17 @@ int scandir(const char* maindir, struct dirent*** namelist,
if (!filter || filter(dirent)) {
struct dirent* copy;
copy = uv__malloc(sizeof(*copy));
if (!copy) {
while (count) {
dirent = nl[--count];
uv__free(dirent);
}
uv__free(nl);
closedir(mdir);
errno = ENOMEM;
return -1;
}
if (!copy)
goto error;
memcpy(copy, dirent, sizeof(*copy));
nl = uv__realloc(nl, sizeof(*copy) * (count + 1));
nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1));
if (nl_copy == NULL) {
uv__free(copy);
goto error;
}
nl = nl_copy;
nl[count++] = copy;
}
}
@ -86,6 +85,16 @@ int scandir(const char* maindir, struct dirent*** namelist,
*namelist = nl;
return count;
error:
while (count > 0) {
dirent = nl[--count];
uv__free(dirent);
}
uv__free(nl);
closedir(mdir);
errno = ENOMEM;
return -1;
}
@ -119,7 +128,7 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
}
newsize = next_power_of_two(len);
newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0]));
if (newlst == NULL)
abort();
@ -269,6 +278,8 @@ int epoll_ctl(uv__os390_epoll* lst,
return 0;
}
#define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd))
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
int maxevents, int timeout) {
@ -277,18 +288,41 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
int pollret;
int reventcount;
int nevents;
struct pollfd msg_fd;
int i;
_SET_FDS_MSGS(size, 1, lst->size - 1);
if (!lst || !lst->items || !events) {
errno = EFAULT;
return -1;
}
if (lst->size > EP_MAX_PFDS) {
errno = EINVAL;
return -1;
}
if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {
errno = EINVAL;
return -1;
}
if (lst->size > 0)
_SET_FDS_MSGS(size, 1, lst->size - 1);
else
_SET_FDS_MSGS(size, 0, 0);
pfds = lst->items;
pollret = poll(pfds, size, timeout);
if (pollret <= 0)
return pollret;
assert(lst->size > 0);
pollret = _NFDS(pollret) + _NMSGS(pollret);
reventcount = 0;
nevents = 0;
for (int i = 0;
msg_fd = pfds[lst->size - 1];
for (i = 0;
i < lst->size && i < maxevents && reventcount < pollret; ++i) {
struct epoll_event ev;
struct pollfd* pfd;
@ -299,6 +333,7 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
ev.fd = pfd->fd;
ev.events = pfd->revents;
ev.is_msg = 0;
if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
reventcount += 2;
else if (pfd->revents & (POLLIN | POLLOUT))
@ -308,6 +343,10 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
events[nevents++] = ev;
}
if (msg_fd.revents != 0 && msg_fd.fd != -1)
if (i == lst->size)
events[nevents - 1].is_msg = 1;
return nevents;
}
@ -369,10 +408,12 @@ int nanosleep(const struct timespec* req, struct timespec* rem) {
* Don't leak EAGAIN, that just means the timeout expired.
*/
if (rv == -1)
if (err != EAGAIN)
if (err == EAGAIN)
rv = 0;
else
errno = err;
if (rem != NULL && (rv == 0 || err == EINTR || err == EAGAIN)) {
if (rem != NULL && (rv == 0 || err == EINTR)) {
rem->tv_nsec = nanorem;
rem->tv_sec = secrem;
}
@ -517,3 +558,28 @@ size_t strnlen(const char* str, size_t maxlen) {
else
return p - str;
}
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
UNREACHABLE();
}
int sem_destroy(UV_PLATFORM_SEM_T* semid) {
UNREACHABLE();
}
int sem_post(UV_PLATFORM_SEM_T* semid) {
UNREACHABLE();
}
int sem_trywait(UV_PLATFORM_SEM_T* semid) {
UNREACHABLE();
}
int sem_wait(UV_PLATFORM_SEM_T* semid) {
UNREACHABLE();
}

View File

@ -40,6 +40,7 @@
struct epoll_event {
int events;
int fd;
int is_msg;
};
typedef struct {
@ -64,5 +65,10 @@ int scandir(const char* maindir, struct dirent*** namelist,
char *mkdtemp(char* path);
ssize_t os390_readlink(const char* path, char* buf, size_t len);
size_t strnlen(const char* str, size_t maxlen);
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value);
int sem_destroy(UV_PLATFORM_SEM_T* semid);
int sem_post(UV_PLATFORM_SEM_T* semid);
int sem_trywait(UV_PLATFORM_SEM_T* semid);
int sem_wait(UV_PLATFORM_SEM_T* semid);
#endif /* UV_OS390_SYSCALL_H_ */

View File

@ -923,7 +923,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
continue;
ep = loop->ep;
if (fd == ep->msg_queue) {
if (pe->is_msg) {
os390_message_queue_handler(ep);
continue;
}

View File

@ -95,8 +95,12 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
if (uv__stream_fd(handle) == -1)
return UV_EINVAL;
#if defined(__MVS__)
if (handle->ipc)
return UV_EINVAL;
#if defined(__MVS__) || defined(__PASE__)
/* On zOS, backlog=0 has undefined behaviour */
/* On IBMi PASE, backlog=0 leads to "Connection refused" error */
if (backlog == 0)
backlog = 1;
else if (backlog < 0)

View File

@ -61,7 +61,7 @@ static void uv__pollfds_maybe_resize(uv_loop_t* loop) {
return;
n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds));
p = uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds));
if (p == NULL)
abort();

View File

@ -112,72 +112,64 @@ static void uv__chld(uv_signal_t* handle, int signum) {
}
int uv__make_socketpair(int fds[2], int flags) {
#if defined(__linux__)
static int no_cloexec;
if (no_cloexec)
goto skip;
if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
return 0;
/* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
* Anything else is a genuine error.
*/
if (errno != EINVAL)
static int uv__make_socketpair(int fds[2]) {
#if defined(__FreeBSD__) || defined(__linux__)
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds))
return UV__ERR(errno);
no_cloexec = 1;
skip:
#endif
return 0;
#else
int err;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
return UV__ERR(errno);
uv__cloexec(fds[0], 1);
uv__cloexec(fds[1], 1);
err = uv__cloexec(fds[0], 1);
if (err == 0)
err = uv__cloexec(fds[1], 1);
if (flags & UV__F_NONBLOCK) {
uv__nonblock(fds[0], 1);
uv__nonblock(fds[1], 1);
if (err != 0) {
uv__close(fds[0]);
uv__close(fds[1]);
return UV__ERR(errno);
}
return 0;
#endif
}
int uv__make_pipe(int fds[2], int flags) {
#if defined(__linux__)
static int no_pipe2;
if (no_pipe2)
goto skip;
if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
return 0;
if (errno != ENOSYS)
#if defined(__FreeBSD__) || defined(__linux__)
if (pipe2(fds, flags | O_CLOEXEC))
return UV__ERR(errno);
no_pipe2 = 1;
skip:
#endif
return 0;
#else
if (pipe(fds))
return UV__ERR(errno);
uv__cloexec(fds[0], 1);
uv__cloexec(fds[1], 1);
if (uv__cloexec(fds[0], 1))
goto fail;
if (uv__cloexec(fds[1], 1))
goto fail;
if (flags & UV__F_NONBLOCK) {
uv__nonblock(fds[0], 1);
uv__nonblock(fds[1], 1);
if (uv__nonblock(fds[0], 1))
goto fail;
if (uv__nonblock(fds[1], 1))
goto fail;
}
return 0;
fail:
uv__close(fds[0]);
uv__close(fds[1]);
return UV__ERR(errno);
#endif
}
@ -200,7 +192,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
if (container->data.stream->type != UV_NAMED_PIPE)
return UV_EINVAL;
else
return uv__make_socketpair(fds, 0);
return uv__make_socketpair(fds);
case UV_INHERIT_FD:
case UV_INHERIT_STREAM:

View File

@ -24,17 +24,19 @@
#include <stdlib.h>
#include <string.h>
struct uv__process_title {
char* str;
size_t len; /* Length of the current process title. */
size_t cap; /* Maximum capacity. Computed once in uv_setup_args(). */
};
extern void uv__set_process_title(const char* title);
static uv_mutex_t process_title_mutex;
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
static struct uv__process_title process_title;
static void* args_mem;
static struct {
char* str;
size_t len;
} process_title;
static void init_process_title_mutex_once(void) {
uv_mutex_init(&process_title_mutex);
@ -42,6 +44,7 @@ static void init_process_title_mutex_once(void) {
char** uv_setup_args(int argc, char** argv) {
struct uv__process_title pt;
char** new_argv;
size_t size;
char* s;
@ -50,20 +53,14 @@ char** uv_setup_args(int argc, char** argv) {
if (argc <= 0)
return argv;
/* Calculate how much memory we need for the argv strings. */
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
pt.str = argv[0];
pt.len = strlen(argv[0]);
pt.cap = pt.len + 1;
#if defined(__MVS__)
/* argv is not adjacent. So just use argv[0] */
process_title.str = argv[0];
process_title.len = strlen(argv[0]);
#else
process_title.str = argv[0];
process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
#endif
/* Calculate how much memory we need for the argv strings. */
size = pt.cap;
for (i = 1; i < argc; i++)
size += strlen(argv[i]) + 1;
/* Add space for the argv pointers. */
size += (argc + 1) * sizeof(char*);
@ -71,32 +68,54 @@ char** uv_setup_args(int argc, char** argv) {
new_argv = uv__malloc(size);
if (new_argv == NULL)
return argv;
args_mem = new_argv;
/* Copy over the strings and set up the pointer table. */
i = 0;
s = (char*) &new_argv[argc + 1];
for (i = 0; i < argc; i++) {
size = pt.cap;
goto loop;
for (/* empty */; i < argc; i++) {
size = strlen(argv[i]) + 1;
loop:
memcpy(s, argv[i], size);
new_argv[i] = s;
s += size;
}
new_argv[i] = NULL;
/* argv is not adjacent on z/os, we use just argv[0] on that platform. */
#ifndef __MVS__
pt.cap = argv[i - 1] + size - argv[0];
#endif
args_mem = new_argv;
process_title = pt;
return new_argv;
}
int uv_set_process_title(const char* title) {
struct uv__process_title* pt;
size_t len;
pt = &process_title;
len = strlen(title);
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
if (process_title.len != 0) {
/* No need to terminate, byte after is always '\0'. */
strncpy(process_title.str, title, process_title.len);
uv__set_process_title(title);
if (len >= pt->cap) {
len = 0;
if (pt->cap > 0)
len = pt->cap - 1;
}
memcpy(pt->str, title, len);
memset(pt->str + len, '\0', pt->cap - len);
pt->len = len;
uv_mutex_unlock(&process_title_mutex);
return 0;
@ -126,7 +145,7 @@ int uv_get_process_title(char* buffer, size_t size) {
}
UV_DESTRUCTOR(static void free_args_mem(void)) {
void uv__process_title_cleanup(void) {
uv__free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}

View File

@ -77,7 +77,7 @@ static void uv__signal_global_init(void) {
}
UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
void uv__signal_cleanup(void) {
/* We can only use signal-safe functions here.
* That includes read/write and close, fortunately.
* We do all of this directly here instead of resetting
@ -98,7 +98,7 @@ UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
static void uv__signal_global_reinit(void) {
uv__signal_global_fini();
uv__signal_cleanup();
if (uv__make_pipe(uv__signal_lock_pipefd, 0))
abort();
@ -331,16 +331,7 @@ int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
void uv__signal_close(uv_signal_t* handle) {
uv__signal_stop(handle);
/* If there are any caught signals "trapped" in the signal pipe, we can't
* call the close callback yet. Otherwise, add the handle to the finish_close
* queue.
*/
if (handle->caught_signals == handle->dispatched_signals) {
uv__make_close_pending((uv_handle_t*) handle);
}
}
@ -472,17 +463,6 @@ static void uv__signal_event(uv_loop_t* loop,
if (handle->flags & UV_SIGNAL_ONE_SHOT)
uv__signal_stop(handle);
/* If uv_close was called while there were caught signals that were not
* yet dispatched, the uv__finish_close was deferred. Make close pending
* now if this has happened.
*/
if (handle->caught_signals == handle->dispatched_signals) {
if (handle->signum == 0)
uv__handle_stop(handle);
if (handle->flags & UV_HANDLE_CLOSING)
uv__make_close_pending((uv_handle_t*) handle);
}
}
bytes -= end;
@ -572,6 +552,5 @@ static void uv__signal_stop(uv_signal_t* handle) {
uv__signal_unlock_and_unblock(&saved_sigmask);
handle->signum = 0;
if (handle->caught_signals == handle->dispatched_signals)
uv__handle_stop(handle);
uv__handle_stop(handle);
}

View File

@ -379,8 +379,16 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
return UV__ERR(errno);
#ifdef TCP_KEEPIDLE
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
return UV__ERR(errno);
if (on) {
int intvl = 1; /* 1 second; same as default on Win32 */
int cnt = 10; /* 10 retries; same as hardcoded on Win32 */
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
return UV__ERR(errno);
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
return UV__ERR(errno);
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
return UV__ERR(errno);
}
#endif
/* Solaris/SmartOS, if you don't support keep-alive,

View File

@ -172,10 +172,11 @@ static size_t thread_stack_size(void) {
#if defined(__APPLE__) || defined(__linux__)
struct rlimit lim;
if (getrlimit(RLIMIT_STACK, &lim))
abort();
if (lim.rlim_cur != RLIM_INFINITY) {
/* getrlimit() can fail on some aarch64 systems due to a glibc bug where
* the system call wrapper invokes the wrong system call. Don't treat
* that as fatal, just use the default stack size instead.
*/
if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) {
/* pthread_attr_setstacksize() expects page-aligned values. */
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();

View File

@ -34,6 +34,34 @@
#define IMAXBEL 0
#endif
#if defined(__PASE__)
/* On IBM i PASE, for better compatibility with running interactive programs in
* a 5250 environment, isatty() will return true for the stdin/stdout/stderr
* streams created by QSH/QP2TERM.
*
* For more, see docs on PASE_STDIO_ISATTY in
* https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/apis/pase_environ.htm
*
* This behavior causes problems for Node as it expects that if isatty() returns
* true that TTY ioctls will be supported by that fd (which is not an
* unreasonable expectation) and when they don't it crashes with assertion
* errors.
*
* Here, we create our own version of isatty() that uses ioctl() to identify
* whether the fd is *really* a TTY or not.
*/
static int isreallyatty(int file) {
int rc;
rc = !ioctl(file, TXISATTY + 0x81, NULL);
if (!rc && errno != EBADF)
errno = ENOTTY;
return rc;
}
#define isatty(fd) isreallyatty(fd)
#endif
static int orig_termios_fd = -1;
static struct termios orig_termios;
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
@ -293,14 +321,7 @@ uv_handle_type uv_guess_handle(uv_file file) {
if (file < 0)
return UV_UNKNOWN_HANDLE;
#if defined(__PASE__)
/* On IBMi PASE isatty() always returns true for stdin, stdout and stderr.
* Use ioctl() instead to identify whether it's actually a TTY.
*/
if (!ioctl(file, TXISATTY + 0x81, NULL) || errno != ENOTTY)
#else
if (isatty(file))
#endif
return UV_TTY;
if (fstat(file, &s))

View File

@ -32,6 +32,8 @@
#endif
#include <sys/un.h>
#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
#endif
@ -40,6 +42,11 @@
# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
#endif
union uv__sockaddr {
struct sockaddr_in6 in6;
struct sockaddr_in in;
struct sockaddr addr;
};
static void uv__udp_run_completed(uv_udp_t* handle);
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
@ -49,6 +56,36 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
int domain,
unsigned int flags);
#if HAVE_MMSG
#define UV__MMSG_MAXWIDTH 20
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf);
static void uv__udp_sendmmsg(uv_udp_t* handle);
static int uv__recvmmsg_avail;
static int uv__sendmmsg_avail;
static uv_once_t once = UV_ONCE_INIT;
static void uv__udp_mmsg_init(void) {
int ret;
int s;
s = uv__socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
return;
ret = uv__sendmmsg(s, NULL, 0, 0);
if (ret == 0 || errno != ENOSYS) {
uv__sendmmsg_avail = 1;
uv__recvmmsg_avail = 1;
} else {
ret = uv__recvmmsg(s, NULL, 0, 0, NULL);
if (ret == 0 || errno != ENOSYS)
uv__recvmmsg_avail = 1;
}
uv__close(s);
}
#endif
void uv__udp_close(uv_udp_t* handle) {
uv__io_close(handle->loop, &handle->io_watcher);
@ -148,6 +185,64 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
}
}
#if HAVE_MMSG
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
struct sockaddr_in6 peers[UV__MMSG_MAXWIDTH];
struct iovec iov[UV__MMSG_MAXWIDTH];
struct uv__mmsghdr msgs[UV__MMSG_MAXWIDTH];
ssize_t nread;
uv_buf_t chunk_buf;
size_t chunks;
int flags;
size_t k;
/* prepare structures for recvmmsg */
chunks = buf->len / UV__UDP_DGRAM_MAXSIZE;
if (chunks > ARRAY_SIZE(iov))
chunks = ARRAY_SIZE(iov);
for (k = 0; k < chunks; ++k) {
iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE;
iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE;
msgs[k].msg_hdr.msg_iov = iov + k;
msgs[k].msg_hdr.msg_iovlen = 1;
msgs[k].msg_hdr.msg_name = peers + k;
msgs[k].msg_hdr.msg_namelen = sizeof(peers[0]);
msgs[k].msg_hdr.msg_control = NULL;
msgs[k].msg_hdr.msg_controllen = 0;
msgs[k].msg_hdr.msg_flags = 0;
}
do
nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
while (nread == -1 && errno == EINTR);
if (nread < 1) {
if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
handle->recv_cb(handle, 0, buf, NULL, 0);
else
handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
} else {
/* pass each chunk to the application */
for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) {
flags = UV_UDP_MMSG_CHUNK;
if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
flags |= UV_UDP_PARTIAL;
chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len);
handle->recv_cb(handle,
msgs[k].msg_len,
&chunk_buf,
msgs[k].msg_hdr.msg_name,
flags);
}
/* one last callback so the original buffer is freed */
if (handle->recv_cb != NULL)
handle->recv_cb(handle, 0, buf, NULL, 0);
}
return nread;
}
#endif
static void uv__udp_recvmsg(uv_udp_t* handle) {
struct sockaddr_storage peer;
@ -167,13 +262,25 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
do {
buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
if (buf.base == NULL || buf.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
return;
}
assert(buf.base != NULL);
#if HAVE_MMSG
if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
uv_once(&once, uv__udp_mmsg_init);
if (uv__recvmmsg_avail) {
nread = uv__udp_recvmmsg(handle, &buf);
if (nread > 0)
count -= nread;
continue;
}
}
#endif
memset(&h, 0, sizeof(h));
memset(&peer, 0, sizeof(peer));
h.msg_name = &peer;
@ -199,21 +306,120 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
handle->recv_cb(handle, nread, &buf, (const struct sockaddr*) &peer, flags);
}
count--;
}
/* recv_cb callback may decide to pause or close the handle */
while (nread != -1
&& count-- > 0
&& count > 0
&& handle->io_watcher.fd != -1
&& handle->recv_cb != NULL);
}
#if HAVE_MMSG
static void uv__udp_sendmmsg(uv_udp_t* handle) {
uv_udp_send_t* req;
struct uv__mmsghdr h[UV__MMSG_MAXWIDTH];
struct uv__mmsghdr *p;
QUEUE* q;
ssize_t npkts;
size_t pkts;
size_t i;
if (QUEUE_EMPTY(&handle->write_queue))
return;
write_queue_drain:
for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue);
pkts < UV__MMSG_MAXWIDTH && q != &handle->write_queue;
++pkts, q = QUEUE_HEAD(q)) {
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
assert(req != NULL);
p = &h[pkts];
memset(p, 0, sizeof(*p));
if (req->addr.ss_family == AF_UNSPEC) {
p->msg_hdr.msg_name = NULL;
p->msg_hdr.msg_namelen = 0;
} else {
p->msg_hdr.msg_name = &req->addr;
if (req->addr.ss_family == AF_INET6)
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
else if (req->addr.ss_family == AF_INET)
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
else if (req->addr.ss_family == AF_UNIX)
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un);
else {
assert(0 && "unsupported address family");
abort();
}
}
h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs;
h[pkts].msg_hdr.msg_iovlen = req->nbufs;
}
do
npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts, 0);
while (npkts == -1 && errno == EINTR);
if (npkts < 1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
return;
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
i < pkts && q != &handle->write_queue;
++i, q = QUEUE_HEAD(q)) {
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
assert(req != NULL);
req->status = UV__ERR(errno);
QUEUE_REMOVE(&req->queue);
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
}
uv__io_feed(handle->loop, &handle->io_watcher);
return;
}
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
i < pkts && q != &handle->write_queue;
++i, q = QUEUE_HEAD(&handle->write_queue)) {
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
assert(req != NULL);
req->status = req->bufs[0].len;
/* Sending a datagram is an atomic operation: either all data
* is written or nothing is (and EMSGSIZE is raised). That is
* why we don't handle partial writes. Just pop the request
* off the write queue and onto the completed queue, done.
*/
QUEUE_REMOVE(&req->queue);
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
}
/* couldn't batch everything, continue sending (jump to avoid stack growth) */
if (!QUEUE_EMPTY(&handle->write_queue))
goto write_queue_drain;
uv__io_feed(handle->loop, &handle->io_watcher);
return;
}
#endif
static void uv__udp_sendmsg(uv_udp_t* handle) {
uv_udp_send_t* req;
QUEUE* q;
struct msghdr h;
QUEUE* q;
ssize_t size;
#if HAVE_MMSG
uv_once(&once, uv__udp_mmsg_init);
if (uv__sendmmsg_avail) {
uv__udp_sendmmsg(handle);
return;
}
#endif
while (!QUEUE_EMPTY(&handle->write_queue)) {
q = QUEUE_HEAD(&handle->write_queue);
assert(q != NULL);
@ -263,7 +469,6 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
}
}
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
* refinements for programs that use multicast.
*
@ -367,11 +572,7 @@ int uv__udp_bind(uv_udp_t* handle,
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
int domain,
unsigned int flags) {
union {
struct sockaddr_in6 in6;
struct sockaddr_in in;
struct sockaddr addr;
} taddr;
union uv__sockaddr taddr;
socklen_t addrlen;
if (handle->io_watcher.fd != -1)
@ -653,7 +854,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
}
#if !defined(__OpenBSD__) && !defined(__NetBSD__)
#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
static int uv__udp_set_source_membership4(uv_udp_t* handle,
const struct sockaddr_in* multicast_addr,
const char* interface_addr,
@ -724,8 +925,10 @@ static int uv__udp_set_source_membership6(uv_udp_t* handle,
mreq.gsr_interface = 0;
}
memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group));
memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source));
STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
if (membership == UV_JOIN_GROUP)
optname = MCAST_JOIN_SOURCE_GROUP;
@ -747,26 +950,17 @@ static int uv__udp_set_source_membership6(uv_udp_t* handle,
#endif
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
int domain;
int err;
int uv__udp_init_ex(uv_loop_t* loop,
uv_udp_t* handle,
unsigned flags,
int domain) {
int fd;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return UV_EINVAL;
if (flags & ~0xFF)
return UV_EINVAL;
fd = -1;
if (domain != AF_UNSPEC) {
err = uv__socket(domain, SOCK_DGRAM, 0);
if (err < 0)
return err;
fd = err;
} else {
fd = -1;
fd = uv__socket(domain, SOCK_DGRAM, 0);
if (fd < 0)
return fd;
}
uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
@ -782,11 +976,6 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
}
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
int err;
@ -842,42 +1031,33 @@ int uv_udp_set_source_membership(uv_udp_t* handle,
const char* interface_addr,
const char* source_addr,
uv_membership membership) {
#if !defined(__OpenBSD__) && !defined(__NetBSD__)
#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
int err;
struct sockaddr_storage mcast_addr;
struct sockaddr_in* mcast_addr4;
struct sockaddr_in6* mcast_addr6;
struct sockaddr_storage src_addr;
struct sockaddr_in* src_addr4;
struct sockaddr_in6* src_addr6;
union uv__sockaddr mcast_addr;
union uv__sockaddr src_addr;
mcast_addr4 = (struct sockaddr_in*)&mcast_addr;
mcast_addr6 = (struct sockaddr_in6*)&mcast_addr;
src_addr4 = (struct sockaddr_in*)&src_addr;
src_addr6 = (struct sockaddr_in6*)&src_addr;
err = uv_ip4_addr(multicast_addr, 0, mcast_addr4);
err = uv_ip4_addr(multicast_addr, 0, &mcast_addr.in);
if (err) {
err = uv_ip6_addr(multicast_addr, 0, mcast_addr6);
err = uv_ip6_addr(multicast_addr, 0, &mcast_addr.in6);
if (err)
return err;
err = uv_ip6_addr(source_addr, 0, src_addr6);
err = uv_ip6_addr(source_addr, 0, &src_addr.in6);
if (err)
return err;
return uv__udp_set_source_membership6(handle,
mcast_addr6,
&mcast_addr.in6,
interface_addr,
src_addr6,
&src_addr.in6,
membership);
}
err = uv_ip4_addr(source_addr, 0, src_addr4);
err = uv_ip4_addr(source_addr, 0, &src_addr.in);
if (err)
return err;
return uv__udp_set_source_membership4(handle,
mcast_addr4,
&mcast_addr.in,
interface_addr,
src_addr4,
&src_addr.in,
membership);
#else
return UV_ENOSYS;
@ -889,7 +1069,7 @@ static int uv__setsockopt(uv_udp_t* handle,
int option4,
int option6,
const void* val,
size_t size) {
socklen_t size) {
int r;
if (handle->flags & UV_HANDLE_IPV6)
@ -1012,7 +1192,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
* and use the general uv__setsockopt_maybe_char call otherwise.
*/
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
defined(__MVS__)
defined(__MVS__)
if (handle->flags & UV_HANDLE_IPV6)
return uv__setsockopt(handle,
IP_MULTICAST_LOOP,

View File

@ -100,6 +100,17 @@ void* uv__realloc(void* ptr, size_t size) {
return NULL;
}
void* uv__reallocf(void* ptr, size_t size) {
void* newptr;
newptr = uv__realloc(ptr, size);
if (newptr == NULL)
if (size > 0)
uv__free(ptr);
return newptr;
}
int uv_replace_allocator(uv_malloc_func malloc_func,
uv_realloc_func realloc_func,
uv_calloc_func calloc_func,
@ -282,6 +293,36 @@ int uv_tcp_bind(uv_tcp_t* handle,
}
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned flags) {
unsigned extra_flags;
int domain;
int rc;
/* Use the lower 8 bits for the domain. */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return UV_EINVAL;
/* Use the higher bits for extra flags. */
extra_flags = flags & ~0xFF;
if (extra_flags & ~UV_UDP_RECVMMSG)
return UV_EINVAL;
rc = uv__udp_init_ex(loop, handle, flags, domain);
if (rc == 0)
if (extra_flags & UV_UDP_RECVMMSG)
handle->flags |= UV_HANDLE_UDP_RECVMMSG;
return rc;
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
}
int uv_udp_bind(uv_udp_t* handle,
const struct sockaddr* addr,
unsigned int flags) {
@ -810,3 +851,19 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
uv__free(cpu_infos);
}
#ifdef __GNUC__ /* Also covers __clang__ and __INTEL_COMPILER. */
__attribute__((destructor))
#endif
void uv_library_shutdown(void) {
static int was_shutdown;
if (was_shutdown)
return;
uv__process_title_cleanup();
uv__signal_cleanup();
uv__threadpool_cleanup();
was_shutdown = 1;
}

View File

@ -104,6 +104,7 @@ enum {
/* Only used by uv_udp_t handles. */
UV_HANDLE_UDP_PROCESSING = 0x01000000,
UV_HANDLE_UDP_CONNECTED = 0x02000000,
UV_HANDLE_UDP_RECVMMSG = 0x04000000,
/* Only used by uv_pipe_t handles. */
UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000,
@ -138,6 +139,11 @@ int uv__tcp_connect(uv_connect_t* req,
unsigned int addrlen,
uv_connect_cb cb);
int uv__udp_init_ex(uv_loop_t* loop,
uv_udp_t* handle,
unsigned flags,
int domain);
int uv__udp_bind(uv_udp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
@ -200,6 +206,10 @@ int uv__next_timeout(const uv_loop_t* loop);
void uv__run_timers(uv_loop_t* loop);
void uv__timer_close(uv_timer_t* handle);
void uv__process_title_cleanup(void);
void uv__signal_cleanup(void);
void uv__threadpool_cleanup(void);
#define uv__has_active_reqs(loop) \
((loop)->active_reqs.count > 0)
@ -322,5 +332,6 @@ char *uv__strndup(const char* s, size_t n);
void* uv__malloc(size_t size);
void uv__free(void* ptr);
void* uv__realloc(void* ptr, size_t size);
void* uv__reallocf(void* ptr, size_t size);
#endif /* UV_COMMON_H_ */

View File

@ -449,12 +449,12 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
timeout_time = loop->time + timeout;
for (repeat = 0; ; repeat++) {
success = GetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
&count,
timeout,
FALSE);
success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
&count,
timeout,
FALSE);
if (success) {
for (i = 0; i < count; i++) {

View File

@ -72,6 +72,7 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_NOACCESS: return UV_EACCES;
case WSAEACCES: return UV_EACCES;
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;

View File

@ -83,6 +83,7 @@ static void uv_relative_path(const WCHAR* filename,
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
WCHAR** file) {
size_t len, i;
DWORD dir_len;
if (filename == NULL) {
if (dir != NULL)
@ -97,12 +98,16 @@ static int uv_split_path(const WCHAR* filename, WCHAR** dir,
if (i == 0) {
if (dir) {
*dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
dir_len = GetCurrentDirectoryW(0, NULL);
if (dir_len == 0) {
return -1;
}
*dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
if (!GetCurrentDirectoryW(dir_len, *dir)) {
uv__free(*dir);
*dir = NULL;
return -1;
@ -155,9 +160,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
int name_size, is_path_dir, size;
DWORD attr, last_error;
WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
WCHAR short_path_buffer[MAX_PATH];
DWORD short_path_buffer_len;
WCHAR *short_path_buffer;
WCHAR* short_path, *long_path;
short_path = NULL;
if (uv__is_active(handle))
return UV_EINVAL;
@ -230,13 +237,23 @@ int uv_fs_event_start(uv_fs_event_t* handle,
*/
/* Convert to short path. */
short_path_buffer = NULL;
short_path_buffer_len = GetShortPathNameW(pathw, NULL, 0);
if (short_path_buffer_len == 0) {
goto short_path_done;
}
short_path_buffer = uv__malloc(short_path_buffer_len * sizeof(WCHAR));
if (short_path_buffer == NULL) {
goto short_path_done;
}
if (GetShortPathNameW(pathw,
short_path_buffer,
ARRAY_SIZE(short_path_buffer))) {
short_path = short_path_buffer;
} else {
short_path = NULL;
short_path_buffer_len) == 0) {
uv__free(short_path_buffer);
short_path_buffer = NULL;
}
short_path_done:
short_path = short_path_buffer;
if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
last_error = GetLastError();
@ -346,6 +363,8 @@ error:
if (uv__is_active(handle))
uv__handle_stop(handle);
uv__free(short_path);
return uv_translate_sys_error(last_error);
}

View File

@ -257,6 +257,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
req->loop = loop;
req->flags = 0;
req->fs_type = fs_type;
req->sys_errno_ = 0;
req->result = 0;
req->ptr = NULL;
req->path = NULL;
@ -321,6 +322,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
WCHAR* w_target;
DWORD w_target_len;
DWORD bytes;
size_t i;
size_t len;
if (!DeviceIoControl(handle,
FSCTL_GET_REPARSE_POINT,
@ -405,6 +408,38 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
w_target += 4;
w_target_len -= 4;
} else if (reparse_data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) {
/* String #3 in the list has the target filename. */
if (reparse_data->AppExecLinkReparseBuffer.StringCount < 3) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
w_target = reparse_data->AppExecLinkReparseBuffer.StringList;
/* The StringList buffer contains a list of strings separated by "\0", */
/* with "\0\0" terminating the list. Move to the 3rd string in the list: */
for (i = 0; i < 2; ++i) {
len = wcslen(w_target);
if (len == 0) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
w_target += len + 1;
}
w_target_len = wcslen(w_target);
if (w_target_len == 0) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
/* Make sure it is an absolute path. */
if (!(w_target_len >= 3 &&
((w_target[0] >= L'a' && w_target[0] <= L'z') ||
(w_target[0] >= L'A' && w_target[0] <= L'Z')) &&
w_target[1] == L':' &&
w_target[2] == L'\\')) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
} else {
/* Reparse tag does not indicate a symlink. */
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
@ -2225,34 +2260,68 @@ INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
return 0;
}
static void fs__utime(uv_fs_t* req) {
INLINE static DWORD fs__utime_impl_from_path(WCHAR* path,
double atime,
double mtime,
int do_lutime) {
HANDLE handle;
DWORD flags;
DWORD ret;
handle = CreateFileW(req->file.pathw,
flags = FILE_FLAG_BACKUP_SEMANTICS;
if (do_lutime) {
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
}
handle = CreateFileW(path,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
flags,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
CloseHandle(handle);
return;
ret = GetLastError();
} else if (fs__utime_handle(handle, atime, mtime) != 0) {
ret = GetLastError();
} else {
ret = 0;
}
CloseHandle(handle);
return ret;
}
INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) {
DWORD error;
error = fs__utime_impl_from_path(req->file.pathw,
req->fs.time.atime,
req->fs.time.mtime,
do_lutime);
if (error != 0) {
if (do_lutime &&
(error == ERROR_SYMLINK_NOT_SUPPORTED ||
error == ERROR_NOT_A_REPARSE_POINT)) {
/* Opened file is a reparse point but not a symlink. Try again. */
fs__utime_impl(req, 0);
} else {
/* utime failed. */
SET_REQ_WIN32_ERROR(req, error);
}
return;
}
req->result = 0;
}
static void fs__utime(uv_fs_t* req) {
fs__utime_impl(req, /* do_lutime */ 0);
}
static void fs__futime(uv_fs_t* req) {
int fd = req->file.fd;
@ -2274,6 +2343,10 @@ static void fs__futime(uv_fs_t* req) {
req->result = 0;
}
static void fs__lutime(uv_fs_t* req) {
fs__utime_impl(req, /* do_lutime */ 1);
}
static void fs__link(uv_fs_t* req) {
DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
@ -2621,14 +2694,62 @@ static void fs__statfs(uv_fs_t* req) {
DWORD bytes_per_sector;
DWORD free_clusters;
DWORD total_clusters;
WCHAR* pathw;
if (0 == GetDiskFreeSpaceW(req->file.pathw,
pathw = req->file.pathw;
retry_get_disk_free_space:
if (0 == GetDiskFreeSpaceW(pathw,
&sectors_per_cluster,
&bytes_per_sector,
&free_clusters,
&total_clusters)) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
DWORD err;
WCHAR* fpart;
size_t len;
DWORD ret;
BOOL is_second;
err = GetLastError();
is_second = pathw != req->file.pathw;
if (err != ERROR_DIRECTORY || is_second) {
if (is_second)
uv__free(pathw);
SET_REQ_WIN32_ERROR(req, err);
return;
}
len = MAX_PATH + 1;
pathw = uv__malloc(len * sizeof(*pathw));
if (pathw == NULL) {
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
return;
}
retry_get_full_path_name:
ret = GetFullPathNameW(req->file.pathw,
len,
pathw,
&fpart);
if (ret == 0) {
uv__free(pathw);
SET_REQ_WIN32_ERROR(req, err);
return;
} else if (ret > len) {
len = ret;
pathw = uv__reallocf(pathw, len * sizeof(*pathw));
if (pathw == NULL) {
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
return;
}
goto retry_get_full_path_name;
}
if (fpart != 0)
*fpart = L'\0';
goto retry_get_disk_free_space;
}
if (pathw != req->file.pathw) {
uv__free(pathw);
}
stat_fs = uv__malloc(sizeof(*stat_fs));
@ -2670,6 +2791,7 @@ static void uv__fs_work(struct uv__work* w) {
XX(FTRUNCATE, ftruncate)
XX(UTIME, utime)
XX(FUTIME, futime)
XX(LUTIME, lutime)
XX(ACCESS, access)
XX(CHMOD, chmod)
XX(FCHMOD, fchmod)
@ -2753,7 +2875,8 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
INIT(UV_FS_OPEN);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.info.file_flags = flags;
@ -2778,8 +2901,10 @@ int uv_fs_read(uv_loop_t* loop,
uv_fs_cb cb) {
INIT(UV_FS_READ);
if (bufs == NULL || nbufs == 0)
if (bufs == NULL || nbufs == 0) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return UV_EINVAL;
}
req->file.fd = fd;
@ -2788,8 +2913,10 @@ int uv_fs_read(uv_loop_t* loop,
if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
if (req->fs.info.bufs == NULL)
if (req->fs.info.bufs == NULL) {
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
return UV_ENOMEM;
}
memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
@ -2807,8 +2934,10 @@ int uv_fs_write(uv_loop_t* loop,
uv_fs_cb cb) {
INIT(UV_FS_WRITE);
if (bufs == NULL || nbufs == 0)
if (bufs == NULL || nbufs == 0) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return UV_EINVAL;
}
req->file.fd = fd;
@ -2817,8 +2946,10 @@ int uv_fs_write(uv_loop_t* loop,
if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
if (req->fs.info.bufs == NULL)
if (req->fs.info.bufs == NULL) {
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
return UV_ENOMEM;
}
memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
@ -2834,7 +2965,8 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
INIT(UV_FS_UNLINK);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -2848,7 +2980,8 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
INIT(UV_FS_MKDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.info.mode = mode;
@ -2864,8 +2997,10 @@ int uv_fs_mkdtemp(uv_loop_t* loop,
INIT(UV_FS_MKDTEMP);
err = fs__capture_path(req, tpl, NULL, TRUE);
if (err)
return uv_translate_sys_error(err);
if (err) {
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
}
@ -2879,8 +3014,10 @@ int uv_fs_mkstemp(uv_loop_t* loop,
INIT(UV_FS_MKSTEMP);
err = fs__capture_path(req, tpl, NULL, TRUE);
if (err)
return uv_translate_sys_error(err);
if (err) {
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
}
@ -2892,7 +3029,8 @@ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
INIT(UV_FS_RMDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -2906,7 +3044,8 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
INIT(UV_FS_SCANDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.info.file_flags = flags;
@ -2921,8 +3060,10 @@ int uv_fs_opendir(uv_loop_t* loop,
INIT(UV_FS_OPENDIR);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err)
return uv_translate_sys_error(err);
if (err) {
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
}
@ -2935,6 +3076,7 @@ int uv_fs_readdir(uv_loop_t* loop,
if (dir == NULL ||
dir->dirents == NULL ||
dir->dir_handle == INVALID_HANDLE_VALUE) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return UV_EINVAL;
}
@ -2947,8 +3089,10 @@ int uv_fs_closedir(uv_loop_t* loop,
uv_dir_t* dir,
uv_fs_cb cb) {
INIT(UV_FS_CLOSEDIR);
if (dir == NULL)
if (dir == NULL) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return UV_EINVAL;
}
req->ptr = dir;
POST;
}
@ -2960,7 +3104,8 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
INIT(UV_FS_LINK);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -2974,7 +3119,8 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
INIT(UV_FS_SYMLINK);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.info.file_flags = flags;
@ -2989,7 +3135,8 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
INIT(UV_FS_READLINK);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -3003,12 +3150,14 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
INIT(UV_FS_REALPATH);
if (!path) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return UV_EINVAL;
}
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -3022,7 +3171,8 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
INIT(UV_FS_CHOWN);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -3043,8 +3193,10 @@ int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
INIT(UV_FS_LCHOWN);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
}
@ -3055,7 +3207,8 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
INIT(UV_FS_STAT);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -3068,7 +3221,8 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
INIT(UV_FS_LSTAT);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -3089,7 +3243,8 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
INIT(UV_FS_RENAME);
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
@ -3132,13 +3287,15 @@ int uv_fs_copyfile(uv_loop_t* loop,
if (flags & ~(UV_FS_COPYFILE_EXCL |
UV_FS_COPYFILE_FICLONE |
UV_FS_COPYFILE_FICLONE_FORCE)) {
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
return UV_EINVAL;
}
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err)
return uv_translate_sys_error(err);
if (err) {
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.info.file_flags = flags;
POST;
@ -3165,8 +3322,10 @@ int uv_fs_access(uv_loop_t* loop,
INIT(UV_FS_ACCESS);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err)
return uv_translate_sys_error(err);
if (err) {
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.info.mode = flags;
POST;
@ -3180,7 +3339,8 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
INIT(UV_FS_CHMOD);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.info.mode = mode;
@ -3204,7 +3364,8 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
INIT(UV_FS_UTIME);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.time.atime = atime;
@ -3222,6 +3383,22 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
POST;
}
int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
double mtime, uv_fs_cb cb) {
int err;
INIT(UV_FS_LUTIME);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
req->fs.time.atime = atime;
req->fs.time.mtime = mtime;
POST;
}
int uv_fs_statfs(uv_loop_t* loop,
uv_fs_t* req,
@ -3231,8 +3408,14 @@ int uv_fs_statfs(uv_loop_t* loop,
INIT(UV_FS_STATFS);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err)
return uv_translate_sys_error(err);
if (err) {
SET_REQ_WIN32_ERROR(req, err);
return req->result;
}
POST;
}
int uv_fs_get_system_error(const uv_fs_t* req) {
return req->sys_errno_;
}

View File

@ -264,8 +264,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
DWORD current_mode = 0;
DWORD err = 0;
if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
handle->handle != INVALID_HANDLE_VALUE)
if (handle->flags & UV_HANDLE_PIPESERVER)
return UV_EINVAL;
if (handle->handle != INVALID_HANDLE_VALUE)
return UV_EBUSY;
if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
@ -312,7 +313,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
/* Overlapped pipe. Try to associate with IOCP. */
if (CreateIoCompletionPort(pipeHandle,
loop->iocp,
(ULONG_PTR)handle,
(ULONG_PTR) handle,
0) == NULL) {
handle->flags |= UV_HANDLE_EMULATE_IOCP;
}
@ -326,6 +327,38 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
}
static int pipe_alloc_accept(uv_loop_t* loop, uv_pipe_t* handle,
uv_pipe_accept_t* req, BOOL firstInstance) {
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
req->pipeHandle =
CreateNamedPipeW(handle->name,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC |
(firstInstance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
return 0;
}
/* Associate it with IOCP so we can get events. */
if (CreateIoCompletionPort(req->pipeHandle,
loop->iocp,
(ULONG_PTR) handle,
0) == NULL) {
uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
}
/* Stash a handle in the server object for use from places such as
* getsockname and chmod. As we transfer ownership of these to client
* objects, we'll allocate new ones here. */
handle->handle = req->pipeHandle;
return 1;
}
static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
uv_loop_t* loop;
uv_pipe_t* handle;
@ -458,7 +491,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
UnregisterWait(handle->read_req.wait_handle);
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
}
if (handle->read_req.event_handle) {
if (handle->read_req.event_handle != NULL) {
CloseHandle(handle->read_req.event_handle);
handle->read_req.event_handle = NULL;
}
@ -540,13 +573,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
* Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
* If this fails then there's already a pipe server for the given pipe name.
*/
handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
if (!pipe_alloc_accept(loop,
handle,
&handle->pipe.serv.accept_reqs[0],
TRUE)) {
err = GetLastError();
if (err == ERROR_ACCESS_DENIED) {
err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
@ -556,15 +586,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
goto error;
}
if (uv_set_pipe_handle(loop,
handle,
handle->pipe.serv.accept_reqs[0].pipeHandle,
-1,
0)) {
err = GetLastError();
goto error;
}
handle->pipe.serv.pending_accepts = NULL;
handle->flags |= UV_HANDLE_PIPESERVER;
handle->flags |= UV_HANDLE_BOUND;
@ -577,11 +598,6 @@ error:
handle->name = NULL;
}
if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
}
return uv_translate_sys_error(err);
}
@ -827,29 +843,11 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
uv_pipe_accept_t* req, BOOL firstInstance) {
assert(handle->flags & UV_HANDLE_LISTENING);
if (!firstInstance) {
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
req->pipeHandle = CreateNamedPipeW(handle->name,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
return;
}
if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
CloseHandle(req->pipeHandle);
req->pipeHandle = INVALID_HANDLE_VALUE;
SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
return;
}
if (!firstInstance && !pipe_alloc_accept(loop, handle, req, FALSE)) {
SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
return;
}
assert(req->pipeHandle != INVALID_HANDLE_VALUE);
@ -904,7 +902,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
uv__free(item);
} else {
pipe_client = (uv_pipe_t*)client;
pipe_client = (uv_pipe_t*) client;
/* Find a connection instance that has been connected, but not yet
* accepted. */
@ -925,6 +923,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
req->next_pending = NULL;
req->pipeHandle = INVALID_HANDLE_VALUE;
server->handle = INVALID_HANDLE_VALUE;
if (!(server->flags & UV_HANDLE_CLOSING)) {
uv_pipe_queue_accept(loop, server, req, FALSE);
}
@ -955,6 +954,10 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
return ERROR_NOT_SUPPORTED;
}
if (handle->ipc) {
return WSAEINVAL;
}
handle->flags |= UV_HANDLE_LISTENING;
INCREASE_ACTIVE_COUNT(loop, handle);
handle->stream.serv.connection_cb = cb;
@ -1131,6 +1134,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
} else {
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
assert(req->event_handle != NULL);
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
}
@ -1148,15 +1152,9 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
}
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
if (!req->event_handle) {
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
if (!req->event_handle) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
}
if (req->wait_handle == INVALID_HANDLE_VALUE) {
if (!RegisterWaitForSingleObject(&req->wait_handle,
req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
req->event_handle, post_completion_read_wait, (void*) req,
INFINITE, WT_EXECUTEINWAITTHREAD)) {
SET_REQ_ERROR(req, GetLastError());
goto error;
@ -1190,8 +1188,16 @@ int uv_pipe_read_start(uv_pipe_t* handle,
/* If reading was stopped and then started again, there could still be a read
* request pending. */
if (!(handle->flags & UV_HANDLE_READ_PENDING))
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
handle->read_req.event_handle == NULL) {
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
if (handle->read_req.event_handle == NULL) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
}
uv_pipe_queue_read(loop, handle);
}
return 0;
}
@ -1326,7 +1332,16 @@ static int uv__pipe_write_data(uv_loop_t* loop,
req->coalesced = 0;
req->event_handle = NULL;
req->wait_handle = INVALID_HANDLE_VALUE;
/* Prepare the overlapped structure. */
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
if (handle->flags & (UV_HANDLE_EMULATE_IOCP | UV_HANDLE_BLOCKING_WRITES)) {
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
if (req->event_handle == NULL) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
}
req->write_buffer = uv_null_buf_;
if (nbufs == 0) {
@ -1375,11 +1390,6 @@ static int uv__pipe_write_data(uv_loop_t* loop,
handle->write_queue_size += req->u.io.queued_bytes;
} else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
/* Using overlapped IO, but wait for completion before returning */
req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
if (!req->u.io.overlapped.hEvent) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
result = WriteFile(handle->handle,
write_buf.base,
write_buf.len,
@ -1388,7 +1398,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
if (!result && GetLastError() != ERROR_IO_PENDING) {
err = GetLastError();
CloseHandle(req->u.io.overlapped.hEvent);
CloseHandle(req->event_handle);
req->event_handle = NULL;
return err;
}
@ -1399,14 +1410,16 @@ static int uv__pipe_write_data(uv_loop_t* loop,
/* Request queued by the kernel. */
req->u.io.queued_bytes = write_buf.len;
handle->write_queue_size += req->u.io.queued_bytes;
if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
if (WaitForSingleObject(req->event_handle, INFINITE) !=
WAIT_OBJECT_0) {
err = GetLastError();
CloseHandle(req->u.io.overlapped.hEvent);
CloseHandle(req->event_handle);
req->event_handle = NULL;
return err;
}
}
CloseHandle(req->u.io.overlapped.hEvent);
CloseHandle(req->event_handle);
req->event_handle = NULL;
REGISTER_HANDLE_REQ(loop, handle, req);
handle->reqs_pending++;
@ -1433,12 +1446,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
}
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
if (!req->event_handle) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
if (!RegisterWaitForSingleObject(&req->wait_handle,
req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
req->event_handle, post_completion_write_wait, (void*) req,
INFINITE, WT_EXECUTEINWAITTHREAD)) {
return GetLastError();
}

View File

@ -134,32 +134,6 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
}
static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
AFD_POLL_INFO afd_poll_info;
int result;
afd_poll_info.Exclusive = TRUE;
afd_poll_info.NumberOfHandles = 1;
afd_poll_info.Timeout.QuadPart = INT64_MAX;
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info.Handles[0].Status = 0;
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
result = uv_msafd_poll(handle->socket,
&afd_poll_info,
uv__get_afd_poll_info_dummy(),
uv__get_overlapped_dummy());
if (result == SOCKET_ERROR) {
DWORD error = WSAGetLastError();
if (error != WSA_IO_PENDING)
return error;
}
return 0;
}
static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
uv_req_t* req) {
unsigned char mask_events;
@ -226,44 +200,6 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
}
static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
assert(handle->type == UV_POLL);
assert(!(handle->flags & UV_HANDLE_CLOSING));
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
handle->events = events;
if (handle->events != 0) {
uv__handle_start(handle);
} else {
uv__handle_stop(handle);
}
if ((handle->events & ~(handle->submitted_events_1 |
handle->submitted_events_2)) != 0) {
uv__fast_poll_submit_poll_req(handle->loop, handle);
}
return 0;
}
static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
handle->events = 0;
uv__handle_closing(handle);
if (handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
return 0;
} else {
/* Cancel outstanding poll requests by executing another, unique poll
* request that forces the outstanding ones to return. */
return uv__fast_poll_cancel_poll_req(loop, handle);
}
}
static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
WSAPROTOCOL_INFOW* protocol_info) {
SOCKET sock = 0;
@ -469,41 +405,6 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
}
static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
assert(handle->type == UV_POLL);
assert(!(handle->flags & UV_HANDLE_CLOSING));
assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
handle->events = events;
if (handle->events != 0) {
uv__handle_start(handle);
} else {
uv__handle_stop(handle);
}
if ((handle->events &
~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
uv__slow_poll_submit_poll_req(handle->loop, handle);
}
return 0;
}
static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
handle->events = 0;
uv__handle_closing(handle);
if (handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
return 0;
}
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
}
@ -582,35 +483,43 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
}
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
int err;
static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
int submitted_events;
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
err = uv__fast_poll_set(handle->loop, handle, events);
} else {
err = uv__slow_poll_set(handle->loop, handle, events);
}
if (err) {
return uv_translate_sys_error(err);
}
assert(handle->type == UV_POLL);
assert(!(handle->flags & UV_HANDLE_CLOSING));
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
handle->events = events;
handle->poll_cb = cb;
if (handle->events == 0) {
uv__handle_stop(handle);
return 0;
}
uv__handle_start(handle);
submitted_events = handle->submitted_events_1 | handle->submitted_events_2;
if (handle->events & ~submitted_events) {
if (handle->flags & UV_HANDLE_POLL_SLOW) {
uv__slow_poll_submit_poll_req(handle->loop, handle);
} else {
uv__fast_poll_submit_poll_req(handle->loop, handle);
}
}
return 0;
}
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
return uv__poll_set(handle, events, cb);
}
int uv_poll_stop(uv_poll_t* handle) {
int err;
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
err = uv__fast_poll_set(handle->loop, handle, 0);
} else {
err = uv__slow_poll_set(handle->loop, handle, 0);
}
return uv_translate_sys_error(err);
return uv__poll_set(handle, 0, handle->poll_cb);
}
@ -624,11 +533,43 @@ void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
return uv__fast_poll_close(loop, handle);
} else {
return uv__slow_poll_close(loop, handle);
AFD_POLL_INFO afd_poll_info;
DWORD error;
int result;
handle->events = 0;
uv__handle_closing(handle);
if (handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
return 0;
}
if (handle->flags & UV_HANDLE_POLL_SLOW)
return 0;
/* Cancel outstanding poll requests by executing another, unique poll
* request that forces the outstanding ones to return. */
afd_poll_info.Exclusive = TRUE;
afd_poll_info.NumberOfHandles = 1;
afd_poll_info.Timeout.QuadPart = INT64_MAX;
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info.Handles[0].Status = 0;
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
result = uv_msafd_poll(handle->socket,
&afd_poll_info,
uv__get_afd_poll_info_dummy(),
uv__get_overlapped_dummy());
if (result == SOCKET_ERROR) {
error = WSAGetLastError();
if (error != WSA_IO_PENDING)
return uv_translate_sys_error(error);
}
return 0;
}

View File

@ -58,7 +58,6 @@ static const env_var_t required_vars[] = { /* keep me sorted */
E_V("USERPROFILE"),
E_V("WINDIR"),
};
static size_t n_required_vars = ARRAY_SIZE(required_vars);
static HANDLE uv_global_job_handle_;
@ -692,7 +691,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
WCHAR* dst_copy;
WCHAR** ptr_copy;
WCHAR** env_copy;
DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*));
DWORD required_vars_value_len[ARRAY_SIZE(required_vars)];
/* first pass: determine size in UTF-16 */
for (env = env_block; *env; env++) {
@ -745,7 +744,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
/* third pass: check for required variables */
for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
for (ptr_copy = env_copy, i = 0; i < ARRAY_SIZE(required_vars); ) {
int cmp;
if (!*ptr_copy) {
cmp = -1;
@ -778,10 +777,10 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
}
for (ptr = dst, ptr_copy = env_copy, i = 0;
*ptr_copy || i < n_required_vars;
*ptr_copy || i < ARRAY_SIZE(required_vars);
ptr += len) {
int cmp;
if (i >= n_required_vars) {
if (i >= ARRAY_SIZE(required_vars)) {
cmp = 1;
} else if (!*ptr_copy) {
cmp = -1;

View File

@ -46,6 +46,11 @@ void uv_signals_init(void) {
}
void uv__signal_cleanup(void) {
/* TODO(bnoordhuis) Undo effects of uv_signal_init()? */
}
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
/* Compare signums first so all watchers with the same signnum end up
* adjacent. */

View File

@ -251,7 +251,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
UnregisterWait(req->wait_handle);
req->wait_handle = INVALID_HANDLE_VALUE;
}
if (req->event_handle) {
if (req->event_handle != NULL) {
CloseHandle(req->event_handle);
req->event_handle = NULL;
}
@ -268,7 +268,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
UnregisterWait(handle->read_req.wait_handle);
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
}
if (handle->read_req.event_handle) {
if (handle->read_req.event_handle != NULL) {
CloseHandle(handle->read_req.event_handle);
handle->read_req.event_handle = NULL;
}
@ -428,6 +428,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
/* Prepare the overlapped structure. */
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
assert(req->event_handle != NULL);
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
}
@ -466,7 +467,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
closesocket(accept_socket);
/* Destroy the event handle */
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
CloseHandle(req->u.io.overlapped.hEvent);
CloseHandle(req->event_handle);
req->event_handle = NULL;
}
}
@ -509,7 +510,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
/* Prepare the overlapped structure. */
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
assert(req->event_handle);
assert(req->event_handle != NULL);
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
}
@ -612,8 +613,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
: uv_simultaneous_server_accepts;
if(!handle->tcp.serv.accept_reqs) {
handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
if (handle->tcp.serv.accept_reqs == NULL) {
handle->tcp.serv.accept_reqs =
uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
if (!handle->tcp.serv.accept_reqs) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
@ -628,7 +629,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
req->wait_handle = INVALID_HANDLE_VALUE;
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
if (!req->event_handle) {
if (req->event_handle == NULL) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
} else {
@ -737,9 +738,9 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
* request pending. */
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
!handle->read_req.event_handle) {
handle->read_req.event_handle == NULL) {
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
if (!handle->read_req.event_handle) {
if (handle->read_req.event_handle == NULL) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
}
@ -862,7 +863,7 @@ int uv_tcp_write(uv_loop_t* loop,
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
if (!req->event_handle) {
if (req->event_handle == NULL) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
@ -1080,7 +1081,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
UnregisterWait(req->wait_handle);
req->wait_handle = INVALID_HANDLE_VALUE;
}
if (req->event_handle) {
if (req->event_handle != NULL) {
CloseHandle(req->event_handle);
req->event_handle = NULL;
}

View File

@ -46,14 +46,16 @@
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
#define ANSI_NORMAL 0x00
#define ANSI_ESCAPE_SEEN 0x02
#define ANSI_CSI 0x04
#define ANSI_ST_CONTROL 0x08
#define ANSI_IGNORE 0x10
#define ANSI_IN_ARG 0x20
#define ANSI_IN_STRING 0x40
#define ANSI_BACKSLASH_SEEN 0x80
#define ANSI_NORMAL 0x0000
#define ANSI_ESCAPE_SEEN 0x0002
#define ANSI_CSI 0x0004
#define ANSI_ST_CONTROL 0x0008
#define ANSI_IGNORE 0x0010
#define ANSI_IN_ARG 0x0020
#define ANSI_IN_STRING 0x0040
#define ANSI_BACKSLASH_SEEN 0x0080
#define ANSI_EXTENSION 0x0100
#define ANSI_DECSCUSR 0x0200
#define MAX_INPUT_BUFFER_LENGTH 8192
#define MAX_CONSOLE_CHAR 8192
@ -62,7 +64,12 @@
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
#define CURSOR_SIZE_SMALL 25
#define CURSOR_SIZE_LARGE 100
static void uv_tty_capture_initial_style(
CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
CONSOLE_CURSOR_INFO* cursor_info);
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
static int uv__cancel_read_console(uv_tty_t* handle);
@ -149,6 +156,8 @@ static char uv_tty_default_fg_bright = 0;
static char uv_tty_default_bg_bright = 0;
static char uv_tty_default_inverse = 0;
static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info;
/* Determine whether or not ANSI support is enabled. */
static BOOL uv__need_check_vterm_state = TRUE;
static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
@ -183,6 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
DWORD NumberOfEvents;
HANDLE handle;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
CONSOLE_CURSOR_INFO cursor_info;
(void)unused;
uv__once_init();
@ -215,6 +225,11 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
return uv_translate_sys_error(GetLastError());
}
/* Obtain the cursor info with the output handle. */
if (!GetConsoleCursorInfo(handle, &cursor_info)) {
return uv_translate_sys_error(GetLastError());
}
/* Obtain the tty_output_lock because the virtual window state is shared
* between all uv_tty_t handles. */
uv_sem_wait(&uv_tty_output_lock);
@ -222,8 +237,8 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
if (uv__need_check_vterm_state)
uv__determine_vterm_state(handle);
/* Remember the original console text attributes. */
uv_tty_capture_initial_style(&screen_buffer_info);
/* Remember the original console text attributes and cursor info. */
uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info);
uv_tty_update_virtual_window(&screen_buffer_info);
@ -274,7 +289,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
/* Set the default console text attributes based on how the console was
* configured when libuv started.
*/
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
static void uv_tty_capture_initial_style(
CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
CONSOLE_CURSOR_INFO* cursor_info) {
static int style_captured = 0;
/* Only do this once.
@ -283,7 +300,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
return;
/* Save raw win32 attributes. */
uv_tty_default_text_attributes = info->wAttributes;
uv_tty_default_text_attributes = screen_buffer_info->wAttributes;
/* Convert black text on black background to use white text. */
if (uv_tty_default_text_attributes == 0)
@ -323,6 +340,9 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
uv_tty_default_inverse = 1;
/* Save the cursor size and the cursor state. */
uv_tty_default_cursor_info = *cursor_info;
style_captured = 1;
}
@ -1230,7 +1250,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
const COORD origin = {0, 0};
const WORD char_attrs = uv_tty_default_text_attributes;
CONSOLE_SCREEN_BUFFER_INFO info;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
DWORD count, written;
if (*error != ERROR_SUCCESS) {
@ -1251,12 +1271,12 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
/* Clear the screen buffer. */
retry:
if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
*error = GetLastError();
return -1;
if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) {
*error = GetLastError();
return -1;
}
count = info.dwSize.X * info.dwSize.Y;
count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y;
if (!(FillConsoleOutputCharacterW(handle->handle,
L'\x20',
@ -1279,7 +1299,13 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
/* Move the virtual window up to the top. */
uv_tty_virtual_offset = 0;
uv_tty_update_virtual_window(&info);
uv_tty_update_virtual_window(&screen_buffer_info);
/* Reset the cursor size and the cursor state. */
if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
*error = GetLastError();
return -1;
}
return 0;
}
@ -1618,6 +1644,31 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
return 0;
}
static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
CONSOLE_CURSOR_INFO cursor_info;
if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
*error = GetLastError();
return -1;
}
if (style == 0) {
cursor_info.dwSize = uv_tty_default_cursor_info.dwSize;
} else if (style <= 2) {
cursor_info.dwSize = CURSOR_SIZE_LARGE;
} else {
cursor_info.dwSize = CURSOR_SIZE_SMALL;
}
if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
*error = GetLastError();
return -1;
}
return 0;
}
static int uv_tty_write_bufs(uv_tty_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
@ -1645,7 +1696,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
unsigned char previous_eol = handle->tty.wr.previous_eol;
unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state;
/* Store the error here. If we encounter an error, stop trying to do i/o but
* keep parsing the buffer so we leave the parser in a consistent state. */
@ -1761,7 +1812,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
ansi_parser_state = ANSI_NORMAL;
continue;
case '8':
case '8':
/* Restore the cursor position and text attributes */
FLUSH_TEXT();
uv_tty_restore_state(handle, 1, error);
@ -1779,121 +1830,193 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
}
}
} else if (ansi_parser_state == ANSI_IGNORE) {
/* We're ignoring this command. Stop only on command character. */
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
ansi_parser_state = ANSI_NORMAL;
}
continue;
} else if (ansi_parser_state == ANSI_DECSCUSR) {
/* So far we've the sequence `ESC [ arg space`, and we're waiting for
* the final command byte. */
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
/* Command byte */
if (utf8_codepoint == 'q') {
/* Change the cursor shape */
int style = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1;
if (style >= 0 && style <= 6) {
FLUSH_TEXT();
uv_tty_set_cursor_shape(handle, style, error);
}
}
/* Sequence ended - go back to normal state. */
ansi_parser_state = ANSI_NORMAL;
continue;
}
/* Unexpected character, but sequence hasn't ended yet. Ignore the rest
* of the sequence. */
ansi_parser_state = ANSI_IGNORE;
} else if (ansi_parser_state & ANSI_CSI) {
if (!(ansi_parser_state & ANSI_IGNORE)) {
if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
/* Parsing a numerical argument */
/* So far we've seen `ESC [`, and we may or may not have already parsed
* some of the arguments that follow. */
if (!(ansi_parser_state & ANSI_IN_ARG)) {
/* We were not currently parsing a number */
/* Check for too many arguments */
if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
ansi_parser_state |= ANSI_IGNORE;
continue;
}
ansi_parser_state |= ANSI_IN_ARG;
handle->tty.wr.ansi_csi_argc++;
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
(unsigned short) utf8_codepoint - '0';
continue;
} else {
/* We were already parsing a number. Parse next digit. */
uint32_t value = 10 *
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
/* Check for overflow. */
if (value > UINT16_MAX) {
ansi_parser_state |= ANSI_IGNORE;
continue;
}
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
(unsigned short) value + (utf8_codepoint - '0');
continue;
}
} else if (utf8_codepoint == ';') {
/* Denotes the end of an argument. */
if (ansi_parser_state & ANSI_IN_ARG) {
ansi_parser_state &= ~ANSI_IN_ARG;
continue;
} else {
/* If ANSI_IN_ARG is not set, add another argument and default it
* to 0. */
/* Check for too many arguments */
if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
ansi_parser_state |= ANSI_IGNORE;
continue;
}
handle->tty.wr.ansi_csi_argc++;
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
/* Parse a numerical argument. */
if (!(ansi_parser_state & ANSI_IN_ARG)) {
/* We were not currently parsing a number, add a new one. */
/* Check for that there are too many arguments. */
if (handle->tty.wr.ansi_csi_argc >=
ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
ansi_parser_state = ANSI_IGNORE;
continue;
}
} else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
handle->tty.wr.ansi_csi_argc == 0) {
/* Ignores '?' if it is the first character after CSI[. This is an
* extension character from the VT100 codeset that is supported and
* used by most ANSI terminals today. */
ansi_parser_state |= ANSI_IN_ARG;
handle->tty.wr.ansi_csi_argc++;
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
(unsigned short) utf8_codepoint - '0';
continue;
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
(handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
int x, y, d;
} else {
/* We were already parsing a number. Parse next digit. */
uint32_t value = 10 *
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
/* Command byte */
/* Check for overflow. */
if (value > UINT16_MAX) {
ansi_parser_state = ANSI_IGNORE;
continue;
}
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
(unsigned short) value + (utf8_codepoint - '0');
continue;
}
} else if (utf8_codepoint == ';') {
/* Denotes the end of an argument. */
if (ansi_parser_state & ANSI_IN_ARG) {
ansi_parser_state &= ~ANSI_IN_ARG;
continue;
} else {
/* If ANSI_IN_ARG is not set, add another argument and default
* it to 0. */
/* Check for too many arguments */
if (handle->tty.wr.ansi_csi_argc >=
ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
ansi_parser_state = ANSI_IGNORE;
continue;
}
handle->tty.wr.ansi_csi_argc++;
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
continue;
}
} else if (utf8_codepoint == '?' &&
!(ansi_parser_state & ANSI_IN_ARG) &&
!(ansi_parser_state & ANSI_EXTENSION) &&
handle->tty.wr.ansi_csi_argc == 0) {
/* Pass through '?' if it is the first character after CSI */
/* This is an extension character from the VT100 codeset */
/* that is supported and used by most ANSI terminals today. */
ansi_parser_state |= ANSI_EXTENSION;
continue;
} else if (utf8_codepoint == ' ' &&
!(ansi_parser_state & ANSI_EXTENSION)) {
/* We expect a command byte to follow after this space. The only
* command that we current support is 'set cursor style'. */
ansi_parser_state = ANSI_DECSCUSR;
continue;
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
/* Command byte */
if (ansi_parser_state & ANSI_EXTENSION) {
/* Sequence is `ESC [ ? args command`. */
switch (utf8_codepoint) {
case 'l':
/* Hide the cursor */
if (handle->tty.wr.ansi_csi_argc == 1 &&
handle->tty.wr.ansi_csi_argv[0] == 25) {
FLUSH_TEXT();
uv_tty_set_cursor_visibility(handle, 0, error);
}
break;
case 'h':
/* Show the cursor */
if (handle->tty.wr.ansi_csi_argc == 1 &&
handle->tty.wr.ansi_csi_argv[0] == 25) {
FLUSH_TEXT();
uv_tty_set_cursor_visibility(handle, 1, error);
}
break;
}
} else {
/* Sequence is `ESC [ args command`. */
int x, y, d;
switch (utf8_codepoint) {
case 'A':
/* cursor up */
FLUSH_TEXT();
y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
y = -(handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, 0, 1, y, 1, error);
break;
case 'B':
/* cursor down */
FLUSH_TEXT();
y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
y = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, 0, 1, y, 1, error);
break;
case 'C':
/* cursor forward */
FLUSH_TEXT();
x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
x = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, x, 1, 0, 1, error);
break;
case 'D':
/* cursor back */
FLUSH_TEXT();
x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
x = -(handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, x, 1, 0, 1, error);
break;
case 'E':
/* cursor next line */
FLUSH_TEXT();
y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
y = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, 0, 0, y, 1, error);
break;
case 'F':
/* cursor previous line */
FLUSH_TEXT();
y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
y = -(handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, 0, 0, y, 1, error);
break;
case 'G':
/* cursor horizontal move absolute */
FLUSH_TEXT();
x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
x = (handle->tty.wr.ansi_csi_argc >= 1 &&
handle->tty.wr.ansi_csi_argv[0])
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
uv_tty_move_caret(handle, x, 0, 0, 1, error);
break;
@ -1902,9 +2025,11 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
case 'f':
/* cursor move absolute */
FLUSH_TEXT();
y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
y = (handle->tty.wr.ansi_csi_argc >= 1 &&
handle->tty.wr.ansi_csi_argv[0])
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
x = (handle->tty.wr.ansi_csi_argc >= 2 &&
handle->tty.wr.ansi_csi_argv[1])
? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
uv_tty_move_caret(handle, x, 0, y, 0, error);
break;
@ -1912,7 +2037,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
case 'J':
/* Erase screen */
FLUSH_TEXT();
d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
d = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 0;
if (d >= 0 && d <= 2) {
uv_tty_clear(handle, d, 1, error);
}
@ -1921,7 +2047,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
case 'K':
/* Erase line */
FLUSH_TEXT();
d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
d = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 0;
if (d >= 0 && d <= 2) {
uv_tty_clear(handle, d, 0, error);
}
@ -1944,41 +2071,17 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT();
uv_tty_restore_state(handle, 0, error);
break;
case 'l':
/* Hide the cursor */
if (handle->tty.wr.ansi_csi_argc == 1 &&
handle->tty.wr.ansi_csi_argv[0] == 25) {
FLUSH_TEXT();
uv_tty_set_cursor_visibility(handle, 0, error);
}
break;
case 'h':
/* Show the cursor */
if (handle->tty.wr.ansi_csi_argc == 1 &&
handle->tty.wr.ansi_csi_argv[0] == 25) {
FLUSH_TEXT();
uv_tty_set_cursor_visibility(handle, 1, error);
}
break;
}
/* Sequence ended - go back to normal state. */
ansi_parser_state = ANSI_NORMAL;
continue;
} else {
/* We don't support commands that use private mode characters or
* intermediaries. Ignore the rest of the sequence. */
ansi_parser_state |= ANSI_IGNORE;
continue;
}
/* Sequence ended - go back to normal state. */
ansi_parser_state = ANSI_NORMAL;
continue;
} else {
/* We're ignoring this command. Stop only on command character. */
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
ansi_parser_state = ANSI_NORMAL;
}
/* We don't support commands that use private mode characters or
* intermediaries. Ignore the rest of the sequence. */
ansi_parser_state = ANSI_IGNORE;
continue;
}

View File

@ -125,17 +125,10 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
}
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
int domain;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return UV_EINVAL;
if (flags & ~0xFF)
return UV_EINVAL;
int uv__udp_init_ex(uv_loop_t* loop,
uv_udp_t* handle,
unsigned flags,
int domain) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
handle->socket = INVALID_SOCKET;
handle->reqs_pending = 0;
@ -174,11 +167,6 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
}
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
}
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
uv_udp_recv_stop(handle);
closesocket(handle->socket);
@ -786,8 +774,10 @@ int uv__udp_set_source_membership6(uv_udp_t* handle,
mreq.gsr_interface = 0;
}
memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group));
memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source));
STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
if (membership == UV_JOIN_GROUP)
optname = MCAST_JOIN_SOURCE_GROUP;

View File

@ -60,8 +60,8 @@
#endif
/* Maximum environment variable size, including the terminating null */
#define MAX_ENV_VAR_LENGTH 32767
/* A RtlGenRandom() by any other name... */
extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
/* Cached copy of the process title, plus a mutex guarding it. */
static char *process_title;
@ -151,20 +151,26 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
int uv_cwd(char* buffer, size_t* size) {
DWORD utf16_len;
WCHAR utf16_buffer[MAX_PATH];
WCHAR *utf16_buffer;
int r;
if (buffer == NULL || size == NULL) {
return UV_EINVAL;
}
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
utf16_len = GetCurrentDirectoryW(0, NULL);
if (utf16_len == 0) {
return uv_translate_sys_error(GetLastError());
} else if (utf16_len > MAX_PATH) {
/* This should be impossible; however the CRT has a code path to deal with
* this scenario, so I added a check anyway. */
return UV_EIO;
}
utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
if (utf16_buffer == NULL) {
return UV_ENOMEM;
}
utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
if (utf16_len == 0) {
uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
}
/* utf16_len contains the length, *not* including the terminating null. */
@ -188,8 +194,10 @@ int uv_cwd(char* buffer, size_t* size) {
NULL,
NULL);
if (r == 0) {
uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
} else if (r > (int) *size) {
uv__free(utf16_buffer);
*size = r;
return UV_ENOBUFS;
}
@ -203,6 +211,8 @@ int uv_cwd(char* buffer, size_t* size) {
*size > INT_MAX ? INT_MAX : (int) *size,
NULL,
NULL);
uv__free(utf16_buffer);
if (r == 0) {
return uv_translate_sys_error(GetLastError());
}
@ -213,43 +223,61 @@ int uv_cwd(char* buffer, size_t* size) {
int uv_chdir(const char* dir) {
WCHAR utf16_buffer[MAX_PATH];
size_t utf16_len;
WCHAR *utf16_buffer;
size_t utf16_len, new_utf16_len;
WCHAR drive_letter, env_var[4];
if (dir == NULL) {
return UV_EINVAL;
}
utf16_len = MultiByteToWideChar(CP_UTF8,
0,
dir,
-1,
NULL,
0);
if (utf16_len == 0) {
return uv_translate_sys_error(GetLastError());
}
utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
if (utf16_buffer == NULL) {
return UV_ENOMEM;
}
if (MultiByteToWideChar(CP_UTF8,
0,
dir,
-1,
utf16_buffer,
MAX_PATH) == 0) {
DWORD error = GetLastError();
/* The maximum length of the current working directory is 260 chars,
* including terminating null. If it doesn't fit, the path name must be too
* long. */
if (error == ERROR_INSUFFICIENT_BUFFER) {
return UV_ENAMETOOLONG;
} else {
return uv_translate_sys_error(error);
}
utf16_len) == 0) {
uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
}
if (!SetCurrentDirectoryW(utf16_buffer)) {
uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
}
/* Windows stores the drive-local path in an "hidden" environment variable,
* which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
* this, so we'll have to do it. */
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
if (new_utf16_len > utf16_len ) {
uv__free(utf16_buffer);
utf16_buffer = uv__malloc(new_utf16_len * sizeof(WCHAR));
if (utf16_buffer == NULL) {
/* When updating the environment variable fails, return UV_OK anyway.
* We did successfully change current working directory, only updating
* hidden env variable failed. */
return 0;
}
new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer);
}
if (utf16_len == 0) {
return uv_translate_sys_error(GetLastError());
} else if (utf16_len > MAX_PATH) {
return UV_EIO;
uv__free(utf16_buffer);
return 0;
}
/* The returned directory should not have a trailing slash, unless it points
@ -281,11 +309,10 @@ int uv_chdir(const char* dir) {
env_var[2] = L':';
env_var[3] = L'\0';
if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
return uv_translate_sys_error(GetLastError());
}
SetEnvironmentVariableW(env_var, utf16_buffer);
}
uv__free(utf16_buffer);
return 0;
}
@ -358,6 +385,10 @@ char** uv_setup_args(int argc, char** argv) {
}
void uv__process_title_cleanup(void) {
}
int uv_set_process_title(const char* title) {
int err;
int length;
@ -1160,20 +1191,29 @@ int uv_os_homedir(char* buffer, size_t* size) {
int uv_os_tmpdir(char* buffer, size_t* size) {
wchar_t path[MAX_PATH + 2];
wchar_t *path;
DWORD bufsize;
size_t len;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
len = GetTempPathW(ARRAY_SIZE(path), path);
len = 0;
len = GetTempPathW(0, NULL);
if (len == 0) {
return uv_translate_sys_error(GetLastError());
} else if (len > ARRAY_SIZE(path)) {
/* This should not be possible */
return UV_EIO;
}
/* Include space for terminating null char. */
len += 1;
path = uv__malloc(len * sizeof(wchar_t));
if (path == NULL) {
return UV_ENOMEM;
}
len = GetTempPathW(len, path);
if (len == 0) {
uv__free(path);
return uv_translate_sys_error(GetLastError());
}
/* The returned directory should not have a trailing slash, unless it points
@ -1188,8 +1228,10 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
uv__free(path);
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
uv__free(path);
*size = bufsize;
return UV_ENOBUFS;
}
@ -1203,6 +1245,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
*size,
NULL,
NULL);
uv__free(path);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
@ -1322,7 +1365,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
int uv__getpwuid_r(uv_passwd_t* pwd) {
HANDLE token;
wchar_t username[UNLEN + 1];
wchar_t path[MAX_PATH];
wchar_t *path;
DWORD bufsize;
int r;
@ -1333,15 +1376,24 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
return uv_translate_sys_error(GetLastError());
bufsize = ARRAY_SIZE(path);
bufsize = 0;
GetUserProfileDirectoryW(token, NULL, &bufsize);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
r = GetLastError();
CloseHandle(token);
return uv_translate_sys_error(r);
}
path = uv__malloc(bufsize * sizeof(wchar_t));
if (path == NULL) {
CloseHandle(token);
return UV_ENOMEM;
}
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
r = GetLastError();
CloseHandle(token);
/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
return UV_ENOMEM;
uv__free(path);
return uv_translate_sys_error(r);
}
@ -1351,6 +1403,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
bufsize = ARRAY_SIZE(username);
if (!GetUserNameW(username, &bufsize)) {
r = GetLastError();
uv__free(path);
/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
@ -1361,6 +1414,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
pwd->homedir = NULL;
r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
uv__free(path);
if (r != 0)
return r;
@ -1402,7 +1456,7 @@ int uv_os_environ(uv_env_item_t** envitems, int* count) {
for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
*envitems = uv__calloc(i, sizeof(**envitems));
if (envitems == NULL) {
if (*envitems == NULL) {
FreeEnvironmentStringsW(env);
return UV_ENOMEM;
}
@ -1458,7 +1512,9 @@ fail:
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
wchar_t var[MAX_ENV_VAR_LENGTH];
wchar_t fastvar[512];
wchar_t* var;
DWORD varlen;
wchar_t* name_w;
DWORD bufsize;
size_t len;
@ -1472,25 +1528,52 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
if (r != 0)
return r;
SetLastError(ERROR_SUCCESS);
len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
var = fastvar;
varlen = ARRAY_SIZE(fastvar);
for (;;) {
SetLastError(ERROR_SUCCESS);
len = GetEnvironmentVariableW(name_w, var, varlen);
if (len < varlen)
break;
/* Try repeatedly because we might have been preempted by another thread
* modifying the environment variable just as we're trying to read it.
*/
if (var != fastvar)
uv__free(var);
varlen = 1 + len;
var = uv__malloc(varlen * sizeof(*var));
if (var == NULL) {
r = UV_ENOMEM;
goto fail;
}
}
uv__free(name_w);
assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
name_w = NULL;
if (len == 0) {
r = GetLastError();
if (r != ERROR_SUCCESS)
return uv_translate_sys_error(r);
if (r != ERROR_SUCCESS) {
r = uv_translate_sys_error(r);
goto fail;
}
}
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
r = uv_translate_sys_error(GetLastError());
goto fail;
} else if (bufsize > *size) {
*size = bufsize;
return UV_ENOBUFS;
r = UV_ENOBUFS;
goto fail;
}
/* Convert to UTF-8 */
@ -1503,11 +1586,23 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
if (bufsize == 0) {
r = uv_translate_sys_error(GetLastError());
goto fail;
}
*size = bufsize - 1;
return 0;
r = 0;
fail:
if (name_w != NULL)
uv__free(name_w);
if (var != fastvar)
uv__free(var);
return r;
}
@ -1862,13 +1957,10 @@ int uv_gettimeofday(uv_timeval64_t* tv) {
}
int uv__random_rtlgenrandom(void* buf, size_t buflen) {
if (pRtlGenRandom == NULL)
return UV_ENOSYS;
if (buflen == 0)
return 0;
if (pRtlGenRandom(buf, buflen) == FALSE)
if (SystemFunction036(buf, buflen) == FALSE)
return UV_EIO;
return 0;

View File

@ -36,9 +36,6 @@ sNtQueryDirectoryFile pNtQueryDirectoryFile;
sNtQuerySystemInformation pNtQuerySystemInformation;
sNtQueryInformationProcess pNtQueryInformationProcess;
/* Advapi32 function pointers */
sRtlGenRandom pRtlGenRandom;
/* Kernel32 function pointers */
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
@ -54,7 +51,6 @@ void uv_winapi_init(void) {
HMODULE powrprof_module;
HMODULE user32_module;
HMODULE kernel32_module;
HMODULE advapi32_module;
ntdll_module = GetModuleHandleA("ntdll.dll");
if (ntdll_module == NULL) {
@ -138,12 +134,4 @@ void uv_winapi_init(void) {
pSetWinEventHook = (sSetWinEventHook)
GetProcAddress(user32_module, "SetWinEventHook");
}
advapi32_module = GetModuleHandleA("advapi32.dll");
if (advapi32_module == NULL) {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
}
pRtlGenRandom =
(sRtlGenRandom) GetProcAddress(advapi32_module, "SystemFunction036");
}

View File

@ -4152,6 +4152,10 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
struct {
ULONG StringCount;
WCHAR StringList[1];
} AppExecLinkReparseBuffer;
};
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
#endif
@ -4517,6 +4521,9 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
#ifndef IO_REPARSE_TAG_SYMLINK
# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
#endif
#ifndef IO_REPARSE_TAG_APPEXECLINK
# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL)
#endif
typedef VOID (NTAPI *PIO_APC_ROUTINE)
(PVOID ApcContext,
@ -4589,11 +4596,6 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess)
ULONG Length,
PULONG ReturnLength);
/*
* Advapi32 headers
*/
typedef BOOLEAN (WINAPI *sRtlGenRandom)(PVOID Buffer, ULONG BufferLength);
/*
* Kernel32 headers
*/
@ -4736,9 +4738,6 @@ extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
extern sNtQuerySystemInformation pNtQuerySystemInformation;
extern sNtQueryInformationProcess pNtQueryInformationProcess;
/* Advapi32 function pointers */
extern sRtlGenRandom pRtlGenRandom;
/* Kernel32 function pointers */
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;

View File

@ -1 +1 @@
1.34.2 release
1.38.0 release