Skip to content

Commit

Permalink
unix,win: add uv_os_homedir()
Browse files Browse the repository at this point in the history
PR-URL: libuv/libuv#350
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Saúl Ibarra Corretgé <[email protected]>
  • Loading branch information
cjihrig committed May 25, 2015
1 parent a74c2c9 commit 6887116
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 7 deletions.
3 changes: 2 additions & 1 deletion deps/uv/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down
1 change: 1 addition & 0 deletions deps/uv/checksparse.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions deps/uv/docs/src/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions deps/uv/include/uv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
80 changes: 80 additions & 0 deletions deps/uv/src/unix/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <limits.h> /* INT_MAX, PATH_MAX */
#include <sys/uio.h> /* writev */
#include <sys/resource.h> /* getrusage */
#include <pwd.h>

#ifdef __linux__
# include <sys/ioctl.h>
Expand Down Expand Up @@ -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;
}
78 changes: 72 additions & 6 deletions deps/uv/src/win/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include <psapi.h>
#include <tlhelp32.h>
#include <windows.h>
#include <shlobj.h>
#include <objbase.h>


/*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
49 changes: 49 additions & 0 deletions deps/uv/test/test-homedir.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "uv.h"
#include "task.h"
#include <string.h>

#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;
}
3 changes: 3 additions & 0 deletions deps/uv/test/test-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions deps/uv/uv.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
'libraries': [
'-ladvapi32',
'-liphlpapi',
'-lole32',
'-lpsapi',
'-lshell32',
'-lws2_32'
Expand Down Expand Up @@ -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',
Expand Down

0 comments on commit 6887116

Please sign in to comment.