From 16124bb34e8afdf0c9a8e968bc3f2b4b3594134a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 28 Jan 2012 00:11:45 +0100 Subject: [PATCH 01/12] sunos: fix uv_udp_set_ttl and uv_udp_multicast_ttl The argument to setsockopt(IP_TTL|IP_MULTICAST_TTL) should be a char, not an int like on other Unices. --- src/unix/udp.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 6db0ea10..3580e4e5 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -528,13 +528,44 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, } X(multicast_loop, IPPROTO_IP, IP_MULTICAST_LOOP) -X(multicast_ttl, IPPROTO_IP, IP_MULTICAST_TTL) X(broadcast, SOL_SOCKET, SO_BROADCAST) -X(ttl, IPPROTO_IP, IP_TTL) #undef X +static int uv__udp_set_ttl(uv_udp_t* handle, int option, int ttl) { +#if __sun + char arg = ttl; +#else + int arg = ttl; +#endif + +#if __sun + if (ttl < 0 || ttl > 255) { + uv__set_sys_error(handle->loop, EINVAL); + return -1; + } +#endif + + if (setsockopt(handle->fd, IPPROTO_IP, option, &arg, sizeof(arg))) { + uv__set_sys_error(handle->loop, errno); + return -1; + } + + return 0; +} + + +int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { + return uv__udp_set_ttl(handle, IP_TTL, ttl); +} + + +int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { + return uv__udp_set_ttl(handle, IP_MULTICAST_TTL, ttl); +} + + int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) { socklen_t socklen; int saved_errno; From 332b72e589cd105e83b619c5b40889f0401c63dc Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 28 Jan 2012 01:18:01 +0100 Subject: [PATCH 02/12] sunos: fix uv_udp_set_ttl and uv_udp_set_multicast_loop It turns out that setsockopt(IP_TTL) *does* expect an int, whereas setsockopt(IP_MULTICAST_LOOP) needs a char. --- src/unix/udp.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 3580e4e5..91f7d1a2 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -527,21 +527,21 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, return 0; \ } -X(multicast_loop, IPPROTO_IP, IP_MULTICAST_LOOP) X(broadcast, SOL_SOCKET, SO_BROADCAST) +X(ttl, IPPROTO_IP, IP_TTL) #undef X -static int uv__udp_set_ttl(uv_udp_t* handle, int option, int ttl) { +static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) { #if __sun - char arg = ttl; + char arg = val; #else - int arg = ttl; + int arg = val; #endif #if __sun - if (ttl < 0 || ttl > 255) { + if (val < 0 || val > 255) { uv__set_sys_error(handle->loop, EINVAL); return -1; } @@ -556,13 +556,13 @@ static int uv__udp_set_ttl(uv_udp_t* handle, int option, int ttl) { } -int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { - return uv__udp_set_ttl(handle, IP_TTL, ttl); +int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { + return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, ttl); } -int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { - return uv__udp_set_ttl(handle, IP_MULTICAST_TTL, ttl); +int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { + return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, on); } From 74cff551d5d827587ddf8b90ee8c05541ce4ec59 Mon Sep 17 00:00:00 2001 From: Brandon Benvie Date: Sat, 28 Jan 2012 03:55:21 -0500 Subject: [PATCH 03/12] windows: fix off-by-one error in uv_fs_stat uv__is_root typo caused incorrect fs.exists results in Node. --- src/win/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index 6948f7ef..5248ac2a 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -541,7 +541,7 @@ static int uv__is_root(const wchar_t* path) { size_t len = wcslen(path); /* Test for \ */ - if (len == 0 && IS_SLASH(path[0])) { + if (len == 1 && IS_SLASH(path[0])) { return 1; } From f9b478cfd8e52aed25cb0968a753d5aef993f657 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 28 Jan 2012 16:51:05 +0100 Subject: [PATCH 04/12] test: add windows-only uv_fs_stat regression test --- test/test-fs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-fs.c b/test/test-fs.c index 1601ac44..b88636b0 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1293,6 +1293,9 @@ TEST_IMPL(fs_stat_root) { int r; uv_loop_t* loop = uv_default_loop(); + r = uv_fs_stat(loop, &stat_req, "\\", NULL); + ASSERT(r == 0); + r = uv_fs_stat(loop, &stat_req, "c:\\", NULL); ASSERT(r == 0); From 98c0498dbc00850d8d1a01c4111d143d80d96a9b Mon Sep 17 00:00:00 2001 From: isaacs Date: Mon, 30 Jan 2012 11:28:54 -0800 Subject: [PATCH 05/12] unix: Remove assert in uv__pipe_accept This assert unnecessarily prevents people from using the pipe_wrap class in node to send file descriptors over sockets. --- src/unix/pipe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 5509136a..f1be9e97 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -251,7 +251,6 @@ void uv__pipe_accept(EV_P_ ev_io* watcher, int revents) { pipe = watcher->data; assert(pipe->type == UV_NAMED_PIPE); - assert(pipe->pipe_fname != NULL); sockfd = uv__accept(pipe->fd, (struct sockaddr *)&saddr, sizeof saddr); if (sockfd == -1) { From 7b83b99fdc1734e5710742e7efc981949585a6ee Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 31 Jan 2012 14:28:04 +0100 Subject: [PATCH 06/12] Windows: try to set up vc environment when not running from vs command prompt --- vcbuild.bat | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/vcbuild.bat b/vcbuild.bat index bccefff9..644f574c 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -64,9 +64,21 @@ echo Project files generated. @rem Skip project generation if requested. if defined nobuild goto run -if not defined VCINSTALLDIR echo Build skipped. To build, this file needs to run from VS cmd prompt.& goto run +@rem If not running in the VS build env, try to start it. If that fails, bail +@rem out. +if defined VCINSTALLDIR goto msbuild-found +if not defined VS100COMNTOOLS goto msbuild-not-found +if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto msbuild-not-found +call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" +if not defined VCINSTALLDIR goto msbuild-not-found +goto msbuild-found + +:msbuild-not-found +echo Build skipped. To build, this file needs to run from VS cmd prompt. +goto run @rem Build the sln with msbuild. +:msbuild-found msbuild uv.sln /t:%target% /p:Configuration=%config% /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo if errorlevel 1 goto exit From cd16ba51867e5ee171737ec8fcef7067ce526cec Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 28 Jan 2012 02:16:00 +0100 Subject: [PATCH 07/12] test: add UDP broadcast/multicast/ttl tests --- test/test-list.h | 2 + test/test-udp-options.c | 85 +++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 3 files changed, 88 insertions(+) create mode 100644 test/test-udp-options.c diff --git a/test/test-list.h b/test/test-list.h index acc5cea9..02fabcb9 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -50,6 +50,7 @@ TEST_DECLARE (udp_multicast_join) TEST_DECLARE (udp_dgram_too_big) TEST_DECLARE (udp_dual_stack) TEST_DECLARE (udp_ipv6_only) +TEST_DECLARE (udp_options) TEST_DECLARE (pipe_bind_error_addrinuse) TEST_DECLARE (pipe_bind_error_addrnotavail) TEST_DECLARE (pipe_bind_error_inval) @@ -187,6 +188,7 @@ TASK_LIST_START TEST_ENTRY (udp_dgram_too_big) TEST_ENTRY (udp_dual_stack) TEST_ENTRY (udp_ipv6_only) + TEST_ENTRY (udp_options) TEST_ENTRY (udp_multicast_join) TEST_ENTRY (pipe_bind_error_addrinuse) diff --git a/test/test-udp-options.c b/test/test-udp-options.c new file mode 100644 index 00000000..b4745741 --- /dev/null +++ b/test/test-udp-options.c @@ -0,0 +1,85 @@ +/* Copyright Joyent, Inc. and other Node 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 +#include +#include + + +TEST_IMPL(udp_options) { + uv_loop_t* loop; + uv_udp_t h; + int i, r; + + loop = uv_default_loop(); + + r = uv_udp_init(loop, &h); + ASSERT(r == 0); + + uv_unref(loop); /* don't keep the loop alive */ + + r = uv_udp_bind(&h, uv_ip4_addr("0.0.0.0", TEST_PORT), 0); + ASSERT(r == 0); + + r = uv_udp_set_broadcast(&h, 1); + r |= uv_udp_set_broadcast(&h, 1); + r |= uv_udp_set_broadcast(&h, 0); + r |= uv_udp_set_broadcast(&h, 0); + ASSERT(r == 0); + + /* values 0-255 should work */ + for (i = 0; i <= 255; i++) { + r = uv_udp_set_ttl(&h, i); + ASSERT(r == 0); + } + + /* anything >255 should fail */ + r = uv_udp_set_ttl(&h, 256); + ASSERT(r == -1); + ASSERT(uv_last_error(loop).code == UV_EINVAL); + /* don't test ttl=-1, it's a valid value on some platforms */ + + r = uv_udp_set_multicast_loop(&h, 1); + r |= uv_udp_set_multicast_loop(&h, 1); + r |= uv_udp_set_multicast_loop(&h, 0); + r |= uv_udp_set_multicast_loop(&h, 0); + ASSERT(r == 0); + + /* values 0-255 should work */ + for (i = 0; i <= 255; i++) { + r = uv_udp_set_multicast_ttl(&h, i); + ASSERT(r == 0); + } + + /* anything >255 should fail */ + r = uv_udp_set_multicast_ttl(&h, 256); + ASSERT(r == -1); + ASSERT(uv_last_error(loop).code == UV_EINVAL); + /* don't test ttl=-1, it's a valid value on some platforms */ + + r = uv_run(loop); + ASSERT(r == 0); + + return 0; +} diff --git a/uv.gyp b/uv.gyp index dc0c0f3a..1bc9ff9b 100644 --- a/uv.gyp +++ b/uv.gyp @@ -317,6 +317,7 @@ 'test/test-tty.c', 'test/test-udp-dgram-too-big.c', 'test/test-udp-ipv6.c', + 'test/test-udp-options.c', 'test/test-udp-send-and-recv.c', 'test/test-udp-multicast-join.c', 'test/test-counters-init.c', From 45d7bd88c9df0facb3ce3dc4f7fdd24e54c8512c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 31 Jan 2012 16:50:56 +0100 Subject: [PATCH 08/12] unix: explain SO_REUSEADDR and SO_REUSEPORT --- src/unix/udp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 91f7d1a2..349bfae3 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -340,7 +340,15 @@ static int uv__bind(uv_udp_t* handle, goto out; } -#ifdef SO_REUSEPORT /* Apple's version of SO_REUSEADDR... */ + /* On the BSDs, SO_REUSEADDR lets you reuse an address that's in the TIME_WAIT + * state (i.e. was until recently tied to a socket) while SO_REUSEPORT lets + * multiple processes bind to the same address. Yes, it's something of a + * misnomer but then again, SO_REUSEADDR was already taken. + * + * None of the above applies to Linux: SO_REUSEADDR implies SO_REUSEPORT on + * Linux and hence it does not have SO_REUSEPORT at all. + */ +#ifdef SO_REUSEPORT yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) == -1) { uv__set_sys_error(handle->loop, errno); From 8c8e6532bf72def18a2827d0180b903bcee90331 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 31 Jan 2012 15:54:34 +0100 Subject: [PATCH 09/12] test-multicast-join: don't attempt to bind to a multicast address Does not work on Windows. Bind to a normal interface first, then join the multicast group instead. --- test/test-udp-multicast-join.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c index 159dba08..b32ef073 100644 --- a/test/test-udp-multicast-join.c +++ b/test/test-udp-multicast-join.c @@ -99,7 +99,7 @@ TEST_IMPL(udp_multicast_join) { int r; uv_udp_send_t req; uv_buf_t buf; - struct sockaddr_in addr = uv_ip4_addr("239.255.0.1", TEST_PORT); + struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT); r = uv_udp_init(uv_default_loop(), &server); ASSERT(r == 0); From 62d936047729dbfc7c3846a2a12c2db1c6248368 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 31 Jan 2012 15:54:17 +0100 Subject: [PATCH 10/12] Windows: enable SO_REUSEADDR for datagram sockets --- src/win/udp.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/win/udp.c b/src/win/udp.c index 0a9990a5..f1225899 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -166,9 +166,9 @@ static int uv__bind(uv_udp_t* handle, struct sockaddr* addr, int addrsize, unsigned int flags) { - DWORD err; int r; SOCKET sock; + DWORD no = 0, yes = 1; if ((flags & UV_UDP_IPV6ONLY) && domain != AF_INET6) { /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */ @@ -190,7 +190,6 @@ static int uv__bind(uv_udp_t* handle, } if (domain == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) { - DWORD off = 0; /* On windows IPV6ONLY is on by default. */ /* If the user doesn't specify it libuv turns it off. */ @@ -200,14 +199,22 @@ static int uv__bind(uv_udp_t* handle, setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - (const char*) &off, - sizeof off); + (char*) &no, + sizeof no); + } + + r = setsockopt(sock, + SOL_SOCKET, + SO_REUSEADDR, + (char*) &yes, + sizeof yes); + if (r == SOCKET_ERROR) { + uv__set_sys_error(handle->loop, WSAGetLastError()); + return -1; } r = bind(handle->socket, addr, addrsize); - if (r == SOCKET_ERROR) { - err = WSAGetLastError(); uv__set_sys_error(handle->loop, WSAGetLastError()); return -1; } From 3eb94e92f70cf8fa9657b318e11912776e77206c Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 27 Jan 2012 16:31:27 +0100 Subject: [PATCH 11/12] Implement udp multicast methods on windows uv_udp_set_membership is not supported for UDP-IPv6 sockets yet. --- src/win/udp.c | 120 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 95 insertions(+), 25 deletions(-) diff --git a/src/win/udp.c b/src/win/udp.c index f1225899..39221de6 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -251,15 +251,6 @@ int uv__udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, } -int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, - const char* interface_addr, uv_membership membership) { - - /* not implemented yet */ - uv__set_artificial_error(handle->loop, UV_ENOSYS); - return -1; -} - - static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { uv_req_t* req; uv_buf_t buf; @@ -586,16 +577,50 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, } -int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { - uv__set_artificial_error(handle->loop, UV_ENOSYS); - return -1; -} +int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, + const char* interface_addr, uv_membership membership) { + int optname; + struct ip_mreq mreq; + /* If the socket is unbound, bind to inaddr_any. */ + if (!(handle->flags & UV_HANDLE_BOUND) && + uv_udp_bind(handle, uv_addr_ip4_any_, 0) < 0) { + return -1; + } -int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { - if (setsockopt(handle->socket, IPPROTO_IP, IP_MULTICAST_TTL, - (const char*)&ttl, sizeof ttl) == -1) { - uv__set_sys_error(handle->loop, WSAGetLastError()); + if (handle->flags & UV_HANDLE_IPV6) { + uv__set_artificial_error(handle->loop, UV_ENOSYS); + return -1; + } + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + mreq.imr_interface.s_addr = inet_addr(interface_addr); + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = inet_addr(multicast_addr); + + switch (membership) { + case UV_JOIN_GROUP: + optname = IP_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IP_DROP_MEMBERSHIP; + break; + default: + uv__set_artificial_error(handle->loop, UV_EFAULT); + return -1; + } + + if (setsockopt(handle->socket, + IPPROTO_IP, + optname, + (char*) &mreq, + sizeof mreq) == SOCKET_ERROR) { + uv__set_sys_error(handle->loop, WSAGetLastError()); return -1; } @@ -603,18 +628,63 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { } -int uv_udp_set_broadcast(uv_udp_t* handle, int on) { - if (setsockopt(handle->socket, SOL_SOCKET, SO_BROADCAST, (const char*)&on, - sizeof on) == -1) { - uv__set_sys_error(handle->loop, WSAGetLastError()); +int uv_udp_set_broadcast(uv_udp_t* handle, int value) { + BOOL optval = (BOOL) value; + + /* If the socket is unbound, bind to inaddr_any. */ + if (!(handle->flags & UV_HANDLE_BOUND) && + uv_udp_bind(handle, uv_addr_ip4_any_, 0) < 0) { return -1; } + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_BROADCAST, + (char*) &optval, + sizeof optval)) { + uv__set_sys_error(handle->loop, WSAGetLastError()); + return -1; + } return 0; } -int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { - uv__set_artificial_error(handle->loop, UV_ENOSYS); - return -1; -} +#define SOCKOPT_SETTER(name, option4, option6) \ + int uv_udp_set_##name(uv_udp_t* handle, int value) { \ + DWORD optval = (DWORD) value; \ + \ + /* If the socket is unbound, bind to inaddr_any. */ \ + if (!(handle->flags & UV_HANDLE_BOUND) && \ + uv_udp_bind(handle, uv_addr_ip4_any_, 0) < 0) { \ + return -1; \ + } \ + \ + if (!(handle->flags & UV_HANDLE_IPV6)) { \ + /* Set IPv4 socket option */ \ + if (setsockopt(handle->socket, \ + IPPROTO_IP, \ + option4, \ + (char*) &optval, \ + sizeof optval)) { \ + uv__set_sys_error(handle->loop, WSAGetLastError()); \ + return -1; \ + } \ + } else { \ + /* Set IPv6 socket option */ \ + if (setsockopt(handle->socket, \ + IPPROTO_IPV6, \ + option6, \ + (char*) &optval, \ + sizeof optval)) { \ + uv__set_sys_error(handle->loop, WSAGetLastError()); \ + return -1; \ + } \ + } \ + return 0; \ + } + +SOCKOPT_SETTER(multicast_loop, IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP) +SOCKOPT_SETTER(multicast_ttl, IP_MULTICAST_TTL, IPV6_MULTICAST_HOPS) +SOCKOPT_SETTER(ttl, IP_TTL, IPV6_HOPLIMIT) + +#undef SOCKOPT_SETTER From 4cfda74de4a3901828942e9418c43a434c0accf6 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Fri, 27 Jan 2012 15:33:25 -0800 Subject: [PATCH 12/12] uv.h: add EPERM to errno map to fix regression EPERM isn't mapped in so chown returns an unknown error. This is a regression from 0.4.12. philips:node/ (master*) $ cat chown.js var fs = require('fs') fs.chown("/tmp/foobar", 100, 100, function(er){ console.log(er);}) philips:node/ (master*) $ ls -la /tmp/foobar total 0 drwxr-xr-x 2 root wheel 68 Jan 24 17:21 . 0.4 --- philips:node/ (master*) $ /usr/local/Cellar/node/0.4.12/bin/node chown.js { stack: [Getter/Setter], arguments: undefined, type: undefined, message: 'EPERM, Operation not permitted \'/tmp/foobar\'', errno: 1, code: 'EPERM', path: '/tmp/foobar' } master ------ philips:node/ (master*) $ ./node chown.js { [Error: UNKNOWN, unknown error '/tmp/foobar'] errno: -1, code: 'UNKNOWN', path: '/tmp/foobar' } AFTER ----- philips:node/ (master*) $ ./node chown.js { [Error: EPERM, operation not permitted '/tmp/foobar'] errno: 49, code: 'EPERM', path: '/tmp/foobar' } --- include/uv.h | 3 ++- src/unix/error.c | 1 + test/test-fs.c | 13 +++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index 62943527..23e5e21d 100644 --- a/include/uv.h +++ b/include/uv.h @@ -116,7 +116,8 @@ typedef intptr_t ssize_t; XX( 46, ESHUTDOWN, "") \ XX( 47, EEXIST, "file already exists") \ XX( 48, ESRCH, "no such process") \ - XX( 49, ENAMETOOLONG, "name too long") + XX( 49, ENAMETOOLONG, "name too long") \ + XX( 50, EPERM, "operation not permitted") #define UV_ERRNO_GEN(val, name, s) UV_##name = val, diff --git a/src/unix/error.c b/src/unix/error.c index 80d3270d..1d38623f 100644 --- a/src/unix/error.c +++ b/src/unix/error.c @@ -59,6 +59,7 @@ void uv_fatal_error(const int errorno, const char* syscall) { uv_err_code uv_translate_sys_error(int sys_errno) { switch (sys_errno) { case 0: return UV_OK; + case EPERM: return UV_EPERM; case ENOSYS: return UV_ENOSYS; case ENOTSOCK: return UV_ENOTSOCK; case ENOENT: return UV_ENOENT; diff --git a/test/test-fs.c b/test/test-fs.c index b88636b0..dbeb2a19 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -184,6 +184,13 @@ static void chown_cb(uv_fs_t* req) { uv_fs_req_cleanup(req); } +static void chown_root_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_CHOWN); + ASSERT(req->result == -1); + ASSERT(req->errorno == UV_EPERM); + chown_cb_count++; + uv_fs_req_cleanup(req); +} static void unlink_cb(uv_fs_t* req) { ASSERT(req == &unlink_req); @@ -1018,6 +1025,12 @@ TEST_IMPL(fs_chown) { uv_run(loop); ASSERT(chown_cb_count == 1); + /* chown to root (fail) */ + chown_cb_count = 0; + r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb); + uv_run(loop); + ASSERT(chown_cb_count == 1); + /* async fchown */ r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb); ASSERT(r == 0);