summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
Diffstat (limited to 'deps')
-rw-r--r--deps/uv/common.gypi102
-rw-r--r--deps/uv/include/uv-private/uv-win.h1
-rw-r--r--deps/uv/include/uv.h8
-rw-r--r--deps/uv/src/unix/core.c1
-rw-r--r--deps/uv/src/unix/darwin.c1
-rw-r--r--deps/uv/src/unix/fs.c74
-rw-r--r--deps/uv/src/win/fs.c217
-rw-r--r--deps/uv/src/win/winapi.c4
-rw-r--r--deps/uv/src/win/winapi.h35
-rw-r--r--deps/uv/test/test-fs.c236
-rw-r--r--deps/uv/test/test-list.h4
11 files changed, 616 insertions, 67 deletions
diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi
index 840d3a7a2..f871a473a 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 3a80f55ab..35c9c1943 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 4f4c7ce70..894c98fbf 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 a35297762..a016d1b36 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 fa2948cd2..bfa06eede 100644
--- a/deps/uv/src/unix/darwin.c
+++ b/deps/uv/src/unix/darwin.c
@@ -24,6 +24,7 @@
#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
+#include <mach-o/dyld.h> /* _NSGetExecutablePath */
uint64_t uv_hrtime() {
diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c
index fc4edbb29..5bc1ca989 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 63d569b4b..770b4df1f 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -22,6 +22,7 @@
#include <assert.h>
#include <malloc.h>
#include <direct.h>
+#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
@@ -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 bf4d5e389..4a58c1457 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 9feee8bb5..9dc0acb28 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 27f91732f..1f14abffb 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 <errno.h>
#include <string.h> /* memset */
#include <fcntl.h>
#include <sys/stat.h>
@@ -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 94cf03c6b..fe8f1ed0b 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)