diff --git a/Makefile.am b/Makefile.am index 41a94045..e9814d7b 100644 --- a/Makefile.am +++ b/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 -lole32 -lshell32 +LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ diff --git a/docs/src/misc.rst b/docs/src/misc.rst index fb5a8a40..9708c5de 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -272,7 +272,7 @@ API 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, + `GetUserProfileDirectoryW()` 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 diff --git a/src/win/util.c b/src/win/util.c index 2e6015f8..58e42bbd 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -36,8 +36,7 @@ #include #include #include -#include -#include +#include /* @@ -1158,7 +1157,8 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { int uv_os_homedir(char* buffer, size_t* size) { - wchar_t* path; + HANDLE token; + wchar_t path[MAX_PATH]; size_t bufsize; size_t len; int r; @@ -1167,55 +1167,54 @@ int uv_os_homedir(char* buffer, size_t* size) { return UV_EINVAL; /* Check if the USERPROFILE environment variable is set first */ - path = uv__malloc(*size * sizeof(WCHAR)); - - if (path == NULL) - return UV_ENOMEM; - - len = GetEnvironmentVariableW(L"USERPROFILE", path, *size); + len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH); if (len == 0) { r = GetLastError(); - uv__free(path); - + /* Don't return an error if USERPROFILE was not found */ if (r != ERROR_ENVVAR_NOT_FOUND) return uv_translate_sys_error(r); + } else if (len > MAX_PATH) { + /* This should not be possible */ + return UV_EIO; } else { - if (len > *size) { - uv__free(path); - *size = len - 1; - return UV_ENOBUFS; - } - - bufsize = uv_utf16_to_utf8(path, -1, buffer, *size); - assert(len + 1 == bufsize); - uv__free(path); - *size = len; - - return 0; + goto convert_buffer; } - /* USERPROFILE is not set, so call SHGetKnownFolderPath() */ - if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, &path) != S_OK) + /* USERPROFILE is not set, so call GetUserProfileDirectoryW() */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) return uv_translate_sys_error(GetLastError()); - bufsize = uv_utf16_to_utf8(path, -1, buffer, *size); - - if (bufsize == 0) { + bufsize = MAX_PATH; + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { r = GetLastError(); + CloseHandle(token); - if (r == ERROR_INSUFFICIENT_BUFFER) { - *size = wcslen(path); - CoTaskMemFree(path); - return UV_ENOBUFS; - } + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_EIO; - CoTaskMemFree(path); return uv_translate_sys_error(r); } - CoTaskMemFree(path); - *size = bufsize - 1; + CloseHandle(token); +convert_buffer: + + /* Check how much space we need */ + bufsize = uv_utf16_to_utf8(path, -1, NULL, 0); + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize - 1; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = uv_utf16_to_utf8(path, -1, buffer, *size); + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; return 0; } diff --git a/uv.gyp b/uv.gyp index cbd70abc..7173a827 100644 --- a/uv.gyp +++ b/uv.gyp @@ -108,9 +108,9 @@ 'libraries': [ '-ladvapi32', '-liphlpapi', - '-lole32', '-lpsapi', '-lshell32', + '-luserenv', '-lws2_32' ], },