diff --git a/deps/uv/.gitignore b/deps/uv/.gitignore index 1eaaca8406e957..86a8a5b7b8584d 100644 --- a/deps/uv/.gitignore +++ b/deps/uv/.gitignore @@ -65,6 +65,9 @@ ipch # sphinx generated files /docs/build/ +# Clion / IntelliJ project files +/.idea/ + *.xcodeproj *.xcworkspace diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 0a152ba8dbb0c4..7a51588c0b7188 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -8,9 +8,11 @@ Brian White Brian White Caleb James DeLisle Christoph Iserlohn +Devchandra Meetei Leishangthem Fedor Indutny Frank Denis Isaac Z. Schlueter +Jason Williams Justin Venus Keno Fischer Keno Fischer @@ -18,6 +20,9 @@ Leith Bade Leonard Hecker Maciej Małecki Marc Schlaich +Michael +Michael Neumann +Nicholas Vavilov Rasmus Christian Pedersen Rasmus Christian Pedersen Robert Mustacchi @@ -25,6 +30,7 @@ Ryan Dahl Ryan Emery Sam Roberts San-Tai Hsu +Santiago Gimeno Saúl Ibarra Corretgé Shigeki Ohtsu Timothy J. Fontaine diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 8dc3955cad5bf3..9a9e9c2a2204b8 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -240,3 +240,16 @@ Yuval Brik Joran Dirk Greef Andrey Mazo sztomi +Martin Bark +Dave +Alexis Murzeau +Didiet +Nan Xiang <514580344@qq.com> +Samuel Lorétan +Nándor István Krácser +Katsutoshi Horie +Lukasz Jagiello +Robert Chiras +Kári Tristan Helgason +Krishnaraj Bhat +Enno Boland diff --git a/deps/uv/CONTRIBUTING.md b/deps/uv/CONTRIBUTING.md index b46edd492aab47..ef5c2b2feaae9f 100644 --- a/deps/uv/CONTRIBUTING.md +++ b/deps/uv/CONTRIBUTING.md @@ -23,8 +23,7 @@ The stable branch is effectively frozen; patches that change the libuv API/ABI or affect the run-time behavior of applications get rejected. In case of doubt, open an issue in the [issue tracker][], post your question -to the [libuv mailing list], or contact one of project maintainers -(@bnoordhuis, @piscisaureus, @indutny or @saghul) on [IRC][]. +to the [libuv mailing list], or contact one of [project maintainers][] on [IRC][]. Especially do so if you plan to work on something big. Nothing is more frustrating than seeing your hard work go to waste because your vision @@ -138,7 +137,10 @@ $ git rebase upstream/v1.x # or upstream/master ### TEST Bug fixes and features should come with tests. Add your tests in the -`test/` directory. Tests also need to be registered in `test/test-list.h`. +`test/` directory. Each new test needs to be registered in `test/test-list.h`. If you add a new test file, it needs to be registered in two places: +- `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list. +- `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target. + Look at other tests to see how they should be structured (license boilerplate, the way entry points are declared, etc.). @@ -164,3 +166,4 @@ not send out notifications when you add commits. [libuv mailing list]: http://groups.google.com/group/libuv [IRC]: http://webchat.freelibuv.net/?channels=libuv [Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml +[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index af0743af72c8db..85d40113e4f052 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,142 @@ +2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 + +Changes since version 1.8.0: + +* win: wait for full timeout duration (João Reis) + +* unix: fix support for uClibc-ng (Martin Bark) + +* doc: indicate where new test files need to be added (Dave) + +* test,unix: fix logic error in test runner (Ben Noordhuis) + +* fs: don't nullify req->bufs on EINTR (Dave) + +* osx: set the default thread stack size to RLIMIT_STACK (Saúl Ibarra Corretgé) + +* build: invoke libtoolize with --copy (Ben Noordhuis) + +* test: fixup eintr_handling (Saúl Ibarra Corretgé) + +* osx: avoid compilation warning with Clang (Saúl Ibarra Corretgé) + +* test,win: fix compilation with shared lib (Alexis Murzeau) + +* test: fix race condition in pipe-close-stdout (Imran Iqbal) + +* unix,win: add uv_os_tmpdir() (cjihrig) + +* ios: fix undefined PTHREAD_STACK_MIN (Didiet) + +* test: fix threadpool_multiple_event_loops for AIX (Imran Iqbal) + +* unix: report errors for unpollable fds (Ben Noordhuis) + +* win: fix watching root files (Nicholas Vavilov) + +* build,win: print the Visual Studio version in use (Saúl Ibarra Corretgé) + +* build,win: remove unneeded condition from GYP file (Saúl Ibarra Corretgé) + +* test,win: fix compilation warning (Saúl Ibarra Corretgé) + +* test: use uv_loop_close and assert its result (Nan Xiang) + +* build: map 'AMD64' host arch to 'x64' (Ben Noordhuis) + +* osx: protected use of potentially undefined macro (Samuel Lorétan) + +* linux: fix compilation with musl (Saúl Ibarra Corretgé) + +* doc: describe how to make release builds on Unix (Saúl Ibarra Corretgé) + +* doc: add missing link in README (Saúl Ibarra Corretgé) + +* build: python 2.x/3.x consistent print usage (Rasmus Christian Pedersen) + +* test: assume no IPv6 if interfaces cannot be listed (Nan Xiang) + +* darwin: replace F_FULLFSYNC with fdatasync syscall (Saúl Ibarra Corretgé) + +* doc: add missing write callback to example (Nándor István Krácser) + +* build: compile with -D_THREAD_SAFE on AIX (Imran Iqbal) + +* test: fix threadpool_multiple_event_loops on PPC (Imran Iqbal) + +* test: reduce timeout in tcp_close_while_connecting (Imran Iqbal) + +* unix, win: consistently null-terminate buffers (Saúl Ibarra Corretgé) + +* unix, win: count null byte on UV_ENOBUFS (Saúl Ibarra Corretgé) + +* test: fix deadlocks in uv_cond_wait (Katsutoshi Horie) + +* linux: fix cpu count (Lukasz Jagiello) + +* unix: fix uv__handle_type for AIX (Imran Iqbal) + +* linux: call fclose(), fix fdopen() memory leak (Ben Noordhuis) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* unix: fix compile error in Android using bionic (Robert Chiras) + +* linux: add braces to multi-statement if (Kári Tristan Helgason) + +* doc: add @cjihrig as a maintainer (Saúl Ibarra Corretgé) + +* unix: add fork-safe open file function (Kári Tristan Helgason) + +* linux: replace calls to fopen with uv__open_file (Kári Tristan Helgason) + +* linux: remove redundant call to rewind() (Krishnaraj Bhat) + +* win: remove duplicated code when processing fsevents (Saúl Ibarra Corretgé) + +* test: fix poll_bad_fdtype for AIX (Imran Iqbal) + +* linux: fix error checking in uv__open_file (Saúl Ibarra Corretgé) + +* poll: add UV_DISCONNECT event (Santiago Gimeno) + +* fs: realpath: fix string size before converting (Yuval Brik) + +* win: use native APIs for UTF conversions (cjihrig) + +* doc: clarify uv_loop_close() (Ben Noordhuis) + +* unix: retry ioctl(TIOCGWINSZ) on EINTR (Ben Noordhuis) + +* win,build: remove unused build defines (Saúl Ibarra Corretgé) + +* win: fix buffer overflow in fs events (Joran Dirk Greef) + +* win: fix uv_relative_path and remove dead branch (Joran Dirk Greef) + +* unix: use open(2) with O_CLOEXEC on OS X (Kári Tristan Helgason) + +* test: add missing copyright header (cjihrig) + +* aix: fix 'POLLRDHUP undeclared' build error (Ben Noordhuis) + +* unix,win: add uv_get_passwd() (cjihrig) + +* process: fix uv_spawn edge-case (Santiago Gimeno) + +* test: use %ld for printing uid/gid (Ben Noordhuis) + +* aix: fix ahafs implementation (Imran Iqbal) + +* aix: do not store absolute path to ahafs (Imran Iqbal) + +* process: close process pipes safely (Santiago Gimeno) + +* unix: open ttyname instead of /dev/tty (Enno Boland) + +* unix: remove outdated comment (Kári Tristan Helgason) + + 2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4 Changes since version 1.7.5: diff --git a/deps/uv/MAINTAINERS.md b/deps/uv/MAINTAINERS.md index 4db2f5130c060d..2f0e618ca24149 100644 --- a/deps/uv/MAINTAINERS.md +++ b/deps/uv/MAINTAINERS.md @@ -6,6 +6,7 @@ libuv is currently managed by the following individuals: * **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis)) - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis) * **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus)) +* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 0ef781ff198804..dfd4353a31b649 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -43,7 +43,6 @@ if WINNT include_HEADERS += include/uv-win.h include/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ - -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv libuv_la_SOURCES += src/win/async.c \ @@ -130,6 +129,7 @@ EXTRA_DIST = test/fixtures/empty_file \ TESTS = test/run-tests check_PROGRAMS = test/run-tests test_run_tests_CFLAGS = +test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ test/dns-server.c \ test/echo-server.c \ @@ -151,6 +151,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-default-loop-close.c \ test/test-delayed-accept.c \ test/test-dlerror.c \ + test/test-eintr-handling.c \ test/test-embed.c \ test/test-emfile.c \ test/test-error.c \ @@ -161,6 +162,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-get-currentexe.c \ test/test-get-loadavg.c \ test/test-get-memory.c \ + test/test-get-passwd.c \ test/test-getaddrinfo.c \ test/test-getnameinfo.c \ test/test-getsockname.c \ @@ -242,6 +244,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-timer-again.c \ test/test-timer-from-check.c \ test/test-timer.c \ + test/test-tmpdir.c \ test/test-tty.c \ test/test-udp-bind.c \ test/test-udp-create-socket-early.c \ @@ -280,7 +283,7 @@ endif if AIX -libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT +libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT -D_THREAD_SAFE include_HEADERS += include/uv-aix.h libuv_la_SOURCES += src/unix/aix.c endif @@ -301,15 +304,18 @@ libuv_la_SOURCES += src/unix/darwin.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ src/unix/proctitle.c +test_run_tests_LDFLAGS += -lutil endif if DRAGONFLY include_HEADERS += include/uv-bsd.h +test_run_tests_LDFLAGS += -lutil endif if FREEBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c +test_run_tests_LDFLAGS += -lutil endif if LINUX @@ -320,16 +326,19 @@ libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/linux-syscalls.c \ src/unix/linux-syscalls.h \ src/unix/proctitle.c +test_run_tests_LDFLAGS += -lutil endif if NETBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c +test_run_tests_LDFLAGS += -lutil endif if OPENBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c +test_run_tests_LDFLAGS += -lutil endif if SUNOS diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw index 156f15dab159f1..3130bac473d30c 100644 --- a/deps/uv/Makefile.mingw +++ b/deps/uv/Makefile.mingw @@ -20,7 +20,6 @@ CFLAGS += -Wall \ -Iinclude \ -Isrc \ -Isrc/win \ - -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 INCLUDES = include/stdint-msvc2008.h \ diff --git a/deps/uv/README.md b/deps/uv/README.md index dfd24ba79d1850..17304a7ab57125 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -156,11 +156,16 @@ project tree manually: ### Unix -Run: +For Debug builds (recommended) run: $ ./gyp_uv.py -f make $ make -C out +For Release builds run: + + $ ./gyp_uv.py -f make + $ BUILDTYPE=Release make -C out + Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. ### OS X @@ -243,3 +248,4 @@ See the [guidelines for contributing][]. [Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express [guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md [libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png +[x32]: https://en.wikipedia.org/wiki/X32_ABI diff --git a/deps/uv/appveyor.yml b/deps/uv/appveyor.yml index 9aa63c5a5d2e73..835730b924c8ff 100644 --- a/deps/uv/appveyor.yml +++ b/deps/uv/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.8.0.build{build} +version: v1.9.0.build{build} install: - cinst -y nsis diff --git a/deps/uv/autogen.sh b/deps/uv/autogen.sh index 0574778a4e1040..271c2ee8c33c44 100755 --- a/deps/uv/autogen.sh +++ b/deps/uv/autogen.sh @@ -40,7 +40,7 @@ echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \ > m4/libuv-extra-automake-flags.m4 set -ex -"$LIBTOOLIZE" +"$LIBTOOLIZE" --copy "$ACLOCAL" -I m4 "$AUTOCONF" "$AUTOMAKE" --add-missing --copy diff --git a/deps/uv/checksparse.sh b/deps/uv/checksparse.sh index 619cf6f8b672d8..68e3bde39305da 100755 --- a/deps/uv/checksparse.sh +++ b/deps/uv/checksparse.sh @@ -101,6 +101,7 @@ test/test-fs.c test/test-get-currentexe.c test/test-get-loadavg.c test/test-get-memory.c +test/test-get-passwd.c test/test-getaddrinfo.c test/test-getsockname.c test/test-homedir.c @@ -155,6 +156,7 @@ test/test-threadpool-cancel.c test/test-threadpool.c test/test-timer-again.c test/test-timer.c +test/test-tmpdir.c test/test-tty.c test/test-udp-dgram-too-big.c test/test-udp-ipv6.c diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 011bee2a891e73..2d5a3b9de5eb6d 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.8.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.9.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst index 2a01d796375e8e..1f504cb391f169 100644 --- a/deps/uv/docs/src/loop.rst +++ b/deps/uv/docs/src/loop.rst @@ -71,9 +71,10 @@ API .. c:function:: int uv_loop_close(uv_loop_t* loop) - Closes all internal loop resources. This function must only be called once - the loop has finished its execution or it will return UV_EBUSY. After this - function returns the user shall free the memory allocated for the loop. + Releases all internal loop resources. Call this function only when the loop + has finished executing and all open handles and requests have been closed, + or it will return UV_EBUSY. After this function returns, the user can free + the memory allocated for the loop. .. c:function:: uv_loop_t* uv_default_loop(void) diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 2ce0887db0c278..f32af48ff9e92d 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -122,6 +122,20 @@ Data types } netmask; } uv_interface_address_t; +.. c:type:: uv_passwd_t + + Data type for password file information. + + :: + + typedef struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; + } uv_passwd_t; + API --- @@ -265,14 +279,50 @@ API `uv_os_homedir()` first checks the `HOME` environment variable using :man:`getenv(3)`. If `HOME` is not set, :man:`getpwuid_r(3)` is called. The user's home directory is stored in `buffer`. When `uv_os_homedir()` is - called, `size` indicates the maximum size of `buffer`. On success or - `UV_ENOBUFS` failure, `size` is set to the string length of `buffer`. + called, `size` indicates the maximum size of `buffer`. On success `size` is set + to the string length of `buffer`. On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. .. warning:: `uv_os_homedir()` is not thread safe. .. versionadded:: 1.6.0 +.. c:function:: int uv_os_tmpdir(char* buffer, size_t* size) + + Gets the temp directory. On Windows, `uv_os_tmpdir()` uses `GetTempPathW()`. + On all other operating systems, `uv_os_tmpdir()` uses the first environment + variable found in the ordered list `TMPDIR`, `TMP`, `TEMP`, and `TEMPDIR`. + If none of these are found, the path `"/tmp"` is used, or, on Android, + `"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When + `uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`. + On success `size` is set to the string length of `buffer` (which does not + include the terminating null). On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. + + .. warning:: + `uv_os_tmpdir()` is not thread safe. + + .. versionadded:: 1.9.0 + +.. c:function:: int uv_os_get_passwd(uv_passwd_t* pwd) + + Gets a subset of the password file entry for the current effective uid (not + the real uid). The populated data includes the username, euid, gid, shell, + and home directory. On non-Windows systems, all data comes from + :man:`getpwuid_r(3)`. On Windows, uid and gid are set to -1 and have no + meaning, and shell is `NULL`. After successfully calling this function, the + memory allocated to `pwd` needs to be freed with + :c:func:`uv_os_free_passwd`. + + .. versionadded:: 1.9.0 + +.. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd) + + Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`. + + .. versionadded:: 1.9.0 + .. uint64_t uv_get_free_memory(void) .. c:function:: uint64_t uv_get_total_memory(void) diff --git a/deps/uv/docs/src/poll.rst b/deps/uv/docs/src/poll.rst index 6dc41839ac1e92..69d45be6d32b29 100644 --- a/deps/uv/docs/src/poll.rst +++ b/deps/uv/docs/src/poll.rst @@ -4,8 +4,8 @@ :c:type:`uv_poll_t` --- Poll handle =================================== -Poll handles are used to watch file descriptors for readability and -writability, similar to the purpose of :man:`poll(2)`. +Poll handles are used to watch file descriptors for readability, +writability and disconnection similar to the purpose of :man:`poll(2)`. The purpose of poll handles is to enable integrating external libraries that rely on the event loop to signal it about the socket status changes, like @@ -51,7 +51,8 @@ Data types enum uv_poll_event { UV_READABLE = 1, - UV_WRITABLE = 2 + UV_WRITABLE = 2, + UV_DISCONNECT = 4 }; @@ -82,10 +83,14 @@ API .. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) Starts polling the file descriptor. `events` is a bitmask consisting made up - of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback - will be called with `status` set to 0, and the detected events set on the + of UV_READABLE, UV_WRITABLE and UV_DISCONNECT. As soon as an event is detected + the callback will be called with `status` set to 0, and the detected events set on the `events` field. + The UV_DISCONNECT event is optional in the sense that it may not be + reported and the user is free to ignore it, but it can help optimize the shutdown + path because an extra read or write call might be avoided. + If an error happens while polling, `status` will be < 0 and corresponds with one of the UV_E* error codes (see :ref:`errors`). The user should not close the socket while the handle is active. If the user does that @@ -96,6 +101,8 @@ API Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so will update the events mask that is being watched for. + .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. + .. c:function:: int uv_poll_stop(uv_poll_t* poll) Stop polling the file descriptor, the callback will no longer be called. diff --git a/deps/uv/docs/src/stream.rst b/deps/uv/docs/src/stream.rst index 9f0aacd16435d0..ed0c79d0045616 100644 --- a/deps/uv/docs/src/stream.rst +++ b/deps/uv/docs/src/stream.rst @@ -148,6 +148,10 @@ API :: + void cb(uv_write_t* req, int status) { + /* Logic which handles the write result */ + } + uv_buf_t a[] = { { .base = "1", .len = 1 }, { .base = "2", .len = 1 } @@ -162,8 +166,8 @@ API uv_write_t req2; /* writes "1234" */ - uv_write(&req1, stream, a, 2); - uv_write(&req2, stream, b, 2); + uv_write(&req1, stream, a, 2, cb); + uv_write(&req2, stream, b, 2, cb); .. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb) diff --git a/deps/uv/docs/src/tty.rst b/deps/uv/docs/src/tty.rst index 655dca9ca20641..01a0585287affc 100644 --- a/deps/uv/docs/src/tty.rst +++ b/deps/uv/docs/src/tty.rst @@ -58,14 +58,22 @@ API `readable`, specifies if you plan on calling :c:func:`uv_read_start` with this stream. stdin is readable, stdout is not. - On Unix this function will try to open ``/dev/tty`` and use it if the passed - file descriptor refers to a TTY. This lets libuv put the tty in non-blocking - mode without affecting other processes that share the tty. + On Unix this function will determine the path of the fd of the terminal + using :man:`ttyname_r(3)`, open it, and use it if the passed file descriptor + refers to a TTY. This lets libuv put the tty in non-blocking mode without + affecting other processes that share the tty. + + This function is not thread safe on systems that don't support + ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris. .. note:: - If opening ``/dev/tty`` fails, libuv falls back to blocking writes for + If reopening the TTY fails, libuv falls back to blocking writes for non-readable TTY streams. + .. versionchanged:: 1.9.0: the path of the TTY is determined by + :man:`ttyname_r(3)`. In earlier versions libuv opened + `/dev/tty` instead. + .. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file descriptor that refers to a file returns `UV_EINVAL` on UNIX. diff --git a/deps/uv/gyp_uv.py b/deps/uv/gyp_uv.py index 39933f624d5c40..bd37d95c4713f6 100755 --- a/deps/uv/gyp_uv.py +++ b/deps/uv/gyp_uv.py @@ -27,6 +27,7 @@ def host_arch(): machine = platform.machine() if machine == 'i386': return 'ia32' + if machine == 'AMD64': return 'x64' if machine == 'x86_64': return 'x64' if machine.startswith('arm'): return 'arm' if machine.startswith('mips'): return 'mips' @@ -36,7 +37,7 @@ def host_arch(): def run_gyp(args): rc = gyp.main(args) if rc != 0: - print 'Error running GYP' + print('Error running GYP') sys.exit(rc) @@ -89,5 +90,5 @@ def run_gyp(args): args.append('--no-parallel') gyp_args = list(args) - print gyp_args + print(gyp_args) run_gyp(gyp_args) diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 6e61f55ed20d85..cb666182892dea 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -31,7 +31,7 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 8 +#define UV_VERSION_MINOR 9 #define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 300be476203ed4..6b537fed0d9019 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -634,11 +634,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); struct uv_req_s signal_req; \ unsigned long pending_signum; -int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, - char* utf8Buffer, size_t utf8Size); -int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, - size_t utf16Size); - #ifndef F_OK #define F_OK 0 #endif diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index dd3111a960e69b..baa0b28124ba59 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -230,6 +230,7 @@ typedef struct uv_work_s uv_work_t; typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; typedef struct uv_dirent_s uv_dirent_t; +typedef struct uv_passwd_s uv_passwd_t; typedef enum { UV_LOOP_BLOCK_SIGNAL @@ -714,7 +715,8 @@ struct uv_poll_s { enum uv_poll_event { UV_READABLE = 1, - UV_WRITABLE = 2 + UV_WRITABLE = 2, + UV_DISCONNECT = 4 }; UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); @@ -1000,6 +1002,14 @@ struct uv_interface_address_s { } netmask; }; +struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; +}; + typedef enum { UV_DIRENT_UNKNOWN, UV_DIRENT_FILE, @@ -1049,6 +1059,9 @@ typedef struct { UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); +UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); +UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); +UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 44d47b88ed22e7..ee73d5a2e6e949 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -138,13 +138,14 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { assert(ctx != NULL); required_len = strlen(ctx->path); - if (required_len > *size) { - *size = required_len; + if (required_len >= *size) { + *size = required_len + 1; return UV_ENOBUFS; } memcpy(buffer, ctx->path, required_len); *size = required_len; + buffer[required_len] = '\0'; return 0; } diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index c90b7e5cb9ba0c..bcaa5ee50bc203 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -91,6 +91,24 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct poll_ctl pc; + + pc.events = POLLIN; + pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */ + pc.fd = fd; + + if (pollset_ctl(loop->backend_fd, &pc, 1)) + return -errno; + + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) + abort(); + + return 0; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct pollfd events[1024]; struct pollfd pqry; @@ -506,7 +524,7 @@ static int uv__makedir_p(const char *dir) { if (*p == '/') { *p = 0; err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if(err != 0) + if (err != 0 && errno != EEXIST) return err; *p = '/'; } @@ -707,59 +725,44 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int int bytes, rc = 0; uv_fs_event_t* handle; int events = 0; - int i = 0; char fname[PATH_MAX]; char *p; handle = container_of(event_watch, uv_fs_event_t, event_watcher); - /* Clean all the buffers*/ - for(i = 0; i < PATH_MAX; i++) { - fname[i] = 0; - } - i = 0; - /* At this point, we assume that polling has been done on the * file descriptor, so we can just read the AHAFS event occurrence * data and parse its results without having to block anything */ bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0); - assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file"); + assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file"); /* Parse the data */ if(bytes > 0) rc = uv__parse_data(result_data, &events, handle); + /* Unrecoverable error */ + if (rc == -1) + return; + /* For directory changes, the name of the files that triggered the change * are never absolute pathnames */ if (uv__path_is_a_directory(handle->path) == 0) { p = handle->dir_filename; - while(*p != NULL){ - fname[i]= *p; - i++; - p++; - } } else { - /* For file changes, figure out whether filename is absolute or not */ - if (handle->path[0] == '/') { - p = strrchr(handle->path, '/'); + p = strrchr(handle->path, '/'); + if (p == NULL) + p = handle->path; + else p++; - - while(*p != NULL) { - fname[i]= *p; - i++; - p++; - } - } } + strncpy(fname, p, sizeof(fname) - 1); + /* Just in case */ + fname[sizeof(fname) - 1] = '\0'; - /* Unrecoverable error */ - if (rc == -1) - return; - else /* Call the actual JavaScript callback function */ - handle->cb(handle, (const char*)&fname, events, 0); + handle->cb(handle, fname, events, 0); } #endif @@ -839,7 +842,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, /* Setup/Initialize all the libuv routines */ uv__handle_start(handle); uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); - handle->path = uv__strdup((const char*)&absolute_path); + handle->path = uv__strdup(filename); handle->cb = cb; uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index cedd86ed34a128..9aaca84187001e 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -53,6 +53,9 @@ # include /* _NSGetExecutablePath */ # include # include +# if defined(O_CLOEXEC) +# define UV__O_CLOEXEC O_CLOEXEC +# endif #endif #if defined(__FreeBSD__) || defined(__DragonFly__) @@ -427,6 +430,22 @@ int uv__socket(int domain, int type, int protocol) { return sockfd; } +/* get a file pointer to a file in read-only and close-on-exec mode */ +FILE* uv__open_file(const char* path) { + int fd; + FILE* fp; + + fd = uv__open_cloexec(path, O_RDONLY); + if (fd < 0) + return NULL; + + fp = fdopen(fd, "r"); + if (fp == NULL) + uv__close(fd); + + return fp; +} + int uv__accept(int sockfd) { int peerfd; @@ -435,7 +454,7 @@ int uv__accept(int sockfd) { assert(sockfd >= 0); while (1) { -#if defined(__linux__) || __FreeBSD__ >= 10 +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) static int no_accept4; if (no_accept4) @@ -479,12 +498,11 @@ int uv__accept(int sockfd) { } -int uv__close(int fd) { +int uv__close_nocheckstdio(int fd) { int saved_errno; int rc; assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ - assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ saved_errno = errno; rc = close(fd); @@ -499,6 +517,12 @@ int uv__close(int fd) { } +int uv__close(int fd) { + assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ + return uv__close_nocheckstdio(fd); +} + + #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ defined(_AIX) || defined(__DragonFly__) @@ -809,7 +833,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -842,7 +866,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); if (w->fd == -1) @@ -874,7 +898,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_close(uv_loop_t* loop, uv__io_t* w) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); + uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ @@ -889,7 +913,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); return 0 != (w->pevents & events); } @@ -930,8 +954,7 @@ int uv__open_cloexec(const char* path, int flags) { int err; int fd; -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) || \ - defined(__DragonFly__) +#if defined(UV__O_CLOEXEC) static int no_cloexec; if (!no_cloexec) { @@ -1014,17 +1037,10 @@ int uv__dup2_cloexec(int oldfd, int newfd) { int uv_os_homedir(char* buffer, size_t* size) { - struct passwd pw; - struct passwd* result; + uv_passwd_t pwd; char* buf; - uid_t uid; - size_t bufsize; size_t len; - long initsize; int r; -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); -#endif if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; @@ -1036,7 +1052,7 @@ int uv_os_homedir(char* buffer, size_t* size) { len = strlen(buf); if (len >= *size) { - *size = len; + *size = len + 1; return -ENOBUFS; } @@ -1046,13 +1062,102 @@ int uv_os_homedir(char* buffer, size_t* size) { return 0; } + /* HOME is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return -ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + const char* buf; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + +#define CHECK_ENV_VAR(name) \ + do { \ + buf = getenv(name); \ + if (buf != NULL) \ + goto return_buffer; \ + } \ + while (0) + + /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ + CHECK_ENV_VAR("TMPDIR"); + CHECK_ENV_VAR("TMP"); + CHECK_ENV_VAR("TEMP"); + CHECK_ENV_VAR("TEMPDIR"); + +#undef CHECK_ENV_VAR + + /* No temp environment variables defined */ + #if defined(__ANDROID__) + buf = "/data/local/tmp"; + #else + buf = "/tmp"; + #endif + +return_buffer: + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + /* The returned directory should not have a trailing slash. */ + if (len > 1 && buf[len - 1] == '/') { + len--; + } + + memcpy(buffer, buf, len + 1); + buffer[len] = '\0'; + *size = len; + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + struct passwd pw; + struct passwd* result; + char* buf; + uid_t uid; + size_t bufsize; + size_t name_size; + size_t homedir_size; + size_t shell_size; + long initsize; + int r; #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); if (getpwuid_r == NULL) return -ENOSYS; #endif - /* HOME is not set, so call getpwuid() */ + if (pwd == NULL) + return -EINVAL; + initsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (initsize <= 0) @@ -1060,7 +1165,7 @@ int uv_os_homedir(char* buffer, size_t* size) { else bufsize = (size_t) initsize; - uid = getuid(); + uid = geteuid(); buf = NULL; for (;;) { @@ -1088,17 +1193,54 @@ int uv_os_homedir(char* buffer, size_t* size) { return -ENOENT; } - len = strlen(pw.pw_dir); + /* Allocate memory for the username, shell, and home directory */ + name_size = strlen(pw.pw_name) + 1; + homedir_size = strlen(pw.pw_dir) + 1; + shell_size = strlen(pw.pw_shell) + 1; + pwd->username = uv__malloc(name_size + homedir_size + shell_size); - if (len >= *size) { - *size = len; + if (pwd->username == NULL) { uv__free(buf); - return -ENOBUFS; + return -ENOMEM; } - memcpy(buffer, pw.pw_dir, len + 1); - *size = len; + /* Copy the username */ + memcpy(pwd->username, pw.pw_name, name_size); + + /* Copy the home directory */ + pwd->homedir = pwd->username + name_size; + memcpy(pwd->homedir, pw.pw_dir, homedir_size); + + /* Copy the shell */ + pwd->shell = pwd->homedir + homedir_size; + memcpy(pwd->shell, pw.pw_shell, shell_size); + + /* Copy the uid and gid */ + pwd->uid = pw.pw_uid; + pwd->gid = pw.pw_gid; + uv__free(buf); return 0; } + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + /* + The memory for name, shell, and homedir are allocated in a single + uv__malloc() call. The base of the pointer is stored in pwd->username, so + that is the field that needs to be freed. + */ + uv__free(pwd->username); + pwd->username = NULL; + pwd->shell = NULL; + pwd->homedir = NULL; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 57b65be25a85ea..8936ad9d837095 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -127,8 +127,8 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { #if defined(__linux__) || defined(__sun) || defined(__NetBSD__) return fdatasync(req->file); -#elif defined(__APPLE__) && defined(F_FULLFSYNC) - return fcntl(req->file, F_FULLFSYNC); +#elif defined(__APPLE__) && defined(SYS_fdatasync) + return syscall(SYS_fdatasync, req->file); #else return fsync(req->file); #endif @@ -749,13 +749,13 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_gen = src->st_gen; #elif defined(__ANDROID__) dst->st_atim.tv_sec = src->st_atime; - dst->st_atim.tv_nsec = src->st_atime_nsec; + dst->st_atim.tv_nsec = src->st_atimensec; dst->st_mtim.tv_sec = src->st_mtime; - dst->st_mtim.tv_nsec = src->st_mtime_nsec; + dst->st_mtim.tv_nsec = src->st_mtimensec; dst->st_ctim.tv_sec = src->st_ctime; - dst->st_ctim.tv_nsec = src->st_ctime_nsec; + dst->st_ctim.tv_nsec = src->st_ctimensec; dst->st_birthtim.tv_sec = src->st_ctime; - dst->st_birthtim.tv_nsec = src->st_ctime_nsec; + dst->st_birthtim.tv_nsec = src->st_ctimensec; dst->st_flags = 0; dst->st_gen = 0; #elif !defined(_AIX) && ( \ @@ -858,9 +858,14 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) total += result; } + if (errno == EINTR && total == -1) + return total; + if (bufs != req->bufsml) uv__free(bufs); + req->bufs = NULL; + req->nbufs = 0; return total; } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 741fa57d69cad3..938e76f1d18d88 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -28,6 +28,7 @@ #include /* abort */ #include /* strrchr */ #include /* O_CLOEXEC, may be */ +#include #if defined(__STRICT_ANSI__) # define inline __inline @@ -89,17 +90,18 @@ #endif #if defined(__linux__) -# define UV__POLLIN UV__EPOLLIN -# define UV__POLLOUT UV__EPOLLOUT -# define UV__POLLERR UV__EPOLLERR -# define UV__POLLHUP UV__EPOLLHUP +# define UV__POLLIN UV__EPOLLIN +# define UV__POLLOUT UV__EPOLLOUT +# define UV__POLLERR UV__EPOLLERR +# define UV__POLLHUP UV__EPOLLHUP +# define UV__POLLRDHUP UV__EPOLLRDHUP #endif #if defined(__sun) || defined(_AIX) -# define UV__POLLIN POLLIN -# define UV__POLLOUT POLLOUT -# define UV__POLLERR POLLERR -# define UV__POLLHUP POLLHUP +# define UV__POLLIN POLLIN +# define UV__POLLOUT POLLOUT +# define UV__POLLERR POLLERR +# define UV__POLLHUP POLLHUP #endif #ifndef UV__POLLIN @@ -118,6 +120,14 @@ # define UV__POLLHUP 8 #endif +#ifndef UV__POLLRDHUP +# ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +# else +# define UV__POLLRDHUP 0x200 +# endif +#endif + #if !defined(O_CLOEXEC) && defined(__FreeBSD__) /* * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. @@ -167,6 +177,7 @@ struct uv__stream_queued_fds_s { /* core */ int uv__nonblock(int fd, int set); int uv__close(int fd); +int uv__close_nocheckstdio(int fd); int uv__cloexec(int fd, int set); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); @@ -180,6 +191,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); void uv__io_close(uv_loop_t* loop, uv__io_t* w); void uv__io_feed(uv_loop_t* loop, uv__io_t* w); int uv__io_active(const uv__io_t* w, unsigned int events); +int uv__io_check_fd(uv_loop_t* loop, int fd); void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ /* async */ @@ -245,6 +257,9 @@ void uv__timer_close(uv_timer_t* handle); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); uv_handle_type uv__handle_type(int fd); +FILE* uv__open_file(const char* path); +int uv__getpwuid_r(uv_passwd_t* pwd); + #if defined(__APPLE__) int uv___stream_fd(const uv_stream_t* handle); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 495f20d285fa30..400b4a4b7c6842 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -48,6 +48,24 @@ int uv__kqueue_init(uv_loop_t* loop) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct kevent ev; + int rc; + + rc = 0; + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + rc = -errno; + + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (rc == 0) + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); + + return rc; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct kevent events[1024]; struct kevent* ev; @@ -241,6 +259,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (ev->flags & EV_ERROR) revents |= UV__POLLERR; + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) + revents |= UV__POLLRDHUP; + if (revents == 0) continue; diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 3ff6fb15e93557..fb8ac3f2379851 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -39,7 +39,7 @@ #define HAVE_IFADDRS_H 1 #ifdef __UCLIBC__ -# if __UCLIBC_MAJOR__ < 0 || __UCLIBC_MINOR__ < 9 || __UCLIBC_SUBLEVEL__ < 32 +# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32 # undef HAVE_IFADDRS_H # endif #endif @@ -52,7 +52,7 @@ # endif # include # include -# include +# include #endif /* HAVE_IFADDRS_H */ /* Available from 2.6.32 onwards. */ @@ -69,7 +69,7 @@ #endif static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); -static int read_times(unsigned int numcpus, uv_cpu_info_t* ci); +static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci); static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static unsigned long read_cpufreq(unsigned int cpunum); @@ -140,6 +140,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event e; + int rc; + + e.events = UV__EPOLLIN; + e.data = -1; + + rc = 0; + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = -errno; + + if (rc == 0) + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + abort(); + + return rc; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes * effectively infinite on 32 bits architectures. To avoid blocking @@ -532,15 +552,42 @@ int uv_uptime(double* uptime) { } +static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { + unsigned int num; + char buf[1024]; + + if (!fgets(buf, sizeof(buf), statfile_fp)) + abort(); + + num = 0; + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (strncmp(buf, "cpu", 3)) + break; + num++; + } + + *numcpus = num; + return 0; +} + + int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int numcpus; uv_cpu_info_t* ci; int err; + FILE* statfile_fp; *cpu_infos = NULL; *count = 0; - numcpus = sysconf(_SC_NPROCESSORS_ONLN); + statfile_fp = uv__open_file("/proc/stat"); + if (statfile_fp == NULL) + return -errno; + + err = uv__cpu_num(statfile_fp, &numcpus); + if (err < 0) + return err; + assert(numcpus != (unsigned int) -1); assert(numcpus != 0); @@ -550,7 +597,11 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { err = read_models(numcpus, ci); if (err == 0) - err = read_times(numcpus, ci); + err = read_times(statfile_fp, numcpus, ci); + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); if (err) { uv_free_cpu_info(ci, numcpus); @@ -608,7 +659,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { defined(__i386__) || \ defined(__mips__) || \ defined(__x86_64__) - fp = fopen("/proc/cpuinfo", "r"); + fp = uv__open_file("/proc/cpuinfo"); if (fp == NULL) return -errno; @@ -676,7 +727,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { } -static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { +static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci) { unsigned long clock_ticks; struct uv_cpu_times_s ts; unsigned long user; @@ -688,22 +739,19 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { unsigned int num; unsigned int len; char buf[1024]; - FILE* fp; clock_ticks = sysconf(_SC_CLK_TCK); assert(clock_ticks != (unsigned long) -1); assert(clock_ticks != 0); - fp = fopen("/proc/stat", "r"); - if (fp == NULL) - return -errno; + rewind(statfile_fp); - if (!fgets(buf, sizeof(buf), fp)) + if (!fgets(buf, sizeof(buf), statfile_fp)) abort(); num = 0; - while (fgets(buf, sizeof(buf), fp)) { + while (fgets(buf, sizeof(buf), statfile_fp)) { if (num >= numcpus) break; @@ -742,7 +790,6 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { ts.irq = clock_ticks * irq; ci[num++].cpu_times = ts; } - fclose(fp); assert(num == numcpus); return 0; @@ -759,7 +806,7 @@ static unsigned long read_cpufreq(unsigned int cpunum) { "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", cpunum); - fp = fopen(buf, "r"); + fp = uv__open_file(buf); if (fp == NULL) return 0; diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 96e79439cf07ab..4260df111f3ae4 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -76,6 +76,7 @@ #define UV__EPOLLOUT 4 #define UV__EPOLLERR 8 #define UV__EPOLLHUP 16 +#define UV__EPOLLRDHUP 0x2000 #define UV__EPOLLONESHOT 0x40000000 #define UV__EPOLLET 0x80000000 diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 7f87a713bf40fe..d4fdfa9d5a5480 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -200,9 +200,6 @@ void uv_pipe_connect(uv_connect_t* req, if (err) uv__io_feed(handle->loop, &handle->io_watcher); - /* Mimic the Windows pipe implementation, always - * return 0 and let the callback handle errors. - */ } @@ -234,14 +231,18 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, addrlen = strlen(sa.sun_path); - if (addrlen > *size) { - *size = addrlen; + if (addrlen >= *size) { + *size = addrlen + 1; return UV_ENOBUFS; } memcpy(buffer, sa.sun_path, addrlen); *size = addrlen; + /* only null-terminate if it's not an abstract socket */ + if (buffer[0] != '\0') + buffer[addrlen] = '\0'; + return 0; } diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 37da3b95851b07..e5efb17160ff95 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -34,7 +34,7 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); if (events & UV__POLLERR) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); + uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); handle->poll_cb(handle, -EBADF, 0); return; @@ -45,6 +45,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { pevents |= UV_READABLE; if (events & UV__POLLOUT) pevents |= UV_WRITABLE; + if (events & UV__POLLRDHUP) + pevents |= UV_DISCONNECT; handle->poll_cb(handle, 0, pevents); } @@ -53,6 +55,10 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { int err; + err = uv__io_check_fd(loop, fd); + if (err) + return err; + err = uv__nonblock(fd, 1); if (err) return err; @@ -71,7 +77,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); + uv__io_stop(handle->loop, + &handle->io_watcher, + UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); } @@ -86,7 +94,7 @@ int uv_poll_stop(uv_poll_t* handle) { int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int events; - assert((pevents & ~(UV_READABLE | UV_WRITABLE)) == 0); + assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); uv__poll_stop(handle); @@ -99,6 +107,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events |= UV__POLLIN; if (pevents & UV_WRITABLE) events |= UV__POLLOUT; + if (pevents & UV_DISCONNECT) + events |= UV__POLLRDHUP; uv__io_start(handle->loop, &handle->io_watcher, events); uv__handle_start(handle); diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 571f8cd778c74f..ef10a3422dc518 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -498,7 +498,7 @@ int uv_spawn(uv_loop_t* loop, } else abort(); - uv__close(signal_pipe[0]); + uv__close_nocheckstdio(signal_pipe[0]); for (i = 0; i < options->stdio_count; i++) { err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); @@ -530,9 +530,9 @@ int uv_spawn(uv_loop_t* loop, if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) continue; if (pipes[i][0] != -1) - close(pipes[i][0]); + uv__close_nocheckstdio(pipes[i][0]); if (pipes[i][1] != -1) - close(pipes[i][1]); + uv__close_nocheckstdio(pipes[i][1]); } uv__free(pipes); } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 7d7ab2633b6f2d..9043664dfcaf9a 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -946,13 +946,14 @@ static void uv__write_callbacks(uv_stream_t* stream) { uv_handle_type uv__handle_type(int fd) { struct sockaddr_storage ss; + socklen_t sslen; socklen_t len; int type; memset(&ss, 0, sizeof(ss)); - len = sizeof(ss); + sslen = sizeof(ss); - if (getsockname(fd, (struct sockaddr*)&ss, &len)) + if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) return UV_UNKNOWN_HANDLE; len = sizeof type; @@ -961,6 +962,14 @@ uv_handle_type uv__handle_type(int fd) { return UV_UNKNOWN_HANDLE; if (type == SOCK_STREAM) { +#if defined(_AIX) + /* on AIX the getsockname call returns an empty sa structure + * for sockets of type AF_UNIX. For all other types it will + * return a properly filled in structure. + */ + if (sslen == 0) + return UV_NAMED_PIPE; +#endif switch (ss.ss_family) { case AF_UNIX: return UV_NAMED_PIPE; @@ -1082,6 +1091,11 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { } +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-folding-constant" +#endif + static void uv__read(uv_stream_t* stream) { uv_buf_t buf; ssize_t nread; @@ -1187,6 +1201,10 @@ static void uv__read(uv_stream_t* stream) { } +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + #undef UV__CMSG_FD_COUNT #undef UV__CMSG_FD_SIZE diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 0c46817b446e61..9a6cc42b5bf3fd 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -116,6 +116,17 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) + return -errno; + + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + abort(); + + return 0; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct port_event events[1024]; struct port_event* pe; diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index c56a3170259e90..c35bc926bf0fac 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -27,6 +27,9 @@ #include #include +#include /* getrlimit() */ + +#include #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) @@ -55,6 +58,11 @@ static void* uv__thread_start(void *arg) int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { struct thread_ctx* ctx; int err; + pthread_attr_t* attr; +#if defined(__APPLE__) + pthread_attr_t attr_storage; + struct rlimit lim; +#endif ctx = uv__malloc(sizeof(*ctx)); if (ctx == NULL) @@ -63,7 +71,30 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { ctx->entry = entry; ctx->arg = arg; - err = pthread_create(tid, NULL, uv__thread_start, ctx); + /* On OSX threads other than the main thread are created with a reduced stack + * size by default, adjust it to RLIMIT_STACK. + */ +#if defined(__APPLE__) + if (getrlimit(RLIMIT_STACK, &lim)) + abort(); + + attr = &attr_storage; + if (pthread_attr_init(attr)) + abort(); + + if (lim.rlim_cur != RLIM_INFINITY && + lim.rlim_cur >= PTHREAD_STACK_MIN) { + if (pthread_attr_setstacksize(attr, lim.rlim_cur)) + abort(); + } +#else + attr = NULL; +#endif + + err = pthread_create(tid, attr, uv__thread_start, ctx); + + if (attr != NULL) + pthread_attr_destroy(attr); if (err) uv__free(ctx); diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 7cc5b714ed302c..32fa37eac96307 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -23,6 +23,7 @@ #include "internal.h" #include "spinlock.h" +#include #include #include #include @@ -33,12 +34,30 @@ static int orig_termios_fd = -1; static struct termios orig_termios; static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; +static int uv__tty_is_slave(const int fd) { + int result; +#if defined(__linux__) || defined(__FreeBSD__) + int dummy; + + result = ioctl(fd, TIOCGPTN, &dummy) != 0; +#elif defined(__APPLE__) + char dummy[256]; + + result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#else + /* Fallback to ptsname + */ + result = ptsname(fd) == NULL; +#endif + return result; +} int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { uv_handle_type type; int flags; int newfd; int r; + char path[256]; /* File descriptors that refer to files cannot be monitored with epoll. * That restriction also applies to character devices like /dev/random @@ -62,7 +81,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * other processes. */ if (type == UV_TTY) { - r = uv__open_cloexec("/dev/tty", O_RDWR); + /* Reopening a pty in master mode won't work either because the reopened + * pty will be in slave mode (*BSD) or reopening will allocate a new + * master/slave pair (Linux). Therefore check if the fd points to a + * slave device. + */ + if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) + r = uv__open_cloexec(path, O_RDWR); + else + r = -1; if (r < 0) { /* fallback to using blocking writes */ @@ -185,8 +212,13 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { struct winsize ws; + int err; + + do + err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws); + while (err == -1 && errno == EINTR); - if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws)) + if (err == -1) return -errno; *width = ws.ws_col; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 40ed28fec5a662..6b8c584fbe75b1 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -451,13 +451,14 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { } required_len = strlen(handle->path); - if (required_len > *size) { - *size = required_len; + if (required_len >= *size) { + *size = required_len + 1; return UV_ENOBUFS; } memcpy(buffer, handle->path, required_len); *size = required_len; + buffer[required_len] = '\0'; return 0; } diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index de0483e1023017..ba306ebc083fbb 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -256,30 +256,48 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) { ULONG_PTR key; OVERLAPPED* overlapped; uv_req_t* req; + int repeat; + uint64_t timeout_time; - GetQueuedCompletionStatus(loop->iocp, - &bytes, - &key, - &overlapped, - timeout); + timeout_time = loop->time + timeout; - if (overlapped) { - /* Package was dequeued */ - req = uv_overlapped_to_req(overlapped); - uv_insert_pending_req(loop, req); + for (repeat = 0; ; repeat++) { + GetQueuedCompletionStatus(loop->iocp, + &bytes, + &key, + &overlapped, + timeout); - /* Some time might have passed waiting for I/O, - * so update the loop time here. - */ - uv_update_time(loop); - } else if (GetLastError() != WAIT_TIMEOUT) { - /* Serious error */ - uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); - } else if (timeout > 0) { - /* GetQueuedCompletionStatus can occasionally return a little early. - * Make sure that the desired timeout is reflected in the loop time. - */ - uv__time_forward(loop, timeout); + if (overlapped) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlapped); + uv_insert_pending_req(loop, req); + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; } } @@ -290,33 +308,51 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; - - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); - - if (success) { - for (i = 0; i < count; i++) { - /* Package was dequeued */ - req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); - uv_insert_pending_req(loop, req); + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + uv_insert_pending_req(loop, req); + } + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } } - - /* Some time might have passed waiting for I/O, - * so update the loop time here. - */ - uv_update_time(loop); - } else if (GetLastError() != WAIT_TIMEOUT) { - /* Serious error */ - uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); - } else if (timeout > 0) { - /* GetQueuedCompletionStatus can occasionally return a little early. - * Make sure that the desired timeout is reflected in the loop time. - */ - uv__time_forward(loop, timeout); + break; } } diff --git a/deps/uv/src/win/dl.c b/deps/uv/src/win/dl.c index e5f3407f8eb27e..39e400ab2dbd19 100644 --- a/deps/uv/src/win/dl.c +++ b/deps/uv/src/win/dl.c @@ -31,7 +31,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) { lib->handle = NULL; lib->errmsg = NULL; - if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + filename, + -1, + filename_w, + ARRAY_SIZE(filename_w))) { return uv__dlerror(lib, GetLastError()); } diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 76ecfebaa24c39..77c935a2d8c8fe 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -63,19 +63,19 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, handle->req_pending = 1; } -static int uv_relative_path(const WCHAR* filename, - const WCHAR* dir, - WCHAR** relpath) { - int dirlen = wcslen(dir); - int filelen = wcslen(filename); - if (dir[dirlen - 1] == '\\') +static void uv_relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { + size_t dirlen = wcslen(dir); + if (dirlen > 0 && dir[dirlen - 1] == '\\') dirlen--; - *relpath = uv__malloc((MAX_PATH + 1) * sizeof(WCHAR)); + size_t filenamelen = wcslen(filename); + size_t relpathlen = filenamelen - dirlen - 1; + *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); if (!*relpath) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - wcsncpy(*relpath, filename + dirlen + 1, filelen - dirlen - 1); - (*relpath)[filelen - dirlen - 1] = L'\0'; - return 0; + wcsncpy(*relpath, filename + dirlen + 1, relpathlen); + (*relpath)[relpathlen] = L'\0'; } static int uv_split_path(const WCHAR* filename, WCHAR** dir, @@ -101,12 +101,12 @@ static int uv_split_path(const WCHAR* filename, WCHAR** dir, *file = wcsdup(filename); } else { if (dir) { - *dir = (WCHAR*)uv__malloc((i + 1) * sizeof(WCHAR)); + *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR)); if (!*dir) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - wcsncpy(*dir, filename, i); - (*dir)[i] = L'\0'; + wcsncpy(*dir, filename, i + 1); + (*dir)[i + 1] = L'\0'; } *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR)); @@ -159,14 +159,20 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__handle_start(handle); /* Convert name to UTF16. */ - name_size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(WCHAR); + + name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * + sizeof(WCHAR); pathw = (WCHAR*)uv__malloc(name_size); if (!pathw) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!uv_utf8_to_utf16(path, pathw, - name_size / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + pathw, + name_size / sizeof(WCHAR))) { return uv_translate_sys_error(GetLastError()); } @@ -340,7 +346,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle) { FILE_NOTIFY_INFORMATION* file_info; - int err, sizew, size, result; + int err, sizew, size; char* filename = NULL; WCHAR* filenamew, *long_filenamew = NULL; DWORD offset = 0; @@ -425,39 +431,23 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (long_filenamew) { /* Get the file name out of the long path. */ - result = uv_relative_path(long_filenamew, - handle->dirw, - &filenamew); + uv_relative_path(long_filenamew, + handle->dirw, + &filenamew); uv__free(long_filenamew); - - if (result == 0) { - long_filenamew = filenamew; - sizew = -1; - } else { - long_filenamew = NULL; - } - } - - /* - * We could not resolve the long form explicitly. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { - filenamew = file_info->FileName; - sizew = file_info->FileNameLength / sizeof(WCHAR); - } - } else { - /* - * Removed or renamed events cannot be resolved to the long form. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { - filenamew = file_info->FileName; - sizew = file_info->FileNameLength / sizeof(WCHAR); + long_filenamew = filenamew; + sizew = -1; } } + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + if (!long_filenamew) { + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } } else { /* We already have the long name of the file, so just use it. */ filenamew = handle->filew; @@ -466,20 +456,28 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (filenamew) { /* Convert the filename to utf8. */ - size = uv_utf16_to_utf8(filenamew, - sizew, - NULL, - 0); + size = WideCharToMultiByte(CP_UTF8, + 0, + filenamew, + sizew, + NULL, + 0, + NULL, + NULL); if (size) { filename = (char*)uv__malloc(size + 1); if (!filename) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - size = uv_utf16_to_utf8(filenamew, - sizew, - filename, - size); + size = WideCharToMultiByte(CP_UTF8, + 0, + filenamew, + sizew, + filename, + size, + NULL, + NULL); if (size) { filename[size] = '\0'; } else { diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index a32b0127f7e1e9..16e3ae7cf1b416 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -1717,25 +1717,26 @@ static void fs__readlink(uv_fs_t* req) { static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { int r; DWORD w_realpath_len; - WCHAR* w_realpath_ptr; - WCHAR* w_finalpath_ptr = NULL; + WCHAR* w_realpath_ptr = NULL; + WCHAR* w_realpath_buf; w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); if (w_realpath_len == 0) { return -1; } - w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); - if (w_realpath_ptr == NULL) { + w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_buf == NULL) { SetLastError(ERROR_OUTOFMEMORY); return -1; } + w_realpath_ptr = w_realpath_buf; if (pGetFinalPathNameByHandleW(handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) { - uv__free(w_realpath_ptr); + uv__free(w_realpath_buf); SetLastError(ERROR_INVALID_HANDLE); return -1; } @@ -1744,20 +1745,22 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { if (wcsncmp(w_realpath_ptr, UNC_PATH_PREFIX, UNC_PATH_PREFIX_LEN) == 0) { - w_finalpath_ptr = w_realpath_ptr + 6; - *w_finalpath_ptr = L'\\'; + w_realpath_ptr += 6; + *w_realpath_ptr = L'\\'; + w_realpath_len -= 6; } else if (wcsncmp(w_realpath_ptr, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0) { - w_finalpath_ptr = w_realpath_ptr + 4; + w_realpath_ptr += 4; + w_realpath_len -= 4; } else { - uv__free(w_realpath_ptr); + uv__free(w_realpath_buf); SetLastError(ERROR_INVALID_HANDLE); return -1; } - r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL); - uv__free(w_realpath_ptr); + r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_buf); return r; } diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index ceed3b7638b457..744f8e02629ccd 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -126,7 +126,14 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); if (addrinfow_ptr->ai_canonname != NULL) { - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); if (name_len == 0) { req->retcode = uv_translate_sys_error(GetLastError()); goto complete; @@ -170,16 +177,24 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { /* convert canonical name to UTF-8 */ if (addrinfow_ptr->ai_canonname != NULL) { - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, - -1, - NULL, - 0); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); assert(name_len > 0); assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); - name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, - -1, - cur_ptr, - name_len); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + name_len, + NULL, + NULL); assert(name_len > 0); addrinfo_ptr->ai_canonname = cur_ptr; cur_ptr += ALIGNED_SIZE(name_len); @@ -261,7 +276,8 @@ int uv_getaddrinfo(uv_loop_t* loop, /* calculate required memory size for all input values */ if (node != NULL) { - nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR)); + nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * + sizeof(WCHAR)); if (nodesize == 0) { err = GetLastError(); goto error; @@ -269,7 +285,12 @@ int uv_getaddrinfo(uv_loop_t* loop, } if (service != NULL) { - servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * + servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + NULL, + 0) * sizeof(WCHAR)); if (servicesize == 0) { err = GetLastError(); @@ -294,9 +315,12 @@ int uv_getaddrinfo(uv_loop_t* loop, /* the request. */ if (node != NULL) { req->node = (WCHAR*)alloc_ptr; - if (uv_utf8_to_utf16(node, - (WCHAR*) alloc_ptr, - nodesize / sizeof(WCHAR)) == 0) { + if (MultiByteToWideChar(CP_UTF8, + 0, + node, + -1, + (WCHAR*) alloc_ptr, + nodesize / sizeof(WCHAR)) == 0) { err = GetLastError(); goto error; } @@ -309,9 +333,12 @@ int uv_getaddrinfo(uv_loop_t* loop, /* in the req. */ if (service != NULL) { req->service = (WCHAR*)alloc_ptr; - if (uv_utf8_to_utf16(service, - (WCHAR*) alloc_ptr, - servicesize / sizeof(WCHAR)) == 0) { + if (MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + (WCHAR*) alloc_ptr, + servicesize / sizeof(WCHAR)) == 0) { err = GetLastError(); goto error; } diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 783f21af0fe9f1..c724793bf05a41 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -246,7 +246,6 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); DWORD uv__next_timeout(const uv_loop_t* loop); -void uv__time_forward(uv_loop_t* loop, uint64_t msecs); void uv_process_timers(uv_loop_t* loop); @@ -329,6 +328,8 @@ uint64_t uv__hrtime(double scale); int uv_parent_pid(); int uv_current_pid(); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); +int uv__getpwuid_r(uv_passwd_t* pwd); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8); /* diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index bcce80c77e5d57..a784325c589474 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -513,13 +513,18 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { } /* Convert name to UTF16. */ - nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)uv__malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { err = GetLastError(); goto error; } @@ -627,13 +632,18 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, req->cb = cb; /* Convert name to UTF16. */ - nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)uv__malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { err = GetLastError(); goto error; } @@ -2038,9 +2048,9 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) *size = 0; err = uv_translate_sys_error(GetLastError()); goto error; - } else if (pipe_prefix_len + addrlen > *size) { + } else if (pipe_prefix_len + addrlen >= *size) { /* "\\\\.\\pipe" + name */ - *size = pipe_prefix_len + addrlen; + *size = pipe_prefix_len + addrlen + 1; err = UV_ENOBUFS; goto error; } @@ -2062,6 +2072,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) addrlen += pipe_prefix_len; *size = addrlen; + buffer[addrlen] = '\0'; err = 0; goto cleanup; diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index ce861d6ffc41eb..d479e521efe24f 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -91,7 +91,11 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { handle->mask_events_1 = handle->events; handle->mask_events_2 = 0; } else { - assert(0); + /* Just wait until there's an unsubmitted req. */ + /* This will happen almost immediately as one of the 2 outstanding */ + /* requests is about to return. When this happens, */ + /* uv__fast_poll_process_poll_req will be called, and the pending */ + /* events, if needed, will be processed in a subsequent request. */ return; } @@ -107,6 +111,10 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { if (handle->events & UV_READABLE) { afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; + } else { + if (handle->events & UV_DISCONNECT) { + afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT; + } } if (handle->events & UV_WRITABLE) { afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; @@ -184,6 +192,9 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) { events |= UV_READABLE; + if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) { + events |= UV_DISCONNECT; + } } if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL)) != 0) { @@ -218,7 +229,7 @@ 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)) == 0); + assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); handle->events = events; diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c index 0da541a2c8685c..27ca7716af6d8a 100644 --- a/deps/uv/src/win/timer.c +++ b/deps/uv/src/win/timer.c @@ -34,13 +34,8 @@ void uv_update_time(uv_loop_t* loop) { uint64_t new_time = uv__hrtime(UV__MILLISEC); - if (new_time > loop->time) { - loop->time = new_time; - } -} - -void uv__time_forward(uv_loop_t* loop, uint64_t msecs) { - loop->time += msecs; + assert(new_time >= loop->time); + loop->time = new_time; } diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index d87cc699097cf7..1b27f60a6f0c9c 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -292,12 +292,9 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { was_reading = 1; alloc_cb = tty->alloc_cb; read_cb = tty->read_cb; - - if (was_reading) { - err = uv_tty_read_stop(tty); - if (err) { - return uv_translate_sys_error(err); - } + err = uv_tty_read_stop(tty); + if (err) { + return uv_translate_sys_error(err); } } else { was_reading = 0; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index cb247513046351..1788b1780e9bba 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -87,30 +87,6 @@ void uv__util_init() { } -int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, - char* utf8Buffer, size_t utf8Size) { - return WideCharToMultiByte(CP_UTF8, - 0, - utf16Buffer, - utf16Size, - utf8Buffer, - utf8Size, - NULL, - NULL); -} - - -int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, - size_t utf16Size) { - return MultiByteToWideChar(CP_UTF8, - 0, - utf8Buffer, - -1, - utf16Buffer, - utf16Size); -} - - int uv_exepath(char* buffer, size_t* size_ptr) { int utf8_len, utf16_buffer_len, utf16_len; WCHAR* utf16_buffer; @@ -210,7 +186,7 @@ int uv_cwd(char* buffer, size_t* size) { if (r == 0) { return uv_translate_sys_error(GetLastError()); } else if (r > (int) *size) { - *size = r -1; + *size = r; return UV_ENOBUFS; } @@ -384,7 +360,7 @@ int uv_set_process_title(const char* title) { uv__once_init(); /* Find out how big the buffer for the wide-char title must be */ - length = uv_utf8_to_utf16(title, NULL, 0); + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0); if (!length) { err = GetLastError(); goto done; @@ -396,7 +372,7 @@ int uv_set_process_title(const char* title) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - length = uv_utf8_to_utf16(title, title_w, length); + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length); if (!length) { err = GetLastError(); goto done; @@ -434,7 +410,7 @@ static int uv__get_process_title() { } /* Find out what the size of the buffer is that we need */ - length = uv_utf16_to_utf8(title_w, -1, NULL, 0); + length = WideCharToMultiByte(CP_UTF8, 0, title_w, -1, NULL, 0, NULL, NULL); if (!length) { return -1; } @@ -446,7 +422,14 @@ static int uv__get_process_title() { } /* Do utf16 -> utf8 conversion here */ - if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) { + if (!WideCharToMultiByte(CP_UTF8, + 0, + title_w, + -1, + process_title, + length, + NULL, + NULL)) { uv__free(process_title); return -1; } @@ -1169,7 +1152,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { int uv_os_homedir(char* buffer, size_t* size) { - HANDLE token; + uv_passwd_t pwd; wchar_t path[MAX_PATH]; DWORD bufsize; size_t len; @@ -1183,6 +1166,7 @@ int uv_os_homedir(char* buffer, size_t* size) { if (len == 0) { r = GetLastError(); + /* Don't return an error if USERPROFILE was not found */ if (r != ERROR_ENVVAR_NOT_FOUND) return uv_translate_sys_error(r); @@ -1190,43 +1174,219 @@ int uv_os_homedir(char* buffer, size_t* size) { /* This should not be possible */ return UV_EIO; } else { - goto convert_buffer; + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; } - /* USERPROFILE is not set, so call GetUserProfileDirectoryW() */ - if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) - return uv_translate_sys_error(GetLastError()); + /* USERPROFILE is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); - bufsize = MAX_PATH; - if (!GetUserProfileDirectoryW(token, path, &bufsize)) { - r = GetLastError(); - CloseHandle(token); + if (r != 0) { + return r; + } - /* This should not be possible */ - if (r == ERROR_INSUFFICIENT_BUFFER) - return UV_EIO; + len = strlen(pwd.homedir); - return uv_translate_sys_error(r); + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return UV_ENOBUFS; } - CloseHandle(token); + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} -convert_buffer: + +int uv_os_tmpdir(char* buffer, size_t* size) { + wchar_t path[MAX_PATH + 1]; + DWORD bufsize; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + len = GetTempPathW(MAX_PATH + 1, path); + + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (len > MAX_PATH + 1) { + /* This should not be possible */ + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (path[len - 1] == L'\\' && + !(len == 3 && path[1] == L':')) { + len--; + path[len] = L'\0'; + } /* Check how much space we need */ - bufsize = uv_utf16_to_utf8(path, -1, NULL, 0); + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + if (bufsize == 0) { return uv_translate_sys_error(GetLastError()); } else if (bufsize > *size) { - *size = bufsize - 1; + *size = bufsize; return UV_ENOBUFS; } /* Convert to UTF-8 */ - bufsize = uv_utf16_to_utf8(path, -1, buffer, *size); + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + if (bufsize == 0) return uv_translate_sys_error(GetLastError()); *size = bufsize - 1; return 0; } + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + uv__free(pwd->username); + uv__free(pwd->homedir); + pwd->username = NULL; + pwd->homedir = NULL; +} + + +int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { + DWORD bufsize; + + if (utf16 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer */ + *utf8 = uv__malloc(bufsize); + + if (*utf8 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + -1, + *utf8, + bufsize, + NULL, + NULL); + + if (bufsize == 0) { + uv__free(*utf8); + return uv_translate_sys_error(GetLastError()); + } + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + HANDLE token; + wchar_t username[UNLEN + 1]; + wchar_t path[MAX_PATH]; + DWORD bufsize; + int r; + + if (pwd == NULL) + return UV_EINVAL; + + /* Get the home directory using GetUserProfileDirectoryW() */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) + return uv_translate_sys_error(GetLastError()); + + bufsize = sizeof(path); + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + r = GetLastError(); + CloseHandle(token); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + CloseHandle(token); + + /* Get the username using GetUserNameW() */ + bufsize = sizeof(username); + if (!GetUserNameW(username, &bufsize)) { + r = GetLastError(); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + pwd->homedir = NULL; + r = uv__convert_utf16_to_utf8(path, &pwd->homedir); + + if (r != 0) + return r; + + pwd->username = NULL; + r = uv__convert_utf16_to_utf8(username, &pwd->username); + + if (r != 0) { + uv__free(pwd->homedir); + return r; + } + + pwd->shell = NULL; + pwd->uid = -1; + pwd->gid = -1; + + return 0; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 2264d1e89d5fae..2405fa878c0805 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -226,7 +226,7 @@ int process_wait(process_info_t* vec, int n, int timeout) { tv = timebase; for (;;) { /* Check that gettimeofday() doesn't jump back in time. */ - assert(tv.tv_sec == timebase.tv_sec || + assert(tv.tv_sec > timebase.tv_sec || (tv.tv_sec == timebase.tv_sec && tv.tv_usec >= timebase.tv_usec)); elapsed_ms = diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index d18c1daa364702..96cc6377cb1fa6 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -108,10 +108,10 @@ typedef enum { /* This macro cleans up the main loop. This is used to avoid valgrind * warnings about memory being "leaked" by the main event loop. */ -#define MAKE_VALGRIND_HAPPY() \ - do { \ - close_loop(uv_default_loop()); \ - uv_loop_delete(uv_default_loop()); \ +#define MAKE_VALGRIND_HAPPY() \ + do { \ + close_loop(uv_default_loop()); \ + ASSERT(0 == uv_loop_close(uv_default_loop())); \ } while (0) /* Just sugar for wrapping the main() for a task or helper. */ @@ -207,7 +207,7 @@ UNUSED static int can_ipv6(void) { int i; if (uv_interface_addresses(&addr, &count)) - return 1; /* Assume IPv6 support on failure. */ + return 0; /* Assume no IPv6 support on failure. */ supported = 0; for (i = 0; supported == 0 && i < count; i += 1) diff --git a/deps/uv/test/test-condvar.c b/deps/uv/test/test-condvar.c index dbacdba384d158..83b28494adbb3f 100644 --- a/deps/uv/test/test-condvar.c +++ b/deps/uv/test/test-condvar.c @@ -25,24 +25,33 @@ #include #include -typedef struct { +typedef struct worker_config { uv_mutex_t mutex; uv_cond_t cond; - int delay; + int signal_delay; + int wait_delay; int use_broadcast; - volatile int posted; + volatile int posted_1; + volatile int posted_2; + void (*signal_cond)(struct worker_config* c, volatile int* flag); + void (*wait_cond)(struct worker_config* c, const volatile int* flag); } worker_config; static void worker(void* arg) { worker_config* c = arg; + c->signal_cond(c, &c->posted_1); + c->wait_cond(c, &c->posted_2); +} + - if (c->delay) - uv_sleep(c->delay); +static void condvar_signal(worker_config* c, volatile int* flag) { + if (c->signal_delay) + uv_sleep(c->signal_delay); uv_mutex_lock(&c->mutex); - ASSERT(c->posted == 0); - c->posted = 1; + ASSERT(*flag == 0); + *flag = 1; if (c->use_broadcast) uv_cond_broadcast(&c->cond); else @@ -51,21 +60,33 @@ static void worker(void* arg) { } +static void condvar_wait(worker_config* c, const volatile int* flag) { + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + uv_cond_wait(&c->cond, &c->mutex); + } + ASSERT(*flag == 1); + uv_mutex_unlock(&c->mutex); +} + + TEST_IMPL(condvar_1) { uv_thread_t thread; worker_config wc; memset(&wc, 0, sizeof(wc)); + wc.wait_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_sleep(100); - uv_cond_wait(&wc.cond, &wc.mutex); - ASSERT(wc.posted == 1); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -80,15 +101,16 @@ TEST_IMPL(condvar_2) { worker_config wc; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_cond_wait(&wc.cond, &wc.mutex); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -98,22 +120,35 @@ TEST_IMPL(condvar_2) { } +static void condvar_timedwait(worker_config* c, const volatile int* flag) { + int r; + + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6)); + ASSERT(r == 0); + } + uv_mutex_unlock(&c->mutex); +} + + TEST_IMPL(condvar_3) { uv_thread_t thread; worker_config wc; - int r; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6)); - ASSERT(r == UV_ETIMEDOUT); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -126,19 +161,18 @@ TEST_IMPL(condvar_3) { TEST_IMPL(condvar_4) { uv_thread_t thread; worker_config wc; - int r; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6)); - ASSERT(r == 0); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -154,16 +188,16 @@ TEST_IMPL(condvar_5) { memset(&wc, 0, sizeof(wc)); wc.use_broadcast = 1; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_sleep(100); - uv_cond_wait(&wc.cond, &wc.mutex); - ASSERT(wc.posted == 1); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); diff --git a/deps/uv/test/test-eintr-handling.c b/deps/uv/test/test-eintr-handling.c new file mode 100644 index 00000000000000..1aaf623b789b6e --- /dev/null +++ b/deps/uv/test/test-eintr-handling.c @@ -0,0 +1,94 @@ +/* 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. + */ + +#include "uv.h" +#include "task.h" + +#ifdef _WIN32 + +TEST_IMPL(eintr_handling) { + RETURN_SKIP("Test not implemented on Windows."); +} + +#else /* !_WIN32 */ + +#include +#include + +static uv_loop_t* loop; +static uv_fs_t read_req; +static uv_buf_t iov; + +static char buf[32]; +static char test_buf[] = "test-buffer\n"; +int pipe_fds[2]; + +struct thread_ctx { + uv_barrier_t barrier; + int fd; +}; + +static void thread_main(void* arg) { + int nwritten; + ASSERT(0 == kill(getpid(), SIGUSR1)); + + do + nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); + while (nwritten == -1 && errno == EINTR); + + ASSERT(nwritten == sizeof(test_buf)); +} + +static void sig_func(uv_signal_t* handle, int signum) { + uv_signal_stop(handle); +} + +TEST_IMPL(eintr_handling) { + struct thread_ctx ctx; + uv_thread_t thread; + uv_signal_t signal; + int nread; + + iov = uv_buf_init(buf, sizeof(buf)); + loop = uv_default_loop(); + + ASSERT(0 == uv_signal_init(loop, &signal)); + ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); + + ASSERT(0 == pipe(pipe_fds)); + ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + + nread = uv_fs_read(loop, &read_req, pipe_fds[0], &iov, 1, -1, NULL); + + ASSERT(nread == sizeof(test_buf)); + ASSERT(0 == strcmp(buf, test_buf)); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(0 == close(pipe_fds[0])); + ASSERT(0 == close(pipe_fds[1])); + uv_close((uv_handle_t*) &signal, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index e02ff2fda5e5d9..35583529e57507 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -531,6 +531,33 @@ TEST_IMPL(fs_event_watch_file_current_dir) { return 0; } +#ifdef _WIN32 +TEST_IMPL(fs_event_watch_file_root_dir) { + uv_loop_t* loop; + int r; + + const char* sys_drive = getenv("SystemDrive"); + char path[] = "\\\\?\\X:\\bootsect.bak"; + + ASSERT(sys_drive != NULL); + strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1); + + loop = uv_default_loop(); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fail_cb, path, 0); + if (r == UV_ENOENT) + RETURN_SKIP("bootsect.bak doesn't exist in system root.\n"); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &fs_event, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + TEST_IMPL(fs_event_no_callback_after_close) { uv_loop_t* loop = uv_default_loop(); int r; @@ -792,6 +819,7 @@ TEST_IMPL(fs_event_getpath) { r = uv_fs_event_getpath(&fs_event, buf, &len); ASSERT(r == 0); ASSERT(buf[len - 1] != 0); + ASSERT(buf[len] == '\0'); ASSERT(memcmp(buf, "watch_dir", len) == 0); r = uv_fs_event_stop(&fs_event); ASSERT(r == 0); diff --git a/deps/uv/test/test-fs-poll.c b/deps/uv/test/test-fs-poll.c index dbc1515b0b1b93..737d50dfd26937 100644 --- a/deps/uv/test/test-fs-poll.c +++ b/deps/uv/test/test-fs-poll.c @@ -173,6 +173,7 @@ TEST_IMPL(fs_poll_getpath) { len = sizeof buf; ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len)); ASSERT(buf[len - 1] != 0); + ASSERT(buf[len] == '\0'); ASSERT(0 == memcmp(buf, FIXTURE, len)); uv_close((uv_handle_t*) &poll_handle, close_cb); diff --git a/deps/uv/test/test-get-passwd.c b/deps/uv/test/test-get-passwd.c new file mode 100644 index 00000000000000..58d9c73c691cf3 --- /dev/null +++ b/deps/uv/test/test-get-passwd.c @@ -0,0 +1,80 @@ +/* Copyright libuv 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. + */ + +#include "uv.h" +#include "task.h" +#include + +TEST_IMPL(get_passwd) { + uv_passwd_t pwd; + size_t len; + int r; + + /* Test the normal case */ + r = uv_os_get_passwd(&pwd); + ASSERT(r == 0); + len = strlen(pwd.username); + ASSERT(len > 0); + +#ifdef _WIN32 + ASSERT(pwd.shell == NULL); +#else + len = strlen(pwd.shell); + ASSERT(len > 0); +#endif + + len = strlen(pwd.homedir); + ASSERT(len > 0); + +#ifdef _WIN32 + ASSERT(pwd.homedir[len - 1] != '\\'); +#else + ASSERT(pwd.homedir[len - 1] != '/'); +#endif + +#ifdef _WIN32 + ASSERT(pwd.uid == -1); + ASSERT(pwd.gid == -1); +#else + ASSERT(pwd.uid >= 0); + ASSERT(pwd.gid >= 0); +#endif + + /* Test uv_os_free_passwd() */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test a double free */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test invalid input */ + r = uv_os_get_passwd(NULL); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/deps/uv/test/test-homedir.c b/deps/uv/test/test-homedir.c index cbc47566c55e42..5027d44c1ea358 100644 --- a/deps/uv/test/test-homedir.c +++ b/deps/uv/test/test-homedir.c @@ -1,3 +1,24 @@ +/* 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. + */ + #include "uv.h" #include "task.h" #include diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 858a20af49c291..8b10f1a5f68507 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -44,6 +44,7 @@ TEST_DECLARE (semaphore_2) TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) TEST_DECLARE (tty_file) +TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (ip6_pton) TEST_DECLARE (ipc_listen_before_write) @@ -154,6 +155,7 @@ TEST_DECLARE (timer_huge_repeat) TEST_DECLARE (timer_run_once) TEST_DECLARE (timer_from_check) TEST_DECLARE (timer_null_callback) +TEST_DECLARE (timer_early_check) TEST_DECLARE (idle_starvation) TEST_DECLARE (loop_handles) TEST_DECLARE (get_loadavg) @@ -191,12 +193,15 @@ TEST_DECLARE (active) TEST_DECLARE (embed) TEST_DECLARE (async) TEST_DECLARE (async_null_cb) +TEST_DECLARE (eintr_handling) TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) +TEST_DECLARE (get_passwd) TEST_DECLARE (handle_fileno) TEST_DECLARE (homedir) +TEST_DECLARE (tmpdir) TEST_DECLARE (hrtime) TEST_DECLARE (getaddrinfo_fail) TEST_DECLARE (getaddrinfo_fail_sync) @@ -267,6 +272,9 @@ TEST_DECLARE (fs_event_watch_dir_recursive) TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_twice) TEST_DECLARE (fs_event_watch_file_current_dir) +#ifdef _WIN32 +TEST_DECLARE (fs_event_watch_file_root_dir) +#endif TEST_DECLARE (fs_event_no_callback_after_close) TEST_DECLARE (fs_event_no_callback_on_close) TEST_DECLARE (fs_event_immediate_close) @@ -292,6 +300,7 @@ TEST_DECLARE (threadpool_cancel_work) TEST_DECLARE (threadpool_cancel_fs) TEST_DECLARE (threadpool_cancel_single) TEST_DECLARE (thread_local_storage) +TEST_DECLARE (thread_stack_size) TEST_DECLARE (thread_mutex) TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_rwlock_trylock) @@ -301,6 +310,7 @@ TEST_DECLARE (dlerror) TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_close) +TEST_DECLARE (poll_bad_fdtype) TEST_DECLARE (ip4_addr) TEST_DECLARE (ip6_addr_link_local) @@ -378,6 +388,7 @@ TASK_LIST_START TEST_ENTRY (pipe_set_non_blocking) TEST_ENTRY (tty) TEST_ENTRY (tty_file) + TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (ip6_pton) TEST_ENTRY (ipc_listen_before_write) @@ -522,6 +533,7 @@ TASK_LIST_START TEST_ENTRY (timer_run_once) TEST_ENTRY (timer_from_check) TEST_ENTRY (timer_null_callback) + TEST_ENTRY (timer_early_check) TEST_ENTRY (idle_starvation) @@ -566,6 +578,7 @@ TASK_LIST_START TEST_ENTRY (async) TEST_ENTRY (async_null_cb) + TEST_ENTRY (eintr_handling) TEST_ENTRY (get_currentexe) @@ -575,12 +588,16 @@ TASK_LIST_START TEST_ENTRY (get_memory) + TEST_ENTRY (get_passwd) + TEST_ENTRY (get_loadavg) TEST_ENTRY (handle_fileno) TEST_ENTRY (homedir) + TEST_ENTRY (tmpdir) + TEST_ENTRY (hrtime) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) @@ -600,6 +617,7 @@ TASK_LIST_START TEST_ENTRY (poll_duplex) TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) + TEST_ENTRY (poll_bad_fdtype) TEST_ENTRY (socket_buffer_size) @@ -688,6 +706,9 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_file) TEST_ENTRY (fs_event_watch_file_twice) TEST_ENTRY (fs_event_watch_file_current_dir) +#ifdef _WIN32 + TEST_ENTRY (fs_event_watch_file_root_dir) +#endif TEST_ENTRY (fs_event_no_callback_after_close) TEST_ENTRY (fs_event_no_callback_on_close) TEST_ENTRY (fs_event_immediate_close) @@ -706,13 +727,21 @@ TASK_LIST_START TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) +#if defined(__PPC__) || defined(__PPC64__) /* For linux PPC and AIX */ + /* pthread_join takes a while, especially on AIX. + * Therefore being gratuitous with timeout. + */ + TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 120000) +#else TEST_ENTRY (threadpool_multiple_event_loops) +#endif TEST_ENTRY (threadpool_cancel_getaddrinfo) TEST_ENTRY (threadpool_cancel_getnameinfo) TEST_ENTRY (threadpool_cancel_work) TEST_ENTRY (threadpool_cancel_fs) TEST_ENTRY (threadpool_cancel_single) TEST_ENTRY (thread_local_storage) + TEST_ENTRY (thread_stack_size) TEST_ENTRY (thread_mutex) TEST_ENTRY (thread_rwlock) TEST_ENTRY (thread_rwlock_trylock) diff --git a/deps/uv/test/test-pipe-close-stdout-read-stdin.c b/deps/uv/test/test-pipe-close-stdout-read-stdin.c index ee8bb2a9a8bc38..4ab14789a3858b 100644 --- a/deps/uv/test/test-pipe-close-stdout-read-stdin.c +++ b/deps/uv/test/test-pipe-close-stdout-read-stdin.c @@ -53,6 +53,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { int pid; int fd[2]; int status; + char buf; uv_pipe_t stdin_pipe; r = pipe(fd); @@ -64,6 +65,8 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { * The write side will be closed by the parent process. */ close(fd[1]); + /* block until write end of pipe is closed */ + read(fd[0], &buf, 1); close(0); r = dup(fd[0]); ASSERT(r != -1); diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c index 5e036f9d528a58..58041c02668271 100644 --- a/deps/uv/test/test-pipe-getsockname.c +++ b/deps/uv/test/test-pipe-getsockname.c @@ -114,6 +114,7 @@ TEST_IMPL(pipe_getsockname) { ASSERT(r == 0); ASSERT(buf[len - 1] != 0); + ASSERT(buf[len] == '\0'); ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0); len = sizeof buf; diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 76495e14fd87c3..2c4740550a198c 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -32,6 +32,7 @@ TEST_IMPL(platform_output) { uv_rusage_t rusage; uv_cpu_info_t* cpus; uv_interface_address_t* interfaces; + uv_passwd_t pwd; int count; int i; int err; @@ -122,5 +123,15 @@ TEST_IMPL(platform_output) { } uv_free_interface_addresses(interfaces, count); + err = uv_os_get_passwd(&pwd); + ASSERT(err == 0); + + printf("uv_os_get_passwd:\n"); + printf(" euid: %ld\n", pwd.uid); + printf(" gid: %ld\n", pwd.gid); + printf(" username: %s\n", pwd.username); + printf(" shell: %s\n", pwd.shell); + printf(" home directory: %s\n", pwd.homedir); + return 0; } diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index be8b00c32ca99b..bfb75af13355ab 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -21,7 +21,9 @@ #include -#ifndef _WIN32 +#ifdef _WIN32 +# include +#else # include # include #endif @@ -49,7 +51,7 @@ typedef struct connection_context_s { size_t read, sent; int is_server_connection; int open_handles; - int got_fin, sent_fin; + int got_fin, sent_fin, got_disconnect; unsigned int events, delayed_events; } connection_context_t; @@ -70,6 +72,8 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; +static int disconnects = 0; + static int got_eagain(void) { #ifdef _WIN32 @@ -140,6 +144,7 @@ static connection_context_t* create_connection_context( context->delayed_events = 0; context->got_fin = 0; context->sent_fin = 0; + context->got_disconnect = 0; r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); context->open_handles++; @@ -373,7 +378,13 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } } - if (context->got_fin && context->sent_fin) { + if (events & UV_DISCONNECT) { + context->got_disconnect = 1; + ++disconnects; + new_events &= ~UV_DISCONNECT; + } + + if (context->got_fin && context->sent_fin && context->got_disconnect) { /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -461,9 +472,9 @@ static void server_poll_cb(uv_poll_t* handle, int status, int events) { #endif connection_context = create_connection_context(sock, 1); - connection_context->events = UV_READABLE | UV_WRITABLE; + connection_context->events = UV_READABLE | UV_WRITABLE | UV_DISCONNECT; r = uv_poll_start(&connection_context->poll_handle, - UV_READABLE | UV_WRITABLE, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, connection_poll_cb); ASSERT(r == 0); @@ -505,9 +516,9 @@ static void start_client(void) { sock = create_bound_socket(addr); context = create_connection_context(sock, 0); - context->events = UV_READABLE | UV_WRITABLE; + context->events = UV_READABLE | UV_WRITABLE | UV_DISCONNECT; r = uv_poll_start(&context->poll_handle, - UV_READABLE | UV_WRITABLE, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, connection_poll_cb); ASSERT(r == 0); @@ -541,6 +552,7 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); + ASSERT(disconnects == NUM_CLIENTS * 2); MAKE_VALGRIND_HAPPY(); } @@ -558,3 +570,29 @@ TEST_IMPL(poll_unidirectional) { start_poll_test(); return 0; } + + +/* Windows won't let you open a directory so we open a file instead. + * OS X lets you poll a file so open the $PWD instead. Both fail + * on Linux so it doesn't matter which one we pick. Both succeed + * on FreeBSD, Solaris and AIX so skip the test on those platforms. + */ +TEST_IMPL(poll_bad_fdtype) { +#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ + !defined(_AIX) + uv_poll_t poll_handle; + int fd; + +#if defined(_WIN32) + fd = open("test/fixtures/empty_file", O_RDONLY); +#else + fd = open(".", O_RDONLY); +#endif + ASSERT(fd != -1); + ASSERT(0 != uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == close(fd)); +#endif + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-tcp-close-while-connecting.c b/deps/uv/test/test-tcp-close-while-connecting.c index 2c39b652b61078..60df7a574409aa 100644 --- a/deps/uv/test/test-tcp-close-while-connecting.c +++ b/deps/uv/test/test-tcp-close-while-connecting.c @@ -72,7 +72,7 @@ TEST_IMPL(tcp_close_while_connecting) { RETURN_SKIP("Network unreachable."); ASSERT(r == 0); ASSERT(0 == uv_timer_init(loop, &timer1_handle)); - ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0)); + ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 1, 0)); ASSERT(0 == uv_timer_init(loop, &timer2_handle)); ASSERT(0 == uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0)); ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); diff --git a/deps/uv/test/test-thread.c b/deps/uv/test/test-thread.c index 7f3321aa06d2c0..10bec3fe6c6587 100644 --- a/deps/uv/test/test-thread.c +++ b/deps/uv/test/test-thread.c @@ -209,3 +209,24 @@ TEST_IMPL(thread_local_storage) { uv_key_delete(&tls_key); return 0; } + + +#if defined(__APPLE__) +static void thread_check_stack(void* arg) { + /* 512KB is the default stack size of threads other than the main thread + * on OSX. */ + ASSERT(pthread_get_stacksize_np(pthread_self()) > 512*1024); +} +#endif + + +TEST_IMPL(thread_stack_size) { +#if defined(__APPLE__) + uv_thread_t thread; + ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); + ASSERT(0 == uv_thread_join(&thread)); + return 0; +#else + RETURN_SKIP("OSX only test"); +#endif +} diff --git a/deps/uv/test/test-timer.c b/deps/uv/test/test-timer.c index aba050fd64c72a..080a73005ee3c2 100644 --- a/deps/uv/test/test-timer.c +++ b/deps/uv/test/test-timer.c @@ -301,3 +301,30 @@ TEST_IMPL(timer_null_callback) { MAKE_VALGRIND_HAPPY(); return 0; } + + +static uint64_t timer_early_check_expected_time; + + +static void timer_early_check_cb(uv_timer_t* handle) { + uint64_t hrtime = uv_hrtime() / 1000000; + ASSERT(hrtime >= timer_early_check_expected_time); +} + + +TEST_IMPL(timer_early_check) { + uv_timer_t timer_handle; + const uint64_t timeout_ms = 10; + + timer_early_check_expected_time = uv_now(uv_default_loop()) + timeout_ms; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_early_check_cb, timeout_ms, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + uv_close((uv_handle_t*) &timer_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-tmpdir.c b/deps/uv/test/test-tmpdir.c new file mode 100644 index 00000000000000..29e8055f1d5d91 --- /dev/null +++ b/deps/uv/test/test-tmpdir.c @@ -0,0 +1,71 @@ +/* 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(tmpdir) { + char tmpdir[PATHMAX]; + size_t len; + char last; + int r; + + /* Test the normal case */ + len = sizeof tmpdir; + tmpdir[0] = '\0'; + + ASSERT(strlen(tmpdir) == 0); + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == 0); + ASSERT(strlen(tmpdir) == len); + ASSERT(len > 0); + ASSERT(tmpdir[len] == '\0'); + + if (len > 1) { + last = tmpdir[len - 1]; +#ifdef _WIN32 + ASSERT(last != '\\'); +#else + ASSERT(last != '/'); +#endif + } + + /* Test the case where the buffer is too small */ + len = SMALLPATH; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_ENOBUFS); + ASSERT(len > SMALLPATH); + + /* Test invalid inputs */ + r = uv_os_tmpdir(NULL, &len); + ASSERT(r == UV_EINVAL); + r = uv_os_tmpdir(tmpdir, NULL); + ASSERT(r == UV_EINVAL); + len = 0; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index b844959d526340..461d1941359018 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -28,6 +28,13 @@ #else /* Unix */ # include # include +# if defined(__linux__) +# include +# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +# include +# elif defined(__FreeBSD__) || defined(__DragonFly__) +# include +# endif #endif #include @@ -182,3 +189,35 @@ TEST_IMPL(tty_file) { #endif return 0; } + +TEST_IMPL(tty_pty) { +# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) + int master_fd, slave_fd; + struct winsize w; + uv_loop_t loop; + uv_tty_t master_tty, slave_tty; + + ASSERT(0 == uv_loop_init(&loop)); + + ASSERT(0 == openpty(&master_fd, &slave_fd, NULL, NULL, &w)); + ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0)); + ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0)); + /* Check if the file descriptor was reopened. If it is, + * UV_STREAM_BLOCKING (value 0x80) isn't set on flags. + */ + ASSERT(0 == (slave_tty.flags & 0x80)); + /* The master_fd of a pty should never be reopened. + */ + ASSERT(master_tty.flags & 0x80); + ASSERT(0 == close(slave_fd)); + uv_close((uv_handle_t*) &slave_tty, NULL); + ASSERT(0 == close(master_fd)); + uv_close((uv_handle_t*) &master_tty, NULL); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); +#endif + return 0; +} diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 635a234ea6eee8..757540193dd7a2 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -92,6 +92,7 @@ 'src/win/req.c', 'src/win/req-inl.h', 'src/win/signal.c', + 'src/win/snprintf.c', 'src/win/stream.c', 'src/win/stream-inl.h', 'src/win/tcp.c', @@ -104,13 +105,6 @@ 'src/win/winsock.c', 'src/win/winsock.h', ], - 'conditions': [ - ['MSVS_VERSION < "2015"', { - 'sources': [ - 'src/win/snprintf.c' - ] - }] - ], 'link_settings': { 'libraries': [ '-ladvapi32', @@ -247,6 +241,7 @@ '_ALL_SOURCE', '_XOPEN_SOURCE=500', '_LINUX_SOURCE_COMPAT', + '_THREAD_SAFE', ], 'link_settings': { 'libraries': [ @@ -300,6 +295,7 @@ 'test/test-cwd-and-chdir.c', 'test/test-default-loop-close.c', 'test/test-delayed-accept.c', + 'test/test-eintr-handling.c', 'test/test-error.c', 'test/test-embed.c', 'test/test-emfile.c', @@ -308,6 +304,7 @@ 'test/test-fs-event.c', 'test/test-get-currentexe.c', 'test/test-get-memory.c', + 'test/test-get-passwd.c', 'test/test-getaddrinfo.c', 'test/test-getnameinfo.c', 'test/test-getsockname.c', @@ -386,6 +383,7 @@ 'test/test-threadpool.c', 'test/test-threadpool-cancel.c', 'test/test-thread-equal.c', + 'test/test-tmpdir.c', 'test/test-mutexes.c', 'test/test-thread.c', 'test/test-barrier.c', @@ -417,7 +415,8 @@ [ 'OS=="win"', { 'sources': [ 'test/runner-win.c', - 'test/runner-win.h' + 'test/runner-win.h', + 'src/win/snprintf.c', ], 'libraries': [ '-lws2_32' ] }, { # POSIX @@ -427,6 +426,11 @@ 'test/runner-unix.h', ], }], + [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { + 'link_settings': { + 'libraries': [ '-lutil' ], + }, + }], [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE 'defines': [ '__EXTENSIONS__', @@ -485,6 +489,7 @@ 'sources': [ 'test/runner-win.c', 'test/runner-win.h', + 'src/win/snprintf.c', ], 'libraries': [ '-lws2_32' ] }, { # POSIX diff --git a/deps/uv/vcbuild.bat b/deps/uv/vcbuild.bat index 696f0db30e15ad..9a7ed4b8c512e0 100644 --- a/deps/uv/vcbuild.bat +++ b/deps/uv/vcbuild.bat @@ -49,6 +49,7 @@ if not defined VS140COMNTOOLS goto vc-set-2013 if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013 call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2015 +echo Using Visual Studio 2015 goto select-target :vc-set-2013 @@ -57,6 +58,7 @@ if not defined VS120COMNTOOLS goto vc-set-2012 if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012 call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2013 +echo Using Visual Studio 2013 goto select-target :vc-set-2012 @@ -65,6 +67,7 @@ if not defined VS110COMNTOOLS goto vc-set-2010 if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010 call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2012 +echo Using Visual Studio 2012 goto select-target :vc-set-2010 @@ -73,6 +76,7 @@ if not defined VS100COMNTOOLS goto vc-set-2008 if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008 call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2010 +echo Using Visual Studio 2010 goto select-target :vc-set-2008 @@ -81,6 +85,7 @@ if not defined VS90COMNTOOLS goto vc-set-notfound if not exist "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-notfound call "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2008 +echo Using Visual Studio 2008 goto select-target :vc-set-notfound