win: add XP support to uv_os_homedir()

The previous Windows implementation used SHGetKnownFolderPath(),
which is only supported on Vista and up. This commit switches to
GetUserProfileDirectoryW(), which returns the same information,
but is supported back to Windows 2000, and is not deprecated.

PR-URL: https://github.com/libuv/libuv/pull/375
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
cjihrig 2015-05-28 21:53:18 -04:00 committed by Saúl Ibarra Corretgé
parent d110a1b6c5
commit a0c8815294
4 changed files with 38 additions and 39 deletions

View File

@ -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 \

View File

@ -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

View File

@ -36,8 +36,7 @@
#include <psapi.h>
#include <tlhelp32.h>
#include <windows.h>
#include <shlobj.h>
#include <objbase.h>
#include <userenv.h>
/*
@ -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;
goto convert_buffer;
}
bufsize = uv_utf16_to_utf8(path, -1, buffer, *size);
assert(len + 1 == bufsize);
uv__free(path);
*size = len;
return 0;
}
/* 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;
}

2
uv.gyp
View File

@ -108,9 +108,9 @@
'libraries': [
'-ladvapi32',
'-liphlpapi',
'-lole32',
'-lpsapi',
'-lshell32',
'-luserenv',
'-lws2_32'
],
},