Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -56,6 +56,7 @@ if( NOT PURE_WINDOWS ) check_include_file(pthread.h HAVE_PTHREAD_H) endif() +check_include_file(pwd.h HAVE_PWD_H) check_include_file(signal.h HAVE_SIGNAL_H) check_include_file(stdint.h HAVE_STDINT_H) check_include_file(sys/dir.h HAVE_SYS_DIR_H) Index: include/llvm/Config/config.h.cmake =================================================================== --- include/llvm/Config/config.h.cmake +++ include/llvm/Config/config.h.cmake @@ -232,6 +232,9 @@ /* Have pthread_rwlock_init */ #cmakedefine HAVE_PTHREAD_RWLOCK_INIT ${HAVE_PTHREAD_RWLOCK_INIT} +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PWD_H ${HAVE_PWD_H} + /* Define to 1 if srand48/lrand48/drand48 exist in */ #cmakedefine HAVE_RAND48 ${HAVE_RAND48} Index: lib/Support/Unix/Path.inc =================================================================== --- lib/Support/Unix/Path.inc +++ lib/Support/Unix/Path.inc @@ -28,6 +28,9 @@ #ifdef HAVE_SYS_MMAN_H #include #endif +#ifdef HAVE_PWD_H +#include +#endif #if HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) @@ -550,13 +553,43 @@ namespace path { -bool home_directory(SmallVectorImpl &result) { +static bool getHomeDirFromPasswd(SmallVectorImpl &Result) { +#ifdef HAVE_PWD_H + static const size_t InitialBufSize = 1024; + SmallString Buf; + Buf.reserve(InitialBufSize); + Buf.set_size(Buf.capacity()); + + ::passwd Passwd; + ::passwd *PasswdResult = nullptr; + int Err = 0; + while ((Err = ::getpwuid_r(::getuid(), &Passwd, Buf.data(), Buf.size(), + &PasswdResult)) == ERANGE) { + Buf.reserve(Buf.size() * 2); + Buf.set_size(Buf.capacity()); + } + + if (!Err) { + assert(PasswdResult == &Passwd && "getpwuid_r does strange things"); + auto Dir = Passwd.pw_dir; + Result.clear(); + Result.append(Dir, Dir + strlen(Dir)); + return true; + } +#endif + return false; +} + +bool home_directory(SmallVectorImpl &Result) { if (char *RequestedDir = getenv("HOME")) { - result.clear(); - result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + Result.clear(); + Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); return true; } + if (getHomeDirFromPasswd(Result)) + return true; + return false; } Index: unittests/Support/Path.cpp =================================================================== --- unittests/Support/Path.cpp +++ unittests/Support/Path.cpp @@ -322,6 +322,52 @@ } } +static std::string path2regex(std::string Path) { + size_t Pos = 0; + while ((Pos = Path.find('\\', Pos)) != std::string::npos) { + Path.replace(Pos, 1, "\\\\"); + Pos += 2; + } + return Path; +} + +/// Helper for running known dir test that depends on enviroment variables in +/// separated process. This allows checking different values of enviroment +/// variables without messing up the environment of the current process. +#define EXPECT_DIR(test, expected) \ + EXPECT_EXIT( \ + { \ + SmallString<300> Dir; \ + test; \ + raw_os_ostream(std::cerr) << Dir; \ + std::exit(0); \ + }, \ + ::testing::ExitedWithCode(0), path2regex(expected)) + +/// Helper for running home dir test in separated process, @see EXPECT_DIR. +#define EXPECT_HOME_DIR(prepare, expected) \ + EXPECT_DIR( \ + { \ + prepare; \ + path::home_directory(Dir); \ + }, \ + expected) + +/// Helper for running temp dir test in separated process, @see EXPECT_DIR. +#define EXPECT_TEMP_DIR(prepare, expected) \ + EXPECT_DIR( \ + { \ + prepare; \ + path::system_temp_directory(true, Dir); \ + }, \ + expected) + +#ifdef LLVM_ON_UNIX +TEST(SupportDeathTest, HomeDirectoryOnUnix) { + EXPECT_HOME_DIR(setenv("HOME", "/home/LLVMUser", true), "/home/LLVMUser"); +} +#endif + TEST(Support, UserCacheDirectory) { SmallString<13> CacheDir; SmallString<20> CacheDir2; @@ -360,28 +406,14 @@ EXPECT_TRUE(!TempDir.empty()); } -#ifdef LLVM_ON_WIN32 -static std::string path2regex(std::string Path) { - size_t Pos = 0; - while ((Pos = Path.find('\\', Pos)) != std::string::npos) { - Path.replace(Pos, 1, "\\\\"); - Pos += 2; - } - return Path; +#ifdef LLVM_ON_UNIX +TEST(SupportDeathTest, TempDirectoryOnUnix) { + EXPECT_TEMP_DIR(setenv("TMPDIR", "/home/LLVMUser/.tmp", true), + "/home/LLVMUser/.tmp"); } +#endif -/// Helper for running temp dir test in separated process. See below. -#define EXPECT_TEMP_DIR(prepare, expected) \ - EXPECT_EXIT( \ - { \ - prepare; \ - SmallString<300> TempDir; \ - path::system_temp_directory(true, TempDir); \ - raw_os_ostream(std::cerr) << TempDir; \ - std::exit(0); \ - }, \ - ::testing::ExitedWithCode(0), path2regex(expected)) - +#ifdef LLVM_ON_WIN32 TEST(SupportDeathTest, TempDirectoryOnWindows) { // In this test we want to check how system_temp_directory responds to // different values of specific env vars. To prevent corrupting env vars of