diff options
Diffstat (limited to 'deps/uv/src')
-rw-r--r-- | deps/uv/src/unix/aix.c | 21 | ||||
-rw-r--r-- | deps/uv/src/unix/android-ifaddrs.c | 41 | ||||
-rw-r--r-- | deps/uv/src/unix/bsd-ifaddrs.c | 15 | ||||
-rw-r--r-- | deps/uv/src/unix/core.c | 11 | ||||
-rw-r--r-- | deps/uv/src/unix/freebsd.c | 6 | ||||
-rw-r--r-- | deps/uv/src/unix/fs.c | 139 | ||||
-rw-r--r-- | deps/uv/src/unix/internal.h | 12 | ||||
-rw-r--r-- | deps/uv/src/unix/kqueue.c | 35 | ||||
-rw-r--r-- | deps/uv/src/unix/linux-core.c | 14 | ||||
-rw-r--r-- | deps/uv/src/unix/netbsd.c | 8 | ||||
-rw-r--r-- | deps/uv/src/unix/openbsd.c | 7 | ||||
-rw-r--r-- | deps/uv/src/unix/os390-syscalls.c | 23 | ||||
-rw-r--r-- | deps/uv/src/unix/os390.c | 38 | ||||
-rw-r--r-- | deps/uv/src/unix/poll.c | 25 | ||||
-rw-r--r-- | deps/uv/src/unix/pthread-barrier.c | 121 | ||||
-rw-r--r-- | deps/uv/src/unix/thread.c | 122 | ||||
-rw-r--r-- | deps/uv/src/win/dl.c | 55 | ||||
-rw-r--r-- | deps/uv/src/win/fs.c | 448 | ||||
-rw-r--r-- | deps/uv/src/win/pipe.c | 2 | ||||
-rw-r--r-- | deps/uv/src/win/process.c | 9 | ||||
-rw-r--r-- | deps/uv/src/win/tcp.c | 15 | ||||
-rw-r--r-- | deps/uv/src/win/tty.c | 1 | ||||
-rw-r--r-- | deps/uv/src/win/winapi.h | 4 |
23 files changed, 664 insertions, 508 deletions
diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 426f7f4735..56a8f4ffe7 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -1108,9 +1108,10 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; - int sockfd, size = 1; + int sockfd, inet6, size = 1; struct ifconf ifc; struct ifreq *ifr, *p, flg; + struct sockaddr_dl* sa_addr; *count = 0; @@ -1174,6 +1175,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, p->ifr_addr.sa_family == AF_INET)) continue; + inet6 = (p->ifr_addr.sa_family == AF_INET6); + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { uv__close(sockfd); @@ -1187,13 +1190,23 @@ int uv_interface_addresses(uv_interface_address_t** addresses, address->name = uv__strdup(p->ifr_name); - if (p->ifr_addr.sa_family == AF_INET6) { + if (inet6) address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); - } else { + else address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + + sa_addr = (struct sockaddr_dl*) &p->ifr_addr; + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + + if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { + uv__close(sockfd); + return -ENOSYS; } - /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + if (inet6) + address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; diff --git a/deps/uv/src/unix/android-ifaddrs.c b/deps/uv/src/unix/android-ifaddrs.c index 30f681b7d0..1a842ced48 100644 --- a/deps/uv/src/unix/android-ifaddrs.c +++ b/deps/uv/src/unix/android-ifaddrs.c @@ -43,9 +43,10 @@ typedef struct NetlinkList unsigned int m_size; } NetlinkList; -static int netlink_socket(void) +static int netlink_socket(pid_t *p_pid) { struct sockaddr_nl l_addr; + socklen_t l_len; int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if(l_socket < 0) @@ -61,6 +62,14 @@ static int netlink_socket(void) return -1; } + l_len = sizeof(l_addr); + if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0) + { + close(l_socket); + return -1; + } + *p_pid = l_addr.nl_pid; + return l_socket; } @@ -128,7 +137,7 @@ static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) } } -static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) +static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done) { size_t l_size = 4096; void *l_buffer = NULL; @@ -153,11 +162,10 @@ static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_don } if(l_read >= 0) { - pid_t l_pid = getpid(); struct nlmsghdr *l_hdr; for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -207,7 +215,7 @@ static void freeResultList(NetlinkList *p_list) } } -static NetlinkList *getResultList(int p_socket, int p_request) +static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid) { int l_size; int l_done; @@ -227,7 +235,7 @@ static NetlinkList *getResultList(int p_socket, int p_request) { NetlinkList *l_item; - struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done); /* Error */ if(!l_hdr) { @@ -578,18 +586,17 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, return 0; } -static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) +static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) { int l_numLinks = 0; - pid_t l_pid = getpid(); for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) { unsigned int l_nlsize = p_netlinkList->m_size; struct nlmsghdr *l_hdr; for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -612,16 +619,15 @@ static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifadd return l_numLinks; } -static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) +static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) { - pid_t l_pid = getpid(); for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) { unsigned int l_nlsize = p_netlinkList->m_size; struct nlmsghdr *l_hdr; for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -648,6 +654,7 @@ int getifaddrs(struct ifaddrs **ifap) int l_socket; int l_result; int l_numLinks; + pid_t l_pid; NetlinkList *l_linkResults; NetlinkList *l_addrResults; @@ -657,20 +664,20 @@ int getifaddrs(struct ifaddrs **ifap) } *ifap = NULL; - l_socket = netlink_socket(); + l_socket = netlink_socket(&l_pid); if(l_socket < 0) { return -1; } - l_linkResults = getResultList(l_socket, RTM_GETLINK); + l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid); if(!l_linkResults) { close(l_socket); return -1; } - l_addrResults = getResultList(l_socket, RTM_GETADDR); + l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid); if(!l_addrResults) { close(l_socket); @@ -679,8 +686,8 @@ int getifaddrs(struct ifaddrs **ifap) } l_result = 0; - l_numLinks = interpretLinks(l_socket, l_linkResults, ifap); - if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) + l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap); + if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1) { l_result = -1; } diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c index 414789451a..ffcf156440 100644 --- a/deps/uv/src/unix/bsd-ifaddrs.c +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -31,11 +31,18 @@ #include <net/if_dl.h> #endif -static int uv__ifaddr_exclude(struct ifaddrs *ent) { +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; if (ent->ifa_addr == NULL) return 1; + /* + * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family` + * equals to `AF_LINK` or not. Otherwise, the result depends on the operation + * system with `AF_LINK` or `PF_INET`. + */ + if (exclude_type == UV__EXCLUDE_IFPHYS) + return (ent->ifa_addr->sa_family != AF_LINK); #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) /* * On BSD getifaddrs returns information related to the raw underlying @@ -63,7 +70,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; (*count)++; } @@ -78,7 +85,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; address->name = uv__strdup(ent->ifa_name); @@ -102,7 +109,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; address = *addresses; diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 4c744925e2..bee641cb44 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -838,7 +838,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -866,7 +866,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); if (w->fd == -1) @@ -898,7 +898,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_close(uv_loop_t* loop, uv__io_t* w) { - uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ @@ -913,7 +913,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); return 0 != (w->pevents & events); } @@ -1292,6 +1292,9 @@ int uv_os_setenv(const char* name, const char* value) { int uv_os_unsetenv(const char* name) { + if (name == NULL) + return -EINVAL; + if (unsetenv(name) != 0) return -errno; diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index c3c4902be9..dba94298d1 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -160,9 +160,13 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { int oid[4]; + char* new_title; + new_title = uv__strdup(title); + if (process_title == NULL) + return -ENOMEM; uv__free(process_title); - process_title = uv__strdup(title); + process_title = new_title; oid[0] = CTL_KERN; oid[1] = KERN_PROC; diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index f9513ea55a..5a172cc780 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -60,8 +60,14 @@ # include <sys/sendfile.h> #endif +#if defined(__APPLE__) +# include <copyfile.h> +#endif + #define INIT(subtype) \ do { \ + if (req == NULL) \ + return -EINVAL; \ req->type = UV_FS; \ if (cb != NULL) \ uv__req_init(loop, req, UV_FS); \ @@ -766,6 +772,112 @@ done: return r; } +static ssize_t uv__fs_copyfile(uv_fs_t* req) { +#if defined(__APPLE__) && !TARGET_OS_IPHONE + /* On macOS, use the native copyfile(3). */ + copyfile_flags_t flags; + + flags = COPYFILE_ALL; + + if (req->flags & UV_FS_COPYFILE_EXCL) + flags |= COPYFILE_EXCL; + + return copyfile(req->path, req->new_path, NULL, flags); +#else + uv_fs_t fs_req; + uv_file srcfd; + uv_file dstfd; + struct stat statsbuf; + int dst_flags; + int result; + int err; + size_t bytes_to_send; + int64_t in_offset; + + dstfd = -1; + + /* Open the source file. */ + srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL); + uv_fs_req_cleanup(&fs_req); + + if (srcfd < 0) + return srcfd; + + /* Get the source file's mode. */ + if (fstat(srcfd, &statsbuf)) { + err = -errno; + goto out; + } + + dst_flags = O_WRONLY | O_CREAT; + + if (req->flags & UV_FS_COPYFILE_EXCL) + dst_flags |= O_EXCL; + + /* Open the destination file. */ + dstfd = uv_fs_open(NULL, + &fs_req, + req->new_path, + dst_flags, + statsbuf.st_mode, + NULL); + uv_fs_req_cleanup(&fs_req); + + if (dstfd < 0) { + err = dstfd; + goto out; + } + + bytes_to_send = statsbuf.st_size; + in_offset = 0; + while (bytes_to_send != 0) { + err = uv_fs_sendfile(NULL, + &fs_req, + dstfd, + srcfd, + in_offset, + bytes_to_send, + NULL); + uv_fs_req_cleanup(&fs_req); + if (err < 0) + break; + bytes_to_send -= fs_req.result; + in_offset += fs_req.result; + } + +out: + if (err < 0) + result = err; + else + result = 0; + + /* Close the source file. */ + err = uv__close_nocheckstdio(srcfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Close the destination file if it is open. */ + if (dstfd >= 0) { + err = uv__close_nocheckstdio(dstfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Remove the destination file if something went wrong. */ + if (result != 0) { + uv_fs_unlink(NULL, &fs_req, req->new_path, NULL); + /* Ignore the unlink return value, as an error already happened. */ + uv_fs_req_cleanup(&fs_req); + } + } + + return result; +#endif +} + static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_dev = src->st_dev; dst->st_mode = src->st_mode; @@ -946,6 +1058,7 @@ static void uv__fs_work(struct uv__work* w) { X(CHMOD, chmod(req->path, req->mode)); X(CHOWN, chown(req->path, req->uid, req->gid)); X(CLOSE, close(req->file)); + X(COPYFILE, uv__fs_copyfile(req)); X(FCHMOD, fchmod(req->file, req->mode)); X(FCHOWN, fchown(req->file, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); @@ -1186,10 +1299,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, unsigned int nbufs, int64_t off, uv_fs_cb cb) { + INIT(READ); + if (bufs == NULL || nbufs == 0) return -EINVAL; - INIT(READ); req->file = file; req->nbufs = nbufs; @@ -1324,10 +1438,11 @@ int uv_fs_write(uv_loop_t* loop, unsigned int nbufs, int64_t off, uv_fs_cb cb) { + INIT(WRITE); + if (bufs == NULL || nbufs == 0) return -EINVAL; - INIT(WRITE); req->file = file; req->nbufs = nbufs; @@ -1349,6 +1464,9 @@ int uv_fs_write(uv_loop_t* loop, void uv_fs_req_cleanup(uv_fs_t* req) { + if (req == NULL) + return; + /* Only necessary for asychronous requests, i.e., requests with a callback. * Synchronous ones don't copy their arguments and have req->path and * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the @@ -1367,3 +1485,20 @@ void uv_fs_req_cleanup(uv_fs_t* req) { uv__free(req->ptr); req->ptr = NULL; } + + +int uv_fs_copyfile(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + INIT(COPYFILE); + + if (flags & ~UV_FS_COPYFILE_EXCL) + return -EINVAL; + + PATH2; + req->flags = flags; + POST; +} diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 2e3afa6c85..c0898d982e 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -110,6 +110,12 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); # define UV__POLLRDHUP 0x2000 #endif +#ifdef POLLPRI +# define UV__POLLPRI POLLPRI +#else +# define UV__POLLPRI 0 +#endif + #if !defined(O_CLOEXEC) && defined(__FreeBSD__) /* * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. @@ -145,6 +151,12 @@ enum { UV_LOOP_BLOCK_SIGPROF = 1 }; +/* flags of excluding ifaddr */ +enum { + UV__EXCLUDE_IFPHYS, + UV__EXCLUDE_IFADDR +}; + typedef enum { UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */ UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 6bc60bbe46..300bac07c3 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -34,6 +34,17 @@ #include <fcntl.h> #include <time.h> +/* + * Required on + * - Until at least FreeBSD 11.0 + * - Older versions of Mac OS X + * + * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp + */ +#ifndef EV_OOBAND +#define EV_OOBAND EV_FLAG1 +#endif + static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); @@ -166,6 +177,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } + if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) { + EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + w->events = w->pevents; } @@ -275,6 +296,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } + if (ev->filter == EV_OOBAND) { + if (w->pevents & UV__POLLPRI) { + revents |= UV__POLLPRI; + w->rcount = ev->data; + } else { + /* TODO batch up */ + struct kevent events[1]; + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != ENOENT) + abort(); + } + } + if (ev->filter == EVFILT_WRITE) { if (w->pevents & POLLOUT) { revents |= POLLOUT; diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 2866e93854..4d480ce10a 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -388,7 +388,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * free when we switch over to edge-triggered I/O. */ if (pe->events == POLLERR || pe->events == POLLHUP) - pe->events |= w->pevents & (POLLIN | POLLOUT); + pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI); if (pe->events != 0) { /* Run signal watchers last. This also affects child process watchers @@ -837,7 +837,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } -static int uv__ifaddr_exclude(struct ifaddrs *ent) { +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; if (ent->ifa_addr == NULL) @@ -847,8 +847,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) { * devices. We're not interested in this information yet. */ if (ent->ifa_addr->sa_family == PF_PACKET) - return 1; - return 0; + return exclude_type; + return !exclude_type; } int uv_interface_addresses(uv_interface_address_t** addresses, @@ -869,7 +869,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; (*count)++; @@ -887,7 +887,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; address->name = uv__strdup(ent->ifa_name); @@ -911,7 +911,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; address = *addresses; diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c index 9b5546b7e6..c54c04df28 100644 --- a/deps/uv/src/unix/netbsd.c +++ b/deps/uv/src/unix/netbsd.c @@ -124,9 +124,13 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { - if (process_title) uv__free(process_title); + char* new_title; - process_title = uv__strdup(title); + new_title = uv__strdup(title); + if (process_title == NULL) + return -ENOMEM; + uv__free(process_title); + process_title = new_title; setproctitle("%s", title); return 0; diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 56f0af15c3..d1c90289e5 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -146,8 +146,13 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { + char* new_title; + + new_title = uv__strdup(title); + if (process_title == NULL) + return -ENOMEM; uv__free(process_title); - process_title = uv__strdup(title); + process_title = new_title; setproctitle("%s", title); return 0; } diff --git a/deps/uv/src/unix/os390-syscalls.c b/deps/uv/src/unix/os390-syscalls.c index 7edf2358d4..08623f4eaf 100644 --- a/deps/uv/src/unix/os390-syscalls.c +++ b/deps/uv/src/unix/os390-syscalls.c @@ -183,33 +183,22 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, int pollret; int reventcount; - uv_mutex_lock(&global_epoll_lock); - uv_mutex_unlock(&global_epoll_lock); size = lst->size; pfds = lst->items; pollret = poll(pfds, size, timeout); - if(pollret == -1) + if (pollret <= 0) return pollret; reventcount = 0; - for (int i = 0; i < lst->size && i < maxevents; ++i) { + for (int i = 0; + i < lst->size && i < maxevents && reventcount < pollret; ++i) { struct epoll_event ev; - ev.events = 0; - ev.fd = pfds[i].fd; - if(!pfds[i].revents) + if (pfds[i].fd == -1 || pfds[i].revents == 0) continue; - if(pfds[i].revents & POLLRDNORM) - ev.events = ev.events | POLLIN; - - if(pfds[i].revents & POLLWRNORM) - ev.events = ev.events | POLLOUT; - - if(pfds[i].revents & POLLHUP) - ev.events = ev.events | POLLHUP; - - pfds[i].revents = 0; + ev.fd = pfds[i].fd; + ev.events = pfds[i].revents; events[reventcount++] = ev; } diff --git a/deps/uv/src/unix/os390.c b/deps/uv/src/unix/os390.c index de7df91169..559970de2c 100644 --- a/deps/uv/src/unix/os390.c +++ b/deps/uv/src/unix/os390.c @@ -33,6 +33,7 @@ #endif #define CVT_PTR 0x10 +#define PSA_PTR 0x00 #define CSD_OFFSET 0x294 /* @@ -70,6 +71,18 @@ /* CPC model length from the CSRSI Service. */ #define CPCMODEL_LENGTH 16 +/* Pointer to the home (current) ASCB. */ +#define PSAAOLD 0x224 + +/* Pointer to rsm address space block extension. */ +#define ASCBRSME 0x16C + +/* + NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE. + It does not include 2G frames. +*/ +#define RAXFMCT 0x2C + /* Thread Entry constants */ #define PGTH_CURRENT 1 #define PGTH_LEN 26 @@ -77,6 +90,9 @@ #pragma linkage(BPX4GTH, OS) #pragma linkage(BPX1GTH, OS) +/* TOD Clock resolution in nanoseconds */ +#define TOD_RES 4.096 + typedef unsigned data_area_ptr_assign_type; typedef union { @@ -122,7 +138,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) { unsigned long long timestamp; __stckf(×tamp); /* Convert to nanoseconds */ - return timestamp / 10; + return timestamp / TOD_RES; } @@ -339,13 +355,17 @@ uint64_t uv_get_total_memory(void) { int uv_resident_set_memory(size_t* rss) { - W_PSPROC buf; + char* psa; + char* ascb; + char* rax; + size_t nframes; - memset(&buf, 0, sizeof(buf)); - if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1) - return -EINVAL; + psa = PSA_PTR; + ascb = *(char* __ptr32 *)(psa + PSAAOLD); + rax = *(char* __ptr32 *)(ascb + ASCBRSME); + nframes = *(unsigned int*)(rax + RAXFMCT); - *rss = buf.ps_size; + *rss = nframes * sysconf(_SC_PAGESIZE); return 0; } @@ -747,9 +767,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); - timeout = real_timeout - timeout; - if (timeout > 0) + + if (timeout > 0) { + timeout = real_timeout - timeout; continue; + } return; } diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 370994bd57..816c7dc2eb 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -33,8 +33,19 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); - if (events & POLLERR) { - uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + /* + * As documented in the kernel source fs/kernfs/file.c #780 + * poll will return POLLERR|POLLPRI in case of sysfs + * polling. This does not happen in case of out-of-band + * TCP messages. + * + * The above is the case on (at least) FreeBSD and Linux. + * + * So to properly determine a POLLPRI or a POLLERR we need + * to check for both. + */ + if ((events & POLLERR) && !(events & UV__POLLPRI)) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); uv__handle_stop(handle); handle->poll_cb(handle, -EBADF, 0); return; @@ -43,6 +54,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { pevents = 0; if (events & POLLIN) pevents |= UV_READABLE; + if (events & UV__POLLPRI) + pevents |= UV_PRIORITIZED; if (events & POLLOUT) pevents |= UV_WRITABLE; if (events & UV__POLLRDHUP) @@ -86,8 +99,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { uv__io_stop(handle->loop, &handle->io_watcher, - POLLIN | POLLOUT | UV__POLLRDHUP); + POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); uv__handle_stop(handle); + uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd); } @@ -101,7 +115,8 @@ int uv_poll_stop(uv_poll_t* handle) { int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int events; - assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT | + UV_PRIORITIZED)) == 0); assert(!uv__is_closing(handle)); uv__poll_stop(handle); @@ -112,6 +127,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events = 0; if (pevents & UV_READABLE) events |= POLLIN; + if (pevents & UV_PRIORITIZED) + events |= UV__POLLPRI; if (pevents & UV_WRITABLE) events |= POLLOUT; if (pevents & UV_DISCONNECT) diff --git a/deps/uv/src/unix/pthread-barrier.c b/deps/uv/src/unix/pthread-barrier.c deleted file mode 100644 index b6e604d46d..0000000000 --- a/deps/uv/src/unix/pthread-barrier.c +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com> - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -#include "uv-common.h" -#include "pthread-barrier.h" - -#include <stdlib.h> -#include <assert.h> - -/* TODO: support barrier_attr */ -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || count == 0) - return EINVAL; - - if (barrier_attr != NULL) - return ENOTSUP; - - b = uv__malloc(sizeof(*b)); - if (b == NULL) - return ENOMEM; - - b->in = 0; - b->out = 0; - b->threshold = count; - - if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) - goto error2; - if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) - goto error; - - barrier->b = b; - return 0; - -error: - pthread_mutex_destroy(&b->mutex); -error2: - uv__free(b); - return rc; -} - -int pthread_barrier_wait(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || barrier->b == NULL) - return EINVAL; - - b = barrier->b; - /* Lock the mutex*/ - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - /* Increment the count. If this is the first thread to reach the threshold, - wake up waiters, unlock the mutex, then return - PTHREAD_BARRIER_SERIAL_THREAD. */ - if (++b->in == b->threshold) { - b->in = 0; - b->out = b->threshold - 1; - rc = pthread_cond_signal(&b->cond); - assert(rc == 0); - - pthread_mutex_unlock(&b->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; - } - /* Otherwise, wait for other threads until in is set to 0, - then return 0 to indicate this is not the first thread. */ - do { - if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) - break; - } while (b->in != 0); - - /* mark thread exit */ - b->out--; - pthread_cond_signal(&b->cond); - pthread_mutex_unlock(&b->mutex); - return rc; -} - -int pthread_barrier_destroy(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || barrier->b == NULL) - return EINVAL; - - b = barrier->b; - - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - if (b->in > 0 || b->out > 0) - rc = EBUSY; - - pthread_mutex_unlock(&b->mutex); - - if (rc) - return rc; - - pthread_cond_destroy(&b->cond); - pthread_mutex_destroy(&b->mutex); - uv__free(barrier->b); - barrier->b = NULL; - return 0; -} diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index a9b5e4c02a..f884622591 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -41,6 +41,110 @@ #define NANOSEC ((uint64_t) 1e9) +#if defined(UV__PTHREAD_BARRIER_FALLBACK) +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + rc = pthread_cond_signal(&b->cond); + assert(rc == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} +#endif + + int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { int err; pthread_attr_t* attr; @@ -283,16 +387,19 @@ int uv_sem_init(uv_sem_t* sem, unsigned int value) { uv_sem_t semid; struct sembuf buf; int err; + union { + int val; + struct semid_ds* buf; + unsigned short* array; + } arg; - buf.sem_num = 0; - buf.sem_op = value; - buf.sem_flg = 0; semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); if (semid == -1) return -errno; - if (-1 == semop(semid, &buf, 1)) { + arg.val = value; + if (-1 == semctl(semid, 0, SETVAL, arg)) { err = errno; if (-1 == semctl(*sem, 0, IPC_RMID)) abort(); @@ -424,7 +531,7 @@ int uv_cond_init(uv_cond_t* cond) { if (err) return -err; -#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) +#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); if (err) goto error2; @@ -511,7 +618,8 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { timeout += uv__hrtime(UV_CLOCK_PRECISE); ts.tv_sec = timeout / NANOSEC; ts.tv_nsec = timeout % NANOSEC; -#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + /* * The bionic pthread implementation doesn't support CLOCK_MONOTONIC, * but has this alternative function instead. @@ -519,7 +627,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts); #else r = pthread_cond_timedwait(cond, mutex, &ts); -#endif /* __ANDROID__ */ +#endif /* __ANDROID_API__ */ #endif diff --git a/deps/uv/src/win/dl.c b/deps/uv/src/win/dl.c index 39e400ab2d..d454014d8a 100644 --- a/deps/uv/src/win/dl.c +++ b/deps/uv/src/win/dl.c @@ -22,7 +22,7 @@ #include "uv.h" #include "internal.h" -static int uv__dlerror(uv_lib_t* lib, int errorno); +static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno); int uv_dlopen(const char* filename, uv_lib_t* lib) { @@ -37,12 +37,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) { -1, filename_w, ARRAY_SIZE(filename_w))) { - return uv__dlerror(lib, GetLastError()); + return uv__dlerror(lib, filename, GetLastError()); } lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (lib->handle == NULL) { - return uv__dlerror(lib, GetLastError()); + return uv__dlerror(lib, filename, GetLastError()); } return 0; @@ -65,7 +65,7 @@ void uv_dlclose(uv_lib_t* lib) { int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { *ptr = (void*) GetProcAddress(lib->handle, name); - return uv__dlerror(lib, *ptr ? 0 : GetLastError()); + return uv__dlerror(lib, "", *ptr ? 0 : GetLastError()); } @@ -88,31 +88,46 @@ static void uv__format_fallback_error(uv_lib_t* lib, int errorno){ -static int uv__dlerror(uv_lib_t* lib, int errorno) { +static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) { + static const char not_win32_app_msg[] = "%1 is not a valid Win32 application"; + DWORD_PTR arg; DWORD res; if (lib->errmsg) { - LocalFree((void*)lib->errmsg); + LocalFree(lib->errmsg); lib->errmsg = NULL; } - if (errorno) { + if (errorno == 0) + return 0; + + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR) &lib->errmsg, 0, NULL); + + if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), - (LPSTR) &lib->errmsg, 0, NULL); - if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { - res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, - 0, (LPSTR) &lib->errmsg, 0, NULL); - } - - if (!res) { - uv__format_fallback_error(lib, errorno); - } + 0, (LPSTR) &lib->errmsg, 0, NULL); + } + + /* Inexpert hack to get the filename into the error message. */ + if (res && strstr(lib->errmsg, not_win32_app_msg)) { + LocalFree(lib->errmsg); + lib->errmsg = NULL; + arg = (DWORD_PTR) filename; + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_FROM_STRING, + not_win32_app_msg, + 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg); } - return errorno ? -1 : 0; + if (!res) + uv__format_fallback_error(lib, errorno); + + return -1; } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 8223d6f655..c374a82ca0 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -43,11 +43,26 @@ #define UV_FS_CLEANEDUP 0x0010 -#define QUEUE_FS_TP_JOB(loop, req) \ - do { \ - uv__req_register(loop, req); \ - uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \ - } while (0) +#define INIT(subtype) \ + do { \ + if (req == NULL) \ + return UV_EINVAL; \ + uv_fs_req_init(loop, req, subtype, cb); \ + } \ + while (0) + +#define POST \ + do { \ + if (cb != NULL) { \ + uv__req_register(loop, req); \ + uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + return 0; \ + } else { \ + uv__fs_work(&req->work_req); \ + return req->result; \ + } \ + } \ + while (0) #define SET_REQ_RESULT(req, result_value) \ do { \ @@ -113,6 +128,7 @@ const WCHAR LONG_PATH_PREFIX_LEN = 4; const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\"; const WCHAR UNC_PATH_PREFIX_LEN = 8; +static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; void uv_fs_init(void) { _fmode = _O_BINARY; @@ -220,6 +236,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type, const uv_fs_cb cb) { + uv__once_init(); UV_REQ_INIT(req, UV_FS); req->loop = loop; req->flags = 0; @@ -1118,8 +1135,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { */ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) { statbuf->st_mode |= S_IFLNK; - } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) { - return -1; } } @@ -1333,6 +1348,22 @@ static void fs__ftruncate(uv_fs_t* req) { } +static void fs__copyfile(uv_fs_t* req) { + int flags; + int overwrite; + + flags = req->fs.info.file_flags; + overwrite = flags & UV_FS_COPYFILE_EXCL; + + if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + SET_REQ_RESULT(req, 0); +} + + static void fs__sendfile(uv_fs_t* req) { int fd_in = req->file.fd, fd_out = req->fs.info.fd_out; size_t length = req->fs.info.bufsml[0].len; @@ -1699,25 +1730,46 @@ error: static void fs__symlink(uv_fs_t* req) { - WCHAR* pathw = req->file.pathw; - WCHAR* new_pathw = req->fs.info.new_pathw; - int flags = req->fs.info.file_flags; - int result; + WCHAR* pathw; + WCHAR* new_pathw; + int flags; + int err; + pathw = req->file.pathw; + new_pathw = req->fs.info.new_pathw; - if (flags & UV_FS_SYMLINK_JUNCTION) { + if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) { fs__create_junction(req, pathw, new_pathw); - } else if (pCreateSymbolicLinkW) { - result = pCreateSymbolicLinkW(new_pathw, - pathw, - flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; - if (result == -1) { - SET_REQ_WIN32_ERROR(req, GetLastError()); - } else { - SET_REQ_RESULT(req, result); - } - } else { + return; + } + if (!pCreateSymbolicLinkW) { SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + + if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR) + flags = SYMBOLIC_LINK_FLAG_DIRECTORY; + else + flags = uv__file_symlink_usermode_flag; + + if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) { + SET_REQ_RESULT(req, 0); + return; + } + + /* Something went wrong. We will test if it is because of user-mode + * symlinks. + */ + err = GetLastError(); + if (err == ERROR_INVALID_PARAMETER && + flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) { + /* This system does not support user-mode symlinks. We will clear the + * unsupported flag and retry. + */ + uv__file_symlink_usermode_flag = 0; + fs__symlink(req); + } else { + SET_REQ_WIN32_ERROR(req, err); } } @@ -1855,6 +1907,7 @@ static void uv__fs_work(struct uv__work* w) { XX(CLOSE, close) XX(READ, read) XX(WRITE, write) + XX(COPYFILE, copyfile) XX(SENDFILE, sendfile) XX(STAT, stat) XX(LSTAT, lstat) @@ -1901,6 +1954,9 @@ static void uv__fs_done(struct uv__work* w, int status) { void uv_fs_req_cleanup(uv_fs_t* req) { + if (req == NULL) + return; + if (req->flags & UV_FS_CLEANEDUP) return; @@ -1931,8 +1987,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_OPEN, cb); - + INIT(UV_FS_OPEN); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -1940,28 +1995,14 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, req->fs.info.file_flags = flags; req->fs.info.mode = mode; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__open(req); - return req->result; - } + POST; } int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_CLOSE, cb); + INIT(UV_FS_CLOSE); req->file.fd = fd; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__close(req); - return req->result; - } + POST; } @@ -1972,11 +2013,11 @@ int uv_fs_read(uv_loop_t* loop, unsigned int nbufs, int64_t offset, uv_fs_cb cb) { + INIT(UV_FS_READ); + if (bufs == NULL || nbufs == 0) return UV_EINVAL; - uv_fs_req_init(loop, req, UV_FS_READ, cb); - req->file.fd = fd; req->fs.info.nbufs = nbufs; @@ -1990,14 +2031,7 @@ int uv_fs_read(uv_loop_t* loop, memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); req->fs.info.offset = offset; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__read(req); - return req->result; - } + POST; } @@ -2008,11 +2042,11 @@ int uv_fs_write(uv_loop_t* loop, unsigned int nbufs, int64_t offset, uv_fs_cb cb) { + INIT(UV_FS_WRITE); + if (bufs == NULL || nbufs == 0) return UV_EINVAL; - uv_fs_req_init(loop, req, UV_FS_WRITE, cb); - req->file.fd = fd; req->fs.info.nbufs = nbufs; @@ -2026,14 +2060,7 @@ int uv_fs_write(uv_loop_t* loop, memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); req->fs.info.offset = offset; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__write(req); - return req->result; - } + POST; } @@ -2041,20 +2068,13 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_UNLINK, cb); - + INIT(UV_FS_UNLINK); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__unlink(req); - return req->result; - } + POST; } @@ -2062,22 +2082,14 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_MKDIR, cb); - + INIT(UV_FS_MKDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } req->fs.info.mode = mode; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__mkdir(req); - return req->result; - } + POST; } @@ -2085,39 +2097,25 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb); - + INIT(UV_FS_MKDTEMP); err = fs__capture_path(req, tpl, NULL, TRUE); if (err) return uv_translate_sys_error(err); - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__mkdtemp(req); - return req->result; - } + POST; } int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_RMDIR, cb); - + INIT(UV_FS_RMDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__rmdir(req); - return req->result; - } + POST; } @@ -2125,22 +2123,14 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb); - + INIT(UV_FS_SCANDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } req->fs.info.file_flags = flags; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__scandir(req); - return req->result; - } + POST; } @@ -2148,20 +2138,13 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_LINK, cb); - + INIT(UV_FS_LINK); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__link(req); - return req->result; - } + POST; } @@ -2169,22 +2152,14 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb); - + INIT(UV_FS_SYMLINK); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { return uv_translate_sys_error(err); } req->fs.info.file_flags = flags; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__symlink(req); - return req->result; - } + POST; } @@ -2192,20 +2167,13 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_READLINK, cb); - + INIT(UV_FS_READLINK); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__readlink(req); - return req->result; - } + POST; } @@ -2213,24 +2181,18 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - if (!req || !path) { + INIT(UV_FS_REALPATH); + + if (!path) { return UV_EINVAL; } - uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); - err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__realpath(req); - return req->result; - } + POST; } @@ -2238,88 +2200,53 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_CHOWN, cb); - + INIT(UV_FS_CHOWN); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__chown(req); - return req->result; - } + POST; } int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb); - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fchown(req); - return req->result; - } + INIT(UV_FS_FCHOWN); + POST; } int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_STAT, cb); - + INIT(UV_FS_STAT); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__stat(req); - return req->result; - } + POST; } int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_LSTAT, cb); - + INIT(UV_FS_LSTAT); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__lstat(req); - return req->result; - } + POST; } int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FSTAT, cb); + INIT(UV_FS_FSTAT); req->file.fd = fd; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fstat(req); - return req->result; - } + POST; } @@ -2327,85 +2254,70 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_RENAME, cb); - + INIT(UV_FS_RENAME); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__rename(req); - return req->result; - } + POST; } int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FSYNC, cb); + INIT(UV_FS_FSYNC); req->file.fd = fd; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fsync(req); - return req->result; - } + POST; } int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb); + INIT(UV_FS_FDATASYNC); req->file.fd = fd; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fdatasync(req); - return req->result; - } + POST; } int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int64_t offset, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb); - + INIT(UV_FS_FTRUNCATE); req->file.fd = fd; req->fs.info.offset = offset; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__ftruncate(req); - return req->result; - } + POST; } +int uv_fs_copyfile(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_COPYFILE); + + if (flags & ~UV_FS_COPYFILE_EXCL) + return UV_EINVAL; + + err = fs__capture_path(req, path, new_path, cb != NULL); + + if (err) + return uv_translate_sys_error(err); + + req->fs.info.file_flags = flags; + POST; +} + int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb); - + INIT(UV_FS_SENDFILE); req->file.fd = fd_in; req->fs.info.fd_out = fd_out; req->fs.info.offset = in_offset; req->fs.info.bufsml[0].len = length; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__sendfile(req); - return req->result; - } + POST; } @@ -2416,21 +2328,13 @@ int uv_fs_access(uv_loop_t* loop, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_ACCESS, cb); - + INIT(UV_FS_ACCESS); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) return uv_translate_sys_error(err); req->fs.info.mode = flags; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } - - fs__access(req); - return req->result; + POST; } @@ -2438,39 +2342,23 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_CHMOD, cb); - + INIT(UV_FS_CHMOD); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); } req->fs.info.mode = mode; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__chmod(req); - return req->result; - } + POST; } int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb); - + INIT(UV_FS_FCHMOD); req->file.fd = fd; req->fs.info.mode = mode; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fchmod(req); - return req->result; - } + POST; } @@ -2478,8 +2366,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_UTIME, cb); - + INIT(UV_FS_UTIME); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2487,30 +2374,15 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, req->fs.time.atime = atime; req->fs.time.mtime = mtime; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__utime(req); - return req->result; - } + POST; } int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, double mtime, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FUTIME, cb); - + INIT(UV_FS_FUTIME); req->file.fd = fd; req->fs.time.atime = atime; req->fs.time.mtime = mtime; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__futime(req); - return req->result; - } + POST; } diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 9b10cc9fe2..5c666788fd 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -1913,6 +1913,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { if (os_handle == INVALID_HANDLE_VALUE) return UV_EBADF; + uv__once_init(); /* In order to avoid closing a stdio file descriptor 0-2, duplicate the * underlying OS handle and forget about the original fd. * We could also opt to use the original OS handle and just never close it, @@ -1986,6 +1987,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) unsigned int name_len; int err; + uv__once_init(); name_info = NULL; if (handle->handle == INVALID_HANDLE_VALUE) { diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index d141601607..97b67ca529 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -405,8 +405,15 @@ static WCHAR* search_path(const WCHAR *file, /* Next slice starts just after where the previous one ended */ dir_start = dir_end; + /* If path is quoted, find quote end */ + if (*dir_start == L'"' || *dir_start == L'\'') { + dir_end = wcschr(dir_start + 1, *dir_start); + if (dir_end == NULL) { + dir_end = wcschr(dir_start, L'\0'); + } + } /* Slice until the next ; or \0 is found */ - dir_end = wcschr(dir_start, L';'); + dir_end = wcschr(dir_end, L';'); if (dir_end == NULL) { dir_end = wcschr(dir_start, L'\0'); } diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 972539f4df..e63a63e771 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -1446,6 +1446,8 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { WSAPROTOCOL_INFOW protocol_info; int opt_len; int err; + struct sockaddr_storage saddr; + int saddr_len; /* Detect the address family of the socket. */ opt_len = (int) sizeof protocol_info; @@ -1466,6 +1468,19 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { return uv_translate_sys_error(err); } + /* Support already active socket. */ + saddr_len = sizeof(saddr); + if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) { + /* Socket is already bound. */ + handle->flags |= UV_HANDLE_BOUND; + saddr_len = sizeof(saddr); + if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) { + /* Socket is already connected. */ + uv_connection_init((uv_stream_t*) handle); + handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + } + return 0; } diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index a6f583956f..c4f99bdc79 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -148,6 +148,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { HANDLE handle; CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; + uv__once_init(); handle = (HANDLE) uv__get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) return UV_EBADF; diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 9401676fbd..6c699bfe17 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4104,6 +4104,10 @@ # define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 #endif +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002 +#endif + /* from winternl.h */ typedef struct _UNICODE_STRING { USHORT Length; |