From: Ryan Dahl Date: Sun, 4 Sep 2011 23:13:03 +0000 (-0700) Subject: Upgrade libuv to 142a702 X-Git-Tag: v0.5.6~45 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=17021ea631dc1eb249f22035a79b7e63402dfa8c;p=platform%2Fupstream%2Fnodejs.git Upgrade libuv to 142a702 --- diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index 840d3a7..f871a47 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -1,5 +1,6 @@ { 'variables': { + 'visibility%': 'hidden', # V8's visibility setting 'target_arch%': 'ia32', # set v8's target architecture 'host_arch%': 'ia32', # set v8's host architecture 'library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds @@ -87,6 +88,11 @@ 'DataExecutionPrevention': 2, # enable DEP 'AllowIsolation': 'true', 'SuppressStartupBanner': 'true', + 'target_conditions': [ + ['_type=="executable"', { + 'SubSystem': 1, # console executable + }], + ], }, }, 'conditions': [ @@ -103,61 +109,55 @@ ], }], [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { - 'target_defaults': { - 'cflags': [ '-Wall', '-pthread', '-fno-rtti', '-fno-exceptions' ], - 'ldflags': [ '-pthread', ], - 'conditions': [ - [ 'target_arch=="ia32"', { - 'cflags': [ '-m32' ], - 'ldflags': [ '-m32' ], - }], - [ 'OS=="linux"', { - 'cflags': [ '-ansi' ], - }], - [ 'visibility=="hidden"', { - 'cflags': [ '-fvisibility=hidden' ], - }], - ], - }, + 'cflags': [ '-Wall', '-pthread', ], + 'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ], + 'ldflags': [ '-pthread', ], + 'conditions': [ + [ 'target_arch=="ia32"', { + 'cflags': [ '-m32' ], + 'ldflags': [ '-m32' ], + }], + [ 'OS=="linux"', { + 'cflags': [ '-ansi' ], + }], + [ 'visibility=="hidden"', { + 'cflags': [ '-fvisibility=hidden' ], + }], + ], }], ['OS=="mac"', { - 'target_defaults': { - 'xcode_settings': { - 'ALWAYS_SEARCH_USER_PATHS': 'NO', - 'GCC_C_LANGUAGE_STANDARD': 'ansi', # -ansi - 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks - 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic - # (Equivalent to -fPIC) - 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions - 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti - 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings - # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden - 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden - 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics - 'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', # -Werror - 'GCC_VERSION': '4.2', - 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof - 'MACOSX_DEPLOYMENT_TARGET': '10.4', # -mmacosx-version-min=10.4 - 'PREBINDING': 'NO', # No -Wl,-prebind - 'USE_HEADERMAP': 'NO', - 'OTHER_CFLAGS': [ - '-fno-strict-aliasing', - ], - 'WARNING_CFLAGS': [ - '-Wall', - '-Wendif-labels', - '-W', - '-Wno-unused-parameter', - '-Wnon-virtual-dtor', - ], - }, - 'target_conditions': [ - ['_type!="static_library"', { - 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']}, - }], + 'xcode_settings': { + 'ALWAYS_SEARCH_USER_PATHS': 'NO', + 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks + 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic + # (Equivalent to -fPIC) + 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions + 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti + 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings + # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden + 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics + 'GCC_VERSION': '4.2', + 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof + 'MACOSX_DEPLOYMENT_TARGET': '10.4', # -mmacosx-version-min=10.4 + 'PREBINDING': 'NO', # No -Wl,-prebind + 'USE_HEADERMAP': 'NO', + 'OTHER_CFLAGS': [ + '-fno-strict-aliasing', + ], + 'WARNING_CFLAGS': [ + '-Wall', + '-Wendif-labels', + '-W', + '-Wno-unused-parameter', ], }, + 'target_conditions': [ + ['_type!="static_library"', { + 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']}, + }], + ], }], ], }, diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 3a80f55..35c9c19 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -247,6 +247,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_FS_PRIVATE_FIELDS \ int flags; \ + int last_error; \ struct _stat stat; \ void* arg0; \ union { \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 4f4c7ce..894c98f 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -948,8 +948,14 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb); int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb); +/* + * This flag can be used with uv_fs_symlink on Windows + * to specify whether path argument points to a directory. + */ +#define UV_FS_SYMLINK_DIR 0x0001 + int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, - const char* new_path, uv_fs_cb cb); + const char* new_path, int flags, uv_fs_cb cb); int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index a352977..a016d1b 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -323,7 +323,6 @@ int64_t uv_now(uv_loop_t* loop) { void uv__req_init(uv_req_t* req) { /* loop->counters.req_init++; */ req->type = UV_UNKNOWN_REQ; - req->data = NULL; } diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index fa2948c..bfa06ee 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -24,6 +24,7 @@ #include #include #include +#include /* _NSGetExecutablePath */ uint64_t uv_hrtime() { diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index fc4edbb..5bc1ca9 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -112,7 +112,7 @@ static int uv__fs_after(eio_req* eio) { case UV_FS_READDIR: /* * XXX This is pretty bad. - * We alloc and copy the large null termiated string list from libeio. + * We alloc and copy the large null terminated string list from libeio. * This is done because libeio is going to free eio->ptr2 after this * callback. We must keep it until uv_fs_req_cleanup. If we get rid of * libeio this can be avoided. @@ -130,12 +130,31 @@ static int uv__fs_after(eio_req* eio) { req->ptr = malloc(buflen); memcpy(req->ptr, req->eio->ptr2, buflen); break; + case UV_FS_STAT: case UV_FS_LSTAT: case UV_FS_FSTAT: req->ptr = req->eio->ptr2; break; + case UV_FS_READLINK: + if (req->result == -1) { + req->ptr = NULL; + } else { + assert(req->result > 0); + + if ((name = realloc(req->eio->ptr2, req->result + 1)) == NULL) { + /* Not enough memory. Reuse buffer, chop off last byte. */ + name = req->eio->ptr2; + req->result--; + } + + name[req->result] = '\0'; + req->ptr = name; + req->result = 0; + } + break; + default: break; } @@ -490,15 +509,62 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, - const char* new_path, uv_fs_cb cb) { + const char* new_path, int flags, uv_fs_cb cb) { WRAP_EIO(UV_FS_SYMLINK, eio_symlink, symlink, ARGS2(path, new_path)) } int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { - assert(0 && "implement me"); - return -1; + size_t size; + int status; + char* buf; + + status = -1; + + uv_fs_req_init(loop, req, UV_FS_READLINK, cb); + + if (cb) { + if ((req->eio = eio_readlink(path, EIO_PRI_DEFAULT, uv__fs_after, req))) { + uv_ref(loop); + return 0; + } else { + uv_err_new(loop, ENOMEM); + return -1; + } + } else { + /* pathconf(_PC_PATH_MAX) may return -1 to signify that path + * lengths have no upper limit or aren't suitable for malloc'ing. + */ + if ((size = pathconf(path, _PC_PATH_MAX)) == -1) { +#if defined(PATH_MAX) + size = PATH_MAX; +#else + size = 4096; +#endif + } + + if ((buf = malloc(size + 1)) == NULL) { + uv_err_new(loop, ENOMEM); + return -1; + } + + if ((size = readlink(path, buf, size)) == -1) { + req->errorno = errno; + req->result = -1; + free(buf); + } else { + /* Cannot conceivably fail since it shrinks the buffer. */ + buf = realloc(buf, size + 1); + buf[size] = '\0'; + req->result = 0; + req->ptr = buf; + } + + return 0; + } + + assert(0 && "unreachable"); } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 63d569b..770b4df 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #define UV_FS_FREE_ARG1 0x0004 #define UV_FS_FREE_PTR 0x0008 #define UV_FS_CLEANEDUP 0x0010 +#define UV_FS_LAST_ERROR_SET 0x0020 #define STRDUP_ARG(req, i) \ req->arg##i = (void*)strdup((const char*)req->arg##i); \ @@ -70,6 +72,16 @@ uv_ref((loop)); +#define SET_UV_LAST_ERROR_FROM_REQ(req) \ + if (req->flags & UV_FS_LAST_ERROR_SET) { \ + uv_set_sys_error(req->loop, req->last_error); \ + } + +#define SET_REQ_LAST_ERROR(req, error) \ + req->last_error = error; \ + req->flags |= UV_FS_LAST_ERROR_SET; + + void uv_fs_init() { _fmode = _O_BINARY; } @@ -86,6 +98,7 @@ static void uv_fs_req_init_async(uv_loop_t* loop, uv_fs_t* req, req->result = 0; req->ptr = NULL; req->errorno = 0; + req->last_error = 0; memset(&req->overlapped, 0, sizeof(req->overlapped)); } @@ -187,6 +200,7 @@ void fs__readdir(uv_fs_t* req, const char* path, int flags) { if(dir == INVALID_HANDLE_VALUE) { result = -1; + SET_REQ_LAST_ERROR(req, GetLastError()); goto done; } @@ -267,6 +281,9 @@ void fs__rename(uv_fs_t* req, const char* path, const char* new_path) { void fs__fsync(uv_fs_t* req, uv_file file) { int result = FlushFileBuffers((HANDLE)_get_osfhandle(file)) ? 0 : -1; + if (result == -1) { + SET_REQ_LAST_ERROR(req, GetLastError()); + } SET_REQ_RESULT(req, result); } @@ -383,6 +400,128 @@ void fs__futime(uv_fs_t* req, uv_file file, double atime, double mtime) { } +void fs__link(uv_fs_t* req, const char* path, const char* new_path) { + int result = CreateHardLinkA(new_path, path, NULL) ? 0 : -1; + if (result == -1) { + SET_REQ_LAST_ERROR(req, GetLastError()); + } + SET_REQ_RESULT(req, result); +} + + +void fs__symlink(uv_fs_t* req, const char* path, const char* new_path, + int flags) { + int result; + if (pCreateSymbolicLinkA) { + result = pCreateSymbolicLinkA(new_path, + path, + flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; + if (result == -1) { + SET_REQ_LAST_ERROR(req, GetLastError()); + } + } else { + result = -1; + errno = ENOTSUP; + } + + SET_REQ_RESULT(req, result); +} + + +void fs__readlink(uv_fs_t* req, const char* path) { + int result = -1; + BOOL rv; + HANDLE symlink; + void* buffer; + DWORD bytes_returned; + REPARSE_DATA_BUFFER* reparse_data; + int utf8size; + + symlink = CreateFileA(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_LAST_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, + 0, + buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, + &bytes_returned, + NULL); + + if (!rv) { + result = -1; + SET_REQ_LAST_ERROR(req, GetLastError()); + goto done; + } + + reparse_data = buffer; + if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK) { + result = -1; + /* something is seriously wrong */ + SET_REQ_LAST_ERROR(req, GetLastError()); + goto done; + } + + utf8size = uv_utf16_to_utf8(reparse_data->SymbolicLinkReparseBuffer.PathBuffer + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t)), + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t), + NULL, + 0); + if (!utf8size) { + result = -1; + SET_REQ_LAST_ERROR(req, GetLastError()); + goto done; + } + + req->ptr = malloc(utf8size + 1); + if (!req->ptr) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + req->flags |= UV_FS_FREE_PTR; + + utf8size = uv_utf16_to_utf8(reparse_data->SymbolicLinkReparseBuffer.PathBuffer + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t)), + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t), + req->ptr, + utf8size); + if (!utf8size) { + result = -1; + SET_REQ_LAST_ERROR(req, GetLastError()); + goto done; + } + + ((char*)req->ptr)[utf8size] = '\0'; + result = 0; + +done: + if (buffer) { + free(buffer); + } + + if (symlink != INVALID_HANDLE_VALUE) { + CloseHandle(symlink); + } + + SET_REQ_RESULT(req, result); +} + + void fs__nop(uv_fs_t* req) { req->result = 0; } @@ -464,6 +603,15 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) { case UV_FS_FUTIME: fs__futime(req, (uv_file)req->arg0, req->arg4, req->arg5); break; + case UV_FS_LINK: + fs__link(req, (const char*)req->arg0, (const char*)req->arg1); + break; + case UV_FS_SYMLINK: + fs__symlink(req, (const char*)req->arg0, (const char*)req->arg1, (int)req->arg2); + break; + case UV_FS_READLINK: + fs__readlink(req, (const char*)req->arg0); + break; case UV_FS_CHOWN: case UV_FS_FCHOWN: fs__nop(req); @@ -488,6 +636,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, } else { uv_fs_req_init_sync(loop, req, UV_FS_OPEN); fs__open(req, path, flags, mode); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -502,6 +651,7 @@ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_CLOSE); fs__close(req, file); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -517,6 +667,7 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf, } else { uv_fs_req_init_sync(loop, req, UV_FS_READ); fs__read(req, file, buf, length, offset); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -532,6 +683,7 @@ int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf, } else { uv_fs_req_init_sync(loop, req, UV_FS_WRITE); fs__write(req, file, buf, length, offset); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -548,6 +700,7 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, } else { uv_fs_req_init_sync(loop, req, UV_FS_UNLINK); fs__unlink(req, path); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -564,6 +717,7 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, } else { uv_fs_req_init_sync(loop, req, UV_FS_MKDIR); fs__mkdir(req, path, mode); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -579,6 +733,7 @@ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_RMDIR); fs__rmdir(req, path); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -595,6 +750,7 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, } else { uv_fs_req_init_sync(loop, req, UV_FS_READDIR); fs__readdir(req, path, flags); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -603,22 +759,54 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) { - assert(0 && "implement me"); - return -1; + if (cb) { + uv_fs_req_init_async(loop, req, UV_FS_LINK, cb); + WRAP_REQ_ARGS2(req, path, new_path); + STRDUP_ARG(req, 0); + STRDUP_ARG(req, 1); + QUEUE_FS_TP_JOB(loop, req); + } else { + uv_fs_req_init_sync(loop, req, UV_FS_LINK); + fs__link(req, path, new_path); + SET_UV_LAST_ERROR_FROM_REQ(req); + } + + return 0; } int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, - const char* new_path, uv_fs_cb cb) { - assert(0 && "implement me"); - return -1; + const char* new_path, int flags, uv_fs_cb cb) { + if (cb) { + uv_fs_req_init_async(loop, req, UV_FS_SYMLINK, cb); + WRAP_REQ_ARGS3(req, path, new_path, flags); + STRDUP_ARG(req, 0); + STRDUP_ARG(req, 1); + QUEUE_FS_TP_JOB(loop, req); + } else { + uv_fs_req_init_sync(loop, req, UV_FS_SYMLINK); + fs__symlink(req, path, new_path, flags); + SET_UV_LAST_ERROR_FROM_REQ(req); + } + + return 0; } int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { - assert(0 && "implement me"); - return -1; + if (cb) { + uv_fs_req_init_async(loop, req, UV_FS_READLINK, cb); + WRAP_REQ_ARGS1(req, path); + STRDUP_ARG(req, 0); + QUEUE_FS_TP_JOB(loop, req); + } else { + uv_fs_req_init_sync(loop, req, UV_FS_READLINK); + fs__readlink(req, path); + SET_UV_LAST_ERROR_FROM_REQ(req); + } + + return 0; } @@ -632,6 +820,7 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid, } else { uv_fs_req_init_sync(loop, req, UV_FS_CHOWN); fs__nop(req); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -647,6 +836,7 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, int uid, } else { uv_fs_req_init_sync(loop, req, UV_FS_FCHOWN); fs__nop(req); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -684,6 +874,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { if (path2) { free(path2); } + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -722,6 +913,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { if (path2) { free(path2); } + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -736,6 +928,7 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_FSTAT); fs__fstat(req, file); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -753,6 +946,7 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, } else { uv_fs_req_init_sync(loop, req, UV_FS_RENAME); fs__rename(req, path, new_path); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -767,6 +961,7 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_FDATASYNC); fs__fsync(req, file); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -781,6 +976,7 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_FSYNC); fs__fsync(req, file); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -796,6 +992,7 @@ int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, } else { uv_fs_req_init_sync(loop, req, UV_FS_FTRUNCATE); fs__ftruncate(req, file, offset); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -811,6 +1008,7 @@ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, } else { uv_fs_req_init_sync(loop, req, UV_FS_SENDFILE); fs__sendfile(req, out_fd, in_fd, in_offset, length); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -827,6 +1025,7 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, } else { uv_fs_req_init_sync(loop, req, UV_FS_CHMOD); fs__chmod(req, path, mode); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -842,6 +1041,7 @@ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, } else { uv_fs_req_init_sync(loop, req, UV_FS_FCHMOD); fs__fchmod(req, file, mode); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -860,6 +1060,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, } else { uv_fs_req_init_sync(loop, req, UV_FS_UTIME); fs__utime(req, path, atime, mtime); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -877,6 +1078,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, } else { uv_fs_req_init_sync(loop, req, UV_FS_FUTIME); fs__futime(req, file, atime, mtime); + SET_UV_LAST_ERROR_FROM_REQ(req); } return 0; @@ -885,6 +1087,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) { assert(req->cb); + SET_UV_LAST_ERROR_FROM_REQ(req); req->cb(req); } diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index bf4d5e3..4a58c14 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -31,6 +31,7 @@ sNtQueryInformationFile pNtQueryInformationFile; sNtSetInformationFile pNtSetInformationFile; sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; +sCreateSymbolicLinkA pCreateSymbolicLinkA; void uv_winapi_init() { @@ -74,4 +75,7 @@ void uv_winapi_init() { pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes) GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes"); + + pCreateSymbolicLinkA = (sCreateSymbolicLinkA) + GetProcAddress(kernel32_module, "CreateSymbolicLinkA"); } diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 9feee8b..9dc0acb 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4075,6 +4075,33 @@ (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_ERROR))) #endif +/* from ntifs.h */ +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; @@ -4186,6 +4213,8 @@ typedef NTSTATUS (NTAPI *sNtSetInformationFile) #define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 #define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 +#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 + #ifdef __MINGW32__ typedef struct _OVERLAPPED_ENTRY { ULONG_PTR lpCompletionKey; @@ -4207,6 +4236,11 @@ typedef BOOL (WINAPI* sSetFileCompletionNotificationModes) (HANDLE FileHandle, UCHAR Flags); +typedef BOOLEAN (WINAPI* sCreateSymbolicLinkA) + (LPCSTR lpSymlinkFileName, + LPCSTR lpTargetFileName, + DWORD dwFlags); + /* Ntapi function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; @@ -4217,5 +4251,6 @@ extern sNtSetInformationFile pNtSetInformationFile; /* Kernel32 function pointers */ extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; +extern sCreateSymbolicLinkA pCreateSymbolicLinkA; #endif /* UV_WIN_WINAPI_H_ */ diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 27f9173..1f14abf 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -25,6 +25,7 @@ #include "uv.h" #include "task.h" +#include #include /* memset */ #include #include @@ -62,6 +63,9 @@ static int chmod_cb_count; static int fchmod_cb_count; static int chown_cb_count; static int fchown_cb_count; +static int link_cb_count; +static int symlink_cb_count; +static int readlink_cb_count; static uv_loop_t* loop; @@ -109,6 +113,29 @@ void check_permission(const char* filename, int mode) { } +static void link_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_LINK); + ASSERT(req->result == 0); + link_cb_count++; + uv_fs_req_cleanup(req); +} + + +static void symlink_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_SYMLINK); + ASSERT(req->result == 0); + symlink_cb_count++; + uv_fs_req_cleanup(req); +} + +static void readlink_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_READLINK); + ASSERT(req->result == 0); + ASSERT(strcmp(req->ptr, "test_file_symlink2") == 0); + readlink_cb_count++; + uv_fs_req_cleanup(req); +} + static void fchmod_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_FCHMOD); ASSERT(req->result == 0); @@ -297,9 +324,8 @@ static void readdir_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_READDIR); ASSERT(req->result == 2); ASSERT(req->ptr); - ASSERT(strcmp((const char*)req->ptr, "file1") == 0); - ASSERT(strcmp((char*)req->ptr + strlen((const char*)req->ptr) + 1, - "file2") == 0); + ASSERT(memcmp(req->ptr, "file1\0file2\0", 12) == 0 + || memcmp(req->ptr, "file2\0file1\0", 12) == 0); readdir_cb_count++; uv_fs_req_cleanup(req); ASSERT(!req->ptr); @@ -734,6 +760,7 @@ TEST_IMPL(fs_chmod) { ASSERT(r == 0); uv_run(loop); ASSERT(chmod_cb_count == 1); + chmod_cb_count = 0; /* reset for the next test */ #endif /* async chmod */ @@ -820,4 +847,207 @@ TEST_IMPL(fs_chown) { unlink("test_file"); return 0; +} + + +TEST_IMPL(fs_link) { + int r; + uv_fs_t req; + uv_file file; + uv_file link; + + /* Setup. */ + unlink("test_file"); + unlink("test_file_link"); + unlink("test_file_link2"); + + uv_init(); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, + S_IWRITE | S_IREAD, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + file = req.result; + uv_fs_req_cleanup(&req); + + r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + ASSERT(r == 0); + ASSERT(req.result == sizeof(test_buf)); + uv_fs_req_cleanup(&req); + + close(file); + + /* sync link */ + r = uv_fs_link(loop, &req, "test_file", "test_file_link", NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "test_file_link", O_RDWR, 0, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + link = req.result; + uv_fs_req_cleanup(&req); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + ASSERT(strcmp(buf, test_buf) == 0); + + close(link); + + /* async link */ + r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb); + ASSERT(r == 0); + uv_run(loop); + ASSERT(link_cb_count == 1); + + r = uv_fs_open(loop, &req, "test_file_link2", O_RDWR, 0, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + link = req.result; + uv_fs_req_cleanup(&req); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + ASSERT(strcmp(buf, test_buf) == 0); + + close(link); + + /* + * Run the loop just to check we don't have make any extraneous uv_ref() + * calls. This should drop out immediately. + */ + uv_run(loop); + + /* Cleanup. */ + unlink("test_file"); + unlink("test_file_link"); + unlink("test_file_link2"); + + return 0; +} + + +TEST_IMPL(fs_symlink) { + int r; + uv_fs_t req; + uv_file file; + uv_file link; + + /* Setup. */ + unlink("test_file"); + unlink("test_file_symlink"); + unlink("test_file_symlink2"); + unlink("test_file_symlink_symlink"); + unlink("test_file_symlink2_symlink"); + + uv_init(); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, + S_IWRITE | S_IREAD, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + file = req.result; + uv_fs_req_cleanup(&req); + + r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + ASSERT(r == 0); + ASSERT(req.result == sizeof(test_buf)); + uv_fs_req_cleanup(&req); + + close(file); + + /* sync symlink */ + r = uv_fs_symlink(loop, &req, "test_file", "test_file_symlink", 0, NULL); + ASSERT(r == 0); +#ifdef _WIN32 + if (req.result == -1) { + if (req.errorno == ENOTSUP) { + /* + * Windows doesn't support symlinks on older versions. + * We just pass the test and bail out early if we get ENOTSUP. + */ + return 0; + } else if (uv_last_error(loop).sys_errno_ == ERROR_PRIVILEGE_NOT_HELD) { + /* + * Creating a symlink is only allowed when running elevated. + * We pass the test and bail out early if we get ERROR_PRIVILEGE_NOT_HELD. + */ + return 0; + } + } +#endif + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "test_file_symlink", O_RDWR, 0, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + link = req.result; + uv_fs_req_cleanup(&req); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + ASSERT(strcmp(buf, test_buf) == 0); + + close(link); + + r = uv_fs_symlink(loop, &req, "test_file_symlink", "test_file_symlink_symlink", 0, NULL); + ASSERT(r == 0); + r = uv_fs_readlink(loop, &req, "test_file_symlink_symlink", NULL); + ASSERT(r == 0); + ASSERT(strcmp(req.ptr, "test_file_symlink") == 0); + uv_fs_req_cleanup(&req); + + /* async link */ + r = uv_fs_symlink(loop, &req, "test_file", "test_file_symlink2", 0, symlink_cb); + ASSERT(r == 0); + uv_run(loop); + ASSERT(symlink_cb_count == 1); + + r = uv_fs_open(loop, &req, "test_file_symlink2", O_RDWR, 0, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + link = req.result; + uv_fs_req_cleanup(&req); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + ASSERT(r == 0); + ASSERT(req.result != -1); + ASSERT(strcmp(buf, test_buf) == 0); + + close(link); + + r = uv_fs_symlink(loop, &req, "test_file_symlink2", "test_file_symlink2_symlink", 0, NULL); + ASSERT(r == 0); + r = uv_fs_readlink(loop, &req, "test_file_symlink2_symlink", readlink_cb); + ASSERT(r == 0); + uv_run(loop); + ASSERT(readlink_cb_count == 1); + + /* + * Run the loop just to check we don't have make any extraneous uv_ref() + * calls. This should drop out immediately. + */ + uv_run(loop); + + /* Cleanup. */ + unlink("test_file"); + unlink("test_file_symlink"); + unlink("test_file_symlink_symlink"); + unlink("test_file_symlink2"); + unlink("test_file_symlink2_symlink"); + + return 0; } \ No newline at end of file diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 94cf03c..fe8f1ed 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -79,6 +79,8 @@ TEST_DECLARE (fs_async_sendfile) TEST_DECLARE (fs_fstat) TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_chown) +TEST_DECLARE (fs_link) +TEST_DECLARE (fs_symlink) TEST_DECLARE (threadpool_queue_work_simple) #ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) @@ -185,6 +187,8 @@ TASK_LIST_START TEST_ENTRY (fs_fstat) TEST_ENTRY (fs_chmod) TEST_ENTRY (fs_chown) + TEST_ENTRY (fs_link) + TEST_ENTRY (fs_symlink) TEST_ENTRY (threadpool_queue_work_simple) diff --git a/src/node_file.cc b/src/node_file.cc index fc422fe..f2d163c 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -384,10 +384,13 @@ static Handle Symlink(const Arguments& args) { String::Utf8Value dest(args[0]->ToString()); String::Utf8Value path(args[1]->ToString()); + // Just set to zero for now. Support UV_FS_SYMLINK_DIR in the future. + int flags = 0; + if (args[2]->IsFunction()) { - ASYNC_CALL(symlink, args[2], *dest, *path) + ASYNC_CALL(symlink, args[2], *dest, *path, flags) } else { - SYNC_CALL(symlink, *path, *dest, *path) + SYNC_CALL(symlink, *path, *dest, *path, flags) return Undefined(); } }