From 94b0481a5661e8d34955a33b50bfbbfe46e93469 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 6 Sep 2011 16:14:14 +0200 Subject: [PATCH] uv: upgrade to cc91989 --- deps/uv/include/uv-private/uv-win.h | 5 +- deps/uv/src/unix/core.c | 6 +- deps/uv/src/unix/fs.c | 26 ++++- deps/uv/src/win/process.c | 133 ++++++++++++++++-------- deps/uv/test/test-fs.c | 155 ++++++++++++++++++++++++++++ deps/uv/test/test-list.h | 6 +- 6 files changed, 278 insertions(+), 53 deletions(-) diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 01acc01f7f..8be0c8a452 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -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; \ diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 4d713c295b..45fef16b62 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -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'; diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 506367cdee..85cfbfba4e 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -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 } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 25b0576ad6..31d40b52cc 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -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; diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index c3712def71..b1c9886182 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -43,6 +43,14 @@ # 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; +} diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 9d4a57f694..0c74310530 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -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)