uv: upgrade to cc91989
authorBen Noordhuis <info@bnoordhuis.nl>
Tue, 6 Sep 2011 14:14:14 +0000 (16:14 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Tue, 6 Sep 2011 14:14:14 +0000 (16:14 +0200)
deps/uv/include/uv-private/uv-win.h
deps/uv/src/unix/core.c
deps/uv/src/unix/fs.c
deps/uv/src/win/process.c
deps/uv/test/test-fs.c
deps/uv/test/test-list.h

index 01acc01..8be0c8a 100644 (file)
@@ -235,10 +235,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   struct uv_process_close_s {             \
     UV_REQ_FIELDS                         \
   } close_req;                            \
-  struct uv_process_stdio_s {             \
-    uv_pipe_t* server_pipe;               \
-    HANDLE child_pipe;                    \
-  } stdio_pipes[3];                       \
+  HANDLE child_stdio[3];                  \
   int exit_signal;                        \
   DWORD spawn_errno;                      \
   HANDLE wait_handle;                     \
index 4d713c2..45fef16 100644 (file)
@@ -764,10 +764,8 @@ size_t uv__strlcpy(char* dst, const char* src, size_t size) {
   }
 
   org = src;
-  while (size > 1) {
-    if ((*dst++ = *src++) == '\0') {
-      return org - src;
-    }
+  while (--size && *src) {
+    *dst++ = *src++;
   }
   *dst = '\0';
 
index 506367c..85cfbfb 100644 (file)
@@ -472,10 +472,34 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
 }
 
 
+#if defined(HAVE_FUTIMES)
+static int _futime(const uv_file file, double atime, double mtime) {
+  struct timeval tv[2];
+
+  /* FIXME possible loss of precision in floating-point arithmetic? */
+  tv[0].tv_sec = atime;
+  tv[0].tv_usec = (unsigned long)(atime * 1000000) % 1000000;
+
+  tv[1].tv_sec = mtime;
+  tv[1].tv_usec = (unsigned long)(mtime * 1000000) % 1000000;
+
+  return futimes(file, tv);
+}
+#endif
+
+
 int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
     double mtime, uv_fs_cb cb) {
-  assert(0 && "implement me");
+  const char* path = NULL;
+
+  uv_fs_req_init(loop, req, UV_FS_FUTIME, path, cb);
+
+#if defined(HAVE_FUTIMES)
+  WRAP_EIO(UV_FS_FUTIME, eio_futime, _futime, ARGS3(file, atime, mtime))
+#else
+  uv_err_new(loop, ENOSYS);
   return -1;
+#endif
 }
 
 
index 25b0576..31d40b5 100644 (file)
@@ -61,12 +61,9 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
   handle->wait_handle = INVALID_HANDLE_VALUE;
   handle->process_handle = INVALID_HANDLE_VALUE;
   handle->close_handle = INVALID_HANDLE_VALUE;
-  handle->stdio_pipes[0].server_pipe = NULL;
-  handle->stdio_pipes[0].child_pipe = INVALID_HANDLE_VALUE;
-  handle->stdio_pipes[1].server_pipe = NULL;
-  handle->stdio_pipes[1].child_pipe = INVALID_HANDLE_VALUE;
-  handle->stdio_pipes[2].server_pipe = NULL;
-  handle->stdio_pipes[2].child_pipe = INVALID_HANDLE_VALUE;
+  handle->child_stdio[0] = INVALID_HANDLE_VALUE;
+  handle->child_stdio[1] = INVALID_HANDLE_VALUE;
+  handle->child_stdio[2] = INVALID_HANDLE_VALUE;
 
   uv_req_init(loop, (uv_req_t*)&handle->exit_req);
   handle->exit_req.type = UV_PROCESS_EXIT;
@@ -625,7 +622,7 @@ static DWORD WINAPI spawn_failure(void* data) {
   char unknown[] = "unknown error\n";
   uv_process_t* process = (uv_process_t*) data;
   uv_loop_t* loop = process->loop;
-  HANDLE child_stderr = process->stdio_pipes[2].child_pipe;
+  HANDLE child_stderr = process->child_stdio[2];
   char* buf = NULL;
   DWORD count, written;
 
@@ -657,18 +654,23 @@ static DWORD WINAPI spawn_failure(void* data) {
 }
 
 
-/* Called on main thread after a child process has exited. */
-void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
+static void close_child_stdio(uv_process_t* process) {
   int i;
-  DWORD exit_code;
+  HANDLE handle;
 
-  /* Close stdio handles. */
-  for (i = 0; i < COUNTOF(handle->stdio_pipes); i++) {
-    if (handle->stdio_pipes[i].child_pipe != INVALID_HANDLE_VALUE) {
-      CloseHandle(handle->stdio_pipes[i].child_pipe);
-      handle->stdio_pipes[i].child_pipe = INVALID_HANDLE_VALUE;
+  for (i = 0; i < COUNTOF(process->child_stdio); i++) {
+    handle = process->child_stdio[i];
+    if (handle != NULL && handle != INVALID_HANDLE_VALUE) {
+      CloseHandle(handle);
+      process->child_stdio[i] = INVALID_HANDLE_VALUE;
     }
   }
+}
+
+
+/* Called on main thread after a child process has exited. */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
+  DWORD exit_code;
 
   /* Unregister from process notification. */
   if (handle->wait_handle != INVALID_HANDLE_VALUE) {
@@ -686,6 +688,10 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
     CloseHandle(handle->process_handle);
     handle->process_handle = INVALID_HANDLE_VALUE;
   } else {
+    /* We probably left the child stdio handles open to report the error */
+    /* asynchronously, so close them now. */
+    close_child_stdio(handle);
+
     /* The process never even started in the first place. */
     exit_code = 127;
   }
@@ -805,13 +811,45 @@ done:
 }
 
 
+static int duplicate_std_handle(uv_loop_t* loop, DWORD id, HANDLE* dup) {
+  HANDLE handle;
+  HANDLE current_process = GetCurrentProcess();
+  
+  handle = GetStdHandle(id);
+
+  if (handle == NULL) {
+    *dup = NULL;
+    return 0;
+  } else if (handle == INVALID_HANDLE_VALUE) {
+    *dup = INVALID_HANDLE_VALUE;
+    uv_set_sys_error(loop, GetLastError());
+    return -1;
+  }
+
+  if (!DuplicateHandle(current_process,
+                       handle,
+                       current_process,
+                       dup,
+                       0,
+                       TRUE,
+                       DUPLICATE_SAME_ACCESS)) {
+    *dup = INVALID_HANDLE_VALUE;
+    uv_set_sys_error(loop, GetLastError());
+    return -1;
+  }
+
+  return 0;
+}
+
+
 int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     uv_process_options_t options) {
-  int err = 0, i;
+  int err = 0, keep_child_stdio_open = 0;
   wchar_t* path;
   int size;
   BOOL result;
   wchar_t* application_path, *application, *arguments, *env, *cwd;
+  HANDLE* child_stdio = process->child_stdio;
   STARTUPINFOW startup;
   PROCESS_INFORMATION info;
 
@@ -864,41 +902,41 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     err = uv_create_stdio_pipe_pair(
         loop,
         options.stdin_stream,
-        &process->stdio_pipes[0].child_pipe,
+        &child_stdio[0],
         PIPE_ACCESS_OUTBOUND,
         GENERIC_READ | FILE_WRITE_ATTRIBUTES);
-    if (err) {
-      goto done;
-    }
-
-    process->stdio_pipes[0].server_pipe = options.stdin_stream;
+  } else {
+    err = duplicate_std_handle(loop, STD_INPUT_HANDLE, &child_stdio[0]);
+  }
+  if (err) {
+    goto done;
   }
 
   if (options.stdout_stream) {
     err = uv_create_stdio_pipe_pair(
         loop, options.stdout_stream,
-        &process->stdio_pipes[1].child_pipe,
+        &child_stdio[1],
         PIPE_ACCESS_INBOUND,
         GENERIC_WRITE);
-    if (err) {
-      goto done;
-    }
-
-    process->stdio_pipes[1].server_pipe = options.stdout_stream;
+  } else {
+    err = duplicate_std_handle(loop, STD_OUTPUT_HANDLE, &child_stdio[1]);
+  }
+  if (err) {
+    goto done;
   }
 
   if (options.stderr_stream) {
     err = uv_create_stdio_pipe_pair(
         loop,
         options.stderr_stream,
-        &process->stdio_pipes[2].child_pipe,
+        &child_stdio[2],
         PIPE_ACCESS_INBOUND,
         GENERIC_WRITE);
-    if (err) {
-      goto done;
-    }
-
-    process->stdio_pipes[2].server_pipe = options.stderr_stream;
+  } else {
+    err = duplicate_std_handle(loop, STD_ERROR_HANDLE, &child_stdio[2]);
+  }
+  if (err) {
+    goto done;
   }
 
   startup.cb = sizeof(startup);
@@ -908,9 +946,9 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
   startup.dwFlags = STARTF_USESTDHANDLES;
   startup.cbReserved2 = 0;
   startup.lpReserved2 = NULL;
-  startup.hStdInput = process->stdio_pipes[0].child_pipe;
-  startup.hStdOutput = process->stdio_pipes[1].child_pipe;
-  startup.hStdError = process->stdio_pipes[2].child_pipe;
+  startup.hStdInput = child_stdio[0];
+  startup.hStdOutput = child_stdio[1];
+  startup.hStdError = child_stdio[2];
 
   if (CreateProcessW(application_path,
                      arguments,
@@ -942,6 +980,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     /* succeeded, and start a thread instead that prints an error */
     /* to the child's intended stderr. */
     process->spawn_errno = GetLastError();
+    keep_child_stdio_open = 1;
     if (!QueueUserWorkItem(spawn_failure, process, WT_EXECUTEDEFAULT)) {
       uv_fatal_error(GetLastError(), "QueueUserWorkItem");
     }
@@ -957,14 +996,22 @@ done:
   free(env);
   free(path);
 
-  if (err) {
-    for (i = 0; i < COUNTOF(process->stdio_pipes); i++) {
-      if (process->stdio_pipes[i].child_pipe != INVALID_HANDLE_VALUE) {
-        CloseHandle(process->stdio_pipes[i].child_pipe);
-        process->stdio_pipes[i].child_pipe = INVALID_HANDLE_VALUE;
-      }
+  /* Under normal circumstances we should close the stdio handles now - */
+  /* the child now has its own duplicates, or something went horribly wrong. */
+  /* The only exception is when CreateProcess has failed, then we actually */
+  /* need to keep the stdio handles to report the error asynchronously. */
+  if (!keep_child_stdio_open) {
+    close_child_stdio(process);
+  } else {
+    /* We're keeping the handles open, the thread pool is going to have */
+    /* it's way with them. But at least make them noninheritable. */
+    int i;
+    for (i = 0; i < COUNTOF(process->child_stdio); i++) {
+      SetHandleInformation(child_stdio[1], HANDLE_FLAG_INHERIT, 0);
     }
+  }
 
+  if (err) {
     if (process->wait_handle != INVALID_HANDLE_VALUE) {
       UnregisterWait(process->wait_handle);
       process->wait_handle = INVALID_HANDLE_VALUE;
index c3712de..b1c9886 100644 (file)
 # define close _close
 #endif
 
+
+typedef struct {
+  const char* path;
+  double atime;
+  double mtime;
+} utime_check_t;
+
+
 static int close_cb_count;
 static int create_cb_count;
 static int open_cb_count;
@@ -66,6 +74,8 @@ static int fchown_cb_count;
 static int link_cb_count;
 static int symlink_cb_count;
 static int readlink_cb_count;
+static int utime_cb_count;
+static int futime_cb_count;
 
 static uv_loop_t* loop;
 
@@ -84,6 +94,8 @@ static uv_fs_t fsync_req;
 static uv_fs_t fdatasync_req;
 static uv_fs_t ftruncate_req;
 static uv_fs_t sendfile_req;
+static uv_fs_t utime_req;
+static uv_fs_t futime_req;
 
 static char buf[32];
 static char test_buf[] = "test-buffer\n";
@@ -395,6 +407,61 @@ TEST_IMPL(fs_file_noent) {
 }
 
 
+static void check_utime(const char* path, double atime, double mtime) {
+  struct stat* s;
+  uv_fs_t req;
+  int r;
+
+  r = uv_fs_stat(loop, &req, path, NULL);
+  ASSERT(r == 0);
+
+  ASSERT(req.result == 0);
+  s = req.ptr;
+
+#if _WIN32
+  ASSERT(s->st_atime == atime);
+  ASSERT(s->st_mtime == mtime);
+#else
+  ASSERT(s->st_atim.tv_sec  == atime);
+  ASSERT(s->st_atim.tv_nsec == 0); /* FIXME check sub-second precision */
+  ASSERT(s->st_mtim.tv_sec  == mtime);
+  ASSERT(s->st_mtim.tv_nsec == 0); /* FIXME check sub-second precision */
+#endif
+
+  uv_fs_req_cleanup(&req);
+}
+
+
+static void utime_cb(uv_fs_t* req) {
+  utime_check_t* c;
+
+  ASSERT(req == &utime_req);
+  ASSERT(req->result == 0);
+  ASSERT(req->fs_type == UV_FS_UTIME);
+
+  c = req->data;
+  check_utime(c->path, c->atime, c->mtime);
+
+  uv_fs_req_cleanup(req);
+  utime_cb_count++;
+}
+
+
+static void futime_cb(uv_fs_t* req) {
+  utime_check_t* c;
+
+  ASSERT(req == &futime_req);
+  ASSERT(req->result == 0);
+  ASSERT(req->fs_type == UV_FS_FUTIME);
+
+  c = req->data;
+  check_utime(c->path, c->atime, c->mtime);
+
+  uv_fs_req_cleanup(req);
+  futime_cb_count++;
+}
+
+
 TEST_IMPL(fs_file_async) {
   int r;
 
@@ -1103,3 +1170,91 @@ TEST_IMPL(fs_symlink) {
 
   return 0;
 }
+
+
+TEST_IMPL(fs_utime) {
+  utime_check_t checkme;
+  const char* path = ".";
+  double atime;
+  double mtime;
+  uv_fs_t req;
+  int r;
+
+  uv_init();
+  loop = uv_default_loop();
+
+  atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
+
+  r = uv_fs_utime(loop, &req, path, atime, mtime, NULL);
+  ASSERT(r == 0);
+  ASSERT(utime_req.result == 0);
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_stat(loop, &req, path, NULL);
+  ASSERT(r == 0);
+  ASSERT(req.result == 0);
+  check_utime(path, atime, mtime);
+  uv_fs_req_cleanup(&req);
+
+  atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
+  checkme.path = path;
+  checkme.atime = atime;
+  checkme.mtime = mtime;
+
+  /* async utime */
+  utime_req.data = &checkme;
+  r = uv_fs_utime(loop, &utime_req, path, atime, mtime, utime_cb);
+  ASSERT(r == 0);
+  uv_run(loop);
+  ASSERT(utime_cb_count == 1);
+
+  return 0;
+}
+
+
+TEST_IMPL(fs_futime) {
+  utime_check_t checkme;
+  const char* path = ".";
+  double atime;
+  double mtime;
+  uv_file file;
+  uv_fs_t req;
+  int r;
+
+  uv_init();
+  loop = uv_default_loop();
+
+  atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
+
+  r = uv_fs_open(loop, &req, path, O_RDONLY, 0, NULL);
+  ASSERT(r == 0);
+  ASSERT(req.result != -1);
+  file = req.result; /* FIXME probably not how it's supposed to be used */
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_futime(loop, &req, file, atime, mtime, NULL);
+  ASSERT(r == 0);
+  ASSERT(req.result == 0);
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_stat(loop, &req, path, NULL);
+  ASSERT(r == 0);
+  ASSERT(req.result == 0);
+  check_utime(path, atime, mtime);
+  uv_fs_req_cleanup(&req);
+
+  atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
+
+  checkme.atime = atime;
+  checkme.mtime = mtime;
+  checkme.path = path;
+
+  /* async futime */
+  futime_req.data = &checkme;
+  r = uv_fs_futime(loop, &futime_req, file, atime, mtime, futime_cb);
+  ASSERT(r == 0);
+  uv_run(loop);
+  ASSERT(futime_cb_count == 1);
+
+  return 0;
+}
index 9d4a57f..0c74310 100644 (file)
@@ -82,6 +82,8 @@ TEST_DECLARE   (fs_chmod)
 TEST_DECLARE   (fs_chown)
 TEST_DECLARE   (fs_link)
 TEST_DECLARE   (fs_symlink)
+TEST_DECLARE   (fs_utime)
+TEST_DECLARE   (fs_futime)
 TEST_DECLARE   (threadpool_queue_work_simple)
 #ifdef _WIN32
 TEST_DECLARE   (spawn_detect_pipe_name_collisions_on_windows)
@@ -189,7 +191,9 @@ TASK_LIST_START
   TEST_ENTRY  (fs_fstat)
   TEST_ENTRY  (fs_chmod)
   TEST_ENTRY  (fs_chown)
-  TEST_ENTRY  (fs_link)
+  TEST_ENTRY  (fs_utime)
+  TEST_ENTRY  (fs_futime)
+  TEST_ENTRY  (fs_symlink)
   TEST_ENTRY  (fs_symlink)
 
   TEST_ENTRY  (threadpool_queue_work_simple)