diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index b9fb80c6738b52..510f14f508a007 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -45,7 +45,7 @@ include_HEADERS += include/uv-win.h include/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 -LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 +LIBS += -lws2_32 -lpsapi -liphlpapi -lole32 -lshell32 libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ @@ -165,6 +165,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-getnameinfo.c \ test/test-getsockname.c \ test/test-handle-fileno.c \ + test/test-homedir.c \ test/test-hrtime.c \ test/test-idle.c \ test/test-ip4-addr.c \ diff --git a/deps/uv/checksparse.sh b/deps/uv/checksparse.sh index 9442c202eabe68..619cf6f8b672d8 100755 --- a/deps/uv/checksparse.sh +++ b/deps/uv/checksparse.sh @@ -103,6 +103,7 @@ test/test-get-loadavg.c test/test-get-memory.c test/test-getaddrinfo.c test/test-getsockname.c +test/test-homedir.c test/test-hrtime.c test/test-idle.c test/test-ip6-addr.c diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index bb97a260057fc8..54681f70461d05 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -227,6 +227,23 @@ API Changes the current working directory. +.. c:function:: int uv_os_homedir(char* buffer, size_t* size) + + Gets the current user's home directory. On Windows, `uv_os_homedir()` first + checks the `USERPROFILE` environment variable using + `GetEnvironmentVariableW()`. If `USERPROFILE` is not set, + `SHGetKnownFolderPath()` is called. On all other operating systems, + `uv_os_homedir()` first checks the `HOME` environment variable using + :man:`getenv(3)`. If `HOME` is not set, :man:`getpwuid_r(3)` is called. The + user's home directory is stored in `buffer`. When `uv_os_homedir()` is + called, `size` indicates the maximum size of `buffer`. On success or + `UV_ENOBUFS` failure, `size` is set to the string length of `buffer`. + + .. warning:: + `uv_os_homedir()` is not thread safe. + + .. versionadded:: 1.6.0 + .. uint64_t uv_get_free_memory(void) .. c:function:: uint64_t uv_get_total_memory(void) diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 75b3a4a5d2f8bf..dcbdea3c23f7ea 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -1028,6 +1028,8 @@ typedef struct { UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); +UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); + UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 6f284ffa7aea31..814c8b3cba8294 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -38,6 +38,7 @@ #include /* INT_MAX, PATH_MAX */ #include /* writev */ #include /* getrusage */ +#include #ifdef __linux__ # include @@ -983,3 +984,82 @@ int uv__dup2_cloexec(int oldfd, int newfd) { return r; } } + + +int uv_os_homedir(char* buffer, size_t* size) { + struct passwd pw; + struct passwd* result; + char* buf; + uid_t uid; + size_t bufsize; + size_t len; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + /* Check if the HOME environment variable is set first */ + buf = getenv("HOME"); + + if (buf != NULL) { + len = strlen(buf); + + if (len >= *size) { + *size = len; + return -ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + + return 0; + } + + /* HOME is not set, so call getpwuid() */ + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + + if (bufsize <= 0) + return -EIO; + + uid = getuid(); + buf = NULL; + + for (;;) { + free(buf); + buf = malloc(bufsize); + + if (buf == NULL) + return -ENOMEM; + + r = getpwuid_r(uid, &pw, buf, bufsize, &result); + + if (r != ERANGE) + break; + + bufsize *= 2; + } + + if (r != 0) { + free(buf); + return -r; + } + + if (result == NULL) { + free(buf); + return -ENOENT; + } + + len = strlen(pw.pw_dir); + + if (len >= *size) { + *size = len; + free(buf); + return -ENOBUFS; + } + + memcpy(buffer, pw.pw_dir, len + 1); + *size = len; + free(buf); + + return 0; +} diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 3697d5aa6aaf20..fe64f85345bc06 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include /* @@ -72,7 +74,7 @@ void uv__util_init() { InitializeCriticalSection(&process_title_lock); /* Retrieve high-resolution timer frequency - * and precompute its reciprocal. + * and precompute its reciprocal. */ if (QueryPerformanceFrequency(&perf_frequency)) { hrtime_interval_ = 1.0 / perf_frequency.QuadPart; @@ -801,8 +803,8 @@ static int is_windows_version_or_greater(DWORD os_major, /* Perform the test. */ return (int) VerifyVersionInfo( - &osvi, - VER_MAJORVERSION | VER_MINORVERSION | + &osvi, + VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, condition_mask); } @@ -870,7 +872,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX; } - + /* Fetch the size of the adapters reported by windows, and then get the */ /* list itself. */ @@ -1053,14 +1055,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, prefix->PrefixLength <= prefix_len) continue; - if (address_prefix_match(sa->sa_family, sa, + if (address_prefix_match(sa->sa_family, sa, prefix->Address.lpSockaddr, prefix->PrefixLength)) { prefix_len = prefix->PrefixLength; } } /* If there is no matching prefix information, return a single-host - * subnet mask (e.g. 255.255.255.255 for IPv4). + * subnet mask (e.g. 255.255.255.255 for IPv4). */ if (!prefix_len) prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32; @@ -1153,3 +1155,67 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { return 0; } + + +int uv_os_homedir(char* buffer, size_t* size) { + wchar_t* path; + size_t bufsize; + size_t len; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + /* Check if the USERPROFILE environment variable is set first */ + path = malloc(*size * sizeof(WCHAR)); + + if (path == NULL) + return UV_ENOMEM; + + len = GetEnvironmentVariableW(L"USERPROFILE", path, *size); + + if (len == 0) { + r = GetLastError(); + free(path); + + if (r != ERROR_ENVVAR_NOT_FOUND) + return uv_translate_sys_error(r); + } else { + if (len > *size) { + free(path); + *size = len - 1; + return UV_ENOBUFS; + } + + bufsize = uv_utf16_to_utf8(path, -1, buffer, *size); + assert(len + 1 == bufsize); + free(path); + *size = len; + + return 0; + } + + /* USERPROFILE is not set, so call SHGetKnownFolderPath() */ + if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, &path) != S_OK) + return uv_translate_sys_error(GetLastError()); + + bufsize = uv_utf16_to_utf8(path, -1, buffer, *size); + + if (bufsize == 0) { + r = GetLastError(); + + if (r == ERROR_INSUFFICIENT_BUFFER) { + *size = wcslen(path); + CoTaskMemFree(path); + return UV_ENOBUFS; + } + + CoTaskMemFree(path); + return uv_translate_sys_error(r); + } + + CoTaskMemFree(path); + *size = bufsize - 1; + + return 0; +} diff --git a/deps/uv/test/test-homedir.c b/deps/uv/test/test-homedir.c new file mode 100644 index 00000000000000..cbc47566c55e42 --- /dev/null +++ b/deps/uv/test/test-homedir.c @@ -0,0 +1,49 @@ +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(homedir) { + char homedir[PATHMAX]; + size_t len; + char last; + int r; + + /* Test the normal case */ + len = sizeof homedir; + homedir[0] = '\0'; + ASSERT(strlen(homedir) == 0); + r = uv_os_homedir(homedir, &len); + ASSERT(r == 0); + ASSERT(strlen(homedir) == len); + ASSERT(len > 0); + ASSERT(homedir[len] == '\0'); + + if (len > 1) { + last = homedir[len - 1]; +#ifdef _WIN32 + ASSERT(last != '\\'); +#else + ASSERT(last != '/'); +#endif + } + + /* Test the case where the buffer is too small */ + len = SMALLPATH; + r = uv_os_homedir(homedir, &len); + ASSERT(r == UV_ENOBUFS); + ASSERT(len > SMALLPATH); + + /* Test invalid inputs */ + r = uv_os_homedir(NULL, &len); + ASSERT(r == UV_EINVAL); + r = uv_os_homedir(homedir, NULL); + ASSERT(r == UV_EINVAL); + len = 0; + r = uv_os_homedir(homedir, &len); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 1e3c13d5e9267d..8f75be90aa9633 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -182,6 +182,7 @@ TEST_DECLARE (process_title) TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) TEST_DECLARE (handle_fileno) +TEST_DECLARE (homedir) TEST_DECLARE (hrtime) TEST_DECLARE (getaddrinfo_fail) TEST_DECLARE (getaddrinfo_fail_sync) @@ -540,6 +541,8 @@ TASK_LIST_START TEST_ENTRY (handle_fileno) + TEST_ENTRY (homedir) + TEST_ENTRY (hrtime) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index acaed862d7c66e..121ddd7731098e 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -108,6 +108,7 @@ 'libraries': [ '-ladvapi32', '-liphlpapi', + '-lole32', '-lpsapi', '-lshell32', '-lws2_32' @@ -304,6 +305,7 @@ 'test/test-getnameinfo.c', 'test/test-getsockname.c', 'test/test-handle-fileno.c', + 'test/test-homedir.c', 'test/test-hrtime.c', 'test/test-idle.c', 'test/test-ip6-addr.c',