From 24e6c7ec86a3b4c73a4ef76924ff35ec0b02c066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Ma=C5=82ecki?= Date: Sun, 22 Jan 2012 02:01:54 +0100 Subject: [PATCH 01/10] unix: map `ENAMETOOLONG` to `UV_ENAMETOOLONG` With tests. Closes #295 --- include/uv.h | 3 ++- src/unix/error.c | 1 + test/test-fs.c | 36 +++++++++++++++++++++++++++++++++++- test/test-list.h | 2 ++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/uv.h b/include/uv.h index fb4e40ab..f4ff6a3a 100644 --- a/include/uv.h +++ b/include/uv.h @@ -115,7 +115,8 @@ typedef intptr_t ssize_t; XX( 45, EAISOCKTYPE, "") \ XX( 46, ESHUTDOWN, "") \ XX( 47, EEXIST, "file already exists") \ - XX( 48, ESRCH, "no such process") + XX( 48, ESRCH, "no such process") \ + XX( 49, ENAMETOOLONG, "name too long") #define UV_ERRNO_GEN(val, name, s) UV_##name = val, diff --git a/src/unix/error.c b/src/unix/error.c index e904d390..80d3270d 100644 --- a/src/unix/error.c +++ b/src/unix/error.c @@ -71,6 +71,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case EFAULT: return UV_EFAULT; case EMFILE: return UV_EMFILE; case EMSGSIZE: return UV_EMSGSIZE; + case ENAMETOOLONG: return UV_ENAMETOOLONG; case EINVAL: return UV_EINVAL; case ECONNREFUSED: return UV_ECONNREFUSED; case EADDRINUSE: return UV_EADDRINUSE; diff --git a/test/test-fs.c b/test/test-fs.c index 763af8a7..b8e0ee65 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -45,6 +45,7 @@ # define close _close #endif +#define TOO_LONG_NAME_LENGTH 8192 typedef struct { const char* path; @@ -416,6 +417,14 @@ static void open_noent_cb(uv_fs_t* req) { uv_fs_req_cleanup(req); } +static void open_nametoolong_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_OPEN); + ASSERT(req->errorno == UV_ENAMETOOLONG); + ASSERT(req->result == -1); + open_cb_count++; + uv_fs_req_cleanup(req); +} + TEST_IMPL(fs_file_noent) { uv_fs_t req; @@ -441,6 +450,31 @@ TEST_IMPL(fs_file_noent) { return 0; } +TEST_IMPL(fs_file_nametoolong) { + uv_fs_t req; + int r; + + loop = uv_default_loop(); + + char name[TOO_LONG_NAME_LENGTH + 1]; + memset(name, 'a', TOO_LONG_NAME_LENGTH); + name[TOO_LONG_NAME_LENGTH] = 0; + + r = uv_fs_open(loop, &req, name, O_RDONLY, 0, NULL); + ASSERT(r == -1); + ASSERT(req.result == -1); + ASSERT(uv_last_error(loop).code == UV_ENAMETOOLONG); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, name, O_RDONLY, 0, open_nametoolong_cb); + ASSERT(r == 0); + + ASSERT(open_cb_count == 0); + uv_run(loop); + ASSERT(open_cb_count == 1); + + return 0; +} static void check_utime(const char* path, double atime, double mtime) { struct stat* s; @@ -1543,4 +1577,4 @@ TEST_IMPL(fs_rename_to_existing_file) { unlink("test_file2"); return 0; -} \ No newline at end of file +} diff --git a/test/test-list.h b/test/test-list.h index 5ff16230..fa9390f9 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -103,6 +103,7 @@ TEST_DECLARE (spawn_and_kill) TEST_DECLARE (spawn_and_ping) TEST_DECLARE (kill) TEST_DECLARE (fs_file_noent) +TEST_DECLARE (fs_file_nametoolong) TEST_DECLARE (fs_file_async) TEST_DECLARE (fs_file_sync) TEST_DECLARE (fs_async_dir) @@ -269,6 +270,7 @@ TASK_LIST_START #endif TEST_ENTRY (fs_file_noent) + TEST_ENTRY (fs_file_nametoolong) TEST_ENTRY (fs_file_async) TEST_ENTRY (fs_file_sync) TEST_ENTRY (fs_async_dir) From 3ade5f0011b145e2a2fa9713cba756b89569f6ae Mon Sep 17 00:00:00 2001 From: Brandon Benvie Date: Sat, 21 Jan 2012 12:04:21 -0500 Subject: [PATCH 02/10] Windows: Add support for interpreting axiterm-style colors. --- src/win/tty.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index 88c68954..e61fc7e2 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -1069,12 +1069,25 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { bg_bright = 0; } else if (arg == 1) { - /* Bright */ + /* Foreground bright on */ fg_bright = 1; - } else if (arg == 21 || arg == 22) { - /* Bright off. */ + } else if (arg == 2) { + /* Both bright off */ fg_bright = 0; + bg_bright = 0; + + } else if (arg == 5) { + /* Background bright on */ + bg_bright = 1; + + } else if (arg == 21 || arg == 22) { + /* Foreground bright off */ + fg_bright = 0; + + } else if (arg == 25) { + /* Background bright off */ + bg_bright = 0; } else if (arg >= 30 && arg <= 37) { /* Set foreground color */ @@ -1091,6 +1104,17 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { } else if (arg == 49) { /* Default background color */ bg_color = 0; + + } else if (arg >= 90 && arg <= 97) { + /* Set bold foreground color */ + fg_bright = 1; + fg_color = arg - 90; + + } else if (arg >= 100 && arg <= 107) { + /* Set bold background color */ + bg_bright = 1; + bg_color = arg - 100; + } } From 6554954e3e00d8d308ba980ec50ad5737f119e51 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 23 Jan 2012 20:21:56 +0100 Subject: [PATCH 03/10] Windows: add error mapping for WSAENOBUFS --- src/win/error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/error.c b/src/win/error.c index 12ce4d1b..59c9ea83 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -94,6 +94,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case WSAEMSGSIZE: return UV_EMSGSIZE; case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; case WSAENETUNREACH: return UV_ENETUNREACH; + case WSAENOBUFS: return UV_ENOBUFS; case ERROR_OUTOFMEMORY: return UV_ENOMEM; case ERROR_NOT_CONNECTED: return UV_ENOTCONN; case WSAENOTCONN: return UV_ENOTCONN; From 02b41f63dc1820928f925a7701d84e3426776263 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 23 Jan 2012 20:20:29 +0100 Subject: [PATCH 04/10] Add missing UV_EXTERN declarations in uv.h --- include/uv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uv.h b/include/uv.h index f4ff6a3a..4a8e5008 100644 --- a/include/uv.h +++ b/include/uv.h @@ -643,7 +643,7 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, * Returns: * 0 on success, -1 on error. */ -int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); +UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); /* * Set broadcast on or off @@ -656,7 +656,7 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); * Returns: * 0 on success, -1 on error. */ -int uv_udp_set_broadcast(uv_udp_t* handle, int on); +UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); /* * Send data. If the socket has not previously been bound with `uv_udp_bind` From e710fdb518bdb17335cd3f71f1f922c23234f591 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 23 Jan 2012 20:41:23 +0100 Subject: [PATCH 05/10] unix: implement uv_udp_set_ttl() --- include/uv.h | 13 +++++++++++++ src/unix/udp.c | 10 ++++++++++ src/win/udp.c | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/include/uv.h b/include/uv.h index 4a8e5008..f4093ff7 100644 --- a/include/uv.h +++ b/include/uv.h @@ -658,6 +658,19 @@ UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); */ UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); +/* + * Set the time to live + * + * Arguments: + * handle UDP handle. Should have been initialized with + * `uv_udp_init`. + * ttl 1 through 255 + * + * Returns: + * 0 on success, -1 on error. + */ +UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl); + /* * Send data. If the socket has not previously been bound with `uv_udp_bind` * or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address) diff --git a/src/unix/udp.c b/src/unix/udp.c index 0ebfe707..26e5f42d 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -528,6 +528,16 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int on) { } +int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { + if (setsockopt(handle->fd, IPPROTO_IP, IP_TTL, &ttl, sizeof ttl)) { + uv__set_sys_error(handle->loop, errno); + return -1; + } + + return 0; +} + + int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) { socklen_t socklen; diff --git a/src/win/udp.c b/src/win/udp.c index 8a36396b..359dce0a 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -599,3 +599,9 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int on) { return 0; } + + +int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { + uv__set_artificial_error(handle->loop, UV_ENOSYS); + return -1; +} From b88bc43543889ac53967ccdb9a6e8338e70c3e14 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 23 Jan 2012 20:57:12 +0100 Subject: [PATCH 06/10] unix: implement uv_udp_set_multicast_loop() --- include/uv.h | 14 ++++++++++++++ src/unix/udp.c | 40 ++++++++++++++-------------------------- src/win/udp.c | 6 ++++++ 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/include/uv.h b/include/uv.h index f4093ff7..62943527 100644 --- a/include/uv.h +++ b/include/uv.h @@ -632,6 +632,20 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership); +/* + * Set IP multicast loop flag. Makes multicast packets loop back to + * local sockets. + * + * Arguments: + * handle UDP handle. Should have been initialized with + * `uv_udp_init`. + * on 1 for on, 0 for off + * + * Returns: + * 0 on success, -1 on error. + */ +UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); + /* * Set the multicast ttl * diff --git a/src/unix/udp.c b/src/unix/udp.c index 26e5f42d..3e5de929 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -509,37 +509,25 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, return 0; } -int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { - if (setsockopt(handle->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof ttl) == -1) { - uv__set_sys_error(handle->loop, errno); - return -1; + +#define X(name, level, option) \ + int uv_udp_set_##name(uv_udp_t* handle, int flag) { \ + if (setsockopt(handle->fd, level, option, &flag, sizeof(flag))) { \ + uv__set_sys_error(handle->loop, errno); \ + return -1; \ + } \ + return 0; \ } - return 0; -} +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) -int uv_udp_set_broadcast(uv_udp_t* handle, int on) { - if (setsockopt(handle->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof on) == -1) { - uv__set_sys_error(handle->loop, errno); - return -1; - } - - return 0; -} +#undef X -int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { - if (setsockopt(handle->fd, IPPROTO_IP, IP_TTL, &ttl, sizeof ttl)) { - uv__set_sys_error(handle->loop, errno); - return -1; - } - - return 0; -} - - -int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, - int* namelen) { +int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) { socklen_t socklen; int saved_errno; int rv = 0; diff --git a/src/win/udp.c b/src/win/udp.c index 359dce0a..0a9990a5 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -579,6 +579,12 @@ 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_multicast_ttl(uv_udp_t* handle, int ttl) { if (setsockopt(handle->socket, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof ttl) == -1) { From 9c76d0d74218575c3898ec2e12311800c54c4adc Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 27 Jan 2012 00:31:13 +0100 Subject: [PATCH 07/10] unix: turn on SO_REUSEPORT for UDP sockets Required on BSD-like systems for local UDP multicast. Without it, the bind() call fails with EADDRINUSE. --- src/unix/udp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/unix/udp.c b/src/unix/udp.c index 3e5de929..6db0ea10 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -340,6 +340,14 @@ static int uv__bind(uv_udp_t* handle, goto out; } +#ifdef SO_REUSEPORT /* Apple's version of SO_REUSEADDR... */ + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) == -1) { + uv__set_sys_error(handle->loop, errno); + goto out; + } +#endif + if (flags & UV_UDP_IPV6ONLY) { #ifdef IPV6_V6ONLY yes = 1; From f9252750e739196090ad06e9b178ad84be24c70f Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 27 Jan 2012 16:29:57 +0100 Subject: [PATCH 08/10] Fix windows build --- test/test-fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index b8e0ee65..7e8f73b9 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -453,10 +453,10 @@ TEST_IMPL(fs_file_noent) { TEST_IMPL(fs_file_nametoolong) { uv_fs_t req; int r; + char name[TOO_LONG_NAME_LENGTH + 1]; loop = uv_default_loop(); - char name[TOO_LONG_NAME_LENGTH + 1]; memset(name, 'a', TOO_LONG_NAME_LENGTH); name[TOO_LONG_NAME_LENGTH] = 0; From 92b260c0654d4b1524271a8ae0f24922445df182 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 27 Jan 2012 18:15:10 +0100 Subject: [PATCH 09/10] windows: fix stat("c:\\") regression --- src/win/fs.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++- test/test-fs.c | 14 ++++++ test/test-list.h | 2 + 3 files changed, 138 insertions(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index d7087b1f..6948f7ef 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -489,6 +489,103 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) { } +#define IS_SLASH(c) \ + ((wchar_t) c == L'/' || (wchar_t) c == L'\\') +#define IS_COLON(c) \ + ((wchar_t) c == L':') +#define IS_LETTER(c) \ + ((((wchar_t) c >= L'a') && ((wchar_t) c <= L'z')) || \ + (((wchar_t) c >= L'A') && ((wchar_t) c <= L'Z'))) +#define IS_QUESTION(c) \ + ((wchar_t) c == L'?') + + +static int uv__count_slash_separated_words(const wchar_t* pos, + const wchar_t* end, + int limit) { + char last_was_slash = 1, count = 0; + + for (; pos < end; pos++) { + if (IS_SLASH(*pos)) { + /* Don't accept double slashes */ + if (last_was_slash) { + return 0; + } else { + last_was_slash = 1; + } + } else { + if (last_was_slash) { + /* Found a new word */ + count++; + if (count > limit) { + return -1; + } + last_was_slash = 0; + } + } + } + + return count; +} + +/* + * Returns true if the given path is a root directory. The following patterns + * are recognized: + * \ + * c:\ (must have trailing slash) + * \\server\share (trailing slash optional) + * \\?\c: (trailing slash optional) + * \\?\UNC\server\share (trailing slash optional) + */ +static int uv__is_root(const wchar_t* path) { + size_t len = wcslen(path); + + /* Test for \ */ + if (len == 0 && IS_SLASH(path[0])) { + return 1; + } + + if (len < 3) { + return 0; + } + + /* Test for c:\ */ + if (IS_LETTER(path[0]) && IS_COLON(path[1]) && IS_SLASH(path[2])) { + return 1; + } + + if (!IS_SLASH(path[0]) || !IS_SLASH(path[1])) { + return 0; + } + + /* Test for \\server\share */ + if (!IS_QUESTION(path[2])) { + return uv__count_slash_separated_words(path + 2, path + len, 2) == 2; + } + + if (!IS_SLASH(path[3])) { + return 0; + } + + if ((len == 6 || len == 7) && + IS_LETTER(path[4]) && IS_COLON(path[5]) && + (len == 6 || IS_SLASH(path[6]))) { + return 1; + } + + /* Test for \\?\UNC\server\share */ + if (len >= 8 && + (path[4] == L'u' || path[4] == L'U') && + (path[5] == L'n' || path[5] == L'N') && + (path[6] == L'c' || path[6] == L'C') && + IS_SLASH(path[7])) { + return uv__count_slash_separated_words(path + 8, path + len, 2) == 2; + } + + return 0; +} + + void fs__stat(uv_fs_t* req, const wchar_t* path) { HANDLE file; WIN32_FIND_DATAW ent; @@ -496,6 +593,30 @@ void fs__stat(uv_fs_t* req, const wchar_t* path) { req->ptr = NULL; + if (uv__is_root(path)) { + /* We can't stat root directories like c:\. _wstati64 can't either, but */ + /* it will make up something reasonable. */ + DWORD drive_type = GetDriveTypeW(path); + if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) { + req->last_error = ERROR_PATH_NOT_FOUND; + req->errorno = UV_ENOENT; + req->result = -1; + return; + } + + memset(&req->stat, 0, sizeof req->stat); + + req->stat.st_nlink = 1; + req->stat.st_mode = ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + + ((_S_IREAD|_S_IWRITE) >> 6)) | S_IFDIR; + + req->last_error = ERROR_SUCCESS; + req->errorno = UV_OK; + req->result = 0; + req->ptr = &req->stat; + return; + } + file = FindFirstFileExW(path, FindExInfoStandard, &ent, FindExSearchNameMatch, NULL, 0); @@ -516,7 +637,7 @@ void fs__stat(uv_fs_t* req, const wchar_t* path) { if (result != -1) { req->ptr = &req->stat; } - + SET_REQ_RESULT(req, result); } diff --git a/test/test-fs.c b/test/test-fs.c index 7e8f73b9..0fd1a134 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1288,6 +1288,20 @@ TEST_IMPL(fs_utime) { } +#ifdef _WIN32 +TEST_IMPL(fs_stat_root) { + int r; + uv_loop_t* loop = uv_default_loop(); + + r = uv_fs_stat(loop, &stat_req, "c:\\", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "\\\\?\\C:\\", NULL); + ASSERT(r == 0); +} +#endif + + TEST_IMPL(fs_futime) { utime_check_t checkme; const char* path = "test_file"; diff --git a/test/test-list.h b/test/test-list.h index fa9390f9..acc5cea9 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -134,6 +134,7 @@ TEST_DECLARE (argument_escaping) TEST_DECLARE (environment_creation) TEST_DECLARE (listen_with_simultaneous_accepts) TEST_DECLARE (listen_no_simultaneous_accepts) +TEST_DECLARE (fs_stat_root) #endif HELPER_DECLARE (tcp4_echo_server) HELPER_DECLARE (tcp6_echo_server) @@ -267,6 +268,7 @@ TASK_LIST_START TEST_ENTRY (environment_creation) TEST_ENTRY (listen_with_simultaneous_accepts) TEST_ENTRY (listen_no_simultaneous_accepts) + TEST_ENTRY (fs_stat_root) #endif TEST_ENTRY (fs_file_noent) From 3f1bad205051b11368191a4c085c76782c4ab4b4 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 27 Jan 2012 22:04:46 +0100 Subject: [PATCH 10/10] test: add missing return statement in fs_stat_root --- test/test-fs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-fs.c b/test/test-fs.c index 0fd1a134..1601ac44 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1298,6 +1298,8 @@ TEST_IMPL(fs_stat_root) { r = uv_fs_stat(loop, &stat_req, "\\\\?\\C:\\", NULL); ASSERT(r == 0); + + return 0; } #endif