From 5a0f3411fcceefa1561d1e7b58e0df23057e7ceb Mon Sep 17 00:00:00 2001 From: Roman Neuhauser Date: Mon, 25 Jun 2012 10:55:46 +0200 Subject: [PATCH 1/7] unix: map ENODEV to UV_ENODEV produces better error message from test-dgram-multicast-multi-process when run w/o network. before: === release test-dgram-multicast-multi-process === Path: simple/test-dgram-multicast-multi-process dgram.js:287 throw new errnoException(errno, 'addMembership'); ^ Error: addMembership Unknown system errno 19 at new errnoException (dgram.js:356:11) at Socket.addMembership (dgram.js:287:11) at Object. (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.runMain (module.js:487:10) at process.startup.processNextTick.process._tickCallback (node.js:244:9) [PARENT] Worker 9223 died. 1 dead of 3 dgram.js:287 throw new errnoException(errno, 'addMembership'); ^ Error: addMembership Unknown system errno 19 at new errnoException (dgram.js:356:11) at Socket.addMembership (dgram.js:287:11) at Object. (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.runMain (module.js:487:10) at process.startup.processNextTick.process._tickCallback (node.js:244:9) [PARENT] sent 'First message to send' to 224.0.0.114:12346 dgram.js:287 [PARENT] sent 'Second message to send' to 224.0.0.114:12346 throw new errnoException(errno, 'addMembership'); [PARENT] sent 'Third message to send' to 224.0.0.114:12346 ^ [PARENT] sendSocket closed [PARENT] Worker 9224 died. 2 dead of 3 Error: addMembership Unknown system errno 19 at new errnoException (dgram.js:356:11) at Socket.addMembership (dgram.js:287:11) at Object. (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.runMain (module.js:487:10) at process.startup.processNextTick.process._tickCallback (node.js:244:9) [PARENT] Worker 9225 died. 3 dead of 3 [PARENT] All workers have died. [PARENT] Fail Command: out/Release/node /home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js after: === release test-dgram-multicast-multi-process === Path: simple/test-dgram-multicast-multi-process dgram.js:287 throw new errnoException(errno, 'addMembership'); ^ Error: addMembership ENODEV at new errnoException (dgram.js:356:11) at Socket.addMembership (dgram.js:287:11) at Object. (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.runMain (module.js:487:10) at process.startup.processNextTick.process._tickCallback (node.js:244:9) [PARENT] Worker 13141 died. 1 dead of 3 dgram.js:287 throw new errnoException(errno, 'addMembership'); ^ [PARENT] sent 'First message to send' to 224.0.0.114:12346 [PARENT] sent 'Second message to send' to 224.0.0.114:12346 [PARENT] sent 'Third message to send' to 224.0.0.114:12346 [PARENT] sent 'Fourth message to send' to 224.0.0.114:12346 [PARENT] sendSocket closed dgram.js:287 throw new errnoException(errno, 'addMembership'); ^ Error: addMembership ENODEV at new errnoException (dgram.js:356:11) at Socket.addMembership (dgram.js:287:11) at Object. (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.runMain (module.js:487:10) at process.startup.processNextTick.process._tickCallback (node.js:244:9) [PARENT] Worker 13142 died. 2 dead of 3 Error: addMembership ENODEV at new errnoException (dgram.js:356:11) at Socket.addMembership (dgram.js:287:11) at Object. (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.runMain (module.js:487:10) at process.startup.processNextTick.process._tickCallback (node.js:244:9) [PARENT] Worker 13143 died. 3 dead of 3 [PARENT] All workers have died. [PARENT] Fail Command: out/Release/node /home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js --- include/uv.h | 3 ++- src/unix/error.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index 69e0db2f8..dbea113a3 100644 --- a/include/uv.h +++ b/include/uv.h @@ -126,7 +126,8 @@ extern "C" { XX( 53, ENOTEMPTY, "directory not empty") \ XX( 54, ENOSPC, "no space left on device") \ XX( 55, EIO, "i/o error") \ - XX( 56, EROFS, "read-only file system" ) + XX( 56, EROFS, "read-only file system" ) \ + XX( 57, ENODEV, "no such device" ) #define UV_ERRNO_GEN(val, name, s) UV_##name = val, diff --git a/src/unix/error.c b/src/unix/error.c index c2651a3a9..9fbb312ee 100644 --- a/src/unix/error.c +++ b/src/unix/error.c @@ -86,6 +86,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case EADDRNOTAVAIL: return UV_EADDRNOTAVAIL; case ENOTDIR: return UV_ENOTDIR; case EISDIR: return UV_EISDIR; + case ENODEV: return UV_ENODEV; case ENOTCONN: return UV_ENOTCONN; case EEXIST: return UV_EEXIST; case EHOSTUNREACH: return UV_EHOSTUNREACH; From 4d42af20e389fa3c3fa63dcd57883071421d25b8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 26 Jun 2012 18:25:54 +0200 Subject: [PATCH 2/7] unix: don't create connect req when connect() fails Fixes a lifecycle issue where the req got created, added to the list of active reqs but wasn't properly activated because uv__connect() returned early. --- src/unix/stream.c | 71 ++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 89790eabf..8c33ee09c 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -802,62 +802,51 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr, int sockfd; int r; + if (stream->type != UV_TCP) + return uv__set_sys_error(stream->loop, ENOTSOCK); + + if (stream->connect_req) + return uv__set_sys_error(stream->loop, EALREADY); + if (stream->fd <= 0) { - if ((sockfd = uv__socket(addr->sa_family, SOCK_STREAM, 0)) == -1) { - uv__set_sys_error(stream->loop, errno); - return -1; - } + sockfd = uv__socket(addr->sa_family, SOCK_STREAM, 0); + + if (sockfd == -1) + return uv__set_sys_error(stream->loop, errno); if (uv__stream_open(stream, sockfd, UV_STREAM_READABLE | UV_STREAM_WRITABLE)) { close(sockfd); - return -2; + return -1; } } + stream->delayed_error = 0; + + do + r = connect(stream->fd, addr, addrlen); + while (r == -1 && errno == EINTR); + + if (r == -1) { + if (errno == EINPROGRESS) + ; /* not an error */ + else if (errno == ECONNREFUSED) + /* If we get a ECONNREFUSED wait until the next tick to report the + * error. Solaris wants to report immediately--other unixes want to + * wait. + */ + stream->delayed_error = errno; + else + return uv__set_sys_error(stream->loop, errno); + } + uv__req_init(stream->loop, req, UV_CONNECT); req->cb = cb; req->handle = stream; ngx_queue_init(&req->queue); - - if (stream->connect_req) { - uv__set_sys_error(stream->loop, EALREADY); - return -1; - } - - if (stream->type != UV_TCP) { - uv__set_sys_error(stream->loop, ENOTSOCK); - return -1; - } - stream->connect_req = req; - do { - r = connect(stream->fd, addr, addrlen); - } - while (r == -1 && errno == EINTR); - - stream->delayed_error = 0; - - if (r != 0 && errno != EINPROGRESS) { - switch (errno) { - /* If we get a ECONNREFUSED wait until the next tick to report the - * error. Solaris wants to report immediately--other unixes want to - * wait. - * - * XXX: do the same for ECONNABORTED? - */ - case ECONNREFUSED: - stream->delayed_error = errno; - break; - - default: - uv__set_sys_error(stream->loop, errno); - return -1; - } - } - uv__io_start(stream->loop, &stream->write_watcher); if (stream->delayed_error) From 1b6843482a3c9834b82b138e8823bc3dae5c7d2d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 28 Jun 2012 01:35:45 +0200 Subject: [PATCH 3/7] unix: assume that dlopen() clobbers dlerror() Or rather, don't assume that dlopen() does *not* clobber dlerror(). Joe Ferner reports that loading libjava on OS X sets dlerror() even when dlopen() succeeds, which makes uv_dlopen() raise an error when it shouldn't. I haven't been able to reproduce it but it's possible that libjava clobbers dlerror() by trying (and failing) to load other libraries. At any rate, Joe confirmed that this patch addresses the issue. Fixes #462. --- src/unix/dl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/dl.c b/src/unix/dl.c index 01796e3b8..9cc830b81 100644 --- a/src/unix/dl.c +++ b/src/unix/dl.c @@ -34,7 +34,7 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) { dlerror(); /* Reset error status. */ lib->errmsg = NULL; lib->handle = dlopen(filename, RTLD_LAZY); - return uv__dlerror(lib); + return lib->handle ? 0 : uv__dlerror(lib); } From 4a88b3b4b72de79d8a6f3107a200f6f960f475a7 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 28 Jun 2012 05:07:18 +0200 Subject: [PATCH 4/7] windows: don't inhibit reparse behavior when non-symlink is encountered This fixes the issue that a mount point would be treated as a symlink, but readlink would subsequently return an NT namespaced path that is unusable for many purposes. This also pre-emptively fixes the problems that would arise when an user has a reparse point whose tag is neither IO_REPARSE_TAG_MOUNT_POINT nor IO_REPARSE_TAG_SYMLINK. Finally uv_lstat() will now return the correct length in st_size. Previously the length was computed incorrectly for relative symlinks, and those that had non-ascii characters in their target. --- src/win/error.c | 2 + src/win/fs.c | 312 ++++++++++++++++++++++++++---------------------- 2 files changed, 168 insertions(+), 146 deletions(-) diff --git a/src/win/error.c b/src/win/error.c index d7c4d5333..6490547dc 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -83,6 +83,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case ERROR_SIGNAL_REFUSED: return UV_EIO; case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_INVALID_NAME: return UV_ENOENT; + case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT; case ERROR_MOD_NOT_FOUND: return UV_ENOENT; case ERROR_PATH_NOT_FOUND: return UV_ENOENT; case ERROR_ACCESS_DENIED: return UV_EPERM; @@ -111,6 +112,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case ERROR_OPERATION_ABORTED: return UV_EINTR; case WSAEINTR: return UV_EINTR; case ERROR_INVALID_DATA: return UV_EINVAL; + case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL; case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP; case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; diff --git a/src/win/fs.c b/src/win/fs.c index 64fc2939f..7d6b4f9d9 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -161,47 +161,147 @@ static int is_path_dir(const wchar_t* path) { } -static int get_reparse_point(HANDLE handle, int* target_length) { - void* buffer = NULL; - REPARSE_DATA_BUFFER* reparse_data; - DWORD bytes_returned; - int rv = 0; - - buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - if (!buffer) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } +INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, + int64_t* target_len_ptr) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; + WCHAR *w_target; + DWORD w_target_len; + char* target; + int target_len; + DWORD bytes; if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, - &bytes_returned, + sizeof buffer, + &bytes, NULL)) { - free(buffer); - return 0; + return -1; } - reparse_data = (REPARSE_DATA_BUFFER*)buffer; - if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { - rv = 1; - if (target_length) { - *target_length = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / - sizeof(wchar_t); + /* Real symlink */ + w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR)); + w_target_len = + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(WCHAR); + + /* Real symlinks can contain pretty much everything, but the only thing */ + /* we really care about is undoing the implicit conversion to an NT */ + /* namespaced path that CreateSymbolicLink will perform on absolute */ + /* paths. If the path is win32-namespaced then the user must have */ + /* explicitly made it so, and we better just return the unmodified */ + /* reparse data. */ + if (w_target_len >= 4 && + w_target[0] == L'\\' && + w_target[1] == L'?' && + w_target[2] == L'?' && + w_target[3] == L'\\') { + /* Starts with \??\ */ + if (w_target_len >= 6 && + ((w_target[4] >= L'A' && w_target[4] <= L'Z') || + (w_target[4] >= L'a' && w_target[4] <= L'z')) && + w_target[5] == L':' && + (w_target_len == 6 || w_target[6] == L'\\')) { + /* \??\«drive»:\ */ + w_target += 4; + w_target_len -= 4; + + } else if (w_target_len >= 8 && + (w_target[4] == L'U' || w_target[4] == L'u') && + (w_target[5] == L'N' || w_target[5] == L'n') && + (w_target[6] == L'C' || w_target[6] == L'c') && + w_target[7] == L'\\') { + /* \??\UNC\«server»\«share»\ - make sure the final path looks like */ + /* \\«server»\«share»\ */ + w_target += 6; + w_target[0] = L'\\'; + w_target_len -= 6; + } } + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { - rv = 1; - if (target_length) { - *target_length = reparse_data->MountPointReparseBuffer.SubstituteNameLength / + /* Junction. */ + w_target = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR)); + w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + + /* Only treat junctions that look like \??\«drive»:\ as symlink. */ + /* Junctions can also be used as mount points, like \??\Volume{«guid»}, */ + /* but that's confusing for programs since they wouldn't be able to */ + /* actually understand such a path when returned by uv_readlink(). */ + /* UNC paths are never valid for junctions so we don't care about them. */ + if (!(w_target_len >= 6 && + w_target[0] == L'\\' && + w_target[1] == L'?' && + w_target[2] == L'?' && + w_target[3] == L'\\' && + ((w_target[4] >= L'A' && w_target[4] <= L'Z') || + (w_target[4] >= L'a' && w_target[4] <= L'z')) && + w_target[5] == L':' && + (w_target_len == 6 || w_target[6] == L'\\'))) { + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; } + + /* Remove leading \??\ */ + w_target += 4; + w_target_len -= 4; + + } else { + /* Reparse tag does not indicate a symlink. */ + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; } - free(buffer); - return rv; + /* Compute the length of the target. */ + target_len = WideCharToMultiByte(CP_UTF8, + 0, + w_target, + w_target_len, + NULL, + 0, + NULL, + NULL); + if (target_len == 0) { + return -1; + } + + /* If requested, allocate memory and convert to UTF8. */ + if (target_ptr != NULL) { + int r; + target = (char*) malloc(target_len + 1); + if (target == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + + r = WideCharToMultiByte(CP_UTF8, + 0, + w_target, + w_target_len, + target, + target_len, + NULL, + NULL); + assert(r == target_len); + target[target_len] = '\0'; + + *target_ptr = target; + } + + if (target_len_ptr != NULL) { + *target_len_ptr = target_len; + } + + return 0; } @@ -455,11 +555,12 @@ void fs__unlink(uv_fs_t* req, const wchar_t* path) { return; } - is_dir_symlink = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && - get_reparse_point(handle, NULL); + is_dir_symlink = (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT); CloseHandle(handle); + /* Todo: very inefficient; fix this. */ if (is_dir_symlink) { fs__rmdir(req, path); } else { @@ -583,7 +684,6 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) { INLINE static int fs__stat_handle(HANDLE handle, uv_statbuf_t* statbuf) { - int target_length; BY_HANDLE_FILE_INFORMATION info; if (!GetFileInformationByHandle(handle, &info)) { @@ -600,28 +700,25 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_statbuf_t* statbuf) { statbuf->st_mode = 0; - if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && - get_reparse_point(handle, &target_length)) { - statbuf->st_mode = S_IFLNK; - /* Adjust for long path */ - statbuf->st_size = target_length - JUNCTION_PREFIX_LEN; + if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) { + return -1; + } + statbuf->st_mode |= S_IFLNK; + } else if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + statbuf->st_mode |= _S_IFDIR; + statbuf->st_size = 0; } else { - if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - statbuf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); - } else { - statbuf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + - ((_S_IREAD|_S_IWRITE) >> 6)); - } - - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - statbuf->st_mode |= _S_IFDIR; - } else { - statbuf->st_mode |= _S_IFREG; - } - + statbuf->st_mode |= _S_IFREG; statbuf->st_size = ((int64_t) info.nFileSizeHigh << 32) + (int64_t) info.nFileSizeLow; + } + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + statbuf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); + } else { + statbuf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + + ((_S_IREAD|_S_IWRITE) >> 6)); } statbuf->st_mtime = FILETIME_TO_TIME_T(info.ftLastWriteTime); @@ -659,7 +756,16 @@ INLINE static void fs__stat(uv_fs_t* req, const wchar_t* path, int do_lstat) { } if (fs__stat_handle(handle, &req->stat) != 0) { - SET_REQ_WIN32_ERROR(req, GetLastError()); + DWORD error = GetLastError(); + if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) { + /* We opened a reparse point but it was not a symlink. Try again. */ + fs__stat(req, path, 0); + + } else { + /* Stat failed. */ + SET_REQ_WIN32_ERROR(req, GetLastError()); + } + CloseHandle(handle); return; } @@ -1099,117 +1205,31 @@ void fs__symlink(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path, void fs__readlink(uv_fs_t* req, const wchar_t* path) { - int result = -1; - BOOL rv; - HANDLE symlink; - void* buffer = NULL; - DWORD bytes_returned; - REPARSE_DATA_BUFFER* reparse_data; - int utf8size; - wchar_t* substitute_name; - int substitute_name_length; + HANDLE handle; - symlink = CreateFileW(path, - 0, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, - NULL); - - if (INVALID_HANDLE_VALUE == symlink) { - result = -1; - SET_REQ_WIN32_ERROR(req, GetLastError()); - goto done; - } - - buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - if (!buffer) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - - rv = DeviceIoControl(symlink, - FSCTL_GET_REPARSE_POINT, - NULL, + handle = CreateFileW(path, 0, - buffer, - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, - &bytes_returned, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (!rv) { - result = -1; + if (handle == INVALID_HANDLE_VALUE) { SET_REQ_WIN32_ERROR(req, GetLastError()); - goto done; + return; } - reparse_data = (REPARSE_DATA_BUFFER*)buffer; - if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { - substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + - (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / - sizeof(wchar_t)); - substitute_name_length = - reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / - sizeof(wchar_t); - } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { - substitute_name = reparse_data->MountPointReparseBuffer.PathBuffer + - (reparse_data->MountPointReparseBuffer.SubstituteNameOffset / - sizeof(wchar_t)); - substitute_name_length = - reparse_data->MountPointReparseBuffer.SubstituteNameLength / - sizeof(wchar_t); - } else { - result = -1; - /* something is seriously wrong */ + if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) { SET_REQ_WIN32_ERROR(req, GetLastError()); - goto done; - } - - /* Strip off the leading \??\ from the substitute name buffer.*/ - if (wcsncmp(substitute_name, JUNCTION_PREFIX, JUNCTION_PREFIX_LEN) == 0) { - substitute_name += JUNCTION_PREFIX_LEN; - substitute_name_length -= JUNCTION_PREFIX_LEN; - } - - utf8size = uv_utf16_to_utf8(substitute_name, - substitute_name_length, - NULL, - 0); - if (!utf8size) { - result = -1; - SET_REQ_WIN32_ERROR(req, GetLastError()); - goto done; - } - - req->ptr = malloc(utf8size + 1); - if (!req->ptr) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - - utf8size = uv_utf16_to_utf8(substitute_name, - substitute_name_length, - (char*)req->ptr, - utf8size); - if (!utf8size) { - result = -1; - SET_REQ_WIN32_ERROR(req, GetLastError()); - goto done; + CloseHandle(handle); + return; } req->flags |= UV_FS_FREE_PTR; - ((char*)req->ptr)[utf8size] = '\0'; - result = 0; + SET_REQ_RESULT(req, 0); -done: - if (buffer) { - free(buffer); - } - - if (symlink != INVALID_HANDLE_VALUE) { - CloseHandle(symlink); - } - - SET_REQ_RESULT(req, result); + CloseHandle(handle); } From 27cd5f03ef26b32b0043ae67bb2dae9dabda60bf Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 29 Jun 2012 02:11:38 +0200 Subject: [PATCH 5/7] linux: fix accept4() ENOSYS detection on i386 accept4() piggybacks on the socketcall() on i386. socketcall() has the flaw that it returns EINVAL instead of ENOSYS when the operation is not supported. The problem is that accept4() also returns EINVAL when its flag argument is invalid. Try to discern between the two failure cases to the best of our abilities. --- src/unix/linux/syscalls.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/unix/linux/syscalls.c b/src/unix/linux/syscalls.c index 5eb826b7c..cbf2bbbde 100644 --- a/src/unix/linux/syscalls.c +++ b/src/unix/linux/syscalls.c @@ -152,13 +152,25 @@ int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { #if __i386__ - unsigned long args[] = { - (unsigned long) fd, - (unsigned long) addr, - (unsigned long) addrlen, - (unsigned long) flags - }; - return syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); + unsigned long args[4]; + int r; + + args[0] = (unsigned long) fd; + args[1] = (unsigned long) addr; + args[2] = (unsigned long) addrlen; + args[3] = (unsigned long) flags; + + r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); + + /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does + * a bad flags argument. Try to distinguish between the two cases. + */ + if (r == -1) + if (errno == EINVAL) + if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0) + errno = ENOSYS; + + return r; #elif __NR_accept4 return syscall(__NR_accept4, fd, addr, addrlen, flags); #else From f6a02fbe763aec5d290aa9d9509aeec5348c7792 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 29 Jun 2012 02:23:39 +0200 Subject: [PATCH 6/7] linux: don't use accept4() syscall after ENOSYS Repeatedly calling the syscall when it's not supported has a small but measurable performance impact. Besides, it's a silly thing to do. --- src/unix/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/unix/core.c b/src/unix/core.c index 318eb7184..bf4299486 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -426,6 +426,11 @@ int uv__accept(int sockfd) { while (1) { #if __linux__ + static int no_accept4; + + if (no_accept4) + goto skip; + peerfd = uv__accept4(sockfd, NULL, NULL, @@ -439,6 +444,9 @@ int uv__accept(int sockfd) { if (errno != ENOSYS) break; + + no_accept4 = 1; +skip: #endif peerfd = accept(sockfd, NULL, NULL); From 5b8a1127fedb80a282f2587f6b0ccae2b591ff36 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 28 Jun 2012 19:01:34 +0200 Subject: [PATCH 7/7] darwin: compile at -O0 in debug builds --- common.gypi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common.gypi b/common.gypi index c2df528f2..79306a755 100644 --- a/common.gypi +++ b/common.gypi @@ -32,6 +32,9 @@ 'LinkIncremental': 2, # enable incremental linking }, }, + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '0', + }, 'conditions': [ ['OS != "win"', { 'defines': [ 'EV_VERIFY=2' ],