瀏覽代碼

Merge topic 'update-libuv'

2628eb7460 libuv: Add proctitle and threadpool cleanup stubs to cmake-bootstrap.c
efdd451f4b Merge branch 'upstream-libuv' into update-libuv
d355f401d7 libuv 2020-04-29 (e7ebae26)

Acked-by: Kitware Robot <[email protected]>
Merge-request: !4687
Brad King 5 年之前
父節點
當前提交
9683d2bd20
共有 32 個文件被更改,包括 842 次插入377 次删除
  1. 22 7
      Utilities/cmlibuv/include/uv.h
  2. 2 2
      Utilities/cmlibuv/include/uv/version.h
  3. 2 2
      Utilities/cmlibuv/src/threadpool.c
  4. 1 6
      Utilities/cmlibuv/src/timer.c
  5. 1 1
      Utilities/cmlibuv/src/unix/aix.c
  6. 23 10
      Utilities/cmlibuv/src/unix/async.c
  7. 2 0
      Utilities/cmlibuv/src/unix/atomic-ops.h
  8. 7 0
      Utilities/cmlibuv/src/unix/bsd-proctitle.c
  9. 6 0
      Utilities/cmlibuv/src/unix/cmake-bootstrap.c
  10. 4 3
      Utilities/cmlibuv/src/unix/core.c
  11. 1 2
      Utilities/cmlibuv/src/unix/darwin-proctitle.c
  12. 97 0
      Utilities/cmlibuv/src/unix/darwin-stub.h
  13. 73 20
      Utilities/cmlibuv/src/unix/fs.c
  14. 25 29
      Utilities/cmlibuv/src/unix/fsevents.c
  15. 0 2
      Utilities/cmlibuv/src/unix/internal.h
  16. 11 9
      Utilities/cmlibuv/src/unix/linux-core.c
  17. 3 0
      Utilities/cmlibuv/src/unix/no-proctitle.c
  18. 1 1
      Utilities/cmlibuv/src/unix/proctitle.c
  19. 2 2
      Utilities/cmlibuv/src/unix/signal.c
  20. 14 27
      Utilities/cmlibuv/src/unix/udp.c
  21. 46 0
      Utilities/cmlibuv/src/uv-common.c
  22. 10 0
      Utilities/cmlibuv/src/uv-common.h
  23. 6 6
      Utilities/cmlibuv/src/win/core.c
  24. 1 0
      Utilities/cmlibuv/src/win/error.c
  25. 26 7
      Utilities/cmlibuv/src/win/fs-event.c
  26. 231 48
      Utilities/cmlibuv/src/win/fs.c
  27. 62 121
      Utilities/cmlibuv/src/win/poll.c
  28. 4 5
      Utilities/cmlibuv/src/win/process.c
  29. 5 0
      Utilities/cmlibuv/src/win/signal.c
  30. 4 16
      Utilities/cmlibuv/src/win/udp.c
  31. 143 51
      Utilities/cmlibuv/src/win/util.c
  32. 7 0
      Utilities/cmlibuv/src/win/winapi.h

+ 22 - 7
Utilities/cmlibuv/include/uv.h

@@ -269,6 +269,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,
@@ -614,7 +616,12 @@ enum uv_udp_flags {
    * 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
+  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);
@@ -1081,11 +1088,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 {
@@ -1292,7 +1299,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 {
@@ -1317,6 +1325,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*);
@@ -1465,6 +1474,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,

+ 2 - 2
Utilities/cmlibuv/include/uv/version.h

@@ -26,12 +26,12 @@
  * 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 35
+#define UV_VERSION_MINOR 37
 #define UV_VERSION_PATCH 1
 #define UV_VERSION_IS_RELEASE 0
 #define UV_VERSION_SUFFIX "dev"

+ 2 - 2
Utilities/cmlibuv/src/threadpool.c

@@ -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) {

+ 1 - 6
Utilities/cmlibuv/src/timer.c

@@ -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;
 }
 
 

+ 1 - 1
Utilities/cmlibuv/src/unix/aix.c

@@ -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;
 }

+ 23 - 10
Utilities/cmlibuv/src/unix/async.c

@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sched.h>  /* sched_yield() */
 
 #ifdef __linux__
 #include <sys/eventfd.h>
@@ -81,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);
-
-    if (rc != 1)
-      return rc;
-
-    /* Other thread is busy with this handle, spin until it's done. */
-    cpu_relax();
+    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;
+
+      /* 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();
   }
 }
 

+ 2 - 0
Utilities/cmlibuv/src/unix/atomic-ops.h

@@ -59,6 +59,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
 }
 

+ 7 - 0
Utilities/cmlibuv/src/unix/bsd-proctitle.c

@@ -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;

+ 6 - 0
Utilities/cmlibuv/src/unix/cmake-bootstrap.c

@@ -1,6 +1,12 @@
 #include "uv.h"
 #include "internal.h"
 
+void uv__process_title_cleanup(void) {
+}
+
+void uv__threadpool_cleanup(void) {
+}
+
 int uv__tcp_nodelay(int fd, int on) {
   errno = EINVAL;
   return -1;

+ 4 - 3
Utilities/cmlibuv/src/unix/core.c

@@ -74,7 +74,7 @@ extern char** environ;
 # include <sys/wait.h>
 # include <sys/param.h>
 # include <sys/cpuset.h>
-# if defined(__FreeBSD__) || defined(__linux__)
+# if defined(__FreeBSD__)
 #  define uv__accept4 accept4
 # endif
 # if defined(__NetBSD__)
@@ -91,7 +91,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);
@@ -1260,7 +1261,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++) {

+ 1 - 2
Utilities/cmlibuv/src/unix/darwin-proctitle.c

@@ -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 - 0
Utilities/cmlibuv/src/unix/darwin-stub.h

@@ -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_ */

+ 73 - 20
Utilities/cmlibuv/src/unix/fs.c

@@ -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
@@ -982,10 +992,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__)                                                 \
@@ -994,10 +1002,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)
@@ -1020,6 +1026,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;
@@ -1089,9 +1120,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;
@@ -1190,7 +1222,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);
 
@@ -1533,6 +1568,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));
@@ -1719,6 +1755,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);
@@ -2047,3 +2096,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;
+}

+ 25 - 29
Utilities/cmlibuv/src/unix/fsevents.c

@@ -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>
-
-/* These are macros to avoid "initializer element is not constant" errors
- * with old versions of gcc.
- */
-#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod |         \
-                           kFSEventStreamEventFlagItemModified |              \
-                           kFSEventStreamEventFlagItemInodeMetaMod |          \
-                           kFSEventStreamEventFlagItemChangeOwner |           \
-                           kFSEventStreamEventFlagItemXattrMod)
-
-#define kFSEventsRenamed  (kFSEventStreamEventFlagItemCreated |               \
-                           kFSEventStreamEventFlagItemRemoved |               \
-                           kFSEventStreamEventFlagItemRenamed)
-
-#define kFSEventsSystem   (kFSEventStreamEventFlagUserDropped |               \
-                           kFSEventStreamEventFlagKernelDropped |             \
-                           kFSEventStreamEventFlagEventIdsWrapped |           \
-                           kFSEventStreamEventFlagHistoryDone |               \
-                           kFSEventStreamEventFlagMount |                     \
-                           kFSEventStreamEventFlagUnmount |                   \
-                           kFSEventStreamEventFlagRootChanged)
+static const int kFSEventsModified =
+    kFSEventStreamEventFlagItemChangeOwner |
+    kFSEventStreamEventFlagItemFinderInfoMod |
+    kFSEventStreamEventFlagItemInodeMetaMod |
+    kFSEventStreamEventFlagItemModified |
+    kFSEventStreamEventFlagItemXattrMod;
+
+static const int kFSEventsRenamed =
+    kFSEventStreamEventFlagItemCreated |
+    kFSEventStreamEventFlagItemRemoved |
+    kFSEventStreamEventFlagItemRenamed;
+
+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;
 

+ 0 - 2
Utilities/cmlibuv/src/unix/internal.h

@@ -116,10 +116,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
 

+ 11 - 9
Utilities/cmlibuv/src/unix/linux-core.c

@@ -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);

+ 3 - 0
Utilities/cmlibuv/src/unix/no-proctitle.c

@@ -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;
 }

+ 1 - 1
Utilities/cmlibuv/src/unix/proctitle.c

@@ -145,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;
 }

+ 2 - 2
Utilities/cmlibuv/src/unix/signal.c

@@ -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();

+ 14 - 27
Utilities/cmlibuv/src/unix/udp.c

@@ -202,6 +202,9 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
     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
@@ -262,11 +265,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
     assert(buf.base != NULL);
 
 #if HAVE_MMSG
-    uv_once(&once, uv__udp_mmsg_init);
-    if (uv__recvmmsg_avail) {
-      /* Returned space for more than 1 datagram, use it to receive
-       * multiple datagrams. */
-      if (buf.len >= 2 * UV__UDP_DGRAM_MAXSIZE) {
+    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;
@@ -946,26 +947,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);
@@ -981,11 +973,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;
 

+ 46 - 0
Utilities/cmlibuv/src/uv-common.c

@@ -294,6 +294,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) {
@@ -823,3 +853,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;
+}

+ 10 - 0
Utilities/cmlibuv/src/uv-common.h

@@ -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)
 

+ 6 - 6
Utilities/cmlibuv/src/win/core.c

@@ -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++) {

+ 1 - 0
Utilities/cmlibuv/src/win/error.c

@@ -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;

+ 26 - 7
Utilities/cmlibuv/src/win/fs-event.c

@@ -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);
 }
 

+ 231 - 48
Utilities/cmlibuv/src/win/fs.c

@@ -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;
+    ret = GetLastError();
+  } else if (fs__utime_handle(handle, atime, mtime) != 0) {
+    ret = GetLastError();
+  } else {
+    ret = 0;
   }
 
-  if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
-    SET_REQ_WIN32_ERROR(req, GetLastError());
-    CloseHandle(handle);
+  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;
   }
 
-  CloseHandle(handle);
-
   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_;
+}

+ 62 - 121
Utilities/cmlibuv/src/win/poll.c

@@ -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);
-  }
+  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 (err) {
-    return uv_translate_sys_error(err);
+  if (handle->events == 0) {
+    uv__handle_stop(handle);
+    return 0;
   }
 
-  handle->poll_cb = cb;
+  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_stop(uv_poll_t* handle) {
-  int err;
+int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
+  return uv__poll_set(handle, events, cb);
+}
 
-  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);
+int uv_poll_stop(uv_poll_t* handle) {
+  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;
 }
 
 

+ 4 - 5
Utilities/cmlibuv/src/win/process.c

@@ -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;

+ 5 - 0
Utilities/cmlibuv/src/win/signal.c

@@ -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. */

+ 4 - 16
Utilities/cmlibuv/src/win/udp.c

@@ -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);

+ 143 - 51
Utilities/cmlibuv/src/win/util.c

@@ -60,9 +60,6 @@
 #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);
 
@@ -154,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. */
@@ -191,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;
   }
@@ -206,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());
   }
@@ -216,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
@@ -284,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;
 }
 
@@ -361,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;
@@ -1163,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());
+  }
+  /* 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());
-  } else if (len > ARRAY_SIZE(path)) {
-    /* This should not be possible */
-    return UV_EIO;
   }
 
   /* The returned directory should not have a trailing slash, unless it points
@@ -1191,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;
   }
@@ -1206,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());
@@ -1325,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;
 
@@ -1336,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);
-  if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
+  bufsize = 0;
+  GetUserProfileDirectoryW(token, NULL, &bufsize);
+  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
     r = GetLastError();
     CloseHandle(token);
+    return uv_translate_sys_error(r);
+  }
 
-    /* This should not be possible */
-    if (r == ERROR_INSUFFICIENT_BUFFER)
-      return UV_ENOMEM;
+  path = uv__malloc(bufsize * sizeof(wchar_t));
+  if (path == NULL) {
+    CloseHandle(token);
+    return UV_ENOMEM;
+  }
 
+  if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
+    r = GetLastError();
+    CloseHandle(token);
+    uv__free(path);
     return uv_translate_sys_error(r);
   }
 
@@ -1354,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)
@@ -1364,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;
@@ -1405,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;
   }
@@ -1461,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;
@@ -1475,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 */
@@ -1506,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;
 }
 
 

+ 7 - 0
Utilities/cmlibuv/src/win/winapi.h

@@ -4160,6 +4160,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
@@ -4525,6 +4529,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,